Blob Blame History Raw
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 <QtWaylandClient/qtwaylandclientglobal.h>
 #include <QtWaylandClient/private/qwaylandshellsurface_p.h>
+#include <QtWaylandClient/private/qwaylandwindow_p.h>
 
 #include <QtCore/QSize>
 #include <QtGui/QRegion>
@@ -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;