diff options
author | Fabien Freling <fabien.freling@nokia.com> | 2011-02-23 14:08:26 (GMT) |
---|---|---|
committer | Fabien Freling <fabien.freling@nokia.com> | 2011-02-23 15:28:36 (GMT) |
commit | cf13f99d32df6c42c5d421da41ef35e815fb46ac (patch) | |
tree | 9a86876c54ac49c7b633407c8f7a416507ffe658 /src/gui/kernel/qt_cocoa_helpers_mac.mm | |
parent | 78c5c1cae5f9e100bfb7388f68208406f0db4b42 (diff) | |
parent | 0a24d2d6269d509e775f7da91c8002eddc2dcbd7 (diff) | |
download | Qt-cf13f99d32df6c42c5d421da41ef35e815fb46ac.zip Qt-cf13f99d32df6c42c5d421da41ef35e815fb46ac.tar.gz Qt-cf13f99d32df6c42c5d421da41ef35e815fb46ac.tar.bz2 |
Merge remote branch 'mainline/master' into merge_raster
Diffstat (limited to 'src/gui/kernel/qt_cocoa_helpers_mac.mm')
-rw-r--r-- | src/gui/kernel/qt_cocoa_helpers_mac.mm | 460 |
1 files changed, 333 insertions, 127 deletions
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm index f3e1c9a..d5a780c 100644 --- a/src/gui/kernel/qt_cocoa_helpers_mac.mm +++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -89,9 +89,16 @@ #include <private/qcocoaview_mac_p.h> #include <private/qkeymapper_p.h> #include <private/qwidget_p.h> +#include <private/qcocoawindow_mac_p.h> QT_BEGIN_NAMESPACE +#ifdef QT_MAC_USE_COCOA +// Cmd + left mousebutton should produce a right button +// press (mainly for mac users with one-button mice): +static bool qt_leftButtonIsRightButton = false; +#endif + Q_GLOBAL_STATIC(QMacWindowFader, macwindowFader); QMacWindowFader::QMacWindowFader() @@ -141,6 +148,9 @@ void QMacWindowFader::performFade() extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // qapplication.cpp; extern QWidget * mac_mouse_grabber; extern QWidget *qt_button_down; //qapplication_mac.cpp +extern QPointer<QWidget> qt_last_mouse_receiver; +extern OSViewRef qt_mac_effectiveview_for(const QWidget *w); +extern void qt_mac_updateCursorWithWidgetUnderMouse(QWidget *widgetUnderMouse); // qcursor_mac.mm void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds) { @@ -167,6 +177,70 @@ void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds) } } } +struct dndenum_mapper +{ + NSDragOperation mac_code; + Qt::DropAction qt_code; + bool Qt2Mac; +}; + +#ifdef QT_MAC_USE_COCOA && __OBJC__ + +static dndenum_mapper dnd_enums[] = { + { NSDragOperationLink, Qt::LinkAction, true }, + { NSDragOperationMove, Qt::MoveAction, true }, + { NSDragOperationCopy, Qt::CopyAction, true }, + { NSDragOperationGeneric, Qt::CopyAction, false }, + { NSDragOperationEvery, Qt::ActionMask, false }, + { NSDragOperationNone, Qt::IgnoreAction, false } +}; + +NSDragOperation qt_mac_mapDropAction(Qt::DropAction action) +{ + for (int i=0; dnd_enums[i].qt_code; i++) { + if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) { + return dnd_enums[i].mac_code; + } + } + return NSDragOperationNone; +} + +NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions) +{ + NSDragOperation nsActions = NSDragOperationNone; + for (int i=0; dnd_enums[i].qt_code; i++) { + if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code)) + nsActions |= dnd_enums[i].mac_code; + } + return nsActions; +} + +Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions) +{ + Qt::DropAction action = Qt::IgnoreAction; + for (int i=0; dnd_enums[i].mac_code; i++) { + if (nsActions & dnd_enums[i].mac_code) + return dnd_enums[i].qt_code; + } + return action; +} + +Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions) +{ + Qt::DropActions actions = Qt::IgnoreAction; + for (int i=0; dnd_enums[i].mac_code; i++) { + if (nsActions & dnd_enums[i].mac_code) + actions |= dnd_enums[i].qt_code; + } + return actions; +} + +Q_GLOBAL_STATIC(DnDParams, currentDnDParameters); +DnDParams *macCurrentDnDParameters() +{ + return currentDnDParameters(); +} +#endif bool macWindowIsTextured( void * /*OSWindowRef*/ window ) { @@ -301,7 +375,7 @@ bool qt_mac_checkForNativeSizeGrip(const QWidget *widget) HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(widget->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip); return (nativeSizeGrip != 0); #else - return [[reinterpret_cast<NSView *>(widget->winId()) window] showsResizeIndicator]; + return [[reinterpret_cast<NSView *>(widget->effectiveWinId()) window] showsResizeIndicator]; #endif } struct qt_mac_enum_mapper @@ -517,8 +591,12 @@ static const KeyPair entries[NumEntries] = { { NSNewlineCharacter, Qt::Key_Return }, { NSCarriageReturnCharacter, Qt::Key_Return }, { NSBackTabCharacter, Qt::Key_Backtab }, - { NSDeleteCharacter, Qt::Key_Delete }, { kEscapeCharCode, Qt::Key_Escape }, + // Cocoa sends us delete when pressing backspace! + // (NB when we reverse this list in qtKey2CocoaKey, there + // will be two indices of Qt::Key_Backspace. But is seems to work + // ok for menu shortcuts (which uses that function): + { NSDeleteCharacter, Qt::Key_Backspace }, { NSUpArrowFunctionKey, Qt::Key_Up }, { NSDownArrowFunctionKey, Qt::Key_Down }, { NSLeftArrowFunctionKey, Qt::Key_Left }, @@ -731,7 +809,6 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) return Qt::NoButton; } -// Helper to share code between QCocoaWindow and QCocoaView bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent) { #ifndef QT_MAC_USE_COCOA @@ -743,6 +820,7 @@ bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEve EventRef key_event = static_cast<EventRef>(const_cast<void *>([event eventRef])); Q_ASSERT(key_event); unsigned int info = 0; + if ([event type] == NSKeyDown) { NSString *characters = [event characters]; if ([characters length]) { @@ -752,19 +830,12 @@ bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEve } } - // Redirect keys to alien widgets. - if (widgetToGetEvent->testAttribute(Qt::WA_NativeWindow) == false) { - widgetToGetEvent = qApp->focusWidget(); - } - - if (widgetToGetEvent == 0) - return false; - if (qt_mac_sendMacEventToWidget(widgetToGetEvent, key_event)) return true; if (mustUseCocoaKeyEvent()) return qt_dispatchKeyEventWithCocoa(keyEvent, widgetToGetEvent); + bool consumed = qt_keymapper_private()->translateKeyEvent(widgetToGetEvent, 0, key_event, &info, true); return consumed && (info != 0); #endif @@ -788,7 +859,6 @@ void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget #endif } - QPointF flipPoint(const NSPoint &p) { return QPointF(p.x, flipYCoordinate(p.y)); @@ -804,21 +874,15 @@ NSPoint flipPoint(const QPointF &p) return NSMakePoint(p.x(), flipYCoordinate(p.y())); } -void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /* NSEvent* */mouseEvent, - QWidget *widgetToGetEvent, bool &leftButtonIsRightButton) +#if QT_MAC_USE_COCOA && __OBJC__ + +void qt_mac_handleNonClientAreaMouseEvent(NSWindow *window, NSEvent *event) { -#ifndef QT_MAC_USE_COCOA - Q_UNUSED(eventWindow); - Q_UNUSED(mouseEvent); - Q_UNUSED(widgetToGetEvent); - Q_UNUSED(leftButtonIsRightButton); -#else + QWidget *widgetToGetEvent = [window QT_MANGLE_NAMESPACE(qt_qwidget)]; if (widgetToGetEvent == 0) return; - NSWindow *window = static_cast<NSWindow *>(eventWindow); - NSEvent *event = static_cast<NSEvent *>(mouseEvent); - NSEventType evtType = [event type]; + NSEventType evtType = [event type]; QPoint qlocalPoint; QPoint qglobalPoint; bool processThisEvent = false; @@ -936,12 +1000,12 @@ void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /* : QEvent::MouseButtonDblClick; if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) { button = Qt::RightButton; - leftButtonIsRightButton = true; + qt_leftButtonIsRightButton = true; } } else if (eventType == QEvent::NonClientAreaMouseButtonRelease || eventType == QEvent::MouseButtonRelease) { - if (button == Qt::LeftButton && leftButtonIsRightButton) { + if (button == Qt::LeftButton && qt_leftButtonIsRightButton) { button = Qt::RightButton; - leftButtonIsRightButton = false; + qt_leftButtonIsRightButton = false; } } @@ -961,97 +1025,197 @@ void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /* // However we might need to unset it if the event is Release. if (eventType == QEvent::MouseButtonRelease) qt_button_down = 0; -#endif } -bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */event, QEvent::Type eventType, Qt::MouseButton button) +QWidget *qt_mac_getTargetForKeyEvent(QWidget *widgetThatReceivedEvent) { -#ifndef QT_MAC_USE_COCOA - Q_UNUSED(view); - Q_UNUSED(event); - Q_UNUSED(eventType); - Q_UNUSED(button); - return false; -#else - QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view); - NSEvent *theEvent = static_cast<NSEvent *>(event); + if (QWidget *popup = QApplication::activePopupWidget()) { + QWidget *focusInPopup = popup->focusWidget(); + return focusInPopup ? focusInPopup : popup; + } - // Give the Input Manager a chance to process the mouse events. - NSInputManager *currentIManager = [NSInputManager currentInputManager]; - if (currentIManager && [currentIManager wantsToHandleMouseEvents]) { - [currentIManager handleMouseEvent:theEvent]; - } + QWidget *widgetToGetKey = qApp->focusWidget(); + if (!widgetToGetKey) + widgetToGetKey = widgetThatReceivedEvent; - // Handle tablet events (if any) first. - if (qt_mac_handleTabletEvent(theView, theEvent)) { - // Tablet event was handled. In Qt we aren't supposed to send the mouse event. - return true; + return widgetToGetKey; +} + +// This function will find the widget that should receive the +// mouse event. Because of explicit/implicit mouse grabs, popups, +// etc, this might not end up being the same as the widget under +// the mouse (which is more interresting when handling enter/leave +// events +QWidget *qt_mac_getTargetForMouseEvent( + // You can call this function without providing an event. + // If so, set returnGlobalPoint before the call. + NSEvent *event, + QEvent::Type eventType, + QPoint &returnLocalPoint, + QPoint &returnGlobalPoint, + QWidget *nativeWidget, + QWidget **returnWidgetUnderMouse) +{ + Q_UNUSED(event); + 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 (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); } - NSPoint windowPoint = [theEvent locationInWindow]; - NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint]; + 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 && nativeWidget->rect().contains(p)) + widgetUnderMouse = nativeWidget; + } - // Find the widget that *should* get the event (e.g., maybe it was a pop-up, - // they always get the mouse event). - QWidget *qwidget = [theView qt_qwidget]; - QWidget *widgetToGetMouse = 0; - NSView *tmpView = 0; - QWidget *popup = qAppInstance()->activePopupWidget(); - QPoint qglobalPoint(flipPoint(globalPoint).toPoint()); + if (widgetUnderMouse) { + // Check if widgetUnderMouse is blocked by a modal + // window, or the mouse if over the frame strut: + if (widgetUnderMouse == qt_button_down) { + // Small optimization to avoid an extra call to isBlockedByModal: + if (buttonDownNotBlockedByModal == false) + widgetUnderMouse = 0; + } else if (QApplicationPrivate::isBlockedByModal(widgetUnderMouse)) { + widgetUnderMouse = 0; + } - if (popup) { - widgetToGetMouse = popup; - tmpView = qt_mac_nativeview_for(popup); - windowPoint = [[tmpView window] convertScreenToBase:globalPoint]; - - QPoint qWindowPoint(windowPoint.x, windowPoint.y); - if (widgetToGetMouse->rect().contains(qWindowPoint)) { - // Keeping the mouse pressed on a combobox button will make - // the popup pop in front of the mouse. But all mouse events - // will be sendt to the button. Since we want mouse events - // to be sendt to widgets inside the popup, we search for the - // widget in front of the mouse: - tmpView = [tmpView hitTest:windowPoint]; - if (!tmpView) - return false; - widgetToGetMouse = - [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(tmpView) qt_qwidget]; + if (widgetUnderMouse && widgetUnderMouse->isWindow()) { + // Exclude the titlebar (and frame strut) when finding widget under mouse: + QPoint p = widgetUnderMouse->mapFromGlobal(returnGlobalPoint); + if (!widgetUnderMouse->rect().contains(p)) + widgetUnderMouse = 0; } + } + if (returnWidgetUnderMouse) + *returnWidgetUnderMouse = widgetUnderMouse; + + // Resolve the target for the mouse event. Default will be + // widgetUnderMouse, except if there is a grab (popup/mouse/button-down): + if (popup && !mouseGrabber) { + // 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 == candidate) { + // INVARIANT: The candidate is the popup itself, and not a child: + returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint); + return popup; + } else { + // INVARIANT: The candidate is a child inside the popup: + returnLocalPoint = candidate->mapFromGlobal(returnGlobalPoint); + return candidate; + } + } + + QWidget *target = mouseGrabber; + if (!target && buttonDownNotBlockedByModal) + target = qt_button_down; + if (!target) + target = widgetUnderMouse; + if (!target) + return 0; + + returnLocalPoint = target->mapFromGlobal(returnGlobalPoint); + 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 + // not. This will in general be the cases when alien widgets are not involved: + // 1. from a native widget to another native widget or + // 2. from a native widget to no widget + // 3. from no widget to a native or alien widget + + if (qt_button_down || QWidget::mouseGrabber()) + return; + + if ((maybeEnterWidget == qt_last_native_mouse_receiver) && qt_last_native_mouse_receiver) + return; + if (maybeEnterWidget) { + if (!qt_last_native_mouse_receiver) { + // case 3 + QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, 0); + qt_last_native_mouse_receiver = maybeEnterWidget->internalWinId() ? maybeEnterWidget : maybeEnterWidget->nativeParentWidget(); + } else if (maybeEnterWidget->internalWinId()) { + // case 1 + 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 { - extern QWidget * qt_button_down; //qapplication_mac.cpp - QPoint pos; - widgetToGetMouse = QApplicationPrivate::pickMouseReceiver(qwidget, qglobalPoint, - pos, eventType, - button, qt_button_down, 0); - if (widgetToGetMouse) - tmpView = qt_mac_nativeview_for(widgetToGetMouse); + if (qt_last_native_mouse_receiver) { + // case 2 + QApplicationPrivate::dispatchEnterLeave(0, qt_last_native_mouse_receiver); + qt_last_mouse_receiver = 0; + qt_last_native_mouse_receiver = 0; + } } +} + +bool qt_mac_handleMouseEvent(NSEvent *event, QEvent::Type eventType, Qt::MouseButton button, QWidget *nativeWidget) +{ + // Give the Input Manager a chance to process the mouse events. + NSInputManager *currentIManager = [NSInputManager currentInputManager]; + if (currentIManager && [currentIManager wantsToHandleMouseEvents]) { + [currentIManager handleMouseEvent:event]; + } + + // Find the widget that should receive the event, and the widget under the mouse. Those + // can differ if an implicit or explicit mouse grab is active: + QWidget *widgetUnderMouse = 0; + QPoint localPoint, globalPoint; + QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(event, eventType, localPoint, globalPoint, nativeWidget, &widgetUnderMouse); if (!widgetToGetMouse) return false; - NSPoint localPoint = [tmpView convertPoint:windowPoint fromView:nil]; - QPoint qlocalPoint = QPoint(localPoint.x, localPoint.y); + // 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); - // Search for alien child widgets (either on this qwidget or on the popup) - if (widgetToGetMouse->testAttribute(Qt::WA_NativeWindow) == false || qt_widget_private(widgetToGetMouse)->hasAlienChildren) { - QPoint qScreenPoint = flipPoint(globalPoint).toPoint(); -#ifdef ALIEN_DEBUG - qDebug() << "alien mouse event" << qScreenPoint << possibleAlien; -#endif - QWidget *possibleAlien = widgetToGetMouse->childAt(qlocalPoint); - if (possibleAlien) { - qlocalPoint = possibleAlien->mapFromGlobal(widgetToGetMouse->mapToGlobal(qlocalPoint)); - widgetToGetMouse = possibleAlien; - } + // Handle tablet events (if any) first. + if (qt_mac_handleTabletEvent(view, event)) { + // Tablet event was handled. In Qt we aren't supposed to send the mouse event. + return true; } - EventRef carbonEvent = static_cast<EventRef>(const_cast<void *>([theEvent eventRef])); + EventRef carbonEvent = static_cast<EventRef>(const_cast<void *>([event eventRef])); if (qt_mac_sendMacEventToWidget(widgetToGetMouse, carbonEvent)) return true; - // Yay! All the special cases are handled, it really is just a normal mouse event. - Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]); - NSInteger clickCount = [theEvent clickCount]; + // Keep previousButton to make sure we don't send double click + // events when the user double clicks using two different buttons: + static Qt::MouseButton previousButton = Qt::NoButton; + + Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]); + NSInteger clickCount = [event clickCount]; Qt::MouseButtons buttons = 0; { UInt32 mac_buttons; @@ -1059,55 +1223,67 @@ bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */ev sizeof(mac_buttons), 0, &mac_buttons) == noErr) buttons = qt_mac_get_buttons(mac_buttons); } + + // Send enter/leave events for the cases when QApplicationPrivate::sendMouseEvent do not: + qt_mac_checkEnterLeaveForNativeWidgets(widgetUnderMouse); + switch (eventType) { default: qWarning("not handled! %d", eventType); break; case QEvent::MouseMove: + if (button == Qt::LeftButton && qt_leftButtonIsRightButton) + button = Qt::RightButton; break; case QEvent::MouseButtonPress: - [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = theView; - [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = theEvent; -#ifndef QT_NAMESPACE - Q_ASSERT(clickCount > 0); -#endif - if (clickCount % 2 == 0 && buttons == button) + qt_button_down = widgetUnderMouse; + if (clickCount % 2 == 0 && (previousButton == Qt::NoButton || previousButton == button)) eventType = QEvent::MouseButtonDblClick; if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) { button = Qt::RightButton; - [theView qt_setLeftButtonIsRightButton: true]; + qt_leftButtonIsRightButton = true; } break; case QEvent::MouseButtonRelease: - if (button == Qt::LeftButton && [theView qt_leftButtonIsRightButton]) { + if (button == Qt::LeftButton && qt_leftButtonIsRightButton) { button = Qt::RightButton; - [theView qt_setLeftButtonIsRightButton: false]; + qt_leftButtonIsRightButton = false; } qt_button_down = 0; break; } - [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->localPoint = localPoint; - QMouseEvent qme(eventType, qlocalPoint, qglobalPoint, button, buttons, keyMods); -#ifdef ALIEN_DEBUG - qDebug() << "sending mouse event to" << widgetToGetMouse; -#endif - extern QWidget *qt_button_down; - extern QPointer<QWidget> qt_last_mouse_receiver; + qt_mac_updateCursorWithWidgetUnderMouse(widgetUnderMouse); - if (qwidget->testAttribute(Qt::WA_NativeWindow) && qt_widget_private(qwidget)->hasAlienChildren == false) - qt_sendSpontaneousEvent(widgetToGetMouse, &qme); - else - QApplicationPrivate::sendMouseEvent(widgetToGetMouse, &qme, widgetToGetMouse, qwidget, &qt_button_down, - qt_last_mouse_receiver); + DnDParams *dndParams = currentDnDParameters(); + dndParams->view = view; + dndParams->theEvent = event; + dndParams->globalPoint = globalPoint; + + // Send the mouse event: + QMouseEvent qme(eventType, localPoint, globalPoint, button, buttons, keyMods); + QApplicationPrivate::sendMouseEvent( + widgetToGetMouse, &qme, widgetUnderMouse, nativeWidget, + &qt_button_down, qt_last_mouse_receiver, true); if (eventType == QEvent::MouseButtonPress && button == Qt::RightButton) { - QContextMenuEvent qcme(QContextMenuEvent::Mouse, qlocalPoint, qglobalPoint, keyMods); + QContextMenuEvent qcme(QContextMenuEvent::Mouse, localPoint, globalPoint, keyMods); qt_sendSpontaneousEvent(widgetToGetMouse, &qcme); } + + 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. 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); + } + + previousButton = button; return true; -#endif } +#endif bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */tabletEvent) { @@ -1291,17 +1467,17 @@ void qt_mac_replaceDrawRectOriginal(void * /*OSWindowRef */window, QWidgetPrivat } #endif // QT_MAC_USE_COCOA +#if QT_MAC_USE_COCOA void qt_mac_showBaseLineSeparator(void * /*OSWindowRef */window, bool show) { if(!window) return; -#if QT_MAC_USE_COCOA QMacCocoaAutoReleasePool pool; OSWindowRef theWindow = static_cast<OSWindowRef>(window); NSToolbar *macToolbar = [theWindow toolbar]; [macToolbar setShowsBaselineSeparator:show]; -#endif // QT_MAC_USE_COCOA } +#endif // QT_MAC_USE_COCOA QStringList qt_mac_NSArrayToQStringList(void *nsarray) { @@ -1321,6 +1497,7 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list) return result; } +#if QT_MAC_USE_COCOA void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow) { if (!widgetForWindow) @@ -1345,6 +1522,7 @@ void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow) [window setShowsToolbarButton:uint(flags & Qt::MacWindowToolBarButtonHint) != 0]; } +#endif // QT_MAC_USE_COCOA // Carbon: Make sure you call QDEndContext on the context when done with it. CGContextRef qt_mac_graphicsContextFor(QWidget *widget) @@ -1446,6 +1624,7 @@ void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayI } } +#ifdef QT_MAC_USE_COCOA void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse) { OSMenuRef menu = static_cast<OSMenuRef>(theMenu); @@ -1479,12 +1658,24 @@ void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse) } } -#ifdef QT_MAC_USE_COCOA -void qt_cocoaChangeOverrideCursor(const QCursor &cursor) +class CocoaPostMessageAfterEventLoopExitHelp : public QObject { - QMacCocoaAutoReleasePool pool; - [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set]; -} + id target; + SEL selector; + int argCount; + id arg1; + id arg2; +public: + CocoaPostMessageAfterEventLoopExitHelp(id target, SEL selector, int argCount, id arg1, id arg2) + : target(target), selector(selector), argCount(argCount), arg1(arg1), arg2(arg2){ + deleteLater(); + } + + ~CocoaPostMessageAfterEventLoopExitHelp() + { + qt_cocoaPostMessage(target, selector, argCount, arg1, arg2); + } +}; void qt_cocoaPostMessage(id target, SEL selector, int argCount, id arg1, id arg2) { @@ -1498,6 +1689,15 @@ void qt_cocoaPostMessage(id target, SEL selector, int argCount, id arg1, id arg2 context:nil subtype:QtCocoaEventSubTypePostMessage data1:lower data2:upper]; [NSApp postEvent:e atStart:NO]; } + +void qt_cocoaPostMessageAfterEventLoopExit(id target, SEL selector, int argCount, id arg1, id arg2) +{ + if (QApplicationPrivate::instance()->threadData->eventLoops.size() <= 1) + qt_cocoaPostMessage(target, selector, argCount, arg1, arg2); + else + new CocoaPostMessageAfterEventLoopExitHelp(target, selector, argCount, arg1, arg2); +} + #endif QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool() @@ -1521,6 +1721,12 @@ void qt_mac_post_retranslateAppMenu() #endif } +QWidgetPrivate *QMacScrollOptimization::_target = 0; +bool QMacScrollOptimization::_inWheelEvent = false; +int QMacScrollOptimization::_dx = 0; +int QMacScrollOptimization::_dy = 0; +QRect QMacScrollOptimization::_scrollRect = QRect(0, 0, -1, -1); + #ifdef QT_MAC_USE_COCOA // This method implements the magic for the drawRectSpecial method. // We draw a line at the upper edge of the content view in order to |