summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Moe Gustavsen <richard.gustavsen@nokia.com>2010-12-09 13:10:57 (GMT)
committerRichard Moe Gustavsen <richard.gustavsen@nokia.com>2011-01-17 13:35:51 (GMT)
commit72aa2eb43b0cf5a6eef940da05ac58f605794ffb (patch)
treee71eca54cfa309286b5203601c7ed2f3461a26ad
parent09656c9b57af5bb383d029c62396b536899b28e7 (diff)
downloadQt-72aa2eb43b0cf5a6eef940da05ac58f605794ffb.zip
Qt-72aa2eb43b0cf5a6eef940da05ac58f605794ffb.tar.gz
Qt-72aa2eb43b0cf5a6eef940da05ac58f605794ffb.tar.bz2
Alien implementation for the Cocoa port
Give Alien on Cocoa a warm welcome.
-rw-r--r--src/gui/kernel/qapplication.cpp13
-rw-r--r--src/gui/kernel/qapplication_mac.mm124
-rw-r--r--src/gui/kernel/qapplication_p.h2
-rw-r--r--src/gui/kernel/qcocoaapplicationdelegate_mac.mm21
-rw-r--r--src/gui/kernel/qcocoapanel_mac.mm7
-rw-r--r--src/gui/kernel/qcocoapanel_mac_p.h9
-rw-r--r--src/gui/kernel/qcocoasharedwindowmethods_mac_p.h407
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm838
-rw-r--r--src/gui/kernel/qcocoaview_mac_p.h28
-rw-r--r--src/gui/kernel/qcocoawindow_mac.mm2
-rw-r--r--src/gui/kernel/qcocoawindow_mac_p.h10
-rw-r--r--src/gui/kernel/qcursor.h5
-rw-r--r--src/gui/kernel/qcursor_mac.mm128
-rw-r--r--src/gui/kernel/qdnd_mac.mm4
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm446
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac_p.h30
-rw-r--r--src/gui/kernel/qwidget.cpp39
-rw-r--r--src/gui/kernel/qwidget_mac.mm769
-rw-r--r--src/gui/kernel/qwidget_p.h5
-rw-r--r--src/gui/painting/qwindowsurface_raster.cpp1
-rw-r--r--src/gui/widgets/qcocoamenu_mac.mm3
-rw-r--r--src/gui/widgets/qfocusframe.cpp3
-rw-r--r--src/gui/widgets/qmainwindow.cpp5
-rw-r--r--src/gui/widgets/qmainwindowlayout_mac.mm25
-rw-r--r--tests/auto/qwidget/tst_qwidget.cpp39
-rw-r--r--tests/auto/qwidget/tst_qwidget_mac_helpers.h13
-rw-r--r--tests/auto/qwidget/tst_qwidget_mac_helpers.mm44
27 files changed, 1700 insertions, 1320 deletions
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 833e803..27d34db 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -2772,7 +2772,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) {
for (int i = 0; i < leaveList.size(); ++i) {
w = leaveList.at(i);
if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) {
-#if defined(Q_WS_WIN) || defined(Q_WS_X11)
+#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC)
if (leaveAfterRelease == w)
leaveAfterRelease = 0;
#endif
@@ -3143,13 +3143,11 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
// Dispatch enter/leave if:
// 1) the mouse grabber is an alien widget
// 2) the button is released on an alien widget
-
QWidget *enter = 0;
if (nativeGuard)
enter = alienGuard ? alienWidget : nativeWidget;
else // The receiver is typically deleted on mouse release with drag'n'drop.
enter = QApplication::widgetAt(event->globalPos());
-
dispatchEnterLeave(enter, leaveAfterRelease);
leaveAfterRelease = 0;
lastMouseReceiver = enter;
@@ -3696,15 +3694,6 @@ void QApplication::changeOverrideCursor(const QCursor &cursor)
if (qApp->d_func()->cursor_list.isEmpty())
return;
qApp->d_func()->cursor_list.removeFirst();
-#ifdef QT_MAC_USE_COCOA
- // We use native NSCursor stacks in Cocoa. The currentCursor is the
- // top of this stack. So to avoid flickering of cursor, we have to
- // change the cusor instead of pop-ing the existing OverrideCursor
- // and pushing the new one.
- qApp->d_func()->cursor_list.prepend(cursor);
- qt_cocoaChangeOverrideCursor(cursor);
- return;
-#endif
setOverrideCursor(cursor);
}
#endif
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index 3aafeb4..3bdfaf8 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -165,6 +165,7 @@ QT_BEGIN_NAMESPACE
//for qt_mac.h
QPaintDevice *qt_mac_safe_pdev = 0;
QList<QMacWindowChangeEvent*> *QMacWindowChangeEvent::change_events = 0;
+QPointer<QWidget> topLevelAt_cache = 0;
/*****************************************************************************
Internal variables and functions
@@ -192,7 +193,6 @@ static bool qt_mac_previous_press_in_popup_mode = false;
static bool qt_mac_no_click_through_mode = false;
static int tablet_button_state = 0;
#endif
-QPointer<QWidget> qt_mouseover;
#if defined(QT_DEBUG)
static bool appNoGrab = false; // mouse/keyboard grabbing
#endif
@@ -216,11 +216,12 @@ extern bool qt_mac_can_clickThrough(const QWidget *); //qwidget_mac.cpp
extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
extern OSWindowRef qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
extern QWidget *qt_mac_find_window(OSWindowRef); //qwidget_mac.cpp
-extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.cpp
+extern void qt_mac_set_cursor(const QCursor *); //qcursor_mac.cpp
extern bool qt_mac_is_macsheet(const QWidget *); //qwidget_mac.cpp
extern QString qt_mac_from_pascal_string(const Str255); //qglobal.cpp
extern void qt_mac_command_set_enabled(MenuRef, UInt32, bool); //qmenu_mac.cpp
extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplication.cpp
+extern void qt_mac_update_cursor(); // qcursor_mac.mm
// Forward Decls
void onApplicationWindowChangedActivation( QWidget*widget, bool activated );
@@ -1364,43 +1365,16 @@ void QApplication::setMainWidget(QWidget *mainWidget)
/*****************************************************************************
QApplication cursor stack
*****************************************************************************/
-#ifdef QT_MAC_USE_COCOA
-void QApplicationPrivate::disableUsageOfCursorRects(bool disable)
-{
- // In Cocoa there are two competing ways of setting the cursor; either
- // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping
- // the cursor manually. When we use override cursors, it makes most sense
- // to use the latter. But then we need to tell cocoa to stop using the
- // first approach so it doesn't change the cursor back when hovering over
- // a cursor rect:
- QWidgetList topLevels = qApp->topLevelWidgets();
- for (int i=0; i<topLevels.size(); ++i) {
- if (NSWindow *window = qt_mac_window_for(topLevels.at(i)))
- disable ? [window disableCursorRects] : [window enableCursorRects];
- }
-}
-
-void QApplicationPrivate::updateOverrideCursor()
-{
- // Sometimes Cocoa forgets that we have set a Cursor
- // manually. In those cases, remind it again:
- if (QCursor *override = qApp->overrideCursor())
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set];
-}
-#endif
void QApplication::setOverrideCursor(const QCursor &cursor)
{
qApp->d_func()->cursor_list.prepend(cursor);
#ifdef QT_MAC_USE_COCOA
- QMacCocoaAutoReleasePool pool;
- if (qApp->d_func()->cursor_list.size() == 1)
- qApp->d_func()->disableUsageOfCursorRects(true);
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
+ qt_mac_update_cursor();
#else
if (qApp && qApp->activeWindow())
- qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
+ qt_mac_set_cursor(&qApp->d_func()->cursor_list.first());
#endif
}
@@ -1411,14 +1385,11 @@ void QApplication::restoreOverrideCursor()
qApp->d_func()->cursor_list.removeFirst();
#ifdef QT_MAC_USE_COCOA
- QMacCocoaAutoReleasePool pool;
- [NSCursor pop];
- if (qApp->d_func()->cursor_list.isEmpty())
- qApp->d_func()->disableUsageOfCursorRects(false);
+ qt_mac_update_cursor();
#else
if (qApp && qApp->activeWindow()) {
const QCursor def(Qt::ArrowCursor);
- qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
+ qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first());
}
#endif
}
@@ -1431,30 +1402,54 @@ QWidget *QApplication::topLevelAt(const QPoint &p)
qt_mac_window_at(p.x(), p.y(), &widget);
return widget;
#else
+ // Use a cache to avoid iterate through the whole list of windows for all
+ // calls to to topLevelAt. We e.g. do this for each and every mouse
+ // move since we need to find the widget under mouse:
+ if (topLevelAt_cache && topLevelAt_cache->frameGeometry().contains(p))
+ return topLevelAt_cache;
+
+ // INVARIANT: Cache miss. Go through the list if windows instead:
+ QMacCocoaAutoReleasePool pool;
+ NSPoint cocoaPoint = flipPoint(p);
NSInteger windowCount;
NSCountWindows(&windowCount);
if (windowCount <= 0)
return 0; // There's no window to find!
- QMacCocoaAutoReleasePool pool;
- NSPoint cocoaPoint = flipPoint(p);
+
QVarLengthArray<NSInteger> windowList(windowCount);
NSWindowList(windowCount, windowList.data());
+ int firstQtWindowFound = -1;
for (int i = 0; i < windowCount; ++i) {
NSWindow *window = [NSApp windowWithWindowNumber:windowList[i]];
- if (window && NSPointInRect(cocoaPoint, [window frame])) {
+ if (window) {
QWidget *candidateWindow = [window QT_MANGLE_NAMESPACE(qt_qwidget)];
- // Check to see if there's a hole in the window where the mask is.
- // If there is, we should just continue to see if there is a window below.
- if (candidateWindow && !candidateWindow->mask().isEmpty()) {
- QPoint localPoint = candidateWindow->mapFromGlobal(p);
- if (!candidateWindow->mask().contains(localPoint)) {
- continue;
+ if (candidateWindow && firstQtWindowFound == -1)
+ firstQtWindowFound = i;
+
+ if (NSPointInRect(cocoaPoint, [window frame])) {
+ // Check to see if there's a hole in the window where the mask is.
+ // If there is, we should just continue to see if there is a window below.
+ if (candidateWindow && !candidateWindow->mask().isEmpty()) {
+ QPoint localPoint = candidateWindow->mapFromGlobal(p);
+ if (!candidateWindow->mask().contains(localPoint))
+ continue;
+ else
+ return candidateWindow;
+ } else {
+ if (i == firstQtWindowFound) {
+ // The cache will only work when the window under mouse is
+ // top most (that is, not partially obscured by other windows.
+ // And we only set it if no mask is present to optimize for the common case:
+ topLevelAt_cache = candidateWindow;
+ }
+ return candidateWindow;
}
}
- return candidateWindow;
}
}
- return 0; // Couldn't find a window at this point
+
+ topLevelAt_cache = 0;
+ return 0;
#endif
}
@@ -1480,8 +1475,8 @@ void QApplicationPrivate::enterModal_sys(QWidget *widget)
if (!qt_modal_stack)
qt_modal_stack = new QWidgetList;
- dispatchEnterLeave(0, qt_mouseover);
- qt_mouseover = 0;
+ dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
qt_modal_stack->insert(0, widget);
if (!app_do_modal)
@@ -1512,8 +1507,8 @@ void QApplicationPrivate::leaveModal_sys(QWidget *widget)
w = grabber;
else
w = QApplication::widgetAt(p.x(), p.y());
- dispatchEnterLeave(w, qt_mouseover); // send synthetic enter event
- qt_mouseover = w;
+ dispatchEnterLeave(w, qt_last_mouse_receiver); // send synthetic enter event
+ qt_last_mouse_receiver = w;
}
#ifdef QT_MAC_USE_COCOA
if (!qt_mac_is_macsheet(widget))
@@ -1938,7 +1933,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
}
}
}
- qt_mac_set_cursor(&cursor, QPoint(where.h, where.v));
+ qt_mac_set_cursor(&cursor);
}
//This mouse button state stuff looks like this on purpose
@@ -2132,20 +2127,20 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
QWidget * const enterLeaveWidget = (inPopupMode || ekind == kEventMouseUp) ?
QApplication::widgetAt(where.h, where.v) : static_cast<QWidget*>(widget);
- if ((QWidget *) qt_mouseover != enterLeaveWidget || inNonClientArea) {
+ if ((QWidget *) qt_last_mouse_receiver != enterLeaveWidget || inNonClientArea) {
#ifdef DEBUG_MOUSE_MAPS
qDebug("Entering: %p - %s (%s), Leaving %s (%s)", (QWidget*)enterLeaveWidget,
enterLeaveWidget ? enterLeaveWidget->metaObject()->className() : "none",
enterLeaveWidget ? enterLeaveWidget->objectName().toLocal8Bit().constData() : "",
- qt_mouseover ? qt_mouseover->metaObject()->className() : "none",
- qt_mouseover ? qt_mouseover->objectName().toLocal8Bit().constData() : "");
+ qt_last_mouse_receiver ? qt_last_mouse_receiver->metaObject()->className() : "none",
+ qt_last_mouse_receiver ? qt_last_mouse_receiver->objectName().toLocal8Bit().constData() : "");
#endif
QWidget * const mouseGrabber = QWidget::mouseGrabber();
if (inPopupMode) {
QWidget *enter = enterLeaveWidget;
- QWidget *leave = qt_mouseover;
+ QWidget *leave = qt_last_mouse_receiver;
if (mouseGrabber) {
QWidget * const popupWidget = qApp->activePopupWidget();
if (leave == popupWidget)
@@ -2155,15 +2150,15 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
if ((enter == mouseGrabber && leave == popupWidget)
|| (leave == mouseGrabber && enter == popupWidget)) {
QApplicationPrivate::dispatchEnterLeave(enter, leave);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
}
} else {
QApplicationPrivate::dispatchEnterLeave(enter, leave);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
}
- } else if ((!qt_button_down || !qt_mouseover) && !mouseGrabber && !leaveAfterRelease) {
- QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_mouseover);
- qt_mouseover = enterLeaveWidget;
+ } else if ((!qt_button_down || !qt_last_mouse_receiver) && !mouseGrabber && !leaveAfterRelease) {
+ QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = enterLeaveWidget;
}
}
break; }
@@ -2240,7 +2235,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
if (leaveAfterRelease) {
QWidget *enter = QApplication::widgetAt(where.h, where.v);
QApplicationPrivate::dispatchEnterLeave(enter, leaveAfterRelease);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
leaveAfterRelease = 0;
}
@@ -2503,7 +2498,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
void QApplicationPrivate::qt_initAfterNSAppStarted()
{
setupAppleEvents();
- updateOverrideCursor();
+ qt_mac_update_cursor();
}
void QApplicationPrivate::setupAppleEvents()
@@ -3080,7 +3075,7 @@ void onApplicationWindowChangedActivation(QWidget *widget, bool activated)
}
QMenuBar::macUpdateMenuBar();
- QApplicationPrivate::updateOverrideCursor();
+ qt_mac_update_cursor();
#else
Q_UNUSED(widget);
Q_UNUSED(activated);
@@ -3115,6 +3110,7 @@ void onApplicationChangedActivation( bool activated )
app->setActiveWindow(tmp_w);
}
QMenuBar::macUpdateMenuBar();
+ qt_mac_update_cursor();
} else { // de-activated
QApplicationPrivate *priv = [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] qAppPrivate];
while (priv->inPopupMode())
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index 7b49999..c5f8717 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -489,8 +489,6 @@ public:
#ifdef QT_MAC_USE_COCOA
static void qt_initAfterNSAppStarted();
static void setupAppleEvents();
- static void updateOverrideCursor();
- static void disableUsageOfCursorRects(bool disable);
#endif
static bool qt_mac_apply_settings();
#endif
diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
index 9b07d64..6c5de59 100644
--- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
+++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
@@ -78,6 +78,7 @@
#import <private/qcocoaapplicationdelegate_mac_p.h>
#import <private/qcocoamenuloader_mac_p.h>
+#import <private/qcocoaapplication_mac_p.h>
#include <private/qapplication_p.h>
#include <private/qt_mac_p.h>
#include <private/qt_cocoa_helpers_mac_p.h>
@@ -89,6 +90,9 @@
QT_BEGIN_NAMESPACE
extern void onApplicationChangedActivation(bool); // qapplication_mac.mm
extern void qt_release_apple_event_handler(); //qapplication_mac.mm
+extern QPointer<QWidget> qt_last_mouse_receiver; // qapplication_mac.cpp
+extern QPointer<QWidget> qt_button_down; // qapplication_mac.cpp
+
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QDesktopWidgetImplementation)
@@ -253,7 +257,18 @@ static void cleanupCocoaApplicationDelegate()
if (reflectionDelegate
&& [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)])
[reflectionDelegate applicationDidBecomeActive:notification];
+
onApplicationChangedActivation(true);
+
+ if (!QWidget::mouseGrabber()){
+ // Update enter/leave immidiatly, don't wait for a move event. But only
+ // if no grab exists (even if the grab points to this widget, it seems, ref X11)
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, 0);
+ qt_last_mouse_receiver = widgetUnderMouse;
+ }
}
- (void)applicationDidResignActive:(NSNotification *)notification;
@@ -261,7 +276,13 @@ static void cleanupCocoaApplicationDelegate()
if (reflectionDelegate
&& [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)])
[reflectionDelegate applicationDidResignActive:notification];
+
onApplicationChangedActivation(false);
+
+ if (!QWidget::mouseGrabber())
+ QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
+ qt_button_down = 0;
}
- (void)applicationDidChangeScreenParameters:(NSNotification *)notification
diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm
index 0b48efd..cb1e5d0 100644
--- a/src/gui/kernel/qcocoapanel_mac.mm
+++ b/src/gui/kernel/qcocoapanel_mac.mm
@@ -47,9 +47,10 @@
#import <private/qcocoaview_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
#import <private/qcocoaapplication_mac_p.h>
-#include <private/qapplication_p.h>
-#include <private/qbackingstore_p.h>
-
+#import <private/qmultitouch_mac_p.h>
+#import <private/qapplication_p.h>
+#import <private/qbackingstore_p.h>
+#import <private/qdnd_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qcocoapanel_mac_p.h b/src/gui/kernel/qcocoapanel_mac_p.h
index 3678f81..3accc1b 100644
--- a/src/gui/kernel/qcocoapanel_mac_p.h
+++ b/src/gui/kernel/qcocoapanel_mac_p.h
@@ -50,20 +50,27 @@
// We mean it.
//
+#ifndef QCOCOAPANEL_MAC_P
+#define QCOCOAPANEL_MAC_P
+
#include "qmacdefines_mac.h"
#ifdef QT_MAC_USE_COCOA
#import <Cocoa/Cocoa.h>
QT_FORWARD_DECLARE_CLASS(QStringList);
+QT_FORWARD_DECLARE_CLASS(QCocoaDropData);
@interface QT_MANGLE_NAMESPACE(QCocoaPanel) : NSPanel {
- bool leftButtonIsRightButton;
QStringList *currentCustomDragTypes;
+ QCocoaDropData *dropData;
+ NSInteger dragEnterSequence;
}
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
- (void)registerDragTypes;
+- (void)drawRectOriginal:(NSRect)rect;
@end
#endif
+#endif
diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
index efe045c..c71d476 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -62,7 +62,6 @@ extern void qt_event_request_window_change(QWidget *); // qapplication_mac.mm
extern void qt_mac_send_posted_gl_updates(QWidget *widget); // qapplication_mac.mm
Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget);
-
QT_END_NAMESPACE
- (id)initWithContentRect:(NSRect)contentRect
@@ -145,66 +144,27 @@ QT_END_NAMESPACE
- (void)sendEvent:(NSEvent *)event
{
- QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
- // Cocoa can hold onto the window after we've disavowed its knowledge. So,
- // if we get sent an event afterwards just have it go through the super's
- // version and don't do any stuff with Qt.
- if (!widget) {
- [super sendEvent:event];
- return;
- }
-
[self retain];
- QT_MANGLE_NAMESPACE(QCocoaView) *view = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(qt_mac_nativeview_for(widget));
- Qt::MouseButton mouseButton = cocoaButton2QtButton([event buttonNumber]);
bool handled = false;
- // sometimes need to redirect mouse events to the popup.
- QWidget *popup = qAppInstance()->activePopupWidget();
- if (popup) {
- switch([event type])
- {
- case NSLeftMouseDown:
- if (!qt_button_down)
- qt_button_down = widget;
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton);
- // Don't call super here. This prevents us from getting the mouseUp event,
- // which we need to send even if the mouseDown event was not accepted.
- // (this is standard Qt behavior.)
- break;
- case NSRightMouseDown:
- case NSOtherMouseDown:
- if (!qt_button_down)
- qt_button_down = widget;
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton);
- break;
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonRelease, mouseButton);
- qt_button_down = 0;
- break;
- case NSMouseMoved:
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseMove, Qt::NoButton);
- break;
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = view;
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = event;
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseMove, mouseButton);
- break;
- default:
- [super sendEvent:event];
- break;
- }
- } else {
- [super sendEvent:event];
+ switch([event type]) {
+ case NSMouseMoved:
+ // Cocoa sends move events to a parent and all its children under the mouse, much
+ // like Qt handles hover events. But we only want to handle the move event once, so
+ // to optimize a bit (since we subscribe for move event for all views), we handle it
+ // here before this logic happends. Note: it might be tempting to do this shortcut for
+ // all mouse events. The problem is that Cocoa does more than just find the correct view
+ // when sending the event, like raising windows etc. So avoid it as much as possible:
+ handled = qt_mac_handleMouseEvent(event, QEvent::MouseMove, Qt::NoButton, 0);
+ break;
+ default:
+ break;
}
- if (!handled)
- qt_mac_dispatchNCMouseMessage(self, event, [self QT_MANGLE_NAMESPACE(qt_qwidget)], leftButtonIsRightButton);
-
+ if (!handled) {
+ [super sendEvent:event];
+ qt_mac_handleNonClientAreaMouseEvent(self, event);
+ }
[self release];
}
@@ -237,6 +197,56 @@ QT_END_NAMESPACE
return [super frameViewClassForStyleMask:styleMask];
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+- (void)touchesBeganWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesMovedWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesEndedWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+
-(void)registerDragTypes
{
// Calling registerForDraggedTypes below is slow, so only do
@@ -259,21 +269,47 @@ QT_END_NAMESPACE
NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
// Add custom types supported by the application.
for (int i = 0; i < customTypes.size(); i++) {
- [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
+ [supportedTypes addObject:qt_mac_QStringToNSString(customTypes[i])];
}
[self registerForDraggedTypes:supportedTypes];
}
}
-- (QWidget *)dragTargetHitTest:(id <NSDraggingInfo>)sender
+- (void)removeDropData
+{
+ if (dropData) {
+ delete dropData;
+ dropData = 0;
+ }
+}
+
+- (void)addDropData:(id <NSDraggingInfo>)sender
{
- // Do a hittest to find the NSView under the
- // mouse, and return the corresponding QWidget:
- NSPoint windowPoint = [sender draggingLocation];
- NSView *candidateView = [[self contentView] hitTest:windowPoint];
- if (![candidateView isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]])
- return 0;
- return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(candidateView) qt_qwidget];
+ [self removeDropData];
+ CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
+ dropData = new QCocoaDropData(dropPasteboard);
+}
+
+- (void)changeDraggingCursor:(NSDragOperation)newOperation
+{
+ static SEL action = nil;
+ static bool operationSupported = false;
+ if (action == nil) {
+ action = NSSelectorFromString(@"operationNotAllowedCursor");
+ if ([NSCursor respondsToSelector:action]) {
+ operationSupported = true;
+ }
+ }
+ if (operationSupported) {
+ NSCursor *notAllowedCursor = [NSCursor performSelector:action];
+ bool isNotAllowedCursor = ([NSCursor currentCursor] == notAllowedCursor);
+ if (newOperation == NSDragOperationNone && !isNotAllowedCursor) {
+ [notAllowedCursor push];
+ } else if (newOperation != NSDragOperationNone && isNotAllowedCursor) {
+ [notAllowedCursor pop];
+ }
+
+ }
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
@@ -286,64 +322,211 @@ QT_END_NAMESPACE
// registerForDraggedTypes on the views will severly degrade initialization time
// for an application that uses a lot of drag subscribing widgets.
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ QWidget *qwidget = QApplication::widgetAt(globalPoint);
+ *currentDragTarget() = qwidget;
+ if (!qwidget)
return [super draggingEntered:sender];
- if (target->testAttribute(Qt::WA_DropSiteRegistered) == false)
+ if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
return NSDragOperationNone;
- *currentDragTarget() = target;
- return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender];
+ [self addDropData:sender];
+
+ QMimeData *mimeData = dropData;
+ if (QDragManager::self()->source())
+ mimeData = QDragManager::self()->dragPrivate()->data;
+
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
+ QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ if ([sender draggingSource] != nil) {
+ // modifier flags might have changed, update it here since we don't send any input events.
+ QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
+ modifiers = QApplication::keyboardModifiers();
+ } else {
+ // when the source is from another application the above technique will not work.
+ modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
+ }
+
+ // send the drag enter event to the widget.
+ QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
+ QDragEnterEvent qDEEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
+ QApplication::sendEvent(qwidget, &qDEEvent);
+
+ if (!qDEEvent.isAccepted()) {
+ // The enter event was not accepted. We mark this by removing
+ // the drop data so we don't send subsequent drag move events:
+ [self removeDropData];
+ [self changeDraggingCursor:NSDragOperationNone];
+ return NSDragOperationNone;
+ } else {
+ // Send a drag move event immediately after a drag enter event (as per documentation).
+ QDragMoveEvent qDMEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
+ qDMEvent.setDropAction(qDEEvent.dropAction());
+ qDMEvent.accept(); // accept by default, since enter event was accepted.
+ QApplication::sendEvent(qwidget, &qDMEvent);
+
+ if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
+ // Since we accepted the drag enter event, the widget expects
+ // future drage move events.
+ nsActions = NSDragOperationNone;
+ // Save as ignored in the answer rect.
+ qDMEvent.setDropAction(Qt::IgnoreAction);
+ } else {
+ nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
+ }
+
+ QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
+ [self changeDraggingCursor:nsActions];
+ return nsActions;
+ }
}
-- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
- return [super draggingUpdated:sender];
-
- if (target == *currentDragTarget()) {
- // The drag continues to move over the widget that we have sendt
- // a draggingEntered message to. So just update the view:
- return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingUpdated:sender];
- } else {
- // The widget under the mouse has changed.
- // So we need to fake enter/leave events:
- if (*currentDragTarget())
- [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender];
- if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) {
- *currentDragTarget() = 0;
- return NSDragOperationNone;
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ QWidget *qwidget = QApplication::widgetAt(globalPoint);
+ if (!qwidget)
+ return [super draggingEntered:sender];
+
+ // First, check if the widget under the mouse has changed since the
+ // last drag move events. If so, we need to change target, and dispatch
+ // syntetic drag enter/leave events:
+ if (qwidget != *currentDragTarget()) {
+ if (*currentDragTarget() && dropData) {
+ QDragLeaveEvent de;
+ QApplication::sendEvent(*currentDragTarget(), &de);
+ [self removeDropData];
}
- *currentDragTarget() = target;
- return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender];
+ return [self draggingEntered:sender];
}
+
+ if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
+ return NSDragOperationNone;
+
+ // If we have no drop data (which will be assigned inside draggingEntered), it means
+ // that the current drag target did not accept the enter event. If so, we ignore
+ // subsequent move events as well:
+ if (dropData == 0) {
+ [self changeDraggingCursor:NSDragOperationNone];
+ return NSDragOperationNone;
+ }
+
+ // If the mouse is still within the accepted rect (provided by
+ // the application on a previous event), we follow the optimization
+ // and just return the answer given at that point:
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
+ if (qt_mac_mouse_inside_answer_rect(localPoint)
+ && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) {
+ NSDragOperation operation = QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
+ [self changeDraggingCursor:operation];
+ return operation;
+ }
+
+ QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
+ Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ // Update modifiers:
+ if ([sender draggingSource] != nil) {
+ QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
+ modifiers = QApplication::keyboardModifiers();
+ } else {
+ modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
+ }
+
+ QMimeData *mimeData = dropData;
+ if (QDragManager::self()->source())
+ mimeData = QDragManager::self()->dragPrivate()->data;
+
+ // Insert the same drop action on the event according to
+ // what the application told us it should be on the previous event:
+ QDragMoveEvent qDMEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
+ if (QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction != Qt::IgnoreAction
+ && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).buttons == qDMEvent.mouseButtons()
+ && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).modifiers == qDMEvent.keyboardModifiers())
+ qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
+
+ // Now, end the drag move event to the widget:
+ qDMEvent.accept();
+ QApplication::sendEvent(qwidget, &qDMEvent);
+
+ NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
+ if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
+ // Ignore this event (we will still receive further
+ // notifications), save as ignored in the answer rect:
+ operation = NSDragOperationNone;
+ qDMEvent.setDropAction(Qt::IgnoreAction);
+ }
+
+ qt_mac_copy_answer_rect(qDMEvent);
+ [self changeDraggingCursor:operation];
+
+ return operation;
}
-- (void)draggingExited:(id < NSDraggingInfo >)sender
+- (void)draggingExited:(id <NSDraggingInfo>)sender
{
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ QWidget *qwidget = *currentDragTarget();
+ if (!qwidget)
return [super draggingExited:sender];
- if (*currentDragTarget()) {
- [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender];
- *currentDragTarget() = 0;
+ if (dropData) {
+ QDragLeaveEvent de;
+ QApplication::sendEvent(qwidget, &de);
+ [self removeDropData];
}
+
+ // Clean-up:
+ [self removeDropData];
+ *currentDragTarget() = 0;
+ [self changeDraggingCursor:NSDragOperationEvery];
}
-- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
- return [super performDragOperation:sender];
-
- BOOL dropResult = NO;
- if (*currentDragTarget()) {
- dropResult = [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) performDragOperation:sender];
- *currentDragTarget() = 0;
- }
- return dropResult;
+ QWidget *qwidget = *currentDragTarget();
+ if (!qwidget)
+ return NO;
+
+ *currentDragTarget() = 0;
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ [self addDropData:sender];
+
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
+ QMimeData *mimeData = dropData;
+
+ if (QDragManager::self()->source())
+ mimeData = QDragManager::self()->dragPrivate()->data;
+ if (QDragManager::self()->object)
+ QDragManager::self()->dragPrivate()->target = qwidget;
+
+ QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
+ QDropEvent de(localPoint, qtAllowed, mimeData,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ QApplication::sendEvent(qwidget, &de);
+
+ if (QDragManager::self()->object)
+ QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
+
+ return de.isAccepted();
}
- (void)displayIfNeeded
@@ -394,8 +577,8 @@ static bool firstDrawingInvocation = true;
- (void)drawRectSpecial:(NSRect)rect
{
// Call the original drawing method.
- [self drawRectOriginal:rect];
- NSWindow *window = [self window];
+ [id(self) drawRectOriginal:rect];
+ NSWindow *window = [id(self) window];
NSToolbar *toolbar = [window toolbar];
if(!toolbar) {
// There is no toolbar, we have to draw a line on top of the line drawn by Cocoa.
@@ -415,3 +598,11 @@ static bool firstDrawingInvocation = true;
}
}
}
+
+- (void)drawRectOriginal:(NSRect)rect
+{
+ Q_UNUSED(rect)
+ // This method implementation is here to silenct the compiler.
+ // See drawRectSpecial for information.
+}
+
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index dfcc2e6..c627b0b 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -49,7 +49,6 @@
#include <private/qt_cocoa_helpers_mac_p.h>
#include <private/qdnd_p.h>
#include <private/qmacinputcontext_p.h>
-#include <private/qmultitouch_mac_p.h>
#include <private/qevent_p.h>
#include <private/qbackingstore_p.h>
@@ -76,70 +75,15 @@
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
-
-extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
+extern void qt_mac_update_cursor(); // qcursor_mac.mm
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
+extern QPointer<QWidget> qt_last_mouse_receiver; // qapplication_mac.cpp
extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
-extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
+extern OSViewRef qt_mac_effectiveview_for(const QWidget *w); // qwidget_mac.mm
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
-
-struct dndenum_mapper
-{
- NSDragOperation mac_code;
- Qt::DropAction qt_code;
- bool Qt2Mac;
-};
-
-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 }
-};
-
-static 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;
-}
-
-static 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;
-}
-
-static 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;
-}
-
-static 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;
-}
+extern QWidget *mac_mouse_grabber;
+extern bool qt_mac_clearDirtyOnWidgetInsideDrawWidget; // qwidget.cpp
static QColor colorFrom(NSColor *color)
{
@@ -222,243 +166,9 @@ static int qCocoaViewCount = 0;
object:self];
}
-- (void)resetCursorRects
-{
- // [NSView addCursorRect] is slow, so bail out early if we can:
- if (NSIsEmptyRect([self visibleRect]))
- return;
-
- QWidget *cursorWidget = qwidget;
-
- if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents))
- cursorWidget = QApplication::widgetAt(qwidget->mapToGlobal(qwidget->rect().center()));
-
- if (cursorWidget == 0)
- return;
-
- if (!cursorWidget->testAttribute(Qt::WA_SetCursor)) {
- [super resetCursorRects];
- return;
- }
-
- QRegion mask = qt_widget_private(cursorWidget)->extra->mask;
- NSCursor *nscursor = static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursorWidget->cursor()));
- // The mask could have the WA_MouseNoMask attribute set and that means that we have to ignore the mask.
- if (mask.isEmpty() || cursorWidget->testAttribute(Qt::WA_MouseNoMask)) {
- [self addCursorRect:[qt_mac_nativeview_for(cursorWidget) visibleRect] cursor:nscursor];
- } else {
- const QVector<QRect> &rects = mask.rects();
- for (int i = 0; i < rects.size(); ++i) {
- const QRect &rect = rects.at(i);
- [self addCursorRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()) cursor:nscursor];
- }
- }
-}
-
-- (void)removeDropData
-{
- if (dropData) {
- delete dropData;
- dropData = 0;
- }
-}
-
-- (void)addDropData:(id <NSDraggingInfo>)sender
-{
- [self removeDropData];
- CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
- dropData = new QCocoaDropData(dropPasteboard);
-}
-
-- (void)changeDraggingCursor:(NSDragOperation)newOperation
-{
- static SEL action = nil;
- static bool operationSupported = false;
- if (action == nil) {
- action = NSSelectorFromString(@"operationNotAllowedCursor");
- if ([NSCursor respondsToSelector:action]) {
- operationSupported = true;
- }
- }
- if (operationSupported) {
- NSCursor *notAllowedCursor = [NSCursor performSelector:action];
- bool isNotAllowedCursor = ([NSCursor currentCursor] == notAllowedCursor);
- if (newOperation == NSDragOperationNone && !isNotAllowedCursor) {
- [notAllowedCursor push];
- } else if (newOperation != NSDragOperationNone && isNotAllowedCursor) {
- [notAllowedCursor pop];
- }
-
- }
-}
-
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- NSPoint windowPoint = [sender draggingLocation];
- dragEnterSequence = [sender draggingSequenceNumber];
- [self addDropData:sender];
- QMimeData *mimeData = dropData;
- if (QDragManager::self()->source())
- mimeData = QDragManager::self()->dragPrivate()->data;
- NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- QPoint posDrag(localPoint.x, localPoint.y);
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
- QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
- Qt::KeyboardModifiers modifiers = Qt::NoModifier;
- if ([sender draggingSource] != nil) {
- // modifier flags might have changed, update it here since we don't send any input events.
- QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
- modifiers = QApplication::keyboardModifiers();
- } else {
- // when the source is from another application the above technique will not work.
- modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
- }
- // send the drag enter event to the widget.
- QDragEnterEvent qDEEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
- QApplication::sendEvent(qwidget, &qDEEvent);
- if (!qDEEvent.isAccepted()) {
- // widget is not interested in this drag, so ignore this drop data.
- [self removeDropData];
- [self changeDraggingCursor:NSDragOperationNone];
- return NSDragOperationNone;
- } else {
- // save the mouse position, used by draggingExited handler.
- DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
- dndParams->activeDragEnterPos = windowPoint;
- // send a drag move event immediately after a drag enter event (as per documentation).
- QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
- qDMEvent.setDropAction(qDEEvent.dropAction());
- qDMEvent.accept(); // accept by default, since enter event was accepted.
- QApplication::sendEvent(qwidget, &qDMEvent);
- if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
- // since we accepted the drag enter event, the widget expects
- // future drage move events.
- // ### check if we need to treat this like the drag enter event.
- nsActions = NSDragOperationNone;
- // Save as ignored in the answer rect.
- qDMEvent.setDropAction(Qt::IgnoreAction);
- } else {
- nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
- }
- QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
- [self changeDraggingCursor:nsActions];
- return nsActions;
- }
- }
-- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- NSPoint windowPoint = [sender draggingLocation];
- // in cases like QFocusFrame, the view under the mouse might
- // not have received the drag enter. Generate a synthetic
- // drag enter event for that view.
- if (dragEnterSequence != [sender draggingSequenceNumber])
- [self draggingEntered:sender];
- // drag enter event was rejected, so ignore the move event.
- if (dropData == 0) {
- [self changeDraggingCursor:NSDragOperationNone];
- return NSDragOperationNone;
- }
- // return last value, if we are still in the answerRect.
- NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
- QPoint posDrag(localPoint.x, localPoint.y);
- if (qt_mac_mouse_inside_answer_rect(posDrag)
- && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) {
- NSDragOperation operation = QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
- [self changeDraggingCursor:operation];
- return operation;
- }
- // send drag move event to the widget
- QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
- Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
- Qt::KeyboardModifiers modifiers = Qt::NoModifier;
- if ([sender draggingSource] != nil) {
- // modifier flags might have changed, update it here since we don't send any input events.
- QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
- modifiers = QApplication::keyboardModifiers();
- } else {
- // when the source is from another application the above technique will not work.
- modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
- }
- QMimeData *mimeData = dropData;
- if (QDragManager::self()->source())
- mimeData = QDragManager::self()->dragPrivate()->data;
- QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
- if (QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction != Qt::IgnoreAction
- && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).buttons == qDMEvent.mouseButtons()
- && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).modifiers == qDMEvent.keyboardModifiers())
- qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
- qDMEvent.accept();
- QApplication::sendEvent(qwidget, &qDMEvent);
-
- NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
- if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
- // ignore this event (we will still receive further notifications)
- operation = NSDragOperationNone;
- // Save as ignored in the answer rect.
- qDMEvent.setDropAction(Qt::IgnoreAction);
- }
- qt_mac_copy_answer_rect(qDMEvent);
- [self changeDraggingCursor:operation];
- return operation;
-}
-
-- (void)draggingExited:(id < NSDraggingInfo >)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- Q_UNUSED(sender);
- dragEnterSequence = -1;
- // drag enter event was rejected, so ignore the move event.
- if (dropData) {
- QDragLeaveEvent de;
- QApplication::sendEvent(qwidget, &de);
- [self removeDropData];
- }
- [self changeDraggingCursor:NSDragOperationEvery];
-
-}
-
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- NSPoint windowPoint = [sender draggingLocation];
- dragEnterSequence = -1;
- [self addDropData:sender];
-
- NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- QPoint posDrop(localPoint.x, localPoint.y);
-
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
- QMimeData *mimeData = dropData;
- if (QDragManager::self()->source())
- mimeData = QDragManager::self()->dragPrivate()->data;
- // send the drop event to the widget.
- QDropEvent de(posDrop, qtAllowed, mimeData,
- QApplication::mouseButtons(), QApplication::keyboardModifiers());
- if (QDragManager::self()->object)
- QDragManager::self()->dragPrivate()->target = qwidget;
- QApplication::sendEvent(qwidget, &de);
- if (QDragManager::self()->object)
- QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
- if (!de.isAccepted())
- return NO;
- else
- return YES;
-}
-
- (void)dealloc
{
+ QMacCocoaAutoReleasePool pool;
delete composingText;
[[NSNotificationCenter defaultCenter] removeObserver:self];
@@ -532,9 +242,8 @@ static int qCocoaViewCount = 0;
{
if (!qwidget)
return;
-
- // We use a different graphics system.
if (QApplicationPrivate::graphicsSystem() != 0 && !qwidgetprivate->isInUnifiedToolbar) {
+ // INVARIANT: We use a different graphics system.
// Qt handles the painting occuring inside the window.
// Cocoa also keeps track of all widgets as NSView and therefore might
@@ -560,7 +269,7 @@ static int qCocoaViewCount = 0;
qwidgetprivate->hd = cg;
// We steal the CGContext for flushing in the unified toolbar with the raster engine.
- if (QApplicationPrivate::graphicsSystem() != 0 && qwidgetprivate->isInUnifiedToolbar) {
+ if (QApplicationPrivate::graphicsSystem() != 0 && qwidgetprivate->isInUnifiedToolbar && qwidgetprivate->unifiedSurface) {
qwidgetprivate->cgContext = cg;
qwidgetprivate->hasOwnContext = true;
qwidgetprivate->unifiedSurface->flush(qwidget, qwidgetprivate->ut_rg, qwidgetprivate->ut_pt);
@@ -576,13 +285,13 @@ static int qCocoaViewCount = 0;
const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
QRegion qrgn;
- const NSRect *rects;
- NSInteger count;
- [self getRectsBeingDrawn:&rects count:&count];
- for (int i = 0; i < count; ++i) {
- QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
- qrgn += tmpRect;
- }
+ const NSRect *rects;
+ NSInteger count;
+ [self getRectsBeingDrawn:&rects count:&count];
+ for (int i = 0; i < count; ++i) {
+ QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
+ qrgn += tmpRect;
+ }
if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
const QRegion &parentMask = qwidget->window()->mask();
@@ -612,38 +321,27 @@ static int qCocoaViewCount = 0;
}
if (qwidget->isWindow() && !qwidgetprivate->isOpaque
- && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
+ && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
CGContextClearRect(cg, NSRectToCGRect(aRect));
}
- // Check for alien widgets, use qwidgetPrivate->drawWidget() to draw the widget if this
- // is the case. This makes sure child widgets are drawn as well, Cocoa does not know about
- // those and wont send them drawRect calls.
- if (qwidget->testAttribute(Qt::WA_NativeWindow) && qt_widget_private(qwidget)->hasAlienChildren == false) {
- if (engine && !qwidget->testAttribute(Qt::WA_NoSystemBackground)
- && (qwidget->isWindow() || qwidget->autoFillBackground())
- || qwidget->testAttribute(Qt::WA_TintedBackground)
- || qwidget->testAttribute(Qt::WA_StyledBackground)) {
-#ifdef DEBUG_WIDGET_PAINT
- if(doDebug)
- qDebug(" Handling erase for [%s::%s]", qwidget->metaObject()->className(),
- qwidget->objectName().local8Bit().data());
-#endif
- QPainter p(qwidget);
- qwidgetprivate->paintBackground(&p, qrgn,
- qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0);
- p.end();
- }
- QPaintEvent e(qrgn);
-#ifdef QT3_SUPPORT
- e.setErased(true);
-#endif
- qt_sendSpontaneousEvent(qwidget, &e);
- } else {
- qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false); // QWidgetPrivate::drawWidget sets this
- QWidgetPrivate *qwidgetPrivate = qt_widget_private(qwidget);
- qwidgetPrivate->drawWidget(qwidget, qrgn, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen | QWidgetPrivate::DrawRecursive, 0);
- }
+ qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
+ QWidgetPrivate *qwidgetPrivate = qt_widget_private(qwidget);
+
+ // We specify that we want to draw the widget itself, and
+ // all its children recursive. But we skip native children, because
+ // they will receive drawRect calls by themselves as needed:
+ int flags = QWidgetPrivate::DrawPaintOnScreen
+ | QWidgetPrivate::DrawRecursive
+ | QWidgetPrivate::DontDrawNativeChildren;
+
+ if (qwidget->isWindow())
+ flags |= QWidgetPrivate::DrawAsRoot;
+
+ // Start to draw:
+ qt_mac_clearDirtyOnWidgetInsideDrawWidget = true;
+ qwidgetPrivate->drawWidget(qwidget, qrgn, QPoint(), flags, 0);
+ qt_mac_clearDirtyOnWidgetInsideDrawWidget = false;
if (!redirectionOffset.isNull())
QPainter::restoreRedirected(qwidget);
@@ -652,7 +350,7 @@ static int qCocoaViewCount = 0;
qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
if(!qwidget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && qwidget->paintingActive())
qWarning("QWidget: It is dangerous to leave painters active on a"
- " widget outside of the PaintEvent");
+ " widget outside of the PaintEvent");
}
qwidgetprivate->hd = 0;
CGContextRestoreGState(cg);
@@ -660,11 +358,13 @@ static int qCocoaViewCount = 0;
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
- if (!qwidget)
+ // Find the widget that should receive the event:
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(theEvent, QEvent::MouseButtonPress, qlocal, qglobal, qwidget, 0);
+ if (!widgetToGetMouse)
return NO;
- Q_UNUSED(theEvent);
- return !qwidget->testAttribute(Qt::WA_MacNoClickThrough);
+ return !widgetToGetMouse->testAttribute(Qt::WA_MacNoClickThrough);
}
- (NSView *)hitTest:(NSPoint)aPoint
@@ -715,161 +415,119 @@ static int qCocoaViewCount = 0;
- (void)mouseEntered:(NSEvent *)event
{
- if (!qwidget)
- return;
- if (qwidgetprivate->data.in_destructor)
- return;
-
- if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
- QEvent enterEvent(QEvent::Enter);
- NSPoint windowPoint = [event locationInWindow];
- NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
- NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
- QApplication::sendEvent(qwidget, &enterEvent);
- qt_mouseover = qwidget;
-
- // Update cursor icon:
- qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
-
- // Send mouse move and hover events as well:
- if (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window()) {
- // This mouse move event should be sendt, even when mouse
- // tracking is switched off (to trigger tooltips):
- NSEvent *mouseEvent = [NSEvent mouseEventWithType:NSMouseMoved
- location:windowPoint modifierFlags:[event modifierFlags] timestamp:[event timestamp]
- windowNumber:[event windowNumber] context:[event context] eventNumber:[event eventNumber]
- clickCount:0 pressure:0];
- qt_mac_handleMouseEvent(self, mouseEvent, QEvent::MouseMove, Qt::NoButton);
-
- if (qwidget->testAttribute(Qt::WA_Hover)) {
- QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1));
- QApplicationPrivate::instance()->notify_helper(qwidget, &he);
- }
- }
- }
+ // Cocoa will not send a move event on mouseEnter. But since
+ // Qt expect this, we fake one now. See also mouseExited below
+ // for info about enter/leave event handling
+ NSEvent *nsmoveEvent = [NSEvent
+ mouseEventWithType:NSMouseMoved
+ location:[[self window] mouseLocationOutsideOfEventStream]
+ modifierFlags: [event modifierFlags]
+ timestamp: [event timestamp]
+ windowNumber: [event windowNumber]
+ context: [event context]
+ eventNumber: [event eventNumber]
+ clickCount: 0
+ pressure: 0];
+
+ // Important: Cocoa sends us mouseEnter on all views under the mouse
+ // and not just the one on top. Therefore, to we cannot use qwidget
+ // as native widget for this case. Instead, we let qt_mac_handleMouseEvent
+ // resolve it (last argument set to 0):
+ qt_mac_handleMouseEvent(nsmoveEvent, QEvent::MouseMove, Qt::NoButton, 0);
}
- (void)mouseExited:(NSEvent *)event
{
- if (!qwidget)
- return;
-
- QEvent leaveEvent(QEvent::Leave);
- NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
- if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
- QApplication::sendEvent(qwidget, &leaveEvent);
-
- // ### Think about if it is necessary to update the cursor, should only be for a few cases.
- qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
- if (qwidget->testAttribute(Qt::WA_Hover)
- && (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window())) {
- QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1),
- qwidget->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos));
- QApplicationPrivate::instance()->notify_helper(qwidget, &he);
+ // Note: normal enter/leave handling is done from within mouseMove. This handler
+ // catches the case when the mouse moves out of the window (which mouseMove do not).
+ // Updating the mouse cursor follows the same logic as enter/leave. And we update
+ // neither if a grab exists (even if the grab points to this widget, it seems, ref X11)
+ Q_UNUSED(event);
+ if (self == [[self window] contentView] && !qt_button_down && !QWidget::mouseGrabber()) {
+ qt_mac_update_cursor();
+ // If the mouse exits the content view, but qt_mac_getTargetForMouseEvent still
+ // reports a target, it means that either there is a grab involved, or the mouse
+ // hovered over another window in the application. In both cases, move events will
+ // cause qt_mac_handleMouseEvent to be called, which will handle enter/leave.
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Leave, qlocal, qglobal, qwidget, &widgetUnderMouse);
+
+ if (widgetUnderMouse == 0) {
+ QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
}
}
}
- (void)flagsChanged:(NSEvent *)theEvent
{
- if (!qwidget)
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
return;
- QWidget *widgetToGetKey = qwidget;
-
- QWidget *popup = qAppInstance()->activePopupWidget();
- if (popup && popup != qwidget->window())
- widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
qt_dispatchModifiersChanged(theEvent, widgetToGetKey);
[super flagsChanged:theEvent];
}
- (void)mouseMoved:(NSEvent *)theEvent
{
- if (!qwidget)
- return;
-
- // We always enable mouse tracking for all QCocoaView-s. In cases where we have
- // child views, we will receive mouseMoved for both parent & the child (if
- // mouse is over the child). We need to ignore the parent mouseMoved in such
- // cases.
- NSPoint windowPoint = [theEvent locationInWindow];
- NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
- if (candidateView && candidateView == self) {
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
- }
+ // Important: this method will only be called when the view's window is _not_ inside
+ // QCocoaWindow/QCocoaPanel. Otherwise, [QCocoaWindow sendEvent] will handle the event
+ // before it ends up here. So, this method is added for supporting QMacNativeWidget.
+ // TODO: Cocoa send move events to all views under the mouse. So make sure we only
+ // handle the event for the widget on top when using QMacNativeWidget.
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)mouseDown:(NSEvent *)theEvent
{
- if (!qt_button_down)
- qt_button_down = qwidget;
-
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::LeftButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, Qt::LeftButton, qwidget);
// Don't call super here. This prevents us from getting the mouseUp event,
// which we need to send even if the mouseDown event was not accepted.
// (this is standard Qt behavior.)
}
-
- (void)mouseUp:(NSEvent *)theEvent
{
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::LeftButton);
-
- qt_button_down = 0;
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, Qt::LeftButton, qwidget);
}
- (void)rightMouseDown:(NSEvent *)theEvent
{
- if (!qt_button_down)
- qt_button_down = qwidget;
-
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::RightButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, Qt::RightButton, qwidget);
}
- (void)rightMouseUp:(NSEvent *)theEvent
{
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::RightButton);
-
- qt_button_down = 0;
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, Qt::RightButton, qwidget);
}
- (void)otherMouseDown:(NSEvent *)theEvent
{
- if (!qt_button_down)
- qt_button_down = qwidget;
-
Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, mouseButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, mouseButton, qwidget);
}
- (void)otherMouseUp:(NSEvent *)theEvent
{
Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, mouseButton);
-
- qt_button_down = 0;
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, mouseButton, qwidget);
}
- (void)mouseDragged:(NSEvent *)theEvent
{
- qMacDnDParams()->view = self;
- qMacDnDParams()->theEvent = theEvent;
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)rightMouseDragged:(NSEvent *)theEvent
{
- qMacDnDParams()->view = self;
- qMacDnDParams()->theEvent = theEvent;
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)otherMouseDragged:(NSEvent *)theEvent
{
- qMacDnDParams()->view = self;
- qMacDnDParams()->theEvent = theEvent;
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)scrollWheel:(NSEvent *)theEvent
@@ -880,21 +538,14 @@ static int qCocoaViewCount = 0;
[currentIManager handleMouseEvent:theEvent];
}
- NSPoint windowPoint = [theEvent locationInWindow];
- NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- QPoint qlocal = QPoint(localPoint.x, localPoint.y);
- QPoint qglobal = QPoint(globalPoint.x, flipYCoordinate(globalPoint.y));
Qt::MouseButtons buttons = QApplication::mouseButtons();
- bool wheelOK = false;
Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
- QWidget *widgetToGetMouse = qwidget;
- // if popup is open it should get wheel events if the cursor is over the popup,
- // otherwise the event should be ignored.
- if (QWidget *popup = qAppInstance()->activePopupWidget()) {
- if (!popup->geometry().contains(qglobal))
- return;
- }
+
+ // Find the widget that should receive the event:
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(theEvent, QEvent::Wheel, qlocal, qglobal, qwidget, 0);
+ if (!widgetToGetMouse)
+ return;
int deltaX = 0;
int deltaY = 0;
@@ -926,27 +577,11 @@ static int qCocoaViewCount = 0;
if (deltaX != 0) {
QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal);
qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
- wheelOK = qwe.isAccepted();
- if (!wheelOK && QApplicationPrivate::focus_widget
- && QApplicationPrivate::focus_widget != widgetToGetMouse) {
- QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
- deltaX, buttons, keyMods, Qt::Horizontal);
- qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
- wheelOK = qwe2.isAccepted();
- }
}
if (deltaY) {
QWheelEvent qwe(qlocal, qglobal, deltaY, buttons, keyMods, Qt::Vertical);
qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
- wheelOK = qwe.isAccepted();
- if (!wheelOK && QApplicationPrivate::focus_widget
- && QApplicationPrivate::focus_widget != widgetToGetMouse) {
- QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
- deltaY, buttons, keyMods, Qt::Vertical);
- qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
- wheelOK = qwe2.isAccepted();
- }
}
if (deltaZ) {
@@ -954,14 +589,6 @@ static int qCocoaViewCount = 0;
// try to be ahead of the pack, I'm adding this extra value.
QWheelEvent qwe(qlocal, qglobal, deltaZ, buttons, keyMods, (Qt::Orientation)3);
qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
- wheelOK = qwe.isAccepted();
- if (!wheelOK && QApplicationPrivate::focus_widget
- && QApplicationPrivate::focus_widget != widgetToGetMouse) {
- QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
- deltaZ, buttons, keyMods, (Qt::Orientation)3);
- qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
- wheelOK = qwe2.isAccepted();
- }
}
#endif //QT_NO_WHEELEVENT
}
@@ -977,35 +604,14 @@ static int qCocoaViewCount = 0;
[super tabletPoint:tabletEvent];
}
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-- (void)touchesBeganWithEvent:(NSEvent *)event;
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-
-- (void)touchesMovedWithEvent:(NSEvent *)event;
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-
-- (void)touchesEndedWithEvent:(NSEvent *)event;
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-
-- (void)touchesCancelledWithEvent:(NSEvent *)event;
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
- (void)magnifyWithEvent:(NSEvent *)event;
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1014,13 +620,18 @@ static int qCocoaViewCount = 0;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
qNGEvent.percentage = [event magnification];
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)rotateWithEvent:(NSEvent *)event;
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1029,13 +640,18 @@ static int qCocoaViewCount = 0;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
qNGEvent.percentage = -[event rotation];
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)swipeWithEvent:(NSEvent *)event;
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1051,13 +667,18 @@ static int qCocoaViewCount = 0;
qNGEvent.angle = 90.0f;
else if ([event deltaY] == -1)
qNGEvent.angle = 270.0f;
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)beginGestureWithEvent:(NSEvent *)event;
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1065,13 +686,18 @@ static int qCocoaViewCount = 0;
qNGEvent.gestureType = QNativeGestureEvent::GestureBegin;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)endGestureWithEvent:(NSEvent *)event;
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1079,9 +705,9 @@ static int qCocoaViewCount = 0;
qNGEvent.gestureType = QNativeGestureEvent::GestureEnd;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
-#endif // QT_NO_GESTURES
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
}
+#endif // QT_NO_GESTURES
- (void)frameDidChange:(NSNotification *)note
{
@@ -1124,16 +750,32 @@ static int qCocoaViewCount = 0;
{
if (!qwidget)
return NO;
- // disabled widget shouldn't get focus even if it's a window.
+
+ // Disabled widget shouldn't get focus even if it's a window.
// hence disabled windows will not get any key or mouse events.
if (!qwidget->isEnabled())
return NO;
- // Before accepting the focus for a window, we check that
- // the focusWidget (if any) is not contained in the same window.
- if (qwidget->isWindow() && !qt_widget_private(qwidget)->topData()->embedded
- && (!qApp->focusWidget() || qApp->focusWidget()->window() != qwidget)) {
- return YES; // Always do it, so that windows can accept key press events.
+
+ if (qwidget->isWindow() && !qt_widget_private(qwidget)->topData()->embedded) {
+ QWidget *focusWidget = qApp->focusWidget();
+ if (!focusWidget) {
+ // There is no focus widget, but we still want to receive key events
+ // for shortcut handling etc. So we accept first responer for the
+ // content view as a last resort:
+ return YES;
+ }
+ if (!focusWidget->internalWinId() && focusWidget->nativeParentWidget() == qwidget) {
+ // The current focus widget is alien, and hence, cannot get acceptsFirstResponder
+ // calls. Since the focus widget is a child of qwidget, we let this view say YES:
+ return YES;
+ }
+ if (focusWidget->window() != qwidget) {
+ // The current focus widget is in another window. Since cocoa
+ // suggest that this window should be key now, we accept:
+ return YES;
+ }
}
+
return qwidget->focusPolicy() != Qt::NoFocus;
}
@@ -1141,10 +783,13 @@ static int qCocoaViewCount = 0;
{
if (!qwidget)
return NO;
+
// Seems like the following test only triggers if this
// view is inside a QMacNativeWidget:
- if (qwidget == QApplication::focusWidget())
- qwidget->clearFocus();
+// if (QWidget *fw = QApplication::focusWidget()) {
+// if (qwidget == fw || qwidget == fw->nativeParentWidget())
+// fw->clearFocus();
+// }
return YES;
}
@@ -1173,11 +818,11 @@ static int qCocoaViewCount = 0;
{
Q_UNUSED(anImage);
Q_UNUSED(aPoint);
- qMacDnDParams()->performedAction = operation;
+ macCurrentDnDParameters()->performedAction = operation;
if (QDragManager::self()->object
&& QDragManager::self()->dragPrivate()->executed_action != Qt::ActionMask) {
- qMacDnDParams()->performedAction =
- qt_mac_mapDropAction(QDragManager::self()->dragPrivate()->executed_action);
+ macCurrentDnDParameters()->performedAction =
+ qt_mac_mapDropAction(QDragManager::self()->dragPrivate()->executed_action);
}
}
@@ -1192,51 +837,37 @@ static int qCocoaViewCount = 0;
qwidgetprivate = 0;
}
-- (BOOL)qt_leftButtonIsRightButton
-{
- return leftButtonIsRightButton;
-}
-
-- (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped
-{
- leftButtonIsRightButton = isSwapped;
-}
-
-+ (DnDParams*)currentMouseEvent
-{
- return qMacDnDParams();
-}
-
- (void)keyDown:(NSEvent *)theEvent
{
- sendKeyEvents = true;
-
- QWidget *widgetToGetKey = qwidget;
+ if (!qwidget)
+ return;
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
+ return;
- QWidget *popup = qAppInstance()->activePopupWidget();
- bool sendToPopup = false;
- if (popup && popup != qwidget->window()) {
- widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
- sendToPopup = true;
- }
+ sendKeyEvents = true;
if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)
&& !(widgetToGetKey->inputMethodHints() & Qt::ImhDigitsOnly
|| widgetToGetKey->inputMethodHints() & Qt::ImhFormattedNumbersOnly
|| widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) {
fromKeyDownEvent = true;
- [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
+ [qt_mac_nativeview_for(qwidget) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
fromKeyDownEvent = false;
}
+
if (sendKeyEvents && !composing) {
- bool keyOK = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
- if (!keyOK && !sendToPopup) {
- // find the first responder that is not created by Qt and forward
- // the event to it (for example if Qt widget is embedded into native).
+ bool keyEventEaten = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
+ if (!keyEventEaten && qwidget) {
+ // The event is not yet eaten, and if Qt is embedded inside a native
+ // cocoa application, send it to first responder not owned by Qt.
+ // The exception is if widgetToGetKey was redirected to a popup.
QWidget *toplevel = qwidget->window();
- if (toplevel && qt_widget_private(toplevel)->topData()->embedded) {
- if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
- [w keyDown:theEvent];
+ if (toplevel == widgetToGetKey->window()) {
+ if (qt_widget_private(toplevel)->topData()->embedded) {
+ if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
+ [w keyDown:theEvent];
+ }
}
}
}
@@ -1246,12 +877,21 @@ static int qCocoaViewCount = 0;
- (void)keyUp:(NSEvent *)theEvent
{
if (sendKeyEvents) {
- bool keyOK = qt_dispatchKeyEvent(theEvent, qwidget);
- if (!keyOK) {
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
+ return;
+
+ bool keyEventEaten = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
+ if (!keyEventEaten && qwidget) {
+ // The event is not yet eaten, and if Qt is embedded inside a native
+ // cocoa application, send it to first responder not owned by Qt.
+ // The exception is if widgetToGetKey was redirected to a popup.
QWidget *toplevel = qwidget->window();
- if (toplevel && qt_widget_private(toplevel)->topData()->embedded) {
- if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
- [w keyUp:theEvent];
+ if (toplevel == widgetToGetKey->window()) {
+ if (qt_widget_private(toplevel)->topData()->embedded) {
+ if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
+ [w keyUp:theEvent];
+ }
}
}
}
@@ -1299,13 +939,14 @@ static int qCocoaViewCount = 0;
// When entering characters through Character Viewer or Keyboard Viewer, the text is passed
// through this insertText method. Since we dont receive a keyDown Event in such cases, the
// composing flag will be false.
- if (([aString length] && composing) || !fromKeyDownEvent) {
+ if (([aString length] && composing) || !fromKeyDownEvent) {
// Send the commit string to the widget.
composing = false;
sendKeyEvents = false;
QInputMethodEvent e;
e.setCommitString(commitText);
- qt_sendSpontaneousEvent(qwidget, &e);
+ if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
+ qt_sendSpontaneousEvent(widgetToGetKey, &e);
} else {
// The key sequence "`q" on a French Keyboard will generate two calls to insertText before
// it returns from interpretKeyEvents. The first call will turn off 'composing' and accept
@@ -1369,8 +1010,11 @@ static int qCocoaViewCount = 0;
0, composingLength, format);
}
*composingText = qtText;
+
QInputMethodEvent e(qtText, attrs);
- qt_sendSpontaneousEvent(qwidget, &e);
+ if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
+ qt_sendSpontaneousEvent(widgetToGetKey, &e);
+
if (!composingLength)
composing = false;
}
@@ -1380,7 +1024,8 @@ static int qCocoaViewCount = 0;
if (composing) {
QInputMethodEvent e;
e.setCommitString(*composingText);
- qt_sendSpontaneousEvent(qwidget, &e);
+ if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
+ qt_sendSpontaneousEvent(widgetToGetKey, &e);
}
composingText->clear();
composing = false;
@@ -1453,8 +1098,12 @@ static int qCocoaViewCount = 0;
{
Q_UNUSED(theRange);
// The returned rect is always based on the internal cursor.
- QRect mr(qwidget->inputMethodQuery(Qt::ImMicroFocus).toRect());
- QPoint mp(qwidget->mapToGlobal(QPoint(mr.bottomLeft())));
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
+ return NSZeroRect;
+
+ QRect mr(widgetToGetKey->inputMethodQuery(Qt::ImMicroFocus).toRect());
+ QPoint mp(widgetToGetKey->mapToGlobal(QPoint(mr.bottomLeft())));
NSRect rect ;
rect.origin.x = mp.x();
rect.origin.y = flipYCoordinate(mp.y());
@@ -1472,10 +1121,11 @@ static int qCocoaViewCount = 0;
- (NSArray*) validAttributesForMarkedText
{
- if (qwidget == 0)
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
return nil;
- if (!qwidget->testAttribute(Qt::WA_InputMethodEnabled))
+ if (!widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled))
return nil; // Not sure if that's correct, but it's saves a malloc.
// Support only underline color/style.
@@ -1489,7 +1139,7 @@ void QMacInputContext::reset()
{
QWidget *w = QInputContext::focusWidget();
if (w) {
- NSView *view = qt_mac_nativeview_for(w);
+ NSView *view = qt_mac_effectiveview_for(w);
if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
QMacCocoaAutoReleasePool pool;
QT_MANGLE_NAMESPACE(QCocoaView) *qc = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
@@ -1506,7 +1156,7 @@ bool QMacInputContext::isComposing() const
{
QWidget *w = QInputContext::focusWidget();
if (w) {
- NSView *view = qt_mac_nativeview_for(w);
+ NSView *view = qt_mac_effectiveview_for(w);
if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) isComposing];
}
@@ -1599,39 +1249,45 @@ Qt::DropAction QDragManager::drag(QDrag *o)
} else {
hotspot = dragPrivate()->hotspot;
}
- // convert the image to NSImage.
+
+ // Convert the image to NSImage:
NSImage *image = (NSImage *)qt_mac_create_nsimage(pix);
[image retain];
- DnDParams dndParams = *[QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
- // save supported actions
- [dndParams.view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
- NSPoint imageLoc = {dndParams.localPoint.x - hotspot.x(),
- dndParams.localPoint.y + pix.height() - hotspot.y()};
+
+ DnDParams *dndParams = macCurrentDnDParameters();
+ QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(dndParams->view);
+
+ // Save supported actions:
+ [theView setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
+ QPoint pointInView = [theView qt_qwidget]->mapFromGlobal(dndParams->globalPoint);
+ NSPoint imageLoc = {pointInView.x() - hotspot.x(), pointInView.y() + pix.height() - hotspot.y()};
NSSize mouseOffset = {0.0, 0.0};
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
- NSPoint windowPoint = [dndParams.theEvent locationInWindow];
dragPrivate()->executed_action = Qt::ActionMask;
- // do the drag
- [dndParams.view retain];
- [dndParams.view dragImage:image
- at:imageLoc
- offset:mouseOffset
- event:dndParams.theEvent
- pasteboard:pboard
- source:dndParams.view
- slideBack:YES];
- // reset the implicit grab widget when drag ends because we will not
- // receive the mouse release event when DND is active.
+
+ // Execute the drag:
+ [theView retain];
+ [theView dragImage:image
+ at:imageLoc
+ offset:mouseOffset
+ event:dndParams->theEvent
+ pasteboard:pboard
+ source:theView
+ slideBack:YES];
+
+ // Reset the implicit grab widget when drag ends because we will not
+ // receive the mouse release event when DND is active:
qt_button_down = 0;
- [dndParams.view release];
+ [theView release];
[image release];
if (dragPrivate())
dragPrivate()->executed_action = Qt::IgnoreAction;
object = 0;
- Qt::DropAction performedAction(qt_mac_mapNSDragOperation(qMacDnDParams()->performedAction));
- // do post drag processing, if required.
- if(performedAction != Qt::IgnoreAction) {
- // check if the receiver points us to a file location.
+ Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction));
+
+ // Do post drag processing, if required.
+ if (performedAction != Qt::IgnoreAction) {
+ // Check if the receiver points us to a file location.
// if so, we need to do the file copy/move ourselves.
QCFType<CFURLRef> pasteLocation = 0;
PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation);
@@ -1648,6 +1304,8 @@ Qt::DropAction QDragManager::drag(QDrag *o)
}
}
}
+
+ // Clean-up:
o->setMimeData(0);
o->deleteLater();
return performedAction;
diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h
index 511423357..2443129 100644
--- a/src/gui/kernel/qcocoaview_mac_p.h
+++ b/src/gui/kernel/qcocoaview_mac_p.h
@@ -58,57 +58,29 @@
QT_FORWARD_DECLARE_CLASS(QWidgetPrivate);
QT_FORWARD_DECLARE_CLASS(QWidget);
QT_FORWARD_DECLARE_CLASS(QEvent);
-QT_FORWARD_DECLARE_CLASS(QCocoaDropData);
QT_FORWARD_DECLARE_CLASS(QString);
QT_FORWARD_DECLARE_CLASS(QStringList);
-QT_BEGIN_NAMESPACE
-struct DnDParams
-{
- QT_MANGLE_NAMESPACE(QCocoaView) *view;
- NSEvent *theEvent;
- NSPoint localPoint;
- NSDragOperation performedAction;
- NSPoint activeDragEnterPos;
-};
-
-QT_END_NAMESPACE
-
-QT_FORWARD_DECLARE_STRUCT(DnDParams);
-
Q_GUI_EXPORT
@interface QT_MANGLE_NAMESPACE(QCocoaView) : NSControl <NSTextInput> {
QWidget *qwidget;
QWidgetPrivate *qwidgetprivate;
- bool leftButtonIsRightButton;
- QCocoaDropData *dropData;
NSDragOperation supportedActions;
bool composing;
int composingLength;
bool sendKeyEvents;
bool fromKeyDownEvent;
QString *composingText;
- NSInteger dragEnterSequence;
}
- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
- (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
- (void)frameDidChange:(NSNotification *)note;
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
-- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender;
-- (void)draggingExited:(id < NSDraggingInfo >)sender;
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
-- (void)removeDropData;
-- (void)addDropData:(id <NSDraggingInfo>)sender;
- (void)setSupportedActions:(NSDragOperation)actions;
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation;
- (BOOL)isComposing;
- (QWidget *)qt_qwidget;
- (void) qt_clearQWidget;
-- (BOOL)qt_leftButtonIsRightButton;
-- (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped;
-- (void)changeDraggingCursor:(NSDragOperation)newOperation;
-+ (DnDParams*)currentMouseEvent;
@end
#endif
diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm
index f1b642b..a4ab224 100644
--- a/src/gui/kernel/qcocoawindow_mac.mm
+++ b/src/gui/kernel/qcocoawindow_mac.mm
@@ -47,6 +47,8 @@
#import <private/qt_cocoa_helpers_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
#import <private/qcocoaapplication_mac_p.h>
+#import <private/qdnd_p.h>
+#import <private/qmultitouch_mac_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qcocoawindow_mac_p.h b/src/gui/kernel/qcocoawindow_mac_p.h
index 21f82df..028b809 100644
--- a/src/gui/kernel/qcocoawindow_mac_p.h
+++ b/src/gui/kernel/qcocoawindow_mac_p.h
@@ -50,17 +50,20 @@
// We mean it.
//
+#ifndef QCOCOAWINDOW_MAC_P
+#define QCOCOAWINDOW_MAC_P
+
#ifdef QT_MAC_USE_COCOA
#include "qmacdefines_mac.h"
#import <Cocoa/Cocoa.h>
#include <private/qapplication_p.h>
#include <private/qbackingstore_p.h>
-
enum { QtMacCustomizeWindow = 1 << 21 }; // This will one day be run over by
QT_FORWARD_DECLARE_CLASS(QWidget);
QT_FORWARD_DECLARE_CLASS(QStringList);
+QT_FORWARD_DECLARE_CLASS(QCocoaDropData);
@interface NSWindow (QtCoverForHackWithCategory)
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
@@ -72,13 +75,16 @@ QT_FORWARD_DECLARE_CLASS(QStringList);
@end
@interface QT_MANGLE_NAMESPACE(QCocoaWindow) : NSWindow {
- bool leftButtonIsRightButton;
QStringList *currentCustomDragTypes;
+ QCocoaDropData *dropData;
+ NSInteger dragEnterSequence;
}
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
- (void)registerDragTypes;
+- (void)drawRectOriginal:(NSRect)rect;
@end
#endif
+#endif
diff --git a/src/gui/kernel/qcursor.h b/src/gui/kernel/qcursor.h
index 62d2f41..9d22b7c 100644
--- a/src/gui/kernel/qcursor.h
+++ b/src/gui/kernel/qcursor.h
@@ -77,7 +77,7 @@ class QBitmap;
class QPixmap;
#if defined(Q_WS_MAC)
-void qt_mac_set_cursor(const QCursor *c, const QPoint &p);
+void qt_mac_set_cursor(const QCursor *c);
#endif
#if defined(Q_OS_SYMBIAN)
extern void qt_symbian_show_pointer_sprite();
@@ -141,7 +141,8 @@ private:
QCursorData *d;
#if defined(Q_WS_MAC)
friend void *qt_mac_nsCursorForQCursor(const QCursor &c);
- friend void qt_mac_set_cursor(const QCursor *c, const QPoint &p);
+ friend void qt_mac_set_cursor(const QCursor *c);
+ friend void qt_mac_updateCursorWithWidgetUnderMouse(QWidget *widgetUnderMouse);
#endif
#if defined(Q_OS_SYMBIAN)
friend void qt_symbian_show_pointer_sprite();
diff --git a/src/gui/kernel/qcursor_mac.mm b/src/gui/kernel/qcursor_mac.mm
index c3d6c54..cebe789 100644
--- a/src/gui/kernel/qcursor_mac.mm
+++ b/src/gui/kernel/qcursor_mac.mm
@@ -50,6 +50,7 @@
#include <AppKit/NSCursor.h>
#include <qpainter.h>
#include <private/qt_cocoa_helpers_mac_p.h>
+#include <private/qapplication_p.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,7 @@ extern QCursorData *qt_cursorTable[Qt::LastCursor + 1];
extern OSWindowRef qt_mac_window_for(const QWidget *); //qwidget_mac.cpp
extern GrafPtr qt_mac_qd_context(const QPaintDevice *); //qpaintdevice_mac.cpp
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_mac.cpp
+extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
/*****************************************************************************
Internal QCursorData class
@@ -95,18 +97,19 @@ protected:
}
};
-void *qt_mac_nsCursorForQCursor(const QCursor &c)
+inline void *qt_mac_nsCursorForQCursor(const QCursor &c)
{
c.d->update();
return [[static_cast<NSCursor *>(c.d->curs.cp.nscursor) retain] autorelease];
}
static QCursorData *currentCursor = 0; //current cursor
-void qt_mac_set_cursor(const QCursor *c, const QPoint &)
+
+void qt_mac_set_cursor(const QCursor *c)
{
#ifdef QT_MAC_USE_COCOA
- Q_UNUSED(c);
- return;
+ QMacCocoaAutoReleasePool pool;
+ [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*c)) set];
#else
if (!c) {
currentCursor = 0;
@@ -128,35 +131,122 @@ void qt_mac_set_cursor(const QCursor *c, const QPoint &)
c->d->curs.tc.anim->start(c->d->curs.tc.curs);
}
}
+
currentCursor = c->d;
#endif
}
-void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos)
+static QPointer<QWidget> lastWidgetUnderMouse = 0;
+static QPointer<QWidget> lastMouseCursorWidget = 0;
+static bool qt_button_down_on_prev_call = false;
+static QCursor *grabCursor = 0;
+
+void qt_mac_updateCursorWithWidgetUnderMouse(QWidget *widgetUnderMouse)
{
-#ifdef QT_MAC_USE_COCOA
- Q_UNUSED(globalPos);
- return;
-#else
QCursor cursor(Qt::ArrowCursor);
+ if (qt_button_down) {
+ // The widget that is currently pressed
+ // grabs the mouse cursor:
+ widgetUnderMouse = qt_button_down;
+ qt_button_down_on_prev_call = true;
+ } else if (qt_button_down_on_prev_call) {
+ // Grab has been released, so do
+ // a full check:
+ qt_button_down_on_prev_call = false;
+ lastWidgetUnderMouse = 0;
+ lastMouseCursorWidget = 0;
+ }
+
if (QApplication::overrideCursor()) {
cursor = *QApplication::overrideCursor();
- } else {
- for(QWidget *w = QApplication::widgetAt(globalPos); w; w = w->parentWidget()) {
- if(w->testAttribute(Qt::WA_SetCursor)) {
- cursor = w->cursor();
- break;
+ } else if (grabCursor) {
+ cursor = *grabCursor;
+ } else if (widgetUnderMouse) {
+ if (widgetUnderMouse == lastWidgetUnderMouse) {
+ // Optimization that should hit when the widget under
+ // the mouse does not change as the mouse moves:
+ if (lastMouseCursorWidget)
+ cursor = lastMouseCursorWidget->cursor();
+ } else {
+ QWidget *w = widgetUnderMouse;
+ for (; w; w = w->parentWidget()) {
+ if (w->testAttribute(Qt::WA_SetCursor)) {
+ cursor = w->cursor();
+ break;
+ }
+ if (w->isWindow())
+ break;
}
+ // One final check in case we ran out of parents in the loop:
+ if (w && !w->testAttribute(Qt::WA_SetCursor))
+ w = 0;
+
+ lastWidgetUnderMouse = widgetUnderMouse;
+ lastMouseCursorWidget = w;
}
}
- qt_mac_set_cursor(&cursor, globalPos);
+
+#ifdef QT_MAC_USE_COCOA
+ cursor.d->update();
+ NSCursor *nsCursor = static_cast<NSCursor *>(cursor.d->curs.cp.nscursor);
+ if ([NSCursor currentCursor] != nsCursor) {
+ QMacCocoaAutoReleasePool pool;
+ [nsCursor set];
+ }
+#else
+ qt_mac_set_cursor(&cursor);
#endif
}
void qt_mac_update_cursor()
{
- qt_mac_update_cursor_at_global_pos(QCursor::pos());
+ // This function is similar to qt_mac_updateCursorWithWidgetUnderMouse
+ // except that is clears the optimization cache, and finds the widget
+ // under mouse itself. Clearing the cache is useful in cases where the
+ // application has been deactivated/activated etc.
+ // NB: since we dont have any true native widget, the call to
+ // qt_mac_getTargetForMouseEvent will fail when the mouse is over QMacNativeWidgets.
+#ifdef QT_MAC_USE_COCOA
+ lastWidgetUnderMouse = 0;
+ lastMouseCursorWidget = 0;
+ QWidget *widgetUnderMouse = 0;
+
+ if (qt_button_down) {
+ widgetUnderMouse = qt_button_down;
+ } else {
+ QPoint localPoint;
+ QPoint globalPoint = QCursor::pos();
+ qt_mac_getTargetForMouseEvent(0, QEvent::None, localPoint, globalPoint, 0, &widgetUnderMouse);
+ }
+ qt_mac_updateCursorWithWidgetUnderMouse(widgetUnderMouse);
+#else
+ qt_mac_updateCursorWithWidgetUnderMouse(QApplication::widgetAt(QCursor::pos()));
+#endif
+}
+
+void qt_mac_setMouseGrabCursor(bool set, QCursor *const cursor = 0)
+{
+ if (grabCursor) {
+ delete grabCursor;
+ grabCursor = 0;
+ }
+ if (set) {
+ if (cursor)
+ grabCursor = new QCursor(*cursor);
+ else if (lastMouseCursorWidget)
+ grabCursor = new QCursor(lastMouseCursorWidget->cursor());
+ else
+ grabCursor = new QCursor(Qt::ArrowCursor);
+ }
+ qt_mac_update_cursor();
+}
+
+#ifndef QT_MAC_USE_COCOA
+void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos)
+{
+ qt_mac_updateCursorWithWidgetUnderMouse(QApplication::widgetAt(globalPos));
}
+#endif
static int nextCursorId = Qt::BitmapCursor;
@@ -427,7 +517,8 @@ void QCursorData::update()
break;
case Qt::DragCopyCursor:
type = QCursorData::TYPE_ThemeCursor;
- curs.cp.nscursor = [NSCursor dragCopyCursor];
+ if ([NSCursor respondsToSelector:@selector(dragCopyCursor)])
+ curs.cp.nscursor = [NSCursor performSelector:@selector(dragCopyCursor)];
break;
case Qt::DragMoveCursor:
type = QCursorData::TYPE_ThemeCursor;
@@ -435,7 +526,8 @@ void QCursorData::update()
break;
case Qt::DragLinkCursor:
type = QCursorData::TYPE_ThemeCursor;
- curs.cp.nscursor = [NSCursor dragLinkCursor];
+ if ([NSCursor respondsToSelector:@selector(dragLinkCursor)])
+ curs.cp.nscursor = [NSCursor performSelector:@selector(dragLinkCursor)];
break;
#define QT_USE_APPROXIMATE_CURSORS
#ifdef QT_USE_APPROXIMATE_CURSORS
diff --git a/src/gui/kernel/qdnd_mac.mm b/src/gui/kernel/qdnd_mac.mm
index 844f5e3..6f43fb6 100644
--- a/src/gui/kernel/qdnd_mac.mm
+++ b/src/gui/kernel/qdnd_mac.mm
@@ -491,7 +491,7 @@ bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef)
SetThemeCursor(cursor);
}
if(found_cursor) {
- qt_mac_set_cursor(0, QPoint()); //just use our's
+ qt_mac_set_cursor(0); //just use our's
} else {
QCursor cursor(Qt::ArrowCursor);
if(qApp && qApp->overrideCursor()) {
@@ -504,7 +504,7 @@ bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef)
}
}
}
- qt_mac_set_cursor(&cursor, QPoint(mouse.h, mouse.v));
+ qt_mac_set_cursor(&cursor);
}
//idle things
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index 48d21e9..7a4af8f 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -89,9 +89,14 @@
#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
+// Cmd + left mousebutton should produce a right button
+// press (mainly for mac users with one-button mice):
+static bool qt_leftButtonIsRightButton = false;
+
Q_GLOBAL_STATIC(QMacWindowFader, macwindowFader);
QMacWindowFader::QMacWindowFader()
@@ -141,6 +146,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 +175,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 +373,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 +589,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 +807,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 +818,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 +828,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 +857,6 @@ void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget
#endif
}
-
QPointF flipPoint(const NSPoint &p)
{
return QPointF(p.x, flipYCoordinate(p.y));
@@ -804,21 +872,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 +998,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 +1023,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)
+{
+ if (QWidget *popup = QApplication::activePopupWidget()) {
+ QWidget *focusInPopup = popup->focusWidget();
+ return focusInPopup ? focusInPopup : popup;
+ }
+
+ QWidget *widgetToGetKey = qApp->focusWidget();
+ if (!widgetToGetKey)
+ widgetToGetKey = widgetThatReceivedEvent;
+
+ 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)
{
-#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);
+ returnGlobalPoint = flipPoint([NSEvent mouseLocation]).toPoint();
+ QWidget *mouseGrabber = QWidget::mouseGrabber();
+ bool buttonDownNotBlockedByModal = qt_button_down && !QApplicationPrivate::isBlockedByModal(qt_button_down);
+
+ // Resolve the widget under the mouse:
+ QWidget *widgetUnderMouse = 0;
+ if (nativeWidget) {
+ 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);
+ }
- // Give the Input Manager a chance to process the mouse events.
- NSInputManager *currentIManager = [NSInputManager currentInputManager];
- if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
- [currentIManager handleMouseEvent:theEvent];
- }
+ 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;
+ }
- // 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;
+ 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 popup-"grab", mousegrab, or button-down-"grab":
+ QWidget *popup = QApplication::activePopupWidget();
+ 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:
+ if (eventType == QEvent::Wheel)
+ return 0;
+ returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint);
+ return popup;
+ } else if (popup == widgetUnderMouse) {
+ returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint);
+ return popup;
+ } else {
+ returnLocalPoint = widgetUnderMouse->mapFromGlobal(returnGlobalPoint);
+ return widgetUnderMouse;
+ }
}
- NSPoint windowPoint = [theEvent locationInWindow];
- NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
+ QWidget *target = mouseGrabber;
+ if (!target && buttonDownNotBlockedByModal)
+ target = qt_button_down;
+ if (!target)
+ target = widgetUnderMouse;
+ if (!target)
+ return 0;
- // 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());
+ returnLocalPoint = target->mapFromGlobal(returnGlobalPoint);
+ return target;
+}
- 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];
- }
+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_mouse_receiver) && qt_last_mouse_receiver)
+ return;
+
+ if (maybeEnterWidget) {
+ if (!qt_last_mouse_receiver) {
+ // case 3
+ QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, 0);
+ qt_last_mouse_receiver = maybeEnterWidget;
+ } else if (qt_last_mouse_receiver->internalWinId() && maybeEnterWidget->internalWinId()) {
+ // case 1
+ if (qt_last_mouse_receiver->isVisible()) {
+ QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = maybeEnterWidget;
+ }
+ } // 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_mouse_receiver && qt_last_mouse_receiver->internalWinId()) {
+ // 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:
+ qt_last_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);
+ 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;
+ }
+ 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];
+ Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);
+ NSInteger clickCount = [event clickCount];
Qt::MouseButtons buttons = 0;
{
UInt32 mac_buttons;
@@ -1059,55 +1221,65 @@ 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
+ qt_button_down = widgetUnderMouse;
if (clickCount % 2 == 0 && buttons == 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.
+ widgetToGetMouse = qt_mac_getTargetForMouseEvent(0, QEvent::None, localPoint, globalPoint, nativeWidget, &widgetUnderMouse);
+ qt_mac_checkEnterLeaveForNativeWidgets(widgetUnderMouse);
+ }
+
return true;
-#endif
}
+#endif
bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */tabletEvent)
{
@@ -1291,17 +1463,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 +1493,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 +1518,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 +1620,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 +1654,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 +1685,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()
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
index 04c2d06..d2978c2 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h
+++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -144,18 +144,14 @@ bool qt_mac_checkForNativeSizeGrip(const QWidget *widget);
void qt_dispatchTabletProximityEvent(void * /*NSEvent * */ tabletEvent);
#ifdef QT_MAC_USE_COCOA
bool qt_dispatchKeyEventWithCocoa(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent);
-void qt_cocoaChangeOverrideCursor(const QCursor &cursor);
// These methods exists only for supporting unified mode.
void macDrawRectOnTop(void * /*OSWindowRef */ window);
void macSyncDrawingOnFirstInvocation(void * /*OSWindowRef */window);
void qt_cocoaStackChildWindowOnTopOfOtherChildren(QWidget *widget);
-#endif
void qt_mac_menu_collapseSeparators(void * /*NSMenu */ menu, bool collapse);
+#endif
bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent);
void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget *widgetToGetEvent);
-void qt_mac_dispatchNCMouseMessage(void */* NSWindow* */eventWindow, void */* NSEvent* */mouseEvent,
- QWidget *widgetToGetEvent, bool &leftButtonIsRightButton);
-bool qt_mac_handleMouseEvent(void * /*QCocoaView * */view, void * /*NSEvent * */event, QEvent::Type eventType, Qt::MouseButton button);
bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */event);
inline QApplication *qAppInstance() { return static_cast<QApplication *>(QCoreApplication::instance()); }
struct ::TabletProximityRec;
@@ -165,6 +161,29 @@ Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations);
QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height);
void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon,
QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase);
+
+#if QT_MAC_USE_COCOA && __OBJC__
+struct DnDParams
+{
+ NSView *view;
+ NSEvent *theEvent;
+ QPoint globalPoint;
+ NSDragOperation performedAction;
+};
+
+DnDParams *macCurrentDnDParameters();
+NSDragOperation qt_mac_mapDropAction(Qt::DropAction action);
+NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions);
+Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions);
+Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions);
+
+QWidget *qt_mac_getTargetForKeyEvent(QWidget *widgetThatReceivedEvent);
+QWidget *qt_mac_getTargetForMouseEvent(NSEvent *event, QEvent::Type eventType,
+ QPoint &returnLocalPoint, QPoint &returnGlobalPoint, QWidget *nativeWidget, QWidget **returnWidgetUnderMouse);
+bool qt_mac_handleMouseEvent(NSEvent *event, QEvent::Type eventType, Qt::MouseButton button, QWidget *nativeWidget);
+void qt_mac_handleNonClientAreaMouseEvent(NSWindow *window, NSEvent *event);
+#endif
+
inline int flipYCoordinate(int y)
{
return QApplication::desktop()->screenGeometry(0).height() - y;
@@ -221,6 +240,7 @@ public:
}
};
void qt_cocoaPostMessage(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0);
+void qt_cocoaPostMessageAfterEventLoopExit(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0);
#endif
#endif
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index cd1c9f0..e5e1e00 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -144,6 +144,10 @@ Q_GUI_EXPORT void qt_x11_set_global_double_buffer(bool enable)
}
#endif
+#if defined(QT_MAC_USE_COCOA)
+bool qt_mac_clearDirtyOnWidgetInsideDrawWidget = false;
+#endif
+
static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
{
return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) &&
@@ -300,7 +304,6 @@ QWidgetPrivate::QWidgetPrivate(int version)
#endif
#elif defined(Q_WS_MAC)
, needWindowChange(0)
- , hasAlienChildren(0)
, window_event(0)
, qd_hd(0)
#elif defined (Q_WS_QPA)
@@ -1305,9 +1308,9 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
if (f & Qt::MSWindowsOwnDC)
q->setAttribute(Qt::WA_NativeWindow);
-#ifdef Q_WS_MAC
- q->setAttribute(Qt::WA_NativeWindow);
-#endif
+//#ifdef Q_WS_MAC
+// q->setAttribute(Qt::WA_NativeWindow);
+//#endif
q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute()
adjustQuitOnCloseAttribute();
@@ -1414,10 +1417,6 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
#ifndef Q_WS_QPA
if (QWidget *parent = parentWidget()) {
-#ifdef Q_WS_MAC
- if (testAttribute(Qt::WA_NativeWindow) == false)
- parent->d_func()->hasAlienChildren = true;
-#endif
if (type & Qt::Window) {
if (!parent->testAttribute(Qt::WA_WState_Created))
parent->createWinId();
@@ -5405,6 +5404,9 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
return;
#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+ if (qt_mac_clearDirtyOnWidgetInsideDrawWidget)
+ dirtyOnWidget = QRegion();
+
// We disable the rendering of QToolBar in the backingStore if
// it's supposed to be in the unified toolbar on Mac OS X.
if (backingStore && isInUnifiedToolbar)
@@ -5492,7 +5494,6 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
//paint the background
if ((asRoot || q->autoFillBackground() || onScreen || q->testAttribute(Qt::WA_StyledBackground))
&& !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) {
-
QPainter p(q);
paintBackground(&p, toBePainted, (asRoot || onScreen) ? flags | DrawAsRoot : 0);
}
@@ -5674,10 +5675,12 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
QRect boundingRect;
bool dirtyBoundingRect = true;
const bool exludeOpaqueChildren = (flags & DontDrawOpaqueChildren);
+ const bool excludeNativeChildren = (flags & DontDrawNativeChildren);
do {
QWidget *x = qobject_cast<QWidget*>(siblings.at(index));
- if (x && !(exludeOpaqueChildren && x->d_func()->isOpaque) && !x->isHidden() && !x->isWindow()) {
+ if (x && !(exludeOpaqueChildren && x->d_func()->isOpaque) && !x->isHidden() && !x->isWindow()
+ && !(excludeNativeChildren && x->internalWinId())) {
if (dirtyBoundingRect) {
boundingRect = rgn.boundingRect();
dirtyBoundingRect = false;
@@ -10081,7 +10084,13 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN)
if (newParent && parent && !desktopWidget) {
- if (testAttribute(Qt::WA_NativeWindow) && !qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings))
+ if (testAttribute(Qt::WA_NativeWindow) && !qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings)
+#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+ // On Mac, toolbars inside the unified title bar will never overlap with
+ // siblings in the content view. So we skip enforce native siblings in that case
+ && !d->isInUnifiedToolbar && parentWidget() && parentWidget()->isWindow()
+#endif // Q_WS_MAC && QT_MAC_USE_COCOA
+ )
parent->d_func()->enforceNativeChildren();
else if (parent->d_func()->nativeChildrenForced() || parent->testAttribute(Qt::WA_PaintOnScreen))
setAttribute(Qt::WA_NativeWindow);
@@ -10728,7 +10737,13 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
ic->setFocusWidget(0);
}
}
- if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget())
+ if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget()
+#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+ // On Mac, toolbars inside the unified title bar will never overlap with
+ // siblings in the content view. So we skip enforce native siblings in that case
+ && !d->isInUnifiedToolbar && parentWidget()->isWindow()
+#endif // Q_WS_MAC && QT_MAC_USE_COCOA
+ )
parentWidget()->d_func()->enforceNativeChildren();
if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created))
d->createWinId();
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index fc94616..e0cdc16 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -155,7 +155,6 @@ static bool qt_mac_raise_process = true;
static OSWindowRef qt_root_win = 0;
QWidget *mac_mouse_grabber = 0;
QWidget *mac_keyboard_grabber = 0;
-extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
#ifndef QT_MAC_USE_COCOA
#ifdef QT_NAMESPACE
@@ -179,13 +178,14 @@ static CFStringRef kObjectQWidget = CFSTR("com.trolltech.qt.widget");
/*****************************************************************************
Externals
*****************************************************************************/
+extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
extern QWidget *qt_mac_modal_blocked(QWidget *); //qapplication_mac.mm
extern void qt_event_request_activate(QWidget *); //qapplication_mac.mm
extern bool qt_event_remove_activate(); //qapplication_mac.mm
extern void qt_mac_event_release(QWidget *w); //qapplication_mac.mm
extern void qt_event_request_showsheet(QWidget *); //qapplication_mac.mm
extern void qt_event_request_window_change(QWidget *); //qapplication_mac.mm
-extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
+extern QPointer<QWidget> qt_last_mouse_receiver; //qapplication_mac.mm
extern IconRef qt_mac_create_iconref(const QPixmap &); //qpixmap_mac.cpp
extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.mm
extern void qt_mac_update_cursor(); //qcursor_mac.mm
@@ -193,7 +193,8 @@ extern bool qt_nograb();
extern CGImageRef qt_mac_create_cgimage(const QPixmap &, bool); //qpixmap_mac.cpp
extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp
-
+extern void qt_mac_setMouseGrabCursor(bool set, QCursor *cursor = 0); // qcursor_mac.mm
+extern QPointer<QWidget> topLevelAt_cache; // qapplication_mac.mm
/*****************************************************************************
QWidget utility functions
*****************************************************************************/
@@ -217,22 +218,13 @@ static QSize qt_mac_desktopSize()
#ifdef QT_MAC_USE_COCOA
static NSDrawer *qt_mac_drawer_for(const QWidget *widget)
{
- // This only goes one level below the content view so start with the window.
- // This works fine for straight Qt stuff, but runs into problems if we are
- // embedding, but if that's the case, they probably want to be using
- // NSDrawer directly.
- NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->winId());
+ NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->effectiveWinId());
NSArray *windows = [NSApp windows];
for (NSWindow *window in windows) {
NSArray *drawers = [window drawers];
for (NSDrawer *drawer in drawers) {
if ([drawer contentView] == widgetView)
return drawer;
- NSArray *views = [[drawer contentView] subviews];
- for (NSView *view in views) {
- if (view == widgetView)
- return drawer;
- }
}
}
return 0;
@@ -314,7 +306,7 @@ bool qt_mac_is_macdrawer(const QWidget *w)
bool qt_mac_insideKeyWindow(const QWidget *w)
{
#ifdef QT_MAC_USE_COCOA
- return [[reinterpret_cast<NSView *>(w->winId()) window] isKeyWindow];
+ return [[reinterpret_cast<NSView *>(w->effectiveWinId()) window] isKeyWindow];
#else
Q_UNUSED(w);
#endif
@@ -421,7 +413,14 @@ inline static void qt_mac_set_fullscreen_mode(bool b)
Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w)
{
- return reinterpret_cast<OSViewRef>(w->data->winid);
+ return reinterpret_cast<OSViewRef>(w->internalWinId());
+}
+
+Q_GUI_EXPORT OSViewRef qt_mac_effectiveview_for(const QWidget *w)
+{
+ // Get the first non-alien (parent) widget for
+ // w, and return its NSView (if it has one):
+ return reinterpret_cast<OSViewRef>(w->effectiveWinId());
}
Q_GUI_EXPORT OSViewRef qt_mac_get_contentview_for(OSWindowRef w)
@@ -479,11 +478,12 @@ bool qt_isGenuineQWidget(const QWidget *window)
Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
{
- OSViewRef hiview = qt_mac_nativeview_for(w);
- if (hiview){
+ if (OSViewRef hiview = qt_mac_effectiveview_for(w)) {
OSWindowRef window = qt_mac_window_for(hiview);
- if (!window && qt_isGenuineQWidget(hiview)) {
- QWidget *myWindow = w->window();
+ if (window)
+ return window;
+
+ if (qt_isGenuineQWidget(hiview)) {
// This is a workaround for NSToolbar. When a widget is hidden
// by clicking the toolbar button, Cocoa reparents the widgets
// to another window (but Qt doesn't know about it).
@@ -491,18 +491,22 @@ Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
// but at this point it's window is nil, but the window it's being brought
// into (the Qt one) is for sure created.
// This stops the hierarchy moving under our feet.
- if (myWindow != w && qt_mac_window_for(qt_mac_nativeview_for(myWindow)))
- return qt_mac_window_for(qt_mac_nativeview_for(myWindow));
+ QWidget *toplevel = w->window();
+ if (toplevel != w) {
+ hiview = qt_mac_nativeview_for(toplevel);
+ if (OSWindowRef w = qt_mac_window_for(hiview))
+ return w;
+ }
- myWindow->d_func()->createWindow_sys();
- // Reget the hiview since the "create window could potentially move the view (I guess).
- hiview = qt_mac_nativeview_for(w);
- window = qt_mac_window_for(hiview);
+ toplevel->d_func()->createWindow_sys();
+ // Reget the hiview since "create window" could potentially move the view (I guess).
+ hiview = qt_mac_nativeview_for(toplevel);
+ return qt_mac_window_for(hiview);
}
- return window;
}
return 0;
}
+
#ifndef QT_MAC_USE_COCOA
/* Checks if the current group is a 'stay on top' group. If so, the
group gets removed from the hash table */
@@ -580,25 +584,6 @@ inline static void qt_mac_set_window_group_to_popup(OSWindowRef window)
}
#endif
-#ifdef QT_MAC_USE_COCOA
-void qt_mac_set_needs_display(QWidget *widget, QRegion region)
-{
- NSView *theNSView = qt_mac_nativeview_for(widget);
- if (region.isEmpty()) {
- [theNSView setNeedsDisplay:YES];
- return;
- }
-
- QVector<QRect> rects = region.rects();
- for (int i = 0; i<rects.count(); ++i) {
- const QRect &rect = rects.at(i);
- NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
- [theNSView setNeedsDisplayInRect:nsrect];
- }
-
-}
-#endif
-
inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
{
if (!widget)
@@ -636,6 +621,51 @@ inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const
return false;
}
+void QWidgetPrivate::macSetNeedsDisplay(QRegion region)
+{
+ Q_Q(QWidget);
+#ifndef QT_MAC_USE_COCOA
+ if (region.isEmpty())
+ HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true);
+ else if (RgnHandle rgnHandle = region.toQDRgnForUpdate_sys())
+ HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
+ else
+ HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
+#else
+ if (NSView *nativeView = qt_mac_nativeview_for(q)) {
+ // INVARIANT: q is _not_ alien. So we can optimize a little:
+ if (region.isEmpty()) {
+ [nativeView setNeedsDisplay:YES];
+ } else {
+ QVector<QRect> rects = region.rects();
+ for (int i = 0; i<rects.count(); ++i) {
+ const QRect &rect = rects.at(i);
+ NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
+ [nativeView setNeedsDisplayInRect:nsrect];
+ }
+ }
+ } else if (QWidget *effectiveWidget = q->nativeParentWidget()) {
+ // INVARIANT: q is alien, and effectiveWidget is native.
+ if (NSView *effectiveView = qt_mac_nativeview_for(effectiveWidget)) {
+ if (region.isEmpty()) {
+ const QRect &rect = q->rect();
+ QPoint p = q->mapTo(effectiveWidget, rect.topLeft());
+ NSRect nsrect = NSMakeRect(p.x(), p.y(), rect.width(), rect.height());
+ [effectiveView setNeedsDisplayInRect:nsrect];
+ } else {
+ QVector<QRect> rects = region.rects();
+ for (int i = 0; i<rects.count(); ++i) {
+ const QRect &rect = rects.at(i);
+ QPoint p = q->mapTo(effectiveWidget, rect.topLeft());
+ NSRect nsrect = NSMakeRect(p.x(), p.y(), rect.width(), rect.height());
+ [effectiveView setNeedsDisplayInRect:nsrect];
+ }
+ }
+ }
+ }
+#endif
+}
+
void QWidgetPrivate::macUpdateIsOpaque()
{
Q_Q(QWidget);
@@ -1569,6 +1599,11 @@ OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, O
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
QT_MANGLE_NAMESPACE(QCocoaView) *view = [[QT_MANGLE_NAMESPACE(QCocoaView) alloc] initWithQWidget:widget widgetPrivate:widgetPrivate];
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "Creating NSView for" << widget;
+#endif
+
if (view && parent)
[parent addSubview:view];
return view;
@@ -1635,7 +1670,7 @@ bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
// to happen, prevent that here (you really want the thing hidden).
if (up >= 0 || topData->resizer != 0)
topData->resizer += up;
- OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->winId()));
+ OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->effectiveWinId()));
{
#ifndef QT_MAC_USE_COCOA
WindowClass wclass;
@@ -1670,6 +1705,7 @@ bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
void QWidgetPrivate::qt_clean_root_win()
{
#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
[qt_root_win release];
#else
if(!qt_root_win)
@@ -2307,15 +2343,12 @@ void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWin
}
[windowRef setContentView:nsview];
[nsview setHidden:NO];
- if (q->testAttribute(Qt::WA_DropSiteRegistered))
- registerDropSite(true);
transferChildren();
// Tell Cocoa explicit that we wan't the view to receive key events
// (regardless of focus policy) because this is how it works on other
// platforms (and in the carbon port):
- if (!qApp->focusWidget())
- [windowRef makeFirstResponder:nsview];
+ [windowRef makeFirstResponder:nsview];
if (topExtra->posFromMove) {
updateFrameStrut();
@@ -2346,8 +2379,9 @@ void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWin
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
- if (qApp->overrideCursor())
- [windowRef disableCursorRects];
+ // Its more performant to handle the mouse cursor
+ // ourselves, expecially when using alien widgets:
+ [windowRef disableCursorRects];
setWindowLevel();
macUpdateHideOnSuspend();
@@ -2465,8 +2499,6 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
data.crect.setRect(0, 0, desktopSize.width(), desktopSize.height());
dialog = popup = false; // force these flags off
} else {
- q->setAttribute(Qt::WA_WState_Visible, false);
-
if (topLevel && (type != Qt::Drawer)) {
if (QDesktopWidget *dsk = QApplication::desktop()) { // calc pos/size from screen
const bool wasResized = q->testAttribute(Qt::WA_Resized);
@@ -2556,6 +2588,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
transfer = true;
} else if (parentWidget) {
// I need to be added to my parent, therefore my parent needs an NSView
+ // Alien note: a 'window' was supplied as argument, meaning this widget
+ // is not alien. So therefore the parent cannot be alien either.
parentWidget->createWinId();
parent = qt_mac_nativeview_for(parentWidget);
}
@@ -2627,11 +2661,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
data.fstrut_dirty = false; // non-toplevel widgets don't have a frame, so no need to update the strut
#ifdef QT_MAC_USE_COCOA
- if (q->testAttribute(Qt::WA_NativeWindow) == false ||
- q->internalWinId() != 0) {
-#ifdef ALIEN_DEBUG
- qDebug() << "Skipping native widget creation for" << this;
-#endif
+ if (q->testAttribute(Qt::WA_NativeWindow) == false || q->internalWinId() != 0) {
+ // INVARIANT: q is Alien, and we should not create an NSView to back it up.
} else
#endif
if (OSViewRef osview = qt_mac_create_widget(q, this, qt_mac_nativeview_for(parentWidget))) {
@@ -2643,13 +2674,20 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
[osview setFrame:bounds];
setWinId((WId)osview);
+ if (q->isVisible()) {
+ // If q were Alien before, but now became native (e.g. if a call to
+ // winId was done from somewhere), we need to show the view immidiatly:
+ QMacCocoaAutoReleasePool pool;
+ [osview setHidden:NO];
+ }
#endif
- if (q->testAttribute(Qt::WA_DropSiteRegistered))
- registerDropSite(true);
}
}
updateIsOpaque();
+
+ if (q->testAttribute(Qt::WA_DropSiteRegistered))
+ registerDropSite(true);
if (q->hasFocus())
setFocus_sys();
if (!topLevel && initializeWindow)
@@ -2691,16 +2729,29 @@ QWidget::macCGHandle() const
return handle();
}
+void qt_mac_repaintParentUnderAlienWidget(QWidget *alienWidget)
+{
+ QWidget *nativeParent = alienWidget->nativeParentWidget();
+ if (!nativeParent)
+ return;
+
+ QPoint globalPos = alienWidget->mapToGlobal(QPoint(0, 0));
+ QRect dirtyRect = QRect(nativeParent->mapFromGlobal(globalPos), alienWidget->size());
+ nativeParent->repaint(dirtyRect);
+}
+
void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
+ QMacCocoaAutoReleasePool pool;
d->aboutToDestroy();
if (!isWindow() && parentWidget())
parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
+ if (!internalWinId())
+ qt_mac_repaintParentUnderAlienWidget(this);
d->deactivateWidgetCleanup();
qt_mac_event_release(this);
if(testAttribute(Qt::WA_WState_Created)) {
- QMacCocoaAutoReleasePool pool;
setAttribute(Qt::WA_WState_Created, false);
QObjectList chldrn = children();
for(int i = 0; i < chldrn.size(); i++) { // destroy all widget children
@@ -2756,7 +2807,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
void QWidgetPrivate::transferChildren()
{
Q_Q(QWidget);
- if (!q->testAttribute(Qt::WA_WState_Created))
+ if (!q->internalWinId())
return; // Can't add any views anyway
QObjectList chlist = q->children();
@@ -2768,7 +2819,7 @@ void QWidgetPrivate::transferChildren()
// This seems weird, no need to call it in a loop right?
if (!topData()->caption.isEmpty())
setWindowTitle_helper(extra->topextra->caption);
- if (w->testAttribute(Qt::WA_WState_Created)) {
+ if (w->internalWinId()) {
#ifndef QT_MAC_USE_COCOA
HIViewAddSubview(qt_mac_nativeview_for(q), qt_mac_nativeview_for(w));
#else
@@ -2889,11 +2940,11 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
#ifndef QT_MAC_USE_COCOA
old_window_event = window_event;
#else
- OSWindowRef oldWindow = qt_mac_window_for(old_id);
if (qt_mac_is_macdrawer(q)) {
oldDrawer = qt_mac_drawer_for(q);
}
if (wasWindow) {
+ OSWindowRef oldWindow = qt_mac_window_for(old_id);
oldToolbar = [oldWindow toolbar];
if (oldToolbar) {
[oldToolbar retain];
@@ -3015,7 +3066,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
QPoint QWidget::mapToGlobal(const QPoint &pos) const
{
Q_D(const QWidget);
- if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ if (!internalWinId()) {
QPoint p = pos + data->crect.topLeft();
return isWindow() ? p : parentWidget()->mapToGlobal(p);
}
@@ -3042,7 +3093,7 @@ QPoint QWidget::mapToGlobal(const QPoint &pos) const
QPoint QWidget::mapFromGlobal(const QPoint &pos) const
{
Q_D(const QWidget);
- if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ if (!internalWinId()) {
QPoint p = isWindow() ? pos : parentWidget()->mapFromGlobal(pos);
return p - data->crect.topLeft();
}
@@ -3069,28 +3120,12 @@ void QWidgetPrivate::updateSystemBackground()
void QWidgetPrivate::setCursor_sys(const QCursor &)
{
-#ifndef QT_MAC_USE_COCOA
qt_mac_update_cursor();
-#else
- Q_Q(QWidget);
- if (q->testAttribute(Qt::WA_WState_Created)) {
- QMacCocoaAutoReleasePool pool;
- [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
- }
-#endif
}
void QWidgetPrivate::unsetCursor_sys()
{
-#ifndef QT_MAC_USE_COCOA
qt_mac_update_cursor();
-#else
- Q_Q(QWidget);
- if (q->testAttribute(Qt::WA_WState_Created)) {
- QMacCocoaAutoReleasePool pool;
- [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
- }
-#endif
}
void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
@@ -3232,24 +3267,28 @@ void QWidget::grabMouse()
if(mac_mouse_grabber)
mac_mouse_grabber->releaseMouse();
mac_mouse_grabber=this;
+ qt_mac_setMouseGrabCursor(true);
}
}
#ifndef QT_NO_CURSOR
-void QWidget::grabMouse(const QCursor &)
+void QWidget::grabMouse(const QCursor &cursor)
{
if(isVisible() && !qt_nograb()) {
if(mac_mouse_grabber)
mac_mouse_grabber->releaseMouse();
mac_mouse_grabber=this;
+ qt_mac_setMouseGrabCursor(true, const_cast<QCursor *>(&cursor));
}
}
#endif
void QWidget::releaseMouse()
{
- if(!qt_nograb() && mac_mouse_grabber == this)
+ if(!qt_nograb() && mac_mouse_grabber == this) {
mac_mouse_grabber = 0;
+ qt_mac_setMouseGrabCursor(false);
+ }
}
void QWidget::grabKeyboard()
@@ -3334,35 +3373,10 @@ QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
void QWidgetPrivate::update_sys(const QRect &r)
{
Q_Q(QWidget);
- if (r == q->rect()) {
- if (updateRedirectedToGraphicsProxyWidget(q, r))
- return;
- dirtyOnWidget += r;
-#ifndef QT_MAC_USE_COCOA
- HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true);
-#else
- qt_mac_set_needs_display(q, QRegion());
-#endif
+ if (updateRedirectedToGraphicsProxyWidget(q, r))
return;
- }
-
- int x = r.x(), y = r.y(), w = r.width(), h = r.height();
- if (w < 0)
- w = q->data->crect.width() - x;
- if (h < 0)
- h = q->data->crect.height() - y;
- if (w && h) {
- const QRect updateRect = QRect(x, y, w, h);
- if (updateRedirectedToGraphicsProxyWidget(q, updateRect))
- return;
-#ifndef QT_MAC_USE_COCOA
- dirtyOnWidget += updateRect;
- HIRect r = CGRectMake(x, y, w, h);
- HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true);
-#else
- [qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(x, y, w, h)];
-#endif
- }
+ dirtyOnWidget += r;
+ macSetNeedsDisplay(r != q->rect() ? r : QRegion());
}
void QWidgetPrivate::update_sys(const QRegion &rgn)
@@ -3371,33 +3385,7 @@ void QWidgetPrivate::update_sys(const QRegion &rgn)
if (updateRedirectedToGraphicsProxyWidget(q, rgn))
return;
dirtyOnWidget += rgn;
-#ifndef QT_MAC_USE_COCOA
- RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys();
- if (rgnHandle)
- HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
- else {
- HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
- }
-#else
- // Alien support: get the first native ancestor widget (will be q itself in the non-alien case),
- // map the coordinates from q space to NSView space and invalidate the rect.
- QWidget *nativeParent = q->internalWinId() ? q : q->nativeParentWidget();
- if (nativeParent == 0)
- return;
-
- QVector<QRect> rects = rgn.rects();
- for (int i = 0; i < rects.count(); ++i) {
- const QRect &rect = rects.at(i);
-
- const QRect nativeBoundingRect = QRect(
- QPoint(q->mapTo(nativeParent, rect.topLeft())),
- QSize(rect.size()));
-
- [qt_mac_nativeview_for(nativeParent) setNeedsDisplayInRect:NSMakeRect(nativeBoundingRect.x(),
- nativeBoundingRect.y(), nativeBoundingRect.width(),
- nativeBoundingRect.height())];
- }
-#endif
+ macSetNeedsDisplay(rgn);
}
bool QWidgetPrivate::isRealWindow() const
@@ -3436,7 +3424,6 @@ void QWidgetPrivate::show_sys()
data.fstrut_dirty = true;
if (realWindow) {
- // Delegates can change window state, so record some things earlier.
bool isCurrentlyMinimized = (q->windowState() & Qt::WindowMinimized);
setModal_sys();
OSWindowRef window = qt_mac_window_for(q);
@@ -3483,9 +3470,11 @@ void QWidgetPrivate::show_sys()
}
}
setSubWindowStacking(true);
+ qt_mac_update_cursor();
#endif
if (q->windowType() == Qt::Popup) {
- if (q->focusWidget())
+ qt_button_down = 0;
+ if (q->focusWidget())
q->focusWidget()->d_func()->setFocus_sys();
else
setFocus_sys();
@@ -3507,21 +3496,32 @@ void QWidgetPrivate::show_sys()
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
- [qt_mac_nativeview_for(q) setHidden:NO];
-
+ if (NSView *view = qt_mac_nativeview_for(q)) {
+ // INVARIANT: q is native. Just show the view:
+ [view setHidden:NO];
+ } else {
+ // INVARIANT: q is alien. Repaint q instead:
+ q->repaint();
+ }
#endif
}
- if (!QWidget::mouseGrabber()){
- QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
- QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
- qt_mouseover = enterWidget;
+#ifdef QT_MAC_USE_COCOA
+ if ([NSApp isActive] && !qt_button_down && !QWidget::mouseGrabber()){
+ // Update enter/leave immidiatly, don't wait for a move event. But only
+ // if no grab exists (even if the grab points to this widget, it seems, ref X11)
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = widgetUnderMouse;
}
+#endif
+ topLevelAt_cache = 0;
qt_event_request_window_change(q);
}
-
QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt)
{
#ifndef QT_MAC_USE_COCOA
@@ -3602,6 +3602,7 @@ void QWidgetPrivate::hide_sys()
}
#endif
toggleDrawers(false);
+ qt_mac_update_cursor();
#ifndef QT_MAC_USE_COCOA
// Clear modality (because it seems something that we've always done).
if (data.window_modality != Qt::NonModal) {
@@ -3649,18 +3650,29 @@ void QWidgetPrivate::hide_sys()
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), false);
#else
- [qt_mac_nativeview_for(q) setHidden:YES];
+ if (NSView *view = qt_mac_nativeview_for(q)) {
+ // INVARIANT: q is native. Just hide the view:
+ [view setHidden:YES];
+ } else {
+ // INVARIANT: q is alien. Repaint where q is placed instead:
+ qt_mac_repaintParentUnderAlienWidget(q);
+ }
#endif
}
- if (!QWidget::mouseGrabber()){
- QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
- if (enterWidget && enterWidget->data->in_destructor)
- enterWidget = 0;
- QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
- qt_mouseover = enterWidget;
- }
-
+#ifdef QT_MAC_USE_COCOA
+ if ([NSApp isActive] && !qt_button_down && !QWidget::mouseGrabber()){
+ // Update enter/leave immidiatly, don't wait for a move event. But only
+ // if no grab exists (even if the grab points to this widget, it seems, ref X11)
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(0, QEvent::Leave, qlocal, qglobal, 0, &widgetUnderMouse);
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = widgetUnderMouse;
+ }
+#endif
+
+ topLevelAt_cache = 0;
qt_event_request_window_change(q);
deactivateWidgetCleanup();
qt_mac_event_release(q);
@@ -3883,12 +3895,14 @@ void QWidgetPrivate::raise_sys()
QWidget *parentWidget = q->parentWidget();
if(parentWidget) {
OSWindowRef parentWindow = qt_mac_window_for(parentWidget);
- if(parentWindow && [parentWindow isOnActiveSpace]) {
- // The window was created in a different space. Therefore if we want
- // to show it in the current space we need to recreate it in the new
- // space.
- recreateMacWindow();
- window = qt_mac_window_for(q);
+ if(parentWindow && [parentWindow respondsToSelector:@selector(isOnActiveSpace)]) {
+ if ([parentWindow performSelector:@selector(isOnActiveSpace)]) {
+ // The window was created in a different space. Therefore if we want
+ // to show it in the current space we need to recreate it in the new
+ // space.
+ recreateMacWindow();
+ window = qt_mac_window_for(q);
+ }
}
}
}
@@ -3905,6 +3919,7 @@ void QWidgetPrivate::raise_sys()
NSView *parentView = [view superview];
[parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)];
}
+ topLevelAt_cache = 0;
#else
if(q->isWindow()) {
//raise this window
@@ -3945,6 +3960,7 @@ void QWidgetPrivate::lower_sys()
NSView *parentView = [view superview];
[parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)];
}
+ topLevelAt_cache = 0;
#else
if(q->isWindow()) {
SendBehind(qt_mac_window_for(q), 0);
@@ -4001,6 +4017,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget *w)
#endif
}
+#ifndef QT_MAC_USE_COCOA
/*
Modifies the bounds for a widgets backing HIView during moves and resizes. Also updates the
widget, either by scrolling its contents or repainting, depending on the WA_StaticContents
@@ -4008,7 +4025,6 @@ void QWidgetPrivate::stackUnder_sys(QWidget *w)
*/
static void qt_mac_update_widget_position(QWidget *q, QRect oldRect, QRect newRect)
{
-#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(newRect.x(), newRect.y(),
newRect.width(), newRect.height());
@@ -4100,13 +4116,8 @@ static void qt_mac_update_widget_position(QWidget *q, QRect oldRect, QRect newRe
HIViewSetNeedsDisplayInRect(view, &verticalSlice, true);
const HIRect horizontalSlice = CGRectMake(0, starty, startx, stopy);
HIViewSetNeedsDisplayInRect(view, &horizontalSlice, true);
-#else
- Q_UNUSED(oldRect);
- NSRect bounds = NSMakeRect(newRect.x(), newRect.y(),
- newRect.width(), newRect.height());
- [qt_mac_nativeview_for(q) setFrame:bounds];
-#endif
}
+#endif
/*
Helper function for non-toplevel widgets. Helps to map Qt's 32bit
@@ -4127,7 +4138,15 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
{
Q_Q(QWidget);
Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
- Q_UNUSED(oldRect);
+
+ if (!q->internalWinId() && QApplicationPrivate::graphicsSystem() != 0) {
+ // We have no view to move, and no paint engine that
+ // we can update dirty regions on. So just return:
+ return;
+ }
+
+ QMacCocoaAutoReleasePool pool;
+
/*
There are up to four different coordinate systems here:
Qt coordinate system for this widget.
@@ -4135,13 +4154,31 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
Qt coordinate system for parent
X coordinate system for parent (relative to parent's wrect).
*/
+
+ // wrect is the same as crect, except that it is
+ // clipped to fit inside parent (and screen):
QRect wrect;
- //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
- QRect xrect = data.crect;
+ // wrectInParentCoordSys will be the same as wrect, except that it is
+ // originated in q's parent rather than q itself. It starts out in
+ // parent's Qt coord system, and ends up in parent's coordinate system:
+ QRect wrectInParentCoordSys = data.crect;
+
+ // If q's parent has been clipped, parentWRect will
+ // be filled with the parents clipped crect:
QRect parentWRect;
+
+ // Embedded have different meaning on each platform, and on
+ // Mac, it means that q is a QMacNativeWidget.
bool isEmbeddedWindow = (q->isWindow() && topData()->embedded);
- if (isEmbeddedWindow) {
+#ifdef QT_MAC_USE_COCOA
+ NSView *nsview = qt_mac_nativeview_for(q);
+#endif
+ if (!isEmbeddedWindow) {
+ parentWRect = q->parentWidget()->data->wrect;
+ } else {
+ // INVARIANT: q's parent view is not owned by Qt. So we need to
+ // do some extra calls to get the clipped rect of the parent view:
#ifndef QT_MAC_USE_COCOA
HIViewRef parentView = HIViewGetSuperview(qt_mac_nativeview_for(q));
#else
@@ -4160,43 +4197,57 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
parentWRect = wrectRange;
}
- } else {
- parentWRect = q->parentWidget()->data->wrect;
}
if (parentWRect.isValid()) {
- // parent is clipped, and we have to clip to the same limit as parent
- if (!parentWRect.contains(xrect) && !isEmbeddedWindow) {
- xrect &= parentWRect;
- wrect = xrect;
- //translate from parent's to my Qt coord sys
+ // INVARIANT: q's parent has been clipped.
+ // So we fit our own wrects inside it:
+ if (!parentWRect.contains(wrectInParentCoordSys) && !isEmbeddedWindow) {
+ wrectInParentCoordSys &= parentWRect;
+ wrect = wrectInParentCoordSys;
+ // Make sure wrect is originated in q's coordinate system:
wrect.translate(-data.crect.topLeft());
}
- //translate from parent's Qt coords to parent's X coords
- xrect.translate(-parentWRect.topLeft());
-
+ // // Make sure wrectInParentCoordSys originated in q's parent coordinate system:
+ wrectInParentCoordSys.translate(-parentWRect.topLeft());
} else {
- // parent is not clipped, we may or may not have to clip
+ // INVARIANT: we dont know yet the clipping rect of q's parent.
+ // So we may or may not have to adjust our wrects:
if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
- // This is where the main optimization is: we are already
- // clipped, and if our clip is still valid, we can just
- // move our window, and do not need to move or clip
- // children
+ // This is where the main optimization is: we have an old wrect from an earlier
+ // setGeometry call, and the new crect is smaller than it. If the final wrect is
+ // also inside the old wrect, we can just move q and its children to the new
+ // location without any clipping:
+
+ // vrect will be the part of q that's will be visible inside
+ // q's parent. If it inside the old wrect, then we can just move:
+ QRect vrect = wrectInParentCoordSys & q->parentWidget()->rect();
+ vrect.translate(-data.crect.topLeft());
- QRect vrect = xrect & q->parentWidget()->rect();
- vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
if (data.wrect.contains(vrect)) {
- xrect = data.wrect;
- xrect.translate(data.crect.topLeft());
+ wrectInParentCoordSys = data.wrect;
+ wrectInParentCoordSys.translate(data.crect.topLeft());
#ifndef QT_MAC_USE_COCOA
- HIRect bounds = CGRectMake(xrect.x(), xrect.y(),
- xrect.width(), xrect.height());
+ HIRect bounds = CGRectMake(wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
+ wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
HIViewSetFrame(qt_mac_nativeview_for(q), &bounds);
#else
- NSRect bounds = NSMakeRect(xrect.x(), xrect.y(),
- xrect.width(), xrect.height());
- [qt_mac_nativeview_for(q) setFrame:bounds];
+ if (nsview) {
+ // INVARIANT: q is native. Set view frame:
+ NSRect bounds = NSMakeRect(wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
+ wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
+ [nsview setFrame:bounds];
+ } else {
+ // INVARIANT: q is alien. Repaint wrect instead (includes old and new wrect):
+ QWidget *parent = q->parentWidget();
+ QPoint globalPosWRect = parent->mapToGlobal(data.wrect.topLeft());
+
+ QWidget *nativeParent = q->nativeParentWidget();
+ QRect dirtyWRect = QRect(nativeParent->mapFromGlobal(globalPosWRect), data.wrect.size());
+
+ nativeParent->update(dirtyWRect);
+ }
#endif
if (q->testAttribute(Qt::WA_OutsideWSRange)) {
q->setAttribute(Qt::WA_OutsideWSRange, false);
@@ -4205,7 +4256,8 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
- [qt_mac_nativeview_for(q) setHidden:NO];
+ // If q is Alien, the following call does nothing:
+ [nsview setHidden:NO];
#endif
}
}
@@ -4213,9 +4265,10 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
}
}
+ // Check if we need to clip q inside the screen:
const QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
- if (!validRange.contains(xrect)) {
- // we are too big, and must clip
+ if (!validRange.contains(wrectInParentCoordSys)) {
+ // We're too big, and must clip:
QPoint screenOffset(0, 0); // offset of the part being on screen
const QWidget *parentWidget = q->parentWidget();
while (parentWidget && !parentWidget->isWindow()) {
@@ -4227,14 +4280,14 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
2*WRECT_MAX,
2*WRECT_MAX);
- xrect &=cropRect;
- wrect = xrect;
- wrect.translate(-data.crect.topLeft()); // translate wrect in my Qt coordinates
+ wrectInParentCoordSys &=cropRect;
+ wrect = wrectInParentCoordSys;
+ wrect.translate(-data.crect.topLeft());
}
}
// unmap if we are outside the valid window system coord system
- bool outsideRange = !xrect.isValid();
+ bool outsideRange = !wrectInParentCoordSys.isValid();
bool mapWindow = false;
if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
@@ -4242,7 +4295,8 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), false);
#else
- [qt_mac_nativeview_for(q) setHidden:YES];
+ // If q is Alien, the following call does nothing:
+ [nsview setHidden:YES];
#endif
q->setAttribute(Qt::WA_Mapped, false);
} else if (!q->isHidden()) {
@@ -4253,10 +4307,10 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
if (outsideRange)
return;
+ // Store the new clipped rect:
bool jump = (data.wrect != wrect);
data.wrect = wrect;
-
// and now recursively for all children...
// ### can be optimized
for (int i = 0; i < children.size(); ++i) {
@@ -4268,17 +4322,56 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
}
}
- qt_mac_update_widget_position(q, oldRect, xrect);
-
- if (jump)
+#ifndef QT_MAC_USE_COCOA
+ // Move the actual HIView:
+ qt_mac_update_widget_position(q, oldRect, wrectInParentCoordSys);
+ if (jump)
q->update();
+#else
+ if (nsview) {
+ // INVARIANT: q is native. Move the actual NSView:
+ NSRect bounds = NSMakeRect(
+ wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
+ wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
+ [nsview setFrame:bounds];
+ if (jump)
+ q->update();
+ } else if (QApplicationPrivate::graphicsSystem() == 0){
+ // INVARIANT: q is alien and we use native paint engine.
+ // Schedule updates where q is moved from and to:
+ const QWidget *parent = q->parentWidget();
+ const QPoint globalPosOldWRect = parent->mapToGlobal(oldRect.topLeft());
+ const QPoint globalPosNewWRect = parent->mapToGlobal(wrectInParentCoordSys.topLeft());
+
+ QWidget *nativeParent = q->nativeParentWidget();
+ const QRegion dirtyOldWRect = QRect(nativeParent->mapFromGlobal(globalPosOldWRect), oldRect.size());
+ const QRegion dirtyNewWRect = QRect(nativeParent->mapFromGlobal(globalPosNewWRect), wrectInParentCoordSys.size());
+
+ const bool sizeUnchanged = oldRect.size() == wrectInParentCoordSys.size();
+ const bool posUnchanged = oldRect.topLeft() == wrectInParentCoordSys.topLeft();
+
+ // Resolve/minimize the region that needs to update:
+ if (sizeUnchanged && q->testAttribute(Qt::WA_OpaquePaintEvent)) {
+ // INVARIANT: q is opaque, and is only moved (not resized). So in theory we only
+ // need to blit pixels, and skip a repaint. But we can only make this work if we
+ // had access to the backbuffer, so we need to update all:
+ nativeParent->update(dirtyOldWRect | dirtyNewWRect);
+ } else if (posUnchanged && q->testAttribute(Qt::WA_StaticContents)) {
+ // We only need to redraw exposed areas:
+ nativeParent->update(dirtyNewWRect - dirtyOldWRect);
+ } else {
+ nativeParent->update(dirtyOldWRect | dirtyNewWRect);
+ }
+ }
+#endif
if (mapWindow && !dontShow) {
q->setAttribute(Qt::WA_Mapped);
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
- [qt_mac_nativeview_for(q) setHidden:NO];
+ // If q is Alien, the following call does nothing:
+ [nsview setHidden:NO];
#endif
}
}
@@ -4340,7 +4433,6 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
QMacCocoaAutoReleasePool pool;
bool realWindow = isRealWindow();
- BOOL needDisplay = realWindow ? YES : NO;
if (realWindow && !q->testAttribute(Qt::WA_DontShowOnScreen)){
adjustWithinMaxAndMinSize(w, h);
@@ -4388,7 +4480,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
if (currTopLeft.x() == x && currTopLeft.y() == y
&& cocoaFrameRect.size.width != 0
&& cocoaFrameRect.size.height != 0) {
- [window setFrame:cocoaFrameRect display:needDisplay];
+ [window setFrame:cocoaFrameRect display:realWindow];
} else {
// The window is moved and resized (or resized to zero).
// Since Cocoa usually only sends us a resize callback after
@@ -4397,7 +4489,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
// would have the same origin as the setFrame call) we shift the
// window back and forth inbetween.
cocoaFrameRect.origin.y += 1;
- [window setFrame:cocoaFrameRect display:needDisplay];
+ [window setFrame:cocoaFrameRect display:realWindow];
cocoaFrameRect.origin.y -= 1;
[window setFrameOrigin:cocoaFrameRect.origin];
}
@@ -4405,6 +4497,8 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
} else {
setGeometry_sys_helper(x, y, w, h, isMove);
}
+
+ topLevelAt_cache = 0;
}
void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isMove)
@@ -4545,6 +4639,7 @@ void QWidgetPrivate::updateMaximizeButton_sys()
void QWidgetPrivate::scroll_sys(int dx, int dy)
{
if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
+ // INVARIANT: Alien paint engine
scrollChildren(dx, dy);
scrollRect(q_func()->rect(), dx, dy);
} else {
@@ -4552,37 +4647,54 @@ void QWidgetPrivate::scroll_sys(int dx, int dy)
}
}
-void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
+void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &qscrollRect)
{
Q_Q(QWidget);
-
if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
- scrollRect(r, dx, dy);
+ // INVARIANT: Alien paint engine
+ scrollRect(qscrollRect, dx, dy);
return;
}
- const bool valid_rect = r.isValid();
- if (!q->updatesEnabled() && (valid_rect || q->children().isEmpty()))
- return;
+ const bool isAlien = (q->internalWinId() == 0);
+ const QPoint scrollDelta(dx, dy);
+
+ // If qscrollRect is valid, we are _not_ supposed to scroll q's children (as documented).
+ // But we do scroll children (and the whole of q) if qscrollRect is invalid. This case is
+ // documented as undefined, but we exploit it to help factor our code into one function.
+ const bool scrollChildren = !qscrollRect.isValid();
+
+ if (!q->updatesEnabled()) {
+ // We are told not to update anything on q at this point. So unless
+ // we are supposed to scroll children, we bail out early:
+ if (!scrollChildren || q->children().isEmpty())
+ return;
+ }
- qt_event_request_window_change(q);
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
+#else
+ // We're not sure what the following call is supposed to achive
+ // but until we see what it breaks, we don't bring it into the
+ // Cocoa port:
+ qt_event_request_window_change(q);
#endif
- if(!valid_rect) { // scroll children
- QPoint pd(dx, dy);
- QWidgetList moved;
- QObjectList chldrn = q->children();
- for(int i = 0; i < chldrn.size(); i++) { //first move all children
- QObject *obj = chldrn.at(i);
- if(obj->isWidgetType()) {
- QWidget *w = (QWidget*)obj;
- if(!w->isWindow()) {
- w->data->crect = QRect(w->pos() + pd, w->size());
- if (w->testAttribute(Qt::WA_WState_Created)) {
+ // First move all native children. Alien children will indirectly be
+ // moved when the parent is scrolled. All directly or indirectly moved
+ // children will receive a move event before the function call returns.
+ QWidgetList movedChildren;
+ if (scrollChildren) {
+ QObjectList children = q->children();
+
+ for (int i=0; i<children.size(); i++) {
+ QObject *obj = children.at(i);
+ if (QWidget *w = qobject_cast<QWidget*>(obj)) {
+ if (!w->isWindow()) {
+ w->data->crect = QRect(w->pos() + scrollDelta, w->size());
#ifndef QT_MAC_USE_COCOA
+ if (w->testAttribute(Qt::WA_WState_Created)) {
HIRect bounds = CGRectMake(w->data->crect.x(), w->data->crect.y(),
w->data->crect.width(), w->data->crect.height());
HIViewRef hiview = qt_mac_nativeview_for(w);
@@ -4593,83 +4705,148 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
HIViewSetFrame(hiview, &bounds);
if (opaque)
HIViewSetDrawingEnabled(hiview, true);
+ }
#else
- [qt_mac_nativeview_for(w)
- setFrame:NSMakeRect(w->data->crect.x(), w->data->crect.y(),
- w->data->crect.width(), w->data->crect.height())];
-#endif
+ if (NSView *view = qt_mac_nativeview_for(w)) {
+ // INVARIANT: w is not alien
+ [view setFrame:NSMakeRect(
+ w->data->crect.x(), w->data->crect.y(),
+ w->data->crect.width(), w->data->crect.height())];
}
- moved.append(w);
+#endif
+ movedChildren.append(w);
}
}
}
- //now send move events (do not do this in the above loop, breaks QAquaFocusWidget)
- for(int i = 0; i < moved.size(); i++) {
- QWidget *w = moved.at(i);
- QMoveEvent e(w->pos(), w->pos() - pd);
- QApplication::sendEvent(w, &e);
- }
}
- if (!q->testAttribute(Qt::WA_WState_Created) || !q->isVisible())
- return;
+ if (q->testAttribute(Qt::WA_WState_Created) && q->isVisible()) {
+ // Scroll q itself according to the qscrollRect, and
+ // call update on any exposed areas so that they get redrawn:
- OSViewRef view = qt_mac_nativeview_for(q);
#ifndef QT_MAC_USE_COCOA
- HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height());
- OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
- if (err) {
- // The only parameter that can go wrong, is the rect.
- qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect");
- scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0),
- qMin(r.width(), q->width()), qMin(r.height(), q->height()));
- _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
- }
+ OSViewRef view = qt_mac_nativeview_for(q);
+ HIRect scrollrect = CGRectMake(qscrollRect.x(), qscrollRect.y(), qscrollRect.width(), qscrollRect.height());
+ OSStatus err = _HIViewScrollRectWithOptions(view, qscrollRect.isValid() ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
+ if (err) {
+ // The only parameter that can go wrong, is the rect.
+ qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect");
+ scrollrect = CGRectMake(qMax(qscrollRect.x(), 0), qMax(qscrollRect.y(), 0),
+ qMin(qscrollRect.width(), q->width()), qMin(qscrollRect.height(), q->height()));
+ _HIViewScrollRectWithOptions(view, qscrollRect.isValid() ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
+ }
#else
- NSRect scrollRect = valid_rect ? NSMakeRect(r.x(), r.y(), r.width(), r.height())
- : NSMakeRect(0, 0, q->width(), q->height());
+ QWidget *nativeWidget = isAlien ? q->nativeParentWidget() : q;
+ if (!nativeWidget)
+ return;
+ OSViewRef view = qt_mac_nativeview_for(nativeWidget);
+ if (!view)
+ return;
- // calc the updateRect
- NSRect deltaXRect = { {0, 0}, {0, 0} };
- NSRect deltaYRect = { {0, 0}, {0, 0} };
- if (dy != 0) {
- deltaYRect.size.width = scrollRect.size.width;
- if (dy > 0) {
- deltaYRect.size.height = dy;
- } else {
- deltaYRect.size.height = -dy;
- deltaYRect.origin.y = scrollRect.size.height + dy;
+ // Scroll the whole widget instead if qscrollRect is not valid:
+ QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : QRect(0, 0, q->width(), q->height());
+
+ if (isAlien) {
+ // Since q is alien, we need to translate the scroll rect:
+ QPoint widgetTopLeftInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(QPoint()));
+ QPoint widgetBottomRightInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(q->rect().bottomRight()));
+ QPoint scrollTopLeftInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(validScrollRect.topLeft()));
+ QPoint scrollBottomRightInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(validScrollRect.bottomRight()));
+
+ // Adjust the scroll rect to the location as seen from the native parent:
+ validScrollRect.moveTo(scrollTopLeftInsideNative);
+
+ // Ensure that that the destination rect of the
+ // scroll doesn't draw outside of q's geometry:
+ if (dy != 0) {
+ if (scrollTopLeftInsideNative.y() + dy < widgetTopLeftInsideNative.y()) {
+ // Scrolling outside top
+ validScrollRect.setTop(widgetTopLeftInsideNative.y() - dy);
+ } else if (scrollBottomRightInsideNative.y() + dy > widgetBottomRightInsideNative.y()) {
+ // Scrolling outside bottom
+ validScrollRect.setBottom(widgetBottomRightInsideNative.y() - dy);
+ }
+ }
+
+ if (dx != 0) {
+ if (scrollTopLeftInsideNative.x() + dx < widgetTopLeftInsideNative.x()) {
+ // Scrolling outside left edge
+ validScrollRect.setLeft(widgetTopLeftInsideNative.x() - dx);
+ } else if (scrollBottomRightInsideNative.x() + dx > widgetBottomRightInsideNative.x()) {
+ // Scrolling outside right edge
+ validScrollRect.setRight(widgetBottomRightInsideNative.x() - dx);
+ }
+ }
}
- }
- if (dx != 0) {
- deltaXRect.size.height = scrollRect.size.height;
- if (dx > 0) {
- deltaXRect.size.width = dx;
- } else {
- deltaXRect.size.width = -dx;
- deltaXRect.origin.x = scrollRect.size.width + dx;
+
+ NSRect nsscrollRect = NSMakeRect(
+ validScrollRect.x(), validScrollRect.y(),
+ validScrollRect.width(), validScrollRect.height());
+
+ // Calculate the rectangles that needs to be redrawn
+ // after the scroll. This will be source rect minus destination rect:
+
+ NSRect deltaXRect = { {0, 0}, {0, 0} };
+ NSRect deltaYRect = { {0, 0}, {0, 0} };
+
+ if (dy != 0) {
+ deltaYRect.size.width = nsscrollRect.size.width;
+ deltaYRect.origin.x = nsscrollRect.origin.x;
+ if (dy > 0) {
+ deltaYRect.size.height = dy;
+ deltaYRect.origin.y = nsscrollRect.origin.y;
+ } else {
+ deltaYRect.size.height = -dy;
+ deltaYRect.origin.y = nsscrollRect.origin.y + nsscrollRect.size.height + dy;
+ }
}
- }
- // ### Scroll the dirty regions as well, the following is not correct.
- QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r);
- const QVector<QRect> &rects = dirtyOnWidget.rects();
- const QVector<QRect>::const_iterator end = rects.end();
- QVector<QRect>::const_iterator it = rects.begin();
- while (it != end) {
- const QRect rect = *it;
- const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy,
- rect.width(), rect.height());
- [view setNeedsDisplayInRect:dirtyRect];
- ++it;
- }
+ if (dx != 0) {
+ deltaXRect.size.height = nsscrollRect.size.height;
+ deltaXRect.origin.y = nsscrollRect.origin.y;
+ if (dx > 0) {
+ deltaXRect.size.width = dx;
+ deltaXRect.origin.x = nsscrollRect.origin.x;
+ } else {
+ deltaXRect.size.width = -dx;
+ deltaXRect.origin.x = nsscrollRect.origin.x + nsscrollRect.size.width + dx;
+ }
+ }
- NSSize deltaSize = NSMakeSize(dx, dy);
- [view scrollRect:scrollRect by:deltaSize];
- [view setNeedsDisplayInRect:deltaXRect];
- [view setNeedsDisplayInRect:deltaYRect];
+ NSSize deltaSize = NSMakeSize(dx, dy);
+ [view scrollRect:nsscrollRect by:deltaSize];
+ [view setNeedsDisplayInRect:deltaXRect];
+ [view setNeedsDisplayInRect:deltaYRect];
+
+ // Some areas inside the scroll rect might have been marked as dirty from before, which
+ // means that they are scheduled to be redrawn. But as we now scroll, those dirty rects
+ // should also move along to ensure that q receives repaints on the correct places.
+ // Since some of the dirty rects might lay outside, or only intersect with, the scroll
+ // rect, the old calls to setNeedsDisplay still makes sense.
+ // NB: Using [view translateRectsNeedingDisplayInRect:nsscrollRect by:deltaSize] have
+ // so far not been proven fruitful to solve this problem.
+ const QVector<QRect> &rects = dirtyOnWidget.rects();
+ const QVector<QRect>::const_iterator end = rects.end();
+ QVector<QRect>::const_iterator it = rects.begin();
+ while (it != end) {
+ QRect qdirtyRect = *it;
+ if (isAlien) {
+ const QPoint dirtyTopLeftInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(qdirtyRect.topLeft()));
+ qdirtyRect.moveTo(dirtyTopLeftInsideNative);
+ }
+ const NSRect nsdirtyRect = NSMakeRect(qdirtyRect.x() + dx, qdirtyRect.y() + dy, qdirtyRect.width(), qdirtyRect.height());
+ [view setNeedsDisplayInRect:nsdirtyRect];
+ ++it;
+ }
#endif // QT_MAC_USE_COCOA
+ }
+
+ for (int i=0; i<movedChildren.size(); i++) {
+ QWidget *w = movedChildren.at(i);
+ QMoveEvent e(w->pos(), w->pos() - scrollDelta);
+ QApplication::sendEvent(w, &e);
+ }
}
int QWidget::metric(PaintDeviceMetric m) const
@@ -4815,7 +4992,7 @@ void QWidgetPrivate::registerTouchWindow()
#ifndef QT_MAC_USE_COCOA
// Needs implementation!
#else
- NSView *view = qt_mac_nativeview_for(q);
+ NSView *view = qt_mac_effectiveview_for(q);
[view setAcceptsTouchEvents:YES];
#endif
#endif
@@ -4837,7 +5014,7 @@ void QWidgetPrivate::setMask_sys(const QRegion &region)
} else {
syncCocoaMask();
}
-
+ topLevelAt_cache = 0;
#endif
}
@@ -4915,7 +5092,7 @@ void QWidgetPrivate::finishCocoaMaskSetup()
[window setOpaque:(extra->imageMask == 0)];
[window invalidateShadow];
}
- qt_mac_set_needs_display(q, QRegion());
+ macSetNeedsDisplay(QRegion());
}
#endif
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index 4b35238..8c29946 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -359,7 +359,8 @@ public:
DrawInvisible = 0x08,
DontSubtractOpaqueChildren = 0x10,
DontSetCompositionMode = 0x20,
- DontDrawOpaqueChildren = 0x40
+ DontDrawOpaqueChildren = 0x40,
+ DontDrawNativeChildren = 0x80
};
enum CloseMode {
@@ -791,7 +792,6 @@ public:
#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC
// This is new stuff
uint needWindowChange : 1;
- uint hasAlienChildren : 1;
// Each wiget keeps a list of all its child and grandchild OpenGL widgets.
// This list is used to update the gl context whenever a parent and a granparent
@@ -822,6 +822,7 @@ public:
void macUpdateIgnoreMouseEvents();
void macUpdateMetalAttribute();
void macUpdateIsOpaque();
+ void macSetNeedsDisplay(QRegion region);
void setEnabled_helper_sys(bool enable);
bool isRealWindow() const;
void adjustWithinMaxAndMinSize(int &w, int &h);
diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp
index ae73d7d..f81c8ab 100644
--- a/src/gui/painting/qwindowsurface_raster.cpp
+++ b/src/gui/painting/qwindowsurface_raster.cpp
@@ -282,6 +282,7 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi
CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
QDBeginCGContext(port, &context);
#else
+ QMacCocoaAutoReleasePool pool;
extern CGContextRef qt_mac_graphicsContextFor(QWidget *);
CGContextRef context = qt_mac_graphicsContextFor(widget);
#endif
diff --git a/src/gui/widgets/qcocoamenu_mac.mm b/src/gui/widgets/qcocoamenu_mac.mm
index b670186..e41e675 100644
--- a/src/gui/widgets/qcocoamenu_mac.mm
+++ b/src/gui/widgets/qcocoamenu_mac.mm
@@ -47,6 +47,7 @@
#include <private/qt_cocoa_helpers_mac_p.h>
#include <private/qapplication_p.h>
#include <private/qaction_p.h>
+#include <private/qcocoaapplication_mac_p.h>
#include <QtGui/QMenu>
@@ -60,6 +61,7 @@ QT_FORWARD_DECLARE_CLASS(QEvent)
QT_BEGIN_NAMESPACE
extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); //qapplication.cpp
+extern NSString *qt_mac_removePrivateUnicode(NSString* string);
QT_END_NAMESPACE
QT_USE_NAMESPACE
@@ -157,7 +159,6 @@ QT_USE_NAMESPACE
// (i.e., fire the menu action).
NSMenuItem *whichItem;
// Change the private unicode keys to the ones used in setting the "Key Equivalents"
- extern NSString *qt_mac_removePrivateUnicode(NSString* string);
NSString *characters = qt_mac_removePrivateUnicode([event characters]);
if ([self hasShortcut:menu
forKey:characters
diff --git a/src/gui/widgets/qfocusframe.cpp b/src/gui/widgets/qfocusframe.cpp
index 4f20bce0..dd508fb 100644
--- a/src/gui/widgets/qfocusframe.cpp
+++ b/src/gui/widgets/qfocusframe.cpp
@@ -85,6 +85,9 @@ void QFocusFramePrivate::update()
void QFocusFramePrivate::updateSize()
{
Q_Q(QFocusFrame);
+ if (!widget)
+ return;
+
int vmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameVMargin),
hmargin = q->style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
QPoint pos(widget->x(), widget->y());
diff --git a/src/gui/widgets/qmainwindow.cpp b/src/gui/widgets/qmainwindow.cpp
index da902d5..2550ee4 100644
--- a/src/gui/widgets/qmainwindow.cpp
+++ b/src/gui/widgets/qmainwindow.cpp
@@ -1516,11 +1516,6 @@ void QMainWindow::setUnifiedTitleAndToolBarOnMac(bool set)
if (!isWindow() || d->useHIToolBar == set || QSysInfo::MacintoshVersion < QSysInfo::MV_10_3)
return;
- // ### Disable when using alien widgets
- if (testAttribute(Qt::WA_NativeWindow) == false) {
- return;
- }
-
d->useHIToolBar = set;
createWinId(); // We need the hiview for down below.
diff --git a/src/gui/widgets/qmainwindowlayout_mac.mm b/src/gui/widgets/qmainwindowlayout_mac.mm
index 9e26423..84cf3eb 100644
--- a/src/gui/widgets/qmainwindowlayout_mac.mm
+++ b/src/gui/widgets/qmainwindowlayout_mac.mm
@@ -355,7 +355,11 @@ void QMainWindowLayout::updateHIToolBarStatus()
// Move everything out of the HIToolbar into the main toolbar.
while (!qtoolbarsInUnifiedToolbarList.isEmpty()) {
// Should shrink the list by one every time.
- layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, qtoolbarsInUnifiedToolbarList.first());
+ QToolBar *toolbar = qtoolbarsInUnifiedToolbarList.first();
+ layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
+#if defined(QT_MAC_USE_COCOA)
+ toolbar->d_func()->isInUnifiedToolbar = false;
+#endif
}
macWindowToolbarSet(qt_mac_window_for(layoutState.mainWindow), 0);
} else {
@@ -363,7 +367,8 @@ void QMainWindowLayout::updateHIToolBarStatus()
for (int i = 0; i < toolbars.size(); ++i) {
QToolBar *toolbar = toolbars.at(i);
if (toolBarArea(toolbar) == Qt::TopToolBarArea) {
- removeWidget(toolbar); // Do this here, because we are in an in-between state.
+ // Do this here, because we are in an in-between state.
+ removeWidget(toolbar);
layoutState.mainWindow->addToolBar(Qt::TopToolBarArea, toolbar);
}
}
@@ -387,10 +392,20 @@ void QMainWindowLayout::insertIntoMacToolbar(QToolBar *before, QToolBar *toolbar
if (toolbar == 0)
return;
+#if defined(QT_MAC_USE_COCOA)
+ // toolbar will now become native (if not allready) since we need
+ // an nsview for it inside the corresponding NSToolbarItem.
+ // Setting isInUnifiedToolbar will (among other things) stop alien
+ // siblings from becoming native when this happends since the toolbar
+ // will not overlap with other children of the QMainWindow. NB: Switching
+ // unified toolbar off after this stage is not supported, as this means
+ // that either the menubar must be alien again, or the sibling must
+ // be backed by an nsview to protect from overlapping issues:
+ toolbar->d_func()->isInUnifiedToolbar = true;
+#endif
QToolBarLayout *toolbarLayout = static_cast<QToolBarLayout *>(toolbar->layout());
- toolbarSaveState.insert(toolbar, ToolBarSaveState(toolbar->isMovable(),
- toolbar->maximumSize()));
+ toolbarSaveState.insert(toolbar, ToolBarSaveState(toolbar->isMovable(), toolbar->maximumSize()));
if (toolbarLayout->hasExpandFlag() == false)
toolbar->setMaximumSize(toolbar->sizeHint());
@@ -399,8 +414,8 @@ void QMainWindowLayout::insertIntoMacToolbar(QToolBar *before, QToolBar *toolbar
toolbarLayout->setUsePopupMenu(true);
// Make the toolbar a child of the mainwindow to avoid creating a window.
toolbar->setParent(layoutState.mainWindow);
- toolbar->createWinId(); // Now create the OSViewRef.
+ toolbar->winId(); // Now create the OSViewRef.
layoutState.mainWindow->createWinId();
OSWindowRef window = qt_mac_window_for(layoutState.mainWindow);
diff --git a/tests/auto/qwidget/tst_qwidget.cpp b/tests/auto/qwidget/tst_qwidget.cpp
index d230f2c..a518470 100644
--- a/tests/auto/qwidget/tst_qwidget.cpp
+++ b/tests/auto/qwidget/tst_qwidget.cpp
@@ -3852,29 +3852,6 @@ void tst_QWidget::testDeletionInEventHandlers()
#ifdef Q_WS_MAC
-bool testAndRelease(const HIViewRef view)
-{
-// qDebug() << CFGetRetainCount(view);
- if (CFGetRetainCount(view) != 2)
- return false;
- CFRelease(view);
- CFRelease(view);
- return true;
-}
-
-typedef QPair<QWidget *, HIViewRef> WidgetViewPair;
-
-WidgetViewPair createAndRetain(QWidget * const parent = 0)
-{
- QWidget * const widget = new QWidget(parent);
- const HIViewRef view = (HIViewRef)widget->winId();
- // Retain twice so we can safely call CFGetRetaintCount even if the retain count
- // is off by one because of a double release.
- CFRetain(view);
- CFRetain(view);
- return qMakePair(widget, view);
-}
-
/*
Test that retaining and releasing the HIView returned by QWidget::winId()
works even if the widget itself is deleted.
@@ -4751,9 +4728,6 @@ void tst_QWidget::update()
QRegion expectedVisible = QRegion(w.rect())
- child.visibleRegion().translated(childOffset);
QCOMPARE(w.visibleRegion(), expectedVisible);
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the content view", Continue);
-#endif
QCOMPARE(w.paintedRegion, expectedVisible);
#ifdef QT_MAC_USE_COCOA
QEXPECT_FAIL(0, "Cocoa compositor says to paint this.", Continue);
@@ -4803,14 +4777,8 @@ void tst_QWidget::update()
& sibling.visibleRegion().translated(siblingOffset));
QCOMPARE(w.numPaintEvents, 1);
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the content view", Continue);
-#endif
QCOMPARE(w.paintedRegion,
w.visibleRegion() & sibling.visibleRegion().translated(siblingOffset));
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the content view", Continue);
-#endif
QCOMPARE(w.paintedRegion,
(w.visibleRegion() - child.visibleRegion().translated(childOffset))
& sibling.visibleRegion().translated(siblingOffset));
@@ -4833,7 +4801,8 @@ void tst_QWidget::update()
QCOMPARE(sibling.paintedRegion, sibling.visibleRegion());
#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints child and sibling", Continue);
+ if (child.internalWinId()) // child is native
+ QEXPECT_FAIL(0, "Cocoa compositor paints child and sibling", Continue);
#endif
QCOMPARE(child.numPaintEvents, 0);
QCOMPARE(child.visibleRegion(),
@@ -5464,6 +5433,7 @@ public:
rect.width(), rect.height()); \
QCOMPARE(pixmap.size(), rect.size()); \
QPixmap expectedPixmap(pixmap); /* ensure equal formats */ \
+ expectedPixmap.detach(); \
expectedPixmap.fill(color); \
QImage image = pixmap.toImage(); \
uint alphaCorrection = image.format() == QImage::Format_RGB32 ? 0xff000000 : 0; \
@@ -5510,9 +5480,6 @@ void tst_QWidget::moveChild()
QTest::qWait(30);
const QPoint tlwOffset = parent.geometry().topLeft();
-#ifdef QT_MAC_USE_COCOA
- QEXPECT_FAIL(0, "Cocoa compositor paints the entire content view, even when opaque", Continue);
-#endif
QTRY_COMPARE(parent.r, QRegion(parent.rect()) - child.geometry());
QTRY_COMPARE(child.r, QRegion(child.rect()));
VERIFY_COLOR(child.geometry().translated(tlwOffset),
diff --git a/tests/auto/qwidget/tst_qwidget_mac_helpers.h b/tests/auto/qwidget/tst_qwidget_mac_helpers.h
index f310aef..b341971 100644
--- a/tests/auto/qwidget/tst_qwidget_mac_helpers.h
+++ b/tests/auto/qwidget/tst_qwidget_mac_helpers.h
@@ -39,9 +39,20 @@
**
****************************************************************************/
#include <QtCore/QString>
-class QWidget;
+#include <QtCore/QPair>
+#include <QtGui/QWidget>
#pragma once // Yeah, it's deprecated in general, but it's standard practive for Mac OS X.
QString nativeWindowTitle(QWidget *widget, Qt::WindowState state);
bool nativeWindowModified(QWidget *widget);
+
+#ifndef QT_MAC_USE_COCOA
+typedef QPair<QWidget *, HIViewRef> WidgetViewPair;
+bool testAndRelease(const HIViewRef view);
+WidgetViewPair createAndRetain(QWidget * const parent = 0);
+#else
+typedef QPair<QWidget *, WId> WidgetViewPair;
+bool testAndRelease(const WId);
+WidgetViewPair createAndRetain(QWidget * const parent = 0);
+#endif
diff --git a/tests/auto/qwidget/tst_qwidget_mac_helpers.mm b/tests/auto/qwidget/tst_qwidget_mac_helpers.mm
index 0572a4c..e1f23b0 100644
--- a/tests/auto/qwidget/tst_qwidget_mac_helpers.mm
+++ b/tests/auto/qwidget/tst_qwidget_mac_helpers.mm
@@ -72,3 +72,47 @@ bool nativeWindowModified(QWidget *widget)
return [qt_mac_window_for(widget) isDocumentEdited];
#endif
}
+
+#ifndef QT_MAC_USE_COCOA
+bool testAndRelease(const HIViewRef view)
+{
+// qDebug() << CFGetRetainCount(view);
+ if (CFGetRetainCount(view) != 2)
+ return false;
+ CFRelease(view);
+ CFRelease(view);
+ return true;
+}
+
+WidgetViewPair createAndRetain(QWidget * const parent)
+{
+ QWidget * const widget = new QWidget(parent);
+ const HIViewRef view = (HIViewRef)widget->winId();
+ // Retain twice so we can safely call CFGetRetaintCount even if the retain count
+ // is off by one because of a double release.
+ CFRetain(view);
+ CFRetain(view);
+ return qMakePair(widget, view);
+}
+#else
+bool testAndRelease(const WId view)
+{
+ if ([id(view) retainCount] != 2)
+ return false;
+ [id(view) release];
+ [id(view) release];
+ return true;
+}
+
+WidgetViewPair createAndRetain(QWidget * const parent)
+{
+ QWidget * const widget = new QWidget(parent);
+ const WId view = widget->winId();
+ // Retain twice so we can safely call retainCount even if the retain count
+ // is off by one because of a double release.
+ [id(view) retain];
+ [id(view) retain];
+ return qMakePair(widget, view);
+}
+#endif
+