1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (info@qt.nokia.com)
7 ** This file is part of the plugins of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
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"
49 #include <QtGui/QGuiApplication>
50 #include <QtGui/QScreen>
51 #include <QtGui/QWindow>
52 #include <QtGui/QWindowSystemInterface>
54 #include <QtCore/QDebug>
58 static QByteArray debugWinStyle(DWORD style)
62 rc += QByteArray::number(qulonglong(style), 16);
67 if (style & WS_OVERLAPPED)
68 rc += " WS_OVERLAPPED";
69 if (style & WS_CLIPSIBLINGS)
70 rc += " WS_CLIPSIBLINGS";
71 if (style & WS_CLIPCHILDREN)
72 rc += " WS_CLIPCHILDREN";
73 if (style & WS_THICKFRAME)
74 rc += " WS_THICKFRAME";
75 if (style & WS_DLGFRAME)
77 if (style & WS_SYSMENU)
79 if (style & WS_MINIMIZEBOX)
80 rc += " WS_MINIMIZEBOX";
81 if (style & WS_MAXIMIZEBOX)
82 rc += " WS_MAXIMIZEBOX";
86 static QByteArray debugWindowStates(Qt::WindowStates s)
90 rc += QByteArray::number(int(s), 16);
91 if (s & Qt::WindowMinimized)
92 rc += " WindowMinimized";
93 if (s & Qt::WindowMaximized)
94 rc += " WindowMaximized";
95 if (s & Qt::WindowFullScreen)
96 rc += " WindowFullScreen";
97 if (s & Qt::WindowActive)
98 rc += " WindowActive";
102 QDebug operator<<(QDebug d, const MINMAXINFO &i)
104 d.nospace() << "MINMAXINFO maxSize=" << i.ptMaxSize.x << ','
105 << i.ptMaxSize.y << " maxpos=" << i.ptMaxPosition.x
106 << ',' << i.ptMaxPosition.y << " mintrack="
107 << i.ptMinTrackSize.x << ',' << i.ptMinTrackSize.y
108 << " maxtrack=" << i.ptMaxTrackSize.x << ','
109 << i.ptMaxTrackSize.y;
113 static inline QSize qSizeOfRect(const RECT &rect)
115 return QSize(rect.right -rect.left, rect.bottom - rect.top);
118 static inline QRect qrectFromRECT(const RECT &rect)
120 return QRect(QPoint(rect.left, rect.top), qSizeOfRect(rect));
123 QDebug operator<<(QDebug d, const RECT &r)
125 d.nospace() << "RECT: left/top=" << r.left << ',' << r.top
126 << " right/bottom=" << r.right << ',' << r.bottom;
130 QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p)
132 qDebug().nospace() << "NCCALCSIZE_PARAMS "
133 << qrectFromRECT(p.rgrc[0])
134 << ' ' << qrectFromRECT(p.rgrc[1]) << ' '
135 << qrectFromRECT(p.rgrc[2]);
139 static inline QRect frameGeometry(HWND hwnd)
141 RECT rect = { 0, 0, 0, 0 };
142 GetWindowRect(hwnd, &rect);
143 return qrectFromRECT(rect);
146 QSize clientSize(HWND hwnd)
148 RECT rect = { 0, 0, 0, 0 };
149 GetClientRect(hwnd, &rect); // Always returns point 0,0, thus unusable for geometry.
150 return qSizeOfRect(rect);
153 // from qwidget_win.cpp/maximum layout size check removed.
154 static bool shouldShowMaximizeButton(Qt::WindowFlags flags)
156 if (flags & Qt::MSWindowsFixedSizeDialogHint)
158 // if the user explicitly asked for the maximize button, we try to add
159 // it even if the window has fixed size.
160 if (flags & Qt::CustomizeWindowHint &&
161 flags & Qt::WindowMaximizeButtonHint)
163 return flags & Qt::WindowMaximizeButtonHint;
167 \class WindowCreationData
168 \brief Window creation code.
170 This struct gathers all information required to create a window.
171 Window creation is split in 3 steps:
174 \o fromWindow() Gather all required information
175 \o create() Create the system handle.
176 \o initialize() Post creation initialization steps.
179 The reason for this split is to also enable changing the QWindowFlags
183 \o fromWindow() Gather information and determine new system styles
184 \o applyWindowFlags() to apply the new window system styles.
185 \o initialize() Post creation initialization steps.
188 Contains the window creation code formerly in qwidget_win.cpp.
190 \sa QWindowCreationContext
191 \ingroup qt-lighthouse-win
194 struct WindowCreationData
196 typedef QWindowsWindow::WindowData WindowData;
198 WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0),
199 topLevel(false), popup(false), dialog(false), desktop(false),
202 void fromWindow(const QWindow *w, const Qt::WindowFlags flags, bool isGL);
203 inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const;
204 inline void applyWindowFlags(HWND hwnd) const;
205 void initialize(HWND h, bool frameChange) const;
207 Qt::WindowFlags flags;
220 QDebug operator<<(QDebug debug, const WindowCreationData &d)
222 debug.nospace() << QWindowsWindow::debugWindowFlags(d.flags)
223 << " gs=" << d.isGL << " topLevel=" << d.topLevel << " popup="
224 << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop
225 << " tool=" << d.tool << " style=" << debugWinStyle(d.style)
226 << " exStyle=0x" << QString::number(d.exStyle, 16)
227 << " parent=" << d.parentHandle;
231 void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flagsIn,
236 topLevel = w->isTopLevel();
238 if (topLevel && flags == 1) {
239 qWarning("Remove me: fixing toplevel window flags");
240 flags |= Qt::WindowTitleHint|Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint
241 |Qt::WindowMaximizeButtonHint|Qt::WindowCloseButtonHint;
244 type = static_cast<Qt::WindowType>(int(flags) & Qt::WindowType_Mask);
263 if ((flags & Qt::MSWindowsFixedSizeDialogHint))
266 // Parent: Use transient parent for top levels.
268 flags |= Qt::WindowStaysOnTopHint; // a popup stays on top, no parent.
270 if (const QWindow *parentWindow = topLevel ? w->transientParent() : w->parent())
271 parentHandle = QWindowsWindow::handleOf(parentWindow);
274 if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) {
276 } else if (topLevel && !desktop) {
277 if (flags & Qt::FramelessWindowHint)
278 style = WS_POPUP; // no border
279 else if (flags & Qt::WindowTitleHint)
280 style = WS_OVERLAPPED;
288 // if (!testAttribute(Qt::WA_PaintUnclipped))
289 // ### Commented out for now as it causes some problems, but
290 // this should be correct anyway, so dig some more into this
291 #ifdef Q_FLATTEN_EXPOSE
293 style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN; // see SetPixelFormat
295 style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN ;
298 if ((type == Qt::Window || dialog || tool)) {
299 if (!(flags & Qt::FramelessWindowHint)) {
301 if (flags & Qt::MSWindowsFixedSizeDialogHint) {
302 style |= WS_DLGFRAME;
304 style |= WS_THICKFRAME;
307 if (flags & Qt::WindowTitleHint)
309 if (flags & Qt::WindowSystemMenuHint)
311 if (flags & Qt::WindowMinimizeButtonHint)
312 style |= WS_MINIMIZEBOX;
313 if (shouldShowMaximizeButton(flags))
314 style |= WS_MAXIMIZEBOX;
316 exStyle |= WS_EX_TOOLWINDOW;
317 if (flags & Qt::WindowContextHelpButtonHint)
318 exStyle |= WS_EX_CONTEXTHELP;
320 exStyle |= WS_EX_TOOLWINDOW;
326 QWindowsWindow::WindowData
327 WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const
329 typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
332 result.flags = flags;
334 if (desktop) { // desktop widget. No frame, hopefully?
335 result.hwnd = GetDesktopWindow();
336 result.geometry = frameGeometry(result.hwnd);
337 if (QWindowsContext::verboseWindows)
338 qDebug().nospace() << "Created desktop window " << w << result.hwnd;
342 const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0);
344 const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
346 if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
347 title = topLevel ? qAppName() : w->objectName();
349 const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
350 const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
352 // Capture events before CreateWindowEx() returns.
353 const QWindowCreationContextPtr context(new QWindowCreationContext(w, geometry, style, exStyle));
354 QWindowsContext::instance()->setWindowCreationContext(context);
356 if (QWindowsContext::verboseWindows)
358 << "CreateWindowEx: " << w << *this
359 << " class=" <<windowClassName << " title=" << title
360 << "\nrequested: " << geometry << ": "
361 << context->frameWidth << 'x' << context->frameHeight
362 << '+' << context->frameX << '+' << context->frameY;
364 result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
366 context->frameX, context->frameY,
367 context->frameWidth, context->frameHeight,
368 parentHandle, NULL, appinst, NULL);
369 QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
370 if (QWindowsContext::verboseWindows)
372 << "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
373 << context->obtainedGeometry << context->margins;
376 qErrnoWarning("%s: CreateWindowEx failed", __FUNCTION__);
380 result.geometry = context->obtainedGeometry;
381 result.frame = context->margins;
385 void WindowCreationData::applyWindowFlags(HWND hwnd) const
387 // Keep enabled and visible from the current style.
388 const LONG_PTR oldStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
389 const LONG_PTR oldExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
391 const LONG_PTR newStyle = style | (oldStyle & (WS_DISABLED|WS_VISIBLE));
392 if (oldStyle != newStyle)
393 SetWindowLongPtr(hwnd, GWL_STYLE, newStyle);
394 const LONG_PTR newExStyle = exStyle;
395 if (newExStyle != oldExStyle)
396 SetWindowLongPtr(hwnd, GWL_EXSTYLE, newExStyle);
397 if (QWindowsContext::verboseWindows)
398 qDebug().nospace() << __FUNCTION__ << hwnd << *this
399 << "\n Style from " << debugWinStyle(oldStyle) << "\n to "
400 << debugWinStyle(newStyle) << "\n ExStyle from 0x"
401 << QByteArray::number(qulonglong(oldExStyle), 16) << " to 0x"
402 << QByteArray::number(qulonglong(newExStyle), 16);
405 void WindowCreationData::initialize(HWND hwnd, bool frameChange) const
407 if (desktop || !hwnd)
409 UINT flags = SWP_NOMOVE | SWP_NOSIZE;
411 flags |= SWP_FRAMECHANGED;
413 flags |= SWP_NOACTIVATE;
414 if ((flags & Qt::WindowStaysOnTopHint) || (type == Qt::ToolTip)) {
415 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, flags);
416 if (flags & Qt::WindowStaysOnBottomHint)
417 qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
418 } else if (flags & Qt::WindowStaysOnBottomHint) {
419 SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, flags);
421 if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
422 HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
423 if (flags & Qt::WindowCloseButtonHint)
424 EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
426 EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
429 SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, flags);
434 \class QWindowsGeometryHint
435 \brief Stores geometry constraints and provides utility functions.
437 Geometry constraints ready to apply to a MINMAXINFO taking frame
440 \ingroup qt-lighthouse-win
443 #define QWINDOWSIZE_MAX ((1<<24)-1)
445 QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) :
446 minimumSize(w->minimumSize()),
447 maximumSize(w->maximumSize())
451 bool QWindowsGeometryHint::validSize(const QSize &s) const
453 const int width = s.width();
454 const int height = s.height();
455 return width >= minimumSize.width() && width <= maximumSize.width()
456 && height >= minimumSize.height() && height <= maximumSize.height();
459 QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
461 RECT rect = {0,0,0,0};
462 style &= ~(WS_OVERLAPPED); // Not permitted, see docs.
463 if (!AdjustWindowRectEx(&rect, style, FALSE, exStyle))
464 qErrnoWarning("%s: AdjustWindowRectEx failed", __FUNCTION__);
465 const QMargins result(qAbs(rect.left), qAbs(rect.top),
466 qAbs(rect.right), qAbs(rect.bottom));
467 if (QWindowsContext::verboseWindows)
468 qDebug().nospace() << __FUNCTION__ << " style= 0x"
469 << QString::number(style, 16)
470 << " exStyle=0x" << QString::number(exStyle, 16) << ' ' << rect << ' ' << result;
475 void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
477 return applyToMinMaxInfo(GetWindowLong(hwnd, GWL_STYLE),
478 GetWindowLong(hwnd, GWL_EXSTYLE), mmi);
481 void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const
483 if (QWindowsContext::verboseWindows)
484 qDebug().nospace() << '>' << __FUNCTION__ << '<' << " min="
485 << minimumSize.width() << ',' << minimumSize.height()
486 << " max=" << maximumSize.width() << ',' << maximumSize.height()
489 const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
490 const int frameWidth = margins.left() + margins.right();
491 const int frameHeight = margins.top() + margins.bottom();
492 if (minimumSize.width() > 0)
493 mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
494 if (minimumSize.height() > 0)
495 mmi->ptMinTrackSize.y = minimumSize.height() + frameHeight;
497 const int maximumWidth = qMax(maximumSize.width(), minimumSize.width());
498 const int maximumHeight = qMax(maximumSize.height(), minimumSize.height());
499 if (maximumWidth < QWINDOWSIZE_MAX)
500 mmi->ptMaxTrackSize.x = maximumWidth + frameWidth;
501 // windows with title bar have an implicit size limit of 112 pixels
502 if (maximumHeight < QWINDOWSIZE_MAX)
503 mmi->ptMaxTrackSize.y = qMax(maximumHeight + frameHeight, 112);
504 if (QWindowsContext::verboseWindows)
505 qDebug().nospace() << '<' << __FUNCTION__
506 << " frame=" << margins << ' ' << frameWidth << ',' << frameHeight
511 \class QWindowCreationContext
512 \brief Active Context for creating windows.
514 There is a phase in window creation (WindowCreationData::create())
515 in which events are sent before the system API CreateWindowEx() returns
516 the handle. These cannot be handled by the platform window as the association
517 of the unknown handle value to the window does not exist yet and as not
518 to trigger recursive handle creation, etc.
520 In that phase, an instance of QWindowCreationContext is set on
523 QWindowCreationContext stores the information to answer the initial
524 WM_GETMINMAXINFO and obtains the corrected size/position.
526 \sa WindowCreationData, QWindowsContext
527 \ingroup qt-lighthouse-win
530 QWindowCreationContext::QWindowCreationContext(const QWindow *w,
531 const QRect &geometry,
532 DWORD style_, DWORD exStyle_) :
533 geometryHint(w), style(style_), exStyle(exStyle_),
534 requestedGeometry(geometry), obtainedGeometry(geometry),
535 margins(QWindowsGeometryHint::frame(style, exStyle)),
536 frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
537 frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
539 // Geometry of toplevels does not consider window frames.
540 // TODO: No concept of WA_wasMoved yet that would indicate a
541 // CW_USEDEFAULT unless set. For now, assume that 0,0 means 'default'
543 if (geometry.isValid()) {
544 if (!w->isTopLevel() || geometry.y() >= margins.top()) {
545 frameX = geometry.x() - margins.left();
546 frameY = geometry.y() - margins.top();
548 frameWidth = geometry.width() + margins.left() + margins.right();
549 frameHeight = geometry.height() + margins.top() + margins.bottom();
551 if (QWindowsContext::verboseWindows)
553 << __FUNCTION__ << ' ' << w << " min" << geometryHint.minimumSize
554 << " min" << geometryHint.maximumSize;
558 \class QWindowsBaseWindow
559 \brief Raster or OpenGL Window.
562 \o Raster type: handleWmPaint() is implemented to
563 to bitblt the image. The DC can be accessed
564 via getDC/Relase DC, which has a special handling
565 when within a paint event (in that case, the DC obtained
566 from BeginPaint() is returned).
568 \o Open GL: The first time QWindowsGLContext accesses
569 the handle, it sets up the pixelformat on the DC
570 which in turn sets it on the window (see flag
571 PixelFormatInitialized).
572 handleWmPaint() is empty (although required).
575 \ingroup qt-lighthouse-win
578 QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
579 QPlatformWindow(aWindow),
583 m_windowState(aWindow->windowState()),
586 m_cursor(QWindowsScreen::screenOf(aWindow)->cursor().standardWindowCursor()),
589 if (aWindow->surfaceType() == QWindow::OpenGLSurface)
590 setFlag(OpenGL_Surface);
591 QWindowsContext::instance()->addWindow(m_data.hwnd, this);
592 if (aWindow->isTopLevel()) {
593 switch (aWindow->windowType()) {
608 QWindowsWindow::~QWindowsWindow()
613 void QWindowsWindow::destroyWindow()
615 if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
616 qDebug() << __FUNCTION__ << this << window() << m_data.hwnd;
618 unregisterDropSite();
619 if (m_data.hwnd != GetDesktopWindow())
620 DestroyWindow(m_data.hwnd);
621 QWindowsContext::instance()->removeWindow(m_data.hwnd);
626 void QWindowsWindow::registerDropSite()
628 if (m_data.hwnd && !m_dropTarget) {
629 m_dropTarget = new QWindowsOleDropTarget(window());
630 RegisterDragDrop(m_data.hwnd, m_dropTarget);
631 CoLockObjectExternal(m_dropTarget, true, true);
635 void QWindowsWindow::unregisterDropSite()
637 if (m_data.hwnd && m_dropTarget) {
638 m_dropTarget->Release();
639 CoLockObjectExternal(m_dropTarget, false, true);
640 RevokeDragDrop(m_data.hwnd);
645 QWindow *QWindowsWindow::topLevelOf(QWindow *w)
647 while (QWindow *parent = w->parent())
652 QWindowsWindow::WindowData
653 QWindowsWindow::WindowData::create(const QWindow *w,
654 const WindowData ¶meters,
655 const QString &title,
658 WindowCreationData creationData;
659 creationData.fromWindow(w, parameters.flags, isGL);
660 WindowData result = creationData.create(w, parameters.geometry, title);
661 creationData.initialize(result.hwnd, false);
665 void QWindowsWindow::setVisible(bool visible)
667 if (QWindowsContext::verboseWindows)
668 qDebug() << __FUNCTION__ << this << window() << m_data.hwnd << visible;
678 bool QWindowsWindow::isVisible() const
680 return m_data.hwnd && IsWindowVisible(m_data.hwnd);
683 // partially from QWidgetPrivate::show_sys()
684 void QWindowsWindow::show_sys() const
686 int sm = SW_SHOWNORMAL;
687 bool fakedMaximize = false;
688 const QWindow *w = window();
689 const Qt::WindowFlags flags = w->windowFlags();
690 const Qt::WindowType type = w->windowType();
691 if (w->isTopLevel()) {
692 const Qt::WindowState state = w->windowState();
693 if (state & Qt::WindowMinimized) {
694 sm = SW_SHOWMINIMIZED;
696 sm = SW_SHOWMINNOACTIVE;
697 } else if (state & Qt::WindowMaximized) {
698 sm = SW_SHOWMAXIMIZED;
699 // Windows will not behave correctly when we try to maximize a window which does not
700 // have minimize nor maximize buttons in the window frame. Windows would then ignore
701 // non-available geometry, and rather maximize the widget to the full screen, minus the
702 // window frame (caption). So, we do a trick here, by adding a maximize button before
703 // maximizing the widget, and then remove the maximize button afterwards.
704 if (flags & Qt::WindowTitleHint &&
705 !(flags & (Qt::WindowMinMaxButtonsHint | Qt::FramelessWindowHint))) {
706 fakedMaximize = TRUE;
707 setStyle(style() | WS_MAXIMIZEBOX);
711 if (type == Qt::Popup || type == Qt::ToolTip || type == Qt::Tool)
712 sm = SW_SHOWNOACTIVATE;
714 ShowWindow(m_data.hwnd, sm);
717 setStyle(style() & ~WS_MAXIMIZEBOX);
718 SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0,
719 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER
724 // partially from QWidgetPrivate::hide_sys()
725 void QWindowsWindow::hide_sys() const
727 const Qt::WindowFlags flags = window()->windowFlags();
728 if (flags != Qt::Desktop) {
729 if (flags & Qt::Popup)
730 ShowWindow(m_data.hwnd, SW_HIDE);
732 SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER);
736 void QWindowsWindow::setParent(const QPlatformWindow *newParent)
738 if (QWindowsContext::verboseWindows)
739 qDebug() << __FUNCTION__ << window() << newParent;
741 if (newParent != parent() && m_data.hwnd)
742 setParent_sys(newParent);
745 void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) const
749 const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent);
750 parentHWND = parentW->handle();
752 SetParent(m_data.hwnd, parentHWND);
755 void QWindowsWindow::handleShown()
757 QWindowSystemInterface::handleMapEvent(window());
760 void QWindowsWindow::handleHidden()
762 QWindowSystemInterface::handleUnmapEvent(window());
765 void QWindowsWindow::setGeometry(const QRect &rect)
767 const QSize oldSize = m_data.geometry.size();
768 m_data.geometry = rect;
769 const QSize newSize = rect.size();
771 if (newSize != oldSize) {
772 const QWindowsGeometryHint hint(window());
773 if (!hint.validSize(newSize)) {
774 qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
775 "(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
776 newSize.width(), newSize.height(),
777 hint.minimumSize.width(), hint.minimumSize.height(),
778 hint.maximumSize.width(), hint.maximumSize.height(),
779 qPrintable(window()->objectName()));
783 // A ResizeEvent with resulting geometry will be sent. If we cannot
784 // achieve that size (for example, window title minimal constraint),
786 setGeometry_sys(rect);
787 if (m_data.geometry != rect) {
788 qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
789 " Resulting geometry: %dx%d+%d+%d.",
791 rect.width(), rect.height(), rect.x(), rect.y(),
792 qPrintable(window()->objectName()),
793 m_data.geometry.width(), m_data.geometry.height(),
794 m_data.geometry.x(), m_data.geometry.y());
797 QPlatformWindow::setGeometry(rect);
801 void QWindowsWindow::handleMoved()
803 if (!IsIconic(m_data.hwnd)) // Minimize can send nonsensical move events.
804 handleGeometryChange();
807 void QWindowsWindow::handleResized(int wParam)
810 case SIZE_MAXHIDE: // Some other window affected.
814 handleWindowStateChange(Qt::WindowMinimized);
817 handleWindowStateChange(Qt::WindowMaximized);
818 handleGeometryChange();
821 if (m_windowState != Qt::WindowNoState)
822 handleWindowStateChange(Qt::WindowNoState);
823 handleGeometryChange();
828 void QWindowsWindow::handleGeometryChange()
830 m_data.geometry = geometry_sys();
831 QPlatformWindow::setGeometry(m_data.geometry);
832 QWindowSystemInterface::handleGeometryChange(window(), m_data.geometry);
834 if (QWindowsContext::verboseEvents || QWindowsContext::verboseWindows)
835 qDebug() << __FUNCTION__ << this << window() << m_data.geometry;
838 void QWindowsWindow::setGeometry_sys(const QRect &rect) const
840 const QRect frameGeometry = rect + frameMargins();
842 if (QWindowsContext::verboseWindows)
843 qDebug() << '>' << __FUNCTION__ << this << window()
844 << " \n from " << geometry_sys() << " to " <<rect
845 << " new frame: " << frameGeometry;
847 const bool rc = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(),
848 frameGeometry.width(), frameGeometry.height(), true);
849 if (QWindowsContext::verboseWindows)
850 qDebug() << '<' << __FUNCTION__ << this << window()
851 << " \n resulting " << rc << geometry_sys();
854 QRect QWindowsWindow::geometry_sys() const
856 // Warning: Returns bogus values when minimized.
857 return frameGeometry(m_data.hwnd) - frameMargins();
861 Allocates a HDC for the window or returns the temporary one
862 obtained from WinAPI BeginPaint within a WM_PAINT event.
867 HDC QWindowsWindow::getDC()
870 m_hdc = GetDC(handle());
875 Relases the HDC for the window or does nothing in
876 case it was obtained from WinAPI BeginPaint within a WM_PAINT event.
881 void QWindowsWindow::releaseDC()
883 if (m_hdc && !testFlag(WithinWmPaint)) {
884 ReleaseDC(handle(), m_hdc);
889 void QWindowsWindow::handleWmPaint(HWND hwnd, UINT,
893 if (testFlag(OpenGL_Surface)) {
894 BeginPaint(hwnd, &ps); // WM_ERASEBKGND needs to be handled.
898 m_hdc = BeginPaint(hwnd, &ps);
899 setFlag(WithinWmPaint);
901 const QRect updateRect = qrectFromRECT(ps.rcPaint);
902 if (QWindowsContext::verboseIntegration)
903 qDebug() << __FUNCTION__ << this << window() << updateRect;
905 QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRegion(updateRect));
906 clearFlag(WithinWmPaint);
912 void QWindowsWindow::setWindowTitle(const QString &title)
914 if (QWindowsContext::verboseWindows)
915 qDebug() << __FUNCTION__ << this << window() <<title;
917 SetWindowText(m_data.hwnd, (const wchar_t*)title.utf16());
920 Qt::WindowFlags QWindowsWindow::setWindowFlags(Qt::WindowFlags flags)
922 if (QWindowsContext::verboseWindows)
923 qDebug() << '>' << __FUNCTION__ << this << window() << "\n from: "
924 << QWindowsWindow::debugWindowFlags(m_data.flags)
925 << "\n to: " << QWindowsWindow::debugWindowFlags(flags);
926 if (m_data.flags != flags) {
927 m_data.flags = flags;
929 m_data = setWindowFlags_sys(flags);
931 if (QWindowsContext::verboseWindows)
932 qDebug() << '<' << __FUNCTION__ << "\n returns: "
933 << QWindowsWindow::debugWindowFlags(m_data.flags);
937 QWindowsWindow::WindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt) const
939 // Geometry changes have not been observed here. Frames change, though.
940 WindowCreationData creationData;
941 creationData.fromWindow(window(), wt, window()->surfaceType() == QWindow::OpenGLSurface);
942 creationData.applyWindowFlags(m_data.hwnd);
943 creationData.initialize(m_data.hwnd, true);
944 WindowData result = m_data;
945 result.flags = creationData.flags;
950 void QWindowsWindow::handleWindowStateChange(Qt::WindowState state)
952 if (QWindowsContext::verboseWindows)
953 qDebug() << __FUNCTION__ << this << window()
954 << "\n from " << debugWindowStates(m_windowState)
955 << " to " << debugWindowStates(state);
957 m_windowState = state;
958 QWindowSystemInterface::handleWindowStateChanged(window(), state);
961 Qt::WindowState QWindowsWindow::setWindowState(Qt::WindowState state)
964 setWindowState_sys(state);
965 m_windowState = state;
970 Qt::WindowState QWindowsWindow::windowState_sys() const
972 if (IsIconic(m_data.hwnd))
973 return Qt::WindowMinimized;
974 if (IsZoomed(m_data.hwnd))
975 return Qt::WindowMaximized;
976 if (geometry_sys() == window()->screen()->geometry())
977 return Qt::WindowFullScreen;
978 return Qt::WindowNoState;
981 Qt::WindowStates QWindowsWindow::windowStates_sys() const
983 Qt::WindowStates result = windowState_sys();
984 if (GetActiveWindow() == m_data.hwnd)
985 result |= Qt::WindowActive;
990 \brief Change the window state.
992 \note Window frames change when maximized;
993 the top margin shrinks somewhat but that cannot be obtained using
994 AdjustWindowRectEx().
996 \note Some calls to SetWindowLong require a subsequent call
1000 void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
1002 const Qt::WindowStates oldStates = windowStates_sys();
1003 // Maintain the active flag as the platform window API does not
1005 Qt::WindowStates newStates = newState;
1006 if (oldStates & Qt::WindowActive)
1007 newStates |= Qt::WindowActive;
1008 if (oldStates == newStates)
1010 if (QWindowsContext::verboseWindows)
1011 qDebug() << '>' << __FUNCTION__ << this << window()
1012 << " from " << debugWindowStates(oldStates)
1013 << " to " << debugWindowStates(newStates);
1015 const bool isActive = newStates & Qt::WindowActive;
1016 const int max = isActive ? SW_SHOWMAXIMIZED : SW_MAXIMIZE;
1017 const int normal = isActive ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE;
1018 const int min = isActive ? SW_SHOWMINIMIZED : SW_MINIMIZE;
1019 const bool visible = isVisible();
1021 setFlag(FrameDirty);
1023 if ((oldStates & Qt::WindowMaximized) != (newStates & Qt::WindowMaximized)) {
1024 if (visible && !(newStates & Qt::WindowMinimized))
1025 ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
1028 if ((oldStates & Qt::WindowFullScreen) != (newStates & Qt::WindowFullScreen)) {
1029 if (newStates & Qt::WindowFullScreen) {
1030 #ifndef Q_FLATTEN_EXPOSE
1031 UINT newStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_POPUP;
1033 UINT newStyle = WS_POPUP;
1035 if (style() & WS_SYSMENU)
1036 newStyle |= WS_SYSMENU;
1038 newStyle |= WS_VISIBLE;
1041 const QRect r = window()->screen()->geometry();
1042 UINT swpf = SWP_FRAMECHANGED;
1043 if (newStates & Qt::WindowActive)
1044 swpf |= SWP_NOACTIVATE;
1046 SetWindowPos(m_data.hwnd, HWND_TOP, r.left(), r.top(), r.width(), r.height(), swpf);
1049 setStyle(style() | WS_VISIBLE);
1050 UINT swpf = SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOSIZE | SWP_NOMOVE;
1051 if (newStates & Qt::WindowActive)
1052 swpf |= SWP_NOACTIVATE;
1053 SetWindowPos(m_data.hwnd, 0, 0, 0, 0, 0, swpf);
1055 // preserve maximized state
1057 ShowWindow(m_data.hwnd, (newStates & Qt::WindowMaximized) ? max : normal);
1061 if ((oldStates & Qt::WindowMinimized) != (newStates & Qt::WindowMinimized)) {
1063 ShowWindow(m_data.hwnd, (newStates & Qt::WindowMinimized) ? min :
1064 (newStates & Qt::WindowMaximized) ? max : normal);
1066 if (QWindowsContext::verboseWindows)
1067 qDebug() << '<' << __FUNCTION__ << this << window()
1068 << debugWindowStates(newStates);
1071 void QWindowsWindow::setStyle(unsigned s) const
1073 if (QWindowsContext::verboseWindows)
1074 qDebug() << __FUNCTION__ << this << window() << debugWinStyle(s);
1075 setFlag(FrameDirty);
1076 SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s);
1079 void QWindowsWindow::setExStyle(unsigned s) const
1081 if (QWindowsContext::verboseWindows)
1082 qDebug().nospace() << __FUNCTION__ << ' ' << this << ' ' << window()
1083 << " 0x" << QByteArray::number(s, 16);
1084 setFlag(FrameDirty);
1085 SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s);
1088 void QWindowsWindow::raise()
1090 if (QWindowsContext::verboseWindows)
1091 qDebug() << __FUNCTION__ << this << window();
1092 SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1095 void QWindowsWindow::lower()
1097 if (QWindowsContext::verboseWindows)
1098 qDebug() << __FUNCTION__ << this << window();
1100 SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1103 void QWindowsWindow::propagateSizeHints()
1105 if (QWindowsContext::verboseWindows)
1106 qDebug() << __FUNCTION__ << this << window();
1109 QMargins QWindowsWindow::frameMargins() const
1111 // Frames are invalidated by style changes (window state, flags).
1112 // As they are also required for geometry calculations in resize
1113 // event sequences, introduce a dirty flag mechanism to be able
1114 // to cache results.
1115 if (testFlag(FrameDirty)) {
1116 m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
1117 clearFlag(FrameDirty);
1119 return m_data.frame;
1122 void QWindowsWindow::setOpacity(qreal level)
1124 if (QWindowsContext::verboseWindows)
1125 qDebug() << __FUNCTION__ << level;
1126 if (m_opacity != level) {
1129 setOpacity_sys(level);
1133 void QWindowsWindow::setOpacity_sys(qreal level) const
1135 const long wl = GetWindowLong(m_data.hwnd, GWL_EXSTYLE);
1136 const bool isOpaque = level == 1.0;
1139 if (wl & WS_EX_LAYERED)
1140 SetWindowLong(m_data.hwnd, GWL_EXSTYLE, wl & ~WS_EX_LAYERED);
1142 if ((wl & WS_EX_LAYERED) == 0)
1143 SetWindowLong(m_data.hwnd, GWL_EXSTYLE, wl | WS_EX_LAYERED);
1144 if (m_data.flags & Qt::FramelessWindowHint) {
1145 BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * level), AC_SRC_ALPHA};
1146 QWindowsContext::user32dll.updateLayeredWindow(m_data.hwnd, NULL, NULL, NULL, NULL, NULL, 0, &blend, ULW_ALPHA);
1148 QWindowsContext::user32dll.setLayeredWindowAttributes(m_data.hwnd, 0, (int)(level * 255), LWA_ALPHA);
1153 void QWindowsWindow::requestActivateWindow()
1155 if (QWindowsContext::verboseWindows)
1156 qDebug() << __FUNCTION__ << this << window();
1158 SetForegroundWindow(m_data.hwnd);
1161 bool QWindowsWindow::setKeyboardGrabEnabled(bool grab)
1164 qWarning("%s: No handle", __FUNCTION__);
1167 if (QWindowsContext::verboseWindows)
1168 qDebug() << __FUNCTION__ << this << window() << grab;
1170 QWindowsContext *context = QWindowsContext::instance();
1172 context->setKeyGrabber(window());
1174 if (context->keyGrabber() == window())
1175 context->setKeyGrabber(0);
1180 bool QWindowsWindow::setMouseGrabEnabled(bool grab)
1182 bool result = false;
1184 qWarning("%s: No handle", __FUNCTION__);
1187 if (QWindowsContext::verboseWindows)
1188 qDebug() << __FUNCTION__ << window() << grab;
1190 if (m_mouseGrab != grab) {
1193 setMouseGrabEnabled_sys(grab);
1198 void QWindowsWindow::setMouseGrabEnabled_sys(bool grab)
1201 SetCapture(m_data.hwnd);
1207 void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
1209 const QWindowsGeometryHint hint(window());
1210 hint.applyToMinMaxInfo(m_data.hwnd, mmi);
1211 if (QWindowsContext::verboseWindows)
1212 qDebug() << __FUNCTION__ << window() << *mmi;
1216 \brief Applies to cursor property set on the window to the global cursor
1217 unless there is an override cursor.
1222 void QWindowsWindow::applyCursor()
1224 if (!QGuiApplication::overrideCursor())
1225 SetCursor(m_cursor.handle());
1228 void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
1230 if (c.handle() != m_cursor.handle()) {
1231 const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
1232 if (QWindowsContext::verboseWindows)
1233 qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
1234 << " isWUM=" << underMouse;
1242 \brief Find a child window using flags from ChildWindowFromPointEx.
1245 QWindowsWindow *QWindowsWindow::childAtScreenPoint(const QPoint &screenPoint,
1246 unsigned cwexflags) const
1249 return QWindowsContext::instance()->findPlatformWindowAt(m_data.hwnd, screenPoint, cwexflags);
1253 QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwexflags) const
1256 return childAtScreenPoint(QWindowsGeometryHint::mapToGlobal(m_data.hwnd, clientPoint),
1261 QByteArray QWindowsWindow::debugWindowFlags(Qt::WindowFlags wf)
1263 const int iwf = int(wf);
1264 QByteArray rc = "0x";
1265 rc += QByteArray::number(iwf, 16);
1268 switch ((iwf & Qt::WindowType_Mask)) {
1290 case Qt::SplashScreen:
1291 rc += " SplashScreen";
1300 if (iwf & Qt::MSWindowsFixedSizeDialogHint) rc += " MSWindowsFixedSizeDialogHint";
1301 if (iwf & Qt::MSWindowsOwnDC) rc += " MSWindowsOwnDC";
1302 if (iwf & Qt::FramelessWindowHint) rc += " FramelessWindowHint";
1303 if (iwf & Qt::WindowTitleHint) rc += " WindowTitleHint";
1304 if (iwf & Qt::WindowSystemMenuHint) rc += " WindowSystemMenuHint";
1305 if (iwf & Qt::WindowMinimizeButtonHint) rc += " WindowMinimizeButtonHint";
1306 if (iwf & Qt::WindowMaximizeButtonHint) rc += " WindowMaximizeButtonHint";
1307 if (iwf & Qt::WindowContextHelpButtonHint) rc += " WindowContextHelpButtonHint";
1308 if (iwf & Qt::WindowShadeButtonHint) rc += " WindowShadeButtonHint";
1309 if (iwf & Qt::WindowStaysOnTopHint) rc += " WindowStaysOnTopHint";
1310 if (iwf & Qt::CustomizeWindowHint) rc += " CustomizeWindowHint";
1311 if (iwf & Qt::WindowStaysOnBottomHint) rc += " WindowStaysOnBottomHint";
1312 if (iwf & Qt::WindowCloseButtonHint) rc += " WindowCloseButtonHint";