From 14efcaa3921687129d4dca9b7d5794668a329cd6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 8 Jan 2016 14:59:22 +0100 Subject: Windows QPA: Improve handling of windows of type Qt::ForeignWindow. Extract a base class QWindowsBaseWindow from QWindowsWindow that provides _sys() getters for geometry and margin calculation and implements QPlatformWindow::geometry()/ frameMargins() to be calculated from the HWND. Implement a QWindowsDesktopWindow class directly inheriting QWindowsBaseWindow which does not allow any manipulation. Add a thin QWindowsForeignWindow class that wraps a foreign window id and always returns correct geometry/margin information when queried. Simple reparenting and manipulation of geometry for child windows is also implemented, allowing for embedding foreign windows into Qt. When calling other setters on it, the unimplemented warnings of QPlatformWindow will trigger. Remove the special casing for foreign/desktop window from QWindowsWindow. The existing mechanism to cache the geometry/margin values in QWindowsWindow remains as is. Rename the existing QWindowsWindow::baseWindowOf() and add checks there. Task-number: QTBUG-50206 Task-number: QTBUG-41186 Change-Id: Ib57cb87e3981312d32920fe3e49f0b1c4ad516a3 Reviewed-by: Joerg Bornemann --- .../platforms/windows/qwindowsbackingstore.cpp | 3 +- src/plugins/platforms/windows/qwindowscontext.cpp | 7 +- src/plugins/platforms/windows/qwindowscursor.cpp | 8 +- .../platforms/windows/qwindowsinputcontext.cpp | 6 +- .../platforms/windows/qwindowsintegration.cpp | 20 ++ .../platforms/windows/qwindowsmousehandler.cpp | 9 +- src/plugins/platforms/windows/qwindowswindow.cpp | 270 ++++++++++++++------- src/plugins/platforms/windows/qwindowswindow.h | 117 ++++++--- 8 files changed, 308 insertions(+), 132 deletions(-) (limited to 'src/plugins') diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 0f41d01716..b2cd5b124b 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -84,7 +84,8 @@ void QWindowsBackingStore::flush(QWindow *window, const QRegion ®ion, const QRect br = region.boundingRect(); if (QWindowsContext::verbose > 1) qCDebug(lcQpaBackingStore) << __FUNCTION__ << this << window << offset << br; - QWindowsWindow *rw = QWindowsWindow::baseWindowOf(window); + QWindowsWindow *rw = QWindowsWindow::windowsWindowOf(window); + Q_ASSERT(rw); #ifndef Q_OS_WINCE const bool hasAlpha = rw->format().hasAlpha(); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 2f133ba705..1f66de23ca 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1177,8 +1177,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, d->m_tabletSupport->notifyActivate(); #endif // !QT_NO_TABLETEVENT if (platformWindow->testFlag(QWindowsWindow::BlockedByModal)) - if (const QWindow *modalWindow = QGuiApplication::modalWindow()) - QWindowsWindow::baseWindowOf(modalWindow)->alertWindow(); + if (const QWindow *modalWindow = QGuiApplication::modalWindow()) { + QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(modalWindow); + Q_ASSERT(platformWindow); + platformWindow->alertWindow(); + } break; case QtWindows::MouseActivateWindowEvent: if (platformWindow->window()->flags() & Qt::WindowDoesNotAcceptFocus) { diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 13514b47b5..166328cf5e 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -648,17 +648,19 @@ QWindowsCursor::QWindowsCursor(const QPlatformScreen *screen) void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window) { - if (!window) + QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window); + if (!platformWindow) // Desktop/Foreign window. return; + if (!cursorIn) { - QWindowsWindow::baseWindowOf(window)->setCursor(CursorHandlePtr(new CursorHandle)); + platformWindow->setCursor(CursorHandlePtr(new CursorHandle)); return; } const CursorHandlePtr wcursor = cursorIn->shape() == Qt::BitmapCursor ? pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape()); if (wcursor->handle()) { - QWindowsWindow::baseWindowOf(window)->setCursor(wcursor); + platformWindow->setCursor(wcursor); } else { qWarning("%s: Unable to obtain system cursor for %d", __FUNCTION__, cursorIn->shape()); diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index e223a2ad93..f1addf186d 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -233,12 +233,10 @@ void QWindowsInputContext::updateEnabled() { if (!QGuiApplication::focusObject()) return; - const QWindow *window = QGuiApplication::focusWindow(); - if (window && window->handle()) { - QWindowsWindow *platformWindow = QWindowsWindow::baseWindowOf(window); + if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(QGuiApplication::focusWindow())) { const bool accepted = inputMethodAccepted(); if (QWindowsContext::verbose > 1) - qCDebug(lcQpaInputMethods) << __FUNCTION__ << window << "accepted=" << accepted; + qCDebug(lcQpaInputMethods) << __FUNCTION__ << platformWindow->window() << "accepted=" << accepted; QWindowsInputContext::setWindowsImeEnabled(platformWindow, accepted); } } diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index d975460ec7..2904999d96 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -302,6 +302,26 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const { + if (window->type() == Qt::Desktop) { + QWindowsDesktopWindow *result = new QWindowsDesktopWindow(window); + qCDebug(lcQpaWindows) << "Desktop window:" << window + << showbase << hex << result->winId() << noshowbase << dec << result->geometry(); + return result; + } + + if (window->type() == Qt::ForeignWindow) { + QWindowsForeignWindow *result = new QWindowsForeignWindow(window, reinterpret_cast(window->winId())); + const QRect obtainedGeometry = result->geometry(); + QScreen *screen = Q_NULLPTR; + if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) + screen = pScreen->screen(); + if (screen && screen != window->screen()) + window->setScreen(screen); + qCDebug(lcQpaWindows) << "Foreign window:" << window << showbase << hex + << result->winId() << noshowbase << dec << obtainedGeometry << screen; + return result; + } + QWindowsWindowData requested; requested.flags = window->flags(); requested.geometry = QHighDpi::toNativePixels(window->geometry(), window); diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 2bc9527b1b..c8b18f3b57 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -267,7 +267,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // Capture is necessary so we don't get WM_MOUSELEAVEs to confuse matters. // This autocapture is released normally when button is released. if (!platformWindow->hasMouseCapture()) { - QWindowsWindow::baseWindowOf(window)->applyCursor(); + platformWindow->applyCursor(); platformWindow->setMouseGrabEnabled(true); platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); qCDebug(lcQpaEvents) << "Automatic mouse capture for missing buttondown event" << window; @@ -355,7 +355,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_trackedWindow = 0; // We are not officially in any window, but we need to set some cursor to clear // whatever cursor the left window had, so apply the cursor of the capture window. - QWindowsWindow::baseWindowOf(window)->applyCursor(); + platformWindow->applyCursor(); } } // Enter is needed if: @@ -367,7 +367,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, || (m_previousCaptureWindow && window != m_previousCaptureWindow && currentWindowUnderMouse && currentWindowUnderMouse != m_previousCaptureWindow)) { qCDebug(lcQpaEvents) << "Entering " << currentWindowUnderMouse; - QWindowsWindow::baseWindowOf(currentWindowUnderMouse)->applyCursor(); + if (QWindowsWindow *wumPlatformWindow = QWindowsWindow::windowsWindowOf(currentWindowUnderMouse)) + wumPlatformWindow->applyCursor(); QWindowSystemInterface::handleEnterEvent(currentWindowUnderMouse, currentWindowUnderMouse->mapFromGlobal(globalPosition), globalPosition); @@ -392,7 +393,7 @@ static bool isValidWheelReceiver(QWindow *candidate) { if (candidate) { const QWindow *toplevel = QWindowsWindow::topLevelOf(candidate); - if (const QWindowsWindow *ww = QWindowsWindow::baseWindowOf(toplevel)) + if (const QWindowsWindow *ww = QWindowsWindow::windowsWindowOf(toplevel)) return !ww->testFlag(QWindowsWindow::BlockedByModal); } diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 218de5da85..246ebcb238 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -418,7 +418,7 @@ struct WindowCreationData enum Flags { ForceChild = 0x1, ForceTopLevel = 0x2 }; WindowCreationData() : parentHandle(0), type(Qt::Widget), style(0), exStyle(0), - topLevel(false), popup(false), dialog(false), desktop(false), + topLevel(false), popup(false), dialog(false), tool(false), embedded(false), hasAlpha(false) {} void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0); @@ -434,7 +434,6 @@ struct WindowCreationData bool topLevel; bool popup; bool dialog; - bool desktop; bool tool; bool embedded; bool hasAlpha; @@ -449,7 +448,7 @@ QDebug operator<<(QDebug debug, const WindowCreationData &d) << "\n topLevel=" << d.topLevel; if (d.parentHandle) debug << " parent=" << d.parentHandle; - debug << " popup=" << d.popup << " dialog=" << d.dialog << " desktop=" << d.desktop + debug << " popup=" << d.popup << " dialog=" << d.dialog << " embedded=" << d.embedded << " tool=" << d.tool << "\n style=" << debugWinStyle(d.style); if (d.exStyle) @@ -518,9 +517,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag case Qt::Popup: popup = true; break; - case Qt::Desktop: - desktop = true; - break; default: break; } @@ -537,7 +533,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag if (popup || (type == Qt::ToolTip) || (type == Qt::SplashScreen)) { style = WS_POPUP; - } else if (topLevel && !desktop) { + } else if (topLevel) { if (flags & Qt::FramelessWindowHint) style = WS_POPUP; // no border else if (flags & Qt::WindowTitleHint) @@ -548,7 +544,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag style = WS_CHILD; } - if (!desktop) { // if (!testAttribute(Qt::WA_PaintUnclipped)) // ### Commented out for now as it causes some problems, but // this should be correct anyway, so dig some more into this @@ -594,7 +589,6 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag if (flagsIn & Qt::WindowTransparentForInput) exStyle |= WS_EX_LAYERED | WS_EX_TRANSPARENT; #endif - } } } @@ -606,26 +600,6 @@ QWindowsWindowData WindowData result; result.flags = flags; - if (desktop) { // desktop widget. No frame, hopefully? - result.hwnd = GetDesktopWindow(); - result.geometry = frameGeometry(result.hwnd, true); - result.embedded = false; - qCDebug(lcQpaWindows) << "Created desktop window " << w << result.hwnd; - return result; - } - if ((flags & Qt::WindowType_Mask) == Qt::ForeignWindow) { - result.hwnd = reinterpret_cast(w->winId()); - Q_ASSERT(result.hwnd); - const LONG_PTR style = GetWindowLongPtr(result.hwnd, GWL_STYLE); - const LONG_PTR exStyle = GetWindowLongPtr(result.hwnd, GWL_EXSTYLE); - result.embedded = false; - result.frame = QWindowsGeometryHint::frame(style, exStyle); - result.geometry = frameGeometry(result.hwnd, !GetParent(result.hwnd)) - .marginsRemoved(result.frame); - qCDebug(lcQpaWindows) << "Foreign window: " << w << result.hwnd << result.geometry; - return result; - } - const HINSTANCE appinst = (HINSTANCE)GetModuleHandle(0); const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w); @@ -697,7 +671,7 @@ void WindowCreationData::applyWindowFlags(HWND hwnd) const void WindowCreationData::initialize(const QWindow *w, HWND hwnd, bool frameChange, qreal opacityLevel) const { - if (desktop || !hwnd) + if (!hwnd) return; UINT swpFlags = SWP_NOMOVE | SWP_NOSIZE; if (frameChange) @@ -848,6 +822,153 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w) == QWindowPrivate::WindowFrameInclusive; } +/*! + \class QWindowsBaseWindow + \brief Base class for QWindowsForeignWindow, QWindowsWindow + + The class provides some _sys() getters for querying window + data from a HWND and some _sys() setters. + + Derived classes wrapping foreign windows may use them directly + to calculate geometry, margins, etc. + + Derived classes representing windows created by Qt may defer + expensive calculations until change notifications are received. + + \since 5.6 + \internal + \ingroup qt-lighthouse-win +*/ + +QWindowsBaseWindow *QWindowsBaseWindow::baseWindowOf(const QWindow *w) +{ + if (w) { + if (QPlatformWindow *pw = w->handle()) + return static_cast(pw); + } + return Q_NULLPTR; +} + +HWND QWindowsBaseWindow::handleOf(const QWindow *w) +{ + const QWindowsBaseWindow *bw = QWindowsBaseWindow::baseWindowOf(w); + return bw ? bw->handle() : HWND(0); +} + +bool QWindowsBaseWindow::isTopLevel_sys() const +{ + const HWND parent = parentHwnd(); + return !parent || parent == GetDesktopWindow(); +} + +QRect QWindowsBaseWindow::frameGeometry_sys() const +{ + return frameGeometry(handle(), isTopLevel()); +} + +QRect QWindowsBaseWindow::geometry_sys() const +{ + return frameGeometry_sys().marginsRemoved(frameMargins()); +} + +QMargins QWindowsBaseWindow::frameMargins_sys() const +{ + return QWindowsGeometryHint::frame(style(), exStyle()); +} + +void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows. +{ + SetWindowPos(handle(),0 , 0, 0, 0, 0, + SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); +} + +void QWindowsBaseWindow::raise_sys() +{ + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); + SetWindowPos(handle(), HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +void QWindowsBaseWindow::lower_sys() +{ + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); + SetWindowPos(handle(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); +} + +void QWindowsBaseWindow::setWindowTitle_sys(const QString &title) +{ + qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << title; + SetWindowText(handle(), reinterpret_cast(title.utf16())); +} + +QPoint QWindowsBaseWindow::mapToGlobal(const QPoint &pos) const +{ + return QWindowsGeometryHint::mapToGlobal(handle(), pos); +} + +QPoint QWindowsBaseWindow::mapFromGlobal(const QPoint &pos) const +{ + return QWindowsGeometryHint::mapFromGlobal(handle(), pos); +} + +/*! + \class QWindowsDesktopWindow + \brief Window wrapping GetDesktopWindow not allowing any manipulation. + \since 5.6 + \internal + \ingroup qt-lighthouse-win +*/ + +/*! + \class QWindowsForeignWindow + \brief Window wrapping a foreign native window. + + QWindowsForeignWindow stores a native HWND and implements getters for + geometry, margins, etc. reparenting and geometry manipulation for use as a + child window in Qt. + + \since 5.6 + \internal + \ingroup qt-lighthouse-win +*/ + +QWindowsForeignWindow::QWindowsForeignWindow(QWindow *window, HWND hwnd) + : QWindowsBaseWindow(window) + , m_hwnd(hwnd) + , m_topLevelStyle(0) +{ +} + +void QWindowsForeignWindow::setParent(const QPlatformWindow *newParentWindow) +{ + const bool wasTopLevel = isTopLevel_sys(); + const HWND newParent = newParentWindow ? reinterpret_cast(newParentWindow->winId()) : HWND(0); + const bool isTopLevel = !newParent; + const DWORD oldStyle = style(); + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << "newParent=" + << newParentWindow << newParent << "oldStyle=" << debugWinStyle(oldStyle); + SetParent(m_hwnd, newParent); + if (wasTopLevel != isTopLevel) { // Top level window flags need to be set/cleared manually. + DWORD newStyle = oldStyle; + if (isTopLevel) { + newStyle = m_topLevelStyle; + } else { + m_topLevelStyle = oldStyle; + newStyle &= ~(WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW); + newStyle |= WS_CHILD; + } + SetWindowLongPtr(m_hwnd, GWL_STYLE, newStyle); + } +} + +void QWindowsForeignWindow::setVisible(bool visible) +{ + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << visible; + if (visible) + ShowWindow(handle(), SW_SHOWNOACTIVATE); + else + hide_sys(); +} + /*! \class QWindowCreationContext \brief Active Context for creating windows. @@ -928,7 +1049,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, */ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : - QPlatformWindow(aWindow), + QWindowsBaseWindow(aWindow), m_data(data), m_flags(WithinCreate), m_hdc(0), @@ -1006,7 +1127,7 @@ void QWindowsWindow::destroyWindow() setFlag(WithinDestroy); // Clear any transient child relationships as Windows will otherwise destroy them (QTBUG-35499, QTBUG-36666) if (QWindow *transientChild = findTransientChild(window())) - if (QWindowsWindow *tw = QWindowsWindow::baseWindowOf(transientChild)) + if (QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(transientChild)) tw->updateTransientParent(); QWindowsContext *context = QWindowsContext::instance(); if (context->windowUnderMouse() == window()) @@ -1029,8 +1150,7 @@ void QWindowsWindow::destroyWindow() } } #endif // !Q_OS_WINCE - if (m_data.hwnd != GetDesktopWindow() && window()->type() != Qt::ForeignWindow) - DestroyWindow(m_data.hwnd); + DestroyWindow(m_data.hwnd); context->removeWindow(m_data.hwnd); m_data.hwnd = 0; } @@ -1143,7 +1263,10 @@ void QWindowsWindow::setVisible(bool visible) } else { if (hasMouseCapture()) setMouseGrabEnabled(false); - hide_sys(); + if (window()->flags() & Qt::Popup) // from QWidgetPrivate::hide_sys(), activate other + ShowWindow(m_data.hwnd, SW_HIDE); + else + hide_sys(); fireExpose(QRegion()); } } @@ -1219,7 +1342,7 @@ void QWindowsWindow::updateTransientParent() const const HWND oldTransientParent = transientParentHwnd(m_data.hwnd); HWND newTransientParent = 0; if (const QWindow *tp = window()->transientParent()) - if (const QWindowsWindow *tw = QWindowsWindow::baseWindowOf(tp)) + if (const QWindowsWindow *tw = QWindowsWindow::windowsWindowOf(tp)) if (!tw->testFlag(WithinDestroy)) // Prevent destruction by parent window (QTBUG-35499, QTBUG-36666) newTransientParent = tw->handle(); if (newTransientParent != oldTransientParent) @@ -1283,18 +1406,6 @@ void QWindowsWindow::show_sys() const } } -// partially from QWidgetPrivate::hide_sys() -void QWindowsWindow::hide_sys() const -{ - const Qt::WindowFlags flags = window()->flags(); - if (flags != Qt::Desktop) { - if (flags & Qt::Popup) - ShowWindow(m_data.hwnd, SW_HIDE); - else - SetWindowPos(m_data.hwnd,0, 0,0,0,0, SWP_HIDEWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE); - } -} - void QWindowsWindow::setParent(const QPlatformWindow *newParent) { qCDebug(lcQpaWindows) << __FUNCTION__ << window() << newParent; @@ -1306,7 +1417,7 @@ void QWindowsWindow::setParent(const QPlatformWindow *newParent) void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) { // Use GetAncestor instead of GetParent, as GetParent can return owner window for toplevels - HWND oldParentHWND = GetAncestor(m_data.hwnd, GA_PARENT); + HWND oldParentHWND = parentHwnd(); HWND newParentHWND = 0; if (parent) { const QWindowsWindow *parentW = static_cast(parent); @@ -1470,7 +1581,7 @@ void QWindowsWindow::handleGeometryChange() qCDebug(lcQpaEvents) << __FUNCTION__ << this << window() << m_data.geometry; } -void QWindowsWindow::setGeometry_sys(const QRect &rect) const +void QWindowsBaseWindow::setGeometry_sys(const QRect &rect) const { const QMargins margins = frameMargins(); const QRect frameGeometry = rect + margins; @@ -1482,38 +1593,28 @@ void QWindowsWindow::setGeometry_sys(const QRect &rect) const bool result = false; #ifndef Q_OS_WINCE + const HWND hwnd = handle(); WINDOWPLACEMENT windowPlacement; windowPlacement.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(m_data.hwnd, &windowPlacement); + GetWindowPlacement(hwnd, &windowPlacement); // If the window is hidden and in maximized state or minimized, instead of moving the // window, set the normal position of the window. - if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(m_data.hwnd)) + if ((windowPlacement.showCmd == SW_MAXIMIZE && !IsWindowVisible(hwnd)) || windowPlacement.showCmd == SW_SHOWMINIMIZED) { windowPlacement.rcNormalPosition = - RECTfromQRect(frameGeometry.translated(-windowPlacementOffset(m_data.hwnd, frameGeometry.topLeft()))); + RECTfromQRect(frameGeometry.translated(-windowPlacementOffset(hwnd, frameGeometry.topLeft()))); windowPlacement.showCmd = windowPlacement.showCmd == SW_SHOWMINIMIZED ? SW_SHOWMINIMIZED : SW_HIDE; - result = SetWindowPlacement(m_data.hwnd, &windowPlacement); + result = SetWindowPlacement(hwnd, &windowPlacement); } else #endif // !Q_OS_WINCE { - result = MoveWindow(m_data.hwnd, frameGeometry.x(), frameGeometry.y(), + result = MoveWindow(hwnd, frameGeometry.x(), frameGeometry.y(), frameGeometry.width(), frameGeometry.height(), true); } qCDebug(lcQpaWindows) << '<' << __FUNCTION__ << window() << "\n resulting " << result << geometry_sys(); } -QRect QWindowsWindow::frameGeometry_sys() const -{ - bool isRealTopLevel = window()->isTopLevel() && !m_data.embedded; - return frameGeometry(m_data.hwnd, isRealTopLevel); -} - -QRect QWindowsWindow::geometry_sys() const -{ - return frameGeometry_sys().marginsRemoved(frameMargins()); -} - /*! Allocates a HDC for the window or returns the temporary one obtained from WinAPI BeginPaint within a WM_PAINT event. @@ -1572,11 +1673,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, void QWindowsWindow::setWindowTitle(const QString &title) { - qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() <isVisible() && child->transientParent() == w) { - QWindowsWindow *platformWindow = QWindowsWindow::baseWindowOf(child); - if (platformWindow->isLayered()) { + QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(child); + if (platformWindow && platformWindow->isLayered()) { platformWindow->fireExpose(QRegion(0, 0, child->width(), child->height())); exposeEventsSent = true; } @@ -1819,19 +1916,6 @@ void QWindowsWindow::setExStyle(unsigned s) const SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s); } -void QWindowsWindow::raise() -{ - qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); - SetWindowPos(m_data.hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -} - -void QWindowsWindow::lower() -{ - qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); - if (m_data.hwnd) - SetWindowPos(m_data.hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); -} - void QWindowsWindow::windowEvent(QEvent *event) { switch (event->type()) { @@ -2152,7 +2236,8 @@ static inline bool applyNewCursor(const QWindow *w) for (const QWindow *p = underMouse; p ; p = p->parent()) { if (p == w) return true; - if (!QWindowsWindow::baseWindowOf(p)->cursor()->isNull()) + const QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p); + if (platformWindow && !platformWindow->cursor()->isNull()) return false; } return false; @@ -2170,7 +2255,8 @@ void QWindowsWindow::applyCursor() #ifndef QT_NO_CURSOR if (m_cursor->isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel. if (const QWindow *p = window()->parent()) { - QWindowsWindow::baseWindowOf(p)->applyCursor(); + if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(p)) + platformWindow->applyCursor(); } else { SetCursor(defaultCursor(window())->handle()); } @@ -2281,6 +2367,11 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon) } } +bool QWindowsWindow::isTopLevel() const +{ + return window()->isTopLevel() && !m_data.embedded; +} + /*! \brief Sets custom margins to be added to the default margins determined by the windows style in the handling of the WM_NCCALCSIZE message. @@ -2345,8 +2436,7 @@ void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWind void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes) { #ifndef Q_OS_WINCE - if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) - && window()->type() != Qt::ForeignWindow) { + if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch)) { ULONG touchFlags = 0; const bool ret = QWindowsContext::user32dll.isTouchWindow(m_data.hwnd, &touchFlags); // Return if it is not a touch window or the flags are already set by a hook diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 8497931b9a..999761f3c6 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -118,7 +118,78 @@ struct QWindowsWindowData const QString &title); }; -class QWindowsWindow : public QPlatformWindow +class QWindowsBaseWindow : public QPlatformWindow +{ +public: + explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {} + + WId winId() const Q_DECL_OVERRIDE { return WId(handle()); } + QRect geometry() const Q_DECL_OVERRIDE { return geometry_sys(); } + QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMargins_sys(); } + QPoint mapToGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE; + + using QPlatformWindow::screenForGeometry; + + virtual HWND handle() const = 0; + virtual bool isTopLevel() const { return isTopLevel_sys(); } + + unsigned style() const { return GetWindowLongPtr(handle(), GWL_STYLE); } + unsigned exStyle() const { return GetWindowLongPtr(handle(), GWL_EXSTYLE); } + + static QWindowsBaseWindow *baseWindowOf(const QWindow *w); + static HWND handleOf(const QWindow *w); + +protected: + HWND parentHwnd() const { return GetAncestor(handle(), GA_PARENT); } + bool isTopLevel_sys() const; + QRect frameGeometry_sys() const; + QRect geometry_sys() const; + void setGeometry_sys(const QRect &rect) const; + QMargins frameMargins_sys() const; + void hide_sys(); + void raise_sys(); + void lower_sys(); + void setWindowTitle_sys(const QString &title); +}; + +class QWindowsDesktopWindow : public QWindowsBaseWindow +{ +public: + explicit QWindowsDesktopWindow(QWindow *window) + : QWindowsBaseWindow(window), m_hwnd(GetDesktopWindow()) {} + + QMargins frameMargins() const Q_DECL_OVERRIDE { return QMargins(); } + bool isTopLevel() const Q_DECL_OVERRIDE { return true; } + +protected: + HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; } + +private: + const HWND m_hwnd; +}; + +class QWindowsForeignWindow : public QWindowsBaseWindow +{ +public: + explicit QWindowsForeignWindow(QWindow *window, HWND hwnd); + + void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE { setGeometry_sys(rect); } + void setVisible(bool visible) Q_DECL_OVERRIDE; + void raise() Q_DECL_OVERRIDE { raise_sys(); } + void lower() Q_DECL_OVERRIDE { lower_sys(); } + void setWindowTitle(const QString &title) Q_DECL_OVERRIDE { setWindowTitle_sys(title); } + +protected: + HWND handle() const Q_DECL_OVERRIDE { return m_hwnd; } + +private: + const HWND m_hwnd; + DWORD m_topLevelStyle; +}; + +class QWindowsWindow : public QWindowsBaseWindow { public: enum Flags @@ -168,14 +239,11 @@ public: void setWindowFlags(Qt::WindowFlags flags) Q_DECL_OVERRIDE; void setWindowState(Qt::WindowState state) Q_DECL_OVERRIDE; - HWND handle() const { return m_data.hwnd; } - - WId winId() const Q_DECL_OVERRIDE { return WId(m_data.hwnd); } void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; void setWindowTitle(const QString &title) Q_DECL_OVERRIDE; - void raise() Q_DECL_OVERRIDE; - void lower() Q_DECL_OVERRIDE; + void raise() Q_DECL_OVERRIDE { raise_sys(); } + void lower() Q_DECL_OVERRIDE { lower_sys(); } void windowEvent(QEvent *event) Q_DECL_OVERRIDE; @@ -198,14 +266,14 @@ public: void setFrameStrutEventsEnabled(bool enabled) Q_DECL_OVERRIDE; bool frameStrutEventsEnabled() const Q_DECL_OVERRIDE { return testFlag(FrameStrutEventsEnabled); } + // QWindowsBaseWindow overrides + HWND handle() const Q_DECL_OVERRIDE { return m_data.hwnd; } + bool isTopLevel() const Q_DECL_OVERRIDE; + QMargins customMargins() const { return m_data.customMargins; } void setCustomMargins(const QMargins &m); - inline unsigned style() const - { return GetWindowLongPtr(m_data.hwnd, GWL_STYLE); } void setStyle(unsigned s) const; - inline unsigned exStyle() const - { return GetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE); } void setExStyle(unsigned s) const; bool handleWmPaint(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -215,8 +283,7 @@ public: void handleHidden(); void handleCompositionSettingsChanged(); - static inline HWND handleOf(const QWindow *w); - static inline QWindowsWindow *baseWindowOf(const QWindow *w); + static QWindowsWindow *windowsWindowOf(const QWindow *w); static QWindow *topLevelOf(QWindow *w); static inline void *userDataOf(HWND hwnd); static inline void setUserDataOf(HWND hwnd, void *ud); @@ -262,10 +329,6 @@ public: void setHasBorderInFullScreen(bool border); private: inline void show_sys() const; - inline void hide_sys() const; - inline void setGeometry_sys(const QRect &rect) const; - inline QRect frameGeometry_sys() const; - inline QRect geometry_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; inline bool isFullScreen_sys() const; inline void setWindowState_sys(Qt::WindowState newState); @@ -334,19 +397,17 @@ QPoint QWindowsGeometryHint::mapFromGlobal(const QWindow *w, const QPoint &p) // ---------- QWindowsBaseWindow inline functions. -QWindowsWindow *QWindowsWindow::baseWindowOf(const QWindow *w) +inline QWindowsWindow *QWindowsWindow::windowsWindowOf(const QWindow *w) { - if (w) - if (QPlatformWindow *pw = w->handle()) - return static_cast(pw); - return 0; -} - -HWND QWindowsWindow::handleOf(const QWindow *w) -{ - if (const QWindowsWindow *bw = QWindowsWindow::baseWindowOf(w)) - return bw->handle(); - return 0; + QWindowsWindow *result = Q_NULLPTR; + if (w) { + const Qt::WindowType type = w->type(); + if (type != Qt::Desktop && type != Qt::ForeignWindow) { + if (QPlatformWindow *pw = w->handle()) + result = static_cast(pw); + } + } + return result; } void *QWindowsWindow::userDataOf(HWND hwnd) -- cgit v1.2.3