1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QCOCOAWINDOW_H
41 #define QCOCOAWINDOW_H
42 
43 #include <AppKit/AppKit.h>
44 
45 #include <qpa/qplatformwindow.h>
46 #include <QRect>
47 #include <QPointer>
48 
49 #ifndef QT_NO_OPENGL
50 #include "qcocoaglcontext.h"
51 #endif
52 #include "qnsview.h"
53 #include "qnswindow.h"
54 
55 #if QT_CONFIG(vulkan)
56 #include <MoltenVK/mvk_vulkan.h>
57 #endif
58 
59 QT_BEGIN_NAMESPACE
60 
61 #ifndef QT_NO_DEBUG_STREAM
62 class QDebug;
63 #endif
64 
65 // QCocoaWindow
66 //
67 // QCocoaWindow is an NSView (not an NSWindow!) in the sense
68 // that it relies on a NSView for all event handling and
69 // graphics output and does not require a NSWindow, except for
70 // for the window-related functions like setWindowTitle.
71 //
72 // As a consequence of this it is possible to embed the QCocoaWindow
73 // in an NSView hierarchy by getting a pointer to the "backing"
74 // NSView and not calling QCocoaWindow::show():
75 //
76 // QWindow *qtWindow = new MyWindow();
77 // qtWindow->create();
78 // QPlatformNativeInterface *platformNativeInterface = QGuiApplication::platformNativeInterface();
79 // NSView *qtView = (NSView *)platformNativeInterface->nativeResourceForWindow("nsview", qtWindow);
80 // [parentView addSubview:qtView];
81 //
82 // See the qt_on_cocoa manual tests for a working example, located
83 // in tests/manual/cocoa at the time of writing.
84 
85 #ifdef Q_MOC_RUN
86 #define Q_NOTIFICATION_HANDLER(notification) Q_INVOKABLE Q_COCOA_NOTIFICATION_##notification
87 #else
88 #define Q_NOTIFICATION_HANDLER(notification)
89 #define Q_NOTIFICATION_PREFIX QT_STRINGIFY2(Q_COCOA_NOTIFICATION_)
90 #endif
91 
92 class QCocoaMenuBar;
93 
94 class QCocoaWindow : public QObject, public QPlatformWindow
95 {
96     Q_OBJECT
97 public:
98     QCocoaWindow(QWindow *tlw, WId nativeHandle = 0);
99     ~QCocoaWindow();
100 
101     void initialize() override;
102 
103     void setGeometry(const QRect &rect) override;
104     QRect geometry() const override;
105     void setCocoaGeometry(const QRect &rect);
106 
107     void setVisible(bool visible) override;
108     void setWindowFlags(Qt::WindowFlags flags) override;
109     void setWindowState(Qt::WindowStates state) override;
110     void setWindowTitle(const QString &title) override;
111     void setWindowFilePath(const QString &filePath) override;
112     void setWindowIcon(const QIcon &icon) override;
113     void setAlertState(bool enabled) override;
114     bool isAlertState() const override;
115     void raise() override;
116     void lower() override;
117     bool isExposed() const override;
118     bool isEmbedded() const override;
119     bool isOpaque() const;
120     void propagateSizeHints() override;
121     void setOpacity(qreal level) override;
122     void setMask(const QRegion &region) override;
123     bool setKeyboardGrabEnabled(bool grab) override;
124     bool setMouseGrabEnabled(bool grab) override;
125     QMargins frameMargins() const override;
126     QSurfaceFormat format() const override;
127 
128     bool isForeignWindow() const override;
129 
130     void requestUpdate() override;
131     bool updatesWithDisplayLink() const;
132     void deliverUpdateRequest() override;
133 
134     void requestActivateWindow() override;
135 
136     WId winId() const override;
137     void setParent(const QPlatformWindow *window) override;
138 
139     NSView *view() const;
140     NSWindow *nativeWindow() const;
141 
142     void setEmbeddedInForeignView();
143 
144     Q_NOTIFICATION_HANDLER(NSViewFrameDidChangeNotification) void viewDidChangeFrame();
145     Q_NOTIFICATION_HANDLER(NSViewGlobalFrameDidChangeNotification) void viewDidChangeGlobalFrame();
146 
147     Q_NOTIFICATION_HANDLER(NSWindowWillMoveNotification) void windowWillMove();
148     Q_NOTIFICATION_HANDLER(NSWindowDidMoveNotification) void windowDidMove();
149     Q_NOTIFICATION_HANDLER(NSWindowDidResizeNotification) void windowDidResize();
150     Q_NOTIFICATION_HANDLER(NSWindowDidEndLiveResizeNotification) void windowDidEndLiveResize();
151     Q_NOTIFICATION_HANDLER(NSWindowDidBecomeKeyNotification) void windowDidBecomeKey();
152     Q_NOTIFICATION_HANDLER(NSWindowDidResignKeyNotification) void windowDidResignKey();
153     Q_NOTIFICATION_HANDLER(NSWindowWillMiniaturizeNotification) void windowWillMiniaturize();
154     Q_NOTIFICATION_HANDLER(NSWindowDidMiniaturizeNotification) void windowDidMiniaturize();
155     Q_NOTIFICATION_HANDLER(NSWindowDidDeminiaturizeNotification) void windowDidDeminiaturize();
156     Q_NOTIFICATION_HANDLER(NSWindowWillEnterFullScreenNotification) void windowWillEnterFullScreen();
157     Q_NOTIFICATION_HANDLER(NSWindowDidEnterFullScreenNotification) void windowDidEnterFullScreen();
158     Q_NOTIFICATION_HANDLER(NSWindowWillExitFullScreenNotification) void windowWillExitFullScreen();
159     Q_NOTIFICATION_HANDLER(NSWindowDidExitFullScreenNotification) void windowDidExitFullScreen();
160     Q_NOTIFICATION_HANDLER(NSWindowDidOrderOnScreenAndFinishAnimatingNotification) void windowDidOrderOnScreen();
161     Q_NOTIFICATION_HANDLER(NSWindowDidOrderOffScreenNotification) void windowDidOrderOffScreen();
162     Q_NOTIFICATION_HANDLER(NSWindowDidChangeOcclusionStateNotification) void windowDidChangeOcclusionState();
163     Q_NOTIFICATION_HANDLER(NSWindowDidChangeScreenNotification) void windowDidChangeScreen();
164     Q_NOTIFICATION_HANDLER(NSWindowWillCloseNotification) void windowWillClose();
165 
166     bool windowShouldClose();
167     bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
168 
169     NSInteger windowLevel(Qt::WindowFlags flags);
170     NSUInteger windowStyleMask(Qt::WindowFlags flags);
171     void setWindowZoomButton(Qt::WindowFlags flags);
172 
173     bool setWindowModified(bool modified) override;
174 
175     void setFrameStrutEventsEnabled(bool enabled) override;
frameStrutEventsEnabled()176     bool frameStrutEventsEnabled() const override
177         { return m_frameStrutEventsEnabled; }
178 
179     void setMenubar(QCocoaMenuBar *mb);
180     QCocoaMenuBar *menubar() const;
181 
182     void setWindowCursor(NSCursor *cursor);
183 
184     void registerTouch(bool enable);
185     void setContentBorderThickness(int topThickness, int bottomThickness);
186     void registerContentBorderArea(quintptr identifier, int upper, int lower);
187     void setContentBorderAreaEnabled(quintptr identifier, bool enable);
188     void setContentBorderEnabled(bool enable);
189     bool testContentBorderAreaPosition(int position) const;
190     void applyContentBorderThickness(NSWindow *window = nullptr);
191     void updateNSToolbar();
192 
193     qreal devicePixelRatio() const override;
194     QWindow *childWindowAt(QPoint windowPoint);
195     bool shouldRefuseKeyWindowAndFirstResponder();
196 
197     static QPoint bottomLeftClippedByNSWindowOffsetStatic(QWindow *window);
198     QPoint bottomLeftClippedByNSWindowOffset() const;
199 
200     enum RecreationReason {
201         RecreationNotNeeded = 0,
202         ParentChanged = 0x1,
203         MissingWindow = 0x2,
204         WindowModalityChanged = 0x4,
205         ContentViewChanged = 0x10,
206         PanelChanged = 0x20,
207     };
208     Q_DECLARE_FLAGS(RecreationReasons, RecreationReason)
209     Q_FLAG(RecreationReasons)
210 
211 protected:
212     void recreateWindowIfNeeded();
213     QCocoaNSWindow *createNSWindow(bool shouldBePanel);
214 
215     Qt::WindowState windowState() const;
216     void applyWindowState(Qt::WindowStates newState);
217     void toggleMaximized();
218     void toggleFullScreen();
219     bool isTransitioningToFullScreen() const;
220 
221     bool startSystemMove() override;
222 
223 // private:
224 public: // for QNSView
225     friend class QCocoaBackingStore;
226     friend class QCocoaNativeInterface;
227 
228     bool isContentView() const;
229 
230     bool alwaysShowToolWindow() const;
231     void removeMonitor();
232 
233     enum HandleFlags {
234         NoHandleFlags = 0,
235         HandleUnconditionally = 1
236     };
237 
238     void handleGeometryChange();
239     void handleWindowStateChanged(HandleFlags flags = NoHandleFlags);
240     void handleExposeEvent(const QRegion &region);
241 
242     NSView *m_view;
243     QCocoaNSWindow *m_nsWindow;
244 
245     Qt::WindowStates m_lastReportedWindowState;
246     Qt::WindowModality m_windowModality;
247     QPointer<QWindow> m_enterLeaveTargetWindow;
248     bool m_windowUnderMouse;
249 
250     bool m_initialized;
251     bool m_inSetVisible;
252     bool m_inSetGeometry;
253     bool m_inSetStyleMask;
254     QCocoaMenuBar *m_menubar;
255 
256     bool m_needsInvalidateShadow;
257 
258     bool m_frameStrutEventsEnabled;
259     QRect m_exposedRect;
260     int m_registerTouchCount;
261     bool m_resizableTransientParent;
262 
263     static const int NoAlertRequest;
264     NSInteger m_alertRequest;
265     id monitor;
266 
267     bool m_drawContentBorderGradient;
268     int m_topContentBorderThickness;
269     int m_bottomContentBorderThickness;
270 
271     struct BorderRange {
BorderRangeBorderRange272         BorderRange(quintptr i, int u, int l) : identifier(i), upper(u), lower(l) { }
273         quintptr identifier;
274         int upper;
275         int lower;
276         bool operator<(BorderRange const& right) const {
277               return upper < right.upper;
278         }
279     };
280     QHash<quintptr, BorderRange> m_contentBorderAreas; // identifer -> uppper/lower
281     QHash<quintptr, bool> m_enabledContentBorderAreas; // identifer -> enabled state (true/false)
282 
283 #if QT_CONFIG(vulkan)
284     VkSurfaceKHR m_vulkanSurface = nullptr;
285 #endif
286 };
287 
288 #ifndef QT_NO_DEBUG_STREAM
289 QDebug operator<<(QDebug debug, const QCocoaWindow *window);
290 #endif
291 
292 QT_END_NAMESPACE
293 
294 #endif // QCOCOAWINDOW_H
295 
296