diff options
Diffstat (limited to 'src/plugins/platforms/windows/qwindowswindow.cpp')
-rw-r--r-- | src/plugins/platforms/windows/qwindowswindow.cpp | 156 |
1 files changed, 91 insertions, 65 deletions
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 48835f26a6..40229d00af 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -118,6 +118,35 @@ static QByteArray debugWinExStyle(DWORD exStyle) return rc; } +static QByteArray debugWinSwpPos(UINT flags) +{ + QByteArray rc = "0x"; + rc += QByteArray::number(flags, 16); + if (flags & SWP_FRAMECHANGED) + rc += " SWP_FRAMECHANGED"; + if (flags & SWP_HIDEWINDOW) + rc += " SWP_HIDEWINDOW"; + if (flags & SWP_NOACTIVATE) + rc += " SWP_NOACTIVATE"; + if (flags & SWP_NOCOPYBITS) + rc += " SWP_NOCOPYBITS"; + if (flags & SWP_NOMOVE) + rc += " SWP_NOMOVE"; + if (flags & SWP_NOOWNERZORDER) + rc += " SWP_NOOWNERZORDER"; + if (flags & SWP_NOREDRAW) + rc += " SWP_NOREDRAW"; + if (flags & SWP_NOSENDCHANGING) + rc += " SWP_NOSENDCHANGING"; + if (flags & SWP_NOSIZE) + rc += " SWP_NOSIZE"; + if (flags & SWP_NOZORDER) + rc += " SWP_NOZORDER"; + if (flags & SWP_SHOWWINDOW) + rc += " SWP_SHOWWINDOW"; + return rc; +} + static inline QSize qSizeOfRect(const RECT &rect) { return QSize(rect.right -rect.left, rect.bottom - rect.top); @@ -141,8 +170,9 @@ QDebug operator<<(QDebug d, const RECT &r) { QDebugStateSaver saver(d); d.nospace(); - d << "RECT: left/top=" << r.left << ',' << r.top - << " right/bottom=" << r.right << ',' << r.bottom; + d << "RECT(left=" << r.left << ", top=" << r.top + << ", right=" << r.right << ", bottom=" << r.bottom + << " (" << r.right - r.left << 'x' << r.bottom - r.top << "))"; return d; } @@ -152,12 +182,23 @@ QDebug operator<<(QDebug d, const POINT &p) return d; } +QDebug operator<<(QDebug d, const WINDOWPOS &wp) +{ + QDebugStateSaver saver(d); + d.nospace(); + d.noquote(); + d << "WINDOWPOS(flags=" << debugWinSwpPos(wp.flags) << ", hwnd=" + << wp.hwnd << ", hwndInsertAfter=" << wp.hwndInsertAfter << ", x=" << wp.x + << ", y=" << wp.y << ", cx=" << wp.cx << ", cy=" << wp.cy << ')'; + return d; +} + QDebug operator<<(QDebug d, const NCCALCSIZE_PARAMS &p) { QDebugStateSaver saver(d); d.nospace(); - d << "NCCALCSIZE_PARAMS " << qrectFromRECT(p.rgrc[0]) - << ' ' << qrectFromRECT(p.rgrc[1]) << ' ' << qrectFromRECT(p.rgrc[2]); + d << "NCCALCSIZE_PARAMS(rgrc=[" << p.rgrc[0] << ' ' << p.rgrc[1] << ' ' + << p.rgrc[2] << "], lppos=" << *p.lppos << ')'; return d; } @@ -177,6 +218,7 @@ QDebug operator<<(QDebug d, const WINDOWPLACEMENT &wp) { QDebugStateSaver saver(d); d.nospace(); + d.noquote(); d << "WINDOWPLACEMENT(flags=0x" << hex << wp.flags << dec << ", showCmd=" << wp.showCmd << ", ptMinPosition=" << wp.ptMinPosition << ", ptMaxPosition=" << wp.ptMaxPosition << ", rcNormalPosition=" << wp.rcNormalPosition; @@ -939,9 +981,7 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, DWORD style_, DWORD exStyle_) : geometryHint(w, cm), window(w), style(style_), exStyle(exStyle_), requestedGeometry(geometry), obtainedGeometry(geometry), - margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm), - frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT), - frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT) + margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm) { // Geometry of toplevels does not consider window frames. // TODO: No concept of WA_wasMoved yet that would indicate a @@ -994,17 +1034,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w, QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) : QWindowsBaseWindow(aWindow), m_data(data), - m_flags(WithinCreate), - m_hdc(0), - m_windowState(Qt::WindowNoState), - m_opacity(1.0), m_cursor(new CursorHandle), - m_dropTarget(0), - m_savedStyle(0), - m_format(aWindow->requestedFormat()), - m_iconSmall(0), - m_iconBig(0), - m_surface(0) + m_format(aWindow->requestedFormat()) { // Clear the creation context as the window can be found in QWindowsContext's map. QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>()); @@ -1095,7 +1126,7 @@ void QWindowsWindow::updateDropSite(bool topLevel) // if the parent window is a foreign window wrapped via QWindow::fromWinId, we need to enable the drop site // on the first child window const QWindow *parent = window()->parent(); - if (parent && (parent->type() == Qt::ForeignWindow)) + if (parent && parent->handle() && parent->handle()->isForeignWindow()) parentIsEmbedded = true; } @@ -1216,18 +1247,14 @@ bool QWindowsWindow::isActive() const return false; } -bool QWindowsWindow::isEmbedded(const QPlatformWindow *parentWindow) const +bool QWindowsWindow::isAncestorOf(const QPlatformWindow *child) const { - if (parentWindow) { - const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(parentWindow); - const HWND hwnd = ww->handle(); - if (!IsChild(hwnd, m_data.hwnd)) - return false; - } - - if (!m_data.embedded && parent()) - return parent()->isEmbedded(); + const QWindowsWindow *childWindow = static_cast<const QWindowsWindow *>(child); + return IsChild(m_data.hwnd, childWindow->handle()); +} +bool QWindowsWindow::isEmbedded() const +{ return m_data.embedded; } @@ -1471,18 +1498,22 @@ void QWindowsWindow::handleResized(int wParam) case SIZE_MAXHIDE: // Some other window affected. case SIZE_MAXSHOW: return; - case SIZE_MINIMIZED: - handleWindowStateChange(Qt::WindowMinimized); + case SIZE_MINIMIZED: // QTBUG-53577, prevent state change events during programmatic state change + if (!testFlag(WithinSetStyle)) + handleWindowStateChange(Qt::WindowMinimized); return; case SIZE_MAXIMIZED: - handleWindowStateChange(Qt::WindowMaximized); + if (!testFlag(WithinSetStyle)) + handleWindowStateChange(Qt::WindowMaximized); handleGeometryChange(); break; case SIZE_RESTORED: - if (isFullScreen_sys()) - handleWindowStateChange(Qt::WindowFullScreen); - else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) - handleWindowStateChange(Qt::WindowNoState); + if (!testFlag(WithinSetStyle)) { + if (isFullScreen_sys()) + handleWindowStateChange(Qt::WindowFullScreen); + else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen)) + handleWindowStateChange(Qt::WindowNoState); + } handleGeometryChange(); break; } @@ -1490,9 +1521,6 @@ void QWindowsWindow::handleResized(int wParam) void QWindowsWindow::handleGeometryChange() { - //Prevent recursive resizes for Windows CE - if (testFlag(WithinSetStyle)) - return; const QRect previousGeometry = m_data.geometry; m_data.geometry = geometry_sys(); QPlatformWindow::setGeometry(m_data.geometry); @@ -1505,10 +1533,16 @@ void QWindowsWindow::handleGeometryChange() && !(m_data.geometry.width() > previousGeometry.width() || m_data.geometry.height() > previousGeometry.height())) { fireExpose(QRect(QPoint(0, 0), m_data.geometry.size()), true); } - if (previousGeometry.topLeft() != m_data.geometry.topLeft()) { - QPlatformScreen *newScreen = screenForGeometry(m_data.geometry); - if (newScreen != screen()) - QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->screen()); + if (!parent() && previousGeometry.topLeft() != m_data.geometry.topLeft()) { + HMONITOR hMonitor = MonitorFromWindow(m_data.hwnd, MONITOR_DEFAULTTONULL); + QPlatformScreen *currentScreen = screen(); + const auto screens = QWindowsContext::instance()->screenManager().screens(); + auto newScreenIt = std::find_if(screens.begin(), screens.end(), [&](QWindowsScreen *s) { + return s->data().hMonitor == hMonitor + && s->data().flags & QWindowsScreenData::VirtualDesktop; + }); + if (newScreenIt != screens.end() && *newScreenIt != currentScreen) + QWindowSystemInterface::handleWindowScreenChanged(window(), (*newScreenIt)->screen()); } if (testFlag(SynchronousGeometryChangeEvent)) QWindowSystemInterface::flushWindowSystemEvents(QEventLoop::ExcludeUserInputEvents); @@ -1659,7 +1693,6 @@ QWindowsWindowData QWindowsWindow::setWindowFlags_sys(Qt::WindowFlags wt, QWindowsWindowData result = m_data; result.flags = creationData.flags; result.embedded = creationData.embedded; - setFlag(FrameDirty); return result; } @@ -1667,7 +1700,6 @@ void QWindowsWindow::handleWindowStateChange(Qt::WindowState state) { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << "\n from " << m_windowState << " to " << state; - setFlag(FrameDirty); m_windowState = state; QWindowSystemInterface::handleWindowStateChanged(window(), state); switch (state) { @@ -1744,8 +1776,6 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState) const bool visible = isVisible(); - setFlag(FrameDirty); - if ((oldState == Qt::WindowFullScreen) != (newState == Qt::WindowFullScreen)) { if (newState == Qt::WindowFullScreen) { #ifndef Q_FLATTEN_EXPOSE @@ -1839,7 +1869,6 @@ void QWindowsWindow::setStyle(unsigned s) const { qCDebug(lcQpaWindows) << __FUNCTION__ << this << window() << debugWinStyle(s); setFlag(WithinSetStyle); - setFlag(FrameDirty); SetWindowLongPtr(m_data.hwnd, GWL_STYLE, s); clearFlag(WithinSetStyle); } @@ -1848,7 +1877,6 @@ void QWindowsWindow::setExStyle(unsigned s) const { qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << this << ' ' << window() << " 0x" << QByteArray::number(s, 16); - setFlag(FrameDirty); SetWindowLongPtr(m_data.hwnd, GWL_EXSTYLE, s); } @@ -1904,22 +1932,17 @@ bool QWindowsWindow::handleGeometryChanging(MSG *message) const return QWindowsWindow::handleGeometryChangingMessage(message, window(), margins); } -QMargins QWindowsWindow::frameMargins() const +void QWindowsWindow::setFrameMargins(const QMargins &newMargins) { - // Frames are invalidated by style changes (window state, flags). - // As they are also required for geometry calculations in resize - // event sequences, introduce a dirty flag mechanism to be able - // to cache results. - if (testFlag(FrameDirty)) { - // Always skip calculating style-dependent margins for windows claimed to be frameless. - // This allows users to remove the margins by handling WM_NCCALCSIZE with WS_THICKFRAME set - // to ensure Areo snap still works (QTBUG-40578). - m_data.frame = m_data.flags & Qt::FramelessWindowHint - ? QMargins(0, 0, 0, 0) - : QWindowsGeometryHint::frame(style(), exStyle()); - clearFlag(FrameDirty); + if (m_data.frame != newMargins) { + qCDebug(lcQpaWindows) << __FUNCTION__ << window() << m_data.frame << "->" << newMargins; + m_data.frame = newMargins; } - return m_data.frame + m_data.customMargins; +} + +QMargins QWindowsWindow::frameMargins() const +{ + return m_data.frame; } void QWindowsWindow::setOpacity(qreal level) @@ -2091,8 +2114,12 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled) void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const { - const QWindowsGeometryHint hint(window(), m_data.customMargins); - hint.applyToMinMaxInfo(m_data.hwnd, mmi); + // We don't apply the min/max size hint as we change the dpi, because we did not adjust the + // QScreen of the window yet so we don't have the min/max with the right ratio + if (!testFlag(QWindowsWindow::WithinDpiChanged)) { + const QWindowsGeometryHint hint(window(), m_data.customMargins); + hint.applyToMinMaxInfo(m_data.hwnd, mmi); + } if ((testFlag(WithinMaximize) || (window()->windowState() == Qt::WindowMinimized)) && (m_data.flags & Qt::FramelessWindowHint)) { @@ -2335,7 +2362,6 @@ void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins) const QPoint topLeft = currentFrameGeometry.topLeft(); QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins; newFrame.moveTo(topLeft); - setFlag(FrameDirty); qCDebug(lcQpaWindows) << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins << currentFrameGeometry << "->" << newFrame; SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED); |