1
/****************************************************************************
3
** Copyright (C) 2016 The Qt Company Ltd.
4
** Contact: https://www.qt.io/licensing/
6
** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
38
****************************************************************************/
40
#include "qwindowswindow.h"
41
#include "qwindowsnativeimage.h"
42
#include "qwindowscontext.h"
43
#include "qwindowsdrag.h"
44
#include "qwindowsscreen.h"
45
#include "qwindowsintegration.h"
46
#include "qwindowsnativeinterface.h"
47
#include "qwindowsopenglcontext.h"
49
# include "qwindowscursor.h"
52
#include <QtGui/QGuiApplication>
53
#include <QtGui/QScreen>
54
#include <QtGui/QWindow>
55
#include <QtGui/QRegion>
56
#include <QtGui/QOpenGLContext>
57
#include <private/qsystemlibrary_p.h>
58
#include <private/qwindow_p.h> // QWINDOWSIZE_MAX
59
#include <private/qguiapplication_p.h>
60
#include <private/qhighdpiscaling_p.h>
61
#include <qpa/qwindowsysteminterface.h>
63
#include <QtCore/QDebug>
68
defaultWindowWidth = 160,
69
defaultWindowHeight = 160
72
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
74
static QByteArray debugWinStyle(DWORD style)
77
rc += QByteArray::number(qulonglong(style), 16);
82
if (style & WS_OVERLAPPED)
83
rc += " WS_OVERLAPPED";
84
if (style & WS_CLIPSIBLINGS)
85
rc += " WS_CLIPSIBLINGS";
86
if (style & WS_CLIPCHILDREN)
87
rc += " WS_CLIPCHILDREN";
88
if (style & WS_THICKFRAME)
89
rc += " WS_THICKFRAME";
90
if (style & WS_DLGFRAME)
92
if (style & WS_SYSMENU)
94
if (style & WS_MINIMIZEBOX)
95
rc += " WS_MINIMIZEBOX";
96
if (style & WS_MAXIMIZEBOX)
97
rc += " WS_MAXIMIZEBOX";
101
static QByteArray debugWinExStyle(DWORD exStyle)
103
QByteArray rc = "0x";
104
rc += QByteArray::number(qulonglong(exStyle), 16);
105
if (exStyle & WS_EX_TOOLWINDOW)
106
rc += " WS_EX_TOOLWINDOW";
107
if (exStyle & WS_EX_CONTEXTHELP)
108
rc += " WS_EX_CONTEXTHELP";
109
if (exStyle & WS_EX_LAYERED)
110
rc += " WS_EX_LAYERED";
111
if (exStyle & WS_EX_DLGMODALFRAME)
112
rc += " WS_EX_DLGMODALFRAME";
116
static inline QSize qSizeOfRect(const RECT &rect)
118
return QSize(rect.right -rect.left, rect.bottom - rect.top);
121
static inline QRect qrectFromRECT(const RECT &rect)
123
return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect));
126
static inline RECT RECTfromQRect(const QRect &rect)
128
const int x = rect.left();
129
const int y = rect.top();
130
RECT result = { x, y, x + rect.width(), y + rect.height() };
134
#ifndef QT_NO_DEBUG_STREAM
135
QDebug operator<<(QDebug d, const RECT &r)
137
QDebugStateSaver saver(d);
139
d << "RECT: left/top=" << r.left << ',' << r.top
140
<< " right/bottom=" << r.right << ',' << r.bottom;
144
QDebug operator<<(QDebug d, const POINT &p)
146
d << p.x << ',' << p.y;
151
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
153
QDebugStateSaver saver(d);
155
d << "NCCALCSIZE_PARAMS " << qrectFromRECT(p.rgrc[0])
156
<< ' ' << qrectFromRECT(p.rgrc[1]) << ' ' << qrectFromRECT(p.rgrc[2]);
160
QDebug operator<<(QDebug d, const MINMAXINFO &i)
162
QDebugStateSaver saver(d);
164
d << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ','
165
<< i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x
166
<< ',' << i.ptMaxPosition.y << " mintrack="
167
<< i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y
168
<< " maxtrack=" << i.ptMaxTrackSize.x << ',' << i.ptMaxTrackSize.y;
172
QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp)
174
QDebugStateSaver saver(d);
176
d << "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd="
177
<< wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition
178
<< ", rcNormalPosition=" << wp.rcNormalPosition;
181
# endif // !Q_OS_WINCE
182
#endif // !QT_NO_DEBUG_STREAM
184
// QTBUG-43872, for windows that do not have WS_EX_TOOLWINDOW set, WINDOWPLACEMENT
185
// is in workspace/available area coordinates.
186
static QPoint windowPlacementOffset(HWND hwnd, const QPoint &point)
189
if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
191
const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager();
192
const QWindowsScreen *screen = screenManager.screens().size() == 1
193
? screenManager.screens().constFirst() : screenManager.screenAtDp(point);
195
return screen->availableGeometry().topLeft() - screen->geometry().topLeft();
203
// Return the frame geometry relative to the parent
205
static inline QRect frameGeometry(HWND hwnd, bool topLevel)
207
RECT rect = { 0, 0, 0, 0 };
210
WINDOWPLACEMENT windowPlacement;
211
windowPlacement.length = sizeof(WINDOWPLACEMENT);
212
GetWindowPlacement(hwnd, &windowPlacement);
213
if (windowPlacement.showCmd == SW_SHOWMINIMIZED) {
214
const QRect result = qrectFromRECT(windowPlacement.rcNormalPosition);
215
return result.translated(windowPlacementOffset(hwnd, result.topLeft()));
218
#endif // !Q_OS_WINCE
219
GetWindowRect(hwnd, &rect); // Screen coordinates.
220
const HWND parent = GetParent(hwnd);
221
if (parent && !topLevel) {
222
const int width = rect.right - rect.left;
223
const int height = rect.bottom - rect.top;
224
POINT leftTop = { rect.left, rect.top };
225
ScreenToClient(parent, &leftTop);
226
rect.left = leftTop.x;
227
rect.top = leftTop.y;
228
rect.right = leftTop.x + width;
229
rect.bottom = leftTop.y + height;
231
return qrectFromRECT(rect);
234
// Return the visibility of the Window (except full screen since it is not a window state).
235
static QWindow::Visibility windowVisibility_sys(HWND hwnd)
237
if (!IsWindowVisible(hwnd))
238
return QWindow::Hidden;
240
WINDOWPLACEMENT windowPlacement;
241
windowPlacement.length = sizeof(WINDOWPLACEMENT);
242
if (GetWindowPlacement(hwnd, &windowPlacement)) {
243
switch (windowPlacement.showCmd) {
244
case SW_SHOWMINIMIZED:
246
case SW_FORCEMINIMIZE:
247
return QWindow::Minimized;
248
case SW_SHOWMAXIMIZED:
249
return QWindow::Maximized;
254
#endif // !Q_OS_WINCE
255
return QWindow::Windowed;
258
static inline bool windowIsOpenGL(const QWindow *w)
260
switch (w->surfaceType()) {
261
case QSurface::OpenGLSurface:
263
case QSurface::RasterGLSurface:
264
return qt_window_private(const_cast<QWindow *>(w))->compositing;
270
static bool applyBlurBehindWindow(HWND hwnd)
276
enum { dwmBbEnable = 0x1, dwmBbBlurRegion = 0x2 };
278
struct DwmBlurBehind {
282
BOOL fTransitionOnMaximized;
285
typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND, const DwmBlurBehind*);
286
typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL *);
288
// DWM API is available only from Windows Vista
289
if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
292
static bool functionPointersResolved = false;
293
static PtrDwmEnableBlurBehindWindow dwmBlurBehind = 0;
294
static PtrDwmIsCompositionEnabled dwmIsCompositionEnabled = 0;
296
if (Q_UNLIKELY(!functionPointersResolved)) {
297
QSystemLibrary library(QStringLiteral("dwmapi"));
298
if (library.load()) {
299
dwmBlurBehind = (PtrDwmEnableBlurBehindWindow)(library.resolve("DwmEnableBlurBehindWindow"));
300
dwmIsCompositionEnabled = (PtrDwmIsCompositionEnabled)(library.resolve("DwmIsCompositionEnabled"));
303
functionPointersResolved = true;
306
if (Q_UNLIKELY(!dwmBlurBehind || !dwmIsCompositionEnabled))
309
BOOL compositionEnabled;
310
if (dwmIsCompositionEnabled(&compositionEnabled) != S_OK)
313
DwmBlurBehind blurBehind = {0, 0, 0, 0};
315
if (compositionEnabled) {
316
blurBehind.dwFlags = dwmBbEnable | dwmBbBlurRegion;
317
blurBehind.fEnable = TRUE;
318
blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
320
blurBehind.dwFlags = dwmBbEnable;
321
blurBehind.fEnable = FALSE;
324
const bool result = dwmBlurBehind(hwnd, &blurBehind) == S_OK;
326
if (blurBehind.hRgnBlur)
327
DeleteObject(blurBehind.hRgnBlur);
333
// from qwidget_win.cpp, pass flags separately in case they have been "autofixed".
334
static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags)
336
if ((flags & Qt::MSWindowsFixedSizeDialogHint) || !(flags & Qt::WindowMaximizeButtonHint))
338
// if the user explicitly asked for the maximize button, we try to add
339
// it even if the window has fixed size.
340
return (flags & Qt::CustomizeWindowHint) ||
341
w->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX);
344
// Set the WS_EX_LAYERED flag on a HWND if required. This is required for
345
// translucent backgrounds, not fully opaque windows and for
346
// Qt::WindowTransparentForInput (in combination with WS_EX_TRANSPARENT).
347
bool QWindowsWindow::setWindowLayered(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, qreal opacity)
349
#ifndef Q_OS_WINCE // maybe needs revisiting WS_EX_LAYERED
350
const LONG exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
351
const bool needsLayered = (flags & Qt::WindowTransparentForInput)
352
|| (hasAlpha && (flags & Qt::FramelessWindowHint)) || opacity < 1.0;
353
const bool isLayered = (exStyle & WS_EX_LAYERED);
354
if (needsLayered != isLayered) {
356
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
358
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
371
static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool openGL, qreal level)
373
#ifdef Q_OS_WINCE // WINCE does not support that feature and microsoft explicitly warns to use those calls
379
if (QWindowsWindow::setWindowLayered(hwnd, flags, hasAlpha, level)) {
380
const BYTE alpha = BYTE(qRound(255.0 * level));
381
if (hasAlpha && !openGL && (flags & Qt::FramelessWindowHint)) {
382
// Non-GL windows with alpha: Use blend function to update.
383
BLENDFUNCTION blend = {AC_SRC_OVER, 0, alpha, AC_SRC_ALPHA};
384
QWindowsContext::user32dll.updateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
386
QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
388
} else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered.
389
InvalidateRect(hwnd, NULL, TRUE);
391
#endif // !Q_OS_WINCE
394
static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::WindowFlags flags, qreal opacity)
396
const bool isGL = windowIsOpenGL(w);
397
const bool hasAlpha = w->format().hasAlpha();
399
if (isGL && hasAlpha)
400
applyBlurBehindWindow(hwnd);
402
setWindowOpacity(hwnd, flags, hasAlpha, isGL, opacity);
406
\class WindowCreationData
407
\brief Window creation code.
409
This struct gathers all information required to create a window.
410
Window creation is split in 3 steps:
413
\li fromWindow() Gather all required information
414
\li create() Create the system handle.
415
\li initialize() Post creation initialization steps.
418
The reason for this split is to also enable changing the QWindowFlags
422
\li fromWindow() Gather information and determine new system styles
423
\li applyWindowFlags() to apply the new window system styles.
424
\li initialize() Post creation initialization steps.
427
Contains the window creation code formerly in qwidget_win.cpp.
429
\sa QWindowCreationContext
431
\ingroup qt-lighthouse-win
434
struct WindowCreationData
436
typedef QWindowsWindowData WindowData;
437
enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 };
439
WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0),
440
topLevel(false), popup(false), dialog(false),
441
tool(false), embedded(false), hasAlpha(false) {}
443
void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0);
444
inline WindowData create(const QWindow *w, const WindowData &data, QString title) const;
445
inline void applyWindowFlags(HWND hwnd) const;
446
void initialize(const QWindow *w, HWND h, bool frameChange, qreal opacityLevel) const;
448
Qt::WindowFlags flags;
461
QDebug operator<<(QDebug debug, const WindowCreationData &d)
463
QDebugStateSaver saver(debug);
466
debug << "WindowCreationData: " << d.flags
467
<< "\n topLevel=" << d.topLevel;
469
debug << " parent=" << d.parentHandle;
470
debug << " popup=" << d.popup << " dialog=" << d.dialog
471
<< " embedded=" << d.embedded << " tool=" << d.tool
472
<< "\n style=" << debugWinStyle(d.style);
474
debug << "\n exStyle=" << debugWinExStyle(d.exStyle);
478
// Fix top level window flags in case only the type flags are passed.
479
static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
481
// Not supported on Windows, also do correction when it is set.
482
flags &= ~Qt::WindowFullscreenButtonHint;
485
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint
486
|Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
489
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint | Qt::WindowCloseButtonHint;
492
flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
497
if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
498
flags |= Qt::FramelessWindowHint;
501
void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
502
unsigned creationFlags)
506
// Sometimes QWindow doesn't have a QWindow parent but does have a native parent window,
507
// e.g. in case of embedded ActiveQt servers. They should not be considered a top-level
508
// windows in such cases.
509
QVariant prop = w->property("_q_embedded_native_parent_handle");
510
if (prop.isValid()) {
512
parentHandle = reinterpret_cast<HWND>(prop.value<WId>());
515
if (creationFlags & ForceChild) {
517
} else if (embedded) {
518
// Embedded native windows (for example Active X server windows) are by
519
// definition never toplevel, even though they do not have QWindow parents.
522
topLevel = (creationFlags & ForceTopLevel) ? true : w->isTopLevel();
526
fixTopLevelWindowFlags(flags);
528
type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask);
544
if ((flags & Qt::MSWindowsFixedSizeDialogHint))
547
// Parent: Use transient parent for top levels.
549
flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent.
550
} else if (!embedded) {
551
if (const QWindow *parentWindow = topLevel ? w->transientParent() : w->parent())
552
parentHandle = QWindowsWindow::handleOf(parentWindow);
555
if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
557
} else if (topLevel) {
558
if (flags & Qt::FramelessWindowHint)
559
style = WS_POPUP; // no border
560
else if (flags & Qt::WindowTitleHint)
561
style = WS_OVERLAPPED;
568
// if (!testAttribute(Qt::WA_PaintUnclipped))
569
// ### Commented out for now as it causes some problems, but
570
// this should be correct anyway, so dig some more into this
571
#ifdef Q_FLATTEN_EXPOSE
572
if (windowIsOpenGL(w)) // a bit incorrect since the is-opengl status may change from false to true at any time later on
573
style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat
575
style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
578
if ((type == Qt::Window || dialog || tool)) {
579
if (!(flags & Qt::FramelessWindowHint)) {
581
if (flags & Qt::MSWindowsFixedSizeDialogHint) {
582
style |= WS_DLGFRAME;
584
style |= WS_THICKFRAME;
586
if (flags & Qt::WindowTitleHint)
587
style |= WS_CAPTION; // Contains WS_DLGFRAME
589
if (flags & Qt::WindowSystemMenuHint)
591
else if (dialog && (flags & Qt::WindowCloseButtonHint) && !(flags & Qt::FramelessWindowHint)) {
592
style |= WS_SYSMENU | WS_BORDER; // QTBUG-2027, dialogs without system menu.
593
exStyle |= WS_EX_DLGMODALFRAME;
595
if (flags & Qt::WindowMinimizeButtonHint)
596
style |= WS_MINIMIZEBOX;
597
if (shouldShowMaximizeButton(w, flags))
598
style |= WS_MAXIMIZEBOX;
600
exStyle |= WS_EX_TOOLWINDOW;
601
if (flags & Qt::WindowContextHelpButtonHint)
602
exStyle |= WS_EX_CONTEXTHELP;
604
exStyle |= WS_EX_TOOLWINDOW;
608
// make mouse events fall through this window
609
// NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
610
if (flagsIn & Qt::WindowTransparentForInput)
611
exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
617
WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const
619
typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
622
result.flags = flags;
624
const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
626
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
628
const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight);
630
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
631
title = topLevel ? qAppName() : w->objectName();
633
const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
634
const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
636
// Capture events before CreateWindowEx() returns. The context is cleared in
637
// the QWindowsWindow constructor.
638
const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, data.customMargins, style, exStyle));
639
QWindowsContext::instance()->setWindowCreationContext(context);
641
qCDebug(lcQpaWindows).nospace()
642
<< "CreateWindowEx: " << w << " class=" << windowClassName << " title=" << title
643
<< '\n' << *this << "\nrequested: " << rect << ": "
644
<< context->frameWidth << 'x' << context->frameHeight
645
<< '+' << context->frameX << '+' << context->frameY
646
<< " custom margins: " << context->customMargins;
648
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
650
context->frameX, context->frameY,
651
context->frameWidth, context->frameHeight,
652
parentHandle, NULL, appinst, NULL);
654
if (DisableGestures(result.hwnd, TGF_GID_ALL, TGF_SCOPE_WINDOW))
655
EnableGestures(result.hwnd, TGF_GID_DIRECTMANIPULATION, TGF_SCOPE_WINDOW);
657
qCDebug(lcQpaWindows).nospace()
658
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
659
<< context->obtainedGeometry << ' ' << context->margins;
662
qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
666
result.geometry = context->obtainedGeometry;
667
result.frame = context->margins;
668
result.embedded = embedded;
669
result.customMargins = context->customMargins;
674
void WindowCreationData::applyWindowFlags(HWND hwnd) const
676
// Keep enabled and visible from the current style.
677
const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
678
const LONG_PTR oldExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
680
const LONG_PTR newStyle = style | (oldStyle & (WS_DISABLED|WS_VISIBLE));
681
if (oldStyle != newStyle)
682
SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
683
const LONG_PTR newExStyle = exStyle;
684
if (newExStyle != oldExStyle)
685
SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
686
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << hwnd << *this
687
<< "\n Style from " << debugWinStyle(DWORD(oldStyle)) << "\n to "
688
<< debugWinStyle(DWORD(newStyle)) << "\n ExStyle from "
689
<< debugWinExStyle(DWORD(oldExStyle)) << " to "
690
<< debugWinExStyle(DWORD(newExStyle));
693
void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChange, qreal opacityLevel) const
697
UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE;
699
swpFlags |= SWP_FRAMECHANGED;
701
swpFlags |= SWP_NOACTIVATE;
702
if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
703
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, swpFlags);
704
if (flags & Qt::WindowStaysOnBottomHint)
705
qWarning("QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time");
706
} else if (flags & Qt::WindowStaysOnBottomHint) {
707
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags);
708
} else if (frameChange) { // Force WM_NCCALCSIZE with wParam=1 in case of custom margins.
709
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, swpFlags);
711
if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
712
HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
713
if (flags & Qt::WindowCloseButtonHint)
714
EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
716
EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
718
updateGLWindowSettings(w, hwnd, flags, opacityLevel);
720
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags);
725
// Scaling helpers for size constraints.
726
static QSize toNativeSizeConstrained(QSize dip, const QWindow *w)
728
if (QHighDpiScaling::isActive()) {
729
const qreal factor = QHighDpiScaling::factor(w);
730
if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX)
731
dip.rwidth() *= factor;
732
if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX)
733
dip.rheight() *= factor;
739
\class QWindowsGeometryHint
740
\brief Stores geometry constraints and provides utility functions.
742
Geometry constraints ready to apply to a MINMAXINFO taking frame
746
\ingroup qt-lighthouse-win
749
QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) :
750
minimumSize(toNativeSizeConstrained(w->minimumSize(), w)),
751
maximumSize(toNativeSizeConstrained(w->maximumSize(), w)),
756
bool QWindowsGeometryHint::validSize(const QSize &s) const
758
const int width = s.width();
759
const int height = s.height();
760
return width >= minimumSize.width() && width <= maximumSize.width()
761
&& height >= minimumSize.height() && height <= maximumSize.height();
764
QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
766
RECT rect = {0,0,0,0};
768
style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
770
if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
771
qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
772
const QMargins result(qAbs(rect.left), qAbs(rect.top),
773
qAbs(rect.right), qAbs(rect.bottom));
774
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << " style="
775
<< showbase << hex << style << " exStyle=" << exStyle << dec << noshowbase
776
<< ' ' << rect << ' ' << result;
780
bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
783
// NCCALCSIZE_PARAMS structure if wParam==TRUE
784
if (!msg.wParam || customMargins.isNull())
786
*result = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
787
NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam);
788
const RECT oldClientArea = ncp->rgrc[0];
789
ncp->rgrc[0].left += customMargins.left();
790
ncp->rgrc[0].top += customMargins.top();
791
ncp->rgrc[0].right -= customMargins.right();
792
ncp->rgrc[0].bottom -= customMargins.bottom();
794
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->"
795
<< ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2]
796
<< ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy;
799
Q_UNUSED(customMargins)
807
void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
809
return applyToMinMaxInfo(DWORD(GetWindowLong(hwnd, GWL_STYLE)),
810
DWORD(GetWindowLong(hwnd, GWL_EXSTYLE)), mmi);
813
void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
815
qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min="
816
<< minimumSize.width() << ',' << minimumSize.height()
817
<< " max=" << maximumSize.width() << ',' << maximumSize.height()
820
const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
821
const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right();
822
const int frameHeight = margins.top() + margins.bottom() + customMargins.top() + customMargins.bottom();
823
if (minimumSize.width() > 0)
824
mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
825
if (minimumSize.height() > 0)
826
mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
828
const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
829
const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
830
if (maximumWidth < QWINDOWSIZE_MAX)
831
mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
832
if (maximumHeight < QWINDOWSIZE_MAX)
833
mmi->ptMaxTrackSize.y = maximumHeight + frameHeight;
834
qCDebug(lcQpaWindows).nospace() << '<' << __FUNCTION__
835
<< " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
838
#endif // !Q_OS_WINCE
840
bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
842
return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
843
== QWindowPrivate::WindowFrameInclusive;
847
\class QWindowsBaseWindow
848
\brief Base class for QWindowsForeignWindow, QWindowsWindow
850
The class provides some _sys() getters for querying window
851
data from a HWND and some _sys() setters.
853
Derived classes wrapping foreign windows may use them directly
854
to calculate geometry, margins, etc.
856
Derived classes representing windows created by Qt may defer
857
expensive calculations until change notifications are received.
861
\ingroup qt-lighthouse-win
864
QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w)
867
if (QPlatformWindow *pw = w->handle())
868
return static_cast<QWindowsBaseWindow *>(pw);
873
HWND QWindowsBaseWindow::handleOf(const QWindow *w)
875
const QWindowsBaseWindow *bw = QWindowsBaseWindow::baseWindowOf(w);
876
return bw ? bw->handle() : HWND(0);
879
bool QWindowsBaseWindow::isTopLevel_sys() const
881
const HWND parent = parentHwnd();
882
return !parent || parent == GetDesktopWindow();
885
QRect QWindowsBaseWindow::frameGeometry_sys() const
887
return frameGeometry(handle(), isTopLevel());
890
QRect QWindowsBaseWindow::geometry_sys() const
892
return frameGeometry_sys().marginsRemoved(frameMargins());
895
QMargins QWindowsBaseWindow::frameMargins_sys() const
897
return QWindowsGeometryHint::frame(style(), exStyle());
900
void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows.
902
SetWindowPos(handle(),0 , 0, 0, 0, 0,
903
SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
906
void QWindowsBaseWindow::raise_sys()
908
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
909
SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
912
void QWindowsBaseWindow::lower_sys()
914
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
915
SetWindowPos(handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
918
void QWindowsBaseWindow::setWindowTitle_sys(const QString &title)
920
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << title;
921
SetWindowText(handle(), reinterpret_cast<const wchar_t *>(title.utf16()));
924
QPoint QWindowsBaseWindow::mapToGlobal(const QPoint &pos) const
926
return QWindowsGeometryHint::mapToGlobal(handle(), pos);
929
QPoint QWindowsBaseWindow::mapFromGlobal(const QPoint &pos) const
931
return QWindowsGeometryHint::mapFromGlobal(handle(), pos);
935
\class QWindowsDesktopWindow
936
\brief Window wrapping GetDesktopWindow not allowing any manipulation.
939
\ingroup qt-lighthouse-win
943
\class QWindowsForeignWindow
944
\brief Window wrapping a foreign native window.
946
QWindowsForeignWindow stores a native HWND and implements getters for
947
geometry, margins, etc. reparenting and geometry manipulation for use as a
952
\ingroup qt-lighthouse-win
955
QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
956
: QWindowsBaseWindow(window)
962
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
964
const bool wasTopLevel = isTopLevel_sys();
965
const HWND newParent = newParentWindow ? reinterpret_cast<HWND>(newParentWindow->winId()) : HWND(0);
966
const bool isTopLevel = !newParent;
967
const DWORD oldStyle = style();
968
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << "newParent="
969
<< newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle);
970
SetParent(m_hwnd, newParent);
971
if (wasTopLevel != isTopLevel) { // Top level window flags need to be set/cleared manually.
972
DWORD newStyle = oldStyle;
974
newStyle = m_topLevelStyle;
976
m_topLevelStyle = oldStyle;
977
newStyle &= ~(WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW);
978
newStyle |= WS_CHILD;
980
SetWindowLongPtr(m_hwnd, GWL_STYLE, newStyle);
984
void QWindowsForeignWindow::setVisible(bool visible)
986
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << visible;
988
ShowWindow(handle(), SW_SHOWNOACTIVATE);
994
\class QWindowCreationContext
995
\brief Active Context for creating windows.
997
There is a phase in window creation (WindowCreationData::create())
998
in which events are sent before the system API CreateWindowEx() returns
999
the handle. These cannot be handled by the platform window as the association
1000
of the unknown handle value to the window does not exist yet and as not
1001
to trigger recursive handle creation, etc.
1003
In that phase, an instance of QWindowCreationContext is set on
1006
QWindowCreationContext stores the information to answer the initial
1007
WM_GETMINMAXINFO and obtains the corrected size/position.
1009
\sa WindowCreationData, QWindowsContext
1011
\ingroup qt-lighthouse-win
1014
QWindowCreationContext::QWindowCreationContext(const QWindow *w,
1015
const QRect &geometry,
1017
DWORD style_, DWORD exStyle_) :
1018
geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_),
1019
requestedGeometry(geometry), obtainedGeometry(geometry),
1020
margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm),
1021
frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
1022
frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
1024
// Geometry of toplevels does not consider window frames.
1025
// TODO: No concept of WA_wasMoved yet that would indicate a
1026
// CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
1028
if (geometry.isValid()) {
1029
frameX = geometry.x();
1030
frameY = geometry.y();
1031
const QMargins effectiveMargins = margins + customMargins;
1032
frameWidth = effectiveMargins.left() + geometry.width() + effectiveMargins.right();
1033
frameHeight = effectiveMargins.top() + geometry.height() + effectiveMargins.bottom();
1034
const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
1035
if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
1036
frameX -= effectiveMargins.left();
1037
frameY -= effectiveMargins.top();
1041
qCDebug(lcQpaWindows).nospace()
1042
<< __FUNCTION__ << ' ' << w << ' ' << geometry
1043
<< " pos incl. frame=" << QWindowsGeometryHint::positionIncludesFrame(w)
1044
<< " frame=" << frameWidth << 'x' << frameHeight << '+'
1045
<< frameX << '+' << frameY
1046
<< " min=" << geometryHint.minimumSize << " max=" << geometryHint.maximumSize
1047
<< " custom margins=" << customMargins;
1051
\class QWindowsWindow
1052
\brief Raster or OpenGL Window.
1055
\li Raster type: handleWmPaint() is implemented to
1056
to bitblt the image. The DC can be accessed
1057
via getDC/Relase DC, which has a special handling
1058
when within a paint event (in that case, the DC obtained
1059
from BeginPaint() is returned).
1061
\li Open GL: The first time QWindowsGLContext accesses
1062
the handle, it sets up the pixelformat on the DC
1063
which in turn sets it on the window (see flag
1064
PixelFormatInitialized).
1065
handleWmPaint() is empty (although required).
1069
\ingroup qt-lighthouse-win
1072
QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) :
1073
QWindowsBaseWindow(aWindow),
1075
m_flags(WithinCreate),
1077
m_windowState(Qt::WindowNoState),
1079
m_cursor(new CursorHandle),
1082
m_format(aWindow->requestedFormat()),
1084
m_previouslyHidden(false),
1090
// Clear the creation context as the window can be found in QWindowsContext's map.
1091
QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>());
1092
QWindowsContext::instance()->addWindow(m_data.hwnd, this);
1093
const Qt::WindowType type = aWindow->type();
1094
if (type == Qt::Desktop)
1095
return; // No further handling for Qt::Desktop
1096
#ifndef QT_NO_OPENGL
1097
if (aWindow->surfaceType() == QWindow::OpenGLSurface) {
1098
if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL)
1099
setFlag(OpenGLSurface);
1101
setFlag(OpenGL_ES2);
1103
#endif // QT_NO_OPENGL
1104
updateDropSite(window()->isTopLevel());
1106
registerTouchWindow();
1107
setWindowState(aWindow->windowState());
1108
const qreal opacity = qt_window_private(aWindow)->opacity;
1109
if (!qFuzzyCompare(opacity, qreal(1.0)))
1110
setOpacity(opacity);
1111
if (aWindow->isTopLevel())
1112
setWindowIcon(aWindow->icon());
1113
clearFlag(WithinCreate);
1116
QWindowsWindow::~QWindowsWindow()
1118
setFlag(WithinDestroy);
1120
if (testFlag(TouchRegistered))
1121
QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd);
1122
#endif // !Q_OS_WINCE
1127
void QWindowsWindow::fireExpose(const QRegion ®ion, bool force)
1129
if (region.isEmpty() && !force)
1133
QWindowSystemInterface::handleExposeEvent(window(), region);
1136
static inline QWindow *findTransientChild(const QWindow *parent)
1138
foreach (QWindow *w, QGuiApplication::topLevelWindows())
1139
if (w->transientParent() == parent)
1144
void QWindowsWindow::destroyWindow()
1146
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << m_data.hwnd;
1147
if (m_data.hwnd) { // Stop event dispatching before Window is destroyed.
1148
setFlag(WithinDestroy);
1149
// Clear any transient child relationships as Windows will otherwise destroy them (QTBUG-35499, QTBUG-36666)
1150
if (QWindow *transientChild = findTransientChild(window()))
1151
if (QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(transientChild))
1152
tw->updateTransientParent();
1153
QWindowsContext *context = QWindowsContext::instance();
1154
if (context->windowUnderMouse() == window())
1155
context->clearWindowUnderMouse();
1156
if (hasMouseCapture())
1157
setMouseGrabEnabled(false);
1158
setDropSiteEnabled(false);
1159
#ifndef QT_NO_OPENGL
1161
if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
1162
staticOpenGLContext->destroyWindowSurface(m_surface);
1167
if ((m_windowState & Qt::WindowFullScreen) && !m_previouslyHidden) {
1168
HWND handle = FindWindow(L"HHTaskBar", L"");
1170
ShowWindow(handle, SW_SHOW);
1173
#endif // !Q_OS_WINCE
1174
DestroyWindow(m_data.hwnd);
1175
context->removeWindow(m_data.hwnd);
1180
void QWindowsWindow::updateDropSite(bool topLevel)
1182
bool enabled = false;
1183
bool parentIsEmbedded = false;
1186
// if the parent window is a foreign window wrapped via QWindow::fromWinId, we need to enable the drop site
1187
// on the first child window
1188
const QWindow *parent = window()->parent();
1189
if (parent && (parent->type() == Qt::ForeignWindow))
1190
parentIsEmbedded = true;
1193
if (topLevel || parentIsEmbedded) {
1194
switch (window()->type()) {
1207
setDropSiteEnabled(enabled);
1210
void QWindowsWindow::setDropSiteEnabled(bool dropEnabled)
1212
if (isDropSiteEnabled() == dropEnabled)
1214
qCDebug(lcQpaMime) << __FUNCTION__ << window() << dropEnabled;
1215
#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_DRAGANDDROP)
1217
Q_ASSERT(m_data.hwnd);
1218
m_dropTarget = new QWindowsOleDropTarget(window());
1219
RegisterDragDrop(m_data.hwnd, m_dropTarget);
1220
CoLockObjectExternal(m_dropTarget, true, true);
1222
CoLockObjectExternal(m_dropTarget, false, true);
1223
m_dropTarget->Release();
1224
RevokeDragDrop(m_data.hwnd);
1227
#endif // !QT_NO_CLIPBOARD && !QT_NO_DRAGANDDROP
1230
// Returns topmost QWindowsWindow ancestor even if there are embedded windows in the chain.
1231
// Returns this window if it is the topmost ancestor.
1232
QWindow *QWindowsWindow::topLevelOf(QWindow *w)
1234
while (QWindow *parent = w->parent())
1237
if (const QPlatformWindow *handle = w->handle()) {
1238
const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(handle);
1239
if (ww->isEmbedded()) {
1240
HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT);
1241
const HWND desktopHwnd = GetDesktopWindow();
1242
const QWindowsContext *ctx = QWindowsContext::instance();
1243
while (parentHWND && parentHWND != desktopHwnd) {
1244
if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND))
1245
return topLevelOf(ancestor->window());
1246
parentHWND = GetAncestor(parentHWND, GA_PARENT);
1254
QWindowsWindowData::create(const QWindow *w,
1255
const QWindowsWindowData ¶meters,
1256
const QString &title)
1258
WindowCreationData creationData;
1259
creationData.fromWindow(w, parameters.flags);
1260
QWindowsWindowData result = creationData.create(w, parameters, title);
1261
// Force WM_NCCALCSIZE (with wParam=1) via SWP_FRAMECHANGED for custom margin.
1262
creationData.initialize(w, result.hwnd, !parameters.customMargins.isNull(), 1);
1266
void QWindowsWindow::setVisible(bool visible)
1268
const QWindow *win = window();
1269
qCDebug(lcQpaWindows) << __FUNCTION__ << this << win << m_data.hwnd << visible;
1274
// When the window is layered, we won't get WM_PAINT, and "we" are in control
1275
// over the rendering of the window
1276
// There is nobody waiting for this, so we don't need to flush afterwards.
1278
fireExpose(QRect(0, 0, win->width(), win->height()));
1279
// QTBUG-44928, QTBUG-7386: This is to resolve the problem where popups are
1280
// opened from the system tray and not being implicitly activated
1282
if (win->type() == Qt::Popup && !win->parent() && !QGuiApplication::focusWindow())
1283
SetForegroundWindow(m_data.hwnd);
1285
if (hasMouseCapture())
1286
setMouseGrabEnabled(false);
1287
if (window()->flags() & Qt::Popup) // from QWidgetPrivate::hide_sys(), activate other
1288
ShowWindow(m_data.hwnd, SW_HIDE);
1291
fireExpose(QRegion());
1296
bool QWindowsWindow::isVisible() const
1298
return m_data.hwnd && IsWindowVisible(m_data.hwnd);
1301
bool QWindowsWindow::isActive() const
1303
// Check for native windows or children of the active native window.
1304
if (const HWND activeHwnd = GetForegroundWindow())
1305
if (m_data.hwnd == activeHwnd || IsChild(activeHwnd, m_data.hwnd))
1310
bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const
1313
const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(parentWindow);
1314
const HWND hwnd = ww->handle();
1315
if (!IsChild(hwnd, m_data.hwnd))
1319
if (!m_data.embedded && parent())
1320
return parent()->isEmbedded();
1322
return m_data.embedded;
1325
QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
1328
return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos);
1333
QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
1336
return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos);
1342
static inline HWND transientParentHwnd(HWND hwnd)
1344
if (GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow()) {
1345
const HWND rootOwnerHwnd = GetAncestor(hwnd, GA_ROOTOWNER);
1346
if (rootOwnerHwnd != hwnd) // May return itself for toplevels.
1347
return rootOwnerHwnd;
1351
#endif // !Q_OS_WINCE
1353
// Update the transient parent for a toplevel window. The concept does not
1354
// really exist on Windows, the relationship is set by passing a parent along with !WS_CHILD
1355
// to window creation or by setting the parent using GWL_HWNDPARENT (as opposed to
1356
// SetParent, which would make it a real child).
1357
void QWindowsWindow::updateTransientParent() const
1360
if (window()->type() == Qt::Popup)
1361
return; // QTBUG-34503, // a popup stays on top, no parent, see also WindowCreationData::fromWindow().
1362
// Update transient parent.
1363
const HWND oldTransientParent = transientParentHwnd(m_data.hwnd);
1364
HWND newTransientParent = 0;
1365
if (const QWindow *tp = window()->transientParent())
1366
if (const QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(tp))
1367
if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666)
1368
newTransientParent = tw->handle();
1369
if (newTransientParent != oldTransientParent)
1370
SetWindowLongPtr(m_data.hwnd, GWL_HWNDPARENT, LONG_PTR(newTransientParent));
1371
#endif // !Q_OS_WINCE
1374
static inline bool testShowWithoutActivating(const QWindow *window)
1376
// QWidget-attribute Qt::WA_ShowWithoutActivating .
1377
const QVariant showWithoutActivating = window->property("_q_showWithoutActivating");
1378
return showWithoutActivating.isValid() && showWithoutActivating.toBool();
1381
// partially from QWidgetPrivate::show_sys()
1382
void QWindowsWindow::show_sys() const
1384
int sm = SW_SHOWNORMAL;
1385
bool fakedMaximize = false;
1386
const QWindow *w = window();
1387
const Qt::WindowFlags flags = w->flags();
1388
const Qt::WindowType type = w->type();
1389
if (w->isTopLevel()) {
1390
const Qt::WindowState state = w->windowState();
1391
if (state & Qt::WindowMinimized) {
1392
sm = SW_SHOWMINIMIZED;
1394
sm = SW_SHOWMINNOACTIVE;
1396
updateTransientParent();
1397
if (state & Qt::WindowMaximized) {
1398
sm = SW_SHOWMAXIMIZED;
1399
// Windows will not behave correctly when we try to maximize a window which does not
1400
// have minimize nor maximize buttons in the window frame. Windows would then ignore
1401
// non-available geometry, and rather maximize the widget to the full screen, minus the
1402
// window frame (caption). So, we do a trick here, by adding a maximize button before
1403
// maximizing the widget, and then remove the maximize button afterwards.
1404
if (flags & Qt::WindowTitleHint &&
1405
!(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
1406
fakedMaximize = TRUE;
1407
setStyle(style() | WS_MAXIMIZEBOX);
1409
} // Qt::WindowMaximized
1410
} // !Qt::WindowMinimized
1412
if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool || testShowWithoutActivating(w))
1413
sm = SW_SHOWNOACTIVATE;
1415
if (w->windowState() & Qt::WindowMaximized)
1416
setFlag(WithinMaximize); // QTBUG-8361
1418
ShowWindow(m_data.hwnd, sm);
1420
clearFlag(WithinMaximize);
1422
if (fakedMaximize) {
1423
setStyle(style() & ~WS_MAXIMIZEBOX);
1424
SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0,
1425
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
1426
| SWP_FRAMECHANGED);
1430
void QWindowsWindow::setParent(const QPlatformWindow *newParent)
1432
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << newParent;
1435
setParent_sys(newParent);
1438
void QWindowsWindow::setParent_sys(const QPlatformWindow *parent)
1440
// Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels
1441
HWND oldParentHWND = parentHwnd();
1442
HWND newParentHWND = 0;
1444
const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
1445
newParentHWND = parentW->handle();
1449
// NULL handle means desktop window, which also has its proper handle -> disambiguate
1450
HWND desktopHwnd = GetDesktopWindow();
1451
if (oldParentHWND == desktopHwnd)
1453
if (newParentHWND == desktopHwnd)
1456
if (newParentHWND != oldParentHWND) {
1457
const bool wasTopLevel = oldParentHWND == 0;
1458
const bool isTopLevel = newParentHWND == 0;
1460
setFlag(WithinSetParent);
1461
SetParent(m_data.hwnd, newParentHWND);
1462
clearFlag(WithinSetParent);
1464
// WS_CHILD/WS_POPUP must be manually set/cleared in addition
1465
// to dialog frames, etc (see SetParent() ) if the top level state changes.
1466
// Force toplevel state as QWindow::isTopLevel cannot be relied upon here.
1467
if (wasTopLevel != isTopLevel) {
1468
setDropSiteEnabled(false);
1469
setWindowFlags_sys(window()->flags(), unsigned(isTopLevel ? WindowCreationData::ForceTopLevel : WindowCreationData::ForceChild));
1470
updateDropSite(isTopLevel);
1475
void QWindowsWindow::handleHidden()
1477
fireExpose(QRegion());
1480
void QWindowsWindow::handleCompositionSettingsChanged()
1482
const QWindow *w = window();
1483
if (w->surfaceType() == QWindow::OpenGLSurface && w->format().hasAlpha())
1484
applyBlurBehindWindow(handle());
1487
static QRect normalFrameGeometry(HWND hwnd)
1491
wp.length = sizeof(WINDOWPLACEMENT);
1492
if (GetWindowPlacement(hwnd, &wp)) {
1493
const QRect result = qrectFromRECT(wp.rcNormalPosition);
1494
return result.translated(windowPlacementOffset(hwnd, result.topLeft()));
1502
QRect QWindowsWindow::normalGeometry() const
1504
// Check for fake 'fullscreen' mode.
1505
const bool fakeFullScreen = m_savedFrameGeometry.isValid() && window()->windowState() == Qt::WindowFullScreen;
1506
const QRect frame = fakeFullScreen ? m_savedFrameGeometry : normalFrameGeometry(m_data.hwnd);
1507
const QMargins margins = fakeFullScreen ? QWindowsGeometryHint::frame(m_savedStyle, 0) : frameMargins();
1508
return frame.isValid() ? frame.marginsRemoved(margins) : frame;
1511
void QWindowsWindow::setGeometry(const QRect &rectIn)
1513
QRect rect = rectIn;
1514
// This means it is a call from QWindow::setFramePosition() and
1515
// the coordinates include the frame (size is still the contents rectangle).
1516
if (QWindowsGeometryHint::positionIncludesFrame(window())) {
1517
const QMargins margins = frameMargins();
1518
rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
1520
if (m_windowState == Qt::WindowMinimized)
1521
m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event.
1523
// A ResizeEvent with resulting geometry will be sent. If we cannot
1524
// achieve that size (for example, window title minimal constraint),
1526
setGeometry_sys(rect);
1527
if (m_data.geometry != rect) {
1528
qWarning("%s: Unable to set geometry %dx%d+%d+%d on %s/'%s'."
1529
" Resulting geometry: %dx%d+%d+%d "
1530
"(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d"
1531
", minimum size: %dx%d, maximum size: %dx%d).",
1533
rect.width(), rect.height(), rect.x(), rect.y(),
1534
window()->metaObject()->className(), qPrintable(window()->objectName()),
1535
m_data.geometry.width(), m_data.geometry.height(),
1536
m_data.geometry.x(), m_data.geometry.y(),
1537
m_data.frame.left(), m_data.frame.top(),
1538
m_data.frame.right(), m_data.frame.bottom(),
1539
m_data.customMargins.left(), m_data.customMargins.top(),
1540
m_data.customMargins.right(), m_data.customMargins.bottom(),
1541
window()->minimumWidth(), window()->minimumHeight(),
1542
window()->maximumWidth(), window()->maximumHeight());
1545
QPlatformWindow::setGeometry(rect);
1549
void QWindowsWindow::handleMoved()
1551
// Minimize/Set parent can send nonsensical move events.
1552
if (!IsIconic(m_data.hwnd) && !testFlag(WithinSetParent))
1553
handleGeometryChange();
1556
void QWindowsWindow::handleResized(int wParam)
1559
case SIZE_MAXHIDE: // Some other window affected.
1562
case SIZE_MINIMIZED:
1563
handleWindowStateChange(Qt::WindowMinimized);
1565
case SIZE_MAXIMIZED:
1566
handleWindowStateChange(Qt::WindowMaximized);
1567
handleGeometryChange();
1570
if (isFullScreen_sys())
1571
handleWindowStateChange(Qt::WindowFullScreen);
1572
else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen))
1573
handleWindowStateChange(Qt::WindowNoState);
1574
handleGeometryChange();
1579
void QWindowsWindow::handleGeometryChange()
1581
//Prevent recursive resizes for Windows CE
1582
if (testFlag(WithinSetStyle))
1584
const QRect previousGeometry = m_data.geometry;
1585
m_data.geometry = geometry_sys();
1586
QPlatformWindow::setGeometry(m_data.geometry);
1587
QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
1588
// QTBUG-32121: OpenGL/normal windows (with exception of ANGLE) do not receive
1589
// expose events when shrinking, synthesize.
1590
if (!testFlag(OpenGL_ES2) && isExposed()
1591
&& m_data.geometry.size() != previousGeometry.size() // Exclude plain move
1592
// One dimension grew -> Windows will send expose, no need to synthesize.
1593
&& !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) {
1594
fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true);
1596
if (previousGeometry.topLeft() != m_data.geometry.topLeft()) {
1597
QPlatformScreen *newScreen = screenForGeometry(m_data.geometry);
1598
if (newScreen != screen())
1599
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen());
1601
if (testFlag(SynchronousGeometryChangeEvent))
1602
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
1604
qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry;
1607
void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
1609
const QMargins margins = frameMargins();
1610
const QRect frameGeometry = rect + margins;
1612
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window()
1613
<< "\n from " << geometry_sys() << " frame: "
1614
<< margins << " to " <<rect
1615
<< " new frame: " << frameGeometry;
1617
bool result = false;
1619
const HWND hwnd = handle();
1620
WINDOWPLACEMENT windowPlacement;
1621
windowPlacement.length = sizeof(WINDOWPLACEMENT);
1622
GetWindowPlacement(hwnd, &windowPlacement);
1623
// If the window is hidden and in maximized state or minimized, instead of moving the
1624
// window, set the normal position of the window.
1625
if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(hwnd))
1626
|| windowPlacement.showCmd == SW_SHOWMINIMIZED) {
1627
windowPlacement.rcNormalPosition =
1628
RECTfromQRect(frameGeometry.translated(-windowPlacementOffset(hwnd, frameGeometry.topLeft())));
1629
windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE;
1630
result = SetWindowPlacement(hwnd, &windowPlacement);
1632
#endif // !Q_OS_WINCE
1634
result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(),
1635
frameGeometry.width(), frameGeometry.height(), true);
1637
qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window()
1638
<< "\n resulting " << result << geometry_sys();
1642
Allocates a HDC for the window or returns the temporary one
1643
obtained from WinAPI BeginPaint within a WM_PAINT event.
1648
HDC QWindowsWindow::getDC()
1651
m_hdc = GetDC(handle());
1656
Relases the HDC for the window or does nothing in
1657
case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
1662
void QWindowsWindow::releaseDC()
1665
ReleaseDC(handle(), m_hdc);
1670
bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
1673
if (message == WM_ERASEBKGND) // Backing store - ignored.
1675
// Ignore invalid update bounding rectangles
1676
if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
1680
BeginPaint(hwnd, &ps);
1682
// Observed painting problems with Aero style disabled (QTBUG-7865).
1683
// 5.8: Consider making it dependent on !DwmIsCompositionEnabled().
1684
if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered))
1685
SelectClipRgn(ps.hdc, NULL);
1687
// If the a window is obscured by another window (such as a child window)
1688
// we still need to send isExposed=true, for compatibility.
1689
// Our tests depend on it.
1690
fireExpose(QRegion(qrectFromRECT(ps.rcPaint)), true);
1691
if (!QWindowsContext::instance()->asyncExpose())
1692
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
1694
EndPaint(hwnd, &ps);
1698
void QWindowsWindow::setWindowTitle(const QString &title)
1700
setWindowTitle_sys(QWindowsWindow::formatWindowTitle(title));
1703
void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
1705
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window() << "\n from: "
1706
<< m_data.flags << "\n to: " << flags;
1707
const QRect oldGeometry = geometry();
1708
if (m_data.flags != flags) {
1709
m_data.flags = flags;
1711
m_data = setWindowFlags_sys(flags);
1712
updateDropSite(window()->isTopLevel());
1715
// When switching to a frameless window, geometry
1716
// may change without a WM_MOVE. Report change manually.
1717
// Do not send synchronously as not to clobber the widget
1718
// geometry in a sequence of setting flags and geometry.
1719
const QRect newGeometry = geometry_sys();
1720
if (oldGeometry != newGeometry)
1721
handleGeometryChange();
1723
qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << "\n returns: "
1724
<< m_data.flags << " geometry " << oldGeometry << "->" << newGeometry;
1727
QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
1728
unsigned flags) const
1730
WindowCreationData creationData;
1731
creationData.fromWindow(window(), wt, flags);
1732
creationData.applyWindowFlags(m_data.hwnd);
1733
creationData.initialize(window(), m_data.hwnd, true, m_opacity);
1735
QWindowsWindowData result = m_data;
1736
result.flags = creationData.flags;
1737
result.embedded = creationData.embedded;
1738
setFlag(FrameDirty);
1742
void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
1744
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window()
1745
<< "\n from " << m_windowState << " to " << state;
1746
setFlag(FrameDirty);
1747
m_windowState = state;
1748
QWindowSystemInterface::handleWindowStateChanged(window(), state);
1750
case Qt::WindowMinimized:
1752
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now.
1754
case Qt::WindowMaximized:
1755
case Qt::WindowFullScreen:
1756
case Qt::WindowNoState: {
1757
// QTBUG-17548: We send expose events when receiving WM_Paint, but for
1758
// layered windows and transient children, we won't receive any WM_Paint.
1759
QWindow *w = window();
1760
bool exposeEventsSent = false;
1762
fireExpose(QRegion(0, 0, w->width(), w->height()));
1763
exposeEventsSent = true;
1765
foreach (QWindow *child, QGuiApplication::allWindows()) {
1766
if (child != w && child->isVisible() && child->transientParent() == w) {
1767
QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child);
1768
if (platformWindow && platformWindow->isLayered()) {
1769
platformWindow->fireExpose(QRegion(0, 0, child->width(), child->height()));
1770
exposeEventsSent = true;
1774
if (exposeEventsSent && !QWindowsContext::instance()->asyncExpose())
1775
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
1783
void QWindowsWindow::setWindowState(Qt::WindowState state)
1786
setWindowState_sys(state);
1787
m_windowState = state;
1791
bool QWindowsWindow::isFullScreen_sys() const
1793
const QWindow *w = window();
1794
if (!w->isTopLevel())
1796
const QScreen *screen = w->screen();
1798
screen = QGuiApplication::primaryScreen();
1799
return screen && geometry_sys() == QHighDpi::toNativePixels(screen->geometry(), w);
1803
\brief Change the window state.
1805
\note Window frames change when maximized;
1806
the top margin shrinks somewhat but that cannot be obtained using
1807
AdjustWindowRectEx().
1809
\note Some calls to SetWindowLong require a subsequent call
1813
void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
1815
const Qt::WindowState oldState = m_windowState;
1816
if (oldState == newState)
1818
qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window()
1819
<< " from " << oldState << " to " << newState;
1821
const bool visible = isVisible();
1823
setFlag(FrameDirty);
1825
if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
1827
HWND handle = FindWindow(L"HHTaskBar", L"");
1829
if (newState == Qt::WindowFullScreen) {
1830
BOOL hidden = ShowWindow(handle, SW_HIDE);
1832
m_previouslyHidden = true;
1833
} else if (!m_previouslyHidden){
1834
ShowWindow(handle, SW_SHOW);
1838
if (newState == Qt::WindowFullScreen) {
1839
#ifndef Q_FLATTEN_EXPOSE
1840
UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
1842
UINT newStyle = WS_POPUP;
1844
// Save geometry and style to be restored when fullscreen
1845
// is turned off again, since on Windows, it is not a real
1846
// Window state but emulated by changing geometry and style.
1847
if (!m_savedStyle) {
1848
m_savedStyle = style();
1850
if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) {
1851
const QRect nf = normalFrameGeometry(m_data.hwnd);
1853
m_savedFrameGeometry = nf;
1856
m_savedFrameGeometry = frameGeometry_sys();
1861
if (m_savedStyle & WS_SYSMENU)
1862
newStyle |= WS_SYSMENU;
1864
newStyle |= WS_VISIBLE;
1865
if (testFlag(HasBorderInFullScreen))
1866
newStyle |= WS_BORDER;
1868
// Use geometry of QWindow::screen() within creation or the virtual screen the
1869
// window is in (QTBUG-31166, QTBUG-30724).
1870
const QScreen *screen = window()->screen();
1872
screen = QGuiApplication::primaryScreen();
1873
const QRect r = screen ? QHighDpi::toNativePixels(screen->geometry(), window()) : m_savedFrameGeometry;
1874
const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
1875
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
1876
setFlag(SynchronousGeometryChangeEvent);
1877
SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
1879
clearFlag(SynchronousGeometryChangeEvent);
1880
QWindowSystemInterface::handleGeometryChange(window(), r);
1881
QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
1882
} else if (newState != Qt::WindowMinimized) {
1883
// Restore saved state.
1884
unsigned newStyle = m_savedStyle ? m_savedStyle : style();
1886
newStyle |= WS_VISIBLE;
1889
UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
1890
if (!m_savedFrameGeometry.isValid())
1891
swpf |= SWP_NOSIZE | SWP_NOMOVE;
1892
const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
1893
setFlag(SynchronousGeometryChangeEvent);
1894
// After maximized/fullscreen; the window can be in a maximized state. Clear
1895
// it before applying the normal geometry.
1896
if (windowVisibility_sys(m_data.hwnd) == QWindow::Maximized)
1897
ShowWindow(m_data.hwnd, SW_SHOWNOACTIVATE);
1898
SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(),
1899
m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf);
1901
clearFlag(SynchronousGeometryChangeEvent);
1902
// preserve maximized state
1904
setFlag(WithinMaximize);
1905
ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA);
1906
clearFlag(WithinMaximize);
1909
m_savedFrameGeometry = QRect();
1911
} else if ((oldState == Qt::WindowMaximized) != (newState == Qt::WindowMaximized)) {
1912
if (visible && !(newState == Qt::WindowMinimized)) {
1913
setFlag(WithinMaximize);
1914
if (newState == Qt::WindowFullScreen)
1915
setFlag(MaximizeToFullScreen);
1916
ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1917
clearFlag(WithinMaximize);
1918
clearFlag(MaximizeToFullScreen);
1922
if ((oldState == Qt::WindowMinimized) != (newState == Qt::WindowMinimized)) {
1924
ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE :
1925
(newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNORMAL);
1927
qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() << newState;
1930
void QWindowsWindow::setStyle(unsigned s) const
1932
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s);
1933
setFlag(WithinSetStyle);
1934
setFlag(FrameDirty);
1935
SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
1936
clearFlag(WithinSetStyle);
1939
void QWindowsWindow::setExStyle(unsigned s) const
1941
qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
1942
<< " 0x" << QByteArray::number(s, 16);
1943
setFlag(FrameDirty);
1944
SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
1947
void QWindowsWindow::windowEvent(QEvent *event)
1949
switch (event->type()) {
1950
case QEvent::WindowBlocked: // Blocked by another modal window.
1952
setFlag(BlockedByModal);
1953
if (hasMouseCapture())
1956
case QEvent::WindowUnblocked:
1958
clearFlag(BlockedByModal);
1965
void QWindowsWindow::propagateSizeHints()
1967
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
1970
bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins)
1973
if (!qWindow->isTopLevel()) // Implement hasHeightForWidth().
1975
WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam);
1976
if ((windowPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE)))
1978
const QRect suggestedFrameGeometry(windowPos->x, windowPos->y,
1979
windowPos->cx, windowPos->cy);
1980
const QRect suggestedGeometry = suggestedFrameGeometry - margins;
1981
const QRectF correctedGeometryF = QPlatformWindow::closestAcceptableGeometry(qWindow, suggestedGeometry);
1982
if (!correctedGeometryF.isValid())
1984
const QRect correctedFrameGeometry = correctedGeometryF.toRect() + margins;
1985
if (correctedFrameGeometry == suggestedFrameGeometry)
1987
windowPos->x = correctedFrameGeometry.left();
1988
windowPos->y = correctedFrameGeometry.top();
1989
windowPos->cx = correctedFrameGeometry.width();
1990
windowPos->cy = correctedFrameGeometry.height();
1992
#else // !Q_OS_WINCE
1998
bool QWindowsWindow::handleGeometryChanging(MSG *message) const
2000
const QMargins margins = window()->isTopLevel() ? frameMargins() : QMargins();
2001
return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins);
2004
QMargins QWindowsWindow::frameMargins() const
2006
// Frames are invalidated by style changes (window state, flags).
2007
// As they are also required for geometry calculations in resize
2008
// event sequences, introduce a dirty flag mechanism to be able
2009
// to cache results.
2010
if (testFlag(FrameDirty)) {
2011
// Always skip calculating style-dependent margins for windows claimed to be frameless.
2012
// This allows users to remove the margins by handling WM_NCCALCSIZE with WS_THICKFRAME set
2013
// to ensure Areo snap still works (QTBUG-40578).
2014
m_data.frame = m_data.flags & Qt::FramelessWindowHint
2015
? QMargins(0, 0, 0, 0)
2016
: QWindowsGeometryHint::frame(style(), exStyle());
2017
clearFlag(FrameDirty);
2019
return m_data.frame + m_data.customMargins;
2022
void QWindowsWindow::setOpacity(qreal level)
2024
qCDebug(lcQpaWindows) << __FUNCTION__ << level;
2025
if (!qFuzzyCompare(m_opacity, level)) {
2028
setWindowOpacity(m_data.hwnd, m_data.flags,
2029
window()->format().hasAlpha(), testFlag(OpenGLSurface),
2034
static inline HRGN createRectRegion(const QRect &r)
2036
return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
2039
static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
2041
if (const HRGN rectRegion = createRectRegion(rect)) {
2042
HRGN result = CreateRectRgn(0, 0, 0, 0);
2043
if (CombineRgn(result, *winRegion, rectRegion, RGN_OR)) {
2044
DeleteObject(*winRegion);
2045
*winRegion = result;
2047
DeleteObject(rectRegion);
2051
static HRGN qRegionToWinRegion(const QRegion ®ion)
2053
const QVector<QRect> rects = region.rects();
2054
if (rects.isEmpty())
2056
const int rectCount = rects.size();
2058
return createRectRegion(region.boundingRect());
2059
HRGN hRegion = createRectRegion(rects.front());
2060
for (int i = 1; i < rectCount; ++i)
2061
addRectToWinRegion(rects.at(i), &hRegion);
2065
void QWindowsWindow::setMask(const QRegion ®ion)
2067
if (region.isEmpty()) {
2068
SetWindowRgn(m_data.hwnd, 0, true);
2071
const HRGN winRegion = qRegionToWinRegion(region);
2073
// Mask is in client area coordinates, so offset it in case we have a frame
2074
if (window()->isTopLevel()) {
2075
const QMargins margins = frameMargins();
2076
OffsetRgn(winRegion, margins.left(), margins.top());
2079
// SetWindowRgn takes ownership.
2080
if (!SetWindowRgn(m_data.hwnd, winRegion, true))
2081
DeleteObject(winRegion);
2084
void QWindowsWindow::requestActivateWindow()
2086
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
2087
// 'Active' state handling is based in focus since it needs to work for
2088
// child windows as well.
2091
const DWORD currentThread = GetCurrentThreadId();
2092
bool attached = false;
2093
DWORD foregroundThread = 0;
2095
// QTBUG-14062, QTBUG-37435: Windows normally only flashes the taskbar entry
2096
// when activating windows of inactive applications. Attach to the input of the
2097
// currently active window while setting the foreground window to always activate
2098
// the window when desired.
2099
if (QGuiApplication::applicationState() != Qt::ApplicationActive
2100
&& QWindowsNativeInterface::windowActivationBehavior() == QWindowsWindowFunctions::AlwaysActivateWindow) {
2101
if (const HWND foregroundWindow = GetForegroundWindow()) {
2102
foregroundThread = GetWindowThreadProcessId(foregroundWindow, NULL);
2103
if (foregroundThread && foregroundThread != currentThread)
2104
attached = AttachThreadInput(foregroundThread, currentThread, TRUE) == TRUE;
2107
#endif // !Q_OS_WINCE
2108
SetForegroundWindow(m_data.hwnd);
2109
SetFocus(m_data.hwnd);
2112
AttachThreadInput(foregroundThread, currentThread, FALSE);
2113
#endif // !Q_OS_WINCE
2117
bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
2120
qWarning("%s: No handle", __FUNCTION__);
2123
qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << grab;
2125
QWindowsContext *context = QWindowsContext::instance();
2127
context->setKeyGrabber(window());
2129
if (context->keyGrabber() == window())
2130
context->setKeyGrabber(0);
2135
bool QWindowsWindow::setMouseGrabEnabled(bool grab)
2137
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << grab;
2139
qWarning("%s: No handle", __FUNCTION__);
2142
if (!isVisible() && grab) {
2143
qWarning("%s: Not setting mouse grab for invisible window %s/'%s'",
2144
__FUNCTION__, window()->metaObject()->className(),
2145
qPrintable(window()->objectName()));
2148
// release grab or an explicit grab overriding autocapture: Clear flag.
2149
clearFlag(QWindowsWindow::AutoMouseCapture);
2150
if (hasMouseCapture() != grab) {
2152
SetCapture(m_data.hwnd);
2160
static inline DWORD cornerToWinOrientation(Qt::Corner corner)
2163
case Qt::TopLeftCorner:
2164
return 0xf004; // SZ_SIZETOPLEFT;
2165
case Qt::TopRightCorner:
2166
return 0xf005; // SZ_SIZETOPRIGHT
2167
case Qt::BottomLeftCorner:
2168
return 0xf007; // SZ_SIZEBOTTOMLEFT
2169
case Qt::BottomRightCorner:
2170
return 0xf008; // SZ_SIZEBOTTOMRIGHT
2175
bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
2177
if (!GetSystemMenu(m_data.hwnd, FALSE))
2181
PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
2182
setFlag(SizeGripOperation);
2186
void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
2189
setFlag(FrameStrutEventsEnabled);
2191
clearFlag(FrameStrutEventsEnabled);
2195
#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
2196
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
2198
const QWindowsGeometryHint hint(window(), m_data.customMargins);
2199
hint.applyToMinMaxInfo(m_data.hwnd, mmi);
2201
if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized))
2202
&& (m_data.flags & Qt::FramelessWindowHint)) {
2203
// This block fixes QTBUG-8361: Frameless windows shouldn't cover the
2204
// taskbar when maximized
2205
const QScreen *screen = window()->screen();
2207
// Documentation of MINMAXINFO states that it will only work for the primary screen
2208
if (screen && screen == QGuiApplication::primaryScreen()) {
2209
const QRect availableGeometry = QHighDpi::toNativePixels(screen->availableGeometry(), screen);
2210
mmi->ptMaxSize.y = availableGeometry.height();
2212
// Width, because you can have the taskbar on the sides too.
2213
mmi->ptMaxSize.x = availableGeometry.width();
2215
// If you have the taskbar on top, or on the left you don't want it at (0,0):
2216
mmi->ptMaxPosition.x = availableGeometry.x();
2217
mmi->ptMaxPosition.y = availableGeometry.y();
2218
} else if (!screen){
2219
qWarning("window()->screen() returned a null screen");
2223
qCDebug(lcQpaWindows) << __FUNCTION__ << window() << *mmi;
2226
bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const
2228
// QTBUG-32663, suppress resize cursor for fixed size windows.
2229
const QWindow *w = window();
2230
if (!w->isTopLevel() // Task 105852, minimized windows need to respond to user input.
2231
|| (m_windowState != Qt::WindowNoState && m_windowState != Qt::WindowActive)
2232
|| (m_data.flags & Qt::FramelessWindowHint)) {
2235
const QSize minimumSize = w->minimumSize();
2236
if (minimumSize.isEmpty())
2238
const QSize maximumSize = w->maximumSize();
2239
const bool fixedWidth = minimumSize.width() == maximumSize.width();
2240
const bool fixedHeight = minimumSize.height() == maximumSize.height();
2241
if (!fixedWidth && !fixedHeight)
2243
const QPoint localPos = w->mapFromGlobal(QHighDpi::fromNativePixels(globalPos, w));
2244
const QSize size = w->size();
2246
if (localPos.y() >= size.height()) {
2247
*result = HTBORDER; // Unspecified border, no resize cursor.
2250
if (localPos.y() < 0) {
2251
const QMargins margins = frameMargins();
2252
const int topResizeBarPos = margins.left() - margins.top();
2253
if (localPos.y() < topResizeBarPos) {
2254
*result = HTCAPTION; // Extend caption over top resize bar, let's user move the window.
2259
if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {
2260
*result = HTBORDER; // Unspecified border, no resize cursor.
2266
#endif // !Q_OS_WINCE
2268
#ifndef QT_NO_CURSOR
2269
// Return the default cursor (Arrow) from QWindowsCursor's cache.
2270
static inline CursorHandlePtr defaultCursor(const QWindow *w)
2272
if (QScreen *screen = w->screen())
2273
if (const QPlatformScreen *platformScreen = screen->handle())
2274
if (QPlatformCursor *cursor = platformScreen->cursor())
2275
return static_cast<QWindowsCursor *>(cursor)->standardWindowCursor(Qt::ArrowCursor);
2276
return CursorHandlePtr(new CursorHandle(QWindowsCursor::createCursorFromShape(Qt::ArrowCursor)));
2279
// Check whether to apply a new cursor. Either the window in question is
2280
// currently under mouse, or it is the parent of the window under mouse and
2281
// there is no other window with an explicitly set cursor in-between.
2282
static inline bool applyNewCursor(const QWindow *w)
2284
const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse();
2285
if (underMouse == w)
2287
for (const QWindow *p = underMouse; p ; p = p->parent()) {
2290
const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p);
2291
if (platformWindow && !platformWindow->cursor()->isNull())
2296
#endif // !QT_NO_CURSOR
2299
\brief Applies to cursor property set on the window to the global cursor.
2304
void QWindowsWindow::applyCursor()
2306
#ifndef QT_NO_CURSOR
2307
if (m_cursor->isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel.
2308
if (const QWindow *p = window()->parent()) {
2309
if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p))
2310
platformWindow->applyCursor();
2312
SetCursor(defaultCursor(window())->handle());
2315
SetCursor(m_cursor->handle());
2320
void QWindowsWindow::setCursor(const CursorHandlePtr &c)
2322
#ifndef QT_NO_CURSOR
2323
if (c->handle() != m_cursor->handle()) {
2324
const bool apply = applyNewCursor(window());
2325
qCDebug(lcQpaWindows) << window() << __FUNCTION__
2326
<< c->handle() << " doApply=" << apply;
2335
void QWindowsWindow::setAlertState(bool enabled)
2337
if (isAlertState() == enabled)
2341
setFlag(AlertState);
2344
clearFlag(AlertState);
2348
void QWindowsWindow::alertWindow(int durationMs)
2350
UINT timeOutMs = GetCaretBlinkTime();
2351
if (!timeOutMs || timeOutMs == INFINITE)
2355
info.cbSize = sizeof(info);
2356
info.hwnd = m_data.hwnd;
2357
info.dwFlags = FLASHW_TRAY;
2358
info.dwTimeout = timeOutMs;
2359
info.uCount = durationMs == 0 ? 10 : UINT(durationMs) / timeOutMs;
2360
FlashWindowEx(&info);
2363
void QWindowsWindow::stopAlertWindow()
2366
info.cbSize = sizeof(info);
2367
info.hwnd = m_data.hwnd;
2368
info.dwFlags = FLASHW_STOP;
2371
FlashWindowEx(&info);
2373
#endif // !Q_OS_WINCE
2375
bool QWindowsWindow::isEnabled() const
2377
return (style() & WS_DISABLED) == 0;
2380
void QWindowsWindow::setEnabled(bool enabled)
2382
const unsigned oldStyle = style();
2383
unsigned newStyle = oldStyle;
2385
newStyle &= ~WS_DISABLED;
2387
newStyle |= WS_DISABLED;
2389
if (newStyle != oldStyle)
2393
static HICON createHIcon(const QIcon &icon, int xSize, int ySize)
2395
if (!icon.isNull()) {
2396
const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
2398
return qt_pixmapToWinHICON(pm);
2403
void QWindowsWindow::setWindowIcon(const QIcon &icon)
2408
m_iconSmall = createHIcon(icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
2409
m_iconBig = createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
2412
SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, LPARAM(m_iconSmall));
2413
SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, LPARAM(m_iconBig));
2415
SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, LPARAM(m_iconSmall));
2416
SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, LPARAM(m_iconSmall));
2421
bool QWindowsWindow::isTopLevel() const
2423
return window()->isTopLevel() && !m_data.embedded;
2427
\brief Sets custom margins to be added to the default margins determined by
2428
the windows style in the handling of the WM_NCCALCSIZE message.
2430
This is currently used to give the Aero-style QWizard a smaller top margin.
2431
The property can be set using QPlatformNativeInterface::setWindowProperty() or,
2432
before platform window creation, by setting a dynamic property
2433
on the QWindow (see QWindowsIntegration::createPlatformWindow()).
2436
void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
2438
if (newCustomMargins != m_data.customMargins) {
2439
const QMargins oldCustomMargins = m_data.customMargins;
2440
m_data.customMargins = newCustomMargins;
2441
// Re-trigger WM_NCALCSIZE with wParam=1 by passing SWP_FRAMECHANGED
2442
const QRect currentFrameGeometry = frameGeometry_sys();
2443
const QPoint topLeft = currentFrameGeometry.topLeft();
2444
QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins;
2445
newFrame.moveTo(topLeft);
2446
setFlag(FrameDirty);
2447
qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins
2448
<< currentFrameGeometry << "->" << newFrame;
2449
SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED);
2453
void *QWindowsWindow::surface(void *nativeConfig, int *err)
2457
Q_UNUSED(nativeConfig)
2461
if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
2462
m_surface = staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig, err);
2469
void QWindowsWindow::invalidateSurface()
2471
#ifndef QT_NO_OPENGL
2473
if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
2474
staticOpenGLContext->destroyWindowSurface(m_surface);
2477
#endif // QT_NO_OPENGL
2480
void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
2482
if (!window->handle())
2484
static_cast<QWindowsWindow *>(window->handle())->registerTouchWindow(touchTypes);
2487
void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
2490
if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)) {
2491
ULONG touchFlags = 0;
2492
const bool ret = QWindowsContext::user32dll.isTouchWindow(m_data.hwnd, &touchFlags);
2493
// Return if it is not a touch window or the flags are already set by a hook
2494
// such as HCBT_CREATEWND
2495
if (ret || touchFlags != 0)
2497
if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, ULONG(touchTypes)))
2498
setFlag(TouchRegistered);
2500
qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
2502
#endif // !Q_OS_WINCE
2505
void QWindowsWindow::aboutToMakeCurrent()
2507
#ifndef QT_NO_OPENGL
2508
// For RasterGLSurface windows, that become OpenGL windows dynamically, it might be
2509
// time to set up some GL specifics. This is particularly important for layered
2510
// windows (WS_EX_LAYERED due to alpha > 0).
2511
const bool isCompositing = qt_window_private(window())->compositing;
2512
if (isCompositing != testFlag(Compositing)) {
2514
setFlag(Compositing);
2516
clearFlag(Compositing);
2518
updateGLWindowSettings(window(), m_data.hwnd, m_data.flags, m_opacity);
2523
void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border)
2525
if (QPlatformWindow *handle = window->handle())
2526
static_cast<QWindowsWindow *>(handle)->setHasBorderInFullScreen(border);
2528
qWarning("%s invoked without window handle; call has no effect.", Q_FUNC_INFO);
2531
void QWindowsWindow::setHasBorderInFullScreen(bool border)
2534
setFlag(HasBorderInFullScreen);
2536
clearFlag(HasBorderInFullScreen);
2539
QString QWindowsWindow::formatWindowTitle(const QString &title)
2541
return QPlatformWindow::formatWindowTitle(title, QStringLiteral(" - "));