From 416941b7141ee6c81cc1f92592f24bcb426d51e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Javier=20Merino=20Mor=C3=A1n?= Date: Wed, 1 Jun 2022 18:21:27 +0200 Subject: [PATCH] Snapshot session on focus, key press and output Before 3d6c839b, sessions were snapshotted every 2 seconds, and also half a second after the associated view received focus or a key press. This second timer could theoretically be postponed indefinitely. Commit 3d6c839b tries to save energy by not taking a snapshot every 2 seconds, and instead has a timer that fires half a second after any event received by the application. This commit goes back to the old behavior, but still without the 2 second timer, and also sets the half second timer after receiving the Emulation::outputChanged signal, which is sent at a maximum 40ms after the emulation receives data. It also copies the idea from commit 3d6c839b of not restarting the timer if it's already started, since otherwise, continuous output could postpone the timer indefinitely. --- src/session/SessionController.cpp | 51 ++++++++++++++----------------- src/session/SessionController.h | 7 ++--- 2 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/session/SessionController.cpp b/src/session/SessionController.cpp index f6e2a32a..0671af69 100644 --- a/src/session/SessionController.cpp +++ b/src/session/SessionController.cpp @@ -114,7 +114,7 @@ SessionController::SessionController(Session *sessionParam, TerminalDisplay *vie , _findAction(nullptr) , _findNextAction(nullptr) , _findPreviousAction(nullptr) - , _snapshotTimer(nullptr) + , _interactionTimer(nullptr) , _searchStartLine(0) , _prevSearchResultLine(0) , _codecAction(nullptr) @@ -209,18 +209,22 @@ SessionController::SessionController(Session *sessionParam, TerminalDisplay *vie connect(session(), &Konsole::Session::flowControlEnabledChanged, view(), &Konsole::TerminalDisplay::setFlowControlWarningEnabled); view()->setFlowControlWarningEnabled(session()->flowControlEnabled()); - // take a snapshot of the session state shortly after any event occurs + // take a snapshot of the session state every so often when + // user activity occurs // - // Don't link the timer with the session or we will have an use after - // free in SessionController::eventFilter - _snapshotTimer = new QTimer(nullptr); - _snapshotTimer->setSingleShot(true); - _snapshotTimer->setInterval(500); - connect(_snapshotTimer, &QTimer::timeout, this, &Konsole::SessionController::snapshot); - // Install an event handler on QCoreApplication - // This will catch all events: key strokes, mouse moves/clicks... - // but also all changes that occur in all tabs - QCoreApplication::instance()->installEventFilter(this); + // the timer is owned by the session so that it will be destroyed along + // with the session + _interactionTimer = new QTimer(session()); + _interactionTimer->setSingleShot(true); + _interactionTimer->setInterval(2000); + connect(_interactionTimer, &QTimer::timeout, this, &Konsole::SessionController::snapshot); + connect(view(), &Konsole::TerminalDisplay::compositeFocusChanged, this, [this](bool focused) { + if (focused) { + interactionHandler(); + } + }); + connect(view(), &Konsole::TerminalDisplay::keyPressedSignal, this, &Konsole::SessionController::interactionHandler); + connect(session()->emulation(), &Konsole::Emulation::outputChanged, this, &Konsole::SessionController::interactionHandler); // xterm '10;?' request connect(session(), &Konsole::Session::getForegroundColor, this, &Konsole::SessionController::sendForegroundColor); @@ -245,8 +249,6 @@ SessionController::SessionController(Session *sessionParam, TerminalDisplay *vie SessionController::~SessionController() { - QCoreApplication::instance()->removeEventFilter(this); - delete _snapshotTimer; _allControllers.remove(this); if (factory() != nullptr) { @@ -309,6 +311,13 @@ void SessionController::viewFocusChangeHandler(bool focused) } } +void SessionController::interactionHandler() +{ + if (!_interactionTimer->isActive()) { + _interactionTimer->start(); + } +} + void SessionController::snapshot() { Q_ASSERT(!session().isNull()); @@ -1325,20 +1334,6 @@ void SessionController::searchClosed() searchHistory(false); } -bool SessionController::eventFilter(QObject *obj, QEvent *event) -{ - // Forward event to super class - bool ret = ViewProperties::eventFilter(obj, event); - - // Start the snapshot timer if: - // - it is not already started - // - the event is not a timer timeout - if(!_snapshotTimer->isActive() && event->type() != QEvent::Timer) { - _snapshotTimer->start(); - } - return ret; -} - void SessionController::updateFilterList(const Profile::Ptr &profile) { if (profile != SessionManager::instance()->sessionProfile(session())) { diff --git a/src/session/SessionController.h b/src/session/SessionController.h index bb3ceb36..39eb5637 100644 --- a/src/session/SessionController.h +++ b/src/session/SessionController.h @@ -219,10 +219,6 @@ public Q_SLOTS: /** Close the incremental search */ void searchClosed(); // called when the user clicks on the -protected: - /** Start snapshot timer if needed */ - bool eventFilter(QObject *obj, QEvent *event) override; - private Q_SLOTS: // menu item handlers void openBrowser(); @@ -284,6 +280,7 @@ private Q_SLOTS: const QExplicitlySharedDataPointer &profile); // Called when the profile has changed, so we might need to change the list of filters void viewFocusChangeHandler(bool focused); + void interactionHandler(); void snapshot(); // called periodically as the user types // to take a snapshot of the state of the // foreground process in the terminal @@ -344,7 +341,7 @@ private: QAction *_findNextAction; QAction *_findPreviousAction; - QTimer *_snapshotTimer; + QTimer *_interactionTimer; int _searchStartLine; int _prevSearchResultLine;