From 6d1f8bbb32425e140aa857305f17def7f835430e Mon Sep 17 00:00:00 2001 From: tsujan Date: Sat, 8 Feb 2025 01:24:02 +0330 Subject: [PATCH] Added mouse cursor auto-hiding to `QTermWidget` (#582) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mouse cursor auto-hiding was implemented by @luebking: https://github.com/lxqt/qtermwidget/commit/b150d8503cf8694d2cb5a87a0617d7c5fc5eb4b0 Apart from adding mouse auto-hiding to `QTermWidget`, this patch fixes two issues of the above implementation: 1. `focusInEvent` and `focusOutEvent` weren't good for controlling auto-hiding, because the hidden mouse cursor can be near other widgets of the app (tab, menu-bar, …), in which case, it wasn't shown when put on them. Therefore, `enterEvent`, and `leaveEvent` are used instead. 2. The scrollbar needed a separate handling because it's a child of `TerminalDisplay`. NOTE: A related PR for QTerminal will follow this one. --- lib/TerminalDisplay.cpp | 55 +++++++++++++++++++++++++++---------- lib/TerminalDisplay.h | 30 ++++++++++++++------ lib/qtermwidget.cpp | 6 +++- lib/qtermwidget.h | 2 ++ lib/qtermwidget_interface.h | 1 + 5 files changed, 69 insertions(+), 25 deletions(-) diff --git a/lib/TerminalDisplay.cpp b/lib/TerminalDisplay.cpp index 11352ea0..0fbcc1c0 100644 --- a/lib/TerminalDisplay.cpp +++ b/lib/TerminalDisplay.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -397,7 +396,7 @@ TerminalDisplay::TerminalDisplay(QWidget *parent) // create scroll bar for scrolling output up and down // set the scroll bar's slider to occupy the whole area of the scroll bar initially - _scrollBar = new QScrollBar(this); + _scrollBar = new ScrollBar(this); // since the contrast with the terminal background may not be enough, // the scrollbar should be auto-filled if not transient if (!_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) @@ -1374,11 +1373,6 @@ void TerminalDisplay::focusOutEvent(QFocusEvent*) blinkEvent(); _blinkTimer->stop(); - if (gs_deadSpot.x() > -1 && QApplication::activeWindow()) // we lost the focus internally - { - gs_deadSpot = QPoint(-1,-1); - QApplication::restoreOverrideCursor(); - } } void TerminalDisplay::focusInEvent(QFocusEvent*) { @@ -1391,12 +1385,28 @@ void TerminalDisplay::focusInEvent(QFocusEvent*) if (_hasBlinker) _blinkTimer->start(); +} - if (gs_deadSpot.x() < 0 && _hideMouseTimer) - { - gs_futureDeadSpot = mapFromGlobal(QCursor::pos()); - _hideMouseTimer->start(_mouseAutohideDelay); - } +void TerminalDisplay::enterEvent(QEnterEvent* event) +{ + if (gs_deadSpot.x() < 0 && _hideMouseTimer + // NOTE: scrollBar->underMouse() doesn't work here + && !_scrollBar->rect().contains(_scrollBar->mapFromParent(event->position().toPoint()))) + { + gs_futureDeadSpot = event->position().toPoint(); + _hideMouseTimer->start(_mouseAutohideDelay); + } + QWidget::enterEvent(event); +} + +void TerminalDisplay::leaveEvent(QEvent* event) +{ + if (gs_deadSpot.x() > -1) + { + gs_deadSpot = QPoint(-1,-1); + QApplication::restoreOverrideCursor(); + } + QWidget::leaveEvent(event); } void TerminalDisplay::paintEvent( QPaintEvent* pe ) @@ -2155,6 +2165,8 @@ void TerminalDisplay::hideStaleMouse() const return; if (QApplication::activeWindow() && QApplication::activeWindow() != window()) // some other app window has the focus return; + if (_scrollBar->underMouse()) // the mouse is over the scrollbar + return; gs_deadSpot = gs_futureDeadSpot; QApplication::setOverrideCursor(Qt::BlankCursor); } @@ -2187,7 +2199,7 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) gs_deadSpot = QPoint(-1,-1); QApplication::restoreOverrideCursor(); } - gs_futureDeadSpot = ev->pos(); + gs_futureDeadSpot = ev->position().toPoint(); Q_ASSERT(_hideMouseTimer); _hideMouseTimer->start(_mouseAutohideDelay); } @@ -2199,7 +2211,7 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) && !_scrollBar->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, _scrollBar)) ? _scrollBar->width() : 0); - getCharacterPosition(ev->pos(),charLine,charColumn); + getCharacterPosition(ev->position().toPoint(),charLine,charColumn); // handle filters // change link hot-spot appearance on mouse-over @@ -2299,7 +2311,7 @@ void TerminalDisplay::mouseMoveEvent(QMouseEvent* ev) // don't extend selection while pasting if (ev->buttons() & Qt::MiddleButton) return; - extendSelection( ev->pos() ); + extendSelection(ev->position().toPoint()); } void TerminalDisplay::extendSelection( const QPoint& position ) @@ -3543,4 +3555,17 @@ bool AutoScrollHandler::eventFilter(QObject* watched,QEvent* event) return false; } +ScrollBar::ScrollBar(QWidget* parent) : QScrollBar(parent) {} + +void ScrollBar::enterEvent(QEnterEvent* event) +{ + // show the mouse cursor that was auto-hidden + if (gs_deadSpot.x() > -1) + { + gs_deadSpot = QPoint(-1,-1); + QApplication::restoreOverrideCursor(); + } + QScrollBar::enterEvent(event); +} + //#include "TerminalDisplay.moc" diff --git a/lib/TerminalDisplay.h b/lib/TerminalDisplay.h index a4d35749..4c6d2201 100644 --- a/lib/TerminalDisplay.h +++ b/lib/TerminalDisplay.h @@ -24,7 +24,7 @@ // Qt #include #include -#include +#include // Konsole #include "Filter.h" @@ -41,7 +41,6 @@ class QTimer; class QEvent; class QGridLayout; class QKeyEvent; -class QScrollBar; class QShowEvent; class QHideEvent; class QTimerEvent; @@ -73,6 +72,7 @@ namespace Konsole extern unsigned short vt100_graphics[32]; class ScreenWindow; +class ScrollBar; /** * A widget which displays output from a terminal emulation and sends input keypresses and mouse activity @@ -435,6 +435,12 @@ class KONSOLEPRIVATE_EXPORT TerminalDisplay : public QWidget int mouseAutohideDelay() const { return _mouseAutohideDelay; } + /** + * hide the mouse cursor after @param delay milliseconds of inactivity + * @param delay < 0 deactivates the behavior + */ + void autoHideMouseAfter(int delay); + public slots: /** @@ -528,12 +534,6 @@ public slots: */ void setForegroundColor(const QColor& color); - /** - * hide the mouse cursor after @param delay milliseconds of inactivity - * @param delay < 0 deactivates the behavior - */ - void autoHideMouseAfter(int delay); - void selectionChanged(); signals: @@ -596,6 +596,8 @@ public slots: virtual void fontChange(const QFont &font); void focusInEvent(QFocusEvent* event) override; void focusOutEvent(QFocusEvent* event) override; + void enterEvent(QEnterEvent* event) override; + void leaveEvent(QEvent* event) override; void keyPressEvent(QKeyEvent* event) override; void mouseDoubleClickEvent(QMouseEvent* ev) override; void mousePressEvent( QMouseEvent* ) override; @@ -795,7 +797,7 @@ private slots: bool _columnSelectionMode; QClipboard* _clipboard; - QScrollBar* _scrollBar; + ScrollBar* _scrollBar; QTermWidget::ScrollBarPosition _scrollbarLocation; QString _wordCharacters; int _bellMode; @@ -896,6 +898,16 @@ Q_OBJECT int _timerId; }; +class ScrollBar : public QScrollBar +{ +Q_OBJECT + +public: + ScrollBar(QWidget* parent = nullptr); +protected: + void enterEvent(QEnterEvent* event) override; +}; + } #endif // TERMINALDISPLAY_H diff --git a/lib/qtermwidget.cpp b/lib/qtermwidget.cpp index 6f7e707e..63fd761d 100644 --- a/lib/qtermwidget.cpp +++ b/lib/qtermwidget.cpp @@ -832,8 +832,12 @@ void QTermWidget::setWordCharacters(const QString& chars) m_impl->m_terminalDisplay->setWordCharacters(chars); } - QTermWidgetInterface* QTermWidget::createWidget(int startnow) const { return new QTermWidget(startnow); } + +void QTermWidget::autoHideMouseAfter(int delay) +{ + m_impl->m_terminalDisplay->autoHideMouseAfter(delay); +} diff --git a/lib/qtermwidget.h b/lib/qtermwidget.h index 10942dc6..fe057222 100644 --- a/lib/qtermwidget.h +++ b/lib/qtermwidget.h @@ -259,6 +259,8 @@ class QTERMWIDGET_EXPORT QTermWidget : public QWidget, public QTermWidgetInterfa void setWordCharacters(const QString& chars) override; QTermWidgetInterface *createWidget(int startnow) const override; + + void autoHideMouseAfter(int delay) override; signals: void finished(); void copyAvailable(bool); diff --git a/lib/qtermwidget_interface.h b/lib/qtermwidget_interface.h index 2ea83af6..13d5a333 100644 --- a/lib/qtermwidget_interface.h +++ b/lib/qtermwidget_interface.h @@ -101,6 +101,7 @@ class QTermWidgetInterface { virtual QString wordCharacters() const = 0; virtual void setWordCharacters(const QString& chars) = 0; virtual QTermWidgetInterface* createWidget(int startnow) const = 0; + virtual void autoHideMouseAfter(int delay) = 0; }; #define QTermWidgetInterface_iid "lxqt.qtermwidget.QTermWidgetInterface/1.5"