Skip to content

Commit

Permalink
QXcbWindow::handleLeaveNotifyEvent(): Consume when leaving geometry
Browse files Browse the repository at this point in the history
QXcbConnection::mousePressWindow() returns the XCB toplevel window,
which has consumed the window system's last mouse press. When the
function returns a valid pointer, QXcbWindow::handleLeaveNotifyEvent()
didn't propagate the leave event to QWSI::handleLeaveEvent(). Instead,
the leave event was ingored.

That behavior is correct, e.g. when a button on the main window is
pressed and the mouse hovers away from the button, with the mouse
button continuously being pressed. It is not correct, if the mouse
cursor leaves the main window.

=> Ignore the leave event only as long as the mouse cursor remains
within mousePressWindow()->geometry().
=> Deliver the leave event, when the mouse cursor leaves the window.

Fixes: QTBUG-119864
Pick-to: 6.6 6.5 6.2 5.15
Change-Id: I30a6ebedcd148285b9f17dfd87885ff67726b54c
Reviewed-by: Liang Qi <liang.qi@qt.io>
(cherry picked from commit ec24b36)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
  • Loading branch information
ASpoerl authored and Qt Cherry-pick Bot committed Feb 17, 2024
1 parent 7874fc1 commit 39e9b6b
Showing 1 changed file with 14 additions and 5 deletions.
19 changes: 14 additions & 5 deletions src/plugins/platforms/xcb/qxcbwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1981,10 +1981,15 @@ static inline bool doCheckUnGrabAncestor(QXcbConnection *conn)
return true;
}

static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn = nullptr)
static bool windowContainsGlobalPoint(QXcbWindow *window, int x, int y)
{
return window ? window->geometry().contains(window->mapFromGlobal(QPoint(x, y))) : false;
}

static bool ignoreLeaveEvent(quint8 mode, quint8 detail, QXcbConnection *conn)
{
return ((doCheckUnGrabAncestor(conn)
&& mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
&& mode == XCB_NOTIFY_MODE_GRAB && detail == XCB_NOTIFY_DETAIL_ANCESTOR)
|| (mode == XCB_NOTIFY_MODE_UNGRAB && detail == XCB_NOTIFY_DETAIL_INFERIOR)
|| detail == XCB_NOTIFY_DETAIL_VIRTUAL
|| detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL);
Expand All @@ -2004,14 +2009,13 @@ void QXcbWindow::handleEnterNotifyEvent(int event_x, int event_y, int root_x, in
{
connection()->setTime(timestamp);

const QPoint global = QPoint(root_x, root_y);

if (ignoreEnterEvent(mode, detail, connection()) || connection()->mousePressWindow())
return;

// Updates scroll valuators, as user might have done some scrolling outside our X client.
connection()->xi2UpdateScrollingDevices();

const QPoint global = QPoint(root_x, root_y);
const QPoint local(event_x, event_y);
QWindowSystemInterface::handleEnterEvent(window(), local, global);
}
Expand All @@ -2021,8 +2025,11 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
{
connection()->setTime(timestamp);

if (ignoreLeaveEvent(mode, detail, connection()) || connection()->mousePressWindow())
QXcbWindow *mousePressWindow = connection()->mousePressWindow();
if (ignoreLeaveEvent(mode, detail, connection())
|| (mousePressWindow && windowContainsGlobalPoint(mousePressWindow, root_x, root_y))) {
return;
}

// check if enter event is buffered
auto event = connection()->eventQueue()->peek([](xcb_generic_event_t *event, int type) {
Expand All @@ -2040,6 +2047,8 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y,
QWindowSystemInterface::handleEnterLeaveEvent(enterWindow->window(), window(), local, global);
} else {
QWindowSystemInterface::handleLeaveEvent(window());
if (!windowContainsGlobalPoint(this, root_x, root_y))
connection()->setMousePressWindow(nullptr);
}

free(enter);
Expand Down

0 comments on commit 39e9b6b

Please sign in to comment.