a2a7950fad21b311ef66042ce6c5dc8baf798142
[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(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 (geometry_sys() == window()->screen()->geometry())
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 /*!
1187     \brief Change the window state.
1188
1189     \note Window frames change when maximized;
1190     the top margin shrinks somewhat but that cannot be obtained using
1191     AdjustWindowRectEx().
1192
1193     \note Some calls to SetWindowLong require a subsequent call
1194     to ShowWindow.
1195 */
1196
1197 void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
1198 {
1199     const Qt::WindowStates oldStates = windowStates_sys();
1200     // Maintain the active flag as the platform window API does not
1201     // use it.
1202     Qt::WindowStates newStates = newState;
1203     if (oldStates & Qt::WindowActive)
1204         newStates |=  Qt::WindowActive;
1205     if (oldStates == newStates)
1206         return;
1207     if (QWindowsContext::verboseWindows)
1208         qDebug() << '>' << __FUNCTION__ << this << window()
1209                  << " from " << debugWindowStates(oldStates)
1210                  << " to " << debugWindowStates(newStates);
1211
1212     const bool isActive = newStates & Qt::WindowActive;
1213     const int max    = isActive ? SW_SHOWMAXIMIZED : SW_MAXIMIZE;
1214     const int normal = isActive ? SW_SHOWNORMAL    : SW_SHOWNOACTIVATE;
1215     const int min    = isActive ? SW_SHOWMINIMIZED : SW_MINIMIZE;
1216     const bool visible = isVisible();
1217
1218     setFlag(FrameDirty);
1219
1220     if ((oldStates & Qt::WindowMaximized) != (newStates & Qt::WindowMaximized)) {
1221         if (visible && !(newStates & Qt::WindowMinimized))
1222             ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
1223     }
1224
1225     if ((oldStates & Qt::WindowFullScreen) != (newStates & Qt::WindowFullScreen)) {
1226         if (newStates & Qt::WindowFullScreen) {
1227 #ifndef Q_FLATTEN_EXPOSE
1228             UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
1229 #else
1230             UINT newStyle = WS_POPUP;
1231 #endif
1232             // Save geometry and style to be restored when fullscreen
1233             // is turned off again, since on Windows, it is not a real
1234             // Window state but emulated by changing geometry and style.
1235             m_savedStyle = style();
1236             m_savedFrameGeometry = frameGeometry_sys();
1237             if (m_savedStyle & WS_SYSMENU)
1238                 newStyle |= WS_SYSMENU;
1239             if (visible)
1240                 newStyle |= WS_VISIBLE;
1241             setStyle(newStyle);
1242
1243             const QRect r = window()->screen()->geometry();
1244             UINT swpf = SWP_FRAMECHANGED;
1245             if (newStates & Qt::WindowActive)
1246                 swpf |= SWP_NOACTIVATE;
1247             SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
1248             QWindowSystemInterface::handleSynchronousGeometryChange(window(), r);
1249         } else {
1250             // Restore saved state.
1251             unsigned newStyle = m_savedStyle ? m_savedStyle : style();
1252             if (visible)
1253                 newStyle |= WS_VISIBLE;
1254             setStyle(newStyle);
1255
1256             UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER;
1257             if (newStates & Qt::WindowActive)
1258                 swpf |= SWP_NOACTIVATE;
1259             if (!m_savedFrameGeometry.isValid())
1260                 swpf |= SWP_NOSIZE | SWP_NOMOVE;
1261             SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(),
1262                          m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf);
1263             // preserve maximized state
1264             if (visible)
1265                 ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
1266             m_savedStyle = 0;
1267             m_savedFrameGeometry = QRect();
1268         }
1269     }
1270
1271     if ((oldStates & Qt::WindowMinimized) != (newStates & Qt::WindowMinimized)) {
1272         if (visible)
1273             ShowWindow(m_data.hwnd, (newStates & Qt::WindowMinimized) ? min :
1274                        (newStates & Qt::WindowMaximized) ? max : normal);
1275     }
1276     if (QWindowsContext::verboseWindows)
1277         qDebug() << '<' << __FUNCTION__ << this << window()
1278                  << debugWindowStates(newStates);
1279 }
1280
1281 void QWindowsWindow::setStyle(unsigned s) const
1282 {
1283     if (QWindowsContext::verboseWindows)
1284         qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s);
1285     setFlag(FrameDirty);
1286     SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
1287 }
1288
1289 void QWindowsWindow::setExStyle(unsigned s) const
1290 {
1291     if (QWindowsContext::verboseWindows)
1292         qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
1293         << " 0x" << QByteArray::number(s, 16);
1294     setFlag(FrameDirty);
1295     SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
1296 }
1297
1298 void QWindowsWindow::raise()
1299 {
1300     if (QWindowsContext::verboseWindows)
1301         qDebug() << __FUNCTION__ << this << window();
1302     SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1303 }
1304
1305 void QWindowsWindow::lower()
1306 {
1307     if (QWindowsContext::verboseWindows)
1308         qDebug() << __FUNCTION__ << this << window();
1309     if (m_data.hwnd)
1310         SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1311 }
1312
1313 void QWindowsWindow::windowEvent(QEvent *event)
1314 {
1315     switch (event->type()) {
1316     case QEvent::WindowBlocked: // Blocked by another modal window.
1317         setEnabled(false);
1318         setFlag(BlockedByModal);
1319         break;
1320     case QEvent::WindowUnblocked:
1321         setEnabled(true);
1322         clearFlag(BlockedByModal);
1323         break;
1324     default:
1325         break;
1326     }
1327 }
1328
1329 void QWindowsWindow::propagateSizeHints()
1330 {
1331     if (QWindowsContext::verboseWindows)
1332         qDebug() << __FUNCTION__ << this << window();
1333 }
1334
1335 QMargins QWindowsWindow::frameMargins() const
1336 {
1337     // Frames are invalidated by style changes (window state, flags).
1338     // As they are also required for geometry calculations in resize
1339     // event sequences, introduce a dirty flag mechanism to be able
1340     // to cache results.
1341     if (testFlag(FrameDirty)) {
1342         m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
1343         clearFlag(FrameDirty);
1344     }
1345     return m_data.frame;
1346 }
1347
1348 void QWindowsWindow::setOpacity(qreal level)
1349 {
1350     if (QWindowsContext::verboseWindows)
1351         qDebug() << __FUNCTION__ << level;
1352     if (m_opacity != level) {
1353         m_opacity = level;
1354         if (m_data.hwnd)
1355             setWindowOpacity(m_data.hwnd, m_data.flags, level);
1356     }
1357 }
1358
1359 static inline HRGN createRectRegion(const QRect &r)
1360 {
1361     return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
1362 }
1363
1364 static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
1365 {
1366     if (const HRGN rectRegion = createRectRegion(rect)) {
1367         HRGN result = CreateRectRgn(0, 0, 0, 0);
1368         if (CombineRgn(result, *winRegion, rectRegion, RGN_OR)) {
1369             DeleteObject(winRegion);
1370             *winRegion = result;
1371         }
1372         DeleteObject(rectRegion);
1373     }
1374 }
1375
1376 static HRGN qRegionToWinRegion(const QRegion &region)
1377 {
1378     const QVector<QRect> rects = region.rects();
1379     if (rects.isEmpty())
1380         return NULL;
1381     const int rectCount = rects.size();
1382     if (rectCount == 1)
1383         return createRectRegion(region.boundingRect());
1384     HRGN hRegion = createRectRegion(rects.front());
1385     for (int i = 1; i < rectCount; ++i)
1386         addRectToWinRegion(rects.at(i), &hRegion);
1387     return hRegion;
1388 }
1389
1390 void QWindowsWindow::setMask(const QRegion &region)
1391 {
1392     if (region.isEmpty()) {
1393          SetWindowRgn(m_data.hwnd, 0, true);
1394          return;
1395     }
1396     const HRGN winRegion = qRegionToWinRegion(region);
1397
1398     // Mask is in client area coordinates, so offset it in case we have a frame
1399     if (window()->isTopLevel()) {
1400         const QMargins margins = frameMargins();
1401         OffsetRgn(winRegion, margins.left(), margins.top());
1402     }
1403
1404     // SetWindowRgn takes ownership.
1405     if (!SetWindowRgn(m_data.hwnd, winRegion, true))
1406         DeleteObject(winRegion);
1407 }
1408
1409 void QWindowsWindow::requestActivateWindow()
1410 {
1411     if (QWindowsContext::verboseWindows)
1412         qDebug() << __FUNCTION__ << this << window();
1413     // 'Active' state handling is based in focus since it needs to work for
1414     // child windows as well.
1415     if (m_data.hwnd) {
1416         SetForegroundWindow(m_data.hwnd);
1417         SetFocus(m_data.hwnd);
1418     }
1419 }
1420
1421 bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
1422 {
1423     if (!m_data.hwnd) {
1424         qWarning("%s: No handle", __FUNCTION__);
1425         return false;
1426     }
1427     if (QWindowsContext::verboseWindows)
1428         qDebug() << __FUNCTION__ << this << window() << grab;
1429
1430     QWindowsContext *context = QWindowsContext::instance();
1431     if (grab) {
1432         context->setKeyGrabber(window());
1433     } else {
1434         if (context->keyGrabber() == window())
1435             context->setKeyGrabber(0);
1436     }
1437     return true;
1438 }
1439
1440 bool QWindowsWindow::setMouseGrabEnabled(bool grab)
1441 {
1442     bool result = false;
1443     if (!m_data.hwnd) {
1444         qWarning("%s: No handle", __FUNCTION__);
1445         return result;
1446     }
1447     if (QWindowsContext::verboseWindows)
1448         qDebug() << __FUNCTION__ << window() << grab;
1449
1450     if (m_mouseGrab != grab) {
1451         m_mouseGrab = grab;
1452         if (isVisible())
1453             setMouseGrabEnabled_sys(grab);
1454     }
1455     return grab;
1456 }
1457
1458 void QWindowsWindow::setMouseGrabEnabled_sys(bool grab)
1459 {
1460     if (grab) {
1461         SetCapture(m_data.hwnd);
1462     } else {
1463         ReleaseCapture();
1464     }
1465 }
1466
1467 static inline DWORD cornerToWinOrientation(Qt::Corner corner)
1468 {
1469     switch (corner) {
1470     case Qt::TopLeftCorner:
1471         return 0xf004; // SZ_SIZETOPLEFT;
1472     case Qt::TopRightCorner:
1473         return 0xf005; // SZ_SIZETOPRIGHT
1474     case Qt::BottomLeftCorner:
1475         return 0xf007; // SZ_SIZEBOTTOMLEFT
1476     case Qt::BottomRightCorner:
1477         return 0xf008; // SZ_SIZEBOTTOMRIGHT
1478     }
1479     return 0;
1480 }
1481
1482 bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
1483 {
1484     if (!GetSystemMenu(m_data.hwnd, FALSE))
1485         return false;
1486
1487     ReleaseCapture();
1488     PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
1489     setFlag(SizeGripOperation);
1490     return true;
1491 }
1492
1493 void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
1494 {
1495     if (enabled) {
1496         setFlag(FrameStrutEventsEnabled);
1497     } else {
1498         clearFlag(FrameStrutEventsEnabled);
1499     }
1500 }
1501
1502 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
1503 void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
1504 {
1505     const QWindowsGeometryHint hint(window());
1506     hint.applyToMinMaxInfo(m_data.hwnd, mmi);
1507     if (QWindowsContext::verboseWindows)
1508         qDebug() << __FUNCTION__ << window() << *mmi;
1509 }
1510 #endif // !Q_OS_WINCE
1511
1512 /*!
1513     \brief Applies to cursor property set on the window to the global cursor.
1514
1515     \sa QWindowsCursor
1516 */
1517
1518 void QWindowsWindow::applyCursor()
1519 {
1520     SetCursor(m_cursor.handle());
1521 }
1522
1523 void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
1524 {
1525     if (c.handle() != m_cursor.handle()) {
1526         const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
1527         if (QWindowsContext::verboseWindows)
1528             qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
1529                      << " isWUM=" << underMouse;
1530         m_cursor = c;
1531         if (underMouse)
1532             applyCursor();
1533     }
1534 }
1535
1536 /*!
1537     \brief Find a child window using flags from  ChildWindowFromPointEx.
1538 */
1539
1540 QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint,
1541                                                            unsigned cwexflags) const
1542 {
1543     if (m_data.hwnd)
1544         return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags);
1545     return 0;
1546 }
1547
1548 QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const
1549 {
1550     if (m_data.hwnd)
1551         return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint),
1552                                   cwexflags);
1553     return 0;
1554 }
1555
1556 #ifndef Q_OS_WINCE
1557 void QWindowsWindow::alertWindow(int durationMs)
1558 {
1559     DWORD timeOutMs = GetCaretBlinkTime();
1560     if (!timeOutMs || timeOutMs == INFINITE)
1561         timeOutMs = 250;
1562
1563     FLASHWINFO info;
1564     info.cbSize = sizeof(info);
1565     info.hwnd = m_data.hwnd;
1566     info.dwFlags = FLASHW_TRAY;
1567     info.dwTimeout = timeOutMs;
1568     info.uCount = durationMs == 0 ? 10 : durationMs / timeOutMs;
1569     FlashWindowEx(&info);
1570 }
1571
1572 void QWindowsWindow::stopAlertWindow()
1573 {
1574     FLASHWINFO info;
1575     info.cbSize = sizeof(info);
1576     info.hwnd = m_data.hwnd;
1577     info.dwFlags = FLASHW_STOP;
1578     info.dwTimeout = 0;
1579     info.uCount = 0;
1580     FlashWindowEx(&info);
1581 }
1582 #endif // !Q_OS_WINCE
1583
1584 bool QWindowsWindow::isEnabled() const
1585 {
1586     return (style() & WS_DISABLED) == 0;
1587 }
1588
1589 void QWindowsWindow::setEnabled(bool enabled)
1590 {
1591     const unsigned oldStyle = style();
1592     unsigned newStyle = oldStyle;
1593     if (enabled) {
1594         newStyle &= ~WS_DISABLED;
1595     } else {
1596         newStyle |= WS_DISABLED;
1597     }
1598     if (newStyle != oldStyle)
1599         setStyle(newStyle);
1600 }
1601
1602 #ifdef QT_OPENGL_ES_2
1603 EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config)
1604 {
1605     if (!m_eglSurface) {
1606         m_staticEglContext = staticContext;
1607         m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL);
1608         if (m_eglSurface == EGL_NO_SURFACE)
1609             qWarning("%s: Could not create the egl surface (eglCreateWindowSurface failed): error = 0x%x\n",
1610                      Q_FUNC_INFO, eglGetError());
1611         if (QWindowsContext::verboseGL)
1612             qDebug("%s: Created EGL surface %p, this = %p",
1613                    __FUNCTION__, m_eglSurface, this);
1614     }
1615     return m_eglSurface;
1616 }
1617 #endif // QT_OPENGL_ES_2
1618
1619 QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf)
1620 {
1621     const int iwf = int(wf);
1622     QByteArray rc = "0x";
1623     rc += QByteArray::number(iwf, 16);
1624     rc += " [";
1625
1626     switch ((iwf & Qt::WindowType_Mask)) {
1627     case Qt::Widget:
1628         rc += " Widget";
1629         break;
1630     case Qt::Window:
1631         rc += " Window";
1632         break;
1633     case Qt::Dialog:
1634         rc += " Dialog";
1635         break;
1636     case Qt::Sheet:
1637         rc += " Sheet";
1638         break;
1639     case Qt::Popup:
1640         rc += " Popup";
1641         break;
1642     case Qt::Tool:
1643         rc += " Tool";
1644         break;
1645     case Qt::ToolTip:
1646         rc += " ToolTip";
1647         break;
1648     case Qt::SplashScreen:
1649         rc += " SplashScreen";
1650         break;
1651     case Qt::Desktop:
1652         rc += " Desktop";
1653         break;
1654     case Qt::SubWindow:
1655         rc += " SubWindow";
1656         break;
1657     }
1658     if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint";
1659     if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC";
1660     if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint";
1661     if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint";
1662     if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint";
1663     if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint";
1664     if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint";
1665     if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint";
1666     if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint";
1667     if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint";
1668     if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint";
1669     if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint";
1670     if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint";
1671     rc += ']';
1672     return rc;
1673 }
1674
1675 QT_END_NAMESPACE