perf(terminal): stop the cursor blink while the window lacks the keyboard

main
reionwong 2 weeks ago
parent c1e778dd75
commit 6e73d0d7b3

@ -80,7 +80,7 @@ TerminalView::TerminalView()
updatePointerCursor();
_blinkTimer.onTimeout = [this] { blinkEvent(); };
_blinkCursorTimer.onTimeout = [this] { blinkCursorEvent(); };
_blinkCursorTimer.onTimeout = [this] { blinkCursorTimeout(); };
_tripleClickTimer.setSingleShot(true);
_tripleClickTimer.onTimeout = [this] { _possibleTripleClick = false; };
_bellTimer.setSingleShot(true);
@ -270,7 +270,7 @@ void TerminalView::setBlinkingCursor(bool blink)
{
_hasBlinkingCursor = blink;
if (blink && !_blinkCursorTimer.isActive() && hasFocus())
if (blink && !_blinkCursorTimer.isActive() && hasKeyboard())
_blinkCursorTimer.start(std::chrono::milliseconds(CURSOR_BLINK_INTERVAL));
if (!blink && _blinkCursorTimer.isActive()) {
@ -306,9 +306,28 @@ void TerminalView::blinkCursorEvent()
requestPaint();
}
void TerminalView::blinkCursorTimeout()
{
// Without the keyboard the cursor shows in its unfocused state; the next
// paint with it starts blinking again.
if (!hasKeyboard()) {
_blinkCursorTimer.stop();
if (_cursorBlinking)
blinkCursorEvent();
return;
}
blinkCursorEvent();
}
bool TerminalView::hasKeyboard() const
{
const ui::Window* window = this->window();
return hasFocus() && window->hasKeyboardFocus();
}
void TerminalView::focusIn(ui::FocusReason)
{
if (_hasBlinkingCursor)
if (_hasBlinkingCursor && hasKeyboard())
_blinkCursorTimer.start(std::chrono::milliseconds(CURSOR_BLINK_INTERVAL));
requestPaint();
@ -2087,6 +2106,15 @@ static void addOtherLineChar(FramePainter& frame, double left, double top, int w
// Mirrors TerminalGpuNode::build(), which mirrored TerminalDisplay::paint().
void TerminalView::paint(ui::Painter& painter)
{
// The window repaints its focus view when the keyboard comes or goes.
if (hasKeyboard()) {
if (_hasBlinkingCursor && !_blinkCursorTimer.isActive())
_blinkCursorTimer.start(std::chrono::milliseconds(CURSOR_BLINK_INTERVAL));
} else if (_blinkCursorTimer.isActive()) {
_blinkCursorTimer.stop();
_cursorBlinking = false;
}
if (_image.empty() || geometry().width <= 0 || geometry().height <= 0)
return;

@ -100,6 +100,7 @@ public:
void setTerminalFont(const std::string& family, double pointSize);
void setBlinkingCursor(bool blink);
bool isCursorBlinking() const { return _blinkCursorTimer.isActive(); }
void setTerminalCursorShape(int shape);
void setBellMode(int mode) { _bellMode = mode; }
void setConfirmMultilinePaste(bool confirm) { _confirmMultilinePaste = confirm; }
@ -229,6 +230,8 @@ private:
int drawnLines() const;
void blinkEvent();
void blinkCursorEvent();
void blinkCursorTimeout();
bool hasKeyboard() const;
void restartCursorBlink();
void bell();
void swapColorTable();

@ -21,6 +21,7 @@
#include "TerminalFont.h"
#include "TerminalSession.h"
#include "TerminalView.h"
#include "tools.h"
#include "terminalpage.h"
@ -153,6 +154,48 @@ TEST_F(WindowTest, CloseOtherTabsAfterTheKeptTabEnded)
EXPECT_TRUE(busy->isVisible());
}
TEST_F(WindowTest, CursorBlinksOnlyWithTheKeyboard)
{
Windows windows(m_settings);
TerminalWindow* window = windows.create(shell());
ui::Window& surface = window->window();
Konsole::TerminalView* terminal = window->currentPage()->terminal();
ASSERT_TRUE(terminal->hasFocus());
ui::TestInput::setKeyboardFocus(surface, true);
surface.grab();
EXPECT_TRUE(terminal->isCursorBlinking());
ui::TestInput::setKeyboardFocus(surface, false);
surface.grab();
EXPECT_FALSE(terminal->isCursorBlinking());
ui::TestInput::setKeyboardFocus(surface, true);
surface.grab();
EXPECT_TRUE(terminal->isCursorBlinking());
// Without a frame drawn, the next blink stops the timer.
ui::TestInput::setKeyboardFocus(surface, false);
EXPECT_TRUE(waitFor([&] { return !terminal->isCursorBlinking(); }));
}
TEST_F(WindowTest, CursorWithoutBlinkingNeverStartsTheTimer)
{
m_settings.setBlinkingCursor(false);
Windows windows(m_settings);
TerminalWindow* window = windows.create(shell());
ui::Window& surface = window->window();
Konsole::TerminalView* terminal = window->currentPage()->terminal();
ui::TestInput::setKeyboardFocus(surface, true);
surface.grab();
EXPECT_FALSE(terminal->isCursorBlinking());
ui::TestInput::setKeyboardFocus(surface, false);
surface.grab();
EXPECT_FALSE(terminal->isCursorBlinking());
}
namespace {
class Canvas : public ui::View

Loading…
Cancel
Save