#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;
[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();
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];
}
return [m_nsWindow contentView];
}
-NSView *QCocoaWindow::windowSurfaceView() const
-{
- return m_windowSurfaceView;
-}
-
void QCocoaWindow::windowDidMove()
{
if (m_glContext)
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)
/*
*/
-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
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:
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];
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;
}
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;
+}