>From 936879ae7bbc37ba20f0992c86369bfde97cc89d Mon Sep 17 00:00:00 2001
From: Carlos R. Mafra <[email protected]>
Date: Sun, 30 Aug 2009 23:34:32 +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.
The maximization is working, but there are things to be considered more
carefully. From my first tests I noticed that after using Maximus the
window can no longer be Resized/moved, and that somehow the keyboard
shortcut associated to Maximus also becomes the shortcut of the
"Select" entry in the window menu (Ctrl+ESC). Furthermore, it
seems that the "exit" dialog sometimes does not grab the keyboard focus
anymore, and exiting wmaker requires a mouse click on the "exit" button.
Those are embarrassing bugs, but this patch is only the first step
anyway.
---
I pushed it to 'next', so people can test it if they feel brave.
I will appreciate comments of any kind, and if people spot where the
bugs are that will be even better!
This is still a work in progress, so any help is warmly welcomed!
WPrefs.app/KeyboardShortcuts.c | 2 +
src/actions.c | 90 +++++++++++++++++++++++++++++++++++++++-
src/actions.h | 13 +++---
src/defaults.c | 2 +
src/event.c | 13 ++++++
src/keybind.h | 81 ++++++++++++++++++------------------
src/placement.c | 16 ++++----
src/window.h | 2 +-
8 files changed, 163 insertions(+), 56 deletions(-)
diff --git a/WPrefs.app/KeyboardShortcuts.c b/WPrefs.app/KeyboardShortcuts.c
index 919d73b..6cc6f9e 100644
--- a/WPrefs.app/KeyboardShortcuts.c
+++ b/WPrefs.app/KeyboardShortcuts.c
@@ -74,6 +74,7 @@ static char *keyOptions[] = {
"HMaximizeKey",
"LHMaximizeKey",
"RHMaximizeKey",
+ "MaximusKey",
"RaiseKey",
"LowerKey",
"RaiseLowerKey",
@@ -477,6 +478,7 @@ static void createPanel(Panel * p)
WMAddListItem(panel->actLs, _("Maximize active window horizontally"));
WMAddListItem(panel->actLs, _("Maximize active window left half"));
WMAddListItem(panel->actLs, _("Maximize active window right half"));
+ WMAddListItem(panel->actLs, _("Maximus: Tiled maximization "));
WMAddListItem(panel->actLs, _("Raise active window"));
WMAddListItem(panel->actLs, _("Lower active window"));
WMAddListItem(panel->actLs, _("Raise/Lower window under mouse
pointer"));
diff --git a/src/actions.c b/src/actions.c
index cd7faa1..a791d79 100644
--- a/src/actions.c
+++ b/src/actions.c
@@ -60,6 +60,9 @@ extern WPreferences wPreferences;
extern Atom _XA_WM_TAKE_FOCUS;
extern void ProcessPendingEvents();
+extern int calcIntersectionLength(int p1, int l1, int p2, int l2);
+
+void find_Maximus_geometry(WWindow *wwin, int *new_x, int *new_y, int
*new_width, int *new_height);
/******* Local Variables *******/
static struct {
@@ -326,7 +329,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 +400,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, &new_x, &new_y, &new_width,
&new_height);
+
wWindowConstrainSize(wwin, &new_width, &new_height);
wWindowCropSize(wwin, usableArea.x2 - usableArea.x1,
@@ -409,6 +415,88 @@ 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.
+ */
+void find_Maximus_geometry(WWindow *wwin, 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;
+
+ /* Try to fully maximize first, then readjust later */
+ new_x_0 = 0;
+ new_y_0 = 0;
+ new_botton_0 = wwin->screen_ptr->scr_height;
+ new_right_border_0 = wwin->screen_ptr->scr_width;
+
+ tmp = wwin;
+ /* TODO: Is the focused window always the last in the list? */
+ while (tmp->prev) {
+ /* ignore windows in other workspaces */
+ if (tmp->prev->frame->workspace !=
wwin->screen_ptr->current_workspace) {
+ 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 - TITLEBAR_HEIGHT - 2 *
FRAME_BORDER_WIDTH;
+ 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_x = new_x_0;
+ *new_y = new_y_0;
+ *new_height = new_height_0;
+ *new_width = new_right_border_0 - new_x_0;
+}
+
void wUnmaximizeWindow(WWindow * wwin)
{
int x, y, w, h;
diff --git a/src/actions.h b/src/actions.h
index caff53f..8560d1b 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
+#define MAX_VERTICAL 2
+#define MAX_LEFTHALF 4
+#define MAX_RIGHTHALF 8
+#define MAX_MAXIMUS 16
+#define MAX_IGNORE_XINERAMA 32
+#define MAX_KEYBOARD 64
void wSetFocusTo(WScreen *scr, WWindow *wwin);
diff --git a/src/defaults.c b/src/defaults.c
index ef1fb71..d317600 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 da83149..70b8a1e 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 d129a69..8879113 100644
--- a/src/keybind.h
+++ b/src/keybind.h
@@ -34,57 +34,58 @@
#define WKBD_HMAXIMIZE 8
#define WKBD_LHMAXIMIZE 9
#define WKBD_RHMAXIMIZE 10
-#define WKBD_SELECT 11
+#define WKBD_MAXIMUS 11
+#define WKBD_SELECT 12
/* Clip */
-#define WKBD_CLIPLOWER 12
-#define WKBD_CLIPRAISE 13
-#define WKBD_CLIPRAISELOWER 14
+#define WKBD_CLIPLOWER 13
+#define WKBD_CLIPRAISE 14
+#define WKBD_CLIPRAISELOWER 15
/* window */
-#define WKBD_RAISE 15
-#define WKBD_LOWER 16
-#define WKBD_RAISELOWER 17
-#define WKBD_MOVERESIZE 18
-#define WKBD_SHADE 19
+#define WKBD_RAISE 16
+#define WKBD_LOWER 17
+#define WKBD_RAISELOWER 18
+#define WKBD_MOVERESIZE 19
+#define WKBD_SHADE 20
/* window, menu */
-#define WKBD_CLOSE 20
+#define WKBD_CLOSE 21
/* window */
-#define WKBD_FOCUSNEXT 21
-#define WKBD_FOCUSPREV 22
+#define WKBD_FOCUSNEXT 22
+#define WKBD_FOCUSPREV 23
-#define WKBD_WORKSPACE1 23
-#define WKBD_WORKSPACE2 24
-#define WKBD_WORKSPACE3 25
-#define WKBD_WORKSPACE4 26
-#define WKBD_WORKSPACE5 27
-#define WKBD_WORKSPACE6 28
-#define WKBD_WORKSPACE7 29
-#define WKBD_WORKSPACE8 30
-#define WKBD_WORKSPACE9 31
-#define WKBD_WORKSPACE10 32
-#define WKBD_NEXTWORKSPACE 33
-#define WKBD_PREVWORKSPACE 34
-#define WKBD_NEXTWSLAYER 35
-#define WKBD_PREVWSLAYER 36
+#define WKBD_WORKSPACE1 24
+#define WKBD_WORKSPACE2 25
+#define WKBD_WORKSPACE3 26
+#define WKBD_WORKSPACE4 27
+#define WKBD_WORKSPACE5 28
+#define WKBD_WORKSPACE6 29
+#define WKBD_WORKSPACE7 30
+#define WKBD_WORKSPACE8 31
+#define WKBD_WORKSPACE9 32
+#define WKBD_WORKSPACE10 33
+#define WKBD_NEXTWORKSPACE 34
+#define WKBD_PREVWORKSPACE 35
+#define WKBD_NEXTWSLAYER 36
+#define WKBD_PREVWSLAYER 37
/* window shortcuts */
-#define WKBD_WINDOW1 37
-#define WKBD_WINDOW2 38
-#define WKBD_WINDOW3 39
-#define WKBD_WINDOW4 40
-#define WKBD_WINDOW5 41
-#define WKBD_WINDOW6 42
-#define WKBD_WINDOW7 43
-#define WKBD_WINDOW8 44
-#define WKBD_WINDOW9 45
-#define WKBD_WINDOW10 46
+#define WKBD_WINDOW1 38
+#define WKBD_WINDOW2 39
+#define WKBD_WINDOW3 40
+#define WKBD_WINDOW4 41
+#define WKBD_WINDOW5 42
+#define WKBD_WINDOW6 43
+#define WKBD_WINDOW7 44
+#define WKBD_WINDOW8 45
+#define WKBD_WINDOW9 46
+#define WKBD_WINDOW10 47
-#define WKBD_SWITCH_SCREEN 47
+#define WKBD_SWITCH_SCREEN 48
#ifdef KEEP_XKB_LOCK_STATUS
-# define WKBD_TOGGLE 48
-# define WKBD_TMP 49
+# define WKBD_TOGGLE 49
+# define WKBD_TMP 50
#else
-# define WKBD_TMP 48
+# define WKBD_TMP 49
#endif
#ifdef VIRTUAL_DESKTOP
diff --git a/src/placement.c b/src/placement.c
index 6a412ac..688c6f3 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 length1, int p2, int length2)
{
int isect;
int tmp;
@@ -243,17 +243,17 @@ static int calcIntersectionLength(int p1, int l1, int p2,
int l2)
tmp = p1;
p1 = p2;
p2 = tmp;
- tmp = l1;
- l1 = l2;
- l2 = tmp;
+ tmp = length1;
+ length1 = length2;
+ length2 = tmp;
}
- if (p1 + l1 < p2)
+ if (p1 + length1 < p2)
isect = 0;
- else if (p2 + l2 < p1 + l1)
- isect = l2;
+ else if (p2 + length2 < p1 + length1)
+ isect = length2;
else
- isect = p1 + l1 - p2;
+ isect = p1 + length1 - p2;
return isect;
}
diff --git a/src/window.h b/src/window.h
index 5e69eb2..e5ac7f4 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;
--
1.6.4.2.236.gf324c
--
To unsubscribe, send mail to [email protected].