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 &parameters,
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 &region) 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 &region, 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