diff options
Diffstat (limited to 'src/gui/kernel/qt_cocoa_helpers_mac.mm')
-rw-r--r-- | src/gui/kernel/qt_cocoa_helpers_mac.mm | 105 |
1 files changed, 51 insertions, 54 deletions
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index ddbf53f..c8132e8 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -1060,30 +1060,26 @@ QWidget *qt_mac_getTargetForMouseEvent( returnGlobalPoint = flipPoint([NSEvent mouseLocation]).toPoint(); QWidget *mouseGrabber = QWidget::mouseGrabber(); bool buttonDownNotBlockedByModal = qt_button_down && !QApplicationPrivate::isBlockedByModal(qt_button_down); + QWidget *popup = QApplication::activePopupWidget(); // Resolve the widget under the mouse: QWidget *widgetUnderMouse = 0; - if (nativeWidget) { + if (popup || qt_button_down || !nativeWidget || !nativeWidget->isVisible()) { + // Using QApplication::widgetAt for finding the widget under the mouse + // is most safe, since it ignores cocoas own mouse down redirections (which + // we need to be prepared for when using nativeWidget as starting point). + // (the only exception is for QMacNativeWidget, where QApplication::widgetAt fails). + // But it is also slower (I guess), so we try to avoid it and use nativeWidget if we can: + widgetUnderMouse = QApplication::widgetAt(returnGlobalPoint); + } + + if (!widgetUnderMouse && nativeWidget) { + // Entering here should be the common case. We + // also handle the QMacNativeWidget fallback case. QPoint p = nativeWidget->mapFromGlobal(returnGlobalPoint); widgetUnderMouse = nativeWidget->childAt(p); - if (!widgetUnderMouse){ - // Cocoa will redirct mouse event to the current - // mouse down widget, which is not what we want for our - // widgetUnderMouse assignment. So we need to check - // if we are actually inside nativeView: - if (nativeWidget->rect().contains(p)) { - widgetUnderMouse = nativeWidget; - } else { - // Ok, fallback to find the widget under mouse ourselves. - widgetUnderMouse = QApplication::widgetAt(returnGlobalPoint); - } - } - } else { - // Calling QApplication::widgetAt is potentially slow, hence the - // reason we avoid it if we can. So supplying a nativeWidget to - // this function is mostly an optimization. But at the same time, - // calling QApplication::widgetAt fails for QMacNativeWidget... - widgetUnderMouse = QApplication::widgetAt(returnGlobalPoint); + if (!widgetUnderMouse && nativeWidget->rect().contains(p)) + widgetUnderMouse = nativeWidget; } if (widgetUnderMouse) { @@ -1107,23 +1103,27 @@ QWidget *qt_mac_getTargetForMouseEvent( if (returnWidgetUnderMouse) *returnWidgetUnderMouse = widgetUnderMouse; - // Resolve the target for the mouse event. Default will be widgetUnderMouse, except - // if there is a popup-"grab", mousegrab, or button-down-"grab": - QWidget *popup = QApplication::activePopupWidget(); + // Resolve the target for the mouse event. Default will be + // widgetUnderMouse, except if there is a grab (popup/mouse/button-down): if (popup && !mouseGrabber) { - if (!popup->isAncestorOf(widgetUnderMouse)) { - // The popup will always grab the mouse unless the - // mouse is over a child, or the user scrolls: + // We special case handling of popups, since they have an implicitt mouse grab. + QWidget *candidate = buttonDownNotBlockedByModal ? qt_button_down : widgetUnderMouse; + if (!popup->isAncestorOf(candidate)) { + // INVARIANT: we have a popup, but the candidate is not + // in it. But the popup will grab the mouse anyway, + // except if the user scrolls: if (eventType == QEvent::Wheel) return 0; returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint); return popup; - } else if (popup == widgetUnderMouse) { + } else if (popup == candidate) { + // INVARIANT: The candidate is the popup itself, and not a child: returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint); return popup; } else { - returnLocalPoint = widgetUnderMouse->mapFromGlobal(returnGlobalPoint); - return widgetUnderMouse; + // INVARIANT: The candidate is a child inside the popup: + returnLocalPoint = candidate->mapFromGlobal(returnGlobalPoint); + return candidate; } } @@ -1139,6 +1139,8 @@ QWidget *qt_mac_getTargetForMouseEvent( return target; } +QPointer<QWidget> qt_last_native_mouse_receiver = 0; + static inline void qt_mac_checkEnterLeaveForNativeWidgets(QWidget *maybeEnterWidget) { // Dispatch enter/leave for the cases where QApplicationPrivate::sendMouseEvent do @@ -1149,29 +1151,25 @@ static inline void qt_mac_checkEnterLeaveForNativeWidgets(QWidget *maybeEnterWid if (qt_button_down || QWidget::mouseGrabber()) return; - if ((maybeEnterWidget == qt_last_mouse_receiver) && qt_last_mouse_receiver) - return; + if ((maybeEnterWidget == qt_last_native_mouse_receiver) && qt_last_native_mouse_receiver) + return; if (maybeEnterWidget) { - if (!qt_last_mouse_receiver) { + if (!qt_last_native_mouse_receiver) { // case 3 QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, 0); - qt_last_mouse_receiver = maybeEnterWidget; - } else if (qt_last_mouse_receiver->internalWinId() && maybeEnterWidget->internalWinId()) { + qt_last_native_mouse_receiver = maybeEnterWidget->internalWinId() ? maybeEnterWidget : maybeEnterWidget->nativeParentWidget(); + } else if (maybeEnterWidget->internalWinId()) { // case 1 - if (qt_last_mouse_receiver->isVisible()) { - QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, qt_last_mouse_receiver); - qt_last_mouse_receiver = maybeEnterWidget; - } + QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, qt_last_native_mouse_receiver); + qt_last_native_mouse_receiver = maybeEnterWidget->internalWinId() ? maybeEnterWidget : maybeEnterWidget->nativeParentWidget(); } // else at lest one of the widgets are alien, so enter/leave will be handled in QApplicationPrivate } else { - if (qt_last_mouse_receiver && qt_last_mouse_receiver->internalWinId()) { + if (qt_last_native_mouse_receiver) { // case 2 - QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver); - // This seems to be the only case where we need to update qt_last_mouse_receiver - // from the mac specific code. Otherwise, QApplicationPrivate::sendMouseEvent - // will handle it: + QApplicationPrivate::dispatchEnterLeave(0, qt_last_native_mouse_receiver); qt_last_mouse_receiver = 0; + qt_last_native_mouse_receiver = 0; } } } @@ -1192,16 +1190,14 @@ bool qt_mac_handleMouseEvent(NSEvent *event, QEvent::Type eventType, Qt::MouseBu if (!widgetToGetMouse) return false; - if (!nativeWidget) { - // Path typically taken for mouse moves (send - // directly from [QCocoaWindow sendEvent] - if (!widgetUnderMouse) - return false; - nativeWidget = widgetUnderMouse->internalWinId() ? - widgetUnderMouse : widgetUnderMouse->nativeParentWidget(); - if (!nativeWidget) - return false; - } + // From here on, we let nativeWidget actually be the native widget under widgetUnderMouse. The reason + // for this, is that qt_mac_getTargetForMouseEvent will set cocoa's mouse event redirection aside when + // determining which widget is under the mouse (in other words, it will usually ignore nativeWidget). + // nativeWidget will be used in QApplicationPrivate::sendMouseEvent to correctly dispatch enter/leave events. + if (widgetUnderMouse) + nativeWidget = widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget(); + if (!nativeWidget) + return false; NSView *view = qt_mac_effectiveview_for(nativeWidget); // Handle tablet events (if any) first. @@ -1278,8 +1274,9 @@ bool qt_mac_handleMouseEvent(NSEvent *event, QEvent::Type eventType, Qt::MouseBu if (eventType == QEvent::MouseButtonRelease) { // A mouse button was released, which means that the implicit grab was // released. We therefore need to re-check if should send (delayed) enter leave events: - // qt_button_down has now become NULL since the call at the top of the function. - widgetToGetMouse = qt_mac_getTargetForMouseEvent(0, QEvent::None, localPoint, globalPoint, nativeWidget, &widgetUnderMouse); + // qt_button_down has now become NULL since the call at the top of the function. Also, since + // the relase might have closed a window, we dont give the nativeWidget hint + qt_mac_getTargetForMouseEvent(0, QEvent::None, localPoint, globalPoint, nativeWidget, &widgetUnderMouse); qt_mac_checkEnterLeaveForNativeWidgets(widgetUnderMouse); } |