This patch adds the ability to "snap" a window to the top, bottom, or any of the
four corners of the screen.  It uses three new helper functions, drawSnapFrame,
getSnapDirection, and doSnap, to reduce code duplication and increase
readability.

It also updates NEWS to indicate the additional directions.
---
 NEWS          |   4 +-
 src/moveres.c | 196 ++++++++++++++++++++++++++++++++++++++++++----------------
 2 files changed, 145 insertions(+), 55 deletions(-)

diff --git a/NEWS b/NEWS
index 9cb1a3c..ea714a1 100644
--- a/NEWS
+++ b/NEWS
@@ -7,8 +7,8 @@ NEWS for veteran Window Maker users
 Window snapping
 ---------------
 
-You can now "snap" a window, i.e., maximize it to the left or right half of the
-screen, by dragging it to that side.  It is enabled by setting
+You can now "snap" a window, i.e., maximize it to a side or corner of the
+screen, by dragging it to that side or corner.  It is enabled by setting
 "WindowSnapping = YES" in ~/GNUstep/Defaults/WindowMaker or selecting "Enable
 window snapping" under "Expert User Preferences" in WPrefs.app.
 
diff --git a/src/moveres.c b/src/moveres.c
index 754f603..fb37148 100644
--- a/src/moveres.c
+++ b/src/moveres.c
@@ -589,7 +589,16 @@ typedef struct {
        int omouseX, omouseY;   /* old mouse position */
        int mouseX, mouseY;     /* last known position of the pointer */
 
-       enum {SNAP_NONE, SNAP_LEFT, SNAP_RIGHT} snap;
+       enum {SNAP_NONE,
+             SNAP_LEFT,
+             SNAP_RIGHT,
+             SNAP_TOP,
+             SNAP_BOTTOM,
+             SNAP_TOPLEFT,
+             SNAP_TOPRIGHT,
+             SNAP_BOTTOMLEFT,
+             SNAP_BOTTOMRIGHT
+       } snap;
 } MoveData;
 
 #define WTOP(w) (w)->frame_y
@@ -1188,6 +1197,118 @@ updateWindowPosition(WWindow * wwin, MoveData * data, 
Bool doResistance,
        data->realY = newY;
 }
 
+static void drawSnapFrame(WWindow *wwin, int direction)
+{
+       WScreen *scr;
+
+       scr = wwin->screen_ptr;
+
+       switch (direction) {
+       case SNAP_LEFT:
+               drawTransparentFrame(wwin, 0, 0, scr->scr_width/2, 
scr->scr_height);
+               break;
+
+       case SNAP_RIGHT:
+               drawTransparentFrame(wwin, scr->scr_width/2, 0, 
scr->scr_width/2, scr->scr_height);
+               break;
+
+       case SNAP_TOP:
+               drawTransparentFrame(wwin, 0, 0, scr->scr_width, 
scr->scr_height/2);
+               break;
+
+       case SNAP_BOTTOM:
+               drawTransparentFrame(wwin, 0, scr->scr_height/2, 
scr->scr_width, scr->scr_height/2);
+               break;
+
+       case SNAP_TOPLEFT:
+               drawTransparentFrame(wwin, 0, 0, scr->scr_width/2, 
scr->scr_height/2);
+               break;
+
+       case SNAP_TOPRIGHT:
+               drawTransparentFrame(wwin, scr->scr_width/2, 0, 
scr->scr_width/2, scr->scr_height/2);
+               break;
+
+       case SNAP_BOTTOMLEFT:
+               drawTransparentFrame(wwin, 0, scr->scr_height/2, 
scr->scr_width/2, scr->scr_height/2);
+               break;
+
+       case SNAP_BOTTOMRIGHT:
+               drawTransparentFrame(wwin, scr->scr_width/2, scr->scr_height/2,
+                                    scr->scr_width/2, scr->scr_height/2);
+               break;
+       }
+}
+
+static int getSnapDirection(WScreen *scr, int x, int y)
+{
+       if (x < 1) {
+               if (y < 1)
+                       return SNAP_TOPLEFT;
+               if (y > scr->scr_height - 2)
+                       return SNAP_BOTTOMLEFT;
+               return SNAP_LEFT;
+       }
+       if (x > scr->scr_width - 2) {
+               if (y < 1)
+                       return SNAP_TOPRIGHT;
+               if (y > scr->scr_height - 2)
+                       return SNAP_BOTTOMRIGHT;
+               return SNAP_RIGHT;
+       }
+       if (y < 1)
+               return SNAP_TOP;
+       if (y > scr->scr_height - 2)
+               return SNAP_BOTTOM;
+       return SNAP_NONE;
+}
+
+static void doSnap(WWindow *wwin, MoveData *data, Bool opaqueMove)
+{
+       int directions;
+       WScreen *scr;
+
+       directions = 0;
+       scr = wwin->screen_ptr;
+
+       /* erase frames */
+       if (!opaqueMove)
+               drawFrames(wwin, scr->selected_windows, data->realX - 
wwin->frame_x, data->realY - wwin->frame_y);
+       drawSnapFrame(wwin, data->snap);
+
+       switch (data->snap) {
+       case SNAP_NONE:
+               return;
+       case SNAP_LEFT:
+               directions = MAX_VERTICAL | MAX_LEFTHALF;
+               break;
+       case SNAP_RIGHT:
+               directions = MAX_VERTICAL | MAX_RIGHTHALF;
+               break;
+       case SNAP_TOP:
+               directions = MAX_HORIZONTAL | MAX_TOPHALF;
+               break;
+       case SNAP_BOTTOM:
+               directions = MAX_HORIZONTAL | MAX_BOTTOMHALF;
+               break;
+       case SNAP_TOPLEFT:
+               directions = MAX_TOPHALF | MAX_LEFTHALF;
+               break;
+       case SNAP_TOPRIGHT:
+               directions = MAX_TOPHALF | MAX_RIGHTHALF;
+               break;
+       case SNAP_BOTTOMLEFT:
+               directions = MAX_BOTTOMHALF | MAX_LEFTHALF;
+               break;
+       case SNAP_BOTTOMRIGHT:
+               directions = MAX_BOTTOMHALF | MAX_RIGHTHALF;
+               break;
+       }
+
+       if (directions)
+               handleMaximize(wwin, directions);
+       data->snap = SNAP_NONE;
+}
+
 #define _KS KEY_CONTROL_WINDOW_WEIGHT
 
 #define MOVABLE_BIT    0x01
@@ -1647,46 +1768,34 @@ int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
 
                case MotionNotify:
                        if (IS_RESIZABLE(wwin) && wPreferences.window_snapping 
&& wPreferences.no_autowrap) {
-                               if (moveData.snap == SNAP_LEFT && 
moveData.mouseX > 1) {
-                                       moveData.snap = SNAP_NONE;
-                                       drawTransparentFrame(wwin, 0, 0, 
scr->scr_width/2, scr->scr_height);
-                               }
-                               if (moveData.snap == SNAP_RIGHT && 
moveData.mouseX < scr->scr_width - 2) {
-                                       moveData.snap = SNAP_NONE;
-                                       drawTransparentFrame(wwin, 
scr->scr_width/2, 0, scr->scr_width/2,
-                                                            scr->scr_height);
-                               }
-                               if (moveData.snap == SNAP_NONE) {
-                                       if (moveData.mouseX <= 1) {
-                                               moveData.snap = SNAP_LEFT;
-                                               drawTransparentFrame(wwin, 0, 
0, scr->scr_width/2,
-                                                                    
scr->scr_height);
-                                       }
-                                       if (moveData.mouseX >= scr->scr_width - 
2) {
-                                               moveData.snap = SNAP_RIGHT;
-                                               drawTransparentFrame(wwin, 
scr->scr_width/2, 0, scr->scr_width/2,
-                                                                    
scr->scr_height);
-                                       }
+                               int snap_direction;
+
+                               snap_direction = getSnapDirection(scr, 
moveData.mouseX, moveData.mouseY);
+
+                               if (moveData.snap != snap_direction) {
+                                       /* erase old frame */
+                                       if (moveData.snap)
+                                               drawSnapFrame(wwin, 
moveData.snap);
+                                       /* draw new frame */
+                                       if (snap_direction)
+                                               drawSnapFrame(wwin, 
snap_direction);
+                                       moveData.snap = snap_direction;
                                }
                        }
 
                        if (started) {
-                               if (moveData.snap == SNAP_LEFT)
-                                       drawTransparentFrame(wwin, 0, 0, 
scr->scr_width/2, scr->scr_height);
-                               if (moveData.snap == SNAP_RIGHT)
-                                       drawTransparentFrame(wwin, 
scr->scr_width/2, 0, scr->scr_width/2,
-                                                            scr->scr_height);
+                               /* erase snap frame */
+                               if (moveData.snap)
+                                       drawSnapFrame(wwin, moveData.snap);
 
                                updateWindowPosition(wwin, &moveData,
                                                     scr->selected_windows == 
NULL
                                                     && 
wPreferences.edge_resistance > 0,
                                                     opaqueMove, 
event.xmotion.x_root, event.xmotion.y_root);
 
-                               if (moveData.snap == SNAP_LEFT)
-                                       drawTransparentFrame(wwin, 0, 0, 
scr->scr_width/2, scr->scr_height);
-                               if (moveData.snap == SNAP_RIGHT)
-                                       drawTransparentFrame(wwin, 
scr->scr_width/2, 0, scr->scr_width/2,
-                                                            scr->scr_height);
+                               /* redraw snap frame */
+                               if (moveData.snap)
+                                       drawSnapFrame(wwin, moveData.snap);
 
                                if (!warped && !wPreferences.no_autowrap) {
                                        int oldWorkspace = 
w_global.workspace.current;
@@ -1775,28 +1884,9 @@ int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
                        if (started) {
                                XEvent e;
 
-                               if (moveData.snap != SNAP_NONE) {
-                                       if (moveData.snap == SNAP_LEFT) {
-                                               /* erase frames */
-                                               if (!opaqueMove)
-                                                       drawFrames(wwin, 
scr->selected_windows,
-                                                                  
moveData.realX - wwin->frame_x,
-                                                                  
moveData.realY - wwin->frame_y);
-                                               drawTransparentFrame(wwin, 0, 
0, scr->scr_width/2, scr->scr_height);
-                                               handleMaximize(wwin, 
MAX_VERTICAL | MAX_LEFTHALF);
-                                       }
-                                       if (moveData.snap == SNAP_RIGHT) {
-                                               /* erase frames */
-                                               if (!opaqueMove)
-                                                       drawFrames(wwin, 
scr->selected_windows,
-                                                                  
moveData.realX - wwin->frame_x,
-                                                                  
moveData.realY - wwin->frame_y);
-                                               drawTransparentFrame(wwin, 
scr->scr_width/2, 0, scr->scr_width/2,
-                                                                    
scr->scr_height);
-                                               handleMaximize(wwin, 
MAX_VERTICAL | MAX_RIGHTHALF);
-                                       }
-                                       moveData.snap = SNAP_NONE;
-                               } else if (!opaqueMove) {
+                               if (moveData.snap)
+                                       doSnap(wwin, &moveData, opaqueMove);
+                               else if (!opaqueMove) {
                                        drawFrames(wwin, scr->selected_windows,
                                                   moveData.realX - 
wwin->frame_x, moveData.realY - wwin->frame_y);
                                        XSync(dpy, 0);
-- 
1.9.1


-- 
To unsubscribe, send mail to wmaker-dev-unsubscr...@lists.windowmaker.org.

Reply via email to