Implement resize <grow|shrink> <width|height>, use it in the default config
Fixes: #576
This commit is contained in:
parent
24ac6e32aa
commit
2d110c90e6
|
@ -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 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
|
||||
|
||||
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"
|
||||
|
|
38
i3.config
38
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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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:
|
||||
|
|
130
src/commands.c
130
src/commands.c
|
@ -391,24 +391,8 @@ void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
|
|||
cmd_output->json_output = sstrdup("{\"success\": true}");
|
||||
}
|
||||
|
||||
/*
|
||||
* 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))) {
|
||||
printf("floating resize\n");
|
||||
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;
|
||||
|
@ -420,7 +404,9 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
|
|||
} else {
|
||||
floating_con->rect.width += px;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
// XXX: default reply for now, make this a better reply
|
||||
cmd_output->json_output = sstrdup("{\"success\": true}");
|
||||
|
|
|
@ -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
|
||||
############################################################
|
||||
|
|
Loading…
Reference in New Issue