From cf62d1591f5aef1e6760a8c0881a6de97ae26e92 Mon Sep 17 00:00:00 2001 From: "Carlos R. Mafra" Date: Wed, 2 Sep 2009 01:37:47 +0200 Subject: [PATCH] Maximus: Tiled Maximization This patch introduces the "tiled maximization" feature, a.k.a. Maximus. By pressing the keyboard shortcut associated with Maximus, the focused window will be maximized to the greatest area satisfying the constraint of not overlapping existing windows. --- src/actions.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/actions.h | 13 +++---- src/defaults.c | 2 ++ src/event.c | 13 +++++++ src/keybind.h | 1 + src/placement.c | 2 +- src/window.h | 2 +- 7 files changed, 133 insertions(+), 9 deletions(-) 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; -- 2.11.4.GIT