]> git.sur5r.net Git - i3/i3/commitdiff
Implement resize <grow|shrink> <width|height>, use it in the default config
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 8 Apr 2012 13:59:49 +0000 (15:59 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 8 Apr 2012 14:00:15 +0000 (16:00 +0200)
Fixes: #576
docs/userguide
i3.config
i3.config.keycodes
parser-specs/commands.spec
src/commands.c
testcases/t/141-resize.t

index ad7c6195b68c253410318af2bf9254eed6e870b0..73db645ab66210902bb238412f0352f6cc5f1e90 100644 (file)
@@ -1365,11 +1365,13 @@ If you want to resize containers/windows using your keyboard, you can use the
 resize <grow|shrink> <direction> [<px> px] [or <ppt> ppt]
 ---------------------------------------------------------
 
-Direction can be one of +up+, +down+, +left+ or +right+. The optional pixel
-argument specifies by how many pixels a *floating container* should be grown or
-shrunk (the default is 10 pixels). The ppt argument means percentage points
-and specifies by how many percentage points a *tiling container* should be
-grown or shrunk (the default is 10 percentage points).
+Direction can either be one of +up+, +down+, +left+ or +right+. Or you can be
+less specific and use +width+ or +height+, in which case i3 will take/give
+space from all the other containers. The optional pixel argument specifies by
+how many pixels a *floating container* should be grown or shrunk (the default
+is 10 pixels). The ppt argument means percentage points and specifies by how
+many percentage points a *tiling container* should be grown or shrunk (the
+default is 10 percentage points).
 
 I recommend using the resize command inside a so called +mode+:
 
@@ -1378,21 +1380,20 @@ I recommend using the resize command inside a so called +mode+:
 mode "resize" {
         # These bindings trigger as soon as you enter the resize mode
 
-        # They resize the border in the direction you pressed, e.g.
-        # when pressing left, the window is resized so that it has
-        # more space on its left
-
-        bindsym j resize shrink left
-        bindsym Shift+j resize grow left
-
-        bindsym k resize grow down
-        bindsym Shift+k resize shrink down
-
-        bindsym l resize shrink up
-        bindsym Shift+l resize grow up
-
-        bindsym semicolon resize grow right
-        bindsym Shift+semicolon resize shrink right
+        # Pressing left will shrink the window’s width.
+        # Pressing right will grow the window’s width.
+        # Pressing up will shrink the window’s height.
+        # Pressing down will grow the window’s height.
+        bindsym j           resize shrink width 10 px or 10 ppt
+        bindsym k           resize grow height 10 px or 10 ppt
+        bindsym l           resize shrink height 10 px or 10 ppt
+        bindsym semicolon   resize grow width 10 px or 10 ppt
+
+        # same bindings, but for the arrow keys
+        bindsym Left        resize shrink width 10 px or 10 ppt
+        bindsym Down        resize grow height 10 px or 10 ppt
+        bindsym Up          resize shrink height 10 px or 10 ppt
+        bindsym Right       resize grow width 10 px or 10 ppt
 
         # back to normal: Enter or Escape
         bindsym Return mode "default"
index 4ee61d4b450af84175655a5f5f3960e595c35753..1a457fcab01d57c1634bd59f906bb421cd7945b8 100644 (file)
--- a/i3.config
+++ b/i3.config
@@ -109,34 +109,20 @@ bindsym Mod1+Shift+e exit
 mode "resize" {
         # These bindings trigger as soon as you enter the resize mode
 
-        # They resize the border in the direction you pressed, e.g.
-        # when pressing left, the window is resized so that it has
-        # more space on its left
-
-        bindsym j               resize shrink left 10 px or 10 ppt
-        bindsym Shift+j         resize grow   left 10 px or 10 ppt
-
-        bindsym k               resize shrink down 10 px or 10 ppt
-        bindsym Shift+k         resize grow   down 10 px or 10 ppt
-
-        bindsym l               resize shrink up 10 px or 10 ppt
-        bindsym Shift+l         resize grow   up 10 px or 10 ppt
-
-        bindsym semicolon       resize shrink right 10 px or 10 ppt
-        bindsym Shift+semicolon resize grow   right 10 px or 10 ppt
+        # Pressing left will shrink the window’s width.
+        # Pressing right will grow the window’s width.
+        # Pressing up will shrink the window’s height.
+        # Pressing down will grow the window’s height.
+        bindsym j           resize shrink width 10 px or 10 ppt
+        bindsym k           resize grow height 10 px or 10 ppt
+        bindsym l           resize shrink height 10 px or 10 ppt
+        bindsym semicolon   resize grow width 10 px or 10 ppt
 
         # same bindings, but for the arrow keys
-        bindsym Left        resize shrink left 10 px or 10 ppt
-        bindsym Shift+Left  resize grow   left 10 px or 10 ppt
-
-        bindsym Down        resize shrink down 10 px or 10 ppt
-        bindsym Shift+Down  resize grow   down 10 px or 10 ppt
-
-        bindsym Up          resize shrink up 10 px or 10 ppt
-        bindsym Shift+Up    resize grow   up 10 px or 10 ppt
-
-        bindsym Right       resize shrink right 10 px or 10 ppt
-        bindsym Shift+Right resize grow   right 10 px or 10 ppt
+        bindsym Left        resize shrink width 10 px or 10 ppt
+        bindsym Down        resize grow height 10 px or 10 ppt
+        bindsym Up          resize shrink height 10 px or 10 ppt
+        bindsym Right       resize grow width 10 px or 10 ppt
 
         # back to normal: Enter or Escape
         bindsym Return mode "default"
index af081de0e14cc0db3004dadc4016070fc29441e3..8f170514271bacfbd0c00acb48230e2a1fc89a2e 100644 (file)
@@ -110,34 +110,20 @@ bindcode $mod+Shift+26 exit
 mode "resize" {
         # These bindings trigger as soon as you enter the resize mode
 
-        # They resize the border in the direction you pressed, e.g.
-        # when pressing left, the window is resized so that it has
-        # more space on its left
-
-        bindcode 44 resize shrink left 10 px or 10 ppt
-        bindcode Shift+44 resize grow   left 10 px or 10 ppt
-
-        bindcode 45 resize shrink down 10 px or 10 ppt
-        bindcode Shift+45 resize grow   down 10 px or 10 ppt
-
-        bindcode 46 resize shrink up 10 px or 10 ppt
-        bindcode Shift+46 resize grow   up 10 px or 10 ppt
-
-        bindcode 47 resize shrink right 10 px or 10 ppt
-        bindcode Shift+47 resize grow   right 10 px or 10 ppt
+        # Pressing left will shrink the window’s width.
+        # Pressing right will grow the window’s width.
+        # Pressing up will shrink the window’s height.
+        # Pressing down will grow the window’s height.
+        bindcode 44 resize shrink width 10 px or 10 ppt
+        bindcode 45 resize grow height 10 px or 10 ppt
+        bindcode 46 resize shrink height 10 px or 10 ppt
+        bindcode 47 resize grow width 10 px or 10 ppt
 
         # same bindings, but for the arrow keys
-        bindcode 113 resize shrink left 10 px or 10 ppt
-        bindcode Shift+113 resize grow   left 10 px or 10 ppt
-
-        bindcode 116 resize shrink down 10 px or 10 ppt
-        bindcode Shift+116 resize grow   down 10 px or 10 ppt
-
-        bindcode 111 resize shrink up 10 px or 10 ppt
-        bindcode Shift+111 resize grow   up 10 px or 10 ppt
-
-        bindcode 114 resize shrink right 10 px or 10 ppt
-        bindcode Shift+114 resize grow   right 10 px or 10 ppt
+        bindsym 113 resize shrink width 10 px or 10 ppt
+        bindsym 116 resize grow height 10 px or 10 ppt
+        bindsym 111 resize shrink height 10 px or 10 ppt
+        bindsym 114 resize grow width 10 px or 10 ppt
 
         # back to normal: Enter or Escape
         bindcode 36 mode "default"
index 490e49720244cdcf0fbf99df2f46837e98d9189a..1a3f99d9434cfaced535b27f58fecd5a17454c33 100644 (file)
@@ -141,7 +141,7 @@ state RESIZE:
       -> RESIZE_DIRECTION
 
 state RESIZE_DIRECTION:
-  direction = 'up', 'down', 'left', 'right'
+  direction = 'up', 'down', 'left', 'right', 'width', 'height'
       -> RESIZE_PX
 
 state RESIZE_PX:
index 2df26f6cd83187daef8d1854d7a55bfa13472461..0a5abde5fc3c662a2ec01487085a39a0917e0645 100644 (file)
@@ -391,6 +391,171 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
     cmd_output->json_output = sstrdup("{\"success\": true}");
 }
 
+static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floating_con, int px) {
+    LOG("floating resize\n");
+    if (strcmp(direction, "up") == 0) {
+        floating_con->rect.y -= px;
+        floating_con->rect.height += px;
+    } else if (strcmp(direction, "down") == 0) {
+        floating_con->rect.height += px;
+    } else if (strcmp(direction, "left") == 0) {
+        floating_con->rect.x -= px;
+        floating_con->rect.width += px;
+    } else {
+        floating_con->rect.width += px;
+    }
+}
+
+static void cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int ppt) {
+    LOG("tiling resize\n");
+    /* get the appropriate current container (skip stacked/tabbed cons) */
+    Con *current = focused;
+    while (current->parent->layout == L_STACKED ||
+           current->parent->layout == L_TABBED)
+        current = current->parent;
+
+    /* Then further go up until we find one with the matching orientation. */
+    orientation_t search_orientation =
+        (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0 ? HORIZ : VERT);
+
+    while (current->type != CT_WORKSPACE &&
+           current->type != CT_FLOATING_CON &&
+           current->parent->orientation != search_orientation)
+        current = current->parent;
+
+    /* get the default percentage */
+    int children = con_num_children(current->parent);
+    Con *other;
+    LOG("ins. %d children\n", children);
+    double percentage = 1.0 / children;
+    LOG("default percentage = %f\n", percentage);
+
+    orientation_t orientation = current->parent->orientation;
+
+    if ((orientation == HORIZ &&
+         (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) ||
+        (orientation == VERT &&
+         (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) {
+        LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
+            (orientation == HORIZ ? "horizontal" : "vertical"));
+        cmd_output->json_output = sstrdup("{\"sucess\": false}");
+        return;
+    }
+
+    if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) {
+        other = TAILQ_PREV(current, nodes_head, nodes);
+    } else {
+        other = TAILQ_NEXT(current, nodes);
+    }
+    if (other == TAILQ_END(workspaces)) {
+        LOG("No other container in this direction found, cannot resize.\n");
+        cmd_output->json_output = sstrdup("{\"sucess\": false}");
+        return;
+    }
+    LOG("other->percent = %f\n", other->percent);
+    LOG("current->percent before = %f\n", current->percent);
+    if (current->percent == 0.0)
+        current->percent = percentage;
+    if (other->percent == 0.0)
+        other->percent = percentage;
+    double new_current_percent = current->percent + ((double)ppt / 100.0);
+    double new_other_percent = other->percent - ((double)ppt / 100.0);
+    LOG("new_current_percent = %f\n", new_current_percent);
+    LOG("new_other_percent = %f\n", new_other_percent);
+    /* Ensure that the new percentages are positive and greater than
+     * 0.05 to have a reasonable minimum size. */
+    if (definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON) &&
+        definitelyGreaterThan(new_other_percent, 0.05, DBL_EPSILON)) {
+        current->percent += ((double)ppt / 100.0);
+        other->percent -= ((double)ppt / 100.0);
+        LOG("current->percent after = %f\n", current->percent);
+        LOG("other->percent after = %f\n", other->percent);
+    } else {
+        LOG("Not resizing, already at minimum size\n");
+    }
+}
+
+static void cmd_resize_tiling_width_height(I3_CMD, char *way, char *direction, int ppt) {
+    LOG("width/height resize\n");
+    /* get the appropriate current container (skip stacked/tabbed cons) */
+    Con *current = focused;
+    while (current->parent->layout == L_STACKED ||
+           current->parent->layout == L_TABBED)
+        current = current->parent;
+
+    /* Then further go up until we find one with the matching orientation. */
+    orientation_t search_orientation =
+        (strcmp(direction, "width") == 0 ? HORIZ : VERT);
+
+    while (current->type != CT_WORKSPACE &&
+           current->type != CT_FLOATING_CON &&
+           current->parent->orientation != search_orientation)
+        current = current->parent;
+
+    /* get the default percentage */
+    int children = con_num_children(current->parent);
+    LOG("ins. %d children\n", children);
+    double percentage = 1.0 / children;
+    LOG("default percentage = %f\n", percentage);
+
+    orientation_t orientation = current->parent->orientation;
+
+    if ((orientation == HORIZ &&
+         strcmp(direction, "height") == 0) ||
+        (orientation == VERT &&
+         strcmp(direction, "width") == 0)) {
+        LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
+            (orientation == HORIZ ? "horizontal" : "vertical"));
+        cmd_output->json_output = sstrdup("{\"sucess\": false}");
+        return;
+    }
+
+    if (children == 1) {
+        LOG("This is the only container, cannot resize.\n");
+        cmd_output->json_output = sstrdup("{\"sucess\": false}");
+        return;
+    }
+
+    /* Ensure all the other children have a percentage set. */
+    Con *child;
+    TAILQ_FOREACH(child, &(current->parent->nodes_head), nodes) {
+        LOG("child->percent = %f (child %p)\n", child->percent, child);
+        if (child->percent == 0.0)
+            child->percent = percentage;
+    }
+
+    double new_current_percent = current->percent + ((double)ppt / 100.0);
+    double subtract_percent = ((double)ppt / 100.0) / (children - 1);
+    LOG("new_current_percent = %f\n", new_current_percent);
+    LOG("subtract_percent = %f\n", subtract_percent);
+    /* Ensure that the new percentages are positive and greater than
+     * 0.05 to have a reasonable minimum size. */
+    TAILQ_FOREACH(child, &(current->parent->nodes_head), nodes) {
+        if (child == current)
+            continue;
+        if (!definitelyGreaterThan(child->percent - subtract_percent, 0.05, DBL_EPSILON)) {
+            LOG("Not resizing, already at minimum size (child %p would end up with a size of %.f\n", child, child->percent - subtract_percent);
+            cmd_output->json_output = sstrdup("{\"sucess\": false}");
+            return;
+        }
+    }
+    if (!definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON)) {
+        LOG("Not resizing, already at minimum size\n");
+        cmd_output->json_output = sstrdup("{\"sucess\": false}");
+        return;
+    }
+
+    current->percent += ((double)ppt / 100.0);
+    LOG("current->percent after = %f\n", current->percent);
+
+    TAILQ_FOREACH(child, &(current->parent->nodes_head), nodes) {
+        if (child == current)
+            continue;
+        child->percent -= subtract_percent;
+        LOG("child->percent after (%p) = %f\n", child, child->percent);
+    }
+}
+
 /*
  * Implementation of 'resize grow|shrink <direction> [<px> px] [or <ppt> ppt]'.
  *
@@ -408,85 +573,12 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
 
     Con *floating_con;
     if ((floating_con = con_inside_floating(focused))) {
-        printf("floating resize\n");
-        if (strcmp(direction, "up") == 0) {
-            floating_con->rect.y -= px;
-            floating_con->rect.height += px;
-        } else if (strcmp(direction, "down") == 0) {
-            floating_con->rect.height += px;
-        } else if (strcmp(direction, "left") == 0) {
-            floating_con->rect.x -= px;
-            floating_con->rect.width += px;
-        } else {
-            floating_con->rect.width += px;
-        }
+        cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
     } else {
-        LOG("tiling resize\n");
-        /* get the appropriate current container (skip stacked/tabbed cons) */
-        Con *current = focused;
-        while (current->parent->layout == L_STACKED ||
-               current->parent->layout == L_TABBED)
-            current = current->parent;
-
-        /* Then further go up until we find one with the matching orientation. */
-        orientation_t search_orientation =
-            (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0 ? HORIZ : VERT);
-
-        while (current->type != CT_WORKSPACE &&
-               current->type != CT_FLOATING_CON &&
-               current->parent->orientation != search_orientation)
-            current = current->parent;
-
-        /* get the default percentage */
-        int children = con_num_children(current->parent);
-        Con *other;
-        LOG("ins. %d children\n", children);
-        double percentage = 1.0 / children;
-        LOG("default percentage = %f\n", percentage);
-
-        orientation_t orientation = current->parent->orientation;
-
-        if ((orientation == HORIZ &&
-             (strcmp(direction, "up") == 0 || strcmp(direction, "down") == 0)) ||
-            (orientation == VERT &&
-             (strcmp(direction, "left") == 0 || strcmp(direction, "right") == 0))) {
-            LOG("You cannot resize in that direction. Your focus is in a %s split container currently.\n",
-                (orientation == HORIZ ? "horizontal" : "vertical"));
-            cmd_output->json_output = sstrdup("{\"sucess\": false}");
-            return;
-        }
-
-        if (strcmp(direction, "up") == 0 || strcmp(direction, "left") == 0) {
-            other = TAILQ_PREV(current, nodes_head, nodes);
-        } else {
-            other = TAILQ_NEXT(current, nodes);
-        }
-        if (other == TAILQ_END(workspaces)) {
-            LOG("No other container in this direction found, cannot resize.\n");
-            cmd_output->json_output = sstrdup("{\"sucess\": false}");
-            return;
-        }
-        LOG("other->percent = %f\n", other->percent);
-        LOG("current->percent before = %f\n", current->percent);
-        if (current->percent == 0.0)
-            current->percent = percentage;
-        if (other->percent == 0.0)
-            other->percent = percentage;
-        double new_current_percent = current->percent + ((double)ppt / 100.0);
-        double new_other_percent = other->percent - ((double)ppt / 100.0);
-        LOG("new_current_percent = %f\n", new_current_percent);
-        LOG("new_other_percent = %f\n", new_other_percent);
-        /* Ensure that the new percentages are positive and greater than
-         * 0.05 to have a reasonable minimum size. */
-        if (definitelyGreaterThan(new_current_percent, 0.05, DBL_EPSILON) &&
-            definitelyGreaterThan(new_other_percent, 0.05, DBL_EPSILON)) {
-            current->percent += ((double)ppt / 100.0);
-            other->percent -= ((double)ppt / 100.0);
-            LOG("current->percent after = %f\n", current->percent);
-            LOG("other->percent after = %f\n", other->percent);
-        } else {
-            LOG("Not resizing, already at minimum size\n");
-        }
+        if (strcmp(direction, "width") == 0 ||
+            strcmp(direction, "height") == 0)
+            cmd_resize_tiling_width_height(current_match, cmd_output, way, direction, ppt);
+        else cmd_resize_tiling_direction(current_match, cmd_output, way, direction, ppt);
     }
 
     cmd_output->needs_tree_render = true;
index c2038060a707c3fd55ae09ec951381a098cd651a..91aeca50314cc899283c2873254a274cf9d77270 100644 (file)
@@ -88,6 +88,45 @@ cmd 'resize grow left 10 px or 25 ppt';
 is($nodes->[0]->{percent}, 0.25, 'left window got 25%');
 is($nodes->[1]->{percent}, 0.75, 'right window got 75%');
 
+################################################################################
+# Check that the resize grow/shrink width/height syntax works.
+################################################################################
+
+# Use two windows
+$tmp = fresh_workspace;
+
+$left = open_window;
+$right = open_window;
+
+cmd 'resize grow width 10 px or 25 ppt';
+
+($nodes, $focus) = get_ws_content($tmp);
+is($nodes->[0]->{percent}, 0.25, 'left window got 25%');
+is($nodes->[1]->{percent}, 0.75, 'right window got 75%');
+
+# Now test it with four windows
+$tmp = fresh_workspace;
+
+open_window for (1..4);
+
+cmd 'resize grow width 10 px or 25 ppt';
+
+($nodes, $focus) = get_ws_content($tmp);
+is($nodes->[0]->{percent}, 0.166666666666667, 'first window got 16%');
+is($nodes->[1]->{percent}, 0.166666666666667, 'second window got 16%');
+is($nodes->[2]->{percent}, 0.166666666666667, 'third window got 16%');
+is($nodes->[3]->{percent}, 0.50, 'fourth window got 50%');
+
+# height should be a no-op in this situation
+cmd 'resize grow height 10 px or 25 ppt';
+
+($nodes, $focus) = get_ws_content($tmp);
+is($nodes->[0]->{percent}, 0.166666666666667, 'first window got 16%');
+is($nodes->[1]->{percent}, 0.166666666666667, 'second window got 16%');
+is($nodes->[2]->{percent}, 0.166666666666667, 'third window got 16%');
+is($nodes->[3]->{percent}, 0.50, 'fourth window got 50%');
+
+
 ############################################################
 # checks that resizing floating windows works
 ############################################################