From f0c6354a38d58251051f389fe703dba553deec37 Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Thu, 5 Sep 2024 11:26:23 +0200 Subject: [PATCH] QGuiApplication: don't send pointer events to windows other than the active popup If a popup is visible, we're not supposed to send pointer events to other windows than the popup. It doesn't matter if the popup doesn't want it. But currently we end up doing so anyway, which mean that we would trigger items elsewhere in the UI. This patch will instead make sure that always return from processMouseEvent() after sending, or forwarding, it to the active popup. Note: some styles in Controls (e.g macOS) has a menu window that is actually substantially bigger than what it appears like on screen (to make room for a drop-shadow). This means that a mouse press can happen outside the visual borders of the menu, but still inside the popup window that contains it. And this is also a reason why some bugs related to forwarding of mouse events only surfaced on some platforms (Ubuntu), but not on others (macOS). E.g for a Menu in a MenuBar, the menu window on macOS would actually be placed on top of the MenuBar and block pointer events from reaching it (because of the menu shadow). While on Ubuntu, since the menu has no shadow, the press would instead trigger the MenuItem in the MenuBar. But by never forwarding pointer events to windows other than the active popup, such differences will never happen. Note: we should actually forward pointer events to the window under the mouse if QPlatformIntegration::ReplayMousePressOutsidePopup is set (and WA_NoMouseReplay is not set). But this API is currently not reimplemented after QGuiApplication was refactored to support popup windows also in Qt Quick. And ReplayMousePressOutsidePopup seems to be false on all platforms other than Windows. Change-Id: I55692cf2cae4c8f9e46976b105660bca96bd65e6 Reviewed-by: Shawn Rutledge Reviewed-by: Oliver Eftevaag (cherry picked from commit fc9af570507bf067a182ab3f1c2f51a29f59e38c) Reviewed-by: Qt Cherry-pick Bot --- src/gui/kernel/qguiapplication.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index e0cee816454..c89b67b1c30 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -2444,13 +2444,15 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo ev.setTimestamp(e->timestamp); if (activePopup && activePopup != window && (!popup_closed_on_press || type == QEvent::MouseButtonRelease)) { - // If the popup handles the event, we're done. auto *handlingPopup = window->d_func()->forwardToPopup(&ev, active_popup_on_press); - if (handlingPopup) { - if (type == QEvent::MouseButtonPress) - active_popup_on_press = handlingPopup; - return; - } + if (handlingPopup && ev.isBeginEvent()) + active_popup_on_press = handlingPopup; + // Regardless of whether the popup accepted the event or not, we return now so that we + // don't forward it to the window under the mouse instead. We're only supposed to + // do such forwarding if QPlatformIntegration::ReplayMousePressOutsidePopup is set, + // but support for that is currently not reimplemented (it needs to be done in + // conjunction with support for WA_NoMouseReplay). This is normally only wanted on Windows. + return; } if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) { @@ -2975,9 +2977,15 @@ void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::T tabletEvent.setTimestamp(e->timestamp); if (activePopup && activePopup != window) { - // If the popup handles the event, we're done. - if (window->d_func()->forwardToPopup(&tabletEvent, active_popup_on_press)) - return; + auto *handlingPopup = window->d_func()->forwardToPopup(&tabletEvent, active_popup_on_press); + if (handlingPopup && tabletEvent.isBeginEvent()) + active_popup_on_press = handlingPopup; + // Regardless of whether the popup accepted the event or not, we return now so that we + // don't forward it to the window under the mouse instead. We're only supposed to + // do such forwarding if QPlatformIntegration::ReplayMousePressOutsidePopup is set, + // but support for that is currently not reimplemented (it needs to be done in + // conjunction with support for WA_NoMouseReplay). This is normally only wanted on Windows. + return; } QGuiApplication::sendSpontaneousEvent(window, &tabletEvent);