src/gui/kernel/qwidget_mac.mm
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
child 18 2f34d5167611
--- a/src/gui/kernel/qwidget_mac.mm	Tue Jan 26 12:42:25 2010 +0200
+++ b/src/gui/kernel/qwidget_mac.mm	Tue Feb 02 00:43:10 2010 +0200
@@ -725,11 +725,29 @@
     return window;
 }
 
+#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
+/* We build the release package against the 10.4 SDK.
+   So, to enable gestures for applications running on
+   10.6+, we define the missing constants here: */
+enum {
+    kEventClassGesture              = 'gest',
+    kEventGestureStarted            = 1,
+    kEventGestureEnded              = 2,
+    kEventGestureMagnify            = 4,
+    kEventGestureSwipe              = 5,
+    kEventGestureRotate             = 6,
+    kEventParamRotationAmount       = 'rota',
+    kEventParamSwipeDirection       = 'swip',
+    kEventParamMagnificationAmount  = 'magn'
+};
+#endif
+
 // window events
 static EventTypeSpec window_events[] = {
     { kEventClassWindow, kEventWindowClose },
     { kEventClassWindow, kEventWindowExpanded },
     { kEventClassWindow, kEventWindowHidden },
+    { kEventClassWindow, kEventWindowZoom },
     { kEventClassWindow, kEventWindowZoomed },
     { kEventClassWindow, kEventWindowCollapsed },
     { kEventClassWindow, kEventWindowToolbarSwitchMode },
@@ -740,13 +758,11 @@
     { kEventClassWindow, kEventWindowGetRegion },
     { kEventClassWindow, kEventWindowGetClickModality },
     { kEventClassWindow, kEventWindowTransitionCompleted },
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
     { kEventClassGesture, kEventGestureStarted },
     { kEventClassGesture, kEventGestureEnded },
     { kEventClassGesture, kEventGestureMagnify },
     { kEventClassGesture, kEventGestureSwipe },
     { kEventClassGesture, kEventGestureRotate },
-#endif
     { kEventClassMouse, kEventMouseDown }
 };
 static EventHandlerUPP mac_win_eventUPP = 0;
@@ -812,6 +828,9 @@
 
             QShowEvent qse;
             QApplication::sendSpontaneousEvent(widget, &qse);
+        } else if(ekind == kEventWindowZoom) {
+            widget->d_func()->topData()->normalGeometry = widget->geometry();
+            handled_event = false;
         } else if(ekind == kEventWindowZoomed) {
             WindowPartCode windowPart;
             GetEventParameter(event, kEventParamWindowPartCode,
@@ -1032,7 +1051,6 @@
         handled_event = false;
         break; }
 
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
     case kEventClassGesture: {
         // First, find the widget that was under
         // the mouse when the gesture happened:
@@ -1060,7 +1078,7 @@
                 break;
             case kEventGestureRotate: {
                 CGFloat amount;
-                if (GetEventParameter(event, kEventParamRotationAmount, typeCGFloat, 0,
+                if (GetEventParameter(event, kEventParamRotationAmount, 'cgfl', 0,
                             sizeof(amount), 0, &amount) != noErr) {
                     handled_event = false;
                     break;
@@ -1087,7 +1105,7 @@
                 break; }
             case kEventGestureMagnify: {
                 CGFloat amount;
-                if (GetEventParameter(event, kEventParamMagnificationAmount, typeCGFloat, 0,
+                if (GetEventParameter(event, kEventParamMagnificationAmount, 'cgfl', 0,
                             sizeof(amount), 0, &amount) != noErr) {
                     handled_event = false;
                     break;
@@ -1099,7 +1117,6 @@
 
         QApplication::sendSpontaneousEvent(widget, &qNGEvent);
     break; }
-#endif // gestures
 
     default:
         handled_event = false;
@@ -2600,8 +2617,6 @@
             releaseMouse();
         if(mac_keyboard_grabber == this)
             releaseKeyboard();
-        if(acceptDrops())
-            setAcceptDrops(false);
 
         if(testAttribute(Qt::WA_ShowModal))          // just be sure we leave modal
             QApplicationPrivate::leaveModal(this);
@@ -2669,7 +2684,10 @@
                     // site disabled until it is part of the new hierarchy.
                     bool oldRegistered = w->testAttribute(Qt::WA_DropSiteRegistered);
                     w->setAttribute(Qt::WA_DropSiteRegistered, false);
+                    [qt_mac_nativeview_for(w) retain];
+                    [qt_mac_nativeview_for(w) removeFromSuperview];
                     [qt_mac_nativeview_for(q) addSubview:qt_mac_nativeview_for(w)];
+                    [qt_mac_nativeview_for(w) release];
                     w->setAttribute(Qt::WA_DropSiteRegistered, oldRegistered);
 #endif
                 }
@@ -2896,6 +2914,7 @@
 #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
@@ -2908,6 +2927,7 @@
 #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
@@ -3015,10 +3035,17 @@
 #else
         QMacCocoaAutoReleasePool pool;
         NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
+        if (iconButton == nil) {
+            QCFString string(q->windowTitle());
+            const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
+            [qt_mac_window_for(q) setRepresentedURL:[NSURL fileURLWithPath:tmpString]];
+            iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
+        }
         if (icon.isNull()) {
             [iconButton setImage:nil];
         } else {
-            NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(*pm));
+            QPixmap scaled = pm->scaled(QSize(16,16), Qt::KeepAspectRatio, Qt::SmoothTransformation);
+            NSImage *image = static_cast<NSImage *>(qt_mac_create_nsimage(scaled));
             [iconButton setImage:image];
             [image release];
         }
@@ -3048,6 +3075,7 @@
     }
 }
 
+#ifndef QT_NO_CURSOR
 void QWidget::grabMouse(const QCursor &)
 {
     if(isVisible() && !qt_nograb()) {
@@ -3056,6 +3084,7 @@
         mac_mouse_grabber=this;
     }
 }
+#endif
 
 void QWidget::releaseMouse()
 {
@@ -3388,12 +3417,19 @@
                 w = q->parentWidget()->window();
             if(!w || (!w->isVisible() && !w->isMinimized())) {
 #ifndef QT_MAC_USE_COCOA
-                for(WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true);
-                    wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) {
+                for (WindowPtr wp = GetFrontWindowOfClass(kMovableModalWindowClass, true);
+                    wp; wp = GetNextWindowOfClass(wp, kMovableModalWindowClass, true)) {
                     if((w = qt_mac_find_window(wp)))
                         break;
                 }
                 if (!w){
+                    for (WindowPtr wp = GetFrontWindowOfClass(kDocumentWindowClass, true);
+                            wp; wp = GetNextWindowOfClass(wp, kDocumentWindowClass, true)) {
+                        if((w = qt_mac_find_window(wp)))
+                            break;
+                    }
+                }
+                if (!w){
                     for(WindowPtr wp = GetFrontWindowOfClass(kSimpleWindowClass, true);
                         wp; wp = GetNextWindowOfClass(wp, kSimpleWindowClass, true)) {
                         if((w = qt_mac_find_window(wp)))
@@ -3469,10 +3505,10 @@
                     qt_mac_set_fullscreen_mode(true);
             } else {
                 needShow = isVisible();
+                if(!qApp->desktop()->screenNumber(this))
+                    qt_mac_set_fullscreen_mode(false);
                 setParent(parentWidget(), d->topData()->savedFlags);
                 setGeometry(d->topData()->normalGeometry);
-                if(!qApp->desktop()->screenNumber(this))
-                    qt_mac_set_fullscreen_mode(false);
                 d->topData()->normalGeometry.setRect(0, 0, -1, -1);
             }
         }
@@ -3574,7 +3610,7 @@
                 [window zoom:window];
 #endif
                 needSendStateChange = oldstate == windowState(); // Zoom didn't change flags.
-            } else if(oldstate & Qt::WindowMaximized) {
+            } else if(oldstate & Qt::WindowMaximized && !(oldstate & Qt::WindowFullScreen)) {
 #ifndef QT_MAC_USE_COCOA
                 Point idealSize;
                 ZoomWindowIdeal(window, inZoomIn, &idealSize);
@@ -3618,6 +3654,16 @@
     }
 }
 
+NSComparisonResult compareViews2Raise(id view1, id view2, void *context)
+{
+    id topView = reinterpret_cast<id>(context);
+    if (view1 == topView)
+        return NSOrderedDescending;
+    if (view2 == topView)
+        return NSOrderedAscending;
+    return NSOrderedSame;
+}
+
 void QWidgetPrivate::raise_sys()
 {
     Q_Q(QWidget);
@@ -3625,7 +3671,6 @@
         return;
 
 #if QT_MAC_USE_COCOA
-    QMacCocoaAutoReleasePool pool;
     if (isRealWindow()) {
         // Calling orderFront shows the window on Cocoa too.
         if (!q->testAttribute(Qt::WA_DontShowOnScreen) && q->isVisible()) {
@@ -3637,16 +3682,9 @@
             SetFrontProcessWithOptions(&psn, kSetFrontProcessFrontWindowOnly);
         }
     } else {
-        // Cocoa doesn't really have an idea of Z-ordering, but you can
-        // fake it by changing the order of it. But beware, removing an
-        // NSView will also remove it as the first responder. So we re-set
-        // the first responder just in case:
         NSView *view = qt_mac_nativeview_for(q);
         NSView *parentView = [view superview];
-        NSResponder *firstResponder = [[view window] firstResponder];
-        [view removeFromSuperview];
-        [parentView addSubview:view];
-        [[view window] makeFirstResponder:firstResponder];
+        [parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)];
     }
 #else
     if(q->isWindow()) {
@@ -3664,47 +3702,29 @@
 #endif
 }
 
+NSComparisonResult compareViews2Lower(id view1, id view2, void *context)
+{
+    id topView = reinterpret_cast<id>(context);
+    if (view1 == topView)
+        return NSOrderedAscending;
+    if (view2 == topView)
+        return NSOrderedDescending;
+    return NSOrderedSame;
+}
+
 void QWidgetPrivate::lower_sys()
 {
     Q_Q(QWidget);
     if((q->windowType() == Qt::Desktop))
         return;
 #ifdef QT_MAC_USE_COCOA
-    QMacCocoaAutoReleasePool pool;
     if (isRealWindow()) {
         OSWindowRef window = qt_mac_window_for(q);
         [window orderBack:window];
     } else {
-        // Cocoa doesn't really have an idea of Z-ordering, but you can
-        // fake it by changing the order of it. In this case
-        // we put the item at the beginning of the list, but that means
-        // we must re-insert everything since we cannot modify the list directly.
-        NSView *myview = qt_mac_nativeview_for(q);
-        NSView *parentView = [myview superview];
-        NSArray *tmpViews = [parentView subviews];
-        NSMutableArray *subviews = [[NSMutableArray alloc] initWithCapacity:[tmpViews count]];
-        [subviews addObjectsFromArray:tmpViews];
-        NSResponder *firstResponder = [[myview window] firstResponder];
-        // Implicit assumption that myViewIndex is included in subviews, that's why I'm not checking
-        // myViewIndex.
-        NSUInteger index = 0;
-        NSUInteger myViewIndex = 0;
-        bool foundMyView = false;
-        for (NSView *subview in subviews) {
-            [subview removeFromSuperview];
-            if (subview == myview) {
-                foundMyView = true;
-                myViewIndex = index;
-            }
-            ++index;
-        }
-        [parentView addSubview:myview];
-        if (foundMyView)
-            [subviews removeObjectAtIndex:myViewIndex];
-        for (NSView *subview in subviews)
-            [parentView addSubview:subview];
-        [subviews release];
-        [[myview window] makeFirstResponder:firstResponder];
+        NSView *view = qt_mac_nativeview_for(q);
+        NSView *parentView = [view superview];
+        [parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)];
     }
 #else
     if(q->isWindow()) {
@@ -3717,6 +3737,16 @@
 #endif
 }
 
+NSComparisonResult compareViews2StackUnder(id view1, id view2, void *context)
+{
+    const QHash<NSView *, int> &viewOrder = *reinterpret_cast<QHash<NSView *, int> *>(context);
+    if (viewOrder[view1] < viewOrder[view2])
+        return NSOrderedAscending;
+    if (viewOrder[view1] > viewOrder[view2])
+        return NSOrderedDescending;
+    return NSOrderedSame;
+}
+
 void QWidgetPrivate::stackUnder_sys(QWidget *w)
 {
     // stackUnder
@@ -3725,37 +3755,23 @@
         return;
 #ifdef QT_MAC_USE_COCOA
     // Do the same trick as lower_sys() and put this widget before the widget passed in.
-    QMacCocoaAutoReleasePool pool;
-    NSView *myview = qt_mac_nativeview_for(q);
+    NSView *myView = qt_mac_nativeview_for(q);
     NSView *wView = qt_mac_nativeview_for(w);
-    NSView *parentView = [myview superview];
-    NSArray *tmpViews = [parentView subviews];
-    NSMutableArray *subviews = [[NSMutableArray alloc] initWithCapacity:[tmpViews count]];
-    [subviews addObjectsFromArray:tmpViews];
-    // Implicit assumption that myViewIndex and wViewIndex is included in subviews,
-    // that's why I'm not checking myViewIndex.
-    NSUInteger index = 0;
-    NSUInteger myViewIndex = 0;
-    NSUInteger wViewIndex = 0;
+
+    QHash<NSView *, int> viewOrder;
+    NSView *parentView = [myView superview];
+    NSArray *subviews = [parentView subviews];
+    NSUInteger index = 1;
+    // make a hash of view->zorderindex and make sure z-value is always odd,
+    // so that when we modify the order we create a new (even) z-value which
+    // will not interfere with others.
     for (NSView *subview in subviews) {
-        [subview removeFromSuperview];
-        if (subview == myview)
-            myViewIndex = index;
-        else if (subview == wView)
-            wViewIndex = index;
+        viewOrder.insert(subview, index * 2);
         ++index;
     }
-
-    index = 0;
-    for (NSView *subview in subviews) {
-        if (index == myViewIndex)
-            continue;
-        if (index == wViewIndex)
-            [parentView addSubview:myview];
-        [parentView addSubview:subview];
-        ++index;
-    }
-    [subviews release];
+    viewOrder[myView] = viewOrder[wView] - 1;
+
+    [parentView sortSubviewsUsingFunction:compareViews2StackUnder context:reinterpret_cast<void *>(&viewOrder)];
 #else
     QWidget *p = q->parentWidget();
     if(!p || p != w->parentWidget())
@@ -3769,7 +3785,7 @@
 /*
     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
-    and QWidgetPrivate::isOpaque flags.
+    flag
 */
 static void qt_mac_update_widget_posisiton(QWidget *q, QRect oldRect, QRect newRect)
 {
@@ -3786,8 +3802,8 @@
 
     // Perform a normal (complete repaint) update in some cases:
     if (
-        // move-by-scroll requires QWidgetPrivate::isOpaque set
-        (isMove && q->testAttribute(Qt::WA_OpaquePaintEvent) == false) ||
+        // always repaint on move.
+        (isMove) ||
 
         // limited update on resize requires WA_StaticContents.
         (isResize && q->testAttribute(Qt::WA_StaticContents) == false) ||