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 QWINDOWSWINDOW_H
41 #define QWINDOWSWINDOW_H
42
43 #include <QtCore/qt_windows.h>
44 #include <QtCore/qpointer.h>
45 #include "qwindowscursor.h"
46
47 #include <qpa/qplatformwindow.h>
48 #include <QtPlatformHeaders/qwindowswindowfunctions.h>
49
50 #if QT_CONFIG(vulkan)
51 #include "qwindowsvulkaninstance.h"
52 #endif
53
54 QT_BEGIN_NAMESPACE
55
56 class QWindowsOleDropTarget;
57 class QWindowsMenuBar;
58 class QDebug;
59
60 struct QWindowsGeometryHint
61 {
62 static QMargins frameOnPrimaryScreen(DWORD style, DWORD exStyle);
63 static QMargins frameOnPrimaryScreen(HWND hwnd);
64 static QMargins frame(DWORD style, DWORD exStyle, qreal dpi);
65 static QMargins frame(HWND hwnd, DWORD style, DWORD exStyle);
66 static QMargins frame(const QWindow *w, const QRect &geometry,
67 DWORD style, DWORD exStyle);
68 static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
69 static void applyToMinMaxInfo(const QWindow *w, const QScreen *screen,
70 const QMargins &margins, MINMAXINFO *mmi);
71 static void applyToMinMaxInfo(const QWindow *w, const QMargins &margins,
72 MINMAXINFO *mmi);
73 static void frameSizeConstraints(const QWindow *w, const QScreen *screen,
74 const QMargins &margins,
75 QSize *minimumSize, QSize *maximumSize);
76 static inline QPoint mapToGlobal(HWND hwnd, const QPoint &);
77 static inline QPoint mapToGlobal(const QWindow *w, const QPoint &);
78 static inline QPoint mapFromGlobal(const HWND hwnd, const QPoint &);
79 static inline QPoint mapFromGlobal(const QWindow *w, const QPoint &);
80
81 static bool positionIncludesFrame(const QWindow *w);
82 };
83
84 struct QWindowCreationContext
85 {
86 explicit QWindowCreationContext(const QWindow *w, const QScreen *s,
87 const QRect &geometryIn, const QRect &geometry,
88 const QMargins &customMargins,
89 DWORD style, DWORD exStyle);
90 void applyToMinMaxInfo(MINMAXINFO *mmi) const;
91
92 const QWindow *window;
93 // The screen to use to scale size constraints, etc. Might differ from the
94 // screen of the window after QPlatformWindow::initialGeometry() (QTBUG-77307).
95 const QScreen *screen;
96 QRect requestedGeometryIn; // QWindow scaled
97 QRect requestedGeometry; // after QPlatformWindow::initialGeometry()
98 QPoint obtainedPos;
99 QSize obtainedSize;
100 QMargins margins;
101 QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
102 int frameX = CW_USEDEFAULT; // Passed on to CreateWindowEx(), including frame.
103 int frameY = CW_USEDEFAULT;
104 int frameWidth = CW_USEDEFAULT;
105 int frameHeight = CW_USEDEFAULT;
106 int menuHeight = 0;
107 };
108
109 struct QWindowsWindowData
110 {
111 Qt::WindowFlags flags;
112 QRect geometry;
113 QMargins fullFrameMargins; // Do not use directly for windows, see FrameDirty.
114 QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
115 HWND hwnd = nullptr;
116 bool embedded = false;
117 bool hasFrame = false;
118
119 static QWindowsWindowData create(const QWindow *w,
120 const QWindowsWindowData ¶meters,
121 const QString &title);
122 };
123
124 class QWindowsBaseWindow : public QPlatformWindow
125 {
Q_DISABLE_COPY_MOVE(QWindowsBaseWindow)126 Q_DISABLE_COPY_MOVE(QWindowsBaseWindow)
127 public:
128 explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
129
winId()130 WId winId() const override { return WId(handle()); }
geometry()131 QRect geometry() const override { return geometry_sys(); }
frameMargins()132 QMargins frameMargins() const override { return fullFrameMargins(); }
133 QPoint mapToGlobal(const QPoint &pos) const override;
134 QPoint mapFromGlobal(const QPoint &pos) const override;
fullFrameMargins()135 virtual QMargins fullFrameMargins() const { return frameMargins_sys(); }
136
137 using QPlatformWindow::screenForGeometry;
138
139 virtual HWND handle() const = 0;
isTopLevel()140 virtual bool isTopLevel() const { return isTopLevel_sys(); }
141
style()142 unsigned style() const { return GetWindowLongPtr(handle(), GWL_STYLE); }
exStyle()143 unsigned exStyle() const { return GetWindowLongPtr(handle(), GWL_EXSTYLE); }
144 static bool isRtlLayout(HWND hwnd);
145
146 static QWindowsBaseWindow *baseWindowOf(const QWindow *w);
147 static HWND handleOf(const QWindow *w);
148
149 protected:
parentHwnd()150 HWND parentHwnd() const { return GetAncestor(handle(), GA_PARENT); }
151 bool isTopLevel_sys() const;
152 QRect frameGeometry_sys() const;
153 QRect geometry_sys() const;
154 void setGeometry_sys(const QRect &rect) const;
155 QMargins frameMargins_sys() const;
156 void hide_sys();
157 void raise_sys();
158 void lower_sys();
159 void setWindowTitle_sys(const QString &title);
160 };
161
162 class QWindowsDesktopWindow : public QWindowsBaseWindow
163 {
164 public:
QWindowsDesktopWindow(QWindow * window)165 explicit QWindowsDesktopWindow(QWindow *window)
166 : QWindowsBaseWindow(window), m_hwnd(GetDesktopWindow()) {}
167
frameMargins()168 QMargins frameMargins() const override { return QMargins(); }
isTopLevel()169 bool isTopLevel() const override { return true; }
170
171 protected:
handle()172 HWND handle() const override { return m_hwnd; }
173
174 private:
175 const HWND m_hwnd;
176 };
177
178 class QWindowsForeignWindow : public QWindowsBaseWindow
179 {
180 public:
181 explicit QWindowsForeignWindow(QWindow *window, HWND hwnd);
182
183 void setParent(const QPlatformWindow *window) override;
setGeometry(const QRect & rect)184 void setGeometry(const QRect &rect) override { setGeometry_sys(rect); }
185 void setVisible(bool visible) override;
raise()186 void raise() override { raise_sys(); }
lower()187 void lower() override { lower_sys(); }
setWindowTitle(const QString & title)188 void setWindowTitle(const QString &title) override { setWindowTitle_sys(title); }
isForeignWindow()189 bool isForeignWindow() const override { return true; }
190
191 protected:
handle()192 HWND handle() const override { return m_hwnd; }
193
194 private:
195 const HWND m_hwnd;
196 DWORD m_topLevelStyle;
197 };
198
199 class QWindowsWindow : public QWindowsBaseWindow
200 {
201 public:
202 enum Flags
203 {
204 AutoMouseCapture = 0x1, //! Automatic mouse capture on button press.
205 WithinSetParent = 0x2,
206 WithinSetGeometry = 0x8,
207 OpenGLSurface = 0x10,
208 OpenGL_ES2 = 0x20,
209 OpenGLDoubleBuffered = 0x40,
210 OpenGlPixelFormatInitialized = 0x80,
211 BlockedByModal = 0x100,
212 SizeGripOperation = 0x200,
213 FrameStrutEventsEnabled = 0x400,
214 SynchronousGeometryChangeEvent = 0x800,
215 WithinSetStyle = 0x1000,
216 WithinDestroy = 0x2000,
217 TouchRegistered = 0x4000,
218 AlertState = 0x8000,
219 Exposed = 0x10000,
220 WithinCreate = 0x20000,
221 WithinMaximize = 0x40000,
222 MaximizeToFullScreen = 0x80000,
223 Compositing = 0x100000,
224 HasBorderInFullScreen = 0x200000,
225 WithinDpiChanged = 0x400000,
226 VulkanSurface = 0x800000,
227 ResizeMoveActive = 0x1000000,
228 DisableNonClientScaling = 0x2000000
229 };
230
231 QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
232 ~QWindowsWindow() override;
233
234 void initialize() override;
235
236 using QPlatformWindow::screenForGeometry;
237
238 QSurfaceFormat format() const override;
239 void setGeometry(const QRect &rect) override;
geometry()240 QRect geometry() const override { return m_data.geometry; }
241 QRect normalGeometry() const override;
242
243 void setVisible(bool visible) override;
244 bool isVisible() const;
isExposed()245 bool isExposed() const override { return testFlag(Exposed); }
246 bool isActive() const override;
247 bool isAncestorOf(const QPlatformWindow *child) const override;
248 bool isEmbedded() const override;
249 QPoint mapToGlobal(const QPoint &pos) const override;
250 QPoint mapFromGlobal(const QPoint &pos) const override;
251
252 void setWindowFlags(Qt::WindowFlags flags) override;
253 void setWindowState(Qt::WindowStates state) override;
254
255 void setParent(const QPlatformWindow *window) override;
256
257 void setWindowTitle(const QString &title) override;
raise()258 void raise() override { raise_sys(); }
lower()259 void lower() override { lower_sys(); }
260
261 bool windowEvent(QEvent *event) override;
262
263 void propagateSizeHints() override;
264 static bool handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &marginsDp);
265 bool handleGeometryChanging(MSG *message) const;
266 QMargins frameMargins() const override;
267 QMargins fullFrameMargins() const override;
268 void setFullFrameMargins(const QMargins &newMargins);
269 void updateFullFrameMargins();
270
271 void setOpacity(qreal level) override;
272 void setMask(const QRegion ®ion) override;
opacity()273 qreal opacity() const { return m_opacity; }
274 void requestActivateWindow() override;
275
276 bool setKeyboardGrabEnabled(bool grab) override;
277 bool setMouseGrabEnabled(bool grab) override;
hasMouseCapture()278 inline bool hasMouseCapture() const { return GetCapture() == m_data.hwnd; }
279
280 bool startSystemResize(Qt::Edges edges) override;
281 bool startSystemMove() override;
282
283 void setFrameStrutEventsEnabled(bool enabled) override;
frameStrutEventsEnabled()284 bool frameStrutEventsEnabled() const override { return testFlag(FrameStrutEventsEnabled); }
285
286 // QWindowsBaseWindow overrides
handle()287 HWND handle() const override { return m_data.hwnd; }
288 bool isTopLevel() const override;
289
290 static bool setDarkBorderToWindow(HWND hwnd, bool d);
291 void setDarkBorder(bool d);
292
293 QWindowsMenuBar *menuBar() const;
294 void setMenuBar(QWindowsMenuBar *mb);
295
customMargins()296 QMargins customMargins() const { return m_data.customMargins; }
297 void setCustomMargins(const QMargins &m);
298
299 void setStyle(unsigned s) const;
300 void setExStyle(unsigned s) const;
301
302 bool handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
303
304 void handleMoved();
305 void handleResized(int wParam);
306 void handleHidden();
307 void handleCompositionSettingsChanged();
308
309 static void displayChanged();
310 static void settingsChanged();
311 static QScreen *forcedScreenForGLWindow(const QWindow *w);
312 static QWindowsWindow *windowsWindowOf(const QWindow *w);
313 static QWindow *topLevelOf(QWindow *w);
314 static inline void *userDataOf(HWND hwnd);
315 static inline void setUserDataOf(HWND hwnd, void *ud);
316
317 static bool setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity);
318 bool isLayered() const;
319
320 HDC getDC();
321 void releaseDC();
322 void getSizeHints(MINMAXINFO *mmi) const;
323 bool handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const;
324
325 #ifndef QT_NO_CURSOR
cursor()326 CursorHandlePtr cursor() const { return m_cursor; }
327 #endif
328 void setCursor(const CursorHandlePtr &c);
329 void applyCursor();
330
testFlag(unsigned f)331 inline bool testFlag(unsigned f) const { return (m_flags & f) != 0; }
setFlag(unsigned f)332 inline void setFlag(unsigned f) const { m_flags |= f; }
clearFlag(unsigned f)333 inline void clearFlag(unsigned f) const { m_flags &= ~f; }
334
335 void setEnabled(bool enabled);
336 bool isEnabled() const;
337 void setWindowIcon(const QIcon &icon) override;
338
339 void *surface(void *nativeConfig, int *err);
340 void invalidateSurface() override;
341 void aboutToMakeCurrent();
342
343 void setAlertState(bool enabled) override;
isAlertState()344 bool isAlertState() const override { return testFlag(AlertState); }
345 void alertWindow(int durationMs = 0);
346 void stopAlertWindow();
347
348 enum ScreenChangeMode { FromGeometryChange, FromDpiChange };
349 void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange);
350
351 static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes);
352 void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch);
353 static void setHasBorderInFullScreenStatic(QWindow *window, bool border);
354 static void setHasBorderInFullScreenDefault(bool border);
355 void setHasBorderInFullScreen(bool border);
356 static QString formatWindowTitle(const QString &title);
357
358 static const char *embeddedNativeParentHandleProperty;
359 static const char *hasBorderInFullScreenProperty;
360
361 private:
362 inline void show_sys() const;
363 inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const;
364 inline bool isFullScreen_sys() const;
365 inline void setWindowState_sys(Qt::WindowStates newState);
366 inline void setParent_sys(const QPlatformWindow *parent);
367 inline void updateTransientParent() const;
368 void destroyWindow();
isDropSiteEnabled()369 inline bool isDropSiteEnabled() const { return m_dropTarget != nullptr; }
370 void setDropSiteEnabled(bool enabled);
371 void updateDropSite(bool topLevel);
372 void handleGeometryChange();
373 void handleWindowStateChange(Qt::WindowStates state);
374 inline void destroyIcon();
375 void fireExpose(const QRegion ®ion, bool force=false);
376 void fireFullExpose(bool force=false);
377 void calculateFullFrameMargins();
378
379 mutable QWindowsWindowData m_data;
380 QPointer<QWindowsMenuBar> m_menuBar;
381 mutable unsigned m_flags = WithinCreate;
382 HDC m_hdc = nullptr;
383 Qt::WindowStates m_windowState = Qt::WindowNoState;
384 qreal m_opacity = 1;
385 #ifndef QT_NO_CURSOR
386 CursorHandlePtr m_cursor;
387 #endif
388 QWindowsOleDropTarget *m_dropTarget = nullptr;
389 unsigned m_savedStyle = 0;
390 QRect m_savedFrameGeometry;
391 HICON m_iconSmall = nullptr;
392 HICON m_iconBig = nullptr;
393 void *m_surface = nullptr;
394
395 static bool m_screenForGLInitialized;
396
397 #if QT_CONFIG(vulkan)
398 // note: intentionally not using void * in order to avoid breaking x86
399 VkSurfaceKHR m_vkSurface = VK_NULL_HANDLE;
400 #endif
401 static bool m_borderInFullScreenDefault;
402 };
403
404 #ifndef QT_NO_DEBUG_STREAM
405 QDebug operator<<(QDebug d, const RECT &r);
406 QDebug operator<<(QDebug d, const POINT &);
407 QDebug operator<<(QDebug d, const MINMAXINFO &i);
408 QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p);
409 QDebug operator<<(QDebug d, const WINDOWPLACEMENT &);
410 QDebug operator<<(QDebug d, const WINDOWPOS &);
411 QDebug operator<<(QDebug d, const GUID &guid);
412 #endif // !QT_NO_DEBUG_STREAM
413
clientToScreen(HWND hwnd,POINT * wP)414 static inline void clientToScreen(HWND hwnd, POINT *wP)
415 {
416 if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
417 RECT clientArea;
418 GetClientRect(hwnd, &clientArea);
419 wP->x = clientArea.right - wP->x;
420 }
421 ClientToScreen(hwnd, wP);
422 }
423
screenToClient(HWND hwnd,POINT * wP)424 static inline void screenToClient(HWND hwnd, POINT *wP)
425 {
426 ScreenToClient(hwnd, wP);
427 if (QWindowsBaseWindow::isRtlLayout(hwnd)) {
428 RECT clientArea;
429 GetClientRect(hwnd, &clientArea);
430 wP->x = clientArea.right - wP->x;
431 }
432 }
433
434 // ---------- QWindowsGeometryHint inline functions.
mapToGlobal(HWND hwnd,const QPoint & qp)435 QPoint QWindowsGeometryHint::mapToGlobal(HWND hwnd, const QPoint &qp)
436 {
437 POINT p = { qp.x(), qp.y() };
438 clientToScreen(hwnd, &p);
439 return QPoint(p.x, p.y);
440 }
441
mapFromGlobal(const HWND hwnd,const QPoint & qp)442 QPoint QWindowsGeometryHint::mapFromGlobal(const HWND hwnd, const QPoint &qp)
443 {
444 POINT p = { qp.x(), qp.y() };
445 screenToClient(hwnd, &p);
446 return QPoint(p.x, p.y);
447 }
448
mapToGlobal(const QWindow * w,const QPoint & p)449 QPoint QWindowsGeometryHint::mapToGlobal(const QWindow *w, const QPoint &p)
450 { return QWindowsGeometryHint::mapToGlobal(QWindowsWindow::handleOf(w), p); }
451
mapFromGlobal(const QWindow * w,const QPoint & p)452 QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p)
453 { return QWindowsGeometryHint::mapFromGlobal(QWindowsWindow::handleOf(w), p); }
454
455
456 // ---------- QWindowsBaseWindow inline functions.
457
windowsWindowOf(const QWindow * w)458 inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w)
459 {
460 if (!w || !w->handle())
461 return nullptr;
462
463 const Qt::WindowType type = w->type();
464 if (type == Qt::Desktop || w->handle()->isForeignWindow())
465 return nullptr;
466
467 return static_cast<QWindowsWindow *>(w->handle());
468 }
469
userDataOf(HWND hwnd)470 void *QWindowsWindow::userDataOf(HWND hwnd)
471 {
472 return reinterpret_cast<void *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
473 }
474
setUserDataOf(HWND hwnd,void * ud)475 void QWindowsWindow::setUserDataOf(HWND hwnd, void *ud)
476 {
477 SetWindowLongPtr(hwnd, GWLP_USERDATA, LONG_PTR(ud));
478 }
479
destroyIcon()480 inline void QWindowsWindow::destroyIcon()
481 {
482 if (m_iconBig) {
483 DestroyIcon(m_iconBig);
484 m_iconBig = nullptr;
485 }
486 if (m_iconSmall) {
487 DestroyIcon(m_iconSmall);
488 m_iconSmall = nullptr;
489 }
490 }
491
isLayered()492 inline bool QWindowsWindow::isLayered() const
493 {
494 return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE) & WS_EX_LAYERED;
495 }
496
497 QT_END_NAMESPACE
498
499 Q_DECLARE_METATYPE(QMargins)
500
501 #endif // QWINDOWSWINDOW_H
502