diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c index a9241e95..88e33788 100644 --- a/WPrefs.app/KeyboardShortcuts.c +++ b/WPrefs.app/KeyboardShortcuts.c @@ -148,6 +148,10 @@ static const struct { { "WindowShortcut9Key", N_("Shortcut for window 9") }, { "WindowShortcut10Key", N_("Shortcut for window 10") }, + /* Head Selection */ + { "MoveTo12to6Head", N_("Move to right/bottom/left/top head") }, + { "MoveTo6to12Head", N_("Move to left/top/right/bottom head") }, + /* Misc. */ { "WindowRelaunchKey", N_("Launch new instance of application") }, { "ScreenSwitchKey", N_("Switch to Next Screen/Monitor") }, diff --git a/src/actions.c b/src/actions.c index 337c2ab9..7e465e0c 100644 --- a/src/actions.c +++ b/src/actions.c @@ -669,6 +669,91 @@ void handleMaximize(WWindow *wwin, int directions) } } +/* Moving window between heads + * + * Window is moved between all avaiable heads for current screen in + * requested direction. + * + * If heads have different sizes, window position will be adjusted to be inside + * screen. Window will be unmaximized on move, so that it can be immediately be + * maximixed by another shortcut. + * + * + * direction = 0 means move clock-wise from 12h position to 6h + * (first try moving right, then bottom, then left, then up) + * direction = 1 means move clock-wise from 6h position to 12h + * (first try moving left, then up, then right, then bottom) + * + * + * As side effect this mean if you have 9 monitors - you will not be able to + * move window into central cell without mouse. + * + * For common cases with 1 or 2 extra monitors this should work just fine. + * + * */ + +void moveBetweenHeads(WWindow *wwin, int direction) +{ + int head = wGetHeadForWindow(wwin); + int destHead = -1; + + unsigned int new_width, new_height; + int offsetX, newX = 0; + int offsetY, newY = 0; + WArea totalArea, oldHeadArea, destHeadArea; + WScreen *scr = wwin->screen_ptr; + + int try_movements[2][4] = { + {DIRECTION_RIGHT, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_UP}, + {DIRECTION_LEFT, DIRECTION_UP, DIRECTION_RIGHT, DIRECTION_DOWN} + }; + + /* loop through directions array and try movements until one works */ + for (int try_movement_idx = 0; + destHead == -1 && try_movement_idx < 4; try_movement_idx++) { + destHead = wGetHeadRelativeToCurrentHead(wwin->screen_ptr, + head, try_movements[direction][try_movement_idx]); + } + + if (destHead != -1) { + totalArea.x1 = 0; + totalArea.y1 = 0; + totalArea.x2 = scr->scr_width; + totalArea.y2 = scr->scr_height; + + oldHeadArea = wGetUsableAreaForHead(scr, head, &totalArea, True); + destHeadArea = wGetUsableAreaForHead(scr, destHead, &totalArea, True); + + offsetX = wwin->frame_x - oldHeadArea.x1; + offsetY = wwin->frame_y - oldHeadArea.y1; + + newX = destHeadArea.x1 + offsetX; + newY = destHeadArea.y1 + offsetY; + + new_width = wwin->client.width; + new_height = wwin->client.height; + + /* try to brind window inside head coordinates */ + if (newX > destHeadArea.x2) + newX = destHeadArea.x2 - wwin->client.width; + + if (newX < destHeadArea.x1) + newX = destHeadArea.x1; + + if (newY > destHeadArea.y2) + newY = destHeadArea.y2 - wwin->client.height; + + if (newY < destHeadArea.y1) + newY = destHeadArea.y1; + + /* unset maximization state */ + wwin->flags.maximized = 0; + wWindowConfigure(wwin, newX, newY, new_width, new_height); + } + + return; +} + /* the window boundary coordinates */ typedef struct { int left; diff --git a/src/defaults.c b/src/defaults.c index 7aee170b..23a0cff9 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -770,6 +770,10 @@ WDefaultEntry optionList[] = { NULL, getKeybind, setKeyGrab, NULL, NULL}, {"WindowShortcut10Key", "None", (void *)WKBD_WINDOW10, NULL, getKeybind, setKeyGrab, NULL, NULL}, + {"MoveTo12to6Head", "None", (void *)WKBD_MOVE_12_TO_6_HEAD, + NULL, getKeybind, setKeyGrab, NULL, NULL}, + {"MoveTo6to12Head", "None", (void *)WKBD_MOVE_6_TO_12_HEAD, + NULL, getKeybind, setKeyGrab, NULL, NULL}, {"WindowRelaunchKey", "None", (void *)WKBD_RELAUNCH, NULL, getKeybind, setKeyGrab, NULL, NULL}, {"ScreenSwitchKey", "None", (void *)WKBD_SWITCH_SCREEN, diff --git a/src/event.c b/src/event.c index 440cc95f..39bf5507 100644 --- a/src/event.c +++ b/src/event.c @@ -1802,6 +1802,13 @@ static void handleKeyPress(XEvent * event) break; + case WKBD_MOVE_12_TO_6_HEAD: + case WKBD_MOVE_6_TO_12_HEAD: + if (wwin) + moveBetweenHeads(wwin, command - WKBD_MOVE_12_TO_6_HEAD); + + break; + case WKBD_RELAUNCH: if (ISMAPPED(wwin) && ISFOCUSED(wwin)) (void) RelaunchWindow(wwin); diff --git a/src/keybind.h b/src/keybind.h index 214fd913..fe8d4c95 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -132,6 +132,10 @@ enum { WKBD_WINDOW9, WKBD_WINDOW10, + /* shortcuts to move window between heads */ + WKBD_MOVE_12_TO_6_HEAD, + WKBD_MOVE_6_TO_12_HEAD, + /* launch a new instance of the active window */ WKBD_RELAUNCH,