diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index c6dd0955aa..c5d88b198b 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -411,6 +411,15 @@ void QWindowPrivate::clearFocusObject() { } +// Allows for manipulating the suggested geometry before a resize/move +// event in derived classes for platforms that support it, for example to +// implement heightForWidth(). +QRectF QWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const +{ + Q_UNUSED(rect) + return QRectF(); +} + /*! Sets the \a surfaceType of the window. diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 46dc2e463c..bc5dfa4876 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -132,6 +132,7 @@ public: void emitScreenChangedRecursion(QScreen *newScreen); virtual void clearFocusObject(); + virtual QRectF closestAcceptableGeometry(const QRectF &rect) const; QWindow::SurfaceType surfaceType; Qt::WindowFlags windowFlags; diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index 99c97d156f..90e6d6ab9d 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -72,7 +72,8 @@ enum WindowsEventType // Simplify event types ShowEventOnParentRestoring = WindowEventFlag + 20, HideEvent = WindowEventFlag + 8, DestroyEvent = WindowEventFlag + 9, - MoveEvent = WindowEventFlag + 10, + GeometryChangingEvent = WindowEventFlag + 10, + MoveEvent = WindowEventFlag + 11, ResizeEvent = WindowEventFlag + 12, QuerySizeHints = WindowEventFlag + 15, CalculateSize = WindowEventFlag + 16, @@ -146,6 +147,10 @@ inline QtWindows::WindowsEventType windowsEventType(UINT message, WPARAM wParamI case WM_MOUSEWHEEL: case WM_MOUSEHWHEEL: return QtWindows::MouseWheelEvent; +#ifndef Q_OS_WINCE + case WM_WINDOWPOSCHANGING: + return QtWindows::GeometryChangingEvent; +#endif case WM_MOVE: return QtWindows::MoveEvent; case WM_SHOWWINDOW: diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 22a4dbb09f..4f1a1a375f 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -995,6 +995,8 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, return QWindowsGeometryHint::handleCalculateSize(platformWindow->customMargins(), msg, result); case QtWindows::NonClientHitTest: return platformWindow->handleNonClientHitTest(QPoint(msg.pt.x, msg.pt.y), result); + case QtWindows::GeometryChangingEvent: + return platformWindow->QWindowsWindow::handleGeometryChanging(&msg); #endif // !Q_OS_WINCE case QtWindows::ExposeEvent: return platformWindow->handleWmPaint(hwnd, message, wParam, lParam); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 8a80729354..0b4bb9b09d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1783,6 +1783,43 @@ void QWindowsWindow::propagateSizeHints() qCDebug(lcQpaWindows) << __FUNCTION__ << this << window(); } +bool QWindowsWindow::handleGeometryChanging(MSG *message) const +{ +#ifndef Q_OS_WINCE + QWindow *qWin = window(); + if (!qWin->isTopLevel()) + return false; + WINDOWPOS *windowPos = reinterpret_cast(message->lParam); + if ((windowPos->flags & (SWP_NOCOPYBITS | SWP_NOSIZE))) + return false; + const QMargins marginsDp = frameMarginsDp(); + const QRect suggestedFrameGeometryDp(windowPos->x, windowPos->y, + windowPos->cx, windowPos->cy); + const qreal factor = QWindowsScaling::factor(); + const QRect suggestedGeometryDp = suggestedFrameGeometryDp - marginsDp; + const QRectF suggestedGeometry = QRectF(QPointF(suggestedGeometryDp.topLeft()) / factor, + QSizeF(suggestedGeometryDp.size()) / factor); + const QRectF correctedGeometryF = + qt_window_private(qWin)->closestAcceptableGeometry(suggestedGeometry); + if (!correctedGeometryF.isValid()) + return false; + const QRect correctedFrameGeometryDp + = QRectF(correctedGeometryF.topLeft() * factor, + correctedGeometryF.size() * factor).toRect() + + marginsDp; + if (correctedFrameGeometryDp == suggestedFrameGeometryDp) + return false; + windowPos->x = correctedFrameGeometryDp.left(); + windowPos->y = correctedFrameGeometryDp.top(); + windowPos->cx = correctedFrameGeometryDp.width(); + windowPos->cy = correctedFrameGeometryDp.height(); + return true; +#else // !Q_OS_WINCE + Q_UNUSED(message) + return false; +#endif +} + QMargins QWindowsWindow::frameMarginsDp() const { // Frames are invalidated by style changes (window state, flags). diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index edba992b19..a63a9f56e3 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -183,6 +183,7 @@ public: void windowEvent(QEvent *event); void propagateSizeHints() Q_DECL_OVERRIDE; + bool handleGeometryChanging(MSG *message) const; QMargins frameMarginsDp() const; QMargins frameMargins() const Q_DECL_OVERRIDE { return frameMarginsDp() / QWindowsScaling::factor(); } diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index e455b772fb..463eea4ddc 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -33,6 +33,7 @@ #include "private/qwindow_p.h" #include "qwidgetwindow_p.h" +#include "qlayout.h" #include "private/qwidget_p.h" #include "private/qapplication_p.h" @@ -79,8 +80,38 @@ public: widget->focusWidget()->clearFocus(); } + QRectF closestAcceptableGeometry(const QRectF &rect) const Q_DECL_OVERRIDE; }; +QRectF QWidgetWindowPrivate::closestAcceptableGeometry(const QRectF &rect) const +{ + Q_Q(const QWidgetWindow); + const QWidget *widget = q->widget(); + if (!widget->isWindow() || !widget->hasHeightForWidth()) + return QRect(); + const QSize oldSize = rect.size().toSize(); + const QSize newSize = QLayout::closestAcceptableSize(widget, oldSize); + if (newSize == oldSize) + return QRectF(); + const int dw = newSize.width() - oldSize.width(); + const int dh = newSize.height() - oldSize.height(); + QRectF result = rect; + const QRectF currentGeometry(widget->geometry()); + const qreal topOffset = result.top() - currentGeometry.top(); + const qreal bottomOffset = result.bottom() - currentGeometry.bottom(); + if (qAbs(topOffset) > qAbs(bottomOffset)) + result.setTop(result.top() - dh); // top edge drag + else + result.setBottom(result.bottom() + dh); // bottom edge drag + const qreal leftOffset = result.left() - currentGeometry.left(); + const qreal rightOffset = result.right() - currentGeometry.right(); + if (qAbs(leftOffset) > qAbs(rightOffset)) + result.setLeft(result.left() - dw); // left edge drag + else + result.setRight(result.right() + dw); // right edge drag + return result; +} + QWidgetWindow::QWidgetWindow(QWidget *widget) : QWindow(*new QWidgetWindowPrivate(), 0) , m_widget(widget)