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

Fixes: #576
next
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]
---------------------------------------------------------
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
# Pressing left will shrink the windows width.
# Pressing right will grow the windows width.
# 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
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
# 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"

View File

@ -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 windows width.
# Pressing right will grow the windows width.
# 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
# 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"

View 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 windows width.
# Pressing right will grow the windows width.
# Pressing up will shrink the windows height.
# Pressing down will grow the windows 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"

View 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:

View 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;

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->[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
############################################################