Cocoa: Set child window geometry correctly.
authorMorten Sorvig <morten.sorvig@nokia.com>
Thu, 11 Aug 2011 09:08:30 +0000 (11:08 +0200)
committerRichard Moe Gustavsen <richard.gustavsen@nokia.com>
Thu, 11 Aug 2011 11:22:36 +0000 (13:22 +0200)
Qt child window geometry is in the parent window
coordinate space, convert from/to OS X screen
coordinates when needed.

Change-Id: I50d35dd35e51af8fc161ec363c0e996a0e8aa9f3
Reviewed-on: http://codereview.qt.nokia.com/2859
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@nokia.com>
src/plugins/platforms/cocoa/qcocoawindow.h
src/plugins/platforms/cocoa/qcocoawindow.mm

index dc7907d..e301c48 100644 (file)
@@ -45,6 +45,7 @@
 #include <Cocoa/Cocoa.h>
 
 #include <QPlatformWindow>
+#include <QRect>
 
 #include "qcocoaglcontext.h"
 #include "qnsview.h"
@@ -76,6 +77,9 @@ public:
 protected:
     void determineWindowClass();
     NSWindow *createWindow();
+    NSRect globalGeometry(const QRect localWindowGeometry) const;
+    QRect windowGeometry() const;
+    QCocoaWindow *parentCocoaWindow() const;
 private:
     friend class QCocoaBackingStore;
     NSWindow *m_nsWindow;
index 492a43a..08a45cb 100644 (file)
@@ -46,6 +46,7 @@
 #include <QtCore/private/qcore_mac_p.h>
 #include <qwindow.h>
 #include <QWindowSystemInterface>
+#include <QPlatformScreen>
 
 #include <Cocoa/Cocoa.h>
 #include <Carbon/Carbon.h>
@@ -68,8 +69,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
     m_contentView = [[QNSView alloc] initWithQWindow:tlw];
 
     if (tlw->surfaceType() == QWindow::OpenGLSurface) {
-        const QRect geo = window()->geometry();
-        NSRect glFrame = NSMakeRect(0, 0, geo.width(), geo.height());
+        NSRect glFrame = globalGeometry(window()->geometry());
         m_windowSurfaceView = [[NSOpenGLView alloc] initWithFrame : glFrame pixelFormat : QCocoaGLContext::createNSOpenGLPixelFormat() ];
         [m_contentView setAutoresizesSubviews : YES];
         [m_windowSurfaceView setAutoresizingMask : (NSViewWidthSizable | NSViewHeightSizable)];
@@ -90,8 +90,9 @@ void QCocoaWindow::setGeometry(const QRect &rect)
 {
     QPlatformWindow::setGeometry(rect);
 
-    NSRect bounds = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
+    NSRect bounds = globalGeometry(window()->geometry());
     [[m_nsWindow contentView]setFrameSize:bounds.size];
+    [m_nsWindow setFrameOrigin : bounds.origin];
 
     if (m_glContext)
         m_glContext->update();
@@ -100,6 +101,11 @@ void QCocoaWindow::setGeometry(const QRect &rect)
 void QCocoaWindow::setVisible(bool visible)
 {
     if (visible) {
+        // The parent window might have moved while this window was hidden,
+        // update the window geometry if there is a parent.
+        if (window()->transientParent())
+            setGeometry(window()->geometry());
+
         [m_nsWindow makeKeyAndOrderFront:nil];
         QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
     } else {
@@ -265,18 +271,7 @@ NSWindow * QCocoaWindow::createWindow()
             wattr |= QtMacCustomizeWindow;
     }
 */
-    // If we haven't created the desktop widget, you have to pass the rectangle
-    // in "cocoa coordinates" (i.e., top points to the lower left coordinate).
-    // Otherwise, we do the conversion for you. Since we are the only ones that
-    // create the desktop widget, this is OK (but confusing).
-/*
-    NSRect geo = NSMakeRect(crect.left(),
-                            (qt_root_win != 0) ? flipYCoordinate(crect.bottom() + 1) : crect.top(),
-                            crect.width(), crect.height());
-*/
-    QRect geo = window()->geometry();
-    NSRect frame = NSMakeRect(geo.x(), geo.y(), geo.width(), geo.height());
-
+    NSRect frame = globalGeometry(window()->geometry());
     QCocoaAutoReleasePool pool;
     NSWindow *window;
 
@@ -328,4 +323,48 @@ NSWindow * QCocoaWindow::createWindow()
     return window;
 }
 
+// Calculate the global screen geometry for the given local geometry, which
+// might be in the parent window coordinate system.
+NSRect QCocoaWindow::globalGeometry(const QRect localGeometry) const
+{
+    QRect finalGeometry = localGeometry;
+
+    if (QCocoaWindow *parent = parentCocoaWindow()) {
+        QRect parentGeometry = parent->windowGeometry();
+        finalGeometry.adjust(parentGeometry.x(), parentGeometry.y(), parentGeometry.x(), parentGeometry.y());
+
+        // Qt child window geometry assumes that the origin is at the
+        // top-left of the content area of the parent window. The title
+        // bar is not a part of this contet area, but is still included
+        // in the NSWindow height. Move the child window down to acccount
+        // for this if the parent window has a title bar.
+        const int titlebarHeight = 22;
+        if (!(window()->windowFlags() & Qt::FramelessWindowHint))
+            finalGeometry.adjust(0, titlebarHeight, 0, titlebarHeight);
+    }
+
+    // The final "y invert" to get OS X global geometry:
+    QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window());
+    int flippedY = onScreen->geometry().height() - finalGeometry.y() - finalGeometry.height();
+    return NSMakeRect(finalGeometry.x(), flippedY, finalGeometry.width(), finalGeometry.height());
+}
+
+// Returns the current global screen geometry for the nswindow accociated with this window.
+QRect QCocoaWindow::windowGeometry() const
+{
+    NSRect rect = [m_nsWindow frame];
+    QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window());
+    int flippedY = onScreen->geometry().height() - rect.origin.y - rect.size.height;  // account for nswindow inverted y.
+    QRect qRect = QRect(rect.origin.x, flippedY, rect.size.width, rect.size.height);
+    return qRect;
+}
+
+// Returns a pointer to the parent QCocoaWindow for this window, or 0 if there is none.
+QCocoaWindow *QCocoaWindow::parentCocoaWindow() const
+{
+    if (window() && window()->transientParent()) {
+        return static_cast<QCocoaWindow*>(window()->transientParent()->handle());
+    }
+    return 0;
+}