diff options
author | Samuel Rødal <samuel.rodal@digia.com> | 2012-11-23 15:10:39 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2012-11-23 17:04:00 +0100 |
commit | 9a90c2232f1e21b3f61da6c3a472380bcb996736 (patch) | |
tree | 847a47225586c523882ee6832ed44dd3c646b38d /src/plugins/platforms/xcb/qxcbwindow.cpp | |
parent | 1022c3ce9d445fd482a62309b9a6c52495c04a92 (diff) |
Fixed excessive enter/leave events being generated with the xcb plugin.
When we get a leave event we peek ahead in the queue to see if there's
an enter event already pending. If so we use
QWindowSystemInterface::handleEnterLeave() instead of two separate
window system interface events, so that you don't get leave and enter
events for the whole parent chain when moving the mouse cursor between
two neighbouring native child widgets.
We skip VIRTUAL events as they are generated for parent windows, and we
only care about the bottom-most window that is being entered / left. Qt
can take care of the rest since it knows the QWindow hierarchy.
We need to not skip leave events with detail set to INFERIOR, since Qt
expects to get a handleEnterLeave() when the mouse moves from a parent
window to a child window.
Task-number: QTBUG-27550
Change-Id: I7457d2e59d8b694081f2e43a16cd2e58d769624e
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbwindow.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 41 |
1 files changed, 39 insertions, 2 deletions
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index e0f5dbc435..5e4e749c83 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1561,6 +1561,29 @@ void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_times QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons, modifiers); } +class EnterEventChecker +{ +public: + bool checkEvent(xcb_generic_event_t *event) + { + if (!event) + return false; + if ((event->response_type & ~0x80) != XCB_ENTER_NOTIFY) + return false; + + xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)event; + + if ((enter->mode != XCB_NOTIFY_MODE_NORMAL && enter->mode != XCB_NOTIFY_MODE_UNGRAB) + || enter->detail == XCB_NOTIFY_DETAIL_VIRTUAL + || enter->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL) + { + return false; + } + + return true; + } +}; + void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) { connection()->setTime(event->time); @@ -1582,12 +1605,26 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) connection()->setTime(event->time); if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB) - || event->detail == XCB_NOTIFY_DETAIL_INFERIOR) + || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL + || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL) { return; } - QWindowSystemInterface::handleLeaveEvent(window()); + EnterEventChecker checker; + xcb_enter_notify_event_t *enter = (xcb_enter_notify_event_t *)connection()->checkEvent(checker); + QXcbWindow *enterWindow = enter ? connection()->platformWindowFromId(enter->event) : 0; + + if (enterWindow) { + QPoint local(enter->event_x, enter->event_y); + QPoint global(enter->root_x, enter->root_y); + + QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global); + } else { + QWindowSystemInterface::handleLeaveEvent(window()); + } + + free(enter); } void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) |