Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcocoawindowmanager.mm
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <AppKit/AppKit.h>
6
8#include "qcocoawindow.h"
9
10#include <QtCore/private/qcore_mac_p.h>
11
12#include <QtGui/qguiapplication.h>
13#include <QtGui/qwindow.h>
14
16
17QCocoaWindowManager::QCocoaWindowManager()
18{
19 if (NSApp) {
20 initialize();
21 } else {
22 m_applicationDidFinishLaunchingObserver = QMacNotificationObserver(nil,
23 NSApplicationDidFinishLaunchingNotification, [this] { initialize(); });
24 }
25}
26
27void QCocoaWindowManager::initialize()
28{
29 Q_ASSERT(NSApp);
30
31 // Whenever the modalWindow property of NSApplication changes we have a new
32 // modal session running. Observing the app modal window instead of our own
33 // event dispatcher sessions allows us to track session started by native
34 // APIs as well. We need to check the initial state as well, in case there
35 // is already a modal session running.
36 m_modalSessionObserver = QMacKeyValueObserver(
37 NSApp, @"modalWindow", [this] { modalSessionChanged(); },
38 NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew);
39}
40
41void QCocoaWindowManager::modalSessionChanged()
42{
43 // Make sure that no window is overlapping the modal window. This can
44 // happen for e.g. splash screens, which have the NSPopUpMenuWindowLevel.
45 for (auto *window : QGuiApplication::topLevelWindows()) {
46 auto *platformWindow = static_cast<QCocoaWindow*>(window->handle());
47 if (!platformWindow)
48 continue;
49
50 auto naturalWindowLevel = platformWindow->windowLevel(window->flags());
51 if (naturalWindowLevel > NSModalPanelWindowLevel) {
52 NSWindow *nativeWindow = platformWindow->nativeWindow();
53 if (NSApp.modalWindow) {
54 // Lower window to that of the modal windows, but no less
55 nativeWindow.level = NSModalPanelWindowLevel;
56 if ([nativeWindow isVisible])
57 [nativeWindow orderBack:nil];
58 } else {
59 // Restore window's natural window level, whatever that was
60 nativeWindow.level = naturalWindowLevel;
61 }
62 }
63 }
64
65 // Our worksWhenModal implementation is declarative and will normally be picked
66 // up by AppKit when needed, but to make sure AppKit also reflects the state
67 // in the window tag, so that the window can be ordered front by clicking it,
68 // we need to explicitly call setWorksWhenModal.
69 for (id window in NSApp.windows) {
70 if ([window isKindOfClass:[QNSPanel class]]) {
71 auto *panel = static_cast<QNSPanel *>(window);
72 // Call setter to tell AppKit that our state has changed
73 [panel setWorksWhenModal:panel.worksWhenModal];
74 }
75 }
76}
77
78QT_END_NAMESPACE