Cocoa: Fix qmlscene flicker on startup.
[profile/ivi/qtbase.git] / src / plugins / platforms / cocoa / qcocoawindow.mm
index 492a43a..ef04fc4 100644 (file)
 #include <QtCore/private/qcore_mac_p.h>
 #include <qwindow.h>
 #include <QWindowSystemInterface>
+#include <QPlatformScreen>
 
 #include <Cocoa/Cocoa.h>
 #include <Carbon/Carbon.h>
 
 #include <QDebug>
 
+@implementation QNSWindow
+
+- (BOOL)canBecomeKeyWindow
+{
+    return YES;
+}
+
+- (BOOL)canBecomeMainWindow
+{
+    return YES;
+}
+
+@end
+
 QCocoaWindow::QCocoaWindow(QWindow *tlw)
     : QPlatformWindow(tlw)
+    , m_windowAttributes(0)
+    , m_windowClass(0)
     , m_glContext(0)
 {
     QCocoaAutoReleasePool pool;
@@ -65,33 +82,32 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
     [m_nsWindow setDelegate:delegate];
     [m_nsWindow setAcceptsMouseMovedEvents:YES];
 
+    // Prevent Cocoa from releasing the window on close. Qt
+    // handles the close event asynchronously and we want to
+    // make sure that m_nsWindow stays valid until the
+    // QCocoaWindow is deleted by Qt.
+    [m_nsWindow setReleasedWhenClosed : NO];
+
     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());
-        m_windowSurfaceView = [[NSOpenGLView alloc] initWithFrame : glFrame pixelFormat : QCocoaGLContext::createNSOpenGLPixelFormat() ];
-        [m_contentView setAutoresizesSubviews : YES];
-        [m_windowSurfaceView setAutoresizingMask : (NSViewWidthSizable | NSViewHeightSizable)];
-        [m_contentView addSubview : m_windowSurfaceView];
-    } else {
-        m_windowSurfaceView = m_contentView;
-    }
+    setGeometry(tlw->geometry());
 
     [m_nsWindow setContentView:m_contentView];
 }
 
 QCocoaWindow::~QCocoaWindow()
 {
-
+    [m_nsWindow release];
 }
 
 void QCocoaWindow::setGeometry(const QRect &rect)
 {
     QPlatformWindow::setGeometry(rect);
 
-    NSRect bounds = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
+    NSRect bounds = globalGeometry(rect);
     [[m_nsWindow contentView]setFrameSize:bounds.size];
+    [m_nsWindow setContentSize : bounds.size];
+    [m_nsWindow setFrameOrigin : bounds.origin];
 
     if (m_glContext)
         m_glContext->update();
@@ -100,8 +116,15 @@ 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());
+
+        // Make sure the QWindow has a frame ready before we show the NSWindow.
+        QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size()));
+
         [m_nsWindow makeKeyAndOrderFront:nil];
-        QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
     } else {
         [m_nsWindow orderOut:nil];
     }
@@ -135,11 +158,6 @@ NSView *QCocoaWindow::contentView() const
     return [m_nsWindow contentView];
 }
 
-NSView *QCocoaWindow::windowSurfaceView() const
-{
-    return m_windowSurfaceView;
-}
-
 void QCocoaWindow::windowDidMove()
 {
     if (m_glContext)
@@ -148,13 +166,18 @@ void QCocoaWindow::windowDidMove()
 
 void QCocoaWindow::windowDidResize()
 {
-    //jlind: XXX This isn't ideal. Eventdispatcher does not run when resizing...
+    if (m_glContext)
+        m_glContext->update();
+
     NSRect rect = [[m_nsWindow contentView]frame];
     QRect geo(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
-    QWindowSystemInterface::handleGeometryChange(window(),geo);
+    QWindowSystemInterface::handleSynchronousGeometryChange(window(), geo);
+}
 
-    if (m_glContext)
-        m_glContext->update();
+
+void QCocoaWindow::windowWillClose()
+{
+    QWindowSystemInterface::handleCloseEvent(window());
 }
 
 void QCocoaWindow::setCurrentContext(QCocoaGLContext *context)
@@ -246,7 +269,7 @@ void QCocoaWindow::determineWindowClass()
 /*
 
 */
-NSWindow * QCocoaWindow::createWindow()
+QNSWindow * QCocoaWindow::createWindow()
 {
     // Determine if we need to add in our "custom window" attribute. Cocoa is rather clever
     // in deciding if we need the maximize button or not (i.e., it's resizeable, so you
@@ -265,20 +288,9 @@ 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;
+    QNSWindow *window;
 
     switch (m_windowClass) {
     case kMovableModalWindowClass:
@@ -309,7 +321,7 @@ NSWindow * QCocoaWindow::createWindow()
         panel = [[NSPanel alloc] initWithContentRect:frame
                                    styleMask:m_windowAttributes
                                    backing:NSBackingStoreBuffered
-                                   defer:YES];
+                                   defer:NO]; // see window case below
 //  ### crashes
 //        [panel setFloatingPanel:needFloating];
 //        [panel setWorksWhenModal:worksWhenModal];
@@ -317,10 +329,11 @@ NSWindow * QCocoaWindow::createWindow()
         break;
     }
     default:
-        window  = [[NSWindow alloc] initWithContentRect:frame
-                                            styleMask:m_windowAttributes
+        window  = [[QNSWindow alloc] initWithContentRect:frame
+                                            styleMask:(NSResizableWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSTitledWindowMask)
                                             backing:NSBackingStoreBuffered
-                                            defer:YES];
+                                            defer:NO]; // Deferring window creation breaks OpenGL (the GL context is set up
+                                                       // before the window is shown and needs a proper window.).
         break;
     }
 
@@ -328,4 +341,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;
+}