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
This commit is contained in:
Jay Nabonne
2019-06-10 15:33:31 +01:00
committed by Vadim Zeitlin
parent 5a228ceb91
commit d66aa35254

View File

@@ -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: