Implement 'resize set <width> ppt <height> ppt' command for tiling windows (#3036)

This commit is contained in:
livanh 2018-01-08 23:25:08 +01:00 committed by Michael Stapelberg
parent 1a04608796
commit 7b59da8a4f
4 changed files with 218 additions and 9 deletions

View File

@ -2320,8 +2320,11 @@ 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 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 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 many percentage points a *tiling container* should be grown or shrunk (the
default is 10 percentage points). Note that +resize set+ will only work for default is 10 percentage points).
floating containers.
Notes about +resize set+: a value of 0 for <width> or <height> means "do
not resize in this direction", and resizing a tiling container by +px+ is not
implemented.
It is recommended to define bindings for resizing in a dedicated binding mode. It is recommended to define bindings for resizing in a dedicated binding mode.
See <<binding_modes>> and the example in the i3 See <<binding_modes>> and the example in the i3

View File

@ -63,7 +63,7 @@ void cmd_move_con_to_workspace_name(I3_CMD, const char *name, const char *no_aut
void cmd_move_con_to_workspace_number(I3_CMD, const char *which, const char *no_auto_back_and_forth); void cmd_move_con_to_workspace_number(I3_CMD, const char *which, const char *no_auto_back_and_forth);
/** /**
* Implementation of 'resize set <px> [px] <px> [px]'. * Implementation of 'resize set <width> [px | ppt] <height> [px | ppt]'.
* *
*/ */
void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height); void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height);

View File

@ -659,7 +659,7 @@ void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px,
*/ */
void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height) { void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height) {
DLOG("resizing to %ld %s x %ld %s\n", cwidth, mode_width, cheight, mode_height); DLOG("resizing to %ld %s x %ld %s\n", cwidth, mode_width, cheight, mode_height);
if (cwidth <= 0 || cheight <= 0) { if (cwidth < 0 || cheight < 0) {
ELOG("Resize failed: dimensions cannot be negative (was %ld %s x %ld %s)\n", cwidth, mode_width, cheight, mode_height); ELOG("Resize failed: dimensions cannot be negative (was %ld %s x %ld %s)\n", cwidth, mode_width, cheight, mode_height);
return; return;
} }
@ -667,25 +667,84 @@ void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, c
HANDLE_EMPTY_MATCH; HANDLE_EMPTY_MATCH;
owindow *current; owindow *current;
bool success = true;
TAILQ_FOREACH(current, &owindows, owindows) { TAILQ_FOREACH(current, &owindows, owindows) {
Con *floating_con; Con *floating_con;
if ((floating_con = con_inside_floating(current->con))) { if ((floating_con = con_inside_floating(current->con))) {
Con *output = con_get_output(floating_con); Con *output = con_get_output(floating_con);
if (mode_width && strcmp(mode_width, "ppt") == 0) { if (cwidth == 0) {
cwidth = output->rect.width;
} else if (mode_width && strcmp(mode_width, "ppt") == 0) {
cwidth = output->rect.width * ((double)cwidth / 100.0); cwidth = output->rect.width * ((double)cwidth / 100.0);
} }
if (mode_height && strcmp(mode_height, "ppt") == 0) { if (cheight == 0) {
cheight = output->rect.height;
} else if (mode_height && strcmp(mode_height, "ppt") == 0) {
cheight = output->rect.height * ((double)cheight / 100.0); cheight = output->rect.height * ((double)cheight / 100.0);
} }
floating_resize(floating_con, cwidth, cheight); floating_resize(floating_con, cwidth, cheight);
} else { } else {
ELOG("Resize failed: %p not a floating container\n", current->con); if (current->con->window && current->con->window->dock) {
DLOG("This is a dock window. Not resizing (con = %p)\n)", current->con);
continue;
}
if (cwidth > 0 && mode_width && strcmp(mode_width, "ppt") == 0) {
/* get the appropriate current container (skip stacked/tabbed cons) */
Con *target = current->con;
Con *dummy;
resize_find_tiling_participants(&target, &dummy, D_LEFT, true);
/* Calculate new size for the target container */
double current_percent = target->percent;
char *action_string;
long adjustment;
if (current_percent > cwidth) {
action_string = "shrink";
adjustment = (int)(current_percent * 100) - cwidth;
} else {
action_string = "grow";
adjustment = cwidth - (int)(current_percent * 100);
}
/* perform resizing and report failure if not possible */
if (!cmd_resize_tiling_width_height(current_match, cmd_output,
target, action_string, "width", adjustment)) {
success = false;
}
}
if (cheight > 0 && mode_width && strcmp(mode_width, "ppt") == 0) {
/* get the appropriate current container (skip stacked/tabbed cons) */
Con *target = current->con;
Con *dummy;
resize_find_tiling_participants(&target, &dummy, D_DOWN, true);
/* Calculate new size for the target container */
double current_percent = target->percent;
char *action_string;
long adjustment;
if (current_percent > cheight) {
action_string = "shrink";
adjustment = (int)(current_percent * 100) - cheight;
} else {
action_string = "grow";
adjustment = cheight - (int)(current_percent * 100);
}
/* perform resizing and report failure if not possible */
if (!cmd_resize_tiling_width_height(current_match, cmd_output,
target, action_string, "height", adjustment)) {
success = false;
}
}
} }
} }
cmd_output->needs_tree_render = true; cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply ysuccess(success);
ysuccess(true);
} }
/* /*

View File

@ -0,0 +1,147 @@
#!perl
# vim:ts=4:sw=4:expandtab
#
# Please read the following documents before working on tests:
# • https://build.i3wm.org/docs/testsuite.html
# (or docs/testsuite)
#
# • https://build.i3wm.org/docs/lib-i3test.html
# (alternatively: perldoc ./testcases/lib/i3test.pm)
#
# • https://build.i3wm.org/docs/ipc.html
# (or docs/ipc)
#
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
# (unless you are already familiar with Perl)
#
# Tests resizing tiling containers
use i3test;
############################################################
# resize horizontally
############################################################
my $tmp = fresh_workspace;
cmd 'split h';
my $left = open_window;
my $right = open_window;
diag("left = " . $left->id . ", right = " . $right->id);
is($x->input_focus, $right->id, 'Right window focused');
cmd 'resize set 75 ppt 0 ppt';
my ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left window got only 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right window got 75%');
############################################################
# resize vertically
############################################################
my $tmp = fresh_workspace;
cmd 'split v';
my $top = open_window;
my $bottom = open_window;
diag("top = " . $top->id . ", bottom = " . $bottom->id);
is($x->input_focus, $bottom->id, 'Bottom window focused');
cmd 'resize set 0 ppt 75 ppt';
my ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'top window got only 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'bottom window got 75%');
############################################################
# resize horizontally and vertically
############################################################
my $tmp = fresh_workspace;
cmd 'split h';
my $left = open_window;
my $top_right = open_window;
cmd 'split v';
my $bottom_right = open_window;
diag("left = " . $left->id . ", top-right = " . $top_right->id . ", bottom-right = " . $bottom_right->id);
is($x->input_focus, $bottom_right->id, 'Bottom-right window focused');
cmd 'resize set 75 ppt 75 ppt';
my ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
cmp_float($nodes->[1]->{nodes}->[0]->{percent}, 0.25, 'top-right window got 25%');
cmp_float($nodes->[1]->{nodes}->[1]->{percent}, 0.75, 'bottom-right window got 75%');
############################################################
# resize from inside a tabbed container
############################################################
my $tmp = fresh_workspace;
cmd 'split h';
my $left = open_window;
my $right1 = open_window;
cmd 'split h';
cmd 'layout tabbed';
my $right2 = open_window;
diag("left = " . $left->id . ", right1 = " . $right1->id . ", right2 = " . $right2->id);
is($x->input_focus, $right2->id, '2nd right window focused');
cmd 'resize set 75 ppt 0 ppt';
my ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
############################################################
# resize from inside a stacked container
############################################################
my $tmp = fresh_workspace;
cmd 'split h';
my $left = open_window;
my $right1 = open_window;
cmd 'split h';
cmd 'layout stacked';
my $right2 = open_window;
diag("left = " . $left->id . ", right1 = " . $right1->id . ", right2 = " . $right2->id);
is($x->input_focus, $right2->id, '2nd right window focused');
cmd 'resize set 75 ppt 0 ppt';
my ($nodes, $focus) = get_ws_content($tmp);
cmp_float($nodes->[0]->{percent}, 0.25, 'left container got 25%');
cmp_float($nodes->[1]->{percent}, 0.75, 'right container got 75%');
done_testing;