1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qwindowswindow.h"
43 #include "qwindowsnativeimage.h"
44 #include "qwindowscontext.h"
45 #include "qwindowsdrag.h"
46 #include "qwindowsscreen.h"
47 #include "qwindowscursor.h"
50 # include "qwindowseglcontext.h"
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>
60 #include <QtCore/QDebug>
64 Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &);
66 static QByteArray debugWinStyle(DWORD style)
69 rc += QByteArray::number(qulonglong(style), 16);
74 if (style & WS_OVERLAPPED)
75 rc += " WS_OVERLAPPED";
76 if (style & WS_CLIPSIBLINGS)
77 rc += " WS_CLIPSIBLINGS";
78 if (style & WS_CLIPCHILDREN)
79 rc += " WS_CLIPCHILDREN";
80 if (style & WS_THICKFRAME)
81 rc += " WS_THICKFRAME";
82 if (style & WS_DLGFRAME)
84 if (style & WS_SYSMENU)
86 if (style & WS_MINIMIZEBOX)
87 rc += " WS_MINIMIZEBOX";
88 if (style & WS_MAXIMIZEBOX)
89 rc += " WS_MAXIMIZEBOX";
93 static QByteArray debugWinExStyle(DWORD exStyle)
96 rc += QByteArray::number(qulonglong(exStyle), 16);
97 if (exStyle & WS_EX_TOOLWINDOW)
98 rc += " WS_EX_TOOLWINDOW";
99 if (exStyle & WS_EX_CONTEXTHELP)
100 rc += " WS_EX_CONTEXTHELP";
101 if (exStyle & WS_EX_LAYERED)
102 rc += " WS_EX_LAYERED";
106 static QByteArray debugWindowStates(Qt::WindowStates s)
109 QByteArray rc = "0x";
110 rc += QByteArray::number(int(s), 16);
111 if (s & Qt::WindowMinimized)
112 rc += " WindowMinimized";
113 if (s & Qt::WindowMaximized)
114 rc += " WindowMaximized";
115 if (s & Qt::WindowFullScreen)
116 rc += " WindowFullScreen";
117 if (s & Qt::WindowActive)
118 rc += " WindowActive";
122 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
123 QDebug operator<<(QDebug d, const MINMAXINFO &i)
125 d.nospace() << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ','
126 << i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x
127 << ',' << i.ptMaxPosition.y << " mintrack="
128 << i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y
129 << " maxtrack=" << i.ptMaxTrackSize.x << ','
130 << i.ptMaxTrackSize.y;
133 #endif // !Q_OS_WINCE
135 static inline QSize qSizeOfRect(const RECT &rect)
137 return QSize(rect.right -rect.left, rect.bottom - rect.top);
140 static inline QRect qrectFromRECT(const RECT &rect)
142 return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect));
145 static inline RECT RECTfromQRect(const QRect &rect)
147 const int x = rect.left();
148 const int y = rect.top();
149 RECT result = { x, y, x + rect.width(), y + rect.height() };
153 QDebug operator<<(QDebug d, const RECT &r)
155 d.nospace() << "RECT: left/top=" << r.left << ',' << r.top
156 << " right/bottom=" << r.right << ',' << r.bottom;
160 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_NCCALCSIZE
161 QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
163 qDebug().nospace() << "NCCALCSIZE_PARAMS "
164 << qrectFromRECT(p.rgrc[0])
165 << ' ' << qrectFromRECT(p.rgrc[1]) << ' '
166 << qrectFromRECT(p.rgrc[2]);
169 #endif // !Q_OS_WINCE
171 // Return the frame geometry relative to the parent
173 static inline QRect frameGeometry(HWND hwnd, bool topLevel)
175 RECT rect = { 0, 0, 0, 0 };
176 GetWindowRect(hwnd, &rect); // Screen coordinates.
177 const HWND parent = GetParent(hwnd);
178 if (parent && !topLevel) {
179 const int width = rect.right - rect.left;
180 const int height = rect.bottom - rect.top;
181 POINT leftTop = { rect.left, rect.top };
182 ScreenToClient(parent, &leftTop);
183 rect.left = leftTop.x;
184 rect.top = leftTop.y;
185 rect.right = leftTop.x + width;
186 rect.bottom = leftTop.y + height;
188 return qrectFromRECT(rect);
191 static inline QSize clientSize(HWND hwnd)
193 RECT rect = { 0, 0, 0, 0 };
194 GetClientRect(hwnd, &rect); // Always returns point 0,0, thus unusable for geometry.
195 return qSizeOfRect(rect);
198 // from qwidget_win.cpp/maximum layout size check removed.
199 static bool shouldShowMaximizeButton(Qt::WindowFlags flags)
201 if (flags & Qt::MSWindowsFixedSizeDialogHint)
203 // if the user explicitly asked for the maximize button, we try to add
204 // it even if the window has fixed size.
205 if (flags & Qt::CustomizeWindowHint &&
206 flags & Qt::WindowMaximizeButtonHint)
208 return flags & Qt::WindowMaximizeButtonHint;
211 static void setWindowOpacity(HWND hwnd, Qt::WindowFlags flags, qreal level)
213 #ifdef Q_OS_WINCE // maybe needs revisit WS_EX_LAYERED
218 const long wl = GetWindowLong(hwnd, GWL_EXSTYLE);
219 const bool isOpaque = level == 1.0 && !(flags & Qt::WindowTransparentForInput);
222 if (wl & WS_EX_LAYERED)
223 SetWindowLong(hwnd, GWL_EXSTYLE, wl & ~WS_EX_LAYERED);
225 if ((wl & WS_EX_LAYERED) == 0)
226 SetWindowLong(hwnd, GWL_EXSTYLE, wl | WS_EX_LAYERED);
227 if (flags & Qt::FramelessWindowHint) {
228 BLENDFUNCTION blend = {AC_SRC_OVER, 0, (BYTE)(255.0 * level), AC_SRC_ALPHA};
229 QWindowsContext::user32dll.updateLayeredWindow(hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
231 QWindowsContext::user32dll.setLayeredWindowAttributes(hwnd, 0, (int)(level * 255), LWA_ALPHA);
234 #endif // !Q_OS_WINCE
238 \class WindowCreationData
239 \brief Window creation code.
241 This struct gathers all information required to create a window.
242 Window creation is split in 3 steps:
245 \li fromWindow() Gather all required information
246 \li create() Create the system handle.
247 \li initialize() Post creation initialization steps.
250 The reason for this split is to also enable changing the QWindowFlags
254 \li fromWindow() Gather information and determine new system styles
255 \li applyWindowFlags() to apply the new window system styles.
256 \li initialize() Post creation initialization steps.
259 Contains the window creation code formerly in qwidget_win.cpp.
261 \sa QWindowCreationContext
263 \ingroup qt-lighthouse-win
266 struct WindowCreationData
268 typedef QWindowsWindow::WindowData WindowData;
269 enum Flags { ForceChild = 0x1 };
271 WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0),
272 topLevel(false), popup(false), dialog(false), desktop(false),
273 tool(false), embedded(false) {}
275 void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0);
276 inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const;
277 inline void applyWindowFlags(HWND hwnd) const;
278 void initialize(HWND h, bool frameChange, qreal opacityLevel) const;
280 Qt::WindowFlags flags;
294 QDebug operator<<(QDebug debug, const WindowCreationData &d)
296 debug.nospace() << QWindowsWindow::debugWindowFlags(d.flags)
297 << " GL=" << d.isGL << " topLevel=" << d.topLevel << " popup="
298 << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop
299 << " embedded=" << d.embedded
300 << " tool=" << d.tool << " style=" << debugWinStyle(d.style)
301 << " exStyle=" << debugWinExStyle(d.exStyle)
302 << " parent=" << d.parentHandle;
306 void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
307 unsigned creationFlags)
309 isGL = w->surfaceType() == QWindow::OpenGLSurface;
312 // Sometimes QWindow doesn't have a QWindow parent but does have a native parent window,
313 // e.g. in case of embedded ActiveQt servers. They should not be considered a top-level
314 // windows in such cases.
315 QVariant prop = w->property("_q_embedded_native_parent_handle");
316 if (prop.isValid()) {
318 parentHandle = (HWND)prop.value<WId>();
321 topLevel = ((creationFlags & ForceChild) || embedded) ? false : w->isTopLevel();
323 if (topLevel && flags == 1) {
324 qWarning("Remove me: fixing toplevel window flags");
325 flags |= Qt::WindowTitleHint|Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint
326 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
329 type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask);
348 if ((flags & Qt::MSWindowsFixedSizeDialogHint))
351 // Parent: Use transient parent for top levels.
353 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent.
354 } else if (!embedded) {
355 if (const QWindow *parentWindow = topLevel ? w->transientParent() : w->parent())
356 parentHandle = QWindowsWindow::handleOf(parentWindow);
359 if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
361 } else if (topLevel && !desktop) {
362 if (flags & Qt::FramelessWindowHint)
363 style = WS_POPUP; // no border
364 else if (flags & Qt::WindowTitleHint)
365 style = WS_OVERLAPPED;
373 // if (!testAttribute(Qt::WA_PaintUnclipped))
374 // ### Commented out for now as it causes some problems, but
375 // this should be correct anyway, so dig some more into this
376 #ifdef Q_FLATTEN_EXPOSE
378 style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat
380 style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
383 if ((type == Qt::Window || dialog || tool)) {
384 if (!(flags & Qt::FramelessWindowHint)) {
386 if (flags & Qt::MSWindowsFixedSizeDialogHint) {
387 style |= WS_DLGFRAME;
389 style |= WS_THICKFRAME;
391 if (flags & Qt::WindowTitleHint)
392 style |= WS_CAPTION; // Contains WS_DLGFRAME
394 if (flags & Qt::WindowSystemMenuHint)
396 if (flags & Qt::WindowMinimizeButtonHint)
397 style |= WS_MINIMIZEBOX;
398 if (shouldShowMaximizeButton(flags))
399 style |= WS_MAXIMIZEBOX;
401 exStyle |= WS_EX_TOOLWINDOW;
402 if (flags & Qt::WindowContextHelpButtonHint)
403 exStyle |= WS_EX_CONTEXTHELP;
405 exStyle |= WS_EX_TOOLWINDOW;
409 // make mouse events fall through this window
410 // NOTE: WS_EX_TRANSPARENT flag can make mouse inputs fall through a layered window
411 if (flagsIn & Qt::WindowTransparentForInput)
412 exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT;
418 QWindowsWindow::WindowData
419 WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const
421 typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
424 result.flags = flags;
426 if (desktop) { // desktop widget. No frame, hopefully?
427 result.hwnd = GetDesktopWindow();
428 result.geometry = frameGeometry(result.hwnd, true);
429 result.embedded = false;
430 if (QWindowsContext::verboseWindows)
431 qDebug().nospace() << "Created desktop window " << w << result.hwnd;
435 const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
437 const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
439 if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
440 title = topLevel ? qAppName() : w->objectName();
442 const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
443 const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
445 // Capture events before CreateWindowEx() returns.
446 const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle));
447 QWindowsContext::instance()->setWindowCreationContext(context);
449 if (QWindowsContext::verboseWindows)
451 << "CreateWindowEx: " << w << *this
452 << " class=" <<windowClassName << " title=" << title
453 << "\nrequested: " << geometry << ": "
454 << context->frameWidth << 'x' << context->frameHeight
455 << '+' << context->frameX << '+' << context->frameY;
457 result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
459 context->frameX, context->frameY,
460 context->frameWidth, context->frameHeight,
461 parentHandle, NULL, appinst, NULL);
462 QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
463 if (QWindowsContext::verboseWindows)
465 << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
466 << context->obtainedGeometry << context->margins;
469 qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
473 result.geometry = context->obtainedGeometry;
474 result.frame = context->margins;
475 result.embedded = embedded;
479 void WindowCreationData::applyWindowFlags(HWND hwnd) const
481 // Keep enabled and visible from the current style.
482 const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
483 const LONG_PTR oldExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
485 const LONG_PTR newStyle = style | (oldStyle & (WS_DISABLED|WS_VISIBLE));
486 if (oldStyle != newStyle)
487 SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
488 const LONG_PTR newExStyle = exStyle;
489 if (newExStyle != oldExStyle)
490 SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
491 if (QWindowsContext::verboseWindows)
492 qDebug().nospace() << __FUNCTION__ << hwnd << *this
493 << "\n Style from " << debugWinStyle(oldStyle) << "\n to "
494 << debugWinStyle(newStyle) << "\n ExStyle from "
495 << debugWinExStyle(oldExStyle) << " to "
496 << debugWinExStyle(newExStyle);
499 void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLevel) const
501 if (desktop || !hwnd)
503 UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE;
505 swpFlags |= SWP_FRAMECHANGED;
507 swpFlags |= SWP_NOACTIVATE;
508 if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
509 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, swpFlags);
510 if (flags & Qt::WindowStaysOnBottomHint)
511 qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
512 } else if (flags & Qt::WindowStaysOnBottomHint) {
513 SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags);
515 if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
516 HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
517 if (flags & Qt::WindowCloseButtonHint)
518 EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
520 EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
523 setWindowOpacity(hwnd, flags, opacityLevel);
525 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, swpFlags);
530 \class QWindowsGeometryHint
531 \brief Stores geometry constraints and provides utility functions.
533 Geometry constraints ready to apply to a MINMAXINFO taking frame
537 \ingroup qt-lighthouse-win
540 #define QWINDOWSIZE_MAX ((1<<24)-1)
542 QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) :
543 minimumSize(w->minimumSize()),
544 maximumSize(w->maximumSize())
548 bool QWindowsGeometryHint::validSize(const QSize &s) const
550 const int width = s.width();
551 const int height = s.height();
552 return width >= minimumSize.width() && width <= maximumSize.width()
553 && height >= minimumSize.height() && height <= maximumSize.height();
556 QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
558 RECT rect = {0,0,0,0};
560 style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
562 if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
563 qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
564 const QMargins result(qAbs(rect.left), qAbs(rect.top),
565 qAbs(rect.right), qAbs(rect.bottom));
566 if (QWindowsContext::verboseWindows)
567 qDebug().nospace() << __FUNCTION__ << " style= 0x"
568 << QString::number(style, 16)
569 << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result;
575 void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
577 return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE),
578 GetWindowLong(hwnd, GWL_EXSTYLE), mmi);
581 void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
583 if (QWindowsContext::verboseWindows)
584 qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min="
585 << minimumSize.width() << ',' << minimumSize.height()
586 << " max=" << maximumSize.width() << ',' << maximumSize.height()
589 const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
590 const int frameWidth = margins.left() + margins.right();
591 const int frameHeight = margins.top() + margins.bottom();
592 if (minimumSize.width() > 0)
593 mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
594 if (minimumSize.height() > 0)
595 mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
597 const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
598 const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
599 if (maximumWidth < QWINDOWSIZE_MAX)
600 mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
601 // windows with title bar have an implicit size limit of 112 pixels
602 if (maximumHeight < QWINDOWSIZE_MAX)
603 mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112);
604 if (QWindowsContext::verboseWindows)
605 qDebug().nospace() << '<' << __FUNCTION__
606 << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
609 #endif // !Q_OS_WINCE
611 bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
613 return qt_window_private(const_cast<QWindow *>(w))->positionPolicy
614 == QWindowPrivate::WindowFrameInclusive;
618 \class QWindowCreationContext
619 \brief Active Context for creating windows.
621 There is a phase in window creation (WindowCreationData::create())
622 in which events are sent before the system API CreateWindowEx() returns
623 the handle. These cannot be handled by the platform window as the association
624 of the unknown handle value to the window does not exist yet and as not
625 to trigger recursive handle creation, etc.
627 In that phase, an instance of QWindowCreationContext is set on
630 QWindowCreationContext stores the information to answer the initial
631 WM_GETMINMAXINFO and obtains the corrected size/position.
633 \sa WindowCreationData, QWindowsContext
635 \ingroup qt-lighthouse-win
638 QWindowCreationContext::QWindowCreationContext(const QWindow *w,
639 const QRect &geometry,
640 DWORD style_, DWORD exStyle_) :
641 geometryHint(w), style(style_), exStyle(exStyle_),
642 requestedGeometry(geometry), obtainedGeometry(geometry),
643 margins(QWindowsGeometryHint::frame(style, exStyle)),
644 frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
645 frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
647 // Geometry of toplevels does not consider window frames.
648 // TODO: No concept of WA_wasMoved yet that would indicate a
649 // CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
651 if (geometry.isValid()) {
652 frameX = geometry.x();
653 frameY = geometry.y();
654 frameWidth = margins.left() + geometry.width() + margins.right();
655 frameHeight = margins.top() + geometry.height() + margins.bottom();
656 const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
657 if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
658 frameX -= margins.left();
659 frameY -= margins.top();
662 if (QWindowsContext::verboseWindows)
664 << __FUNCTION__ << ' ' << w << geometry
665 << " pos incl. frame" << QWindowsGeometryHint::positionIncludesFrame(w)
666 << " frame: " << frameWidth << 'x' << frameHeight << '+'
667 << frameX << '+' << frameY
668 << " min" << geometryHint.minimumSize
669 << " max" << geometryHint.maximumSize;
673 \class QWindowsWindow
674 \brief Raster or OpenGL Window.
677 \li Raster type: handleWmPaint() is implemented to
678 to bitblt the image. The DC can be accessed
679 via getDC/Relase DC, which has a special handling
680 when within a paint event (in that case, the DC obtained
681 from BeginPaint() is returned).
683 \li Open GL: The first time QWindowsGLContext accesses
684 the handle, it sets up the pixelformat on the DC
685 which in turn sets it on the window (see flag
686 PixelFormatInitialized).
687 handleWmPaint() is empty (although required).
691 \ingroup qt-lighthouse-win
694 QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
695 QPlatformWindow(aWindow),
699 m_windowState(Qt::WindowNoState),
701 m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()),
704 m_format(aWindow->format()),
705 #ifdef QT_OPENGL_ES_2
709 m_previouslyHidden(false),
714 if (aWindow->surfaceType() == QWindow::OpenGLSurface)
715 setFlag(OpenGLSurface);
716 QWindowsContext::instance()->addWindow(m_data.hwnd, this);
717 if (aWindow->isTopLevel()) {
718 switch (aWindow->type()) {
731 setWindowState(aWindow->windowState());
734 QWindowsWindow::~QWindowsWindow()
740 void QWindowsWindow::destroyWindow()
742 if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
743 qDebug() << __FUNCTION__ << this << window() << m_data.hwnd;
744 if (m_data.hwnd) { // Stop event dispatching before Window is destroyed.
745 setFlag(WithinDestroy);
746 if (hasMouseCapture())
747 setMouseGrabEnabled(false);
748 unregisterDropSite();
749 #ifdef QT_OPENGL_ES_2
751 if (QWindowsContext::verboseGL)
752 qDebug("%s: Freeing EGL surface %p, this = %p",
753 __FUNCTION__, m_eglSurface, this);
754 eglDestroySurface(m_staticEglContext->display(), m_eglSurface);
759 if ((m_windowState & Qt::WindowFullScreen) && !m_previouslyHidden) {
760 HWND handle = FindWindow(L"HHTaskBar", L"");
762 ShowWindow(handle, SW_SHOW);
766 if (m_data.hwnd != GetDesktopWindow())
767 DestroyWindow(m_data.hwnd);
768 QWindowsContext::instance()->removeWindow(m_data.hwnd);
773 void QWindowsWindow::registerDropSite()
775 if (m_data.hwnd && !m_dropTarget) {
776 m_dropTarget = new QWindowsOleDropTarget(window());
777 RegisterDragDrop(m_data.hwnd, m_dropTarget);
778 CoLockObjectExternal(m_dropTarget, true, true);
782 void QWindowsWindow::unregisterDropSite()
784 if (m_data.hwnd && m_dropTarget) {
785 m_dropTarget->Release();
786 CoLockObjectExternal(m_dropTarget, false, true);
787 RevokeDragDrop(m_data.hwnd);
792 // Returns topmost QWindowsWindow ancestor even if there are embedded windows in the chain.
793 // Returns this window if it is the topmost ancestor.
794 QWindow *QWindowsWindow::topLevelOf(QWindow *w)
796 while (QWindow *parent = w->parent())
799 const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(w->handle());
801 // In case the topmost parent is embedded, find next ancestor using native methods
802 if (ww->isEmbedded(0)) {
803 HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT);
804 const HWND desktopHwnd = GetDesktopWindow();
805 const QWindowsContext *ctx = QWindowsContext::instance();
806 while (parentHWND && parentHWND != desktopHwnd) {
807 if (QWindowsWindow *ancestor = ctx->findPlatformWindow(parentHWND))
808 return topLevelOf(ancestor->window());
809 parentHWND = GetAncestor(parentHWND, GA_PARENT);
815 QWindowsWindow::WindowData
816 QWindowsWindow::WindowData::create(const QWindow *w,
817 const WindowData ¶meters,
818 const QString &title)
820 WindowCreationData creationData;
821 creationData.fromWindow(w, parameters.flags);
822 WindowData result = creationData.create(w, parameters.geometry, title);
823 creationData.initialize(result.hwnd, false, 1);
827 void QWindowsWindow::setVisible(bool visible)
829 if (QWindowsContext::verboseWindows)
830 qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible;
834 QWindowSystemInterface::handleExposeEvent(window(),
835 QRect(QPoint(), geometry().size()));
837 if (hasMouseCapture())
838 setMouseGrabEnabled(false);
840 QWindowSystemInterface::handleExposeEvent(window(), QRegion());
845 bool QWindowsWindow::isVisible() const
847 return m_data.hwnd && IsWindowVisible(m_data.hwnd);
850 bool QWindowsWindow::isActive() const
852 // Check for native windows or children of the active native window.
853 if (const HWND activeHwnd = GetActiveWindow())
854 if (m_data.hwnd == activeHwnd || IsChild(activeHwnd, m_data.hwnd))
859 bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const
862 const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(parentWindow);
863 const HWND hwnd = ww->handle();
864 if (!IsChild(hwnd, m_data.hwnd))
868 if (!m_data.embedded && parent())
869 return parent()->isEmbedded(0);
871 return m_data.embedded;
874 QPoint QWindowsWindow::mapToGlobal(const QPoint &pos) const
877 return QWindowsGeometryHint::mapToGlobal(m_data.hwnd, pos);
882 QPoint QWindowsWindow::mapFromGlobal(const QPoint &pos) const
885 return QWindowsGeometryHint::mapFromGlobal(m_data.hwnd, pos);
890 // partially from QWidgetPrivate::show_sys()
891 void QWindowsWindow::show_sys() const
893 int sm = SW_SHOWNORMAL;
894 bool fakedMaximize = false;
895 const QWindow *w = window();
896 const Qt::WindowFlags flags = w->flags();
897 const Qt::WindowType type = w->type();
898 if (w->isTopLevel()) {
899 const Qt::WindowState state = w->windowState();
900 if (state & Qt::WindowMinimized) {
901 sm = SW_SHOWMINIMIZED;
903 sm = SW_SHOWMINNOACTIVE;
904 } else if (state & Qt::WindowMaximized) {
905 sm = SW_SHOWMAXIMIZED;
906 // Windows will not behave correctly when we try to maximize a window which does not
907 // have minimize nor maximize buttons in the window frame. Windows would then ignore
908 // non-available geometry, and rather maximize the widget to the full screen, minus the
909 // window frame (caption). So, we do a trick here, by adding a maximize button before
910 // maximizing the widget, and then remove the maximize button afterwards.
911 if (flags & Qt::WindowTitleHint &&
912 !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
913 fakedMaximize = TRUE;
914 setStyle(style() | WS_MAXIMIZEBOX);
918 if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool)
919 sm = SW_SHOWNOACTIVATE;
921 ShowWindow(m_data.hwnd, sm);
924 setStyle(style() & ~WS_MAXIMIZEBOX);
925 SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0,
926 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
931 // partially from QWidgetPrivate::hide_sys()
932 void QWindowsWindow::hide_sys() const
934 const Qt::WindowFlags flags = window()->flags();
935 if (flags != Qt::Desktop) {
936 if (flags & Qt::Popup)
937 ShowWindow(m_data.hwnd, SW_HIDE);
939 SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
943 void QWindowsWindow::setParent(const QPlatformWindow *newParent)
945 if (QWindowsContext::verboseWindows)
946 qDebug() << __FUNCTION__ << window() << newParent;
949 setParent_sys(newParent);
952 void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
954 // Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels
955 HWND oldParentHWND = GetAncestor(m_data.hwnd, GA_PARENT);
956 HWND newParentHWND = 0;
958 const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
959 newParentHWND = parentW->handle();
963 // NULL handle means desktop window, which also has its proper handle -> disambiguate
964 HWND desktopHwnd = GetDesktopWindow();
965 if (oldParentHWND == desktopHwnd)
967 if (newParentHWND == desktopHwnd)
970 if (newParentHWND != oldParentHWND) {
971 const bool wasTopLevel = oldParentHWND == 0;
972 const bool isTopLevel = newParentHWND == 0;
974 setFlag(WithinSetParent);
975 SetParent(m_data.hwnd, newParentHWND);
976 clearFlag(WithinSetParent);
978 // WS_CHILD/WS_POPUP must be manually set/cleared in addition
979 // to dialog frames, etc (see SetParent() ) if the top level state changes.
980 if (wasTopLevel != isTopLevel) {
981 const unsigned flags = isTopLevel ? unsigned(0) : unsigned(WindowCreationData::ForceChild);
982 setWindowFlags_sys(window()->flags(), flags);
987 void QWindowsWindow::handleShown()
989 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(0, 0), geometry().size()));
992 void QWindowsWindow::handleHidden()
994 QWindowSystemInterface::handleExposeEvent(window(), QRegion());
997 void QWindowsWindow::setGeometry(const QRect &rectIn)
1000 // This means it is a call from QWindow::setFramePos() and
1001 // the coordinates include the frame (size is still the contents rectangle).
1002 if (QWindowsGeometryHint::positionIncludesFrame(window())) {
1003 const QMargins margins = frameMargins();
1004 rect.moveTopLeft(rect.topLeft() + QPoint(margins.left(), margins.top()));
1006 const QSize oldSize = m_data.geometry.size();
1007 m_data.geometry = rect;
1008 const QSize newSize = rect.size();
1010 if (newSize != oldSize) {
1011 const QWindowsGeometryHint hint(window());
1012 if (!hint.validSize(newSize)) {
1013 qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
1014 "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
1015 newSize.width(), newSize.height(),
1016 hint.minimumSize.width(), hint.minimumSize.height(),
1017 hint.maximumSize.width(), hint.maximumSize.height(),
1018 qPrintable(window()->objectName()));
1022 // A ResizeEvent with resulting geometry will be sent. If we cannot
1023 // achieve that size (for example, window title minimal constraint),
1025 setGeometry_sys(rect);
1026 if (m_data.geometry != rect) {
1027 qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
1028 " Resulting geometry: %dx%d+%d+%d "
1029 "(frame: %d, %d, %d, %d).",
1031 rect.width(), rect.height(), rect.x(), rect.y(),
1032 qPrintable(window()->objectName()),
1033 m_data.geometry.width(), m_data.geometry.height(),
1034 m_data.geometry.x(), m_data.geometry.y(),
1035 m_data.frame.left(), m_data.frame.top(),
1036 m_data.frame.right(), m_data.frame.bottom());
1039 QPlatformWindow::setGeometry(rect);
1043 void QWindowsWindow::handleMoved()
1045 // Minimize/Set parent can send nonsensical move events.
1046 if (!IsIconic(m_data.hwnd) && !testFlag(WithinSetParent))
1047 handleGeometryChange();
1050 void QWindowsWindow::handleResized(int wParam)
1053 case SIZE_MAXHIDE: // Some other window affected.
1056 case SIZE_MINIMIZED:
1057 handleWindowStateChange(Qt::WindowMinimized);
1059 case SIZE_MAXIMIZED:
1060 handleWindowStateChange(Qt::WindowMaximized);
1061 handleGeometryChange();
1064 bool fullScreen = isFullScreen_sys();
1065 if ((m_windowState != Qt::WindowNoState) || fullScreen)
1066 handleWindowStateChange(fullScreen ? Qt::WindowFullScreen : Qt::WindowNoState);
1067 handleGeometryChange();
1072 void QWindowsWindow::handleGeometryChange()
1074 //Prevent recursive resizes for Windows CE
1075 if (testFlag(WithinSetStyle))
1077 m_data.geometry = geometry_sys();
1078 QPlatformWindow::setGeometry(m_data.geometry);
1079 QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
1080 if (testFlag(SynchronousGeometryChangeEvent))
1081 QWindowSystemInterface::flushWindowSystemEvents();
1083 if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows)
1084 qDebug() << __FUNCTION__ << this << window() << m_data.geometry;
1087 void QWindowsWindow::setGeometry_sys(const QRect &rect) const
1089 const QMargins margins = frameMargins();
1090 const QRect frameGeometry = rect + margins;
1092 if (QWindowsContext::verboseWindows)
1093 qDebug() << '>' << __FUNCTION__ << this << window()
1094 << " \n from " << geometry_sys() << " frame: "
1095 << margins << " to " <<rect
1096 << " new frame: " << frameGeometry;
1098 const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(),
1099 frameGeometry.width(), frameGeometry.height(), true);
1100 if (QWindowsContext::verboseWindows)
1101 qDebug() << '<' << __FUNCTION__ << this << window()
1102 << " \n resulting " << rc << geometry_sys();
1105 QRect QWindowsWindow::frameGeometry_sys() const
1107 // Warning: Returns bogus values when minimized.
1108 bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded;
1109 return frameGeometry(m_data.hwnd, isRealTopLevel);
1112 QRect QWindowsWindow::geometry_sys() const
1114 return frameGeometry_sys() - frameMargins();
1118 Allocates a HDC for the window or returns the temporary one
1119 obtained from WinAPI BeginPaint within a WM_PAINT event.
1124 HDC QWindowsWindow::getDC()
1127 m_hdc = GetDC(handle());
1132 Relases the HDC for the window or does nothing in
1133 case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
1138 void QWindowsWindow::releaseDC()
1141 ReleaseDC(handle(), m_hdc);
1146 bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message,
1149 // Ignore invalid update bounding rectangles
1150 if (!GetUpdateRect(m_data.hwnd, 0, FALSE))
1152 if (message == WM_ERASEBKGND) // Backing store - ignored.
1155 if (testFlag(OpenGLSurface)) {
1156 // Observed painting problems with Aero style disabled (QTBUG-7865).
1157 if (testFlag(OpenGLDoubleBuffered))
1158 InvalidateRect(hwnd, 0, false);
1159 BeginPaint(hwnd, &ps);
1160 QWindowSystemInterface::handleExposeEvent(window(), QRegion(qrectFromRECT(ps.rcPaint)));
1161 if (!QWindowsContext::instance()->asyncExpose())
1162 QWindowSystemInterface::flushWindowSystemEvents();
1164 EndPaint(hwnd, &ps);
1166 BeginPaint(hwnd, &ps);
1167 const QRect updateRect = qrectFromRECT(ps.rcPaint);
1169 if (QWindowsContext::verboseIntegration)
1170 qDebug() << __FUNCTION__ << this << window() << updateRect;
1172 QWindowSystemInterface::handleExposeEvent(window(), QRegion(updateRect));
1173 if (!QWindowsContext::instance()->asyncExpose())
1174 QWindowSystemInterface::flushWindowSystemEvents();
1175 EndPaint(hwnd, &ps);
1180 void QWindowsWindow::setWindowTitle(const QString &title)
1182 if (QWindowsContext::verboseWindows)
1183 qDebug() << __FUNCTION__ << this << window() <<title;
1185 SetWindowText(m_data.hwnd, (const wchar_t*)title.utf16());
1188 void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
1190 if (QWindowsContext::verboseWindows)
1191 qDebug() << '>' << __FUNCTION__ << this << window() << "\n from: "
1192 << QWindowsWindow::debugWindowFlags(m_data.flags)
1193 << "\n to: " << QWindowsWindow::debugWindowFlags(flags);
1194 const QRect oldGeometry = geometry();
1195 if (m_data.flags != flags) {
1196 m_data.flags = flags;
1198 m_data = setWindowFlags_sys(flags);
1200 // When switching to a frameless window, geometry
1201 // may change without a WM_MOVE. Report change manually.
1202 // Do not send synchronously as not to clobber the widget
1203 // geometry in a sequence of setting flags and geometry.
1204 const QRect newGeometry = geometry_sys();
1205 if (oldGeometry != newGeometry)
1206 handleGeometryChange();
1208 if (QWindowsContext::verboseWindows)
1209 qDebug() << '<' << __FUNCTION__ << "\n returns: "
1210 << QWindowsWindow::debugWindowFlags(m_data.flags)
1211 << " geometry " << oldGeometry << "->" << newGeometry;
1214 QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt,
1215 unsigned flags) const
1217 WindowCreationData creationData;
1218 creationData.fromWindow(window(), wt, flags);
1219 creationData.applyWindowFlags(m_data.hwnd);
1220 creationData.initialize(m_data.hwnd, true, m_opacity);
1222 WindowData result = m_data;
1223 result.flags = creationData.flags;
1224 result.embedded = creationData.embedded;
1225 setFlag(FrameDirty);
1229 void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
1231 if (QWindowsContext::verboseWindows)
1232 qDebug() << __FUNCTION__ << this << window()
1233 << "\n from " << debugWindowStates(m_windowState)
1234 << " to " << debugWindowStates(state);
1235 setFlag(FrameDirty);
1236 m_windowState = state;
1237 QWindowSystemInterface::handleWindowStateChanged(window(), state);
1240 void QWindowsWindow::setWindowState(Qt::WindowState state)
1243 setWindowState_sys(state);
1244 m_windowState = state;
1248 bool QWindowsWindow::isFullScreen_sys() const
1250 return geometry_sys() == window()->screen()->geometry();
1254 \brief Change the window state.
1256 \note Window frames change when maximized;
1257 the top margin shrinks somewhat but that cannot be obtained using
1258 AdjustWindowRectEx().
1260 \note Some calls to SetWindowLong require a subsequent call
1264 void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
1266 const Qt::WindowState oldState = m_windowState;
1267 if (oldState == newState)
1269 if (QWindowsContext::verboseWindows)
1270 qDebug() << '>' << __FUNCTION__ << this << window()
1271 << " from " << debugWindowStates(oldState)
1272 << " to " << debugWindowStates(newState);
1274 const bool visible = isVisible();
1276 setFlag(FrameDirty);
1278 if ((oldState == Qt::WindowMaximized) != (newState == Qt::WindowMaximized)) {
1279 if (visible && !(newState == Qt::WindowMinimized))
1280 ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1283 if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) {
1285 HWND handle = FindWindow(L"HHTaskBar", L"");
1287 if (newState == Qt::WindowFullScreen) {
1288 BOOL hidden = ShowWindow(handle, SW_HIDE);
1290 m_previouslyHidden = true;
1291 } else if (!m_previouslyHidden){
1292 ShowWindow(handle, SW_SHOW);
1296 if (newState == Qt::WindowFullScreen) {
1297 #ifndef Q_FLATTEN_EXPOSE
1298 UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
1300 UINT newStyle = WS_POPUP;
1302 // Save geometry and style to be restored when fullscreen
1303 // is turned off again, since on Windows, it is not a real
1304 // Window state but emulated by changing geometry and style.
1305 if (!m_savedStyle) {
1306 m_savedStyle = style();
1308 if (oldState == Qt::WindowMinimized) {
1310 wp.length = sizeof(WINDOWPLACEMENT);
1311 if (GetWindowPlacement(m_data.hwnd, &wp))
1312 m_savedFrameGeometry = qrectFromRECT(wp.rcNormalPosition);
1315 m_savedFrameGeometry = frameGeometry_sys();
1320 if (m_savedStyle & WS_SYSMENU)
1321 newStyle |= WS_SYSMENU;
1323 newStyle |= WS_VISIBLE;
1326 const QRect r = window()->screen()->geometry();
1327 const UINT swpf = SWP_FRAMECHANGED | SWP_NOACTIVATE;
1328 const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
1329 setFlag(SynchronousGeometryChangeEvent);
1330 SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
1332 clearFlag(SynchronousGeometryChangeEvent);
1333 QWindowSystemInterface::handleGeometryChange(window(), r);
1334 QWindowSystemInterface::flushWindowSystemEvents();
1335 } else if (newState != Qt::WindowMinimized) {
1336 // Restore saved state.
1337 unsigned newStyle = m_savedStyle ? m_savedStyle : style();
1339 newStyle |= WS_VISIBLE;
1342 UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE;
1343 if (!m_savedFrameGeometry.isValid())
1344 swpf |= SWP_NOSIZE | SWP_NOMOVE;
1345 const bool wasSync = testFlag(SynchronousGeometryChangeEvent);
1346 setFlag(SynchronousGeometryChangeEvent);
1347 SetWindowPos(m_data.hwnd, 0, m_savedFrameGeometry.x(), m_savedFrameGeometry.y(),
1348 m_savedFrameGeometry.width(), m_savedFrameGeometry.height(), swpf);
1350 clearFlag(SynchronousGeometryChangeEvent);
1351 // preserve maximized state
1353 ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1355 m_savedFrameGeometry = QRect();
1359 if ((oldState == Qt::WindowMinimized) != (newState == Qt::WindowMinimized)) {
1361 ShowWindow(m_data.hwnd, (newState == Qt::WindowMinimized) ? SW_MINIMIZE :
1362 (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
1364 if (QWindowsContext::verboseWindows)
1365 qDebug() << '<' << __FUNCTION__ << this << window()
1366 << debugWindowStates(newState);
1369 void QWindowsWindow::setStyle(unsigned s) const
1371 if (QWindowsContext::verboseWindows)
1372 qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s);
1373 setFlag(WithinSetStyle);
1374 setFlag(FrameDirty);
1375 SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
1376 clearFlag(WithinSetStyle);
1379 void QWindowsWindow::setExStyle(unsigned s) const
1381 if (QWindowsContext::verboseWindows)
1382 qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
1383 << " 0x" << QByteArray::number(s, 16);
1384 setFlag(FrameDirty);
1385 SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
1388 void QWindowsWindow::raise()
1390 if (QWindowsContext::verboseWindows)
1391 qDebug() << __FUNCTION__ << this << window();
1392 SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1395 void QWindowsWindow::lower()
1397 if (QWindowsContext::verboseWindows)
1398 qDebug() << __FUNCTION__ << this << window();
1400 SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1403 void QWindowsWindow::windowEvent(QEvent *event)
1405 switch (event->type()) {
1406 case QEvent::WindowBlocked: // Blocked by another modal window.
1408 setFlag(BlockedByModal);
1410 case QEvent::WindowUnblocked:
1412 clearFlag(BlockedByModal);
1419 void QWindowsWindow::propagateSizeHints()
1421 if (QWindowsContext::verboseWindows)
1422 qDebug() << __FUNCTION__ << this << window();
1425 QMargins QWindowsWindow::frameMargins() const
1427 // Frames are invalidated by style changes (window state, flags).
1428 // As they are also required for geometry calculations in resize
1429 // event sequences, introduce a dirty flag mechanism to be able
1430 // to cache results.
1431 if (testFlag(FrameDirty)) {
1432 m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
1433 clearFlag(FrameDirty);
1435 return m_data.frame;
1438 void QWindowsWindow::setOpacity(qreal level)
1440 if (QWindowsContext::verboseWindows)
1441 qDebug() << __FUNCTION__ << level;
1442 if (m_opacity != level) {
1445 setWindowOpacity(m_data.hwnd, m_data.flags, level);
1449 static inline HRGN createRectRegion(const QRect &r)
1451 return CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
1454 static inline void addRectToWinRegion(const QRect &rect, HRGN *winRegion)
1456 if (const HRGN rectRegion = createRectRegion(rect)) {
1457 HRGN result = CreateRectRgn(0, 0, 0, 0);
1458 if (CombineRgn(result, *winRegion, rectRegion, RGN_OR)) {
1459 DeleteObject(*winRegion);
1460 *winRegion = result;
1462 DeleteObject(rectRegion);
1466 static HRGN qRegionToWinRegion(const QRegion ®ion)
1468 const QVector<QRect> rects = region.rects();
1469 if (rects.isEmpty())
1471 const int rectCount = rects.size();
1473 return createRectRegion(region.boundingRect());
1474 HRGN hRegion = createRectRegion(rects.front());
1475 for (int i = 1; i < rectCount; ++i)
1476 addRectToWinRegion(rects.at(i), &hRegion);
1480 void QWindowsWindow::setMask(const QRegion ®ion)
1482 if (region.isEmpty()) {
1483 SetWindowRgn(m_data.hwnd, 0, true);
1486 const HRGN winRegion = qRegionToWinRegion(region);
1488 // Mask is in client area coordinates, so offset it in case we have a frame
1489 if (window()->isTopLevel()) {
1490 const QMargins margins = frameMargins();
1491 OffsetRgn(winRegion, margins.left(), margins.top());
1494 // SetWindowRgn takes ownership.
1495 if (!SetWindowRgn(m_data.hwnd, winRegion, true))
1496 DeleteObject(winRegion);
1499 void QWindowsWindow::requestActivateWindow()
1501 if (QWindowsContext::verboseWindows)
1502 qDebug() << __FUNCTION__ << this << window();
1503 // 'Active' state handling is based in focus since it needs to work for
1504 // child windows as well.
1506 SetForegroundWindow(m_data.hwnd);
1507 SetFocus(m_data.hwnd);
1511 bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
1514 qWarning("%s: No handle", __FUNCTION__);
1517 if (QWindowsContext::verboseWindows)
1518 qDebug() << __FUNCTION__ << this << window() << grab;
1520 QWindowsContext *context = QWindowsContext::instance();
1522 context->setKeyGrabber(window());
1524 if (context->keyGrabber() == window())
1525 context->setKeyGrabber(0);
1530 bool QWindowsWindow::setMouseGrabEnabled(bool grab)
1532 if (QWindowsContext::verboseWindows)
1533 qDebug() << __FUNCTION__ << window() << grab;
1535 qWarning("%s: No handle", __FUNCTION__);
1538 if (!isVisible() && grab) {
1539 qWarning("%s: Not setting mouse grab for invisible window %s",
1540 __FUNCTION__, qPrintable(window()->objectName()));
1543 // release grab or an explicit grab overriding autocapture: Clear flag.
1544 clearFlag(QWindowsWindow::AutoMouseCapture);
1545 if (hasMouseCapture() != grab) {
1547 SetCapture(m_data.hwnd);
1555 static inline DWORD cornerToWinOrientation(Qt::Corner corner)
1558 case Qt::TopLeftCorner:
1559 return 0xf004; // SZ_SIZETOPLEFT;
1560 case Qt::TopRightCorner:
1561 return 0xf005; // SZ_SIZETOPRIGHT
1562 case Qt::BottomLeftCorner:
1563 return 0xf007; // SZ_SIZEBOTTOMLEFT
1564 case Qt::BottomRightCorner:
1565 return 0xf008; // SZ_SIZEBOTTOMRIGHT
1570 bool QWindowsWindow::startSystemResize(const QPoint &, Qt::Corner corner)
1572 if (!GetSystemMenu(m_data.hwnd, FALSE))
1576 PostMessage(m_data.hwnd, WM_SYSCOMMAND, cornerToWinOrientation(corner), 0);
1577 setFlag(SizeGripOperation);
1581 void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
1584 setFlag(FrameStrutEventsEnabled);
1586 clearFlag(FrameStrutEventsEnabled);
1590 #ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
1591 void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
1593 const QWindowsGeometryHint hint(window());
1594 hint.applyToMinMaxInfo(m_data.hwnd, mmi);
1595 if (QWindowsContext::verboseWindows)
1596 qDebug() << __FUNCTION__ << window() << *mmi;
1598 #endif // !Q_OS_WINCE
1601 \brief Applies to cursor property set on the window to the global cursor.
1606 void QWindowsWindow::applyCursor()
1608 SetCursor(m_cursor.handle());
1611 void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
1613 if (c.handle() != m_cursor.handle()) {
1614 const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
1615 if (QWindowsContext::verboseWindows)
1616 qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
1617 << " isWUM=" << underMouse;
1625 \brief Find a child window using flags from ChildWindowFromPointEx.
1628 QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint,
1629 unsigned cwexflags) const
1632 return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags);
1636 QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const
1639 return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint),
1645 void QWindowsWindow::alertWindow(int durationMs)
1647 DWORD timeOutMs = GetCaretBlinkTime();
1648 if (!timeOutMs || timeOutMs == INFINITE)
1652 info.cbSize = sizeof(info);
1653 info.hwnd = m_data.hwnd;
1654 info.dwFlags = FLASHW_TRAY;
1655 info.dwTimeout = timeOutMs;
1656 info.uCount = durationMs == 0 ? 10 : durationMs / timeOutMs;
1657 FlashWindowEx(&info);
1660 void QWindowsWindow::stopAlertWindow()
1663 info.cbSize = sizeof(info);
1664 info.hwnd = m_data.hwnd;
1665 info.dwFlags = FLASHW_STOP;
1668 FlashWindowEx(&info);
1670 #endif // !Q_OS_WINCE
1672 bool QWindowsWindow::isEnabled() const
1674 return (style() & WS_DISABLED) == 0;
1677 void QWindowsWindow::setEnabled(bool enabled)
1679 const unsigned oldStyle = style();
1680 unsigned newStyle = oldStyle;
1682 newStyle &= ~WS_DISABLED;
1684 newStyle |= WS_DISABLED;
1686 if (newStyle != oldStyle)
1690 #ifdef QT_OPENGL_ES_2
1691 EGLSurface QWindowsWindow::ensureEglSurfaceHandle(const QWindowsWindow::QWindowsEGLStaticContextPtr &staticContext, EGLConfig config)
1693 if (!m_eglSurface) {
1694 m_staticEglContext = staticContext;
1695 m_eglSurface = eglCreateWindowSurface(staticContext->display(), config, (EGLNativeWindowType)m_data.hwnd, NULL);
1696 if (m_eglSurface == EGL_NO_SURFACE)
1697 qWarning("%s: Could not create the egl surface (eglCreateWindowSurface failed): error = 0x%x\n",
1698 Q_FUNC_INFO, eglGetError());
1699 if (QWindowsContext::verboseGL)
1700 qDebug("%s: Created EGL surface %p, this = %p",
1701 __FUNCTION__, m_eglSurface, this);
1703 return m_eglSurface;
1705 #endif // QT_OPENGL_ES_2
1707 QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf)
1709 const int iwf = int(wf);
1710 QByteArray rc = "0x";
1711 rc += QByteArray::number(iwf, 16);
1714 switch ((iwf & Qt::WindowType_Mask)) {
1736 case Qt::SplashScreen:
1737 rc += " SplashScreen";
1746 if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint";
1747 if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC";
1748 if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint";
1749 if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint";
1750 if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint";
1751 if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint";
1752 if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint";
1753 if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint";
1754 if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint";
1755 if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint";
1756 if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint";
1757 if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint";
1758 if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint";
1763 static HICON createHIcon(const QIcon &icon, int xSize, int ySize)
1765 if (!icon.isNull()) {
1766 const QPixmap pm = icon.pixmap(icon.actualSize(QSize(xSize, ySize)));
1768 return qt_pixmapToWinHICON(pm);
1773 void QWindowsWindow::setWindowIcon(const QIcon &icon)
1778 m_iconSmall = createHIcon(icon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON));
1779 m_iconBig = createHIcon(icon, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON));
1782 SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)m_iconSmall);
1783 SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)m_iconBig);
1785 SendMessage(m_data.hwnd, WM_SETICON, 0 /* ICON_SMALL */, (LPARAM)m_iconSmall);
1786 SendMessage(m_data.hwnd, WM_SETICON, 1 /* ICON_BIG */, (LPARAM)m_iconSmall);