Cocoa: Implement support for child windows.

On OS X, child windows (in the Qt sense) are not
windows. Add special case to window creation that
links the content views instead of creating a
NSWindow. Add a similar special case to
setGeometry().

Refactor window (re)creation into recreateWindow(),
which is called from both the QCocoaWindow
constructor and setParent().

m_nsWindow may now be null, add null-pointer checks
to all usages. Change winId() to return the
m_contentView pointer instead of m_nsWindow.

QGLWidget now works, but probably has sibling window
stacking issues which we won't be able to fix without
moving to client-side compositing.

Change-Id: I2e74cf27734dba7076c150e0d8341f0a62d3de2d
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
Morten Johan Sorvig 2012-03-13 10:37:53 +01:00 committed by Qt by Nokia
parent 5939cd33af
commit 6d9f04422a
2 changed files with 69 additions and 21 deletions

View File

@ -92,6 +92,7 @@ public:
~QCocoaWindow();
void setGeometry(const QRect &rect);
void setCocoaGeometry(const QRect &rect);
void setVisible(bool visible);
Qt::WindowFlags setWindowFlags(Qt::WindowFlags flags);
void setWindowTitle(const QString &title);
@ -117,6 +118,7 @@ public:
protected:
// NSWindow handling. The QCocoaWindow/QNSView can either be displayed
// in an existing NSWindow or in one created by Qt.
void recreateWindow(const QPlatformWindow *parentWindow);
NSWindow *createNSWindow();
void setNSWindow(NSWindow *window);
void clearNSWindow(NSWindow *window);

View File

@ -90,6 +90,7 @@
QCocoaWindow::QCocoaWindow(QWindow *tlw)
: QPlatformWindow(tlw)
, m_nsWindow(0)
, m_glContext(0)
, m_inConstructor(true)
{
@ -98,8 +99,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
m_contentView = [[QNSView alloc] initWithQWindow:tlw platformWindow:this];
setGeometry(tlw->geometry());
m_nsWindow = createNSWindow();
setNSWindow(m_nsWindow);
recreateWindow(parent());
m_inConstructor = false;
}
@ -119,10 +119,18 @@ void QCocoaWindow::setGeometry(const QRect &rect)
qDebug() << "QCocoaWindow::setGeometry" << this << rect;
#endif
QPlatformWindow::setGeometry(rect);
setCocoaGeometry(rect);
}
NSRect bounds = qt_mac_flipRect(rect, window());
[m_nsWindow setContentSize : bounds.size];
[m_nsWindow setFrameOrigin : bounds.origin];
void QCocoaWindow::setCocoaGeometry(const QRect &rect)
{
if (m_nsWindow) {
NSRect bounds = qt_mac_flipRect(rect, window());
[m_nsWindow setContentSize : bounds.size];
[m_nsWindow setFrameOrigin : bounds.origin];
} else {
[m_contentView setFrame : NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
}
}
void QCocoaWindow::setVisible(bool visible)
@ -151,13 +159,16 @@ void QCocoaWindow::setVisible(bool visible)
// Make sure the QWindow has a frame ready before we show the NSWindow.
QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size()));
if ([m_nsWindow canBecomeKeyWindow])
[m_nsWindow makeKeyAndOrderFront:nil];
else
[m_nsWindow orderFront: nil];
if (m_nsWindow) {
if ([m_nsWindow canBecomeKeyWindow])
[m_nsWindow makeKeyAndOrderFront:nil];
else
[m_nsWindow orderFront: nil];
}
} else {
// qDebug() << "close" << this;
[m_nsWindow orderOut:m_nsWindow];
if (m_nsWindow)
[m_nsWindow orderOut:m_nsWindow];
}
}
@ -170,6 +181,8 @@ Qt::WindowFlags QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
void QCocoaWindow::setWindowTitle(const QString &title)
{
QCocoaAutoReleasePool pool;
if (!m_nsWindow)
return;
CFStringRef windowTitle = QCFString::toCFStringRef(title);
[m_nsWindow setTitle: const_cast<NSString *>(reinterpret_cast<const NSString *>(windowTitle))];
@ -180,17 +193,21 @@ void QCocoaWindow::raise()
{
//qDebug() << "raise" << this;
// ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm)
[m_nsWindow orderFront: m_nsWindow];
if (m_nsWindow)
[m_nsWindow orderFront: m_nsWindow];
}
void QCocoaWindow::lower()
{
[m_nsWindow orderBack: m_nsWindow];
if (m_nsWindow)
[m_nsWindow orderBack: m_nsWindow];
}
void QCocoaWindow::propagateSizeHints()
{
QCocoaAutoReleasePool pool;
if (!m_nsWindow)
return;
[m_nsWindow setMinSize : qt_mac_toNSSize(window()->minimumSize())];
[m_nsWindow setMaxSize : qt_mac_toNSSize(window()->maximumSize())];
@ -213,6 +230,9 @@ void QCocoaWindow::propagateSizeHints()
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
{
if (!m_nsWindow)
return false;
if (grab && ![m_nsWindow isKeyWindow])
[m_nsWindow makeKeyWindow];
else if (!grab && [m_nsWindow isKeyWindow])
@ -222,6 +242,9 @@ bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
bool QCocoaWindow::setMouseGrabEnabled(bool grab)
{
if (!m_nsWindow)
return false;
if (grab && ![m_nsWindow isKeyWindow])
[m_nsWindow makeKeyWindow];
else if (!grab && [m_nsWindow isKeyWindow])
@ -231,23 +254,19 @@ bool QCocoaWindow::setMouseGrabEnabled(bool grab)
WId QCocoaWindow::winId() const
{
return WId(m_nsWindow);
return WId(m_contentView);
}
void QCocoaWindow::setParent(const QPlatformWindow *window)
void QCocoaWindow::setParent(const QPlatformWindow *parentWindow)
{
// recreate the window for compatibility
clearNSWindow(m_nsWindow);
[m_nsWindow close];
[m_nsWindow release];
m_nsWindow = createNSWindow();
setNSWindow(m_nsWindow);
recreateWindow(parentWindow);
setCocoaGeometry(geometry());
}
NSView *QCocoaWindow::contentView() const
{
return [m_nsWindow contentView];
return m_contentView;
}
void QCocoaWindow::windowWillMove()
@ -266,6 +285,9 @@ void QCocoaWindow::windowDidMove()
void QCocoaWindow::windowDidResize()
{
if (!m_nsWindow)
return;
NSRect rect = [[m_nsWindow contentView]frame];
// Call setFrameSize which will trigger a frameDidChangeNotification on QNSView.
[[m_nsWindow contentView] setFrameSize:rect.size];
@ -286,6 +308,27 @@ QCocoaGLContext *QCocoaWindow::currentContext() const
return m_glContext;
}
void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
{
// Remove current window (if any)
if (m_nsWindow) {
clearNSWindow(m_nsWindow);
[m_nsWindow close];
[m_nsWindow release];
m_nsWindow = 0;
}
if (!parentWindow) {
// Create a new NSWindow if this is a top-level window.
m_nsWindow = createNSWindow();
setNSWindow(m_nsWindow);
} else {
// Child windows have no NSWindow, link the NSViews instead.
const QCocoaWindow *parentCococaWindow = static_cast<const QCocoaWindow *>(parentWindow);
[parentCococaWindow->m_contentView addSubview : m_contentView];
}
}
NSWindow * QCocoaWindow::createNSWindow()
{
QCocoaAutoReleasePool pool;
@ -378,6 +421,9 @@ void QCocoaWindow::clearNSWindow(NSWindow *window)
// Returns the current global screen geometry for the nswindow associated with this window.
QRect QCocoaWindow::windowGeometry() const
{
if (!m_nsWindow)
return geometry();
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.