i3: bump version 4.23 -> 4.24
This commit is contained in:
@@ -1,454 +0,0 @@
|
||||
From b660d6a902cf44be22c434101dd2a4e6743e26bc Mon Sep 17 00:00:00 2001
|
||||
From: sethpollen <seth.pollen@gmail.com>
|
||||
Date: Mon, 22 Jan 2024 13:34:40 -0600
|
||||
Subject: [PATCH] Add support for _NET_WM_STATE_MAXIMIZED_{HORZ, VERT} (#5840)
|
||||
|
||||
If a window occupies the entirety of its workspace vertically and/or horizontally, pass it the _NET_WM_STATE_MAXIMIZED_{HORZ, VERT} atoms. This helps applications like Google Chrome draw the tab bar correctly and handle tab clicks correctly (see https://crbug.com/1495853).
|
||||
|
||||
This change is based on work from @yshui in #2380.
|
||||
---
|
||||
include/con.h | 16 +++
|
||||
include/i3-atoms_NET_SUPPORTED.xmacro.h | 2 +
|
||||
.../changes/2-net-wrm-state-maximized | 1 +
|
||||
src/con.c | 59 ++++++++++
|
||||
src/x.c | 41 +++++++
|
||||
testcases/lib/i3test.pm.in | 15 +--
|
||||
testcases/t/158-wm_take_focus.t | 7 +-
|
||||
testcases/t/283-net-wm-state-hidden.t | 23 +---
|
||||
testcases/t/295-net-wm-state-focused.t | 15 ++-
|
||||
testcases/t/551-net-wm-state-maximized.t | 104 ++++++++++++++++++
|
||||
10 files changed, 245 insertions(+), 38 deletions(-)
|
||||
create mode 100644 release-notes/changes/2-net-wrm-state-maximized
|
||||
create mode 100644 testcases/t/551-net-wm-state-maximized.t
|
||||
|
||||
diff --git a/include/con.h b/include/con.h
|
||||
index e1bb6813af..52f588b8bc 100644
|
||||
--- a/include/con.h
|
||||
+++ b/include/con.h
|
||||
@@ -83,6 +83,22 @@ bool con_is_split(Con *con);
|
||||
*/
|
||||
bool con_is_hidden(Con *con);
|
||||
|
||||
+/**
|
||||
+ * Returns true if the container is maximized in the given orientation.
|
||||
+ *
|
||||
+ * If the container is floating or fullscreen, it is not considered maximized.
|
||||
+ * Otherwise, it is maximized if it doesn't share space with any other
|
||||
+ * container in the given orientation. For example, if a workspace contains
|
||||
+ * a single splitv container with three children, none of them are considered
|
||||
+ * vertically maximized, but they are all considered horizontally maximized.
|
||||
+ *
|
||||
+ * Passing "maximized" hints to the application can help it make the right
|
||||
+ * choices about how to draw its borders. See discussion in
|
||||
+ * https://github.com/i3/i3/pull/2380.
|
||||
+ *
|
||||
+ */
|
||||
+bool con_is_maximized(Con *con, orientation_t orientation);
|
||||
+
|
||||
/**
|
||||
* Returns whether the container or any of its children is sticky.
|
||||
*
|
||||
diff --git a/include/i3-atoms_NET_SUPPORTED.xmacro.h b/include/i3-atoms_NET_SUPPORTED.xmacro.h
|
||||
index b491da98a6..90d03c20e0 100644
|
||||
--- a/include/i3-atoms_NET_SUPPORTED.xmacro.h
|
||||
+++ b/include/i3-atoms_NET_SUPPORTED.xmacro.h
|
||||
@@ -11,6 +11,8 @@ xmacro(_NET_WM_STATE_DEMANDS_ATTENTION) \
|
||||
xmacro(_NET_WM_STATE_MODAL) \
|
||||
xmacro(_NET_WM_STATE_HIDDEN) \
|
||||
xmacro(_NET_WM_STATE_FOCUSED) \
|
||||
+xmacro(_NET_WM_STATE_MAXIMIZED_VERT) \
|
||||
+xmacro(_NET_WM_STATE_MAXIMIZED_HORZ) \
|
||||
xmacro(_NET_WM_STATE) \
|
||||
xmacro(_NET_WM_WINDOW_TYPE) \
|
||||
xmacro(_NET_WM_WINDOW_TYPE_NORMAL) \
|
||||
diff --git a/release-notes/changes/2-net-wrm-state-maximized b/release-notes/changes/2-net-wrm-state-maximized
|
||||
new file mode 100644
|
||||
index 0000000000..1a3268c55d
|
||||
--- /dev/null
|
||||
+++ b/release-notes/changes/2-net-wrm-state-maximized
|
||||
@@ -0,0 +1 @@
|
||||
+pass _NET_WM_STATE_MAXIMIZED_{HORZ, VERT} to tiled windows
|
||||
diff --git a/src/con.c b/src/con.c
|
||||
index 5ecc270073..72f3ad6e22 100644
|
||||
--- a/src/con.c
|
||||
+++ b/src/con.c
|
||||
@@ -419,6 +419,65 @@ bool con_is_hidden(Con *con) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Returns true if the container is maximized in the given orientation.
|
||||
+ *
|
||||
+ * If the container is floating or fullscreen, it is not considered maximized.
|
||||
+ * Otherwise, it is maximized if it doesn't share space with any other
|
||||
+ * container in the given orientation. For example, if a workspace contains
|
||||
+ * a single splitv container with three children, none of them are considered
|
||||
+ * vertically maximized, but they are all considered horizontally maximized.
|
||||
+ *
|
||||
+ * Passing "maximized" hints to the application can help it make the right
|
||||
+ * choices about how to draw its borders. See discussion in
|
||||
+ * https://github.com/i3/i3/pull/2380.
|
||||
+ */
|
||||
+bool con_is_maximized(Con *con, orientation_t orientation) {
|
||||
+ /* Fullscreen containers are not considered maximized. */
|
||||
+ if (con->fullscreen_mode != CF_NONE) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Look up the container layout which corresponds to the given
|
||||
+ * orientation. */
|
||||
+ layout_t layout;
|
||||
+ switch (orientation) {
|
||||
+ case HORIZ:
|
||||
+ layout = L_SPLITH;
|
||||
+ break;
|
||||
+ case VERT:
|
||||
+ layout = L_SPLITV;
|
||||
+ break;
|
||||
+ default:
|
||||
+ assert(false);
|
||||
+ }
|
||||
+
|
||||
+ /* Go through all parents, stopping once we reach the workspace node. */
|
||||
+ Con *current = con;
|
||||
+ while (true) {
|
||||
+ Con *parent = current->parent;
|
||||
+ if (parent == NULL || parent->type == CT_WORKSPACE) {
|
||||
+ /* We are done searching. We found no reason that the container
|
||||
+ * should not be considered maximized. */
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ if (parent->layout == layout && con_num_children(parent) > 1) {
|
||||
+ /* The parent has a split in the indicated direction, which
|
||||
+ * means none of its children are maximized in that direction. */
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ /* Floating containers and their children are not considered
|
||||
+ * maximized. */
|
||||
+ if (parent->type == CT_FLOATING_CON) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ current = parent;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Returns whether the container or any of its children is sticky.
|
||||
*
|
||||
diff --git a/src/x.c b/src/x.c
|
||||
index 48105b03b1..a3a6aec516 100644
|
||||
--- a/src/x.c
|
||||
+++ b/src/x.c
|
||||
@@ -41,6 +41,8 @@ typedef struct con_state {
|
||||
bool unmap_now;
|
||||
bool child_mapped;
|
||||
bool is_hidden;
|
||||
+ bool is_maximized_vert;
|
||||
+ bool is_maximized_horz;
|
||||
|
||||
/* The con for which this state is. */
|
||||
Con *con;
|
||||
@@ -816,6 +818,44 @@ static void set_hidden_state(Con *con) {
|
||||
state->is_hidden = should_be_hidden;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Sets or removes _NET_WM_STATE_MAXIMIZE_{HORZ, VERT} on con
|
||||
+ *
|
||||
+ */
|
||||
+static void set_maximized_state(Con *con) {
|
||||
+ if (!con->window) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ con_state *state = state_for_frame(con->frame.id);
|
||||
+
|
||||
+ const bool con_maximized_horz = con_is_maximized(con, HORIZ);
|
||||
+ if (con_maximized_horz != state->is_maximized_horz) {
|
||||
+ DLOG("setting _NET_WM_STATE_MAXIMIZED_HORZ for con %p(%s) to %d\n", con, con->name, con_maximized_horz);
|
||||
+
|
||||
+ if (con_maximized_horz) {
|
||||
+ xcb_add_property_atom(conn, con->window->id, A__NET_WM_STATE, A__NET_WM_STATE_MAXIMIZED_HORZ);
|
||||
+ } else {
|
||||
+ xcb_remove_property_atom(conn, con->window->id, A__NET_WM_STATE, A__NET_WM_STATE_MAXIMIZED_HORZ);
|
||||
+ }
|
||||
+
|
||||
+ state->is_maximized_horz = con_maximized_horz;
|
||||
+ }
|
||||
+
|
||||
+ const bool con_maximized_vert = con_is_maximized(con, VERT);
|
||||
+ if (con_maximized_vert != state->is_maximized_vert) {
|
||||
+ DLOG("setting _NET_WM_STATE_MAXIMIZED_VERT for con %p(%s) to %d\n", con, con->name, con_maximized_vert);
|
||||
+
|
||||
+ if (con_maximized_vert) {
|
||||
+ xcb_add_property_atom(conn, con->window->id, A__NET_WM_STATE, A__NET_WM_STATE_MAXIMIZED_VERT);
|
||||
+ } else {
|
||||
+ xcb_remove_property_atom(conn, con->window->id, A__NET_WM_STATE, A__NET_WM_STATE_MAXIMIZED_VERT);
|
||||
+ }
|
||||
+
|
||||
+ state->is_maximized_vert = con_maximized_vert;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Set the container frame shape as the union of the window shape and the
|
||||
* shape of the frame borders.
|
||||
@@ -1121,6 +1161,7 @@ void x_push_node(Con *con) {
|
||||
}
|
||||
|
||||
set_hidden_state(con);
|
||||
+ set_maximized_state(con);
|
||||
|
||||
/* Handle all children and floating windows of this node. We recurse
|
||||
* in focus order to display the focused client in a stack first when
|
||||
diff --git a/testcases/lib/i3test.pm.in b/testcases/lib/i3test.pm.in
|
||||
index 6d73afca7a..44d4a3d41b 100644
|
||||
--- a/testcases/lib/i3test.pm.in
|
||||
+++ b/testcases/lib/i3test.pm.in
|
||||
@@ -53,7 +53,7 @@ our @EXPORT = qw(
|
||||
kill_all_windows
|
||||
events_for
|
||||
listen_for_binding
|
||||
- is_net_wm_state_focused
|
||||
+ net_wm_state_contains
|
||||
cmp_tree
|
||||
);
|
||||
|
||||
@@ -1090,18 +1090,19 @@ sub listen_for_binding {
|
||||
return $command;
|
||||
}
|
||||
|
||||
-=head2 is_net_wm_state_focused
|
||||
+=head2 net_wm_state_contains
|
||||
|
||||
-Returns true if the given window has the _NET_WM_STATE_FOCUSED atom.
|
||||
+Returns true if the given window has the given _NET_WM_STATE atom.
|
||||
|
||||
- ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
|
||||
+ ok(net_wm_state_contains($window, '_NET_WM_STATE_FOCUSED'),
|
||||
+ '_NET_WM_STATE_FOCUSED set');
|
||||
|
||||
=cut
|
||||
-sub is_net_wm_state_focused {
|
||||
- my ($window) = @_;
|
||||
+sub net_wm_state_contains {
|
||||
+ my ($window, $atom_name) = @_;
|
||||
|
||||
sync_with_i3;
|
||||
- my $atom = $x->atom(name => '_NET_WM_STATE_FOCUSED');
|
||||
+ my $atom = $x->atom(name => $atom_name);
|
||||
my $cookie = $x->get_property(
|
||||
0,
|
||||
$window->{id},
|
||||
diff --git a/testcases/t/158-wm_take_focus.t b/testcases/t/158-wm_take_focus.t
|
||||
index e9a32cd00a..c779365b3e 100644
|
||||
--- a/testcases/t/158-wm_take_focus.t
|
||||
+++ b/testcases/t/158-wm_take_focus.t
|
||||
@@ -55,8 +55,7 @@ subtest 'Window without WM_TAKE_FOCUS', sub {
|
||||
my $window = open_window;
|
||||
|
||||
ok(!recv_take_focus($window), 'did not receive ClientMessage');
|
||||
- ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
|
||||
-
|
||||
+ ok(net_wm_state_contains($window, '_NET_WM_STATE_FOCUSED'), '_NET_WM_STATE_FOCUSED set');
|
||||
my ($nodes) = get_ws_content($ws);
|
||||
my $con = shift @$nodes;
|
||||
ok($con->{focused}, 'con is focused');
|
||||
@@ -92,7 +91,7 @@ subtest 'Window with WM_TAKE_FOCUS and without InputHint', sub {
|
||||
$window->map;
|
||||
|
||||
ok(!recv_take_focus($window), 'did not receive ClientMessage');
|
||||
- ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
|
||||
+ ok(net_wm_state_contains($window, '_NET_WM_STATE_FOCUSED'), '_NET_WM_STATE_FOCUSED set');
|
||||
|
||||
my ($nodes) = get_ws_content($ws);
|
||||
my $con = shift @$nodes;
|
||||
@@ -114,7 +113,7 @@ subtest 'Window with WM_TAKE_FOCUS and unspecified InputHint', sub {
|
||||
my $window = open_window({ protocols => [ $take_focus ] });
|
||||
|
||||
ok(!recv_take_focus($window), 'did not receive ClientMessage');
|
||||
- ok(is_net_wm_state_focused($window), '_NET_WM_STATE_FOCUSED set');
|
||||
+ ok(net_wm_state_contains($window, '_NET_WM_STATE_FOCUSED'), '_NET_WM_STATE_FOCUSED set');
|
||||
|
||||
my ($nodes) = get_ws_content($ws);
|
||||
my $con = shift @$nodes;
|
||||
diff --git a/testcases/t/283-net-wm-state-hidden.t b/testcases/t/283-net-wm-state-hidden.t
|
||||
index d6c7b2f8b7..0738ee0b99 100644
|
||||
--- a/testcases/t/283-net-wm-state-hidden.t
|
||||
+++ b/testcases/t/283-net-wm-state-hidden.t
|
||||
@@ -20,29 +20,8 @@ use i3test;
|
||||
use X11::XCB qw(:all);
|
||||
|
||||
sub is_hidden {
|
||||
- sync_with_i3;
|
||||
- my $atom = $x->atom(name => '_NET_WM_STATE_HIDDEN');
|
||||
-
|
||||
my ($con) = @_;
|
||||
- my $cookie = $x->get_property(
|
||||
- 0,
|
||||
- $con->{id},
|
||||
- $x->atom(name => '_NET_WM_STATE')->id,
|
||||
- GET_PROPERTY_TYPE_ANY,
|
||||
- 0,
|
||||
- 4096
|
||||
- );
|
||||
-
|
||||
- my $reply = $x->get_property_reply($cookie->{sequence});
|
||||
- my $len = $reply->{length};
|
||||
- return 0 if $len == 0;
|
||||
-
|
||||
- my @atoms = unpack("L$len", $reply->{value});
|
||||
- for (my $i = 0; $i < $len; $i++) {
|
||||
- return 1 if $atoms[$i] == $atom->id;
|
||||
- }
|
||||
-
|
||||
- return 0;
|
||||
+ return net_wm_state_contains($con, '_NET_WM_STATE_HIDDEN');
|
||||
}
|
||||
|
||||
my ($tabA, $tabB, $tabC, $subtabA, $subtabB, $windowA, $windowB);
|
||||
diff --git a/testcases/t/295-net-wm-state-focused.t b/testcases/t/295-net-wm-state-focused.t
|
||||
index 68283e9c86..1a9b065eeb 100644
|
||||
--- a/testcases/t/295-net-wm-state-focused.t
|
||||
+++ b/testcases/t/295-net-wm-state-focused.t
|
||||
@@ -23,17 +23,22 @@ my ($windowA, $windowB);
|
||||
|
||||
fresh_workspace;
|
||||
$windowA = open_window;
|
||||
-ok(is_net_wm_state_focused($windowA), 'a newly opened window that is focused should have _NET_WM_STATE_FOCUSED set');
|
||||
+ok(net_wm_state_contains($windowA, '_NET_WM_STATE_FOCUSED'),
|
||||
+ 'a newly opened window that is focused should have _NET_WM_STATE_FOCUSED set');
|
||||
|
||||
$windowB = open_window;
|
||||
-ok(!is_net_wm_state_focused($windowA), 'when a another window is focused, the old window should not have _NET_WM_STATE_FOCUSED set');
|
||||
-ok(is_net_wm_state_focused($windowB), 'a newly opened window that is focused should have _NET_WM_STATE_FOCUSED set');
|
||||
+ok(!net_wm_state_contains($windowA, '_NET_WM_STATE_FOCUSED'),
|
||||
+ 'when a another window is focused, the old window should not have _NET_WM_STATE_FOCUSED set');
|
||||
+ok(net_wm_state_contains($windowB, '_NET_WM_STATE_FOCUSED'),
|
||||
+ 'a newly opened window that is focused should have _NET_WM_STATE_FOCUSED set');
|
||||
|
||||
# See issue #3495.
|
||||
cmd 'kill';
|
||||
-ok(is_net_wm_state_focused($windowA), 'when the second window is closed, the first window should have _NET_WM_STATE_FOCUSED set');
|
||||
+ok(net_wm_state_contains($windowA, '_NET_WM_STATE_FOCUSED'),
|
||||
+ 'when the second window is closed, the first window should have _NET_WM_STATE_FOCUSED set');
|
||||
|
||||
fresh_workspace;
|
||||
-ok(!is_net_wm_state_focused($windowA), 'when focus moves to the ewmh support window, no window should have _NET_WM_STATE_FOCUSED set');
|
||||
+ok(!net_wm_state_contains($windowA, '_NET_WM_STATE_FOCUSED'),
|
||||
+ 'when focus moves to the ewmh support window, no window should have _NET_WM_STATE_FOCUSED set');
|
||||
|
||||
done_testing;
|
||||
diff --git a/testcases/t/551-net-wm-state-maximized.t b/testcases/t/551-net-wm-state-maximized.t
|
||||
new file mode 100644
|
||||
index 0000000000..4db03ade57
|
||||
--- /dev/null
|
||||
+++ b/testcases/t/551-net-wm-state-maximized.t
|
||||
@@ -0,0 +1,104 @@
|
||||
+#!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)
|
||||
+#
|
||||
+# • https://i3wm.org/downloads/modern_perl_a4.pdf
|
||||
+# (unless you are already familiar with Perl)
|
||||
+#
|
||||
+# Tests for setting and removing the _NET_WM_STATE_MAXIMIZED_VERT and
|
||||
+# _NET_WM_STATE_MAXIMIZED_HORZ atoms.
|
||||
+use i3test;
|
||||
+use X11::XCB qw(:all);
|
||||
+
|
||||
+sub maximized_vert {
|
||||
+ my ($window) = @_;
|
||||
+ return net_wm_state_contains($window, '_NET_WM_STATE_MAXIMIZED_VERT');
|
||||
+}
|
||||
+
|
||||
+sub maximized_horz {
|
||||
+ my ($window) = @_;
|
||||
+ return net_wm_state_contains($window, '_NET_WM_STATE_MAXIMIZED_HORZ');
|
||||
+}
|
||||
+
|
||||
+# Returns true if the given window is maximized in both directions.
|
||||
+sub maximized_both {
|
||||
+ my ($window) = @_;
|
||||
+ return maximized_vert($window) && maximized_horz($window);
|
||||
+}
|
||||
+
|
||||
+# Returns true if the given window is maximized in neither direction.
|
||||
+sub maximized_neither {
|
||||
+ my ($window) = @_;
|
||||
+ return !maximized_vert($window) && !maximized_horz($window);
|
||||
+}
|
||||
+
|
||||
+my ($winA, $winB, $winC);
|
||||
+fresh_workspace;
|
||||
+
|
||||
+$winA = open_window;
|
||||
+ok(maximized_both($winA), 'if there is just one window, it is maximized');
|
||||
+
|
||||
+cmd 'fullscreen enable';
|
||||
+ok(maximized_neither($winA), 'fullscreen windows are not maximized');
|
||||
+
|
||||
+cmd 'fullscreen disable';
|
||||
+ok(maximized_both($winA), 'disabling fullscreen sets maximized to true again');
|
||||
+
|
||||
+cmd 'floating enable';
|
||||
+ok(maximized_neither($winA), 'floating windows are not maximized');
|
||||
+
|
||||
+cmd 'floating disable';
|
||||
+ok(maximized_both($winA), 'disabling floating sets maximized to true again');
|
||||
+
|
||||
+# Open a second window.
|
||||
+$winB = open_window;
|
||||
+
|
||||
+# Windows in stacked or tabbed containers are considered maximized.
|
||||
+cmd 'layout stacking';
|
||||
+ok(maximized_both($winA) && maximized_both($winB),
|
||||
+ 'stacking layout maximizes all windows');
|
||||
+
|
||||
+cmd 'layout tabbed';
|
||||
+ok(maximized_both($winA) && maximized_both($winB),
|
||||
+ 'tabbed layout maximizes all windows');
|
||||
+
|
||||
+# Arrange the two windows with a vertical split.
|
||||
+cmd 'layout splitv';
|
||||
+ok(!maximized_vert($winA) && !maximized_vert($winB),
|
||||
+ 'vertical split means children are not maximized vertically');
|
||||
+ok(maximized_horz($winA) && maximized_horz($winB),
|
||||
+ 'children may still be maximized horizontally in a vertical split');
|
||||
+
|
||||
+# Arrange the two windows with a horizontal split.
|
||||
+cmd 'layout splith';
|
||||
+ok(maximized_vert($winA) && maximized_vert($winB),
|
||||
+ 'children may still be maximized vertically in a horizontal split');
|
||||
+ok(!maximized_horz($winA) && !maximized_horz($winB),
|
||||
+ 'horizontal split means children are not maximized horizontally');
|
||||
+
|
||||
+# Add a vertical split within the horizontal split, and open a third window.
|
||||
+cmd 'split vertical';
|
||||
+$winC = open_window;
|
||||
+ok(maximized_vert($winA), 'winA still reaches from top to bottom');
|
||||
+ok(!maximized_vert($winB) && !maximized_vert($winC),
|
||||
+ 'winB and winC are split vertically, so they are not maximized vertically');
|
||||
+ok(!maximized_horz($winA) && !maximized_horz($winB) && !maximized_horz($winC),
|
||||
+ 'horizontal split means children are not maximized horizontally');
|
||||
+
|
||||
+# Change the vertical split container to a tabbed container.
|
||||
+cmd 'layout tabbed';
|
||||
+ok(maximized_vert($winA) && maximized_vert($winB) && maximized_vert($winC),
|
||||
+ 'all windows now reach from top to bottom');
|
||||
+ok(!maximized_horz($winA) && !maximized_horz($winB) && !maximized_horz($winC),
|
||||
+ 'horizontal split means children are not maximized horizontally');
|
||||
+
|
||||
+done_testing;
|
||||
@@ -1,146 +0,0 @@
|
||||
From f8befe378ab3c9f8d035657ca0247c9b8c242b6b Mon Sep 17 00:00:00 2001
|
||||
From: Orestis Floros <orestisflo@gmail.com>
|
||||
Date: Wed, 31 Jan 2024 08:14:32 +0100
|
||||
Subject: [PATCH] Avoid creating redundant containers when switching between
|
||||
tabbed/stacked and split layouts (#5469)
|
||||
|
||||
Fixes #3001
|
||||
---
|
||||
release-notes/changes/3-redundant-containers | 1 +
|
||||
src/con.c | 25 ++++++
|
||||
testcases/t/550-split-redundant-containers.t | 82 ++++++++++++++++++++
|
||||
3 files changed, 108 insertions(+)
|
||||
create mode 100644 release-notes/changes/3-redundant-containers
|
||||
create mode 100644 testcases/t/550-split-redundant-containers.t
|
||||
|
||||
diff --git a/release-notes/changes/3-redundant-containers b/release-notes/changes/3-redundant-containers
|
||||
new file mode 100644
|
||||
index 000000000..cd6ab9f3d
|
||||
--- /dev/null
|
||||
+++ b/release-notes/changes/3-redundant-containers
|
||||
@@ -0,0 +1 @@
|
||||
+avoid creating redundant containers when switching between tabbed/stacked and split layouts
|
||||
diff --git a/src/con.c b/src/con.c
|
||||
index aebc46cf8..917e797a6 100644
|
||||
--- a/src/con.c
|
||||
+++ b/src/con.c
|
||||
@@ -2063,6 +2063,31 @@ void con_set_layout(Con *con, layout_t layout) {
|
||||
}
|
||||
}
|
||||
|
||||
+ if (con->type != CT_WORKSPACE && con->parent->type != CT_WORKSPACE &&
|
||||
+ con_num_children(con) == 1 && con_num_children(con->parent) == 1) {
|
||||
+ /* Special case: Avoid creating redundant containers (#3001):
|
||||
+ * split h / v (tree_split()) will avoid creating new containers when
|
||||
+ * the target container is already a single child in L_SPLITH /
|
||||
+ * L_SPLITV. However, if the layout is tabbed / stacked, a new split is
|
||||
+ * created. This means, however, that when the user continuously
|
||||
+ * switches between split h/v and tabbed / stacked, an endless series
|
||||
+ * of 1-child containers will be created. Since a single level of split
|
||||
+ * containers on top of tabbed / stacked containers are useful, we want
|
||||
+ * to avoid this situation here.
|
||||
+ * Example of past behaviour: S[V[w]] -> S[S[w]] -> S[S[V[w]]] -> …
|
||||
+ * Example of desired behaviour: S[V[w]] -> S[w] -> S[v[w]] -> …
|
||||
+ * Therefore, when both the current & parent containers have a single
|
||||
+ * child, we just close the redundant middle container and proceed with
|
||||
+ * the parent. */
|
||||
+ Con *parent = con->parent;
|
||||
+ Con *child = TAILQ_FIRST(&(con->nodes_head));
|
||||
+ con_detach(child);
|
||||
+ con_attach(child, parent, true);
|
||||
+ parent->last_split_layout = con->last_split_layout;
|
||||
+ tree_close_internal(con, DONT_KILL_WINDOW, true);
|
||||
+ con = parent;
|
||||
+ }
|
||||
+
|
||||
if (layout == L_DEFAULT) {
|
||||
/* Special case: the layout formerly known as "default" (in combination
|
||||
* with an orientation). Since we switched to splith/splitv layouts,
|
||||
diff --git a/testcases/t/550-split-redundant-containers.t b/testcases/t/550-split-redundant-containers.t
|
||||
new file mode 100644
|
||||
index 000000000..3dfef3995
|
||||
--- /dev/null
|
||||
+++ b/testcases/t/550-split-redundant-containers.t
|
||||
@@ -0,0 +1,82 @@
|
||||
+#!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)
|
||||
+#
|
||||
+# Test that splitting and stacked/tabbed layouts do not create redundant
|
||||
+# containers.
|
||||
+# Ticket: #3001
|
||||
+# Bug still in: 4.22-24-ga5da4d54
|
||||
+use i3test;
|
||||
+
|
||||
+cmp_tree(
|
||||
+ msg => 'toggling between split h/v',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'V[a*]',
|
||||
+ cb => sub {
|
||||
+ cmd 'split v, split h, split v';
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'toggling between tabbed/stacked',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'S[a*]',
|
||||
+ cb => sub {
|
||||
+ cmd 'layout tabbed, layout stacked';
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'split h to v and then tabbed',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'T[a*]',
|
||||
+ cb => sub {
|
||||
+ cmd 'split v, layout tabbed';
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'repeat tabbed layout',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'T[a*]',
|
||||
+ cb => sub {
|
||||
+ cmd 'layout tabbed' for 1..5;
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'split v inside tabbed',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'T[V[a*]]',
|
||||
+ cb => sub {
|
||||
+ cmd 'layout tabbed, split v';
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'split v inside tabbed and back to just tabbed',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'T[a*]',
|
||||
+ cb => sub {
|
||||
+ cmd 'layout tabbed, split v, layout tabbed';
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'toggle split v inside tabbed',
|
||||
+ layout_before => 'H[a*]',
|
||||
+ layout_after => 'T[V[a*]]',
|
||||
+ cb => sub {
|
||||
+ cmd 'layout tabbed, split v, layout tabbed, split v';
|
||||
+ });
|
||||
+cmp_tree(
|
||||
+ msg => 'tabbed with 2 nodes inside other tabbed',
|
||||
+ layout_before => 'T[a*]',
|
||||
+ layout_after => 'T[T[a b*]]',
|
||||
+ cb => sub {
|
||||
+ cmd 'split v';
|
||||
+ open_window(wm_class => "b", name => "b");
|
||||
+ cmd 'layout tabbed';
|
||||
+ });
|
||||
+
|
||||
+done_testing;
|
||||
@@ -28,8 +28,8 @@
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
PRGNAM=i3
|
||||
VERSION=${VERSION:-4.23}
|
||||
BUILD=${BUILD:-2}
|
||||
VERSION=${VERSION:-4.24}
|
||||
BUILD=${BUILD:-1}
|
||||
TAG=${TAG:-_EXs}
|
||||
|
||||
if [ -z "$ARCH" ]; then
|
||||
@@ -74,9 +74,6 @@ find -L . \
|
||||
\( -perm 666 -o -perm 664 -o -perm 640 -o -perm 600 -o -perm 444 \
|
||||
-o -perm 440 -o -perm 400 \) -exec chmod 644 {} \+
|
||||
|
||||
patch -p1 -i $CWD/f8befe378ab3c9f8d035657ca0247c9b8c242b6b.patch
|
||||
patch -p1 -i $CWD/b660d6a902cf44be22c434101dd2a4e6743e26bc.patch
|
||||
|
||||
# Configure, build, and install:
|
||||
export CFLAGS="-g3 $SLKCFLAGS -flto -rdynamic"
|
||||
export CXXFLAGS="-g3 $SLKCFLAGS -flto -rdynamic"
|
||||
@@ -115,9 +112,7 @@ mkdir -p $PKG/usr/share/apps/kdm/sessions
|
||||
ln -s /usr/share/xsessions/i3.desktop $PKG/usr/share/apps/kdm/sessions/
|
||||
|
||||
# Install an xinitrc script
|
||||
mkdir -p $PKG/etc/X11/xinit
|
||||
cat $CWD/xinitrc.i3 > $PKG/etc/X11/xinit/xinitrc.i3
|
||||
chmod 0755 $PKG/etc/X11/xinit/xinitrc.i3
|
||||
install -Dpm 0755 $CWD/xinitrc.i3 $PKG/etc/X11/xinit/xinitrc.i3
|
||||
|
||||
mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION/html $PKG/usr/doc/$PRGNAM-$VERSION/txt
|
||||
cp -a DEPENDS LICENSE RELEASE-NOTES-* $PKG/usr/doc/$PRGNAM-$VERSION
|
||||
@@ -135,7 +130,6 @@ perl Makefile.PL \
|
||||
INSTALLVENDORMAN1DIR=/usr/man/man1 \
|
||||
INSTALLVENDORMAN3DIR=/usr/man/man3
|
||||
make -j$(nproc)
|
||||
#make test
|
||||
make install DESTDIR=$PKG
|
||||
|
||||
find $PKG -name perllocal.pod -o -name ".packlist" -o -name "*.bs" | xargs rm -f || true
|
||||
@@ -145,13 +139,14 @@ cp -a Changes README MANIFEST $PKG/usr/doc/$PRGNAM-$VERSION/AnyEvent-I3/
|
||||
|
||||
# man pages
|
||||
find $PKG/usr/man -type f -exec gzip -9 {} +
|
||||
for i in $( find $PKG/usr/man -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done
|
||||
for i in $( find $PKG/usr/man -type l ); do
|
||||
ln -s $( readlink $i ).gz $i.gz
|
||||
rm $i
|
||||
done
|
||||
|
||||
find $PKG -depth -type d -empty -delete || true
|
||||
|
||||
install -Dpm 0644 $CWD/$PRGNAM.SlackBuild $PKG/usr/doc/$PRGNAM-$VERSION/$PRGNAM.SlackBuild
|
||||
|
||||
mkdir -p $PKG/install
|
||||
install -Dpm 0644 $CWD/slack-desc $PKG/install/slack-desc
|
||||
install -Dpm 0644 $CWD/doinst.sh $PKG/install/doinst.sh
|
||||
install -Dpm 0644 $CWD/slack-required $PKG/install/slack-required
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
PRGNAM="i3"
|
||||
VERSION="4.23"
|
||||
VERSION="4.24"
|
||||
HOMEPAGE="https://www.i3wm.org"
|
||||
DOWNLOAD="https://i3wm.org/downloads/i3-4.23.tar.xz"
|
||||
MD5SUM="ea71162d40b403b6098fe833697b747a"
|
||||
DOWNLOAD="https://i3wm.org/downloads/i3-4.24.tar.xz"
|
||||
MD5SUM="239a821e091e383fb0e3981eac6f8ae9"
|
||||
DOWNLOAD_x86_64=""
|
||||
MD5SUM_x86_64=""
|
||||
REQUIRES="dmenu libev xcb-util-xrm yajl perl-JSON-XS perl-AnyEvent"
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
diff -ruNp i3-4.19/testcases/inject_randr1.5.c i3-4.19.new/testcases/inject_randr1.5.c
|
||||
--- i3-4.19/testcases/inject_randr1.5.c 2020-11-15 20:23:01.532988500 +0300
|
||||
+++ i3-4.19.new/testcases/inject_randr1.5.c 2020-11-20 12:23:02.176011604 +0300
|
||||
@@ -267,9 +267,9 @@ static void read_client_x11_packet_cb(EV
|
||||
}
|
||||
} else if (opcode == connstate->randr_major_opcode) {
|
||||
const uint8_t randr_opcode = ((generic_x11_request_t *)request)->pad0;
|
||||
- if (randr_opcode == XCB_RANDR_GET_MONITORS) {
|
||||
+ if (randr_opcode == 42) {
|
||||
connstate->getmonitors = connstate->sequence;
|
||||
- } else if (randr_opcode == XCB_RANDR_GET_OUTPUT_INFO) {
|
||||
+ } else if (randr_opcode == 9) {
|
||||
connstate->getoutputinfo = connstate->sequence;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user