Revert "Move QWindowSystemInterface out of qpa."
[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 #ifndef Q_OS_WINCE
557     style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
558 #endif
559     if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
560         qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
561     const QMargins result(qAbs(rect.left), qAbs(rect.top),
562                           qAbs(rect.right), qAbs(rect.bottom));
563     if (QWindowsContext::verboseWindows)
564         qDebug().nospace() << __FUNCTION__ << " style= 0x"
565                  << QString::number(style, 16)
566                  << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result;
567
568     return result;
569 }
570
571 #ifndef Q_OS_WINCE
572 void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
573 {
574     return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE),
575                              GetWindowLong(hwnd, GWL_EXSTYLE), mmi);
576 }
577
578 void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
579 {
580     if (QWindowsContext::verboseWindows)
581         qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min="
582                            << minimumSize.width() << ',' << minimumSize.height()
583                            << " max=" << maximumSize.width() << ',' << maximumSize.height()
584                            << " in " << *mmi;
585
586     const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
587     const int frameWidth = margins.left() + margins.right();
588     const int frameHeight = margins.top() + margins.bottom();
589     if (minimumSize.width() > 0)
590         mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
591     if (minimumSize.height() > 0)
592         mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
593
594     const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
595     const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
596     if (maximumWidth < QWINDOWSIZE_MAX)
597         mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
598     // windows with title bar have an implicit size limit of 112 pixels
599     if (maximumHeight < QWINDOWSIZE_MAX)
600         mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112);
601     if (QWindowsContext::verboseWindows)
602         qDebug().nospace() << '<' << __FUNCTION__
603                            << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
604                            << " out " << *mmi;
605 }
606 #endif // !Q_OS_WINCE
607
608 bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
609 {
610     return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
611            == QWindowPrivate::WindowFrameInclusive;
612 }
613
614 /*!
615     \class QWindowCreationContext
616     \brief Active Context for creating windows.
617
618     There is a phase in window creation (WindowCreationData::create())
619     in which events are sent before the system API CreateWindowEx() returns
620     the handle. These cannot be handled by the platform window as the association
621     of the unknown handle value to the window does not exist yet and as not
622     to trigger recursive handle creation, etc.
623
624     In that phase, an instance of  QWindowCreationContext is set on
625     QWindowsContext.
626
627     QWindowCreationContext stores the information to answer the initial
628     WM_GETMINMAXINFO and obtains the corrected size/position.
629
630     \sa WindowCreationData, QWindowsContext
631     \internal
632     \ingroup qt-lighthouse-win
633 */
634
635 QWindowCreationContext::QWindowCreationContext(const QWindow *w,
636                                                const QRect &geometry,
637                                                DWORD style_, DWORD exStyle_) :
638     geometryHint(w), style(style_), exStyle(exStyle_),
639     requestedGeometry(geometry), obtainedGeometry(geometry),
640     margins(QWindowsGeometryHint::frame(style, exStyle)),
641     frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
642     frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
643 {
644     // Geometry of toplevels does not consider window frames.
645     // TODO: No concept of WA_wasMoved yet that would indicate a
646     // CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
647     // for toplevels.
648     if (geometry.isValid()) {
649         frameX = geometry.x();
650         frameY = geometry.y();
651         frameWidth = margins.left() + geometry.width() + margins.right();
652         frameHeight = margins.top() + geometry.height() + margins.bottom();
653         const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
654         if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
655             frameX -= margins.left();
656             frameY -= margins.top();
657         }
658     }
659     if (QWindowsContext::verboseWindows)
660         qDebug().nospace()
661                 << __FUNCTION__ << ' ' << w << geometry
662                 << " pos incl. frame" << QWindowsGeometryHint::positionIncludesFrame(w)
663                 << " frame: " << frameWidth << 'x' << frameHeight << '+'
664                 << frameX << '+' << frameY
665                 << " min" << geometryHint.minimumSize
666                 << " max" << geometryHint.maximumSize;
667 }
668
669 /*!
670     \class QWindowsWindow
671     \brief Raster or OpenGL Window.
672
673     \list
674     \li Raster type: handleWmPaint() is implemented to
675        to bitblt the image. The DC can be accessed
676        via getDC/Relase DC, which has a special handling
677        when within a paint event (in that case, the DC obtained
678        from BeginPaint() is returned).
679
680     \li Open GL: The first time QWindowsGLContext accesses
681        the handle, it sets up the pixelformat on the DC
682        which in turn sets it on the window (see flag
683        PixelFormatInitialized).
684        handleWmPaint() is empty (although required).
685     \endlist
686
687     \internal
688     \ingroup qt-lighthouse-win
689 */
690
691 QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
692     QPlatformWindow(aWindow),
693     m_data(data),
694     m_flags(0),
695     m_hdc(0),
696     m_windowState(Qt::WindowNoState),
697     m_opacity(1.0),
698     m_mouseGrab(false),
699     m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()),
700     m_dropTarget(0),
701     m_savedStyle(0),
702     m_format(aWindow->format())
703 #ifdef QT_OPENGL_ES_2
704    , m_eglSurface(0)
705 #endif
706 {
707     if (aWindow->surfaceType() == QWindow::OpenGLSurface)
708         setFlag(OpenGLSurface);
709     QWindowsContext::instance()->addWindow(m_data.hwnd, this);
710     if (aWindow->isTopLevel()) {
711         switch (aWindow->windowType()) {
712         case Qt::Window:
713         case Qt::Dialog:
714         case Qt::Sheet:
715         case Qt::Drawer:
716         case Qt::Popup:
717         case Qt::Tool:
718             registerDropSite();
719             break;
720         default:
721             break;
722         }
723     }
724     setWindowState(aWindow->windowState());
725 }
726
727 QWindowsWindow::~QWindowsWindow()
728 {
729     destroyWindow();
730 }
731
732 void QWindowsWindow::destroyWindow()
733 {
734     if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
735         qDebug() << __FUNCTION__ << this << window() << m_data.hwnd;
736     if (m_data.hwnd) { // Stop event dispatching before Window is destroyed.
737         unregisterDropSite();
738         QWindowsContext::instance()->removeWindow(m_data.hwnd);
739 #ifdef QT_OPENGL_ES_2
740         if (m_eglSurface) {
741             if (QWindowsContext::verboseGL)
742                 qDebug("%s: Freeing EGL surface %p, this = %p",
743                        __FUNCTION__, m_eglSurface, this);
744             eglDestroySurface(m_staticEglContext->display(), m_eglSurface);
745             m_eglSurface = 0;
746         }
747 #endif
748         if (m_data.hwnd != GetDesktopWindow())
749             DestroyWindow(m_data.hwnd);
750         m_data.hwnd = 0;
751     }
752 }
753
754 void QWindowsWindow::registerDropSite()
755 {
756     if (m_data.hwnd && !m_dropTarget) {
757         m_dropTarget = new QWindowsOleDropTarget(window());
758         RegisterDragDrop(m_data.hwnd, m_dropTarget);
759         CoLockObjectExternal(m_dropTarget, true, true);
760     }
761 }
762
763 void QWindowsWindow::unregisterDropSite()
764 {
765     if (m_data.hwnd && m_dropTarget) {
766         m_dropTarget->Release();
767         CoLockObjectExternal(m_dropTarget, false, true);
768         RevokeDragDrop(m_data.hwnd);
769         m_dropTarget = 0;
770     }
771 }
772
773 QWindow *QWindowsWindow::topLevelOf(QWindow *w)
774 {
775     while (QWindow *parent = w->parent())
776         w = parent;
777     return w;
778 }
779
780 QWindowsWindow::WindowData
781     QWindowsWindow::WindowData::create(const QWindow *w,
782                                        const WindowData &parameters,
783                                        const QString &title)
784 {
785     WindowCreationData creationData;
786     creationData.fromWindow(w, parameters.flags);
787     WindowData result = creationData.create(w, parameters.geometry, title);
788     creationData.initialize(result.hwnd, false, 1);
789     return result;
790 }
791
792 void QWindowsWindow::setVisible(bool visible)
793 {
794     if (QWindowsContext::verboseWindows)
795         qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible;
796     if (m_data.hwnd) {
797         if (visible) {
798             show_sys();
799             QWindowSystemInterface::handleExposeEvent(window(),
800                                                       QRect(QPoint(), geometry().size()));
801         } else {
802             hide_sys();
803             QWindowSystemInterface::handleExposeEvent(window(), QRegion());
804         }
805     }
806 }
807
808 bool QWindowsWindow::isVisible() const
809 {
810     return m_data.hwnd && IsWindowVisible(m_data.hwnd);
811 }
812
813 bool QWindowsWindow::isActive() const
814 {
815     // Check for native windows or children of the active native window.
816     if (const HWND activeHwnd = GetActiveWindow())
817         if (m_data.hwnd == activeHwnd || IsChild(activeHwnd, m_data.hwnd))
818             return true;
819     return false;
820 }
821
822 // partially from QWidgetPrivate::show_sys()
823 void QWindowsWindow::show_sys() const
824 {
825     int sm = SW_SHOWNORMAL;
826     bool fakedMaximize = false;
827     const QWindow *w = window();
828     const Qt::WindowFlags flags = w->windowFlags();
829     const Qt::WindowType type = w->windowType();
830     if (w->isTopLevel()) {
831         const Qt::WindowState state = w->windowState();
832         if (state & Qt::WindowMinimized) {
833             sm = SW_SHOWMINIMIZED;
834             if (!isVisible())
835                 sm = SW_SHOWMINNOACTIVE;
836         } else if (state & Qt::WindowMaximized) {
837             sm = SW_SHOWMAXIMIZED;
838             // Windows will not behave correctly when we try to maximize a window which does not
839             // have minimize nor maximize buttons in the window frame. Windows would then ignore
840             // non-available geometry, and rather maximize the widget to the full screen, minus the
841             // window frame (caption). So, we do a trick here, by adding a maximize button before
842             // maximizing the widget, and then remove the maximize button afterwards.
843             if (flags & Qt::WindowTitleHint &&
844                 !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
845                 fakedMaximize = TRUE;
846                 setStyle(style() | WS_MAXIMIZEBOX);
847             }
848         }
849     }
850     if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool)
851         sm = SW_SHOWNOACTIVATE;
852
853     ShowWindow(m_data.hwnd, sm);
854
855     if (fakedMaximize) {
856         setStyle(style() & ~WS_MAXIMIZEBOX);
857         SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0,
858                      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
859                      | SWP_FRAMECHANGED);
860     }
861 }
862
863 // partially from QWidgetPrivate::hide_sys()
864 void QWindowsWindow::hide_sys() const
865 {
866     const Qt::WindowFlags flags = window()->windowFlags();
867     if (flags != Qt::Desktop) {
868         if (flags & Qt::Popup)
869             ShowWindow(m_data.hwnd, SW_HIDE);
870         else
871             SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
872     }
873 }
874
875 void QWindowsWindow::setParent(const QPlatformWindow *newParent)
876 {
877     if (QWindowsContext::verboseWindows)
878         qDebug() << __FUNCTION__ << window() << newParent;
879
880     if (newParent != parent() && m_data.hwnd)
881         setParent_sys(newParent);
882 }
883
884 void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
885 {
886     HWND parentHWND = 0;
887     if (parent) {
888         const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
889         parentHWND = parentW->handle();
890
891     }
892
893     const bool wasTopLevel = window()->isTopLevel();
894     const bool isTopLevel = parentHWND == 0;
895
896     setFlag(WithinSetParent);
897     SetParent(m_data.hwnd, parentHWND);
898     clearFlag(WithinSetParent);
899
900     // WS_CHILD/WS_POPUP must be manually set/cleared in addition
901     // to dialog frames, etc (see  SetParent() ) if the top level state changes.
902     if (wasTopLevel != isTopLevel) {
903         const unsigned flags = isTopLevel ? unsigned(0) : unsigned(WindowCreationData::ForceChild);
904         setWindowFlags_sys(window()->windowFlags(), flags);
905     }
906 }
907
908 void QWindowsWindow::handleShown()
909 {
910     QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
911 }
912
913 void QWindowsWindow::handleHidden()
914 {
915     QWindowSystemInterface::handleExposeEvent(window(), QRegion());
916 }
917
918 void QWindowsWindow::setGeometry(const QRect &rectIn)
919 {
920     QRect rect = rectIn;
921     // This means it is a call from QWindow::setFramePos() and
922     // the coordinates include the frame (size is still the contents rectangle).
923     if (QWindowsGeometryHint::positionIncludesFrame(window())) {
924         const QMargins margins = frameMargins();
925         rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
926     }
927     const QSize oldSize = m_data.geometry.size();
928     m_data.geometry = rect;
929     const QSize newSize = rect.size();
930     // Check on hint.
931     if (newSize != oldSize) {
932         const QWindowsGeometryHint hint(window());
933         if (!hint.validSize(newSize)) {
934             qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
935                      "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
936                      newSize.width(), newSize.height(),
937                      hint.minimumSize.width(), hint.minimumSize.height(),
938                      hint.maximumSize.width(), hint.maximumSize.height(),
939                      qPrintable(window()->objectName()));
940         }
941     }
942     if (m_data.hwnd) {
943         // A ResizeEvent with resulting geometry will be sent. If we cannot
944         // achieve that size (for example, window title minimal constraint),
945         // notify and warn.
946         setGeometry_sys(rect);
947         if (m_data.geometry != rect) {
948             qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
949                      " Resulting geometry:  %dx%d+%d+%d "
950                      "(frame: %d, %d, %d, %d).",
951                      __FUNCTION__,
952                      rect.width(), rect.height(), rect.x(), rect.y(),
953                      qPrintable(window()->objectName()),
954                      m_data.geometry.width(), m_data.geometry.height(),
955                      m_data.geometry.x(), m_data.geometry.y(),
956                      m_data.frame.left(), m_data.frame.top(),
957                      m_data.frame.right(), m_data.frame.bottom());
958         }
959     } else {
960         QPlatformWindow::setGeometry(rect);
961     }
962 }
963
964 void QWindowsWindow::handleMoved()
965 {
966     // Minimize/Set parent can send nonsensical move events.
967     if (!IsIconic(m_data.hwnd) && !testFlag(WithinSetParent))
968         handleGeometryChange();
969 }
970
971 void QWindowsWindow::handleResized(int wParam)
972 {
973     switch (wParam) {
974     case SIZE_MAXHIDE: // Some other window affected.
975     case SIZE_MAXSHOW:
976         return;
977     case SIZE_MINIMIZED:
978         handleWindowStateChange(Qt::WindowMinimized);
979         return;
980     case SIZE_MAXIMIZED:
981         handleWindowStateChange(Qt::WindowMaximized);
982         handleGeometryChange();
983         break;
984     case SIZE_RESTORED:
985         bool fullScreen = isFullScreen_sys();
986         if ((m_windowState != Qt::WindowNoState) || fullScreen)
987             handleWindowStateChange(fullScreen ? Qt::WindowFullScreen : Qt::WindowNoState);
988         handleGeometryChange();
989         break;
990     }
991 }
992
993 void QWindowsWindow::handleGeometryChange()
994 {
995     //Prevent recursive resizes for Windows CE
996     if (testFlag(WithinSetStyle))
997         return;
998     m_data.geometry = geometry_sys();
999     QPlatformWindow::setGeometry(m_data.geometry);
1000     if (testFlag(SynchronousGeometryChangeEvent))
1001         QWindowSystemInterface::handleSynchronousGeometryChange(window(), m_data.geometry);
1002     else
1003         QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
1004
1005     if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows)
1006         qDebug() << __FUNCTION__ << this << window() << m_data.geometry;
1007 }
1008
1009 void QWindowsWindow::setGeometry_sys(const QRect &rect) const
1010 {
1011     const QMargins margins = frameMargins();
1012     const QRect frameGeometry = rect + margins;
1013
1014     if (QWindowsContext::verboseWindows)
1015         qDebug() << '>' << __FUNCTION__ << this << window()
1016                  << "    \n from " << geometry_sys() << " frame: "
1017                  << margins << " to " <<rect
1018                  << " new frame: " << frameGeometry;
1019
1020     const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(),
1021                                frameGeometry.width(), frameGeometry.height(), true);
1022     if (QWindowsContext::verboseWindows)
1023         qDebug() << '<' << __FUNCTION__ << this << window()
1024                  << "    \n resulting " << rc << geometry_sys();
1025 }
1026
1027 QRect QWindowsWindow::frameGeometry_sys() const
1028 {
1029     // Warning: Returns bogus values when minimized.
1030     bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded;
1031     return frameGeometry(m_data.hwnd, isRealTopLevel);
1032 }
1033
1034 QRect QWindowsWindow::geometry_sys() const
1035 {
1036     return frameGeometry_sys() - frameMargins();
1037 }
1038
1039 /*!
1040     Allocates a HDC for the window or returns the temporary one
1041     obtained from WinAPI BeginPaint within a WM_PAINT event.
1042
1043     \sa releaseDC()
1044 */
1045
1046 HDC QWindowsWindow::getDC()
1047 {
1048     if (!m_hdc)
1049         m_hdc = GetDC(handle());
1050     return m_hdc;
1051 }
1052
1053 /*!
1054     Relases the HDC for the window or does nothing in
1055     case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
1056
1057     \sa getDC()
1058 */
1059
1060 void QWindowsWindow::releaseDC()
1061 {
1062     if (m_hdc && !testFlag(DCFromBeginPaint)) {
1063         ReleaseDC(handle(), m_hdc);
1064         m_hdc = 0;
1065     }
1066 }
1067
1068 bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
1069                                          WPARAM, LPARAM)
1070 {
1071     // Ignore invalid update bounding rectangles
1072     if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
1073         return false;
1074     if (message == WM_ERASEBKGND) // Backing store - ignored.
1075         return true;
1076     PAINTSTRUCT ps;
1077     if (testFlag(OpenGLSurface)) {
1078         // Observed painting problems with Aero style disabled (QTBUG-7865).
1079         if (testFlag(OpenGLDoubleBuffered))
1080             InvalidateRect(hwnd, 0, false);
1081         BeginPaint(hwnd, &ps);
1082         QWindowSystemInterface::handleSynchronousExposeEvent(window(),
1083                                                              QRegion(qrectFromRECT(ps.rcPaint)));
1084         EndPaint(hwnd, &ps);
1085     } else {
1086         const HDC dc = BeginPaint(hwnd, &ps);
1087         const QRect updateRect = qrectFromRECT(ps.rcPaint);
1088         if (updateRect.size() == m_data.geometry.size()) {
1089             // Store DC for access by the backing store if it has the full size.
1090             releaseDC();
1091             setFlag(DCFromBeginPaint);
1092             m_hdc = dc;
1093         }
1094         if (QWindowsContext::verboseIntegration)
1095             qDebug() << __FUNCTION__ << this << window() << updateRect;
1096
1097         QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRegion(updateRect));
1098         if (testFlag(DCFromBeginPaint)) {
1099             clearFlag(DCFromBeginPaint);
1100             m_hdc = 0;
1101         }
1102         EndPaint(hwnd, &ps);
1103     }
1104     return true;
1105 }
1106
1107 void QWindowsWindow::setWindowTitle(const QString &title)
1108 {
1109     if (QWindowsContext::verboseWindows)
1110         qDebug() << __FUNCTION__ << this << window() <<title;
1111     if (m_data.hwnd)
1112         SetWindowText(m_data.hwnd, (const wchar_t*)title.utf16());
1113 }
1114
1115 Qt::WindowFlags QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
1116 {
1117     if (QWindowsContext::verboseWindows)
1118         qDebug() << '>' << __FUNCTION__ << this << window() << "\n    from: "
1119                  << QWindowsWindow::debugWindowFlags(m_data.flags)
1120                  << "\n    to: " << QWindowsWindow::debugWindowFlags(flags);
1121     const QRect oldGeometry = geometry();
1122     if (m_data.flags != flags) {
1123         m_data.flags = flags;
1124         if (m_data.hwnd)
1125             m_data = setWindowFlags_sys(flags);
1126     }
1127     // When switching to a frameless window, geometry
1128     // may change without a WM_MOVE. Report change manually.
1129     // Do not send synchronously as not to clobber the widget
1130     // geometry in a sequence of setting flags and geometry.
1131     const QRect newGeometry = geometry_sys();
1132     if (oldGeometry != newGeometry)
1133         handleGeometryChange();
1134
1135     if (QWindowsContext::verboseWindows)
1136         qDebug() << '<' << __FUNCTION__ << "\n    returns: "
1137                  << QWindowsWindow::debugWindowFlags(m_data.flags)
1138                  << " geometry " << oldGeometry << "->" << newGeometry;
1139     return m_data.flags;
1140 }
1141
1142 QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
1143                                                               unsigned flags) const
1144 {
1145     WindowCreationData creationData;
1146     creationData.fromWindow(window(), wt, flags);
1147     creationData.applyWindowFlags(m_data.hwnd);
1148     creationData.initialize(m_data.hwnd, true, m_opacity);
1149
1150     WindowData result = m_data;
1151     result.flags = creationData.flags;
1152     result.embedded = creationData.embedded;
1153     setFlag(FrameDirty);
1154     return result;
1155 }
1156
1157 void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
1158 {
1159     if (QWindowsContext::verboseWindows)
1160         qDebug() << __FUNCTION__ << this << window()
1161                  << "\n    from " << debugWindowStates(m_windowState)
1162                  << " to " << debugWindowStates(state);
1163     setFlag(FrameDirty);
1164     m_windowState = state;
1165     QWindowSystemInterface::handleWindowStateChanged(window(), state);
1166 }
1167
1168 Qt::WindowState QWindowsWindow::setWindowState(Qt::WindowState state)
1169 {
1170     if (m_data.hwnd) {
1171         setWindowState_sys(state);
1172         m_windowState = state;
1173     }
1174     return state;
1175 }
1176
1177 bool QWindowsWindow::isFullScreen_sys() const
1178 {
1179     return geometry_sys() == window()->screen()->geometry();
1180 }
1181
1182 /*!
1183     \brief Change the window state.
1184
1185     \note Window frames change when maximized;
1186     the top margin shrinks somewhat but that cannot be obtained using
1187     AdjustWindowRectEx().
1188
1189     \note Some calls to SetWindowLong require a subsequent call
1190     to ShowWindow.
1191 */
1192
1193 void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
1194 {
1195     const Qt::WindowState &oldState = m_windowState;
1196     if (oldState == newState)
1197         return;
1198     if (QWindowsContext::verboseWindows)
1199         qDebug() << '>' << __FUNCTION__ << this << window()
1200                  << " from " << debugWindowStates(oldState)
1201                  << " to " << debugWindowStates(newState);
1202
1203     const bool visible = isVisible();
1204
1205     setFlag(FrameDirty);
1206
1207     if ((oldState == Qt::WindowMaximized) != (newState == Qt::WindowMaximized)) {
1208         if (visible && !(newState == Qt::WindowMinimized))
1209             ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1210     }
1211
1212     if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
1213         if (newState == Qt::WindowFullScreen) {
1214 #ifndef Q_FLATTEN_EXPOSE
1215             UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
1216 #else
1217             UINT newStyle = WS_POPUP;
1218 #endif
1219             // Save geometry and style to be restored when fullscreen
1220             // is turned off again, since on Windows, it is not a real
1221             // Window state but emulated by changing geometry and style.
1222             if (!m_savedStyle) {
1223                 m_savedStyle = style();
1224 #ifndef Q_OS_WINCE
1225                 if (oldState == Qt::WindowMinimized) {
1226                     WINDOWPLACEMENT wp;
1227                     wp.length = sizeof(WINDOWPLACEMENT);
1228                     if (GetWindowPlacement(m_data.hwnd, &wp))
1229                         m_savedFrameGeometry = qrectFromRECT(wp.rcNormalPosition);
1230                 } else {
1231 #endif
1232                     m_savedFrameGeometry = frameGeometry_sys();
1233 #ifndef Q_OS_WINCE
1234                 }
1235 #endif
1236             }
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             const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
1245             const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
1246             setFlag(SynchronousGeometryChangeEvent);
1247             SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
1248             if (!wasSync)
1249                 clearFlag(SynchronousGeometryChangeEvent);
1250             QWindowSystemInterface::handleSynchronousGeometryChange(window(), r);
1251         } else if (newState != Qt::WindowMinimized) {
1252             // Restore saved state.
1253             unsigned newStyle = m_savedStyle ? m_savedStyle : style();
1254             if (visible)
1255                 newStyle |= WS_VISIBLE;
1256             setStyle(newStyle);
1257
1258             UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
1259             if (!m_savedFrameGeometry.isValid())
1260                 swpf |= SWP_NOSIZE | SWP_NOMOVE;
1261             const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
1262             setFlag(SynchronousGeometryChangeEvent);
1263             SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(),
1264                          m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf);
1265             if (!wasSync)
1266                 clearFlag(SynchronousGeometryChangeEvent);
1267             // preserve maximized state
1268             if (visible)
1269                 ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1270             m_savedStyle = 0;
1271             m_savedFrameGeometry = QRect();
1272         }
1273     }
1274
1275     if ((oldState == Qt::WindowMinimized) != (newState == Qt::WindowMinimized)) {
1276         if (visible)
1277             ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE :
1278                        (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1279     }
1280     if (QWindowsContext::verboseWindows)
1281         qDebug() << '<' << __FUNCTION__ << this << window()
1282                  << debugWindowStates(newState);
1283 }
1284
1285 void QWindowsWindow::setStyle(unsigned s) const
1286 {
1287     if (QWindowsContext::verboseWindows)
1288         qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s);
1289     setFlag(WithinSetStyle);
1290     setFlag(FrameDirty);
1291     SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
1292     clearFlag(WithinSetStyle);
1293 }
1294
1295 void QWindowsWindow::setExStyle(unsigned s) const
1296 {
1297     if (QWindowsContext::verboseWindows)
1298         qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
1299         << " 0x" << QByteArray::number(s, 16);
1300     setFlag(FrameDirty);
1301     SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
1302 }
1303
1304 void QWindowsWindow::raise()
1305 {
1306     if (QWindowsContext::verboseWindows)
1307         qDebug() << __FUNCTION__ << this << window();
1308     SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1309 }
1310
1311 void QWindowsWindow::lower()
1312 {
1313     if (QWindowsContext::verboseWindows)
1314         qDebug() << __FUNCTION__ << this << window();
1315     if (m_data.hwnd)
1316         SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1317 }
1318
1319 void QWindowsWindow::windowEvent(QEvent *event)
1320 {
1321     switch (event->type()) {
1322     case QEvent::WindowBlocked: // Blocked by another modal window.
1323         setEnabled(false);
1324         setFlag(BlockedByModal);
1325         break;
1326     case QEvent::WindowUnblocked:
1327         setEnabled(true);
1328         clearFlag(BlockedByModal);
1329         break;
1330     default:
1331         break;
1332     }
1333 }
1334
1335 void QWindowsWindow::propagateSizeHints()
1336 {
1337     if (QWindowsContext::verboseWindows)
1338         qDebug() << __FUNCTION__ << this << window();
1339 }
1340
1341 QMargins QWindowsWindow::frameMargins() const
1342 {
1343     // Frames are invalidated by style changes (window state, flags).
1344     // As they are also required for geometry calculations in resize
1345     // event sequences, introduce a dirty flag mechanism to be able
1346     // to cache results.
1347     if (testFlag(FrameDirty)) {
1348         m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
1349         clearFlag(FrameDirty);
1350     }
1351     return m_data.frame;
1352 }
1353
1354 void QWindowsWindow::setOpacity(qreal level)
1355 {
1356     if (QWindowsContext::verboseWindows)
1357         qDebug() << __FUNCTION__ << level;
1358     if (m_opacity != level) {
1359         m_opacity = level;
1360         if (m_data.hwnd)
1361             setWindowOpacity(m_data.hwnd, m_data.flags, level);
1362     }
1363 }
1364
1365 static inline HRGN createRectRegion(const QRect &r)
1366 {
1367     return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
1368 }
1369
1370 static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
1371 {
1372     if (const HRGN rectRegion = createRectRegion(rect)) {
1373         HRGN result = CreateRectRgn(0, 0, 0, 0);
1374         if (CombineRgn(result, *winRegion, rectRegion, RGN_OR)) {
1375             DeleteObject(winRegion);
1376             *winRegion = result;
1377         }
1378         DeleteObject(rectRegion);
1379     }
1380 }
1381
1382 static HRGN qRegionToWinRegion(const QRegion &region)
1383 {
1384     const QVector<QRect> rects = region.rects();
1385     if (rects.isEmpty())
1386         return NULL;
1387     const int rectCount = rects.size();
1388     if (rectCount == 1)
1389         return createRectRegion(region.boundingRect());
1390     HRGN hRegion = createRectRegion(rects.front());
1391     for (int i = 1; i < rectCount; ++i)
1392         addRectToWinRegion(rects.at(i), &hRegion);
1393     return hRegion;
1394 }
1395
1396 void QWindowsWindow::setMask(const QRegion &region)
1397 {
1398     if (region.isEmpty()) {
1399          SetWindowRgn(m_data.hwnd, 0, true);
1400          return;
1401     }
1402     const HRGN winRegion = qRegionToWinRegion(region);
1403
1404     // Mask is in client area coordinates, so offset it in case we have a frame
1405     if (window()->isTopLevel()) {
1406         const QMargins margins = frameMargins();
1407         OffsetRgn(winRegion, margins.left(), margins.top());
1408     }
1409
1410     // SetWindowRgn takes ownership.
1411     if (!SetWindowRgn(m_data.hwnd, winRegion, true))
1412         DeleteObject(winRegion);
1413 }
1414
1415 void QWindowsWindow::requestActivateWindow()
1416 {
1417     if (QWindowsContext::verboseWindows)
1418         qDebug() << __FUNCTION__ << this << window();
1419     // 'Active' state handling is based in focus since it needs to work for
1420     // child windows as well.
1421     if (m_data.hwnd) {
1422         SetForegroundWindow(m_data.hwnd);
1423         SetFocus(m_data.hwnd);
1424     }
1425 }
1426
1427 bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
1428 {
1429     if (!m_data.hwnd) {
1430         qWarning("%s: No handle", __FUNCTION__);
1431         return false;
1432     }
1433     if (QWindowsContext::verboseWindows)
1434         qDebug() << __FUNCTION__ << this << window() << grab;
1435
1436     QWindowsContext *context = QWindowsContext::instance();
1437     if (grab) {
1438         context->setKeyGrabber(window());
1439     } else {
1440         if (context->keyGrabber() == window())
1441             context->setKeyGrabber(0);
1442     }
1443     return true;
1444 }
1445
1446 bool QWindowsWindow::setMouseGrabEnabled(bool grab)
1447 {
1448     bool result = false;
1449     if (!m_data.hwnd) {
1450         qWarning("%s: No handle", __FUNCTION__);
1451         return result;
1452     }
1453     if (QWindowsContext::verboseWindows)
1454         qDebug() << __FUNCTION__ << window() << grab;
1455
1456     if (m_mouseGrab != grab) {
1457         m_mouseGrab = grab;
1458         if (isVisible())
1459             setMouseGrabEnabled_sys(grab);
1460     }
1461     return grab;
1462 }
1463
1464 void QWindowsWindow::setMouseGrabEnabled_sys(bool grab)
1465 {
1466     if (grab) {
1467         SetCapture(m_data.hwnd);
1468     } else {
1469         ReleaseCapture();
1470     }
1471 }
1472
1473 static inline DWORD cornerToWinOrientation(Qt::Corner corner)
1474 {
1475     switch (corner) {
1476     case Qt::TopLeftCorner:
1477         return 0xf004; // SZ_SIZETOPLEFT;
1478     case Qt::TopRightCorner:
1479         return 0xf005; // SZ_SIZETOPRIGHT
1480     case Qt::BottomLeftCorner:
1481         return 0xf007; // SZ_SIZEBOTTOMLEFT
1482     case Qt::BottomRightCorner:
1483         return 0xf008; // SZ_SIZEBOTTOMRIGHT
1484     }
1485     return 0;
1486 }
1487
1488 bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
1489 {
1490     if (!GetSystemMenu(m_data.hwnd, FALSE))
1491         return false;
1492
1493     ReleaseCapture();
1494     PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
1495     setFlag(SizeGripOperation);
1496     return true;
1497 }
1498
1499 void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
1500 {
1501     if (enabled) {
1502         setFlag(FrameStrutEventsEnabled);
1503     } else {
1504         clearFlag(FrameStrutEventsEnabled);
1505     }
1506 }
1507
1508 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
1509 void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
1510 {
1511     const QWindowsGeometryHint hint(window());
1512     hint.applyToMinMaxInfo(m_data.hwnd, mmi);
1513     if (QWindowsContext::verboseWindows)
1514         qDebug() << __FUNCTION__ << window() << *mmi;
1515 }
1516 #endif // !Q_OS_WINCE
1517
1518 /*!
1519     \brief Applies to cursor property set on the window to the global cursor.
1520
1521     \sa QWindowsCursor
1522 */
1523
1524 void QWindowsWindow::applyCursor()
1525 {
1526     SetCursor(m_cursor.handle());
1527 }
1528
1529 void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
1530 {
1531     if (c.handle() != m_cursor.handle()) {
1532         const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
1533         if (QWindowsContext::verboseWindows)
1534             qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
1535                      << " isWUM=" << underMouse;
1536         m_cursor = c;
1537         if (underMouse)
1538             applyCursor();
1539     }
1540 }
1541
1542 /*!
1543     \brief Find a child window using flags from  ChildWindowFromPointEx.
1544 */
1545
1546 QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint,
1547                                                            unsigned cwexflags) const
1548 {
1549     if (m_data.hwnd)
1550         return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags);
1551     return 0;
1552 }
1553
1554 QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const
1555 {
1556     if (m_data.hwnd)
1557         return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint),
1558                                   cwexflags);
1559     return 0;
1560 }
1561
1562 #ifndef Q_OS_WINCE
1563 void QWindowsWindow::alertWindow(int durationMs)
1564 {
1565     DWORD timeOutMs = GetCaretBlinkTime();
1566     if (!timeOutMs || timeOutMs == INFINITE)
1567         timeOutMs = 250;
1568
1569     FLASHWINFO info;
1570     info.cbSize = sizeof(info);
1571     info.hwnd = m_data.hwnd;
1572     info.dwFlags = FLASHW_TRAY;
1573     info.dwTimeout = timeOutMs;
1574     info.uCount = durationMs == 0 ? 10 : durationMs / timeOutMs;
1575     FlashWindowEx(&info);
1576 }
1577
1578 void QWindowsWindow::stopAlertWindow()
1579 {
1580     FLASHWINFO info;
1581     info.cbSize = sizeof(info);
1582     info.hwnd = m_data.hwnd;
1583     info.dwFlags = FLASHW_STOP;
1584     info.dwTimeout = 0;
1585     info.uCount = 0;
1586     FlashWindowEx(&info);
1587 }
1588 #endif // !Q_OS_WINCE
1589
1590 bool QWindowsWindow::isEnabled() const
1591 {
1592     return (style() & WS_DISABLED) == 0;
1593 }
1594
1595 void QWindowsWindow::setEnabled(bool enabled)
1596 {
1597     const unsigned oldStyle = style();
1598     unsigned newStyle = oldStyle;
1599     if (enabled) {
1600         newStyle &= ~WS_DISABLED;
1601     } else {
1602         newStyle |= WS_DISABLED;
1603     }
1604     if (newStyle != oldStyle)
1605         setStyle(newStyle);
1606 }
1607
1608 #ifdef QT_OPENGL_ES_2
1609 EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config)
1610 {
1611     if (!m_eglSurface) {
1612         m_staticEglContext = staticContext;
1613         m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL);
1614         if (m_eglSurface == EGL_NO_SURFACE)
1615             qWarning("%s: Could not create the egl surface (eglCreateWindowSurface failed): error = 0x%x\n",
1616                      Q_FUNC_INFO, eglGetError());
1617         if (QWindowsContext::verboseGL)
1618             qDebug("%s: Created EGL surface %p, this = %p",
1619                    __FUNCTION__, m_eglSurface, this);
1620     }
1621     return m_eglSurface;
1622 }
1623 #endif // QT_OPENGL_ES_2
1624
1625 QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf)
1626 {
1627     const int iwf = int(wf);
1628     QByteArray rc = "0x";
1629     rc += QByteArray::number(iwf, 16);
1630     rc += " [";
1631
1632     switch ((iwf & Qt::WindowType_Mask)) {
1633     case Qt::Widget:
1634         rc += " Widget";
1635         break;
1636     case Qt::Window:
1637         rc += " Window";
1638         break;
1639     case Qt::Dialog:
1640         rc += " Dialog";
1641         break;
1642     case Qt::Sheet:
1643         rc += " Sheet";
1644         break;
1645     case Qt::Popup:
1646         rc += " Popup";
1647         break;
1648     case Qt::Tool:
1649         rc += " Tool";
1650         break;
1651     case Qt::ToolTip:
1652         rc += " ToolTip";
1653         break;
1654     case Qt::SplashScreen:
1655         rc += " SplashScreen";
1656         break;
1657     case Qt::Desktop:
1658         rc += " Desktop";
1659         break;
1660     case Qt::SubWindow:
1661         rc += " SubWindow";
1662         break;
1663     }
1664     if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint";
1665     if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC";
1666     if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint";
1667     if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint";
1668     if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint";
1669     if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint";
1670     if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint";
1671     if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint";
1672     if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint";
1673     if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint";
1674     if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint";
1675     if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint";
1676     if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint";
1677     rc += ']';
1678     return rc;
1679 }
1680
1681 QT_END_NAMESPACE