Maximus: Tiled Maximization
[wmaker-crm.git] / src / actions.c
index e3e2249..f9b9257 100644 (file)
@@ -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;