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*:
*/
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).
*
* 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
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;
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)
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).
*
*
*/
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);
}
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) {
hide_edge_borders vertical
hide_edge_borders horizontal
hide_edge_borders both
+hide_edge_borders smart
EOT
$expected = <<'EOT';
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),
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: ^^^^^^
--- /dev/null
+#!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;