diff --git a/src/actions.c b/src/actions.c index e3e2249b..f9b92577 100644 --- a/src/actions.c +++ b/src/actions.c @@ -60,6 +60,10 @@ extern WPreferences wPreferences; extern Atom _XA_WM_TAKE_FOCUS; extern void ProcessPendingEvents(); +extern int calcIntersectionLength(int p1, int l1, int p2, int l2); + +static void find_Maximus_geometry(WWindow *wwin, WArea usableArea, int *new_x, + int *new_y, int *new_width, int *new_height); /******* Local Variables *******/ static struct { @@ -326,7 +330,7 @@ void wMaximizeWindow(WWindow * wwin, int directions) wUnshadeWindow(wwin); } /* Only save directions, not kbd or xinerama hints */ - directions &= (MAX_HORIZONTAL|MAX_VERTICAL|MAX_LEFTHALF|MAX_RIGHTHALF); + directions &= (MAX_HORIZONTAL | MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS); changed_h = ((wwin->flags.maximized ^ directions) & MAX_HORIZONTAL); changed_v = ((wwin->flags.maximized ^ directions) & MAX_VERTICAL); @@ -397,6 +401,9 @@ void wMaximizeWindow(WWindow * wwin, int directions) new_height -= wwin->frame->top_width + wwin->frame->bottom_width; } + if (directions & MAX_MAXIMUS) + find_Maximus_geometry(wwin, usableArea, &new_x, &new_y, &new_width, &new_height); + wWindowConstrainSize(wwin, &new_width, &new_height); wWindowCropSize(wwin, usableArea.x2 - usableArea.x1, @@ -409,6 +416,106 @@ void wMaximizeWindow(WWindow * wwin, int directions) wSoundPlay(WSOUND_MAXIMIZE); } +/* + * Maximus: tiled maximization (maximize without overlapping other windows) + * + * The window to be maximized will be denoted by w_0 (sub-index zero) + * while the windows which will stop the maximization of w_0 are denoted by w_j. + */ +static void find_Maximus_geometry(WWindow *wwin, WArea usableArea, int *new_x, int *new_y, + int *new_width, int *new_height) +{ + WWindow *tmp; + int x_0 = wwin->frame_x; + int y_0 = wwin->frame_y; + int width_0 = wwin->frame->core->width; + int height_0 = wwin->frame->core->height; + int botton_0 = y_0 + height_0; + int right_border_0 = x_0 + width_0; + int new_x_0, new_y_0, new_botton_0, new_right_border_0, new_height_0; + int x_j, y_j, width_j, height_j, botton_j, top_j, right_border_j; + int x_intsect, y_intsect; + /* Assume that the window w_0 has titlebar etc */ + int has_titlebar = 1, has_resizebar = 1, has_border = 1; + int adjust_height, adjust_width; + + /* Try to fully maximize first, then readjust later */ + new_x_0 = usableArea.x1; + new_y_0 = usableArea.y1; + new_botton_0 = usableArea.y2; + new_right_border_0 = usableArea.x2; + + if (!HAS_TITLEBAR(wwin)) + has_titlebar = 0; + if (!HAS_RESIZEBAR(wwin)) + has_resizebar = 0; + if (!HAS_BORDER(wwin)) + has_border = 0; + + /* the lengths to be subtracted if w_0 has titlebar, etc */ + adjust_height = TITLEBAR_HEIGHT * has_titlebar + + 2 * FRAME_BORDER_WIDTH * has_border + RESIZEBAR_HEIGHT * has_resizebar; + adjust_width = 2 * FRAME_BORDER_WIDTH * has_border; + + tmp = wwin; + /* TODO: Is the focused window always the last in the list? */ + while (tmp->prev) { + /* ignore windows in other workspaces or minimized */ + if (tmp->prev->frame->workspace != wwin->screen_ptr->current_workspace + || tmp->prev->flags.miniaturized) { + tmp = tmp->prev; + continue; + } + tmp = tmp->prev; + + /* set the w_j window coordinates */ + x_j = tmp->frame_x; + y_j = tmp->frame_y; + width_j = tmp->frame->core->width; + height_j = tmp->frame->core->height; + botton_j = y_j + height_j; + top_j = y_j; + right_border_j = x_j + width_j; + + /* Try to maximize in the y direction first */ + x_intsect = calcIntersectionLength(x_0, width_0, x_j, width_j); + if (x_intsect != 0) { + if (botton_j < y_0 && botton_j > new_y_0) { + /* w_0 is below the botton of w_j */ + new_y_0 = botton_j; + } + if (botton_0 < top_j && top_j < new_botton_0) { + /* The botton of w_0 is above the top of w_j */ + new_botton_0 = top_j; + } + } + + /* + * Use the updated y coordinates from the above step to account + * the possibility that the new value of y_0 will have different + * intersections with w_j + */ + new_height_0 = new_botton_0 - new_y_0 - adjust_height; + y_intsect = calcIntersectionLength(new_y_0, new_height_0, y_j, height_j); + if (y_intsect != 0) { + if (right_border_j < x_0 && right_border_j > new_x_0) { + /* w_0 is completely to the right of w_j */ + new_x_0 = right_border_j; + } + if (right_border_0 < x_j && x_j < new_right_border_0) { + /* w_0 is completely to the left of w_j */ + new_right_border_0 = x_j; + } + } + } + + new_height_0 = new_botton_0 - new_y_0 - adjust_height; + *new_x = new_x_0; + *new_y = new_y_0; + *new_height = new_height_0; + *new_width = new_right_border_0 - new_x_0 - adjust_width; +} + void wUnmaximizeWindow(WWindow * wwin) { int x, y, w, h; diff --git a/src/actions.h b/src/actions.h index caff53fa..7069ff51 100644 --- a/src/actions.h +++ b/src/actions.h @@ -24,12 +24,13 @@ #include "window.h" -#define MAX_HORIZONTAL 1 -#define MAX_VERTICAL 2 -#define MAX_LEFTHALF 4 -#define MAX_RIGHTHALF 8 -#define MAX_IGNORE_XINERAMA 16 -#define MAX_KEYBOARD 32 +#define MAX_HORIZONTAL (1 << 0) +#define MAX_VERTICAL (1 << 1) +#define MAX_LEFTHALF (1 << 2) +#define MAX_RIGHTHALF (1 << 3) +#define MAX_MAXIMUS (1 << 4) +#define MAX_IGNORE_XINERAMA (1 << 5) +#define MAX_KEYBOARD (1 << 6) void wSetFocusTo(WScreen *scr, WWindow *wwin); diff --git a/src/defaults.c b/src/defaults.c index ef1fb715..d3176006 100644 --- a/src/defaults.c +++ b/src/defaults.c @@ -583,6 +583,8 @@ WDefaultEntry optionList[] = { NULL, getKeybind, setKeyGrab}, {"RHMaximizeKey", "None", (void*)WKBD_RHMAXIMIZE, NULL, getKeybind, setKeyGrab}, + {"MaximusKey", "None", (void*)WKBD_MAXIMUS, + NULL, getKeybind, setKeyGrab}, {"RaiseKey", "\"Meta+Up\"", (void *)WKBD_RAISE, NULL, getKeybind, setKeyGrab}, {"LowerKey", "\"Meta+Down\"", (void *)WKBD_LOWER, diff --git a/src/event.c b/src/event.c index da831491..70b8a1ed 100644 --- a/src/event.c +++ b/src/event.c @@ -1497,6 +1497,19 @@ static void handleKeyPress(XEvent * event) } } break; + case WKBD_MAXIMUS: + if (ISMAPPED(wwin) && ISFOCUSED(wwin) && IS_RESIZABLE(wwin)) { + int newdir = MAX_MAXIMUS; + + CloseWindowMenu(scr); + + if (wwin->flags.maximized == newdir) { + wUnmaximizeWindow(wwin); + } else { + wMaximizeWindow(wwin, newdir|MAX_KEYBOARD); + } + } + break; case WKBD_RAISE: if (ISMAPPED(wwin) && ISFOCUSED(wwin)) { CloseWindowMenu(scr); diff --git a/src/keybind.h b/src/keybind.h index 446e27fb..995e7a70 100644 --- a/src/keybind.h +++ b/src/keybind.h @@ -35,6 +35,7 @@ enum { WKBD_HMAXIMIZE, WKBD_LHMAXIMIZE, WKBD_RHMAXIMIZE, + WKBD_MAXIMUS, WKBD_SELECT, WKBD_RAISE, WKBD_LOWER, diff --git a/src/placement.c b/src/placement.c index 6a412ac4..32bdf7eb 100644 --- a/src/placement.c +++ b/src/placement.c @@ -234,7 +234,7 @@ void PlaceIcon(WScreen *scr, int *x_ret, int *y_ret, int head) } /* Computes the intersecting length of two line sections */ -static int calcIntersectionLength(int p1, int l1, int p2, int l2) +int calcIntersectionLength(int p1, int l1, int p2, int l2) { int isect; int tmp; diff --git a/src/window.h b/src/window.h index 5e69eb2e..e5ac7f49 100644 --- a/src/window.h +++ b/src/window.h @@ -258,7 +258,7 @@ typedef struct WWindow { unsigned int miniaturized:1; unsigned int hidden:1; unsigned int shaded:1; - unsigned int maximized:4; + unsigned int maximized:5; unsigned int fullscreen:1; unsigned int omnipresent:1;