>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].

Reply via email to