From 7b59da8a4f9e7aa93ec0cc68ee60bebf3d97a604 Mon Sep 17 00:00:00 2001 From: livanh Date: Mon, 8 Jan 2018 23:25:08 +0100 Subject: [PATCH] Implement 'resize set ppt ppt' command for tiling windows (#3036) --- docs/userguide | 7 +- include/commands.h | 2 +- src/commands.c | 71 ++++++++++++-- testcases/t/541-resize-set-tiling.t | 147 ++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 9 deletions(-) create mode 100644 testcases/t/541-resize-set-tiling.t diff --git a/docs/userguide b/docs/userguide index 98242a9b..974135ac 100644 --- a/docs/userguide +++ b/docs/userguide @@ -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 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). Note that +resize set+ will only work for -floating containers. +default is 10 percentage points). + +Notes about +resize set+: a value of 0 for or 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. See <> and the example in the i3 diff --git a/include/commands.h b/include/commands.h index 85d5fe78..1057f021 100644 --- a/include/commands.h +++ b/include/commands.h @@ -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); /** - * Implementation of 'resize set [px] [px]'. + * Implementation of 'resize set [px | ppt] [px | ppt]'. * */ void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, const char *mode_height); diff --git a/src/commands.c b/src/commands.c index 136184af..1263a56b 100644 --- a/src/commands.c +++ b/src/commands.c @@ -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) { 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); return; } @@ -667,25 +667,84 @@ void cmd_resize_set(I3_CMD, long cwidth, const char *mode_width, long cheight, c HANDLE_EMPTY_MATCH; owindow *current; + bool success = true; TAILQ_FOREACH(current, &owindows, owindows) { Con *floating_con; if ((floating_con = con_inside_floating(current->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); } - 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); } floating_resize(floating_con, cwidth, cheight); } 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; - // XXX: default reply for now, make this a better reply - ysuccess(true); + ysuccess(success); } /* diff --git a/testcases/t/541-resize-set-tiling.t b/testcases/t/541-resize-set-tiling.t new file mode 100644 index 00000000..82267baf --- /dev/null +++ b/testcases/t/541-resize-set-tiling.t @@ -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; -- 2.39.5