From d66aa35254abe27790e08946f484a0575756a2f5 Mon Sep 17 00:00:00 2001 From: Jay Nabonne Date: Mon, 10 Jun 2019 15:33:31 +0100 Subject: [PATCH] Fix handling captured mouse events in a window with scrollbars Handle some mouse events explicitly when a wxQtScrollArea is set as "mouse captured". The issue arises in that the QScrollArea has two methods: event() and viewportEvent(). Normally a "QAbstractScrollAreaFilter" is set up by Qt which routes any events to the viewportEvent() method. And the normal event() method throws mouse events away (for reasons I'm not aware of - but it is what it is). If a wx window with a scroll area (e.g. wxRichTextCtrl) sets capture, the wxQtScrollArea (QScroll-derived) gets set as the direct "mouse grabber", and all events then bypass the filter and are sent directly to the "event" method, which throws them away. The typical result is that the window setting capture no longer gets mouse events, it keeps capture since it's looking for a mouse up that never comes, and the app more or less locks up since all mouse events are being effectively discarded. This change catches any event that comes in via the event() method and, when the mouse is captured by the widget, forwards it on to the viewportEvent method instead, performing what the filter would do via the normal event routing. It doesn't forward on "mouse press" events because the initial event that causes the capture ends up being fed back again, resulting in a "captured twice" error. The underlying reason I can see for this "being fed back again" is that, for some inexplicable reason, the wxRichTextCtrl "skips" the event even though it has actually processed it and taken capture. That means this solution isn't 100%, but it does fix the 99%+ cases where the capture is only gotten to redirect mouse moves and button ups. Perhaps an alternative solution might be to stop grabbing the mouse in wxQtScrollArea, but this would require more changes. Closes https://github.com/wxWidgets/wxWidgets/pull/1346 --- src/qt/window.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/qt/window.cpp b/src/qt/window.cpp index 43bec0e3e9..4410308d7e 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -59,9 +59,10 @@ wxQtWidget::wxQtWidget( wxWindowQt *parent, wxWindowQt *handler ) class wxQtScrollArea : public wxQtEventSignalHandler< QScrollArea, wxWindowQt > { +public: + wxQtScrollArea(wxWindowQt *parent, wxWindowQt *handler); - public: - wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ); + bool event(QEvent *e) wxOVERRIDE; }; wxQtScrollArea::wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ) @@ -69,6 +70,27 @@ wxQtScrollArea::wxQtScrollArea( wxWindowQt *parent, wxWindowQt *handler ) { } +bool wxQtScrollArea::event(QEvent *e) +{ + wxWindowQt* handler = GetHandler(); + if ( handler && handler->HasCapture() ) + { + switch ( e->type() ) + { + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::Wheel: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + return viewportEvent(e); + default: + break; + } + } + return QScrollArea::event(e); +} + class wxQtInternalScrollBar : public wxQtEventSignalHandler< QScrollBar, wxWindowQt > { public: