]> git.sur5r.net Git - i3/i3/commitdiff
Make cmd_resize_tiling_direction work with pixels
authorOrestis Floros <orestisf1993@gmail.com>
Thu, 23 Aug 2018 19:09:52 +0000 (22:09 +0300)
committerOrestis Floros <orestisf1993@gmail.com>
Fri, 24 Aug 2018 01:13:03 +0000 (04:13 +0300)
Introduces resize_neighboring_cons in resize.c which is also used by
resize_graphical_handler.

Co-authored-by: Andrew Laucius <andrewla@gmail.com>
Authored original code and tests in #3240. I rewrote most of the
resizing code and fixed the failing tests.

docs/userguide
include/resize.h
parser-specs/commands.spec
src/commands.c
src/resize.c
testcases/t/141-resize.t
testcases/t/187-commands-parser.t

index 2746f24e346c5decdf83b6118d7b673a05e7dbb1..1c85feb60346d7a4eac2fbcc980862d304b977c1 100644 (file)
@@ -2330,12 +2330,12 @@ resize set [width] <width> [px | ppt] [height] <height> [px | ppt]
 -------------------------------------------------------
 
 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).
+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 container should be grown or shrunk (the default is 10 pixels). The
+optional ppt argument means "percentage points", and if specified it indicates
+that a *tiling container* should be grown or shrunk by that many points, instead
+of by the +px+ value.
 
 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
index 234f4b1faaa3cee008437a8357d8856142649296..758cb4a1a28376f5e4bdd4d9d8c1ccc305fc5742 100644 (file)
 bool resize_find_tiling_participants(Con **current, Con **other, direction_t direction, bool both_sides);
 
 void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event);
+
+/**
+ * Resize the two given containers using the given amount of pixels or
+ * percentage points. One of the two needs to be 0. A positive amount means
+ * growing the first container while a negative means shrinking it.
+ * Returns false when the resize would result in one of the two containers
+ * having less than 1 pixel of size.
+ *
+ */
+bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt);
+
+/**
+ * Calculate the given container's new percent given a change in pixels.
+ *
+ */
+double px_resize_to_percent(Con *con, int px_diff);
index c0c32933c3a0f69c2fdde5fbe4b2933e757d0660..6b015188e3584dd4cd4718ece5c531447bdaa2c5 100644 (file)
@@ -243,7 +243,7 @@ state RESIZE_TILING:
   'or'
       -> RESIZE_TILING_OR
   end
-      -> call cmd_resize($way, $direction, &resize_px, 10)
+      -> call cmd_resize($way, $direction, &resize_px, 0)
 
 state RESIZE_TILING_OR:
   resize_ppt = number
index 0a2f3424f5f6984adbb2519ed0f79e1f64808a7e..99c5368e0d7fc8ba647d3d659a0a06cbcf0f056c 100644 (file)
@@ -497,47 +497,23 @@ static void cmd_resize_floating(I3_CMD, const char *way, const char *direction_s
     }
 }
 
-static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *way, const char *direction, int ppt) {
-    LOG("tiling resize\n");
+static bool cmd_resize_tiling_direction(I3_CMD, Con *current, const char *way, const char *direction, int px, int ppt) {
     Con *second = NULL;
     Con *first = current;
     direction_t search_direction = parse_direction(direction);
 
     bool res = resize_find_tiling_participants(&first, &second, search_direction, false);
     if (!res) {
-        LOG("No second container in this direction found.\n");
-        ysuccess(false);
+        yerror("No second container found in this direction.\n");
         return false;
     }
 
-    /* get the default percentage */
-    int children = con_num_children(first->parent);
-    LOG("ins. %d children\n", children);
-    double percentage = 1.0 / children;
-    LOG("default percentage = %f\n", percentage);
-
-    /* resize */
-    LOG("first->percent before = %f\n", first->percent);
-    LOG("second->percent before = %f\n", second->percent);
-    if (first->percent == 0.0)
-        first->percent = percentage;
-    if (second->percent == 0.0)
-        second->percent = percentage;
-    double new_first_percent = first->percent + ((double)ppt / 100.0);
-    double new_second_percent = second->percent - ((double)ppt / 100.0);
-    LOG("new_first_percent = %f\n", new_first_percent);
-    LOG("new_second_percent = %f\n", new_second_percent);
-    /* Ensure that the new percentages are positive. */
-    if (new_first_percent > 0.0 && new_second_percent > 0.0) {
-        first->percent = new_first_percent;
-        second->percent = new_second_percent;
-        LOG("first->percent after = %f\n", first->percent);
-        LOG("second->percent after = %f\n", second->percent);
-    } else {
-        LOG("Not resizing, already at minimum size\n");
+    if (ppt) {
+        /* For backwards compatibility, 'X px or Y ppt' means that ppt is
+         * preferred. */
+        px = 0;
     }
-
-    return true;
+    return resize_neighboring_cons(first, second, px, ppt);
 }
 
 static bool cmd_resize_tiling_width_height(I3_CMD, Con *current, const char *way, const char *direction, int ppt) {
@@ -631,7 +607,8 @@ void cmd_resize(I3_CMD, const char *way, const char *direction, long resize_px,
                     return;
             } else {
                 if (!cmd_resize_tiling_direction(current_match, cmd_output,
-                                                 current->con, way, direction, resize_ppt))
+                                                 current->con, way, direction,
+                                                 resize_px, resize_ppt))
                     return;
             }
         }
index 1f8ede1037d213a635e64e36573e339fdb280bbb..38591b457030ed9674fa513f58d5f3861335f3b3 100644 (file)
@@ -101,6 +101,53 @@ bool resize_find_tiling_participants(Con **current, Con **other, direction_t dir
     return true;
 }
 
+/*
+ * Calculate the given container's new percent given a change in pixels.
+ *
+ */
+double px_resize_to_percent(Con *con, int px_diff) {
+    Con *parent = con->parent;
+    const orientation_t o = con_orientation(parent);
+    const int total = (o == HORIZ ? parent->rect.width : parent->rect.height);
+    /* deco_rect.height is subtracted from each child in render_con_split */
+    const int target = px_diff + (o == HORIZ ? con->rect.width : con->rect.height + con->deco_rect.height);
+    return ((double)target / (double)total);
+}
+
+/*
+ * Resize the two given containers using the given amount of pixels or
+ * percentage points. One of the two needs to be 0. A positive amount means
+ * growing the first container while a negative means shrinking it.
+ * Returns false when the resize would result in one of the two containers
+ * having less than 1 pixel of size.
+ *
+ */
+bool resize_neighboring_cons(Con *first, Con *second, int px, int ppt) {
+    assert(px * ppt == 0);
+
+    Con *parent = first->parent;
+    orientation_t orientation = con_orientation(parent);
+    const int total = (orientation == HORIZ ? parent->rect.width : parent->rect.height);
+    double new_first_percent;
+    double new_second_percent;
+    if (ppt) {
+        new_first_percent = first->percent + ((double)ppt / 100.0);
+        new_second_percent = second->percent - ((double)ppt / 100.0);
+    } else {
+        new_first_percent = px_resize_to_percent(first, px);
+        new_second_percent = second->percent + first->percent - new_first_percent;
+    }
+    /* Ensure that no container will be less than 1 pixel in the resizing
+     * direction. */
+    if (lround(new_first_percent * total) <= 0 || lround(new_second_percent * total) <= 0) {
+        return false;
+    }
+
+    first->percent = new_first_percent;
+    second->percent = new_second_percent;
+    con_fix_percent(parent);
+    return true;
+}
 
 void resize_graphical_handler(Con *first, Con *second, orientation_t orientation, const xcb_button_press_event_t *event) {
     Con *output = con_get_output(first);
@@ -179,24 +226,7 @@ void resize_graphical_handler(Con *first, Con *second, orientation_t orientation
     /* if we got thus far, the containers must have valid percentages. */
     assert(first->percent > 0.0);
     assert(second->percent > 0.0);
-
-    /* calculate the new percentage for the first container */
-    double new_percent, difference;
-    double percent = first->percent;
-    DLOG("percent = %f\n", percent);
-    int original = (orientation == HORIZ ? first->rect.width : first->rect.height);
-    DLOG("original = %d\n", original);
-    new_percent = (original + pixels) * (percent / original);
-    difference = percent - new_percent;
-    DLOG("difference = %f\n", difference);
-    DLOG("new percent = %f\n", new_percent);
-    first->percent = new_percent;
-
-    /* calculate the new percentage for the second container */
-    double s_percent = second->percent;
-    second->percent = s_percent + difference;
-    DLOG("second->percent = %f\n", second->percent);
-
-    /* now we must make sure that the sum of the percentages remain 1.0 */
-    con_fix_percent(first->parent);
+    const bool result = resize_neighboring_cons(first, second, pixels, 0);
+    DLOG("Graphical resize %s: first->percent = %f, second->percent = %f.\n",
+         result ? "successful" : "failed", first->percent, second->percent);
 }
index 0e7fd526b75e9d450a532c92cfad26268d621d3d..7e8249f1cc5d0ba94a0375195414df3d72ae9085 100644 (file)
@@ -141,6 +141,81 @@ cmp_float($nodes->[1]->{percent}, 0.166666666666667, 'second window got 16%');
 cmp_float($nodes->[2]->{percent}, 0.166666666666667, 'third window got 16%');
 cmp_float($nodes->[3]->{percent}, 0.50, 'fourth window got 50%');
 
+################################################################################
+# Check that we can grow tiled windows by pixels
+################################################################################
+
+$tmp = fresh_workspace;
+
+$left = open_window;
+$right = open_window;
+
+($nodes, $focus) = get_ws_content($tmp);
+cmp_float($nodes->[0]->{rect}->{width}, 640, 'left window is 640px');
+cmp_float($nodes->[1]->{rect}->{width}, 640, 'right window is 640px');
+
+cmd 'resize grow left 10px';
+($nodes, $focus) = get_ws_content($tmp);
+cmp_float($nodes->[0]->{rect}->{width}, 630, 'left window is 630px');
+cmp_float($nodes->[1]->{rect}->{width}, 650, 'right window is 650px');
+
+################################################################################
+# Check that we can shrink tiled windows by pixels
+################################################################################
+
+$tmp = fresh_workspace;
+
+$left = open_window;
+$right = open_window;
+
+($nodes, $focus) = get_ws_content($tmp);
+cmp_float($nodes->[0]->{rect}->{width}, 640, 'left window is 640px');
+cmp_float($nodes->[1]->{rect}->{width}, 640, 'right window is 640px');
+
+cmd 'resize shrink left 10px';
+($nodes, $focus) = get_ws_content($tmp);
+cmp_float($nodes->[0]->{rect}->{width}, 650, 'left window is 650px');
+cmp_float($nodes->[1]->{rect}->{width}, 630, 'right window is 630px');
+
+
+################################################################################
+# Check that we can shrink vertical tiled windows by pixels
+################################################################################
+
+$tmp = fresh_workspace;
+
+cmd 'split v';
+
+$top = open_window;
+$bottom = open_window;
+
+($nodes, $focus) = get_ws_content($tmp);
+my @heights = ($nodes->[0]->{rect}->{height}, $nodes->[1]->{rect}->{height});
+
+cmd 'resize grow up 10px';
+($nodes, $focus) = get_ws_content($tmp);
+cmp_float($nodes->[0]->{rect}->{height}, $heights[0] - 10, 'top window is 10px larger');
+cmp_float($nodes->[1]->{rect}->{height}, $heights[1] + 10, 'bottom window is 10px smaller');
+
+################################################################################
+# Check that we can shrink vertical tiled windows by pixels
+################################################################################
+
+$tmp = fresh_workspace;
+
+cmd 'split v';
+
+$top = open_window;
+$bottom = open_window;
+
+($nodes, $focus) = get_ws_content($tmp);
+my @heights = ($nodes->[0]->{rect}->{height}, $nodes->[1]->{rect}->{height});
+
+cmd 'resize shrink up 10px';
+($nodes, $focus) = get_ws_content($tmp);
+cmp_float($nodes->[0]->{rect}->{height}, $heights[0] + 10, 'top window is 10px smaller');
+cmp_float($nodes->[1]->{rect}->{height}, $heights[1] - 10, 'bottom window is 10px larger');
+
 ################################################################################
 # Check that the resize grow/shrink width/height syntax works if a nested split
 # was set on the container, but no sibling has been opened yet. See #2015.
index 39da19d8aeefd578903f25f86bf4c0046783a175..48f50e8d1266f2dad143e87d8973bbc531d88437 100644 (file)
@@ -86,9 +86,9 @@ is(parser_calls(
    'resize shrink left 25 px or 33 ppt; ' .
    'resize shrink left 25'),
    "cmd_resize(shrink, left, 10, 10)\n" .
-   "cmd_resize(shrink, left, 25, 10)\n" .
+   "cmd_resize(shrink, left, 25, 0)\n" .
    "cmd_resize(shrink, left, 25, 33)\n" .
-   "cmd_resize(shrink, left, 25, 10)",
+   "cmd_resize(shrink, left, 25, 0)",
    'simple resize ok');
 
 is(parser_calls('resize shrink left 25 px or 33 ppt,'),