From a2c6d7f29c29f3eb8b7cee1dcb228fb0d565efdd Mon Sep 17 00:00:00 2001
From: Jannis Pohlmann <jannis@xfce.org>
Date: Sun, 6 Sep 2009 18:39:14 +0200
Subject: [PATCH] Snap with respect to the window spacing when resizing
 windows.

When resizing, snap to windows and struts by taking the new window
spacing option into account.

When snapping to a window, snap with a distance of window spacing to
the other window's edge if we're approaching this edge from outside
(e.g. window A is placed left of window B, window A is enlarged and the
right edge of window A snaps to the left edge of window B minus the
spacing). If we're approaching a window edge from inside, snap to this
edge without spacing (e.g. window A is placed inside window B, window A
is enlarged an the right edge of window A snaps to the right edge of
window B).

When snapping to struts, allow both snapping directly to the edges and
snapping with spacing.
---
 src/moveresize.c | 178 +++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 158 insertions(+), 20 deletions(-)

diff --git a/src/moveresize.c b/src/moveresize.c
index f96087e09..a4c0a1f05 100644
--- a/src/moveresize.c
+++ b/src/moveresize.c
@@ -387,36 +387,105 @@ clientFindClosestEdgeX (Client *c, int edge_pos)
        
     Client *c2;
     ScreenInfo *screen_info;
-    int i, closest;
-    int snap_width;
+    int i, closest, snap_width, left_margin, right_margin;
+    gboolean is_visible, is_snap_window, is_snap_strut;
 
     screen_info = c->screen_info;
     snap_width = screen_info->params->snap_width;
     closest = edge_pos + snap_width + 2; /* This only needs to be out of the snap range to work. -Cliff */
     
+    /* iterate over all client windows */
     for (c2 = screen_info->clients, i = 0; i < screen_info->client_count; c2 = c2->next, i++)
     {
-        if (FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE)  && (c2 != c) &&
-            (((screen_info->params->snap_to_windows) && (c2->win_layer == c->win_layer))
-             || ((screen_info->params->snap_to_border)
-                  && FLAG_TEST (c2->flags, CLIENT_FLAG_HAS_STRUT)
-                  && FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE))))  
+        /* skip the parameter client itself */
+        if (c2 == c)
+        {
+            continue;
+        }
+
+        /* check if the client is visible */
+        is_visible = FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE);
+
+        /* check if this is a window we can snap to (if window snapping is enabled) */
+        is_snap_window = is_visible && screen_info->params->snap_to_windows && (c2->win_layer == c->win_layer);
+
+        /* check if this a strut we can snap to (if snapping to the screen edges is enabled) */
+        is_snap_strut = is_visible && screen_info->params->snap_to_border && FLAG_TEST (c2->flags, CLIENT_FLAG_HAS_STRUT);
+
+        /* calculate margins */
+        if (is_snap_window)
         {
-        
+            left_margin = right_margin = screen_info->params->window_spacing;
+        }
+        else if (is_snap_strut)
+        {
+            left_margin = screen_info->params->xfwm_margins[STRUTS_RIGHT];
+            right_margin = screen_info->params->xfwm_margins[STRUTS_LEFT];
+        }
+
+        /* check if this client is something we can snap to */
+        if (is_snap_window || is_snap_strut)
+        {
+            /* check if the two clients overlap vertically */
             if (clientCheckOverlap (c->y - frameTop (c) - 1, c->y + c->height + frameBottom (c) + 1, c2->y - frameTop (c) - 1, c2->y + c2->height + frameBottom (c) + 1))
             {
+                /* check if we are closer to the left edge of c2 than to any previous edge */
                 if (abs (c2->x - frameLeft (c2) - edge_pos) < abs (closest - edge_pos))
                 {
+                    /* snap directly to the edge */
                     closest = c2->x - frameLeft (c2);
                 }
-                if (abs ((c2->x + c2->width) + frameRight (c2) - edge_pos) < abs (closest - edge_pos))
+                
+                if (abs (c2->x - frameLeft (c2) - left_margin - edge_pos) < (closest - edge_pos))
                 {
-                    closest = (c2->x + c2->width) + frameRight (c2);
+                    /* we're approaching the edge from the left. snap to the edge from the left, with a certain space between the two clients */
+                    closest = c2->x - frameLeft (c2) - left_margin;
+                }
+                
+                if (abs (c2->x - frameLeft (c2) + left_margin - edge_pos) < (closest - edge_pos))
+                {
+                    if (is_snap_window) 
+                    {
+                        /* we're approaching the edge from the right. snap to the edge directly */
+                        closest = c2->x - frameLeft (c2);
+                    }
+                    else
+                    {
+                        /* we're approaching the edge from the right. snap to the edge from the right, with a certain space between the two clients */
+                        closest = c2->x - frameLeft (c2) + left_margin;
+                    }
+                }
+
+                /* check if we are closer to the right edge of c2 than to any previous edge */
+                if (abs (c2->x + c2->width + frameRight (c2) - edge_pos) < abs (closest - edge_pos))
+                {
+                    /* snap directly to the edge */
+                    closest = c2->x + c2->width + frameRight (c2);
+                }
+                
+                if (abs (c2->x + c2->width + frameRight (c2) - right_margin - edge_pos) < (closest - edge_pos))
+                {
+                    if (is_snap_window)
+                    {
+                        /* we're approaching the edge from the left. snap to directly to the edge */
+                        closest = c2->x + c2->width + frameRight (c2);
+                    }
+                    else
+                    {
+                        /* we're approaching the edge from the left. snap to the edge from the left, with a certain space between the two clients */
+                        closest = c2->x + c2->width + frameRight (c2) - right_margin;
+                    }
+                }
+
+                if (abs (c2->x + c2->width + frameRight (c2) + right_margin - edge_pos) < (closest - edge_pos))
+                {
+                    /* we're approaching the edge from the right. snap to the edge from the right, with a certain space between the two clients */
+                    closest = c2->x + c2->width + frameRight (c2) + right_margin;
                 }
             }            
         }
     }
-    
+
     if (abs (closest - edge_pos) > snap_width)
     {
         closest = edge_pos;
@@ -434,31 +503,100 @@ clientFindClosestEdgeY (Client *c, int edge_pos)
        
     Client *c2;
     ScreenInfo *screen_info;
-    int i, closest;
-    int snap_width;
+    int i, closest, snap_width, top_margin, bottom_margin;
+    gboolean is_visible, is_snap_window, is_snap_strut;
 
     screen_info = c->screen_info;
     snap_width = screen_info->params->snap_width;
     closest = edge_pos + snap_width + 1; /* This only needs to be out of the snap range to work. -Cliff */
     
+    /* iterate over all client windows */
     for (c2 = screen_info->clients, i = 0; i < screen_info->client_count; c2 = c2->next, i++)
     {
-        if (FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE)  && (c2 != c) &&
-            (((screen_info->params->snap_to_windows) && (c2->win_layer == c->win_layer))
-             || ((screen_info->params->snap_to_border)
-                  && FLAG_TEST (c2->flags, CLIENT_FLAG_HAS_STRUT)
-                  && FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE))))  
+        /* skip the parameter client itself */
+        if (c2 == c)
         {
+            continue;
+        }
+
+        /* check if the client is visible */
+        is_visible = FLAG_TEST (c2->xfwm_flags, XFWM_FLAG_VISIBLE);
+
+        /* check if this is a window we can snap to (if window snapping is enabled) */
+        is_snap_window = is_visible && screen_info->params->snap_to_windows && (c2->win_layer == c->win_layer);
 
+        /* check if this a strut we can snap to (if snapping to the screen edges is enabled) */
+        is_snap_strut = is_visible && screen_info->params->snap_to_border && FLAG_TEST (c2->flags, CLIENT_FLAG_HAS_STRUT);
+
+        /* calculate margins */
+        if (is_snap_window)
+        {
+            top_margin = bottom_margin = screen_info->params->window_spacing;
+        }
+        else if (is_snap_strut)
+        {
+            top_margin = screen_info->params->xfwm_margins[STRUTS_BOTTOM];
+            bottom_margin = screen_info->params->xfwm_margins[STRUTS_TOP];
+        }
+
+        /* check if this client is something we can snap to */
+        if (is_snap_window || is_snap_strut)
+        {
+            /* check if the two clients overlap horizontally */
             if (clientCheckOverlap (c->x - frameLeft (c) - 1, c->x + c->width + frameRight (c) + 1, c2->x - frameLeft (c) - 1, c2->x + c2->width + frameRight (c) + 1))
             {
+                /* check if we are closer to the top edge of c2 than to any previous edge */
                 if (abs (c2->y - frameTop(c2) - edge_pos) < abs (closest - edge_pos))
                 {
+                    /* snap directly to the edge */
                     closest = c2->y - frameTop (c2);
                 }
-                if (abs ((c2->y + c2->height) + frameBottom (c2) - edge_pos) < abs (closest - edge_pos))
+
+                if (abs (c2->y - frameTop (c2) - top_margin - edge_pos) < abs (closest - edge_pos))
+                {
+                    /* we're approaching the edge from the top. snap to the edge from the top, with a certain space between the two clients */
+                    closest = c2->y - frameTop (c2) - top_margin;
+                }
+
+                if (abs (c2->y - frameTop (c2) + top_margin - edge_pos) < abs (closest - edge_pos))
+                {
+                    if (is_snap_window)
+                    {
+                        /* we're approaching the edge from the bottom. snap directly to the edge */
+                        closest = c2->y - frameTop (c2);
+                    }
+                    else
+                    {
+                        /* we're approaching the edge from the bottom. snap to the edge from the bottom, with a certain space between the two clients */
+                        closest = c2->y - frameTop (c2) + top_margin;
+                    }
+                }
+
+                /* check if we are closer to the bottom edge of c2 than to any previous edge */
+                if (abs (c2->y + c2->height + frameBottom (c2) - edge_pos) < abs (closest - edge_pos))
+                {
+                    /* snap directly to the edge */
+                    closest = c2->y + c2->height + frameBottom (c2);
+                }
+                
+                if (abs (c2->y + c2->height + frameBottom (c2) - bottom_margin - edge_pos) < (closest - edge_pos))
+                {
+                    if (is_snap_window)
+                    {
+                        /* we're approaching the edge from the top. snap directly to the edge */
+                        closest = c2->y + c2->height + frameBottom (c2);
+                    }
+                    else
+                    {
+                        /* we're approaching the edge from the top. snap to the edge from the top, with a certain space between the two clients */
+                        closest = c2->y + c2->height + frameBottom (c2) - bottom_margin;
+                    }
+                }
+                
+                if (abs (c2->y + c2->height + frameBottom (c2) + bottom_margin - edge_pos) < (closest - edge_pos))
                 {
-                    closest = (c2->y + c2->height) + frameBottom (c2);
+                    /* snap to the edge from the bottom, with a certain space between the two clients */
+                    closest = c2->y + c2->height + frameBottom (c2) + bottom_margin;
                 }
             }            
         }
-- 
GitLab