[plasma/kwin] src: Rework how min visible area for interactive move/resize is specified

Vlad Zahorodnii <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit c9ba0758ccb1e81ecb03843747f2ad228e526aa3 by Vlad Zahorodnii.
Committed on 03/08/2026 at 05:37.
Pushed by vladz into branch 'master'.

Rework how min visible area for interactive move/resize is specified

M  +39   -27   src/window.cpp
M  +2    -2    src/window.h

https://invent.kde.org/plasma/kwin/-/commit/c9ba0758ccb1e81ecb03843747f2ad228e526aa3

diff --git a/src/window.cpp b/src/window.cpp
index 52814e6a50e..7019972edc1 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -1258,19 +1258,28 @@ void Window::updateInteractiveMoveResize(const QPointF &global, Qt::KeyboardModi
     }
 }
 
-qreal Window::titlebarThickness() const
+QSizeF Window::minVisibleArea() const
 {
+    const qreal minVisibleWidth = 100;
+
+    qreal minVisibleHeight;
     switch (titlebarPosition()) {
     case Qt::LeftEdge:
-        return borderLeft();
+        minVisibleHeight = borderLeft();
+        break;
     case Qt::BottomEdge:
-        return borderBottom();
+        minVisibleHeight = borderBottom();
+        break;
     case Qt::RightEdge:
-        return borderRight();
+        minVisibleHeight = borderRight();
+        break;
     case Qt::TopEdge:
     default:
-        return borderTop();
+        minVisibleHeight = borderTop();
+        break;
     }
+
+    return QSizeF(minVisibleWidth, minVisibleHeight);
 }
 
 /**
@@ -1284,7 +1293,7 @@ qreal Window::titlebarThickness() const
  *
  * See doc/moveresizerestriction for more details on algorithm.
  */
-static RegionF interactiveMoveResizeVisibleSubrectRegion(const RectF &geometry, Gravity gravity, int minWidth, int minHeight)
+static RegionF interactiveMoveResizeVisibleSubrectRegion(const RectF &geometry, Gravity gravity, const QSizeF &minVisibleArea)
 {
     const auto outputs = workspace()->outputs();
     const auto struts = workspace()->restrictedMoveArea();
@@ -1300,21 +1309,21 @@ static RegionF interactiveMoveResizeVisibleSubrectRegion(const RectF &geometry,
     case Gravity::None:
     case Gravity::Top:
         // resizing from the top is handled like moving the window to avoid zero width rectangles when window width is equal to minWidth
-        initialRect.adjust(0, 0, -minWidth, -minHeight);
+        initialRect.adjust(0, 0, -minVisibleArea.width(), -minVisibleArea.height());
         break;
     case Gravity::Left:
     case Gravity::TopLeft:
     case Gravity::BottomLeft:
         initialRect.setRight(std::min(initialRect.right(), geometry.right()));
         initialRect.setBottom(std::min(initialRect.bottom(), geometry.bottom()));
-        initialRect.adjust(0, 0, -minWidth, -minHeight);
+        initialRect.adjust(0, 0, -minVisibleArea.width(), -minVisibleArea.height());
         break;
     case Gravity::Right:
     case Gravity::TopRight:
     case Gravity::BottomRight:
         initialRect.setLeft(std::max(initialRect.left(), geometry.left()));
         initialRect.setBottom(std::min(initialRect.bottom(), geometry.bottom()));
-        initialRect.adjust(minWidth, 0, 0, -minHeight);
+        initialRect.adjust(minVisibleArea.width(), 0, 0, -minVisibleArea.height());
         break;
     default:
         Q_UNREACHABLE();
@@ -1329,20 +1338,20 @@ static RegionF interactiveMoveResizeVisibleSubrectRegion(const RectF &geometry,
     case Gravity::TopLeft:
     case Gravity::BottomLeft:
         for (const RectF &rect : struts) {
-            availableRegion -= rect.adjusted(-minWidth, -minHeight, 0, 0);
+            availableRegion -= rect.adjusted(-minVisibleArea.width(), -minVisibleArea.height(), 0, 0);
         }
         for (const RectF &rect : offscreenArea.rects()) {
-            availableRegion -= rect.adjusted(-minWidth, -minHeight, 0, 0);
+            availableRegion -= rect.adjusted(-minVisibleArea.width(), -minVisibleArea.height(), 0, 0);
         }
         break;
     case Gravity::Right:
     case Gravity::TopRight:
     case Gravity::BottomRight:
         for (const RectF &rect : struts) {
-            availableRegion -= rect.adjusted(0, -minHeight, minWidth, 0);
+            availableRegion -= rect.adjusted(0, -minVisibleArea.height(), minVisibleArea.width(), 0);
         }
         for (const RectF &rect : offscreenArea.rects()) {
-            availableRegion -= rect.adjusted(0, -minHeight, minWidth, 0);
+            availableRegion -= rect.adjusted(0, -minVisibleArea.height(), minVisibleArea.width(), 0);
         }
         break;
     default:
@@ -1357,19 +1366,21 @@ static RegionF interactiveMoveResizeVisibleSubrectRegion(const RectF &geometry,
  *
  * See doc/moveresizerestriction for more details on algorithm.
  */
-static std::optional<QPointF> confineInteractiveMove(const RectF &geometry, int minVisibleWidth, int minVisibleHeight)
+static std::optional<QPointF> confineInteractiveMove(const RectF &geometry, const QSizeF &minVisibleArea)
 {
     std::optional<QPointF> candidate;
     qreal bestScore;
 
-    minVisibleWidth = std::min(std::floor(geometry.width()), qreal(minVisibleWidth));
+    const QSizeF effectiveMinVisibleArea(std::min(geometry.width(), minVisibleArea.width()),
+                                         std::min(geometry.height(), minVisibleArea.height()));
 
-    const RegionF visibleSubrectRegion = interactiveMoveResizeVisibleSubrectRegion(geometry, Gravity::None, minVisibleWidth, minVisibleHeight);
+    const RegionF visibleSubrectRegion = interactiveMoveResizeVisibleSubrectRegion(geometry, Gravity::None, effectiveMinVisibleArea);
     const QPointF anchor = geometry.topLeft();
     for (RectF rect : visibleSubrectRegion.rects()) {
-        // convert visibleSubrect top left to window top left
-        // Allow the window to be moved "geometry.width() - minVisibleWidth" pixels offscreen to the left
-        rect.setLeft(rect.left() - geometry.width() + minVisibleWidth);
+        // Extend the left edge of the rect so the right edge of the window can be
+        // effectiveMinVisibleArea.width() away from the left edge of the work area.
+        rect.setLeft(rect.left() - geometry.width() + effectiveMinVisibleArea.width());
+
         const QPointF closest(std::clamp(anchor.x(), rect.left(), rect.right()),
                               std::clamp(anchor.y(), rect.top(), rect.bottom()));
         const qreal score = QLineF(anchor, closest).length();
@@ -1392,22 +1403,23 @@ static std::optional<QPointF> confineInteractiveMove(const RectF &geometry, int
  *
  * See doc/moveresizerestriction for more details on algorithm.
  */
-std::optional<QPointF> Window::confineInteractiveResize(const RectF &geometry, Gravity gravity, int minVisibleWidth, int minVisibleHeight) const
+std::optional<QPointF> Window::confineInteractiveResize(const RectF &geometry, Gravity gravity, const QSizeF &minVisibleArea) const
 {
     if (gravity == Gravity::Bottom) {
         QPointF candidate = geometry.bottomLeft();
-        if (geometry.height() < minVisibleHeight) {
-            candidate.setY(geometry.top() + minVisibleHeight);
+        if (geometry.height() < minVisibleArea.height()) {
+            candidate.setY(geometry.top() + minVisibleArea.height());
         }
         return candidate;
     }
 
+    QSizeF effectiveMinVisibleArea = minVisibleArea;
     if (gravity == Gravity::Top) {
         // only in this case is the width of the window fixed during resize
-        minVisibleWidth = std::min(std::floor(geometry.width()), qreal(minVisibleWidth));
+        effectiveMinVisibleArea.rwidth() = std::min(geometry.width(), effectiveMinVisibleArea.width());
     }
 
-    const RegionF visibleSubrectRegion = interactiveMoveResizeVisibleSubrectRegion(geometry, gravity, minVisibleWidth, minVisibleHeight);
+    const RegionF visibleSubrectRegion = interactiveMoveResizeVisibleSubrectRegion(geometry, gravity, effectiveMinVisibleArea);
     QPointF anchor;
     switch (gravity) {
     case Gravity::Top:
@@ -1438,7 +1450,7 @@ std::optional<QPointF> Window::confineInteractiveResize(const RectF &geometry, G
         case Gravity::Top:
             // Resizing from the top is handled like moving the window to avoid zero width
             // rectangles when window width is equal to minVisibleWidth.
-            constrainedRect.setLeft(rect.left() - geometry.width() + minVisibleWidth);
+            constrainedRect.setLeft(rect.left() - geometry.width() + effectiveMinVisibleArea.width());
             break;
 
         case Gravity::Left:
@@ -1653,7 +1665,7 @@ RectF Window::nextInteractiveResizeGeometry(const QPointF &global) const
     }
 
     if (!isUnrestrictedInteractiveMoveResize()) {
-        if (const auto anchor = confineInteractiveResize(nextMoveResizeGeom, gravity, 100, titlebarThickness())) {
+        if (const auto anchor = confineInteractiveResize(nextMoveResizeGeom, gravity, minVisibleArea())) {
             switch (gravity) {
             case Gravity::TopLeft:
                 nextMoveResizeGeom.setTopLeft(*anchor);
@@ -1696,7 +1708,7 @@ RectF Window::nextInteractiveMoveGeometry(const RectF &rect) const
     nextMoveResizeGeom.moveTopLeft(workspace()->adjustWindowPosition(this, nextMoveResizeGeom.topLeft(), isUnrestrictedInteractiveMoveResize()));
 
     if (!isUnrestrictedInteractiveMoveResize()) {
-        if (const auto anchor = confineInteractiveMove(nextMoveResizeGeom, 100, titlebarThickness())) {
+        if (const auto anchor = confineInteractiveMove(nextMoveResizeGeom, minVisibleArea())) {
             nextMoveResizeGeom.moveTopLeft(anchor.value());
         }
     }
diff --git a/src/window.h b/src/window.h
index ea24507a4e0..8ab31081e8f 100644
--- a/src/window.h
+++ b/src/window.h
@@ -1742,10 +1742,10 @@ protected:
      * method to perform windowing system specific syncing.
      */
     virtual void doInteractiveResizeSync(const RectF &rect);
-    qreal titlebarThickness() const;
+    QSizeF minVisibleArea() const;
     RectF nextInteractiveMoveGeometry(const RectF &rect) const;
     RectF nextInteractiveResizeGeometry(const QPointF &global) const;
-    std::optional<QPointF> confineInteractiveResize(const RectF &geometry, Gravity gravity, int minVisibleWidth, int minVisibleHeight) const;
+    std::optional<QPointF> confineInteractiveResize(const RectF &geometry, Gravity gravity, const QSizeF &minVisibleArea) const;
     void dontInteractiveMoveResize();
 
     virtual QSizeF resizeIncrements() const;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.