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