diff --git a/NEWS b/NEWS index ac03d901..889d019f 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 c77a1058..27f6ce1d 100644 --- a/src/moveres.c +++ b/src/moveres.c @@ -589,7 +589,17 @@ 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 +1198,118 @@ updateWindowPosition(WWindow * wwin, MoveData * data, Bool doResistance, data->realY = newY; } +static void draw_snap_frame(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 get_snap_direction(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 do_snap(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); + draw_snap_frame(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 +1769,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 = get_snap_direction(scr, moveData.mouseX, moveData.mouseY); + + if (moveData.snap != snap_direction) { + /* erase old frame */ + if (moveData.snap) + draw_snap_frame(wwin, moveData.snap); + /* draw new frame */ + if (snap_direction) + draw_snap_frame(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) + draw_snap_frame(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) + draw_snap_frame(wwin, moveData.snap); if (!warped && !wPreferences.no_autowrap) { int oldWorkspace = w_global.workspace.current; @@ -1773,30 +1883,12 @@ int wMouseMoveWindow(WWindow * wwin, XEvent * ev) if (event.xbutton.button != ev->xbutton.button) break; - 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 (started) { + if (started) { XEvent e; - if (!opaqueMove) { + + if (moveData.snap) + do_snap(wwin, &moveData, opaqueMove); + else if (!opaqueMove) { drawFrames(wwin, scr->selected_windows, moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y); XSync(dpy, 0);