Bug 45805

Summary: Windows do not snap on resize
Product: [Plasma] kwin Reporter: jwbroek
Component: generalAssignee: Lubos Lunak <l.lunak>
Status: RESOLVED FIXED    
Severity: wishlist    
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: Slackware   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: Implementation of requested snapping functions against KDE CVS
Correct patch for snap on resize

Description a 2002-07-26 19:17:47 UTC
(*** This bug was imported into bugs.kde.org ***)

Package:           kwin
Version:           KDE 3.0.1 
Severity:          wishlist
Installed from:    Slackware Packages
Compiler:          Not Specified
OS:                Linux
OS/Compiler notes: Slackware 8.1

When I move a window it will snap to other windows or sides of the screen. But when I resize a window I think it should do the same with the resized edge.

(Submitted via bugs.kde.org)
Comment 1 Lubos Lunak 2002-10-03 11:26:46 UTC
*** Bug 45687 has been marked as a duplicate of this bug. ***
Comment 2 Cle 2004-03-14 09:04:35 UTC
i'm using kde 3.2.1 and the feature is not implemented yet. would be nice to see it in 3.3 (or even earlier)!
Comment 3 Lubos Lunak 2004-04-05 11:55:39 UTC
*** Bug 78982 has been marked as a duplicate of this bug. ***
Comment 4 Stephan Kulow 2004-05-25 09:24:21 UTC
Replaced a@b.c with jwbroek@students.cs.uu.nl due to bounces by reporter
Comment 5 Christopher Suleski 2004-06-02 01:05:27 UTC
Created attachment 6221 [details]
Implementation of requested snapping functions against KDE CVS

Here is a patch to implement this functionality.
Comment 6 Christopher Suleski 2004-06-02 01:10:46 UTC
Comment on attachment 6221 [details]
Implementation of requested snapping functions against KDE CVS

>--- kdebase/kwin/workspace.h	2004-05-29 16:52:31.000000000 -0400
>+++ kdebase.snapresize/kwin/workspace.h	2004-06-01 18:22:16.316586256 -0400
>@@ -129,6 +129,7 @@
>         void placeSmart( Client* c, const QRect& area );
> 
>         QPoint adjustClientPosition( Client* c, QPoint pos );
>+        QRect adjustClientSize( Client* c, QRect moveResizeGeom, int mode );
>         void raiseClient( Client* c );
>         void lowerClient( Client* c );
>         void raiseClientRequest( Client* c, NET::RequestSource src, Time timestamp );
>--- kdebase/kwin/geometry.cpp	2004-05-29 16:52:01.000000000 -0400
>+++ kdebase-snapresize/kwin/geometry.cpp	2004-06-01 18:32:21.891524872 -0400
>@@ -372,6 +372,202 @@
>     return pos;
>     }
> 
>+QRect Workspace::adjustClientSize( Client* c, QRect moveResizeGeom, int mode )
>+    {
>+   //adapted from adjustClientPosition on 29May2004
>+   //this function is called when resizing a window and will modify
>+   //the new dimensions to snap to other windows/borders if appropriate
>+    if ( options->windowSnapZone || options->borderSnapZone  )
>+        {
>+        bool sOWO=options->snapOnlyWhenOverlapping;
>+        
>+        QRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop());
>+        int xmin = maxRect.left();
>+        int xmax = maxRect.right()+1;               //desk size
>+        int ymin = maxRect.top();
>+        int ymax = maxRect.bottom()+1;
>+
>+        int cx(moveResizeGeom.left());
>+        int cy(moveResizeGeom.top());
>+        int rx(moveResizeGeom.right());
>+        int ry(moveResizeGeom.bottom());
>+
>+        int newcx(cx), newcy(cy);                         //buffers
>+        int newrx(rx), newry(ry); 
>+        int deltaX(xmax);
>+        int deltaY(ymax);   //minimum distance to other clients
>+
>+        int lx, ly, lrx, lry; //coords and size for the comparison client, l
>+
>+      // border snap
>+        int snap = options->borderSnapZone; //snap trigger
>+        if (snap)
>+            {
>+            deltaX = int(snap);
>+            deltaY = int(snap);
>+                        
>+#define SNAP_BORDER_TOP \
>+            if ((sOWO?(newcy<ymin):true) && (QABS(ymin-newcy)<deltaY)) \
>+              { \
>+                deltaY = QABS(ymin-newcy); \
>+                newcy = ymin; \
>+               }
>+               
>+#define SNAP_BORDER_BOTTOM \
>+            if ((sOWO?(newry>ymax):true) && (QABS(ymax-newry)<deltaY)) \
>+              { \
>+                deltaY = QABS(ymax-newcy); \
>+                newry = ymax; \
>+               }
>+               
>+#define SNAP_BORDER_LEFT \
>+            if ((sOWO?(newcx<xmin):true) && (QABS(xmin-newcx)<deltaX)) \
>+              { \
>+                deltaX = QABS(xmin-newcx); \
>+                newcx = xmin; \
>+               }
>+               
>+#define SNAP_BORDER_RIGHT \
>+            if ((sOWO?(newrx>xmax):true) && (QABS(xmax-newrx)<deltaX)) \
>+              { \
>+                deltaX = QABS(xmax-newrx); \
>+                newrx = xmax; \
>+               }
>+                     switch ( mode )
>+                      {
>+                      case PositionBottomRight:
>+                        SNAP_BORDER_BOTTOM
>+                        SNAP_BORDER_RIGHT
>+                        break;
>+                      case PositionRight:
>+                        SNAP_BORDER_RIGHT
>+                        break;
>+                      case PositionBottom:
>+                        SNAP_BORDER_BOTTOM
>+                        break;
>+                      case PositionTopLeft:
>+                        SNAP_BORDER_TOP
>+                        SNAP_BORDER_LEFT
>+                        break;
>+                      case PositionLeft:
>+                        SNAP_BORDER_LEFT
>+                        break;
>+                      case PositionTop:
>+                        SNAP_BORDER_TOP
>+                        break;
>+                      case PositionTopRight:
>+                        SNAP_BORDER_TOP
>+                        SNAP_BORDER_RIGHT
>+                        break;
>+                      case PositionBottomLeft:
>+                        SNAP_BORDER_BOTTOM
>+                        SNAP_BORDER_LEFT
>+                        break;
>+                      default:
>+                        assert( false );
>+                        break;
>+                      }
>+               
>+     
>+            }
>+        
>+      // windows snap
>+        snap = options->windowSnapZone;
>+        if (snap)
>+            {
>+            deltaX = int(snap);
>+            deltaY = int(snap);
>+            QValueList<Client *>::ConstIterator l;
>+            for (l = clients.begin();l != clients.end();++l )
>+                {
>+                if ((*l)->isOnDesktop(currentDesktop()) &&
>+                   !(*l)->isMinimized()
>+                    && (*l) != c )
>+                    {
>+                    lx = (*l)->x();
>+                    ly = (*l)->y();
>+                    lrx = lx + (*l)->width();
>+                    lry = ly + (*l)->height();
>+
>+#define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy  >= ly  ))  || \
>+                         (( newry >= ly  ) && ( newry  <= lry ))  || \
>+                         (( newcy <= ly  ) && ( newry >= lry  )) )
>+
>+#define WITHIN_WIDTH  ( (( cx <= lrx ) && ( cx  >= lx  ))  || \
>+                         (( rx >= lx  ) && ( rx  <= lrx ))  || \
>+                         (( cx <= lx  ) && ( rx >= lrx  )) )
>+
>+#define SNAP_WINDOW_TOP  if ( (sOWO?(newcy<lry):true) \
>+                  && WITHIN_WIDTH  \
>+                  && (QABS( lry - newcy ) < deltaY) ) {  \
>+                  deltaY = QABS( lry - newcy ); \
>+                  newcy=lry; \
>+                  }
>+                  
>+#define SNAP_WINDOW_BOTTOM  if ( (sOWO?(newry>ly):true)  \
>+                     && WITHIN_WIDTH  \
>+                     && (QABS( ly - newry ) < deltaY) ) {  \
>+                     deltaY = QABS( ly - newry );  \
>+                     newry=ly;  \
>+                     }
>+
>+#define SNAP_WINDOW_LEFT  if ( (sOWO?(newcx<lrx):true)  \
>+                   && WITHIN_HEIGHT  \
>+                   && (QABS( lrx - newcx ) < deltaX)) {  \
>+                   deltaX = QABS( lrx - newcx );  \
>+                   newcx=lrx;  \
>+                   }
>+
>+#define SNAP_WINDOW_RIGHT  if ( (sOWO?(newrx>lx):true)  \
>+                    && WITHIN_HEIGHT  \
>+                    && (QABS( lx - newrx ) < deltaX))  \
>+                    {  \
>+                    deltaX = QABS( lx - newrx );  \
>+                    newrx=lx;  \
>+                    }
>+                    
>+                    switch ( mode )
>+                      {
>+                      case PositionBottomRight:
>+                        SNAP_WINDOW_BOTTOM
>+                        SNAP_WINDOW_RIGHT
>+                        break;
>+                      case PositionRight:
>+                        SNAP_WINDOW_RIGHT
>+                        break;
>+                      case PositionBottom:
>+                        SNAP_WINDOW_BOTTOM
>+                        break;
>+                      case PositionTopLeft:
>+                        SNAP_WINDOW_TOP
>+                        SNAP_WINDOW_LEFT
>+                        break;
>+                      case PositionLeft:
>+                        SNAP_WINDOW_LEFT
>+                        break;
>+                      case PositionTop:
>+                        SNAP_WINDOW_TOP
>+                        break;
>+                      case PositionTopRight:
>+                        SNAP_WINDOW_TOP
>+                        SNAP_WINDOW_RIGHT
>+                        break;
>+                      case PositionBottomLeft:
>+                        SNAP_WINDOW_BOTTOM
>+                        SNAP_WINDOW_LEFT
>+                        break;
>+                      default:
>+                        assert( false );
>+                        break;
>+                      }
>+                    }
>+                }
>+            }
>+       moveResizeGeom = QRect(QPoint(newcx, newcy), QPoint(newrx, newry));
>+       } 
>+    return moveResizeGeom;
>+    }
>+    
> /*!
>   Marks the client as being moved around by the user.
>  */
>@@ -1935,6 +2131,9 @@
>             moveResizeGeom.setLeft(desktopArea.right() - right_marge );
>         if( !unrestrictedMoveResize && moveResizeGeom.top() < desktopArea.top() ) // titlebar mustn't go out
>             moveResizeGeom.setTop( desktopArea.top());
>+            
>+        // adjust new size to snap to other windows/borders
>+        moveResizeGeom = workspace()->adjustClientSize( this, moveResizeGeom, mode );
> 
>         QSize size = adjustedSize( moveResizeGeom.size(), sizemode );
>         // the new topleft and bottomright corners (after checking size constrains), if they'll be needed
Comment 7 Christopher Suleski 2004-06-02 01:16:17 UTC
Created attachment 6222 [details]
Correct patch for snap on resize

Sorry I am making a mess of this bug report ;-)
Here is the correct patch, my earlier one mistakenly called SNAP_WINDOW_RIGHT
instead of SNAP_WINDOW_LEFT in the second switch's PositionBottomLeft case.
This should work fine.
Comment 8 Cristian Tibirna 2004-06-02 02:37:03 UTC
Very nice patch Christopher. Didn't test it yet but I intend to, ASAP. One over the hand observation: make a more aggressive use of const, so that compiler gets a chance to optimize code (optimization is important, as it's in a critical path): maxRect, sOWO, xmin, xmax, ymin, ymax, cx, cy, rx, ry can all be const-ed.
Comment 9 Lubos Lunak 2004-06-02 10:04:06 UTC
Patch seems to work for me. I'll leave reviewing of the adjustClientSize() function to you Cristian :). One small note: I think the call to adjustedClientSize() should be few lines higher, there's a 'TODO snap' note.
Comment 10 Cristian Tibirna 2004-06-03 14:37:03 UTC
CVS commit by tibirna: 

window and border snapping during resize operations.
Patch contributed by Christopher Suleski (linux from tildewave com): http://bugs.kde.org/show_bug.cgi?id=45805
Many thanks, Christopher.
Code inspected by Lubos Lunak.
Reviewed, slightly adapted and tested by me.
CCMAIL: 45805-done@bugs.kde.org


  M +213 -14   geometry.cpp   2.73
  M +1 -0      workspace.h   1.176



Comment 11 Dominik Haumann 2004-06-25 22:26:21 UTC
CVS commit by dhaumann: 

Fix: snap on resize snapped by 1px wrong on the right and bottom.
Now it works perfectly with all client windows including the desktop.
CCMAIL: 45805@bugs.kde.org


  M +6 -6      geometry.cpp   2.79


--- kdebase/kwin/geometry.cpp  #2.78:2.79
@@ -385,7 +385,7 @@ QRect Workspace::adjustClientSize( Clien
         const QRect maxRect = clientArea(MovementArea, c->rect().center(), c->desktop());
         const int xmin = maxRect.left();
-        const int xmax = maxRect.right()+1;               //desk size
+        const int xmax = maxRect.right();               //desk size
         const int ymin = maxRect.top();
-        const int ymax = maxRect.bottom()+1;
+        const int ymax = maxRect.bottom();
 
         const int cx(moveResizeGeom.left());
@@ -486,8 +486,8 @@ QRect Workspace::adjustClientSize( Clien
                     && (*l) != c )
                     {
-                    lx = (*l)->x();
-                    ly = (*l)->y();
-                    lrx = lx + (*l)->width();
-                    lry = ly + (*l)->height();
+                    lx = (*l)->x()-1;
+                    ly = (*l)->y()-1;
+                    lrx =(*l)->x() + (*l)->width();
+                    lry =(*l)->y() + (*l)->height();
 
 #define WITHIN_HEIGHT ((( newcy <= lry ) && ( newcy  >= ly  ))  || \