summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qcocoawindow.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoawindow.mm')
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm123
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;
+}