summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel/qt_cocoa_helpers_mac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel/qt_cocoa_helpers_mac.mm')
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm105
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);
}