]> git.sur5r.net Git - i3/i3/commitdiff
Smart option added to hide_edge_borders config param (#2191) (#2191)
authorJulien Lequertier <avrelaun@users.noreply.github.com>
Tue, 10 May 2016 18:27:20 +0000 (20:27 +0200)
committerMichael Stapelberg <stapelberg@users.noreply.github.com>
Tue, 10 May 2016 18:27:20 +0000 (20:27 +0200)
Use case:

* When managing multiple terminals in a workspace, the borders makes it easier
to know where the focus is, but when there is only one it's obvious where the
focus is.

* When there's only a web browser for example, the borders are actually counter-
productive since it makes clicking a side scrollbar or a tab a bit harder (if I
smash my cursor to the side or the top of the workspace, I have to move it in
the other direction by just a few pixels to be able to grab it)

Behaviour:

* No borders when there's a single window in a workspace
* Borders when there are multiple windows in a workspace

fixes #2188

docs/userguide
include/con.h
include/config.h
include/data.h
parser-specs/config.spec
src/con.c
src/config_directives.c
testcases/t/201-config-parser.t
testcases/t/263-edge-borders.t [new file with mode: 0644]

index d9cfc642b99b47d04f4633a3a4cc76f880e1d94e..9abdd5b0cea8a631dfd45e89dc8f5306803073e0 100644 (file)
@@ -610,11 +610,13 @@ new_window pixel 3
 
 You can hide container borders adjacent to the screen edges using
 +hide_edge_borders+. This is useful if you are using scrollbars, or do not want
-to waste even two pixels in displayspace. Default is none.
+to waste even two pixels in displayspace. The "smart" setting hides borders on
+workspaces with only one window visible, but keeps them on workspaces with
+multiple windows visible. Default is none.
 
 *Syntax*:
 -----------------------------------------------
-hide_edge_borders none|vertical|horizontal|both
+hide_edge_borders none|vertical|horizontal|both|smart
 -----------------------------------------------
 
 *Example*:
index 7fa7facfa6feb67cab1f076da7f2bee2c16975ed..73ae0f38db239e4a84001a262abfc91a0c4e3aff 100644 (file)
@@ -200,6 +200,13 @@ Con *con_for_window(Con *con, i3Window *window, Match **store_match);
  */
 int con_num_children(Con *con);
 
+/**
+ * Returns the number of visible non-floating children of this container.
+ * For example, if the container contains a hsplit which has two children,
+ * this will return 2 instead of 1.
+ */
+int con_num_visible_children(Con *con);
+
 /**
  * Count the number of windows (i.e., leaf containers).
  *
index acdd2c8999ddc40f57e2830b7f97c37c4d9c059a..699cc882acc9a7c657526e4a54816248af7c1547 100644 (file)
@@ -125,7 +125,7 @@ struct Config {
      * This is useful if you are reaching scrollbar on the edge of the
      * screen or do not want to waste a single pixel of displayspace.
      * By default, this is disabled. */
-    adjacent_t hide_edge_borders;
+    hide_edge_borders_mode_t hide_edge_borders;
 
     /** By default, a workspace bar is drawn at the bottom of the screen.
      * If you want to have a more fancy bar, it is recommended to replace
index 3a059e7bf7d3898ebb6613f18687065823ab43f9..88ed6879de53b0016d260941ff9ae0b898947333 100644 (file)
@@ -75,6 +75,12 @@ typedef enum { ADJ_NONE = 0,
                ADJ_UPPER_SCREEN_EDGE = (1 << 2),
                ADJ_LOWER_SCREEN_EDGE = (1 << 4) } adjacent_t;
 
+typedef enum { HEBM_NONE = ADJ_NONE,
+               HEBM_VERTICAL = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE,
+               HEBM_HORIZONTAL = ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE,
+               HEBM_BOTH = HEBM_VERTICAL | HEBM_HORIZONTAL,
+               HEBM_SMART = (1 << 5) } hide_edge_borders_mode_t;
+
 typedef enum { MM_REPLACE,
                MM_ADD } mark_mode_t;
 
index 24f40802b8dac4e8e6edab16bd6beffe5389d860..eeafaac868c1b42962a70ff406ef8a68c064aca5 100644 (file)
@@ -122,10 +122,10 @@ state NEW_WINDOW_PIXELS_PX:
   end
       -> call cfg_new_window($windowtype, $border, &width)
 
-# hide_edge_borders <none|vertical|horizontal|both>
+# hide_edge_borders <none|vertical|horizontal|both|smart>
 # also hide_edge_borders <bool> for compatibility
 state HIDE_EDGE_BORDERS:
-  hide_borders = 'none', 'vertical', 'horizontal', 'both'
+  hide_borders = 'none', 'vertical', 'horizontal', 'both', 'smart'
       -> call cfg_hide_edge_borders($hide_borders)
   hide_borders = '1', 'yes', 'true', 'on', 'enable', 'active'
       -> call cfg_hide_edge_borders($hide_borders)
index 2c637a1f7d91f80a3084bfa4f9db770a62c0de7e..dbb6d6014559a895d006198dceee1b932bab14e4 100644 (file)
--- a/src/con.c
+++ b/src/con.c
@@ -727,6 +727,29 @@ int con_num_children(Con *con) {
     return children;
 }
 
+/**
+ * Returns the number of visible non-floating children of this container.
+ * For example, if the container contains a hsplit which has two children,
+ * this will return 2 instead of 1.
+ */
+int con_num_visible_children(Con *con) {
+    if (con == NULL)
+        return 0;
+
+    int children = 0;
+    Con *current = NULL;
+    TAILQ_FOREACH(current, &(con->nodes_head), nodes) {
+        /* Visible leaf nodes are a child. */
+        if (!con_is_hidden(current) && con_is_leaf(current))
+            children++;
+        /* All other containers need to be recursed. */
+        else
+            children += con_num_visible_children(current);
+    }
+
+    return children;
+}
+
 /*
  * Count the number of windows (i.e., leaf containers).
  *
@@ -1444,6 +1467,12 @@ Con *con_descend_direction(Con *con, direction_t direction) {
  *
  */
 Rect con_border_style_rect(Con *con) {
+    if (config.hide_edge_borders == HEBM_SMART && con_num_visible_children(con_get_workspace(con)) <= 1) {
+        if (!con_is_floating(con)) {
+            return (Rect){0, 0, 0, 0};
+        }
+    }
+
     adjacent_t borders_to_hide = ADJ_NONE;
     int border_width = con->current_border_width;
     DLOG("The border width for con is set to: %d\n", con->current_border_width);
index ec99321a9849b8b708010c4848769c203e80cffe..05c19c70628b1d0fff12e286a45e97c63b4f0352 100644 (file)
@@ -223,18 +223,20 @@ CFGFUN(new_window, const char *windowtype, const char *border, const long width)
 }
 
 CFGFUN(hide_edge_borders, const char *borders) {
-    if (strcmp(borders, "vertical") == 0)
-        config.hide_edge_borders = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE;
+    if (strcmp(borders, "smart") == 0)
+        config.hide_edge_borders = HEBM_SMART;
+    else if (strcmp(borders, "vertical") == 0)
+        config.hide_edge_borders = HEBM_VERTICAL;
     else if (strcmp(borders, "horizontal") == 0)
-        config.hide_edge_borders = ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE;
+        config.hide_edge_borders = HEBM_HORIZONTAL;
     else if (strcmp(borders, "both") == 0)
-        config.hide_edge_borders = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE | ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE;
+        config.hide_edge_borders = HEBM_BOTH;
     else if (strcmp(borders, "none") == 0)
-        config.hide_edge_borders = ADJ_NONE;
+        config.hide_edge_borders = HEBM_NONE;
     else if (eval_boolstr(borders))
-        config.hide_edge_borders = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE;
+        config.hide_edge_borders = HEBM_VERTICAL;
     else
-        config.hide_edge_borders = ADJ_NONE;
+        config.hide_edge_borders = HEBM_NONE;
 }
 
 CFGFUN(focus_follows_mouse, const char *value) {
index bcccc5a2e5fdf1f2f5db0d77506b091db44abf4e..d3da42354ba4e012cb2a3fb2c2c5ca6374c09f9b 100644 (file)
@@ -286,6 +286,7 @@ hide_edge_borders none
 hide_edge_borders vertical
 hide_edge_borders horizontal
 hide_edge_borders both
+hide_edge_borders smart
 EOT
 
 $expected = <<'EOT';
@@ -293,6 +294,7 @@ cfg_hide_edge_borders(none)
 cfg_hide_edge_borders(vertical)
 cfg_hide_edge_borders(horizontal)
 cfg_hide_edge_borders(both)
+cfg_hide_edge_borders(smart)
 EOT
 
 is(parser_calls($config),
@@ -464,7 +466,7 @@ client.focused          #4c7899 #285577 #ffffff #2e9ef4
 EOT
 
 $expected = <<'EOT';
-ERROR: CONFIG: Expected one of these tokens: 'none', 'vertical', 'horizontal', 'both', '1', 'yes', 'true', 'on', 'enable', 'active'
+ERROR: CONFIG: Expected one of these tokens: 'none', 'vertical', 'horizontal', 'both', 'smart', '1', 'yes', 'true', 'on', 'enable', 'active'
 ERROR: CONFIG: (in file <stdin>)
 ERROR: CONFIG: Line   1: hide_edge_borders FOOBAR
 ERROR: CONFIG:                             ^^^^^^
diff --git a/testcases/t/263-edge-borders.t b/testcases/t/263-edge-borders.t
new file mode 100644 (file)
index 0000000..0d14c65
--- /dev/null
@@ -0,0 +1,159 @@
+#!perl
+# vim:ts=4:sw=4:expandtab
+#
+# Please read the following documents before working on tests:
+# • http://build.i3wm.org/docs/testsuite.html
+#   (or docs/testsuite)
+#
+# • http://build.i3wm.org/docs/lib-i3test.html
+#   (alternatively: perldoc ./testcases/lib/i3test.pm)
+#
+# • http://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 that the hide_edge_borders smart option works
+# Ticket: #2188
+
+use i3test i3_autostart => 0;
+
+####################################################################
+# 1: check that the borders are present on a floating windows
+#####################################################################
+
+my $config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+my $pid = launch_with_config($config);
+
+my $tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+my $floatwindow = open_floating_window;
+
+my $wscontent = get_ws($tmp);
+
+my @floating = @{$wscontent->{floating_nodes}};
+ok(@floating == 1, 'one floating container opened');
+is($floating[0]->{nodes}[0]->{current_border_width}, 2, 'floating current border width set to 2');
+is($floatwindow->rect->width, $floating[0]->{rect}->{width} - 2*2, 'floating border width 2');
+
+exit_gracefully($pid);
+
+#####################################################################
+# 2: check that the borders are present on a workspace with two tiled
+# windows visible
+#####################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+$pid = launch_with_config($config);
+
+$tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+my $tilewindow = open_window;
+my $tilewindow2 = open_window;
+
+$wscontent = get_ws($tmp);
+
+my @tiled = @{$wscontent->{nodes}};
+ok(@tiled == 2, 'two tiled container opened');
+is($tiled[0]->{current_border_width}, 2, 'first tiled current border width set to 2');
+is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*2, 'first tiled border width 2');
+is($tiled[1]->{current_border_width}, 2, 'second tiled current border width set to 2');
+is($tilewindow2->rect->width, $tiled[1]->{rect}->{width} - 2*2, 'second tiled border width 2');
+
+exit_gracefully($pid);
+
+#####################################################################
+# 3: check that the borders are hidden on a workspace with one tiled
+# window visible
+#####################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+$pid = launch_with_config($config);
+
+$tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+$tilewindow = open_window;
+
+$wscontent = get_ws($tmp);
+
+@tiled = @{$wscontent->{nodes}};
+ok(@tiled == 1, 'one tiled container opened');
+is($tiled[0]->{current_border_width}, 2, 'tiled current border width set to 2');
+is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*0, 'single tiled border width 0');
+
+exit_gracefully($pid);
+
+#####################################################################
+# 4: check that the borders are present on a workspace with two tiled
+# windows visible, recursively
+#####################################################################
+
+$config = <<EOT;
+# i3 config file (v4)
+font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+
+new_window pixel 2
+new_float pixel 2
+hide_edge_borders smart
+EOT
+
+$pid = launch_with_config($config);
+
+$tmp = fresh_workspace;
+
+ok(@{get_ws_content($tmp)} == 0, 'no containers yet');
+
+$tilewindow = open_window;
+$tilewindow2 = open_window;
+ok(@{get_ws_content($tmp)} == 2, 'two containers opened');
+
+cmd 'layout tabbed';
+ok(@{get_ws_content($tmp)} == 1, 'layout tabbed -> back to one container');
+
+cmd 'focus parent';
+my $tilewindow3 = open_window;
+ok(@{get_ws_content($tmp)} == 2, 'after split & new window, two containers');
+
+$wscontent = get_ws($tmp);
+
+@tiled = @{$wscontent->{nodes}};
+ok(@tiled == 2, 'two tiled container opened in another container');
+is($tiled[0]->{current_border_width}, -1, 'first tiled current border width set to -1');
+is($tilewindow->rect->width, $tiled[0]->{rect}->{width} - 2*2, 'first tiled border width 2');
+is($tiled[1]->{current_border_width}, 2, 'second tiled current border width set to 2');
+is($tilewindow2->rect->width, $tiled[1]->{rect}->{width} - 2*2, 'second tiled border width 2');
+
+exit_gracefully($pid);
+
+done_testing;