Implement resize <grow|shrink> <width|height>, use it in the default config

Fixes: #576
This commit is contained in:
Michael Stapelberg 2012-04-08 15:59:49 +02:00
parent 24ac6e32aa
commit 2d110c90e6
6 changed files with 254 additions and 150 deletions

View 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] resize <grow|shrink> <direction> [<px> px] [or <ppt> ppt]
--------------------------------------------------------- ---------------------------------------------------------
Direction can be one of +up+, +down+, +left+ or +right+. The optional pixel Direction can either be one of +up+, +down+, +left+ or +right+. Or you can be
argument specifies by how many pixels a *floating container* should be grown or less specific and use +width+ or +height+, in which case i3 will take/give
shrunk (the default is 10 pixels). The ppt argument means percentage points space from all the other containers. The optional pixel argument specifies by
and specifies by how many percentage points a *tiling container* should be how many pixels a *floating container* should be grown or shrunk (the default
grown or shrunk (the default is 10 percentage points). 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+: 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" { mode "resize" {
# These bindings trigger as soon as you enter the resize mode # These bindings trigger as soon as you enter the resize mode
# They resize the border in the direction you pressed, e.g. # Pressing left will shrink the windows width.
# when pressing left, the window is resized so that it has # Pressing right will grow the windows width.
# more space on its left # Pressing up will shrink the windows height.
# Pressing down will grow the windows 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
bindsym j resize shrink left # same bindings, but for the arrow keys
bindsym Shift+j resize grow left bindsym Left resize shrink width 10 px or 10 ppt
bindsym Down resize grow height 10 px or 10 ppt
bindsym k resize grow down bindsym Up resize shrink height 10 px or 10 ppt
bindsym Shift+k resize shrink down bindsym Right resize grow width 10 px or 10 ppt
bindsym l resize shrink up
bindsym Shift+l resize grow up
bindsym semicolon resize grow right
bindsym Shift+semicolon resize shrink right
# back to normal: Enter or Escape # back to normal: Enter or Escape
bindsym Return mode "default" bindsym Return mode "default"

View File

@ -109,34 +109,20 @@ bindsym Mod1+Shift+e exit
mode "resize" { mode "resize" {
# These bindings trigger as soon as you enter the resize mode # These bindings trigger as soon as you enter the resize mode
# They resize the border in the direction you pressed, e.g. # Pressing left will shrink the windows width.
# when pressing left, the window is resized so that it has # Pressing right will grow the windows width.
# more space on its left # Pressing up will shrink the windows height.
# Pressing down will grow the windows height.
bindsym j resize shrink left 10 px or 10 ppt bindsym j resize shrink width 10 px or 10 ppt
bindsym Shift+j resize grow left 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 k resize shrink down 10 px or 10 ppt bindsym semicolon resize grow width 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
# same bindings, but for the arrow keys # same bindings, but for the arrow keys
bindsym Left resize shrink left 10 px or 10 ppt bindsym Left resize shrink width 10 px or 10 ppt
bindsym Shift+Left resize grow left 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 Down resize shrink down 10 px or 10 ppt bindsym Right resize grow width 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
# back to normal: Enter or Escape # back to normal: Enter or Escape
bindsym Return mode "default" bindsym Return mode "default"

View File

@ -110,34 +110,20 @@ bindcode $mod+Shift+26 exit
mode "resize" { mode "resize" {
# These bindings trigger as soon as you enter the resize mode # These bindings trigger as soon as you enter the resize mode
# They resize the border in the direction you pressed, e.g. # Pressing left will shrink the windows width.
# when pressing left, the window is resized so that it has # Pressing right will grow the windows width.
# more space on its left # Pressing up will shrink the windows height.
# Pressing down will grow the windows height.
bindcode 44 resize shrink left 10 px or 10 ppt bindcode 44 resize shrink width 10 px or 10 ppt
bindcode Shift+44 resize grow left 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 45 resize shrink down 10 px or 10 ppt bindcode 47 resize grow width 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
# same bindings, but for the arrow keys # same bindings, but for the arrow keys
bindcode 113 resize shrink left 10 px or 10 ppt bindsym 113 resize shrink width 10 px or 10 ppt
bindcode Shift+113 resize grow left 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
bindcode 116 resize shrink down 10 px or 10 ppt bindsym 114 resize grow width 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
# back to normal: Enter or Escape # back to normal: Enter or Escape
bindcode 36 mode "default" bindcode 36 mode "default"

View File

@ -141,7 +141,7 @@ state RESIZE:
-> RESIZE_DIRECTION -> RESIZE_DIRECTION
state RESIZE_DIRECTION: state RESIZE_DIRECTION:
direction = 'up', 'down', 'left', 'right' direction = 'up', 'down', 'left', 'right', 'width', 'height'
-> RESIZE_PX -> RESIZE_PX
state RESIZE_PX: state RESIZE_PX:

View File

@ -391,24 +391,8 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
cmd_output->json_output = sstrdup("{\"success\": true}"); cmd_output->json_output = sstrdup("{\"success\": true}");
} }
/* static void cmd_resize_floating(I3_CMD, char *way, char *direction, Con *floating_con, int px) {
* Implementation of 'resize grow|shrink <direction> [<px> px] [or <ppt> ppt]'. LOG("floating resize\n");
*
*/
void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resize_ppt) {
/* resize <grow|shrink> <direction> [<px> px] [or <ppt> ppt] */
DLOG("resizing in way %s, direction %s, px %s or ppt %s\n", way, direction, resize_px, resize_ppt);
// TODO: We could either handle this in the parser itself as a separate token (and make the stack typed) or we need a better way to convert a string to a number with error checking
int px = atoi(resize_px);
int ppt = atoi(resize_ppt);
if (strcmp(way, "shrink") == 0) {
px *= -1;
ppt *= -1;
}
Con *floating_con;
if ((floating_con = con_inside_floating(focused))) {
printf("floating resize\n");
if (strcmp(direction, "up") == 0) { if (strcmp(direction, "up") == 0) {
floating_con->rect.y -= px; floating_con->rect.y -= px;
floating_con->rect.height += px; floating_con->rect.height += px;
@ -420,7 +404,9 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
} else { } else {
floating_con->rect.width += px; floating_con->rect.width += px;
} }
} else { }
static void cmd_resize_tiling_direction(I3_CMD, char *way, char *direction, int ppt) {
LOG("tiling resize\n"); LOG("tiling resize\n");
/* get the appropriate current container (skip stacked/tabbed cons) */ /* get the appropriate current container (skip stacked/tabbed cons) */
Con *current = focused; Con *current = focused;
@ -489,6 +475,112 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
} }
} }
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]'.
*
*/
void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resize_ppt) {
/* resize <grow|shrink> <direction> [<px> px] [or <ppt> ppt] */
DLOG("resizing in way %s, direction %s, px %s or ppt %s\n", way, direction, resize_px, resize_ppt);
// TODO: We could either handle this in the parser itself as a separate token (and make the stack typed) or we need a better way to convert a string to a number with error checking
int px = atoi(resize_px);
int ppt = atoi(resize_ppt);
if (strcmp(way, "shrink") == 0) {
px *= -1;
ppt *= -1;
}
Con *floating_con;
if ((floating_con = con_inside_floating(focused))) {
cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
} else {
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; cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply // XXX: default reply for now, make this a better reply
cmd_output->json_output = sstrdup("{\"success\": true}"); cmd_output->json_output = sstrdup("{\"success\": true}");

View 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->[0]->{percent}, 0.25, 'left window got 25%');
is($nodes->[1]->{percent}, 0.75, 'right window got 75%'); 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 # checks that resizing floating windows works
############################################################ ############################################################