summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-09-08 14:57:37 +0200
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-09-13 19:14:29 +0200
commit73753ee3af58456bfccba8281bda19228aa98bd1 (patch)
treecd95895a31f550b4f8a18e443299f5fff038e74a /src
parent1093562d08f325bbbdcd60627eadae535779e376 (diff)
macOS: Don't close popups in Cocoa plugin for most mouse events
QWidget and QApplication handle popup closing for most events at the right time for the Qt-internal state logic. On other platforms popup QWindows are never closed automatically when clicking outside. So don't close any popups in the Cocoa plugin either, and let the Qt logic take care of it. This ensures that window activation is done at the right time, that Qt's modal popup stack is consistent, and that mouse replay for events closing a popup works. There are however two exceptions: mouse events in the window frame don't produce a QMouseEvent for Qt; and mouse events in a modally blocked (by Cocoa) window don't reach Qt at all. For those case, the logic in QWidget and QApplication is not enough. For the former, leave the change introduced in 70b94eea10d7af83cced092967 to explicitly close popups for LMB down in the frame. This still needs to happen before the event is delivered. For the latter case, deliver the event explicitly to Qt when we discover that the target window is modally blocked while a popup is active. The handleMouseEvent implementation then takes care of the redirect to the active popup, and Qt will further respect the modal stack in the QApplication::isWindowBlocked implementation. Change-Id: I578eb5e6aebc897a0ff1f69bc5c53bcaa05d138d Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h1
-rw-r--r--src/plugins/platforms/cocoa/qnsview_mouse.mm10
-rw-r--r--src/plugins/platforms/cocoa/qnswindow.mm12
3 files changed, 13 insertions, 10 deletions
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 3b318c6dd8..f4be8c466f 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -56,6 +56,7 @@ QT_DECLARE_NAMESPACED_OBJC_INTERFACE(QNSView, NSView
#if defined(__OBJC__)
@interface QNSView (MouseAPI)
+- (void)handleMouseEvent:(NSEvent *)theEvent;
- (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent;
- (bool)closePopups:(NSEvent *)theEvent;
- (void)resetMouseButtons;
diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm
index abafb8446f..9b2ff36c64 100644
--- a/src/plugins/platforms/cocoa/qnsview_mouse.mm
+++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm
@@ -446,16 +446,6 @@ static const QPointingDevice *pointingDeviceFor(qint64 deviceID)
return [super mouseDown:theEvent];
m_sendUpAsRightButton = false;
- // Handle any active poup windows; clicking outisde them should close them
- // all. Don't do anything or clicks inside one of the menus, let Cocoa
- // handle that case. Note that in practice many windows of the Qt::Popup type
- // will actually close themselves in this case using logic implemented in
- // that particular poup type (for example context menus). However, Qt expects
- // that plain popup QWindows will also be closed, so we implement the logic
- // here as well.
- if ([self closePopups:theEvent])
- return;
-
QPointF qtWindowPoint;
QPointF qtScreenPoint;
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint];
diff --git a/src/plugins/platforms/cocoa/qnswindow.mm b/src/plugins/platforms/cocoa/qnswindow.mm
index 9656d0e970..1fa11e2789 100644
--- a/src/plugins/platforms/cocoa/qnswindow.mm
+++ b/src/plugins/platforms/cocoa/qnswindow.mm
@@ -45,6 +45,7 @@
#include "qcocoawindow.h"
#include "qcocoahelpers.h"
#include "qcocoaeventdispatcher.h"
+#include "qcocoaintegration.h"
#include <qpa/qwindowsysteminterface.h>
#include <qoperatingsystemversion.h>
@@ -370,6 +371,17 @@ OSStatus CGSClearWindowTags(const CGSConnectionID, const CGSWindowID, int *, int
if (!m_platformWindow)
return; // Platform window went away while processing event
+ // Cocoa will not deliver mouse events to a window that is modally blocked (by Cocoa,
+ // not Qt). However, an active popup is expected to grab any mouse event within the
+ // application, so we need to handle those explicitly and trust Qt's isWindowBlocked
+ // implementation to eat events that shouldn't be delivered anyway.
+ if (isMouseEvent(theEvent) && QCocoaIntegration::instance()->activePopupWindow()
+ && QGuiApplicationPrivate::instance()->isWindowBlocked(m_platformWindow->window(), nullptr)) {
+ qCDebug(lcQpaWindow) << "Mouse event over modally blocked window" << m_platformWindow->window()
+ << "while popup" << QCocoaIntegration::instance()->activePopupWindow()
+ << "is open - redirecting";
+ [qnsview_cast(m_platformWindow->view()) handleMouseEvent:theEvent];
+ }
if (m_platformWindow->frameStrutEventsEnabled() && mouseEventInFrameStrut)
[qnsview_cast(m_platformWindow->view()) handleFrameStrutMouseEvent:theEvent];
}