QWindowsWindow: fix restoring from minimized to fullscreen
[profile/ivi/qtbase.git] / src / plugins / platforms / windows / qwindowswindow.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwindowswindow.h"
43 #include "qwindowsnativeimage.h"
44 #include "qwindowscontext.h"
45 #include "qwindowsdrag.h"
46 #include "qwindowsscreen.h"
47 #include "qwindowscursor.h"
48
49 #ifdef QT_OPENGL_ES_2
50 #  include "qwindowseglcontext.h"
51 #endif
52
53 #include <QtGui/QGuiApplication>
54 #include <QtGui/QScreen>
55 #include <QtGui/QWindow>
56 #include <QtGui/QRegion>
57 #include <private/qwindow_p.h>
58 #include <qpa/qwindowsysteminterface.h>
59
60 #include <QtCore/QDebug>
61
62 QT_BEGIN_NAMESPACE
63
64 static QByteArray debugWinStyle(DWORD style)
65 {
66     QByteArray rc = "0x";
67     rc += QByteArray::number(qulonglong(style), 16);
68     if (style & WS_POPUP)
69         rc += " WS_POPUP";
70     if (style & WS_CHILD)
71         rc += " WS_CHILD";
72     if (style & WS_OVERLAPPED)
73         rc += " WS_OVERLAPPED";
74     if (style & WS_CLIPSIBLINGS)
75         rc += " WS_CLIPSIBLINGS";
76     if (style & WS_CLIPCHILDREN)
77         rc += " WS_CLIPCHILDREN";
78     if (style & WS_THICKFRAME)
79         rc += " WS_THICKFRAME";
80     if (style & WS_DLGFRAME)
81         rc += " WS_DLGFRAME";
82     if (style & WS_SYSMENU)
83         rc += " WS_SYSMENU";
84     if (style & WS_MINIMIZEBOX)
85         rc += " WS_MINIMIZEBOX";
86     if (style & WS_MAXIMIZEBOX)
87         rc += " WS_MAXIMIZEBOX";
88     return rc;
89 }
90
91 static QByteArray debugWinExStyle(DWORD exStyle)
92 {
93     QByteArray rc = "0x";
94     rc += QByteArray::number(qulonglong(exStyle), 16);
95     if (exStyle & WS_EX_TOOLWINDOW)
96         rc += " WS_EX_TOOLWINDOW";
97     if (exStyle & WS_EX_CONTEXTHELP)
98         rc += " WS_EX_CONTEXTHELP";
99     if (exStyle & WS_EX_LAYERED)
100         rc += " WS_EX_LAYERED";
101     return rc;
102 }
103
104 static QByteArray debugWindowStates(Qt::WindowStates s)
105 {
106
107     QByteArray rc = "0x";
108     rc += QByteArray::number(int(s), 16);
109     if (s & Qt::WindowMinimized)
110         rc += " WindowMinimized";
111     if (s & Qt::WindowMaximized)
112         rc += " WindowMaximized";
113     if (s & Qt::WindowFullScreen)
114         rc += " WindowFullScreen";
115     if (s & Qt::WindowActive)
116         rc += " WindowActive";
117     return rc;
118 }
119
120 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
121 QDebug operator<<(QDebug d, const MINMAXINFO &i)
122 {
123     d.nospace() << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ','
124                 << i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x
125                  << ',' << i.ptMaxPosition.y << " mintrack="
126                  << i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y
127                  << " maxtrack=" << i.ptMaxTrackSize.x << ','
128                  << i.ptMaxTrackSize.y;
129     return d;
130 }
131 #endif // !Q_OS_WINCE
132
133 static inline QSize qSizeOfRect(const RECT &rect)
134 {
135     return QSize(rect.right -rect.left, rect.bottom - rect.top);
136 }
137
138 static inline QRect qrectFromRECT(const RECT &rect)
139 {
140     return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect));
141 }
142
143 static inline RECT RECTfromQRect(const QRect &rect)
144 {
145     const int x = rect.left();
146     const int y = rect.top();
147     RECT result = { x, y, x + rect.width(), y + rect.height() };
148     return result;
149 }
150
151 QDebug operator<<(QDebug d, const RECT &r)
152 {
153     d.nospace() << "RECT: left/top=" << r.left << ',' << r.top
154                 << " right/bottom=" << r.right << ',' << r.bottom;
155     return d;
156 }
157
158 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_NCCALCSIZE
159 QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
160 {
161     qDebug().nospace() << "NCCALCSIZE_PARAMS "
162         << qrectFromRECT(p.rgrc[0])
163         << ' ' << qrectFromRECT(p.rgrc[1]) << ' '
164         << qrectFromRECT(p.rgrc[2]);
165     return d;
166 }
167 #endif // !Q_OS_WINCE
168
169 // Return the frame geometry relative to the parent
170 // if there is one.
171 static inline QRect frameGeometry(HWND hwnd, bool topLevel)
172 {
173     RECT rect = { 0, 0, 0, 0 };
174     GetWindowRect(hwnd, &rect); // Screen coordinates.
175     const HWND parent = GetParent(hwnd);
176     if (parent && !topLevel) {
177         const int width = rect.right - rect.left;
178         const int height = rect.bottom - rect.top;
179         POINT leftTop = { rect.left, rect.top };
180         ScreenToClient(parent, &leftTop);
181         rect.left = leftTop.x;
182         rect.top = leftTop.y;
183         rect.right = leftTop.x + width;
184         rect.bottom = leftTop.y + height;
185     }
186     return qrectFromRECT(rect);
187 }
188
189 static inline QSize clientSize(HWND hwnd)
190 {
191     RECT rect = { 0, 0, 0, 0 };
192     GetClientRect(hwnd, &rect); // Always returns point 0,0, thus unusable for geometry.
193     return qSizeOfRect(rect);
194 }
195
196 // from qwidget_win.cpp/maximum layout size check removed.
197 static bool shouldShowMaximizeButton(Qt::WindowFlags flags)
198 {
199     if (flags & Qt::MSWindowsFixedSizeDialogHint)
200         return false;
201     // if the user explicitly asked for the maximize button, we try to add
202     // it even if the window has fixed size.
203     if (flags & Qt::CustomizeWindowHint &&
204         flags & Qt::WindowMaximizeButtonHint)
205         return true;
206     return flags & Qt::WindowMaximizeButtonHint;
207 }
208
209 static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, qreal level)
210 {
211 #ifdef Q_OS_WINCE // maybe needs revisit WS_EX_LAYERED
212     Q_UNUSED(hwnd);
213     Q_UNUSED(flags);
214     Q_UNUSED(level);
215 #else
216     const long wl = GetWindowLong(hwnd, GWL_EXSTYLE);
217     const bool isOpaque = level == 1.0 && !(flags & Qt::WindowTransparentForInput);
218
219     if (isOpaque) {
220         if (wl & WS_EX_LAYERED)
221             SetWindowLong(hwnd, GWL_EXSTYLE, wl & ~WS_EX_LAYERED);
222     } else {
223         if ((wl & WS_EX_LAYERED) == 0)
224             SetWindowLong(hwnd, GWL_EXSTYLE, wl | WS_EX_LAYERED);
225         if (flags & Qt::FramelessWindowHint) {
226             BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA};
227             QWindowsContext::user32dll.updateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
228         } else {
229             QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, (int)(level * 255), LWA_ALPHA);
230         }
231     }
232 #endif // !Q_OS_WINCE
233 }
234
235 /*!
236     \class WindowCreationData
237     \brief Window creation code.
238
239     This struct gathers all information required to create a window.
240     Window creation is split in 3 steps:
241
242     \list
243     \li fromWindow() Gather all required information
244     \li create() Create the system handle.
245     \li initialize() Post creation initialization steps.
246     \endlist
247
248     The reason for this split is to also enable changing the QWindowFlags
249     by calling:
250
251     \list
252     \li fromWindow() Gather information and determine new system styles
253     \li applyWindowFlags() to apply the new window system styles.
254     \li initialize() Post creation initialization steps.
255     \endlist
256
257     Contains the window creation code formerly in qwidget_win.cpp.
258
259     \sa QWindowCreationContext
260     \internal
261     \ingroup qt-lighthouse-win
262 */
263
264 struct WindowCreationData
265 {
266     typedef QWindowsWindow::WindowData WindowData;
267     enum Flags { ForceChild = 0x1 };
268
269     WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0),
270         topLevel(false), popup(false), dialog(false), desktop(false),
271         tool(false), embedded(false) {}
272
273     void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0);
274     inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const;
275     inline void applyWindowFlags(HWND hwnd) const;
276     void initialize(HWND h, bool frameChange, qreal opacityLevel) const;
277
278     Qt::WindowFlags flags;
279     HWND parentHandle;
280     Qt::WindowType type;
281     unsigned style;
282     unsigned exStyle;
283     bool isGL;
284     bool topLevel;
285     bool popup;
286     bool dialog;
287     bool desktop;
288     bool tool;
289     bool embedded;
290 };
291
292 QDebug operator<<(QDebug debug, const WindowCreationData &d)
293 {
294     debug.nospace() << QWindowsWindow::debugWindowFlags(d.flags)
295         << " GL=" << d.isGL << " topLevel=" << d.topLevel << " popup="
296         << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop
297         << " embedded=" << d.embedded
298         << " tool=" << d.tool << " style=" << debugWinStyle(d.style)
299         << " exStyle=" << debugWinExStyle(d.exStyle)
300         << " parent=" << d.parentHandle;
301     return debug;
302 }
303
304 void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
305                                     unsigned creationFlags)
306 {
307     isGL = w->surfaceType() == QWindow::OpenGLSurface;
308     flags = flagsIn;
309
310     // Sometimes QWindow doesn't have a QWindow parent but does have a native parent window,
311     // e.g. in case of embedded ActiveQt servers. They should not be considered a top-level
312     // windows in such cases.
313     QVariant prop = w->property("_q_embedded_native_parent_handle");
314     if (prop.isValid()) {
315         embedded = true;
316         parentHandle = (HWND)prop.value<WId>();
317     }
318
319     topLevel = ((creationFlags & ForceChild) || embedded) ? false : w->isTopLevel();
320
321     if (topLevel && flags == 1) {
322         qWarning("Remove me: fixing toplevel window flags");
323         flags |= Qt::WindowTitleHint|Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint
324                 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
325     }
326
327     type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask);
328     switch (type) {
329     case Qt::Dialog:
330     case Qt::Sheet:
331         dialog = true;
332         break;
333     case Qt::Drawer:
334     case Qt::Tool:
335         tool = true;
336         break;
337     case Qt::Popup:
338         popup = true;
339         break;
340     case Qt::Desktop:
341         desktop = true;
342         break;
343     default:
344         break;
345     }
346     if ((flags & Qt::MSWindowsFixedSizeDialogHint))
347         dialog = true;
348
349     // Parent: Use transient parent for top levels.
350     if (popup) {
351         flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent.
352     } else if (!embedded) {
353         if (const QWindow *parentWindow = topLevel ? w->transientParent() : w->parent())
354             parentHandle = QWindowsWindow::handleOf(parentWindow);
355     }
356
357     if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
358         style = WS_POPUP;
359     } else if (topLevel && !desktop) {
360         if (flags & Qt::FramelessWindowHint)
361             style = WS_POPUP;                // no border
362         else if (flags & Qt::WindowTitleHint)
363             style = WS_OVERLAPPED;
364         else
365             style = 0;
366     } else {
367         style = WS_CHILD;
368     }
369
370     if (!desktop) {
371         // if (!testAttribute(Qt::WA_PaintUnclipped))
372         // ### Commented out for now as it causes some problems, but
373         // this should be correct anyway, so dig some more into this
374 #ifdef Q_FLATTEN_EXPOSE
375         if (isGL)
376             style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat
377 #else
378         style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
379 #endif
380         if (topLevel) {
381             if ((type == Qt::Window || dialog || tool)) {
382                 if (!(flags & Qt::FramelessWindowHint)) {
383                     style |= WS_POPUP;
384                     if (flags & Qt::MSWindowsFixedSizeDialogHint) {
385                         style |= WS_DLGFRAME;
386                     } else {
387                         style |= WS_THICKFRAME;
388                     }
389                     if (flags & Qt::WindowTitleHint)
390                         style |= WS_CAPTION; // Contains WS_DLGFRAME
391                 }
392                 if (flags & Qt::WindowSystemMenuHint)
393                     style |= WS_SYSMENU;
394                 if (flags & Qt::WindowMinimizeButtonHint)
395                     style |= WS_MINIMIZEBOX;
396                 if (shouldShowMaximizeButton(flags))
397                     style |= WS_MAXIMIZEBOX;
398                 if (tool)
399                     exStyle |= WS_EX_TOOLWINDOW;
400                 if (flags & Qt::WindowContextHelpButtonHint)
401                     exStyle |= WS_EX_CONTEXTHELP;
402             } else {
403                  exStyle |= WS_EX_TOOLWINDOW;
404             }
405
406 #ifndef Q_OS_WINCE
407             // make mouse events fall through this window
408             // NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
409             if (flagsIn & Qt::WindowTransparentForInput)
410                 exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
411 #endif
412         }
413     }
414 }
415
416 QWindowsWindow::WindowData
417     WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const
418 {
419     typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
420
421     WindowData result;
422     result.flags = flags;
423
424     if (desktop) {                        // desktop widget. No frame, hopefully?
425         result.hwnd = GetDesktopWindow();
426         result.geometry = frameGeometry(result.hwnd, true);
427         if (QWindowsContext::verboseWindows)
428             qDebug().nospace() << "Created desktop window " << w << result.hwnd;
429         return result;
430     }
431
432     const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
433
434     const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
435
436     if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
437         title = topLevel ? qAppName() : w->objectName();
438
439     const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
440     const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
441
442     // Capture events before CreateWindowEx() returns.
443     const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle));
444     QWindowsContext::instance()->setWindowCreationContext(context);
445
446     if (QWindowsContext::verboseWindows)
447         qDebug().nospace()
448                 << "CreateWindowEx: " << w << *this
449                 << " class=" <<windowClassName << " title=" << title
450                 << "\nrequested: " << geometry << ": "
451                 << context->frameWidth << 'x' <<  context->frameHeight
452                 << '+' << context->frameX << '+' << context->frameY;
453
454     result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
455                                  style,
456                                  context->frameX, context->frameY,
457                                  context->frameWidth, context->frameHeight,
458                                  parentHandle, NULL, appinst, NULL);
459     QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
460     if (QWindowsContext::verboseWindows)
461         qDebug().nospace()
462                 << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
463                 << context->obtainedGeometry << context->margins;
464
465     if (!result.hwnd) {
466         qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
467         return result;
468     }
469
470     result.geometry = context->obtainedGeometry;
471     result.frame = context->margins;
472     result.embedded = embedded;
473     return result;
474 }
475
476 void WindowCreationData::applyWindowFlags(HWND hwnd) const
477 {
478     // Keep enabled and visible from the current style.
479     const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
480     const LONG_PTR oldExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
481
482     const LONG_PTR newStyle = style | (oldStyle & (WS_DISABLED|WS_VISIBLE));
483     if (oldStyle != newStyle)
484         SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
485     const LONG_PTR newExStyle = exStyle;
486     if (newExStyle != oldExStyle)
487         SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
488     if (QWindowsContext::verboseWindows)
489         qDebug().nospace() << __FUNCTION__ << hwnd << *this
490         << "\n    Style from " << debugWinStyle(oldStyle) << "\n    to "
491         << debugWinStyle(newStyle) << "\n    ExStyle from "
492         << debugWinExStyle(oldExStyle) << " to "
493         << debugWinExStyle(newExStyle);
494 }
495
496 void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLevel) const
497 {
498     if (desktop || !hwnd)
499         return;
500     UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE;
501     if (frameChange)
502         swpFlags |= SWP_FRAMECHANGED;
503     if (topLevel) {
504         swpFlags |= SWP_NOACTIVATE;
505         if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
506             SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, swpFlags);
507             if (flags & Qt::WindowStaysOnBottomHint)
508                 qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
509         } else if (flags & Qt::WindowStaysOnBottomHint) {
510             SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags);
511         }
512         if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
513             HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
514             if (flags & Qt::WindowCloseButtonHint)
515                 EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
516             else
517                 EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
518         }
519
520         setWindowOpacity(hwnd, flags, opacityLevel);
521     } else { // child.
522         SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags);
523     }
524 }
525
526 /*!
527     \class QWindowsGeometryHint
528     \brief Stores geometry constraints and provides utility functions.
529
530     Geometry constraints ready to apply to a MINMAXINFO taking frame
531     into account.
532
533     \internal
534     \ingroup qt-lighthouse-win
535 */
536
537 #define QWINDOWSIZE_MAX ((1<<24)-1)
538
539 QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) :
540      minimumSize(w->minimumSize()),
541      maximumSize(w->maximumSize())
542 {
543 }
544
545 bool QWindowsGeometryHint::validSize(const QSize &s) const
546 {
547     const int width = s.width();
548     const int height = s.height();
549     return width >= minimumSize.width() && width <= maximumSize.width()
550            && height >= minimumSize.height() && height <= maximumSize.height();
551 }
552
553 QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
554 {
555     RECT rect = {0,0,0,0};
556     style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
557     if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
558         qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
559     const QMargins result(qAbs(rect.left), qAbs(rect.top),
560                           qAbs(rect.right), qAbs(rect.bottom));
561     if (QWindowsContext::verboseWindows)
562         qDebug().nospace() << __FUNCTION__ << " style= 0x"
563                  << QString::number(style, 16)
564                  << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result;
565
566     return result;
567 }
568
569 #ifndef Q_OS_WINCE
570 void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
571 {
572     return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE),
573                              GetWindowLong(hwnd, GWL_EXSTYLE), mmi);
574 }
575
576 void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
577 {
578     if (QWindowsContext::verboseWindows)
579         qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min="
580                            << minimumSize.width() << ',' << minimumSize.height()
581                            << " max=" << maximumSize.width() << ',' << maximumSize.height()
582                            << " in " << *mmi;
583
584     const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
585     const int frameWidth = margins.left() + margins.right();
586     const int frameHeight = margins.top() + margins.bottom();
587     if (minimumSize.width() > 0)
588         mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
589     if (minimumSize.height() > 0)
590         mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
591
592     const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
593     const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
594     if (maximumWidth < QWINDOWSIZE_MAX)
595         mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
596     // windows with title bar have an implicit size limit of 112 pixels
597     if (maximumHeight < QWINDOWSIZE_MAX)
598         mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112);
599     if (QWindowsContext::verboseWindows)
600         qDebug().nospace() << '<' << __FUNCTION__
601                            << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
602                            << " out " << *mmi;
603 }
604 #endif // !Q_OS_WINCE
605
606 bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
607 {
608     return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
609            == QWindowPrivate::WindowFrameInclusive;
610 }
611
612 /*!
613     \class QWindowCreationContext
614     \brief Active Context for creating windows.
615
616     There is a phase in window creation (WindowCreationData::create())
617     in which events are sent before the system API CreateWindowEx() returns
618     the handle. These cannot be handled by the platform window as the association
619     of the unknown handle value to the window does not exist yet and as not
620     to trigger recursive handle creation, etc.
621
622     In that phase, an instance of  QWindowCreationContext is set on
623     QWindowsContext.
624
625     QWindowCreationContext stores the information to answer the initial
626     WM_GETMINMAXINFO and obtains the corrected size/position.
627
628     \sa WindowCreationData, QWindowsContext
629     \internal
630     \ingroup qt-lighthouse-win
631 */
632
633 QWindowCreationContext::QWindowCreationContext(const QWindow *w,
634                                                const QRect &geometry,
635                                                DWORD style_, DWORD exStyle_) :
636     geometryHint(w), style(style_), exStyle(exStyle_),
637     requestedGeometry(geometry), obtainedGeometry(geometry),
638     margins(QWindowsGeometryHint::frame(style, exStyle)),
639     frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
640     frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
641 {
642     // Geometry of toplevels does not consider window frames.
643     // TODO: No concept of WA_wasMoved yet that would indicate a
644     // CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
645     // for toplevels.
646     if (geometry.isValid()) {
647         frameX = geometry.x();
648         frameY = geometry.y();
649         frameWidth = margins.left() + geometry.width() + margins.right();
650         frameHeight = margins.top() + geometry.height() + margins.bottom();
651         const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
652         if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
653             frameX -= margins.left();
654             frameY -= margins.top();
655         }
656     }
657     if (QWindowsContext::verboseWindows)
658         qDebug().nospace()
659                 << __FUNCTION__ << ' ' << w << geometry
660                 << " pos incl. frame" << QWindowsGeometryHint::positionIncludesFrame(w)
661                 << " frame: " << frameWidth << 'x' << frameHeight << '+'
662                 << frameX << '+' << frameY
663                 << " min" << geometryHint.minimumSize
664                 << " max" << geometryHint.maximumSize;
665 }
666
667 /*!
668     \class QWindowsWindow
669     \brief Raster or OpenGL Window.
670
671     \list
672     \li Raster type: handleWmPaint() is implemented to
673        to bitblt the image. The DC can be accessed
674        via getDC/Relase DC, which has a special handling
675        when within a paint event (in that case, the DC obtained
676        from BeginPaint() is returned).
677
678     \li Open GL: The first time QWindowsGLContext accesses
679        the handle, it sets up the pixelformat on the DC
680        which in turn sets it on the window (see flag
681        PixelFormatInitialized).
682        handleWmPaint() is empty (although required).
683     \endlist
684
685     \internal
686     \ingroup qt-lighthouse-win
687 */
688
689 QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
690     QPlatformWindow(aWindow),
691     m_data(data),
692     m_flags(0),
693     m_hdc(0),
694     m_windowState(aWindow->windowState()),
695     m_opacity(1.0),
696     m_mouseGrab(false),
697     m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()),
698     m_dropTarget(0),
699     m_savedStyle(0),
700     m_format(aWindow->format())
701 #ifdef QT_OPENGL_ES_2
702    , m_eglSurface(0)
703 #endif
704 {
705     if (aWindow->surfaceType() == QWindow::OpenGLSurface)
706         setFlag(OpenGLSurface);
707     QWindowsContext::instance()->addWindow(m_data.hwnd, this);
708     if (aWindow->isTopLevel()) {
709         switch (aWindow->windowType()) {
710         case Qt::Window:
711         case Qt::Dialog:
712         case Qt::Sheet:
713         case Qt::Drawer:
714         case Qt::Popup:
715         case Qt::Tool:
716             registerDropSite();
717             break;
718         default:
719             break;
720         }
721     }
722 }
723
724 QWindowsWindow::~QWindowsWindow()
725 {
726     destroyWindow();
727 }
728
729 void QWindowsWindow::destroyWindow()
730 {
731     if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
732         qDebug() << __FUNCTION__ << this << window() << m_data.hwnd;
733     if (m_data.hwnd) { // Stop event dispatching before Window is destroyed.
734         unregisterDropSite();
735         QWindowsContext::instance()->removeWindow(m_data.hwnd);
736 #ifdef QT_OPENGL_ES_2
737         if (m_eglSurface) {
738             if (QWindowsContext::verboseGL)
739                 qDebug("%s: Freeing EGL surface %p, this = %p",
740                        __FUNCTION__, m_eglSurface, this);
741             eglDestroySurface(m_staticEglContext->display(), m_eglSurface);
742             m_eglSurface = 0;
743         }
744 #endif
745         if (m_data.hwnd != GetDesktopWindow())
746             DestroyWindow(m_data.hwnd);
747         m_data.hwnd = 0;
748     }
749 }
750
751 void QWindowsWindow::registerDropSite()
752 {
753     if (m_data.hwnd && !m_dropTarget) {
754         m_dropTarget = new QWindowsOleDropTarget(window());
755         RegisterDragDrop(m_data.hwnd, m_dropTarget);
756         CoLockObjectExternal(m_dropTarget, true, true);
757     }
758 }
759
760 void QWindowsWindow::unregisterDropSite()
761 {
762     if (m_data.hwnd && m_dropTarget) {
763         m_dropTarget->Release();
764         CoLockObjectExternal(m_dropTarget, false, true);
765         RevokeDragDrop(m_data.hwnd);
766         m_dropTarget = 0;
767     }
768 }
769
770 QWindow *QWindowsWindow::topLevelOf(QWindow *w)
771 {
772     while (QWindow *parent = w->parent())
773         w = parent;
774     return w;
775 }
776
777 QWindowsWindow::WindowData
778     QWindowsWindow::WindowData::create(const QWindow *w,
779                                        const WindowData &parameters,
780                                        const QString &title)
781 {
782     WindowCreationData creationData;
783     creationData.fromWindow(w, parameters.flags);
784     WindowData result = creationData.create(w, parameters.geometry, title);
785     creationData.initialize(result.hwnd, false, 1);
786     return result;
787 }
788
789 void QWindowsWindow::setVisible(bool visible)
790 {
791     if (QWindowsContext::verboseWindows)
792         qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible;
793     if (m_data.hwnd) {
794         if (visible) {
795             show_sys();
796             QWindowSystemInterface::handleSynchronousExposeEvent(window(),
797                                                                  QRect(QPoint(), geometry().size()));
798         } else {
799             hide_sys();
800             QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRegion());
801         }
802     }
803 }
804
805 bool QWindowsWindow::isVisible() const
806 {
807     return m_data.hwnd && IsWindowVisible(m_data.hwnd);
808 }
809
810 bool QWindowsWindow::isActive() const
811 {
812     // Check for native windows or children of the active native window.
813     if (const HWND activeHwnd = GetActiveWindow())
814         if (m_data.hwnd == activeHwnd || IsChild(activeHwnd, m_data.hwnd))
815             return true;
816     return false;
817 }
818
819 // partially from QWidgetPrivate::show_sys()
820 void QWindowsWindow::show_sys() const
821 {
822     int sm = SW_SHOWNORMAL;
823     bool fakedMaximize = false;
824     const QWindow *w = window();
825     const Qt::WindowFlags flags = w->windowFlags();
826     const Qt::WindowType type = w->windowType();
827     if (w->isTopLevel()) {
828         const Qt::WindowState state = w->windowState();
829         if (state & Qt::WindowMinimized) {
830             sm = SW_SHOWMINIMIZED;
831             if (!isVisible())
832                 sm = SW_SHOWMINNOACTIVE;
833         } else if (state & Qt::WindowMaximized) {
834             sm = SW_SHOWMAXIMIZED;
835             // Windows will not behave correctly when we try to maximize a window which does not
836             // have minimize nor maximize buttons in the window frame. Windows would then ignore
837             // non-available geometry, and rather maximize the widget to the full screen, minus the
838             // window frame (caption). So, we do a trick here, by adding a maximize button before
839             // maximizing the widget, and then remove the maximize button afterwards.
840             if (flags & Qt::WindowTitleHint &&
841                 !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
842                 fakedMaximize = TRUE;
843                 setStyle(style() | WS_MAXIMIZEBOX);
844             }
845         }
846     }
847     if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool)
848         sm = SW_SHOWNOACTIVATE;
849
850     ShowWindow(m_data.hwnd, sm);
851
852     if (fakedMaximize) {
853         setStyle(style() & ~WS_MAXIMIZEBOX);
854         SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0,
855                      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
856                      | SWP_FRAMECHANGED);
857     }
858 }
859
860 // partially from QWidgetPrivate::hide_sys()
861 void QWindowsWindow::hide_sys() const
862 {
863     const Qt::WindowFlags flags = window()->windowFlags();
864     if (flags != Qt::Desktop) {
865         if (flags & Qt::Popup)
866             ShowWindow(m_data.hwnd, SW_HIDE);
867         else
868             SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
869     }
870 }
871
872 void QWindowsWindow::setParent(const QPlatformWindow *newParent)
873 {
874     if (QWindowsContext::verboseWindows)
875         qDebug() << __FUNCTION__ << window() << newParent;
876
877     if (newParent != parent() && m_data.hwnd)
878         setParent_sys(newParent);
879 }
880
881 void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
882 {
883     HWND parentHWND = 0;
884     if (parent) {
885         const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
886         parentHWND = parentW->handle();
887
888     }
889
890     const bool wasTopLevel = window()->isTopLevel();
891     const bool isTopLevel = parentHWND == 0;
892
893     setFlag(WithinSetParent);
894     SetParent(m_data.hwnd, parentHWND);
895     clearFlag(WithinSetParent);
896
897     // WS_CHILD/WS_POPUP must be manually set/cleared in addition
898     // to dialog frames, etc (see  SetParent() ) if the top level state changes.
899     if (wasTopLevel != isTopLevel) {
900         const unsigned flags = isTopLevel ? unsigned(0) : unsigned(WindowCreationData::ForceChild);
901         setWindowFlags_sys(window()->windowFlags(), flags);
902     }
903 }
904
905 void QWindowsWindow::handleShown()
906 {
907     QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
908 }
909
910 void QWindowsWindow::handleHidden()
911 {
912     QWindowSystemInterface::handleExposeEvent(window(), QRegion());
913 }
914
915 void QWindowsWindow::setGeometry(const QRect &rectIn)
916 {
917     QRect rect = rectIn;
918     // This means it is a call from QWindow::setFramePos() and
919     // the coordinates include the frame (size is still the contents rectangle).
920     if (QWindowsGeometryHint::positionIncludesFrame(window())) {
921         const QMargins margins = frameMargins();
922         rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
923     }
924     const QSize oldSize = m_data.geometry.size();
925     m_data.geometry = rect;
926     const QSize newSize = rect.size();
927     // Check on hint.
928     if (newSize != oldSize) {
929         const QWindowsGeometryHint hint(window());
930         if (!hint.validSize(newSize)) {
931             qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
932                      "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
933                      newSize.width(), newSize.height(),
934                      hint.minimumSize.width(), hint.minimumSize.height(),
935                      hint.maximumSize.width(), hint.maximumSize.height(),
936                      qPrintable(window()->objectName()));
937         }
938     }
939     if (m_data.hwnd) {
940         // A ResizeEvent with resulting geometry will be sent. If we cannot
941         // achieve that size (for example, window title minimal constraint),
942         // notify and warn.
943         setGeometry_sys(rect);
944         if (m_data.geometry != rect) {
945             qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
946                      " Resulting geometry:  %dx%d+%d+%d "
947                      "(frame: %d, %d, %d, %d).",
948                      __FUNCTION__,
949                      rect.width(), rect.height(), rect.x(), rect.y(),
950                      qPrintable(window()->objectName()),
951                      m_data.geometry.width(), m_data.geometry.height(),
952                      m_data.geometry.x(), m_data.geometry.y(),
953                      m_data.frame.left(), m_data.frame.top(),
954                      m_data.frame.right(), m_data.frame.bottom());
955         }
956     } else {
957         QPlatformWindow::setGeometry(rect);
958     }
959 }
960
961 void QWindowsWindow::handleMoved()
962 {
963     // Minimize/Set parent can send nonsensical move events.
964     if (!IsIconic(m_data.hwnd) && !testFlag(WithinSetParent))
965         handleGeometryChange();
966 }
967
968 void QWindowsWindow::handleResized(int wParam)
969 {
970     switch (wParam) {
971     case SIZE_MAXHIDE: // Some other window affected.
972     case SIZE_MAXSHOW:
973         return;
974     case SIZE_MINIMIZED:
975         handleWindowStateChange(Qt::WindowMinimized);
976         return;
977     case SIZE_MAXIMIZED:
978         handleWindowStateChange(Qt::WindowMaximized);
979         handleGeometryChange();
980         break;
981     case SIZE_RESTORED:
982         if (m_windowState != Qt::WindowNoState)
983             handleWindowStateChange(isFullScreen_sys() ? Qt::WindowFullScreen : Qt::WindowNoState);
984         handleGeometryChange();
985         break;
986     }
987 }
988
989 void QWindowsWindow::handleGeometryChange()
990 {
991     m_data.geometry = geometry_sys();
992     QPlatformWindow::setGeometry(m_data.geometry);
993     QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
994
995     if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows)
996         qDebug() << __FUNCTION__ << this << window() << m_data.geometry;
997 }
998
999 void QWindowsWindow::setGeometry_sys(const QRect &rect) const
1000 {
1001     const QMargins margins = frameMargins();
1002     const QRect frameGeometry = rect + margins;
1003
1004     if (QWindowsContext::verboseWindows)
1005         qDebug() << '>' << __FUNCTION__ << this << window()
1006                  << "    \n from " << geometry_sys() << " frame: "
1007                  << margins << " to " <<rect
1008                  << " new frame: " << frameGeometry;
1009
1010     const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(),
1011                                frameGeometry.width(), frameGeometry.height(), true);
1012     if (QWindowsContext::verboseWindows)
1013         qDebug() << '<' << __FUNCTION__ << this << window()
1014                  << "    \n resulting " << rc << geometry_sys();
1015 }
1016
1017 QRect QWindowsWindow::frameGeometry_sys() const
1018 {
1019     // Warning: Returns bogus values when minimized.
1020     bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded;
1021     return frameGeometry(m_data.hwnd, isRealTopLevel);
1022 }
1023
1024 QRect QWindowsWindow::geometry_sys() const
1025 {
1026     return frameGeometry_sys() - frameMargins();
1027 }
1028
1029 /*!
1030     Allocates a HDC for the window or returns the temporary one
1031     obtained from WinAPI BeginPaint within a WM_PAINT event.
1032
1033     \sa releaseDC()
1034 */
1035
1036 HDC QWindowsWindow::getDC()
1037 {
1038     if (!m_hdc)
1039         m_hdc = GetDC(handle());
1040     return m_hdc;
1041 }
1042
1043 /*!
1044     Relases the HDC for the window or does nothing in
1045     case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
1046
1047     \sa getDC()
1048 */
1049
1050 void QWindowsWindow::releaseDC()
1051 {
1052     if (m_hdc && !testFlag(DCFromBeginPaint)) {
1053         ReleaseDC(handle(), m_hdc);
1054         m_hdc = 0;
1055     }
1056 }
1057
1058 bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
1059                                          WPARAM, LPARAM)
1060 {
1061     // Ignore invalid update bounding rectangles
1062     if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
1063         return false;
1064     if (message == WM_ERASEBKGND) // Backing store - ignored.
1065         return true;
1066     PAINTSTRUCT ps;
1067     if (testFlag(OpenGLSurface)) {
1068         // Observed painting problems with Aero style disabled (QTBUG-7865).
1069         if (testFlag(OpenGLDoubleBuffered))
1070             InvalidateRect(hwnd, 0, false);
1071         BeginPaint(hwnd, &ps);
1072         QWindowSystemInterface::handleSynchronousExposeEvent(window(),
1073                                                              QRegion(qrectFromRECT(ps.rcPaint)));
1074         EndPaint(hwnd, &ps);
1075     } else {
1076         const HDC dc = BeginPaint(hwnd, &ps);
1077         const QRect updateRect = qrectFromRECT(ps.rcPaint);
1078         if (updateRect.size() == m_data.geometry.size()) {
1079             // Store DC for access by the backing store if it has the full size.
1080             releaseDC();
1081             setFlag(DCFromBeginPaint);
1082             m_hdc = dc;
1083         }
1084         if (QWindowsContext::verboseIntegration)
1085             qDebug() << __FUNCTION__ << this << window() << updateRect;
1086
1087         QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRegion(updateRect));
1088         if (testFlag(DCFromBeginPaint)) {
1089             clearFlag(DCFromBeginPaint);
1090             m_hdc = 0;
1091         }
1092         EndPaint(hwnd, &ps);
1093     }
1094     return true;
1095 }
1096
1097 void QWindowsWindow::setWindowTitle(const QString &title)
1098 {
1099     if (QWindowsContext::verboseWindows)
1100         qDebug() << __FUNCTION__ << this << window() <<title;
1101     if (m_data.hwnd)
1102         SetWindowText(m_data.hwnd, (const wchar_t*)title.utf16());
1103 }
1104
1105 Qt::WindowFlags QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
1106 {
1107     if (QWindowsContext::verboseWindows)
1108         qDebug() << '>' << __FUNCTION__ << this << window() << "\n    from: "
1109                  << QWindowsWindow::debugWindowFlags(m_data.flags)
1110                  << "\n    to: " << QWindowsWindow::debugWindowFlags(flags);
1111     const QRect oldGeometry = geometry();
1112     if (m_data.flags != flags) {
1113         m_data.flags = flags;
1114         if (m_data.hwnd)
1115             m_data = setWindowFlags_sys(flags);
1116     }
1117     // When switching to a frameless window, geometry
1118     // may change without a WM_MOVE. Report change manually.
1119     // Do not send synchronously as not to clobber the widget
1120     // geometry in a sequence of setting flags and geometry.
1121     const QRect newGeometry = geometry_sys();
1122     if (oldGeometry != newGeometry)
1123         handleGeometryChange();
1124
1125     if (QWindowsContext::verboseWindows)
1126         qDebug() << '<' << __FUNCTION__ << "\n    returns: "
1127                  << QWindowsWindow::debugWindowFlags(m_data.flags)
1128                  << " geometry " << oldGeometry << "->" << newGeometry;
1129     return m_data.flags;
1130 }
1131
1132 QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
1133                                                               unsigned flags) const
1134 {
1135     WindowCreationData creationData;
1136     creationData.fromWindow(window(), wt, flags);
1137     creationData.applyWindowFlags(m_data.hwnd);
1138     creationData.initialize(m_data.hwnd, true, m_opacity);
1139
1140     WindowData result = m_data;
1141     result.flags = creationData.flags;
1142     result.embedded = creationData.embedded;
1143     setFlag(FrameDirty);
1144     return result;
1145 }
1146
1147 void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
1148 {
1149     if (QWindowsContext::verboseWindows)
1150         qDebug() << __FUNCTION__ << this << window()
1151                  << "\n    from " << debugWindowStates(m_windowState)
1152                  << " to " << debugWindowStates(state);
1153     setFlag(FrameDirty);
1154     m_windowState = state;
1155     QWindowSystemInterface::handleWindowStateChanged(window(), state);
1156 }
1157
1158 Qt::WindowState QWindowsWindow::setWindowState(Qt::WindowState state)
1159 {
1160     if (m_data.hwnd) {
1161         setWindowState_sys(state);
1162         m_windowState = state;
1163     }
1164     return state;
1165 }
1166
1167 Qt::WindowState QWindowsWindow::windowState_sys() const
1168 {
1169     if (IsIconic(m_data.hwnd))
1170         return Qt::WindowMinimized;
1171     if (IsZoomed(m_data.hwnd))
1172         return Qt::WindowMaximized;
1173     if (isFullScreen_sys())
1174         return Qt::WindowFullScreen;
1175     return Qt::WindowNoState;
1176 }
1177
1178 Qt::WindowStates QWindowsWindow::windowStates_sys() const
1179 {
1180     Qt::WindowStates result = windowState_sys();
1181     if (GetActiveWindow() == m_data.hwnd)
1182         result |= Qt::WindowActive;
1183     return result;
1184 }
1185
1186 bool QWindowsWindow::isFullScreen_sys() const
1187 {
1188     return geometry_sys() == window()->screen()->geometry();
1189 }
1190
1191 /*!
1192     \brief Change the window state.
1193
1194     \note Window frames change when maximized;
1195     the top margin shrinks somewhat but that cannot be obtained using
1196     AdjustWindowRectEx().
1197
1198     \note Some calls to SetWindowLong require a subsequent call
1199     to ShowWindow.
1200 */
1201
1202 void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
1203 {
1204     const Qt::WindowStates oldStates = windowStates_sys();
1205     // Maintain the active flag as the platform window API does not
1206     // use it.
1207     Qt::WindowStates newStates = newState;
1208     if (oldStates & Qt::WindowActive)
1209         newStates |=  Qt::WindowActive;
1210     if (oldStates == newStates)
1211         return;
1212     if (QWindowsContext::verboseWindows)
1213         qDebug() << '>' << __FUNCTION__ << this << window()
1214                  << " from " << debugWindowStates(oldStates)
1215                  << " to " << debugWindowStates(newStates);
1216
1217     const bool isActive = newStates & Qt::WindowActive;
1218     const int max    = isActive ? SW_SHOWMAXIMIZED : SW_MAXIMIZE;
1219     const int normal = isActive ? SW_SHOWNORMAL    : SW_SHOWNOACTIVATE;
1220     const int min    = isActive ? SW_SHOWMINIMIZED : SW_MINIMIZE;
1221     const bool visible = isVisible();
1222
1223     setFlag(FrameDirty);
1224
1225     if ((oldStates & Qt::WindowMaximized) != (newStates & Qt::WindowMaximized)) {
1226         if (visible && !(newStates & Qt::WindowMinimized))
1227             ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
1228     }
1229
1230     if ((oldStates & Qt::WindowFullScreen) != (newStates & Qt::WindowFullScreen)) {
1231         if (newStates & Qt::WindowFullScreen) {
1232 #ifndef Q_FLATTEN_EXPOSE
1233             UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
1234 #else
1235             UINT newStyle = WS_POPUP;
1236 #endif
1237             // Save geometry and style to be restored when fullscreen
1238             // is turned off again, since on Windows, it is not a real
1239             // Window state but emulated by changing geometry and style.
1240             m_savedStyle = style();
1241             m_savedFrameGeometry = frameGeometry_sys();
1242             if (m_savedStyle & WS_SYSMENU)
1243                 newStyle |= WS_SYSMENU;
1244             if (visible)
1245                 newStyle |= WS_VISIBLE;
1246             setStyle(newStyle);
1247
1248             const QRect r = window()->screen()->geometry();
1249             UINT swpf = SWP_FRAMECHANGED;
1250             if (newStates & Qt::WindowActive)
1251                 swpf |= SWP_NOACTIVATE;
1252             SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
1253             QWindowSystemInterface::handleSynchronousGeometryChange(window(), r);
1254         } else {
1255             // Restore saved state.
1256             unsigned newStyle = m_savedStyle ? m_savedStyle : style();
1257             if (visible)
1258                 newStyle |= WS_VISIBLE;
1259             setStyle(newStyle);
1260
1261             UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER;
1262             if (newStates & Qt::WindowActive)
1263                 swpf |= SWP_NOACTIVATE;
1264             if (!m_savedFrameGeometry.isValid())
1265                 swpf |= SWP_NOSIZE | SWP_NOMOVE;
1266             SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(),
1267                          m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf);
1268             // preserve maximized state
1269             if (visible)
1270                 ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
1271             m_savedStyle = 0;
1272             m_savedFrameGeometry = QRect();
1273         }
1274     }
1275
1276     if ((oldStates & Qt::WindowMinimized) != (newStates & Qt::WindowMinimized)) {
1277         if (visible)
1278             ShowWindow(m_data.hwnd, (newStates & Qt::WindowMinimized) ? min :
1279                        (newStates & Qt::WindowMaximized) ? max : normal);
1280     }
1281     if (QWindowsContext::verboseWindows)
1282         qDebug() << '<' << __FUNCTION__ << this << window()
1283                  << debugWindowStates(newStates);
1284 }
1285
1286 void QWindowsWindow::setStyle(unsigned s) const
1287 {
1288     if (QWindowsContext::verboseWindows)
1289         qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s);
1290     setFlag(FrameDirty);
1291     SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
1292 }
1293
1294 void QWindowsWindow::setExStyle(unsigned s) const
1295 {
1296     if (QWindowsContext::verboseWindows)
1297         qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
1298         << " 0x" << QByteArray::number(s, 16);
1299     setFlag(FrameDirty);
1300     SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
1301 }
1302
1303 void QWindowsWindow::raise()
1304 {
1305     if (QWindowsContext::verboseWindows)
1306         qDebug() << __FUNCTION__ << this << window();
1307     SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1308 }
1309
1310 void QWindowsWindow::lower()
1311 {
1312     if (QWindowsContext::verboseWindows)
1313         qDebug() << __FUNCTION__ << this << window();
1314     if (m_data.hwnd)
1315         SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1316 }
1317
1318 void QWindowsWindow::windowEvent(QEvent *event)
1319 {
1320     switch (event->type()) {
1321     case QEvent::WindowBlocked: // Blocked by another modal window.
1322         setEnabled(false);
1323         setFlag(BlockedByModal);
1324         break;
1325     case QEvent::WindowUnblocked:
1326         setEnabled(true);
1327         clearFlag(BlockedByModal);
1328         break;
1329     default:
1330         break;
1331     }
1332 }
1333
1334 void QWindowsWindow::propagateSizeHints()
1335 {
1336     if (QWindowsContext::verboseWindows)
1337         qDebug() << __FUNCTION__ << this << window();
1338 }
1339
1340 QMargins QWindowsWindow::frameMargins() const
1341 {
1342     // Frames are invalidated by style changes (window state, flags).
1343     // As they are also required for geometry calculations in resize
1344     // event sequences, introduce a dirty flag mechanism to be able
1345     // to cache results.
1346     if (testFlag(FrameDirty)) {
1347         m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
1348         clearFlag(FrameDirty);
1349     }
1350     return m_data.frame;
1351 }
1352
1353 void QWindowsWindow::setOpacity(qreal level)
1354 {
1355     if (QWindowsContext::verboseWindows)
1356         qDebug() << __FUNCTION__ << level;
1357     if (m_opacity != level) {
1358         m_opacity = level;
1359         if (m_data.hwnd)
1360             setWindowOpacity(m_data.hwnd, m_data.flags, level);
1361     }
1362 }
1363
1364 static inline HRGN createRectRegion(const QRect &r)
1365 {
1366     return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
1367 }
1368
1369 static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
1370 {
1371     if (const HRGN rectRegion = createRectRegion(rect)) {
1372         HRGN result = CreateRectRgn(0, 0, 0, 0);
1373         if (CombineRgn(result, *winRegion, rectRegion, RGN_OR)) {
1374             DeleteObject(winRegion);
1375             *winRegion = result;
1376         }
1377         DeleteObject(rectRegion);
1378     }
1379 }
1380
1381 static HRGN qRegionToWinRegion(const QRegion &region)
1382 {
1383     const QVector<QRect> rects = region.rects();
1384     if (rects.isEmpty())
1385         return NULL;
1386     const int rectCount = rects.size();
1387     if (rectCount == 1)
1388         return createRectRegion(region.boundingRect());
1389     HRGN hRegion = createRectRegion(rects.front());
1390     for (int i = 1; i < rectCount; ++i)
1391         addRectToWinRegion(rects.at(i), &hRegion);
1392     return hRegion;
1393 }
1394
1395 void QWindowsWindow::setMask(const QRegion &region)
1396 {
1397     if (region.isEmpty()) {
1398          SetWindowRgn(m_data.hwnd, 0, true);
1399          return;
1400     }
1401     const HRGN winRegion = qRegionToWinRegion(region);
1402
1403     // Mask is in client area coordinates, so offset it in case we have a frame
1404     if (window()->isTopLevel()) {
1405         const QMargins margins = frameMargins();
1406         OffsetRgn(winRegion, margins.left(), margins.top());
1407     }
1408
1409     // SetWindowRgn takes ownership.
1410     if (!SetWindowRgn(m_data.hwnd, winRegion, true))
1411         DeleteObject(winRegion);
1412 }
1413
1414 void QWindowsWindow::requestActivateWindow()
1415 {
1416     if (QWindowsContext::verboseWindows)
1417         qDebug() << __FUNCTION__ << this << window();
1418     // 'Active' state handling is based in focus since it needs to work for
1419     // child windows as well.
1420     if (m_data.hwnd) {
1421         SetForegroundWindow(m_data.hwnd);
1422         SetFocus(m_data.hwnd);
1423     }
1424 }
1425
1426 bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
1427 {
1428     if (!m_data.hwnd) {
1429         qWarning("%s: No handle", __FUNCTION__);
1430         return false;
1431     }
1432     if (QWindowsContext::verboseWindows)
1433         qDebug() << __FUNCTION__ << this << window() << grab;
1434
1435     QWindowsContext *context = QWindowsContext::instance();
1436     if (grab) {
1437         context->setKeyGrabber(window());
1438     } else {
1439         if (context->keyGrabber() == window())
1440             context->setKeyGrabber(0);
1441     }
1442     return true;
1443 }
1444
1445 bool QWindowsWindow::setMouseGrabEnabled(bool grab)
1446 {
1447     bool result = false;
1448     if (!m_data.hwnd) {
1449         qWarning("%s: No handle", __FUNCTION__);
1450         return result;
1451     }
1452     if (QWindowsContext::verboseWindows)
1453         qDebug() << __FUNCTION__ << window() << grab;
1454
1455     if (m_mouseGrab != grab) {
1456         m_mouseGrab = grab;
1457         if (isVisible())
1458             setMouseGrabEnabled_sys(grab);
1459     }
1460     return grab;
1461 }
1462
1463 void QWindowsWindow::setMouseGrabEnabled_sys(bool grab)
1464 {
1465     if (grab) {
1466         SetCapture(m_data.hwnd);
1467     } else {
1468         ReleaseCapture();
1469     }
1470 }
1471
1472 static inline DWORD cornerToWinOrientation(Qt::Corner corner)
1473 {
1474     switch (corner) {
1475     case Qt::TopLeftCorner:
1476         return 0xf004; // SZ_SIZETOPLEFT;
1477     case Qt::TopRightCorner:
1478         return 0xf005; // SZ_SIZETOPRIGHT
1479     case Qt::BottomLeftCorner:
1480         return 0xf007; // SZ_SIZEBOTTOMLEFT
1481     case Qt::BottomRightCorner:
1482         return 0xf008; // SZ_SIZEBOTTOMRIGHT
1483     }
1484     return 0;
1485 }
1486
1487 bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
1488 {
1489     if (!GetSystemMenu(m_data.hwnd, FALSE))
1490         return false;
1491
1492     ReleaseCapture();
1493     PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
1494     setFlag(SizeGripOperation);
1495     return true;
1496 }
1497
1498 void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
1499 {
1500     if (enabled) {
1501         setFlag(FrameStrutEventsEnabled);
1502     } else {
1503         clearFlag(FrameStrutEventsEnabled);
1504     }
1505 }
1506
1507 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
1508 void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
1509 {
1510     const QWindowsGeometryHint hint(window());
1511     hint.applyToMinMaxInfo(m_data.hwnd, mmi);
1512     if (QWindowsContext::verboseWindows)
1513         qDebug() << __FUNCTION__ << window() << *mmi;
1514 }
1515 #endif // !Q_OS_WINCE
1516
1517 /*!
1518     \brief Applies to cursor property set on the window to the global cursor.
1519
1520     \sa QWindowsCursor
1521 */
1522
1523 void QWindowsWindow::applyCursor()
1524 {
1525     SetCursor(m_cursor.handle());
1526 }
1527
1528 void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
1529 {
1530     if (c.handle() != m_cursor.handle()) {
1531         const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
1532         if (QWindowsContext::verboseWindows)
1533             qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
1534                      << " isWUM=" << underMouse;
1535         m_cursor = c;
1536         if (underMouse)
1537             applyCursor();
1538     }
1539 }
1540
1541 /*!
1542     \brief Find a child window using flags from  ChildWindowFromPointEx.
1543 */
1544
1545 QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint,
1546                                                            unsigned cwexflags) const
1547 {
1548     if (m_data.hwnd)
1549         return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags);
1550     return 0;
1551 }
1552
1553 QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const
1554 {
1555     if (m_data.hwnd)
1556         return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint),
1557                                   cwexflags);
1558     return 0;
1559 }
1560
1561 #ifndef Q_OS_WINCE
1562 void QWindowsWindow::alertWindow(int durationMs)
1563 {
1564     DWORD timeOutMs = GetCaretBlinkTime();
1565     if (!timeOutMs || timeOutMs == INFINITE)
1566         timeOutMs = 250;
1567
1568     FLASHWINFO info;
1569     info.cbSize = sizeof(info);
1570     info.hwnd = m_data.hwnd;
1571     info.dwFlags = FLASHW_TRAY;
1572     info.dwTimeout = timeOutMs;
1573     info.uCount = durationMs == 0 ? 10 : durationMs / timeOutMs;
1574     FlashWindowEx(&info);
1575 }
1576
1577 void QWindowsWindow::stopAlertWindow()
1578 {
1579     FLASHWINFO info;
1580     info.cbSize = sizeof(info);
1581     info.hwnd = m_data.hwnd;
1582     info.dwFlags = FLASHW_STOP;
1583     info.dwTimeout = 0;
1584     info.uCount = 0;
1585     FlashWindowEx(&info);
1586 }
1587 #endif // !Q_OS_WINCE
1588
1589 bool QWindowsWindow::isEnabled() const
1590 {
1591     return (style() & WS_DISABLED) == 0;
1592 }
1593
1594 void QWindowsWindow::setEnabled(bool enabled)
1595 {
1596     const unsigned oldStyle = style();
1597     unsigned newStyle = oldStyle;
1598     if (enabled) {
1599         newStyle &= ~WS_DISABLED;
1600     } else {
1601         newStyle |= WS_DISABLED;
1602     }
1603     if (newStyle != oldStyle)
1604         setStyle(newStyle);
1605 }
1606
1607 #ifdef QT_OPENGL_ES_2
1608 EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config)
1609 {
1610     if (!m_eglSurface) {
1611         m_staticEglContext = staticContext;
1612         m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL);
1613         if (m_eglSurface == EGL_NO_SURFACE)
1614             qWarning("%s: Could not create the egl surface (eglCreateWindowSurface failed): error = 0x%x\n",
1615                      Q_FUNC_INFO, eglGetError());
1616         if (QWindowsContext::verboseGL)
1617             qDebug("%s: Created EGL surface %p, this = %p",
1618                    __FUNCTION__, m_eglSurface, this);
1619     }
1620     return m_eglSurface;
1621 }
1622 #endif // QT_OPENGL_ES_2
1623
1624 QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf)
1625 {
1626     const int iwf = int(wf);
1627     QByteArray rc = "0x";
1628     rc += QByteArray::number(iwf, 16);
1629     rc += " [";
1630
1631     switch ((iwf & Qt::WindowType_Mask)) {
1632     case Qt::Widget:
1633         rc += " Widget";
1634         break;
1635     case Qt::Window:
1636         rc += " Window";
1637         break;
1638     case Qt::Dialog:
1639         rc += " Dialog";
1640         break;
1641     case Qt::Sheet:
1642         rc += " Sheet";
1643         break;
1644     case Qt::Popup:
1645         rc += " Popup";
1646         break;
1647     case Qt::Tool:
1648         rc += " Tool";
1649         break;
1650     case Qt::ToolTip:
1651         rc += " ToolTip";
1652         break;
1653     case Qt::SplashScreen:
1654         rc += " SplashScreen";
1655         break;
1656     case Qt::Desktop:
1657         rc += " Desktop";
1658         break;
1659     case Qt::SubWindow:
1660         rc += " SubWindow";
1661         break;
1662     }
1663     if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint";
1664     if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC";
1665     if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint";
1666     if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint";
1667     if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint";
1668     if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint";
1669     if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint";
1670     if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint";
1671     if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint";
1672     if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint";
1673     if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint";
1674     if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint";
1675     if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint";
1676     rc += ']';
1677     return rc;
1678 }
1679
1680 QT_END_NAMESPACE