diff options
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoawindow.mm')
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 123 |
1 files changed, 98 insertions, 25 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index de58842772..83b6534b7c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -41,6 +41,7 @@ #include "qcocoawindow.h" #include "qnswindowdelegate.h" #include "qcocoaautoreleasepool.h" +#include "qcocoaeventdispatcher.h" #include "qcocoaglcontext.h" #include "qcocoahelpers.h" #include "qnsview.h" @@ -96,8 +97,10 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) : QPlatformWindow(tlw) , m_nsWindow(0) + , m_synchedWindowState(Qt::WindowActive) , m_inConstructor(true) , m_glContext(0) + , m_hasModalSession(false) { QCocoaAutoReleasePool pool; @@ -145,7 +148,10 @@ void QCocoaWindow::setVisible(bool visible) qDebug() << "QCocoaWindow::setVisible" << window() << visible; #endif if (visible) { + QCocoaWindow *parentCocoaWindow = 0; if (window()->transientParent()) { + parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); + // The parent window might have moved while this window was hidden, // update the window geometry if there is a parent. setGeometry(window()->geometry()); @@ -154,8 +160,6 @@ void QCocoaWindow::setVisible(bool visible) // close them when needed. if (window()->windowType() == Qt::Popup) { // qDebug() << "transientParent and popup" << window()->windowType() << Qt::Popup << (window()->windowType() & Qt::Popup); - - QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); parentCocoaWindow->m_activePopupWindow = window(); } @@ -165,15 +169,47 @@ void QCocoaWindow::setVisible(bool visible) QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size())); if (m_nsWindow) { - if ([m_nsWindow canBecomeKeyWindow]) - [m_nsWindow makeKeyAndOrderFront:nil]; - else - [m_nsWindow orderFront: nil]; + // setWindowState might have been called while the window was hidden and + // will not change the NSWindow state in that case. Sync up here: + syncWindowState(window()->windowState()); + + if (window()->windowState() != Qt::WindowMinimized) { + if ((window()->windowModality() == Qt::WindowModal + || window()->windowType() == Qt::Sheet) + && parentCocoaWindow) { + // show the window as a sheet + [NSApp beginSheet:m_nsWindow modalForWindow:parentCocoaWindow->m_nsWindow modalDelegate:nil didEndSelector:nil contextInfo:nil]; + } else if (window()->windowModality() != Qt::NonModal) { + // show the window as application modal + QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); + Q_ASSERT(cocoaEventDispatcher != 0); + QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); + cocoaEventDispatcherPrivate->beginModalSession(window()); + m_hasModalSession = true; + } else if ([m_nsWindow canBecomeKeyWindow]) { + [m_nsWindow makeKeyAndOrderFront:nil]; + } else { + [m_nsWindow orderFront: nil]; + } + } } } else { // qDebug() << "close" << this; - if (m_nsWindow) + if (m_nsWindow) { + if (m_hasModalSession) { + QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); + Q_ASSERT(cocoaEventDispatcher != 0); + QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); + cocoaEventDispatcherPrivate->endModalSession(window()); + m_hasModalSession = false; + } else { + if ([m_nsWindow isSheet]) + [NSApp endSheet:m_nsWindow]; + } [m_nsWindow orderOut:m_nsWindow]; + } + if (!QCoreApplication::closingDown()) + QWindowSystemInterface::handleExposeEvent(window(), QRegion()); } } @@ -183,6 +219,14 @@ Qt::WindowFlags QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) return m_windowFlags; } +Qt::WindowState QCocoaWindow::setWindowState(Qt::WindowState state) +{ + if ([m_nsWindow isVisible]) + syncWindowState(state); // Window state set for hidden windows take effect when show() is called. + + return state; +} + void QCocoaWindow::setWindowTitle(const QString &title) { QCocoaAutoReleasePool pool; @@ -347,6 +391,12 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) // Create a new NSWindow if this is a top-level window. m_nsWindow = createNSWindow(); setNSWindow(m_nsWindow); + + if (window()->transientParent()) { + // keep this window on the same level as its transient parent (which may be a modal dialog, for example) + QCocoaWindow *parentCocoaWindow = static_cast<QCocoaWindow *>(window()->transientParent()->handle()); + [m_nsWindow setLevel:[parentCocoaWindow->m_nsWindow level]]; + } } else { // Child windows have no NSWindow, link the NSViews instead. const QCocoaWindow *parentCococaWindow = static_cast<const QCocoaWindow *>(parentWindow); @@ -446,27 +496,12 @@ void QCocoaWindow::setNSWindow(NSWindow *window) // QCocoaWindow is deleted by Qt. [window setReleasedWhenClosed : NO]; - [[NSNotificationCenter defaultCenter] addObserver:m_contentView - selector:@selector(windowDidBecomeKey) - name:NSWindowDidBecomeKeyNotification - object:m_nsWindow]; [[NSNotificationCenter defaultCenter] addObserver:m_contentView - selector:@selector(windowDidResignKey) - name:NSWindowDidResignKeyNotification + selector:@selector(windowNotification:) + name:nil // Get all notifications object:m_nsWindow]; - [[NSNotificationCenter defaultCenter] addObserver:m_contentView - selector:@selector(windowDidBecomeMain) - name:NSWindowDidBecomeMainNotification - object:m_nsWindow]; - - [[NSNotificationCenter defaultCenter] addObserver:m_contentView - selector:@selector(windowDidResignMain) - name:NSWindowDidResignMainNotification - object:m_nsWindow]; - - // ### Accept touch events by default. // Beware that enabling touch events has a negative impact on the overall performance. // We probably need a QWindowSystemInterface API to enable/disable touch events. @@ -479,7 +514,6 @@ void QCocoaWindow::clearNSWindow(NSWindow *window) { [window setDelegate:nil]; [[NSNotificationCenter defaultCenter] removeObserver:m_contentView]; - [m_contentView removeFromSuperviewWithoutNeedingDisplay]; } // Returns the current global screen geometry for the nswindow associated with this window. @@ -504,3 +538,42 @@ QCocoaWindow *QCocoaWindow::parentCocoaWindow() const return 0; } +// Syncs the NSWindow minimize/maximize/fullscreen state with the current QWindow state +void QCocoaWindow::syncWindowState(Qt::WindowState newState) +{ + if (!m_nsWindow) + return; + + if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { + [m_nsWindow performZoom : m_nsWindow]; // toggles + } + + if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) { + if (newState & Qt::WindowMinimized) { + [m_nsWindow performMiniaturize : m_nsWindow]; + } else { + [m_nsWindow deminiaturize : m_nsWindow]; + } + } + + if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { + [m_nsWindow toggleFullScreen : m_nsWindow]; + } else { + // TODO: "normal" fullscreen + } +#endif + } + + // New state is now the current synched state + m_synchedWindowState = newState; +} + +bool QCocoaWindow::setWindowModified(bool modified) +{ + if (!m_nsWindow) + return false; + [m_nsWindow setDocumentEdited:(modified?YES:NO)]; + return true; +} |