~gabriel1984sibiu/minitube/qt5.6

« back to all changes in this revision

Viewing changes to src/plugins/platforms/windows/qwindowswindow.cpp

  • Committer: Grevutiu Gabriel
  • Date: 2017-06-13 08:43:17 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20170613084317-ek0zqe0u9g3ocvi8
OriginalĀ upstreamĀ code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#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"
 
48
#ifdef QT_NO_CURSOR
 
49
#  include "qwindowscursor.h"
 
50
#endif
 
51
 
 
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>
 
62
 
 
63
#include <QtCore/QDebug>
 
64
 
 
65
QT_BEGIN_NAMESPACE
 
66
 
 
67
enum {
 
68
    defaultWindowWidth = 160,
 
69
    defaultWindowHeight = 160
 
70
};
 
71
 
 
72
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
 
73
 
 
74
static QByteArray debugWinStyle(DWORD style)
 
75
{
 
76
    QByteArray rc = "0x";
 
77
    rc += QByteArray::number(qulonglong(style), 16);
 
78
    if (style & WS_POPUP)
 
79
        rc += " WS_POPUP";
 
80
    if (style & WS_CHILD)
 
81
        rc += " WS_CHILD";
 
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)
 
91
        rc += " WS_DLGFRAME";
 
92
    if (style & WS_SYSMENU)
 
93
        rc += " WS_SYSMENU";
 
94
    if (style & WS_MINIMIZEBOX)
 
95
        rc += " WS_MINIMIZEBOX";
 
96
    if (style & WS_MAXIMIZEBOX)
 
97
        rc += " WS_MAXIMIZEBOX";
 
98
    return rc;
 
99
}
 
100
 
 
101
static QByteArray debugWinExStyle(DWORD exStyle)
 
102
{
 
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";
 
113
    return rc;
 
114
}
 
115
 
 
116
static inline QSize qSizeOfRect(const RECT &rect)
 
117
{
 
118
    return QSize(rect.right -rect.left, rect.bottom - rect.top);
 
119
}
 
120
 
 
121
static inline QRect qrectFromRECT(const RECT &rect)
 
122
{
 
123
    return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect));
 
124
}
 
125
 
 
126
static inline RECT RECTfromQRect(const QRect &rect)
 
127
{
 
128
    const int x = rect.left();
 
129
    const int y = rect.top();
 
130
    RECT result = { x, y, x + rect.width(), y + rect.height() };
 
131
    return result;
 
132
}
 
133
 
 
134
#ifndef QT_NO_DEBUG_STREAM
 
135
QDebug operator<<(QDebug d, const RECT &r)
 
136
{
 
137
    QDebugStateSaver saver(d);
 
138
    d.nospace();
 
139
    d << "RECT: left/top=" << r.left << ',' << r.top
 
140
        << " right/bottom=" << r.right << ',' << r.bottom;
 
141
    return d;
 
142
}
 
143
 
 
144
QDebug operator<<(QDebug d, const POINT &p)
 
145
{
 
146
    d << p.x << ',' << p.y;
 
147
    return d;
 
148
}
 
149
 
 
150
#  ifndef Q_OS_WINCE
 
151
QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
 
152
{
 
153
    QDebugStateSaver saver(d);
 
154
    d.nospace();
 
155
    d << "NCCALCSIZE_PARAMS " << qrectFromRECT(p.rgrc[0])
 
156
        << ' ' << qrectFromRECT(p.rgrc[1]) << ' ' << qrectFromRECT(p.rgrc[2]);
 
157
    return d;
 
158
}
 
159
 
 
160
QDebug operator<<(QDebug d, const MINMAXINFO &i)
 
161
{
 
162
    QDebugStateSaver saver(d);
 
163
    d.nospace();
 
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;
 
169
    return d;
 
170
}
 
171
 
 
172
QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp)
 
173
{
 
174
    QDebugStateSaver saver(d);
 
175
    d.nospace();
 
176
    d <<  "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd="
 
177
        << wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition
 
178
        << ", rcNormalPosition=" << wp.rcNormalPosition;
 
179
    return d;
 
180
}
 
181
#  endif // !Q_OS_WINCE
 
182
#endif // !QT_NO_DEBUG_STREAM
 
183
 
 
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)
 
187
{
 
188
#ifndef Q_OS_WINCE
 
189
    if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
 
190
        return QPoint(0, 0);
 
191
    const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager();
 
192
    const QWindowsScreen *screen = screenManager.screens().size() == 1
 
193
        ? screenManager.screens().constFirst() : screenManager.screenAtDp(point);
 
194
    if (screen)
 
195
        return screen->availableGeometry().topLeft() - screen->geometry().topLeft();
 
196
#else
 
197
    Q_UNUSED(hwnd)
 
198
    Q_UNUSED(point)
 
199
#endif
 
200
    return QPoint(0, 0);
 
201
}
 
202
 
 
203
// Return the frame geometry relative to the parent
 
204
// if there is one.
 
205
static inline QRect frameGeometry(HWND hwnd, bool topLevel)
 
206
{
 
207
    RECT rect = { 0, 0, 0, 0 };
 
208
#ifndef Q_OS_WINCE
 
209
    if (topLevel) {
 
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()));
 
216
        }
 
217
    }
 
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;
 
230
    }
 
231
    return qrectFromRECT(rect);
 
232
}
 
233
 
 
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)
 
236
{
 
237
    if (!IsWindowVisible(hwnd))
 
238
        return QWindow::Hidden;
 
239
#ifndef Q_OS_WINCE
 
240
    WINDOWPLACEMENT windowPlacement;
 
241
    windowPlacement.length = sizeof(WINDOWPLACEMENT);
 
242
    if (GetWindowPlacement(hwnd, &windowPlacement)) {
 
243
        switch (windowPlacement.showCmd) {
 
244
        case SW_SHOWMINIMIZED:
 
245
        case SW_MINIMIZE:
 
246
        case SW_FORCEMINIMIZE:
 
247
            return QWindow::Minimized;
 
248
        case SW_SHOWMAXIMIZED:
 
249
            return QWindow::Maximized;
 
250
        default:
 
251
            break;
 
252
        }
 
253
    }
 
254
#endif // !Q_OS_WINCE
 
255
    return QWindow::Windowed;
 
256
}
 
257
 
 
258
static inline bool windowIsOpenGL(const QWindow *w)
 
259
{
 
260
    switch (w->surfaceType()) {
 
261
    case QSurface::OpenGLSurface:
 
262
        return true;
 
263
    case QSurface::RasterGLSurface:
 
264
        return qt_window_private(const_cast<QWindow *>(w))->compositing;
 
265
    default:
 
266
        return false;
 
267
    }
 
268
}
 
269
 
 
270
static bool applyBlurBehindWindow(HWND hwnd)
 
271
{
 
272
#ifdef Q_OS_WINCE
 
273
    Q_UNUSED(hwnd);
 
274
    return false;
 
275
#else
 
276
    enum { dwmBbEnable = 0x1, dwmBbBlurRegion = 0x2 };
 
277
 
 
278
    struct DwmBlurBehind {
 
279
        DWORD dwFlags;
 
280
        BOOL  fEnable;
 
281
        HRGN  hRgnBlur;
 
282
        BOOL  fTransitionOnMaximized;
 
283
    };
 
284
 
 
285
    typedef HRESULT (WINAPI *PtrDwmEnableBlurBehindWindow)(HWND, const DwmBlurBehind*);
 
286
    typedef HRESULT (WINAPI *PtrDwmIsCompositionEnabled)(BOOL *);
 
287
 
 
288
    // DWM API is available only from Windows Vista
 
289
    if (QSysInfo::windowsVersion() < QSysInfo::WV_VISTA)
 
290
        return false;
 
291
 
 
292
    static bool functionPointersResolved = false;
 
293
    static PtrDwmEnableBlurBehindWindow dwmBlurBehind = 0;
 
294
    static PtrDwmIsCompositionEnabled dwmIsCompositionEnabled = 0;
 
295
 
 
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"));
 
301
        }
 
302
 
 
303
        functionPointersResolved = true;
 
304
    }
 
305
 
 
306
    if (Q_UNLIKELY(!dwmBlurBehind || !dwmIsCompositionEnabled))
 
307
        return false;
 
308
 
 
309
    BOOL compositionEnabled;
 
310
    if (dwmIsCompositionEnabled(&compositionEnabled) != S_OK)
 
311
        return false;
 
312
 
 
313
    DwmBlurBehind blurBehind = {0, 0, 0, 0};
 
314
 
 
315
    if (compositionEnabled) {
 
316
        blurBehind.dwFlags = dwmBbEnable | dwmBbBlurRegion;
 
317
        blurBehind.fEnable = TRUE;
 
318
        blurBehind.hRgnBlur = CreateRectRgn(0, 0, -1, -1);
 
319
    } else {
 
320
        blurBehind.dwFlags = dwmBbEnable;
 
321
        blurBehind.fEnable = FALSE;
 
322
    }
 
323
 
 
324
    const bool result = dwmBlurBehind(hwnd, &blurBehind) == S_OK;
 
325
 
 
326
    if (blurBehind.hRgnBlur)
 
327
        DeleteObject(blurBehind.hRgnBlur);
 
328
 
 
329
    return result;
 
330
#endif // Q_OS_WINCE
 
331
}
 
332
 
 
333
// from qwidget_win.cpp, pass flags separately in case they have been "autofixed".
 
334
static bool shouldShowMaximizeButton(const QWindow *w, Qt::WindowFlags flags)
 
335
{
 
336
    if ((flags & Qt::MSWindowsFixedSizeDialogHint) || !(flags & Qt::WindowMaximizeButtonHint))
 
337
        return false;
 
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);
 
342
}
 
343
 
 
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)
 
348
{
 
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) {
 
355
        if (needsLayered) {
 
356
            SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_LAYERED);
 
357
        } else {
 
358
            SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
 
359
        }
 
360
    }
 
361
    return needsLayered;
 
362
#else // !Q_OS_WINCE
 
363
    Q_UNUSED(hwnd);
 
364
    Q_UNUSED(flags);
 
365
    Q_UNUSED(hasAlpha);
 
366
    Q_UNUSED(opacity);
 
367
    return false;
 
368
#endif // Q_OS_WINCE
 
369
}
 
370
 
 
371
static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, bool hasAlpha, bool openGL, qreal level)
 
372
{
 
373
#ifdef Q_OS_WINCE // WINCE does not support that feature and microsoft explicitly warns to use those calls
 
374
    Q_UNUSED(hwnd);
 
375
    Q_UNUSED(flags);
 
376
    Q_UNUSED(hasAlpha);
 
377
    Q_UNUSED(level);
 
378
#else
 
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);
 
385
        } else {
 
386
            QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
 
387
        }
 
388
    } else if (IsWindowVisible(hwnd)) { // Repaint when switching from layered.
 
389
        InvalidateRect(hwnd, NULL, TRUE);
 
390
    }
 
391
#endif // !Q_OS_WINCE
 
392
}
 
393
 
 
394
static inline void updateGLWindowSettings(const QWindow *w, HWND hwnd, Qt::WindowFlags flags, qreal opacity)
 
395
{
 
396
    const bool isGL = windowIsOpenGL(w);
 
397
    const bool hasAlpha = w->format().hasAlpha();
 
398
 
 
399
    if (isGL && hasAlpha)
 
400
        applyBlurBehindWindow(hwnd);
 
401
 
 
402
    setWindowOpacity(hwnd, flags, hasAlpha, isGL, opacity);
 
403
}
 
404
 
 
405
/*!
 
406
    \class WindowCreationData
 
407
    \brief Window creation code.
 
408
 
 
409
    This struct gathers all information required to create a window.
 
410
    Window creation is split in 3 steps:
 
411
 
 
412
    \list
 
413
    \li fromWindow() Gather all required information
 
414
    \li create() Create the system handle.
 
415
    \li initialize() Post creation initialization steps.
 
416
    \endlist
 
417
 
 
418
    The reason for this split is to also enable changing the QWindowFlags
 
419
    by calling:
 
420
 
 
421
    \list
 
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.
 
425
    \endlist
 
426
 
 
427
    Contains the window creation code formerly in qwidget_win.cpp.
 
428
 
 
429
    \sa QWindowCreationContext
 
430
    \internal
 
431
    \ingroup qt-lighthouse-win
 
432
*/
 
433
 
 
434
struct WindowCreationData
 
435
{
 
436
    typedef QWindowsWindowData WindowData;
 
437
    enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 };
 
438
 
 
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) {}
 
442
 
 
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;
 
447
 
 
448
    Qt::WindowFlags flags;
 
449
    HWND parentHandle;
 
450
    Qt::WindowType type;
 
451
    unsigned style;
 
452
    unsigned exStyle;
 
453
    bool topLevel;
 
454
    bool popup;
 
455
    bool dialog;
 
456
    bool tool;
 
457
    bool embedded;
 
458
    bool hasAlpha;
 
459
};
 
460
 
 
461
QDebug operator<<(QDebug debug, const WindowCreationData &d)
 
462
{
 
463
    QDebugStateSaver saver(debug);
 
464
    debug.nospace();
 
465
    debug.noquote();
 
466
    debug << "WindowCreationData: " << d.flags
 
467
        << "\n  topLevel=" << d.topLevel;
 
468
     if (d.parentHandle)
 
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);
 
473
    if (d.exStyle)
 
474
        debug << "\n  exStyle=" << debugWinExStyle(d.exStyle);
 
475
    return debug;
 
476
}
 
477
 
 
478
// Fix top level window flags in case only the type flags are passed.
 
479
static inline void fixTopLevelWindowFlags(Qt::WindowFlags &flags)
 
480
{
 
481
    // Not supported on Windows, also do correction when it is set.
 
482
    flags &= ~Qt::WindowFullscreenButtonHint;
 
483
    switch (flags) {
 
484
    case Qt::Window:
 
485
        flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint
 
486
              |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
 
487
        break;
 
488
    case Qt::Dialog:
 
489
        flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint | Qt::WindowCloseButtonHint;
 
490
        break;
 
491
    case Qt::Tool:
 
492
         flags |= Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
 
493
         break;
 
494
    default:
 
495
        break;
 
496
    }
 
497
    if ((flags & Qt::WindowType_Mask) == Qt::SplashScreen)
 
498
        flags |= Qt::FramelessWindowHint;
 
499
}
 
500
 
 
501
void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
 
502
                                    unsigned creationFlags)
 
503
{
 
504
    flags = flagsIn;
 
505
 
 
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()) {
 
511
        embedded = true;
 
512
        parentHandle = reinterpret_cast<HWND>(prop.value<WId>());
 
513
    }
 
514
 
 
515
    if (creationFlags & ForceChild) {
 
516
        topLevel = false;
 
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.
 
520
        topLevel = false;
 
521
    } else {
 
522
        topLevel = (creationFlags & ForceTopLevel) ? true : w->isTopLevel();
 
523
    }
 
524
 
 
525
    if (topLevel)
 
526
        fixTopLevelWindowFlags(flags);
 
527
 
 
528
    type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask);
 
529
    switch (type) {
 
530
    case Qt::Dialog:
 
531
    case Qt::Sheet:
 
532
        dialog = true;
 
533
        break;
 
534
    case Qt::Drawer:
 
535
    case Qt::Tool:
 
536
        tool = true;
 
537
        break;
 
538
    case Qt::Popup:
 
539
        popup = true;
 
540
        break;
 
541
    default:
 
542
        break;
 
543
    }
 
544
    if ((flags & Qt::MSWindowsFixedSizeDialogHint))
 
545
        dialog = true;
 
546
 
 
547
    // Parent: Use transient parent for top levels.
 
548
    if (popup) {
 
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);
 
553
    }
 
554
 
 
555
    if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
 
556
        style = WS_POPUP;
 
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;
 
562
        else
 
563
            style = 0;
 
564
    } else {
 
565
        style = WS_CHILD;
 
566
    }
 
567
 
 
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
 
574
#else
 
575
        style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
 
576
#endif
 
577
        if (topLevel) {
 
578
            if ((type == Qt::Window || dialog || tool)) {
 
579
                if (!(flags & Qt::FramelessWindowHint)) {
 
580
                    style |= WS_POPUP;
 
581
                    if (flags & Qt::MSWindowsFixedSizeDialogHint) {
 
582
                        style |= WS_DLGFRAME;
 
583
                    } else {
 
584
                        style |= WS_THICKFRAME;
 
585
                    }
 
586
                    if (flags & Qt::WindowTitleHint)
 
587
                        style |= WS_CAPTION; // Contains WS_DLGFRAME
 
588
                }
 
589
                if (flags & Qt::WindowSystemMenuHint)
 
590
                    style |= WS_SYSMENU;
 
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;
 
594
                }
 
595
                if (flags & Qt::WindowMinimizeButtonHint)
 
596
                    style |= WS_MINIMIZEBOX;
 
597
                if (shouldShowMaximizeButton(w, flags))
 
598
                    style |= WS_MAXIMIZEBOX;
 
599
                if (tool)
 
600
                    exStyle |= WS_EX_TOOLWINDOW;
 
601
                if (flags & Qt::WindowContextHelpButtonHint)
 
602
                    exStyle |= WS_EX_CONTEXTHELP;
 
603
            } else {
 
604
                 exStyle |= WS_EX_TOOLWINDOW;
 
605
            }
 
606
 
 
607
#ifndef Q_OS_WINCE
 
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;
 
612
#endif
 
613
    }
 
614
}
 
615
 
 
616
QWindowsWindowData
 
617
    WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const
 
618
{
 
619
    typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
 
620
 
 
621
    WindowData result;
 
622
    result.flags = flags;
 
623
 
 
624
    const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
 
625
 
 
626
    const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w);
 
627
 
 
628
    const QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight);
 
629
 
 
630
    if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
 
631
        title = topLevel ? qAppName() : w->objectName();
 
632
 
 
633
    const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
 
634
    const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
 
635
 
 
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);
 
640
 
 
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;
 
647
 
 
648
    result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
 
649
                                 style,
 
650
                                 context->frameX, context->frameY,
 
651
                                 context->frameWidth, context->frameHeight,
 
652
                                 parentHandle, NULL, appinst, NULL);
 
653
#ifdef Q_OS_WINCE
 
654
    if (DisableGestures(result.hwnd, TGF_GID_ALL, TGF_SCOPE_WINDOW))
 
655
        EnableGestures(result.hwnd, TGF_GID_DIRECTMANIPULATION, TGF_SCOPE_WINDOW);
 
656
#endif
 
657
    qCDebug(lcQpaWindows).nospace()
 
658
        << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
 
659
        << context->obtainedGeometry << ' ' << context->margins;
 
660
 
 
661
    if (!result.hwnd) {
 
662
        qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
 
663
        return result;
 
664
    }
 
665
 
 
666
    result.geometry = context->obtainedGeometry;
 
667
    result.frame = context->margins;
 
668
    result.embedded = embedded;
 
669
    result.customMargins = context->customMargins;
 
670
 
 
671
    return result;
 
672
}
 
673
 
 
674
void WindowCreationData::applyWindowFlags(HWND hwnd) const
 
675
{
 
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);
 
679
 
 
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));
 
691
}
 
692
 
 
693
void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChange, qreal opacityLevel) const
 
694
{
 
695
    if (!hwnd)
 
696
        return;
 
697
    UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE;
 
698
    if (frameChange)
 
699
        swpFlags |= SWP_FRAMECHANGED;
 
700
    if (topLevel) {
 
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);
 
710
        }
 
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);
 
715
            else
 
716
                EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
 
717
        }
 
718
        updateGLWindowSettings(w, hwnd, flags, opacityLevel);
 
719
    } else { // child.
 
720
        SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags);
 
721
    }
 
722
}
 
723
 
 
724
 
 
725
// Scaling helpers for size constraints.
 
726
static QSize toNativeSizeConstrained(QSize dip, const QWindow *w)
 
727
{
 
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;
 
734
    }
 
735
    return dip;
 
736
}
 
737
 
 
738
/*!
 
739
    \class QWindowsGeometryHint
 
740
    \brief Stores geometry constraints and provides utility functions.
 
741
 
 
742
    Geometry constraints ready to apply to a MINMAXINFO taking frame
 
743
    into account.
 
744
 
 
745
    \internal
 
746
    \ingroup qt-lighthouse-win
 
747
*/
 
748
 
 
749
QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) :
 
750
     minimumSize(toNativeSizeConstrained(w->minimumSize(), w)),
 
751
     maximumSize(toNativeSizeConstrained(w->maximumSize(), w)),
 
752
     customMargins(cm)
 
753
{
 
754
}
 
755
 
 
756
bool QWindowsGeometryHint::validSize(const QSize &s) const
 
757
{
 
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();
 
762
}
 
763
 
 
764
QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
 
765
{
 
766
    RECT rect = {0,0,0,0};
 
767
#ifndef Q_OS_WINCE
 
768
    style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
 
769
#endif
 
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;
 
777
    return result;
 
778
}
 
779
 
 
780
bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
 
781
{
 
782
#ifndef Q_OS_WINCE
 
783
    // NCCALCSIZE_PARAMS structure if wParam==TRUE
 
784
    if (!msg.wParam || customMargins.isNull())
 
785
        return false;
 
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();
 
793
    result = 0;
 
794
    qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->"
 
795
        << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2]
 
796
        << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy;
 
797
    return true;
 
798
#else
 
799
    Q_UNUSED(customMargins)
 
800
    Q_UNUSED(msg)
 
801
    Q_UNUSED(result)
 
802
    return false;
 
803
#endif
 
804
}
 
805
 
 
806
#ifndef Q_OS_WINCE
 
807
void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
 
808
{
 
809
    return applyToMinMaxInfo(DWORD(GetWindowLong(hwnd, GWL_STYLE)),
 
810
                             DWORD(GetWindowLong(hwnd, GWL_EXSTYLE)), mmi);
 
811
}
 
812
 
 
813
void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
 
814
{
 
815
    qCDebug(lcQpaWindows).nospace() << '>' << __FUNCTION__ << '<' << " min="
 
816
        << minimumSize.width() << ',' << minimumSize.height()
 
817
        << " max=" << maximumSize.width() << ',' << maximumSize.height()
 
818
        << " in " << *mmi;
 
819
 
 
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;
 
827
 
 
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
 
836
        << " out " << *mmi;
 
837
}
 
838
#endif // !Q_OS_WINCE
 
839
 
 
840
bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
 
841
{
 
842
    return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
 
843
           == QWindowPrivate::WindowFrameInclusive;
 
844
}
 
845
 
 
846
/*!
 
847
    \class QWindowsBaseWindow
 
848
    \brief Base class for QWindowsForeignWindow, QWindowsWindow
 
849
 
 
850
    The class provides some _sys() getters for querying window
 
851
    data from a HWND and some _sys() setters.
 
852
 
 
853
    Derived classes wrapping foreign windows may use them directly
 
854
    to calculate geometry, margins, etc.
 
855
 
 
856
    Derived classes representing windows created by Qt may defer
 
857
    expensive calculations until change notifications are received.
 
858
 
 
859
    \since 5.6
 
860
    \internal
 
861
    \ingroup qt-lighthouse-win
 
862
*/
 
863
 
 
864
QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w)
 
865
{
 
866
    if (w) {
 
867
        if (QPlatformWindow *pw = w->handle())
 
868
            return static_cast<QWindowsBaseWindow *>(pw);
 
869
    }
 
870
    return Q_NULLPTR;
 
871
}
 
872
 
 
873
HWND QWindowsBaseWindow::handleOf(const QWindow *w)
 
874
{
 
875
    const QWindowsBaseWindow *bw = QWindowsBaseWindow::baseWindowOf(w);
 
876
    return bw ? bw->handle() : HWND(0);
 
877
}
 
878
 
 
879
bool QWindowsBaseWindow::isTopLevel_sys() const
 
880
{
 
881
    const HWND parent = parentHwnd();
 
882
    return !parent || parent == GetDesktopWindow();
 
883
}
 
884
 
 
885
QRect QWindowsBaseWindow::frameGeometry_sys() const
 
886
{
 
887
    return frameGeometry(handle(), isTopLevel());
 
888
}
 
889
 
 
890
QRect QWindowsBaseWindow::geometry_sys() const
 
891
{
 
892
    return frameGeometry_sys().marginsRemoved(frameMargins());
 
893
}
 
894
 
 
895
QMargins QWindowsBaseWindow::frameMargins_sys() const
 
896
{
 
897
    return QWindowsGeometryHint::frame(style(), exStyle());
 
898
}
 
899
 
 
900
void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows.
 
901
{
 
902
    SetWindowPos(handle(),0 , 0, 0, 0, 0,
 
903
                 SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
 
904
}
 
905
 
 
906
void QWindowsBaseWindow::raise_sys()
 
907
{
 
908
    qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
 
909
    SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
 
910
}
 
911
 
 
912
void QWindowsBaseWindow::lower_sys()
 
913
{
 
914
    qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
 
915
    SetWindowPos(handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
 
916
}
 
917
 
 
918
void QWindowsBaseWindow::setWindowTitle_sys(const QString &title)
 
919
{
 
920
    qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << title;
 
921
    SetWindowText(handle(), reinterpret_cast<const wchar_t *>(title.utf16()));
 
922
}
 
923
 
 
924
QPoint QWindowsBaseWindow::mapToGlobal(const QPoint &pos) const
 
925
{
 
926
    return QWindowsGeometryHint::mapToGlobal(handle(), pos);
 
927
}
 
928
 
 
929
QPoint QWindowsBaseWindow::mapFromGlobal(const QPoint &pos) const
 
930
{
 
931
    return QWindowsGeometryHint::mapFromGlobal(handle(), pos);
 
932
}
 
933
 
 
934
/*!
 
935
    \class QWindowsDesktopWindow
 
936
    \brief Window wrapping GetDesktopWindow not allowing any manipulation.
 
937
    \since 5.6
 
938
    \internal
 
939
    \ingroup qt-lighthouse-win
 
940
*/
 
941
 
 
942
/*!
 
943
    \class QWindowsForeignWindow
 
944
    \brief Window wrapping a foreign native window.
 
945
 
 
946
    QWindowsForeignWindow stores a native HWND and implements getters for
 
947
    geometry, margins, etc. reparenting and geometry manipulation for use as a
 
948
    child window in Qt.
 
949
 
 
950
    \since 5.6
 
951
    \internal
 
952
    \ingroup qt-lighthouse-win
 
953
*/
 
954
 
 
955
QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd)
 
956
    : QWindowsBaseWindow(window)
 
957
    , m_hwnd(hwnd)
 
958
    , m_topLevelStyle(0)
 
959
{
 
960
}
 
961
 
 
962
void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow)
 
963
{
 
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;
 
973
        if (isTopLevel) {
 
974
            newStyle = m_topLevelStyle;
 
975
        } else {
 
976
            m_topLevelStyle = oldStyle;
 
977
            newStyle &= ~(WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW);
 
978
            newStyle |= WS_CHILD;
 
979
        }
 
980
        SetWindowLongPtr(m_hwnd, GWL_STYLE, newStyle);
 
981
    }
 
982
}
 
983
 
 
984
void QWindowsForeignWindow::setVisible(bool visible)
 
985
{
 
986
    qCDebug(lcQpaWindows) << __FUNCTION__ << window() << visible;
 
987
    if (visible)
 
988
        ShowWindow(handle(), SW_SHOWNOACTIVATE);
 
989
    else
 
990
        hide_sys();
 
991
}
 
992
 
 
993
/*!
 
994
    \class QWindowCreationContext
 
995
    \brief Active Context for creating windows.
 
996
 
 
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.
 
1002
 
 
1003
    In that phase, an instance of  QWindowCreationContext is set on
 
1004
    QWindowsContext.
 
1005
 
 
1006
    QWindowCreationContext stores the information to answer the initial
 
1007
    WM_GETMINMAXINFO and obtains the corrected size/position.
 
1008
 
 
1009
    \sa WindowCreationData, QWindowsContext
 
1010
    \internal
 
1011
    \ingroup qt-lighthouse-win
 
1012
*/
 
1013
 
 
1014
QWindowCreationContext::QWindowCreationContext(const QWindow *w,
 
1015
                                               const QRect &geometry,
 
1016
                                               const QMargins &cm,
 
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)
 
1023
{
 
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'
 
1027
    // for toplevels.
 
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();
 
1038
        }
 
1039
    }
 
1040
 
 
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;
 
1048
}
 
1049
 
 
1050
/*!
 
1051
    \class QWindowsWindow
 
1052
    \brief Raster or OpenGL Window.
 
1053
 
 
1054
    \list
 
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).
 
1060
 
 
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).
 
1066
    \endlist
 
1067
 
 
1068
    \internal
 
1069
    \ingroup qt-lighthouse-win
 
1070
*/
 
1071
 
 
1072
QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) :
 
1073
    QWindowsBaseWindow(aWindow),
 
1074
    m_data(data),
 
1075
    m_flags(WithinCreate),
 
1076
    m_hdc(0),
 
1077
    m_windowState(Qt::WindowNoState),
 
1078
    m_opacity(1.0),
 
1079
    m_cursor(new CursorHandle),
 
1080
    m_dropTarget(0),
 
1081
    m_savedStyle(0),
 
1082
    m_format(aWindow->requestedFormat()),
 
1083
#ifdef Q_OS_WINCE
 
1084
    m_previouslyHidden(false),
 
1085
#endif
 
1086
    m_iconSmall(0),
 
1087
    m_iconBig(0),
 
1088
    m_surface(0)
 
1089
{
 
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);
 
1100
        else
 
1101
            setFlag(OpenGL_ES2);
 
1102
    }
 
1103
#endif // QT_NO_OPENGL
 
1104
    updateDropSite(window()->isTopLevel());
 
1105
 
 
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);
 
1114
}
 
1115
 
 
1116
QWindowsWindow::~QWindowsWindow()
 
1117
{
 
1118
    setFlag(WithinDestroy);
 
1119
#ifndef Q_OS_WINCE
 
1120
    if (testFlag(TouchRegistered))
 
1121
        QWindowsContext::user32dll.unregisterTouchWindow(m_data.hwnd);
 
1122
#endif // !Q_OS_WINCE
 
1123
    destroyWindow();
 
1124
    destroyIcon();
 
1125
}
 
1126
 
 
1127
void QWindowsWindow::fireExpose(const QRegion &region, bool force)
 
1128
{
 
1129
    if (region.isEmpty() && !force)
 
1130
        clearFlag(Exposed);
 
1131
    else
 
1132
        setFlag(Exposed);
 
1133
    QWindowSystemInterface::handleExposeEvent(window(), region);
 
1134
}
 
1135
 
 
1136
static inline QWindow *findTransientChild(const QWindow *parent)
 
1137
{
 
1138
    foreach (QWindow *w, QGuiApplication::topLevelWindows())
 
1139
        if (w->transientParent() == parent)
 
1140
            return w;
 
1141
    return 0;
 
1142
}
 
1143
 
 
1144
void QWindowsWindow::destroyWindow()
 
1145
{
 
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
 
1160
        if (m_surface) {
 
1161
            if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
 
1162
                staticOpenGLContext->destroyWindowSurface(m_surface);
 
1163
            m_surface = 0;
 
1164
        }
 
1165
#endif
 
1166
#ifdef Q_OS_WINCE
 
1167
        if ((m_windowState & Qt::WindowFullScreen) && !m_previouslyHidden) {
 
1168
            HWND handle = FindWindow(L"HHTaskBar", L"");
 
1169
            if (handle) {
 
1170
                ShowWindow(handle, SW_SHOW);
 
1171
            }
 
1172
        }
 
1173
#endif // !Q_OS_WINCE
 
1174
        DestroyWindow(m_data.hwnd);
 
1175
        context->removeWindow(m_data.hwnd);
 
1176
        m_data.hwnd = 0;
 
1177
    }
 
1178
}
 
1179
 
 
1180
void QWindowsWindow::updateDropSite(bool topLevel)
 
1181
{
 
1182
    bool enabled = false;
 
1183
    bool parentIsEmbedded = false;
 
1184
 
 
1185
    if (!topLevel) {
 
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;
 
1191
    }
 
1192
 
 
1193
    if (topLevel || parentIsEmbedded) {
 
1194
        switch (window()->type()) {
 
1195
        case Qt::Window:
 
1196
        case Qt::Dialog:
 
1197
        case Qt::Sheet:
 
1198
        case Qt::Drawer:
 
1199
        case Qt::Popup:
 
1200
        case Qt::Tool:
 
1201
            enabled = true;
 
1202
            break;
 
1203
        default:
 
1204
            break;
 
1205
        }
 
1206
    }
 
1207
    setDropSiteEnabled(enabled);
 
1208
}
 
1209
 
 
1210
void QWindowsWindow::setDropSiteEnabled(bool dropEnabled)
 
1211
{
 
1212
    if (isDropSiteEnabled() == dropEnabled)
 
1213
        return;
 
1214
    qCDebug(lcQpaMime) << __FUNCTION__ << window() << dropEnabled;
 
1215
#if !defined(QT_NO_CLIPBOARD) && !defined(QT_NO_DRAGANDDROP)
 
1216
    if (dropEnabled) {
 
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);
 
1221
    } else {
 
1222
        CoLockObjectExternal(m_dropTarget, false, true);
 
1223
        m_dropTarget->Release();
 
1224
        RevokeDragDrop(m_data.hwnd);
 
1225
        m_dropTarget = 0;
 
1226
    }
 
1227
#endif // !QT_NO_CLIPBOARD && !QT_NO_DRAGANDDROP
 
1228
}
 
1229
 
 
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)
 
1233
{
 
1234
    while (QWindow *parent = w->parent())
 
1235
        w = parent;
 
1236
 
 
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);
 
1247
            }
 
1248
        }
 
1249
    }
 
1250
    return w;
 
1251
}
 
1252
 
 
1253
QWindowsWindowData
 
1254
    QWindowsWindowData::create(const QWindow *w,
 
1255
                                       const QWindowsWindowData &parameters,
 
1256
                                       const QString &title)
 
1257
{
 
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);
 
1263
    return result;
 
1264
}
 
1265
 
 
1266
void QWindowsWindow::setVisible(bool visible)
 
1267
{
 
1268
    const QWindow *win = window();
 
1269
    qCDebug(lcQpaWindows) << __FUNCTION__ << this << win << m_data.hwnd << visible;
 
1270
    if (m_data.hwnd) {
 
1271
        if (visible) {
 
1272
            show_sys();
 
1273
 
 
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.
 
1277
            if (isLayered())
 
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
 
1281
 
 
1282
            if (win->type() == Qt::Popup && !win->parent() && !QGuiApplication::focusWindow())
 
1283
                SetForegroundWindow(m_data.hwnd);
 
1284
        } else {
 
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);
 
1289
            else
 
1290
                hide_sys();
 
1291
            fireExpose(QRegion());
 
1292
        }
 
1293
    }
 
1294
}
 
1295
 
 
1296
bool QWindowsWindow::isVisible() const
 
1297
{
 
1298
    return m_data.hwnd && IsWindowVisible(m_data.hwnd);
 
1299
}
 
1300
 
 
1301
bool QWindowsWindow::isActive() const
 
1302
{
 
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))
 
1306
            return true;
 
1307
    return false;
 
1308
}
 
1309
 
 
1310
bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const
 
1311
{
 
1312
    if (parentWindow) {
 
1313
        const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(parentWindow);
 
1314
        const HWND hwnd = ww->handle();
 
1315
        if (!IsChild(hwnd, m_data.hwnd))
 
1316
            return false;
 
1317
    }
 
1318
 
 
1319
    if (!m_data.embedded && parent())
 
1320
        return parent()->isEmbedded();
 
1321
 
 
1322
    return m_data.embedded;
 
1323
}
 
1324
 
 
1325
QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
 
1326
{
 
1327
    if (m_data.hwnd)
 
1328
        return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos);
 
1329
    else
 
1330
        return pos;
 
1331
}
 
1332
 
 
1333
QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
 
1334
{
 
1335
    if (m_data.hwnd)
 
1336
        return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos);
 
1337
    else
 
1338
        return pos;
 
1339
}
 
1340
 
 
1341
#ifndef Q_OS_WINCE
 
1342
static inline HWND transientParentHwnd(HWND hwnd)
 
1343
{
 
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;
 
1348
    }
 
1349
    return 0;
 
1350
}
 
1351
#endif // !Q_OS_WINCE
 
1352
 
 
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
 
1358
{
 
1359
#ifndef Q_OS_WINCE
 
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
 
1372
}
 
1373
 
 
1374
static inline bool testShowWithoutActivating(const QWindow *window)
 
1375
{
 
1376
    // QWidget-attribute Qt::WA_ShowWithoutActivating .
 
1377
    const QVariant showWithoutActivating = window->property("_q_showWithoutActivating");
 
1378
    return showWithoutActivating.isValid() && showWithoutActivating.toBool();
 
1379
}
 
1380
 
 
1381
// partially from QWidgetPrivate::show_sys()
 
1382
void QWindowsWindow::show_sys() const
 
1383
{
 
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;
 
1393
            if (!isVisible())
 
1394
                sm = SW_SHOWMINNOACTIVE;
 
1395
        } else {
 
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);
 
1408
                }
 
1409
            } // Qt::WindowMaximized
 
1410
        } // !Qt::WindowMinimized
 
1411
    }
 
1412
    if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool || testShowWithoutActivating(w))
 
1413
        sm = SW_SHOWNOACTIVATE;
 
1414
 
 
1415
    if (w->windowState() & Qt::WindowMaximized)
 
1416
        setFlag(WithinMaximize); // QTBUG-8361
 
1417
 
 
1418
    ShowWindow(m_data.hwnd, sm);
 
1419
 
 
1420
    clearFlag(WithinMaximize);
 
1421
 
 
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);
 
1427
    }
 
1428
}
 
1429
 
 
1430
void QWindowsWindow::setParent(const QPlatformWindow *newParent)
 
1431
{
 
1432
    qCDebug(lcQpaWindows) << __FUNCTION__ << window() << newParent;
 
1433
 
 
1434
    if (m_data.hwnd)
 
1435
        setParent_sys(newParent);
 
1436
}
 
1437
 
 
1438
void QWindowsWindow::setParent_sys(const QPlatformWindow *parent)
 
1439
{
 
1440
    // Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels
 
1441
    HWND oldParentHWND = parentHwnd();
 
1442
    HWND newParentHWND = 0;
 
1443
    if (parent) {
 
1444
        const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
 
1445
        newParentHWND = parentW->handle();
 
1446
 
 
1447
    }
 
1448
 
 
1449
    // NULL handle means desktop window, which also has its proper handle -> disambiguate
 
1450
    HWND desktopHwnd = GetDesktopWindow();
 
1451
    if (oldParentHWND == desktopHwnd)
 
1452
        oldParentHWND = 0;
 
1453
    if (newParentHWND == desktopHwnd)
 
1454
        newParentHWND = 0;
 
1455
 
 
1456
    if (newParentHWND != oldParentHWND) {
 
1457
        const bool wasTopLevel = oldParentHWND == 0;
 
1458
        const bool isTopLevel = newParentHWND == 0;
 
1459
 
 
1460
        setFlag(WithinSetParent);
 
1461
        SetParent(m_data.hwnd, newParentHWND);
 
1462
        clearFlag(WithinSetParent);
 
1463
 
 
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);
 
1471
        }
 
1472
    }
 
1473
}
 
1474
 
 
1475
void QWindowsWindow::handleHidden()
 
1476
{
 
1477
    fireExpose(QRegion());
 
1478
}
 
1479
 
 
1480
void QWindowsWindow::handleCompositionSettingsChanged()
 
1481
{
 
1482
    const QWindow *w = window();
 
1483
    if (w->surfaceType() == QWindow::OpenGLSurface && w->format().hasAlpha())
 
1484
        applyBlurBehindWindow(handle());
 
1485
}
 
1486
 
 
1487
static QRect normalFrameGeometry(HWND hwnd)
 
1488
{
 
1489
#ifndef Q_OS_WINCE
 
1490
    WINDOWPLACEMENT wp;
 
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()));
 
1495
    }
 
1496
#else
 
1497
    Q_UNUSED(hwnd)
 
1498
#endif
 
1499
    return QRect();
 
1500
}
 
1501
 
 
1502
QRect QWindowsWindow::normalGeometry() const
 
1503
{
 
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;
 
1509
}
 
1510
 
 
1511
void QWindowsWindow::setGeometry(const QRect &rectIn)
 
1512
{
 
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()));
 
1519
    }
 
1520
    if (m_windowState == Qt::WindowMinimized)
 
1521
        m_data.geometry = rect; // Otherwise set by handleGeometryChange() triggered by event.
 
1522
    if (m_data.hwnd) {
 
1523
        // A ResizeEvent with resulting geometry will be sent. If we cannot
 
1524
        // achieve that size (for example, window title minimal constraint),
 
1525
        // notify and warn.
 
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).",
 
1532
                     __FUNCTION__,
 
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());
 
1543
        }
 
1544
    } else {
 
1545
        QPlatformWindow::setGeometry(rect);
 
1546
    }
 
1547
}
 
1548
 
 
1549
void QWindowsWindow::handleMoved()
 
1550
{
 
1551
    // Minimize/Set parent can send nonsensical move events.
 
1552
    if (!IsIconic(m_data.hwnd) && !testFlag(WithinSetParent))
 
1553
        handleGeometryChange();
 
1554
}
 
1555
 
 
1556
void QWindowsWindow::handleResized(int wParam)
 
1557
{
 
1558
    switch (wParam) {
 
1559
    case SIZE_MAXHIDE: // Some other window affected.
 
1560
    case SIZE_MAXSHOW:
 
1561
        return;
 
1562
    case SIZE_MINIMIZED:
 
1563
        handleWindowStateChange(Qt::WindowMinimized);
 
1564
        return;
 
1565
    case SIZE_MAXIMIZED:
 
1566
        handleWindowStateChange(Qt::WindowMaximized);
 
1567
        handleGeometryChange();
 
1568
        break;
 
1569
    case SIZE_RESTORED:
 
1570
        if (isFullScreen_sys())
 
1571
            handleWindowStateChange(Qt::WindowFullScreen);
 
1572
        else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen))
 
1573
            handleWindowStateChange(Qt::WindowNoState);
 
1574
        handleGeometryChange();
 
1575
        break;
 
1576
    }
 
1577
}
 
1578
 
 
1579
void QWindowsWindow::handleGeometryChange()
 
1580
{
 
1581
    //Prevent recursive resizes for Windows CE
 
1582
    if (testFlag(WithinSetStyle))
 
1583
        return;
 
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);
 
1595
    }
 
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());
 
1600
    }
 
1601
    if (testFlag(SynchronousGeometryChangeEvent))
 
1602
        QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
 
1603
 
 
1604
    qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry;
 
1605
}
 
1606
 
 
1607
void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const
 
1608
{
 
1609
    const QMargins margins = frameMargins();
 
1610
    const QRect frameGeometry = rect + margins;
 
1611
 
 
1612
    qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << window()
 
1613
        << "\n from " << geometry_sys() << " frame: "
 
1614
        << margins << " to " <<rect
 
1615
        << " new frame: " << frameGeometry;
 
1616
 
 
1617
    bool result = false;
 
1618
#ifndef Q_OS_WINCE
 
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);
 
1631
    } else
 
1632
#endif // !Q_OS_WINCE
 
1633
    {
 
1634
        result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(),
 
1635
                            frameGeometry.width(), frameGeometry.height(), true);
 
1636
    }
 
1637
    qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window()
 
1638
        << "\n resulting " << result << geometry_sys();
 
1639
}
 
1640
 
 
1641
/*!
 
1642
    Allocates a HDC for the window or returns the temporary one
 
1643
    obtained from WinAPI BeginPaint within a WM_PAINT event.
 
1644
 
 
1645
    \sa releaseDC()
 
1646
*/
 
1647
 
 
1648
HDC QWindowsWindow::getDC()
 
1649
{
 
1650
    if (!m_hdc)
 
1651
        m_hdc = GetDC(handle());
 
1652
    return m_hdc;
 
1653
}
 
1654
 
 
1655
/*!
 
1656
    Relases the HDC for the window or does nothing in
 
1657
    case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
 
1658
 
 
1659
    \sa getDC()
 
1660
*/
 
1661
 
 
1662
void QWindowsWindow::releaseDC()
 
1663
{
 
1664
    if (m_hdc) {
 
1665
        ReleaseDC(handle(), m_hdc);
 
1666
        m_hdc = 0;
 
1667
    }
 
1668
}
 
1669
 
 
1670
bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
 
1671
                                         WPARAM, LPARAM)
 
1672
{
 
1673
    if (message == WM_ERASEBKGND) // Backing store - ignored.
 
1674
        return true;
 
1675
    // Ignore invalid update bounding rectangles
 
1676
    if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
 
1677
        return false;
 
1678
    PAINTSTRUCT ps;
 
1679
 
 
1680
    BeginPaint(hwnd, &ps);
 
1681
 
 
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);
 
1686
 
 
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);
 
1693
 
 
1694
    EndPaint(hwnd, &ps);
 
1695
    return true;
 
1696
}
 
1697
 
 
1698
void QWindowsWindow::setWindowTitle(const QString &title)
 
1699
{
 
1700
    setWindowTitle_sys(QWindowsWindow::formatWindowTitle(title));
 
1701
}
 
1702
 
 
1703
void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
 
1704
{
 
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;
 
1710
        if (m_data.hwnd) {
 
1711
            m_data = setWindowFlags_sys(flags);
 
1712
            updateDropSite(window()->isTopLevel());
 
1713
        }
 
1714
    }
 
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();
 
1722
 
 
1723
    qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << "\n    returns: "
 
1724
        << m_data.flags << " geometry " << oldGeometry << "->" << newGeometry;
 
1725
}
 
1726
 
 
1727
QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
 
1728
                                                              unsigned flags) const
 
1729
{
 
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);
 
1734
 
 
1735
    QWindowsWindowData result = m_data;
 
1736
    result.flags = creationData.flags;
 
1737
    result.embedded = creationData.embedded;
 
1738
    setFlag(FrameDirty);
 
1739
    return result;
 
1740
}
 
1741
 
 
1742
void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
 
1743
{
 
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);
 
1749
    switch (state) {
 
1750
    case Qt::WindowMinimized:
 
1751
        handleHidden();
 
1752
        QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); // Tell QQuickWindow to stop rendering now.
 
1753
        break;
 
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;
 
1761
        if (isLayered()) {
 
1762
            fireExpose(QRegion(0, 0, w->width(), w->height()));
 
1763
            exposeEventsSent = true;
 
1764
        }
 
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;
 
1771
                }
 
1772
            }
 
1773
        }
 
1774
        if (exposeEventsSent && !QWindowsContext::instance()->asyncExpose())
 
1775
            QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents);
 
1776
    }
 
1777
        break;
 
1778
    default:
 
1779
        break;
 
1780
    }
 
1781
}
 
1782
 
 
1783
void QWindowsWindow::setWindowState(Qt::WindowState state)
 
1784
{
 
1785
    if (m_data.hwnd) {
 
1786
        setWindowState_sys(state);
 
1787
        m_windowState = state;
 
1788
    }
 
1789
}
 
1790
 
 
1791
bool QWindowsWindow::isFullScreen_sys() const
 
1792
{
 
1793
    const QWindow *w = window();
 
1794
    if (!w->isTopLevel())
 
1795
        return false;
 
1796
    const QScreen *screen = w->screen();
 
1797
    if (!screen)
 
1798
        screen = QGuiApplication::primaryScreen();
 
1799
    return screen && geometry_sys() == QHighDpi::toNativePixels(screen->geometry(), w);
 
1800
}
 
1801
 
 
1802
/*!
 
1803
    \brief Change the window state.
 
1804
 
 
1805
    \note Window frames change when maximized;
 
1806
    the top margin shrinks somewhat but that cannot be obtained using
 
1807
    AdjustWindowRectEx().
 
1808
 
 
1809
    \note Some calls to SetWindowLong require a subsequent call
 
1810
    to ShowWindow.
 
1811
*/
 
1812
 
 
1813
void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
 
1814
{
 
1815
    const Qt::WindowState oldState = m_windowState;
 
1816
    if (oldState == newState)
 
1817
        return;
 
1818
    qCDebug(lcQpaWindows) << '>' << __FUNCTION__ << this << window()
 
1819
        << " from " << oldState << " to " << newState;
 
1820
 
 
1821
    const bool visible = isVisible();
 
1822
 
 
1823
    setFlag(FrameDirty);
 
1824
 
 
1825
    if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
 
1826
#ifdef Q_OS_WINCE
 
1827
        HWND handle = FindWindow(L"HHTaskBar", L"");
 
1828
        if (handle) {
 
1829
            if (newState == Qt::WindowFullScreen) {
 
1830
                BOOL hidden = ShowWindow(handle, SW_HIDE);
 
1831
                if (!hidden)
 
1832
                    m_previouslyHidden = true;
 
1833
            } else if (!m_previouslyHidden){
 
1834
                ShowWindow(handle, SW_SHOW);
 
1835
            }
 
1836
        }
 
1837
#endif
 
1838
        if (newState == Qt::WindowFullScreen) {
 
1839
#ifndef Q_FLATTEN_EXPOSE
 
1840
            UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
 
1841
#else
 
1842
            UINT newStyle = WS_POPUP;
 
1843
#endif
 
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();
 
1849
#ifndef Q_OS_WINCE
 
1850
                if (oldState == Qt::WindowMinimized || oldState == Qt::WindowMaximized) {
 
1851
                    const QRect nf = normalFrameGeometry(m_data.hwnd);
 
1852
                    if (nf.isValid())
 
1853
                        m_savedFrameGeometry = nf;
 
1854
                } else {
 
1855
#endif
 
1856
                    m_savedFrameGeometry = frameGeometry_sys();
 
1857
#ifndef Q_OS_WINCE
 
1858
                }
 
1859
#endif
 
1860
            }
 
1861
            if (m_savedStyle & WS_SYSMENU)
 
1862
                newStyle |= WS_SYSMENU;
 
1863
            if (visible)
 
1864
                newStyle |= WS_VISIBLE;
 
1865
            if (testFlag(HasBorderInFullScreen))
 
1866
                newStyle |= WS_BORDER;
 
1867
            setStyle(newStyle);
 
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();
 
1871
            if (!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);
 
1878
            if (!wasSync)
 
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();
 
1885
            if (visible)
 
1886
                newStyle |= WS_VISIBLE;
 
1887
            setStyle(newStyle);
 
1888
 
 
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);
 
1900
            if (!wasSync)
 
1901
                clearFlag(SynchronousGeometryChangeEvent);
 
1902
            // preserve maximized state
 
1903
            if (visible) {
 
1904
                setFlag(WithinMaximize);
 
1905
                ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNA);
 
1906
                clearFlag(WithinMaximize);
 
1907
            }
 
1908
            m_savedStyle = 0;
 
1909
            m_savedFrameGeometry = QRect();
 
1910
        }
 
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);
 
1919
        }
 
1920
    }
 
1921
 
 
1922
    if ((oldState == Qt::WindowMinimized) != (newState == Qt::WindowMinimized)) {
 
1923
        if (visible)
 
1924
            ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE :
 
1925
                       (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNORMAL);
 
1926
    }
 
1927
    qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << this << window() << newState;
 
1928
}
 
1929
 
 
1930
void QWindowsWindow::setStyle(unsigned s) const
 
1931
{
 
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);
 
1937
}
 
1938
 
 
1939
void QWindowsWindow::setExStyle(unsigned s) const
 
1940
{
 
1941
    qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
 
1942
        << " 0x" << QByteArray::number(s, 16);
 
1943
    setFlag(FrameDirty);
 
1944
    SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
 
1945
}
 
1946
 
 
1947
void QWindowsWindow::windowEvent(QEvent *event)
 
1948
{
 
1949
    switch (event->type()) {
 
1950
    case QEvent::WindowBlocked: // Blocked by another modal window.
 
1951
        setEnabled(false);
 
1952
        setFlag(BlockedByModal);
 
1953
        if (hasMouseCapture())
 
1954
            ReleaseCapture();
 
1955
        break;
 
1956
    case QEvent::WindowUnblocked:
 
1957
        setEnabled(true);
 
1958
        clearFlag(BlockedByModal);
 
1959
        break;
 
1960
    default:
 
1961
        break;
 
1962
    }
 
1963
}
 
1964
 
 
1965
void QWindowsWindow::propagateSizeHints()
 
1966
{
 
1967
    qCDebug(lcQpaWindows) << __FUNCTION__ << this << window();
 
1968
}
 
1969
 
 
1970
bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins)
 
1971
{
 
1972
#ifndef Q_OS_WINCE
 
1973
    if (!qWindow->isTopLevel()) // Implement hasHeightForWidth().
 
1974
        return false;
 
1975
    WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam);
 
1976
    if ((windowPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE)))
 
1977
        return false;
 
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())
 
1983
        return false;
 
1984
    const QRect correctedFrameGeometry = correctedGeometryF.toRect() + margins;
 
1985
    if (correctedFrameGeometry == suggestedFrameGeometry)
 
1986
        return false;
 
1987
    windowPos->x = correctedFrameGeometry.left();
 
1988
    windowPos->y = correctedFrameGeometry.top();
 
1989
    windowPos->cx = correctedFrameGeometry.width();
 
1990
    windowPos->cy = correctedFrameGeometry.height();
 
1991
    return true;
 
1992
#else // !Q_OS_WINCE
 
1993
    Q_UNUSED(message)
 
1994
    return false;
 
1995
#endif
 
1996
}
 
1997
 
 
1998
bool QWindowsWindow::handleGeometryChanging(MSG *message) const
 
1999
{
 
2000
    const QMargins margins = window()->isTopLevel() ? frameMargins() : QMargins();
 
2001
    return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins);
 
2002
}
 
2003
 
 
2004
QMargins QWindowsWindow::frameMargins() const
 
2005
{
 
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);
 
2018
    }
 
2019
    return m_data.frame + m_data.customMargins;
 
2020
}
 
2021
 
 
2022
void QWindowsWindow::setOpacity(qreal level)
 
2023
{
 
2024
    qCDebug(lcQpaWindows) << __FUNCTION__ << level;
 
2025
    if (!qFuzzyCompare(m_opacity, level)) {
 
2026
        m_opacity = level;
 
2027
        if (m_data.hwnd)
 
2028
            setWindowOpacity(m_data.hwnd, m_data.flags,
 
2029
                             window()->format().hasAlpha(), testFlag(OpenGLSurface),
 
2030
                             level);
 
2031
    }
 
2032
}
 
2033
 
 
2034
static inline HRGN createRectRegion(const QRect &r)
 
2035
{
 
2036
    return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
 
2037
}
 
2038
 
 
2039
static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
 
2040
{
 
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;
 
2046
        }
 
2047
        DeleteObject(rectRegion);
 
2048
    }
 
2049
}
 
2050
 
 
2051
static HRGN qRegionToWinRegion(const QRegion &region)
 
2052
{
 
2053
    const QVector<QRect> rects = region.rects();
 
2054
    if (rects.isEmpty())
 
2055
        return NULL;
 
2056
    const int rectCount = rects.size();
 
2057
    if (rectCount == 1)
 
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);
 
2062
    return hRegion;
 
2063
}
 
2064
 
 
2065
void QWindowsWindow::setMask(const QRegion &region)
 
2066
{
 
2067
    if (region.isEmpty()) {
 
2068
         SetWindowRgn(m_data.hwnd, 0, true);
 
2069
         return;
 
2070
    }
 
2071
    const HRGN winRegion = qRegionToWinRegion(region);
 
2072
 
 
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());
 
2077
    }
 
2078
 
 
2079
    // SetWindowRgn takes ownership.
 
2080
    if (!SetWindowRgn(m_data.hwnd, winRegion, true))
 
2081
        DeleteObject(winRegion);
 
2082
}
 
2083
 
 
2084
void QWindowsWindow::requestActivateWindow()
 
2085
{
 
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.
 
2089
    if (m_data.hwnd) {
 
2090
#ifndef Q_OS_WINCE
 
2091
        const DWORD currentThread = GetCurrentThreadId();
 
2092
        bool attached = false;
 
2093
        DWORD foregroundThread = 0;
 
2094
 
 
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;
 
2105
            }
 
2106
        }
 
2107
#endif // !Q_OS_WINCE
 
2108
        SetForegroundWindow(m_data.hwnd);
 
2109
        SetFocus(m_data.hwnd);
 
2110
#ifndef Q_OS_WINCE
 
2111
        if (attached)
 
2112
            AttachThreadInput(foregroundThread, currentThread, FALSE);
 
2113
#endif // !Q_OS_WINCE
 
2114
    }
 
2115
}
 
2116
 
 
2117
bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
 
2118
{
 
2119
    if (!m_data.hwnd) {
 
2120
        qWarning("%s: No handle", __FUNCTION__);
 
2121
        return false;
 
2122
    }
 
2123
    qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << grab;
 
2124
 
 
2125
    QWindowsContext *context = QWindowsContext::instance();
 
2126
    if (grab) {
 
2127
        context->setKeyGrabber(window());
 
2128
    } else {
 
2129
        if (context->keyGrabber() == window())
 
2130
            context->setKeyGrabber(0);
 
2131
    }
 
2132
    return true;
 
2133
}
 
2134
 
 
2135
bool QWindowsWindow::setMouseGrabEnabled(bool grab)
 
2136
{
 
2137
    qCDebug(lcQpaWindows) << __FUNCTION__ << window() << grab;
 
2138
    if (!m_data.hwnd) {
 
2139
        qWarning("%s: No handle", __FUNCTION__);
 
2140
        return false;
 
2141
    }
 
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()));
 
2146
        return false;
 
2147
    }
 
2148
    // release grab or an explicit grab overriding autocapture: Clear flag.
 
2149
    clearFlag(QWindowsWindow::AutoMouseCapture);
 
2150
    if (hasMouseCapture() != grab) {
 
2151
        if (grab) {
 
2152
            SetCapture(m_data.hwnd);
 
2153
        } else {
 
2154
            ReleaseCapture();
 
2155
        }
 
2156
    }
 
2157
    return grab;
 
2158
}
 
2159
 
 
2160
static inline DWORD cornerToWinOrientation(Qt::Corner corner)
 
2161
{
 
2162
    switch (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
 
2171
    }
 
2172
    return 0;
 
2173
}
 
2174
 
 
2175
bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
 
2176
{
 
2177
    if (!GetSystemMenu(m_data.hwnd, FALSE))
 
2178
        return false;
 
2179
 
 
2180
    ReleaseCapture();
 
2181
    PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
 
2182
    setFlag(SizeGripOperation);
 
2183
    return true;
 
2184
}
 
2185
 
 
2186
void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
 
2187
{
 
2188
    if (enabled) {
 
2189
        setFlag(FrameStrutEventsEnabled);
 
2190
    } else {
 
2191
        clearFlag(FrameStrutEventsEnabled);
 
2192
    }
 
2193
}
 
2194
 
 
2195
#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
 
2196
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
 
2197
{
 
2198
    const QWindowsGeometryHint hint(window(), m_data.customMargins);
 
2199
    hint.applyToMinMaxInfo(m_data.hwnd, mmi);
 
2200
 
 
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();
 
2206
 
 
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();
 
2211
 
 
2212
            // Width, because you can have the taskbar on the sides too.
 
2213
            mmi->ptMaxSize.x = availableGeometry.width();
 
2214
 
 
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");
 
2220
        }
 
2221
    }
 
2222
 
 
2223
    qCDebug(lcQpaWindows) << __FUNCTION__ << window() << *mmi;
 
2224
}
 
2225
 
 
2226
bool QWindowsWindow::handleNonClientHitTest(const QPoint &globalPos, LRESULT *result) const
 
2227
{
 
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)) {
 
2233
        return false;
 
2234
    }
 
2235
    const QSize minimumSize = w->minimumSize();
 
2236
    if (minimumSize.isEmpty())
 
2237
        return false;
 
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)
 
2242
        return false;
 
2243
    const QPoint localPos = w->mapFromGlobal(QHighDpi::fromNativePixels(globalPos, w));
 
2244
    const QSize size = w->size();
 
2245
    if (fixedHeight) {
 
2246
        if (localPos.y() >= size.height()) {
 
2247
            *result = HTBORDER; // Unspecified border, no resize cursor.
 
2248
            return true;
 
2249
        }
 
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.
 
2255
                return true;
 
2256
            }
 
2257
        }
 
2258
    }
 
2259
    if (fixedWidth && (localPos.x() < 0 || localPos.x() >= size.width())) {
 
2260
        *result = HTBORDER; // Unspecified border, no resize cursor.
 
2261
        return true;
 
2262
    }
 
2263
    return false;
 
2264
}
 
2265
 
 
2266
#endif // !Q_OS_WINCE
 
2267
 
 
2268
#ifndef QT_NO_CURSOR
 
2269
// Return the default cursor (Arrow) from QWindowsCursor's cache.
 
2270
static inline CursorHandlePtr defaultCursor(const QWindow *w)
 
2271
{
 
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)));
 
2277
}
 
2278
 
 
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)
 
2283
{
 
2284
    const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse();
 
2285
    if (underMouse == w)
 
2286
        return true;
 
2287
    for (const QWindow *p = underMouse; p ; p = p->parent()) {
 
2288
        if (p == w)
 
2289
            return true;
 
2290
        const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p);
 
2291
        if (platformWindow && !platformWindow->cursor()->isNull())
 
2292
            return false;
 
2293
    }
 
2294
    return false;
 
2295
}
 
2296
#endif // !QT_NO_CURSOR
 
2297
 
 
2298
/*!
 
2299
    \brief Applies to cursor property set on the window to the global cursor.
 
2300
 
 
2301
    \sa QWindowsCursor
 
2302
*/
 
2303
 
 
2304
void QWindowsWindow::applyCursor()
 
2305
{
 
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();
 
2311
        } else {
 
2312
            SetCursor(defaultCursor(window())->handle());
 
2313
        }
 
2314
    } else {
 
2315
        SetCursor(m_cursor->handle());
 
2316
    }
 
2317
#endif
 
2318
}
 
2319
 
 
2320
void QWindowsWindow::setCursor(const CursorHandlePtr &c)
 
2321
{
 
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;
 
2327
        m_cursor = c;
 
2328
        if (apply)
 
2329
            applyCursor();
 
2330
    }
 
2331
#endif
 
2332
}
 
2333
 
 
2334
#ifndef Q_OS_WINCE
 
2335
void QWindowsWindow::setAlertState(bool enabled)
 
2336
{
 
2337
    if (isAlertState() == enabled)
 
2338
        return;
 
2339
    if (enabled) {
 
2340
        alertWindow(0);
 
2341
        setFlag(AlertState);
 
2342
    } else {
 
2343
        stopAlertWindow();
 
2344
        clearFlag(AlertState);
 
2345
    }
 
2346
}
 
2347
 
 
2348
void QWindowsWindow::alertWindow(int durationMs)
 
2349
{
 
2350
    UINT timeOutMs = GetCaretBlinkTime();
 
2351
    if (!timeOutMs || timeOutMs == INFINITE)
 
2352
        timeOutMs = 250;
 
2353
 
 
2354
    FLASHWINFO info;
 
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);
 
2361
}
 
2362
 
 
2363
void QWindowsWindow::stopAlertWindow()
 
2364
{
 
2365
    FLASHWINFO info;
 
2366
    info.cbSize = sizeof(info);
 
2367
    info.hwnd = m_data.hwnd;
 
2368
    info.dwFlags = FLASHW_STOP;
 
2369
    info.dwTimeout = 0;
 
2370
    info.uCount = 0;
 
2371
    FlashWindowEx(&info);
 
2372
}
 
2373
#endif // !Q_OS_WINCE
 
2374
 
 
2375
bool QWindowsWindow::isEnabled() const
 
2376
{
 
2377
    return (style() & WS_DISABLED) == 0;
 
2378
}
 
2379
 
 
2380
void QWindowsWindow::setEnabled(bool enabled)
 
2381
{
 
2382
    const unsigned oldStyle = style();
 
2383
    unsigned newStyle = oldStyle;
 
2384
    if (enabled) {
 
2385
        newStyle &= ~WS_DISABLED;
 
2386
    } else {
 
2387
        newStyle |= WS_DISABLED;
 
2388
    }
 
2389
    if (newStyle != oldStyle)
 
2390
        setStyle(newStyle);
 
2391
}
 
2392
 
 
2393
static HICON createHIcon(const QIcon &icon, int xSize, int ySize)
 
2394
{
 
2395
    if (!icon.isNull()) {
 
2396
        const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
 
2397
        if (!pm.isNull())
 
2398
            return qt_pixmapToWinHICON(pm);
 
2399
    }
 
2400
    return 0;
 
2401
}
 
2402
 
 
2403
void QWindowsWindow::setWindowIcon(const QIcon &icon)
 
2404
{
 
2405
    if (m_data.hwnd) {
 
2406
        destroyIcon();
 
2407
 
 
2408
        m_iconSmall = createHIcon(icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
 
2409
        m_iconBig = createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
 
2410
 
 
2411
        if (m_iconBig) {
 
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));
 
2414
        } else {
 
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));
 
2417
        }
 
2418
    }
 
2419
}
 
2420
 
 
2421
bool QWindowsWindow::isTopLevel() const
 
2422
{
 
2423
    return window()->isTopLevel() && !m_data.embedded;
 
2424
}
 
2425
 
 
2426
/*!
 
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.
 
2429
 
 
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()).
 
2434
*/
 
2435
 
 
2436
void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
 
2437
{
 
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);
 
2450
    }
 
2451
}
 
2452
 
 
2453
void *QWindowsWindow::surface(void *nativeConfig, int *err)
 
2454
{
 
2455
#ifdef QT_NO_OPENGL
 
2456
    Q_UNUSED(err)
 
2457
    Q_UNUSED(nativeConfig)
 
2458
    return 0;
 
2459
#else
 
2460
    if (!m_surface) {
 
2461
        if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
 
2462
            m_surface = staticOpenGLContext->createWindowSurface(m_data.hwnd, nativeConfig, err);
 
2463
    }
 
2464
 
 
2465
    return m_surface;
 
2466
#endif
 
2467
}
 
2468
 
 
2469
void QWindowsWindow::invalidateSurface()
 
2470
{
 
2471
#ifndef QT_NO_OPENGL
 
2472
    if (m_surface) {
 
2473
        if (QWindowsStaticOpenGLContext *staticOpenGLContext = QWindowsIntegration::staticOpenGLContext())
 
2474
            staticOpenGLContext->destroyWindowSurface(m_surface);
 
2475
        m_surface = 0;
 
2476
    }
 
2477
#endif // QT_NO_OPENGL
 
2478
}
 
2479
 
 
2480
void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
 
2481
{
 
2482
    if (!window->handle())
 
2483
        return;
 
2484
    static_cast<QWindowsWindow *>(window->handle())->registerTouchWindow(touchTypes);
 
2485
}
 
2486
 
 
2487
void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes)
 
2488
{
 
2489
#ifndef Q_OS_WINCE
 
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)
 
2496
            return;
 
2497
        if (QWindowsContext::user32dll.registerTouchWindow(m_data.hwnd, ULONG(touchTypes)))
 
2498
            setFlag(TouchRegistered);
 
2499
        else
 
2500
            qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
 
2501
    }
 
2502
#endif // !Q_OS_WINCE
 
2503
}
 
2504
 
 
2505
void QWindowsWindow::aboutToMakeCurrent()
 
2506
{
 
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)) {
 
2513
        if (isCompositing)
 
2514
            setFlag(Compositing);
 
2515
        else
 
2516
            clearFlag(Compositing);
 
2517
 
 
2518
        updateGLWindowSettings(window(), m_data.hwnd, m_data.flags, m_opacity);
 
2519
    }
 
2520
#endif
 
2521
}
 
2522
 
 
2523
void QWindowsWindow::setHasBorderInFullScreenStatic(QWindow *window, bool border)
 
2524
{
 
2525
    if (QPlatformWindow *handle = window->handle())
 
2526
        static_cast<QWindowsWindow *>(handle)->setHasBorderInFullScreen(border);
 
2527
    else
 
2528
        qWarning("%s invoked without window handle; call has no effect.", Q_FUNC_INFO);
 
2529
}
 
2530
 
 
2531
void QWindowsWindow::setHasBorderInFullScreen(bool border)
 
2532
{
 
2533
    if (border)
 
2534
        setFlag(HasBorderInFullScreen);
 
2535
    else
 
2536
        clearFlag(HasBorderInFullScreen);
 
2537
}
 
2538
 
 
2539
QString QWindowsWindow::formatWindowTitle(const QString &title)
 
2540
{
 
2541
    return QPlatformWindow::formatWindowTitle(title, QStringLiteral(" - "));
 
2542
}
 
2543
 
 
2544
QT_END_NAMESPACE