diff --git a/src/client/qwaylandabstractdecoration_p.h b/src/client/qwaylandabstractdecoration_p.h index 81c8e177..61cbde77 100644 --- a/src/client/qwaylandabstractdecoration_p.h +++ b/src/client/qwaylandabstractdecoration_p.h @@ -82,6 +82,12 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandAbstractDecoration : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QWaylandAbstractDecoration) public: + enum MarginsType { + Full, + ShadowsExcluded, + ShadowsOnly + }; + QWaylandAbstractDecoration(); ~QWaylandAbstractDecoration() override; @@ -91,7 +97,8 @@ public: void update(); bool isDirty() const; - virtual QMargins margins() const = 0; + virtual QMargins margins(MarginsType marginsType = Full) const = 0; + QWindow *window() const; const QImage &contentImage(); diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp index bd70f4af..0e819235 100644 --- a/src/client/qwaylandwindow.cpp +++ b/src/client/qwaylandwindow.cpp @@ -380,6 +380,16 @@ void QWaylandWindow::setGeometry(const QRect &rect) void QWaylandWindow::resizeFromApplyConfigure(const QSize &sizeWithMargins, const QPoint &offset) { QMargins margins = frameMargins(); + + // Exclude shadows from margins once they are excluded from window geometry + // 1) First resizeFromApplyConfigure() call will have sizeWithMargins equal to surfaceSize() + // which has full margins (shadows included). + // 2) Following resizeFromApplyConfigure() calls should have sizeWithMargins equal to + // windowContentGeometry() which excludes shadows, therefore in this case we have to + // exclude them too in order not to accidentally apply smaller size to the window. + if (mWindowDecoration && (sizeWithMargins != surfaceSize())) + margins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsExcluded); + int widthWithoutMargins = qMax(sizeWithMargins.width() - (margins.left() + margins.right()), 1); int heightWithoutMargins = qMax(sizeWithMargins.height() - (margins.top() + margins.bottom()), 1); QRect geometry(windowGeometry().topLeft(), QSize(widthWithoutMargins, heightWithoutMargins)); @@ -690,7 +700,12 @@ QSize QWaylandWindow::surfaceSize() const */ QRect QWaylandWindow::windowContentGeometry() const { - return QRect(QPoint(), surfaceSize()); + QMargins shadowMargins; + + if (mWindowDecoration) + shadowMargins = mWindowDecoration->margins(QWaylandAbstractDecoration::ShadowsOnly); + + return QRect(QPoint(shadowMargins.left(), shadowMargins.top()), surfaceSize().shrunkBy(shadowMargins)); } /*! @@ -1079,6 +1094,21 @@ bool QWaylandWindow::setMouseGrabEnabled(bool grab) return true; } +QWaylandWindow::ToplevelWindowTilingStates QWaylandWindow::toplevelWindowTilingStates() const +{ + return mLastReportedToplevelWindowTilingStates; +} + +void QWaylandWindow::handleToplevelWindowTilingStatesChanged(ToplevelWindowTilingStates states) +{ + mLastReportedToplevelWindowTilingStates = states; +} + +Qt::WindowStates QWaylandWindow::windowStates() const +{ + return mLastReportedWindowStates; +} + void QWaylandWindow::handleWindowStatesChanged(Qt::WindowStates states) { createDecoration(); diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h index 6cc1664b..93ba0623 100644 --- a/src/client/qwaylandwindow_p.h +++ b/src/client/qwaylandwindow_p.h @@ -95,6 +95,15 @@ public: Vulkan }; + enum ToplevelWindowTilingState { + WindowNoState = 0, + WindowTiledLeft = 1, + WindowTiledRight = 2, + WindowTiledTop = 4, + WindowTiledBottom = 8 + }; + Q_DECLARE_FLAGS(ToplevelWindowTilingStates, ToplevelWindowTilingState) + QWaylandWindow(QWindow *window, QWaylandDisplay *display); ~QWaylandWindow() override; @@ -145,6 +154,10 @@ public: void handleContentOrientationChange(Qt::ScreenOrientation orientation) override; void setOrientationMask(Qt::ScreenOrientations mask); + ToplevelWindowTilingStates toplevelWindowTilingStates() const; + void handleToplevelWindowTilingStatesChanged(ToplevelWindowTilingStates states); + + Qt::WindowStates windowStates() const; void setWindowState(Qt::WindowStates states) override; void setWindowFlags(Qt::WindowFlags flags) override; void handleWindowStatesChanged(Qt::WindowStates states); @@ -256,6 +269,7 @@ protected: QRegion mMask; QRegion mOpaqueArea; Qt::WindowStates mLastReportedWindowStates = Qt::WindowNoState; + ToplevelWindowTilingStates mLastReportedToplevelWindowTilingStates = WindowNoState; QWaylandShmBackingStore *mBackingStore = nullptr; QWaylandBuffer *mQueuedBuffer = nullptr; @@ -292,6 +306,8 @@ private: friend class QWaylandSubSurface; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QWaylandWindow::ToplevelWindowTilingStates) + inline QIcon QWaylandWindow::windowIcon() const { return mWindowIcon; diff --git a/src/plugins/decorations/bradient/main.cpp b/src/plugins/decorations/bradient/main.cpp index e75fda3c..72dda67f 100644 --- a/src/plugins/decorations/bradient/main.cpp +++ b/src/plugins/decorations/bradient/main.cpp @@ -72,7 +72,7 @@ class Q_WAYLAND_CLIENT_EXPORT QWaylandBradientDecoration : public QWaylandAbstra public: QWaylandBradientDecoration(); protected: - QMargins margins() const override; + QMargins margins(MarginsType marginsType = Full) const override; void paint(QPaintDevice *device) override; bool handleMouse(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global,Qt::MouseButtons b,Qt::KeyboardModifiers mods) override; bool handleTouch(QWaylandInputDevice *inputDevice, const QPointF &local, const QPointF &global, Qt::TouchPointState state, Qt::KeyboardModifiers mods) override; @@ -129,8 +129,11 @@ QRectF QWaylandBradientDecoration::minimizeButtonRect() const (margins().top() - BUTTON_WIDTH) / 2, BUTTON_WIDTH, BUTTON_WIDTH); } -QMargins QWaylandBradientDecoration::margins() const +QMargins QWaylandBradientDecoration::margins(MarginsType marginsType) const { + if (marginsType == ShadowsOnly) + return QMargins(); + return QMargins(3, 30, 3, 3); } diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp index 7d33dabd..cf7eb4e9 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell.cpp @@ -94,6 +94,7 @@ void QWaylandXdgSurface::Toplevel::applyConfigure() // TODO: none of the other plugins send WindowActive either, but is it on purpose? Qt::WindowStates statesWithoutActive = m_pending.states & ~Qt::WindowActive; + m_xdgSurface->m_window->handleToplevelWindowTilingStatesChanged(m_toplevelStates); m_xdgSurface->m_window->handleWindowStatesChanged(statesWithoutActive); if (m_pending.size.isEmpty()) { @@ -126,6 +127,7 @@ void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure(int32_t width, int32_t size_t numStates = states->size / sizeof(uint32_t); m_pending.states = Qt::WindowNoState; + m_toplevelStates = QWaylandWindow::WindowNoState; for (size_t i = 0; i < numStates; i++) { switch (xdgStates[i]) { @@ -138,6 +140,18 @@ void QWaylandXdgSurface::Toplevel::xdg_toplevel_configure(int32_t width, int32_t case XDG_TOPLEVEL_STATE_FULLSCREEN: m_pending.states |= Qt::WindowFullScreen; break; + case XDG_TOPLEVEL_STATE_TILED_LEFT: + m_toplevelStates |= QWaylandWindow::WindowTiledLeft; + break; + case XDG_TOPLEVEL_STATE_TILED_RIGHT: + m_toplevelStates |= QWaylandWindow::WindowTiledRight; + break; + case XDG_TOPLEVEL_STATE_TILED_TOP: + m_toplevelStates |= QWaylandWindow::WindowTiledTop; + break; + case XDG_TOPLEVEL_STATE_TILED_BOTTOM: + m_toplevelStates |= QWaylandWindow::WindowTiledBottom; + break; default: break; } @@ -457,7 +471,7 @@ void QWaylandXdgSurface::xdg_surface_configure(uint32_t serial) } QWaylandXdgShell::QWaylandXdgShell(QWaylandDisplay *display, uint32_t id, uint32_t availableVersion) - : QtWayland::xdg_wm_base(display->wl_registry(), id, qMin(availableVersion, 1u)) + : QtWayland::xdg_wm_base(display->wl_registry(), id, qMin(availableVersion, 2u)) , m_display(display) { display->addRegistryListener(&QWaylandXdgShell::handleRegistryGlobal, this); diff --git a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h index 0c98be35..d7912132 100644 --- a/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h +++ b/src/plugins/shellintegration/xdg-shell/qwaylandxdgshell_p.h @@ -58,6 +58,7 @@ #include #include +#include #include #include @@ -69,7 +70,6 @@ class QWindow; namespace QtWaylandClient { class QWaylandDisplay; -class QWaylandWindow; class QWaylandInputDevice; class QWaylandXdgShell; @@ -123,6 +123,7 @@ private: QSize size = {0, 0}; Qt::WindowStates states = Qt::WindowNoState; } m_pending, m_applied; + QWaylandWindow::ToplevelWindowTilingStates m_toplevelStates = QWaylandWindow::WindowNoState; QSize m_normalSize; QWaylandXdgSurface *m_xdgSurface = nullptr;