diff options
author | Ronan Pigott <rpigott@berkeley.edu> | 2020-11-01 23:43:07 -0700 |
---|---|---|
committer | Tudor Brindus <me@tbrindus.ca> | 2020-12-20 00:58:42 -0500 |
commit | 8eb0c54693e44e7c6126ce35045e34ad0f4d4607 (patch) | |
tree | f70faa5d8d809591909881e992323d5439d7f21d | |
parent | commands/move: rework container_move_in_direction (diff) | |
download | sway-8eb0c54693e44e7c6126ce35045e34ad0f4d4607.tar.gz sway-8eb0c54693e44e7c6126ce35045e34ad0f4d4607.tar.zst sway-8eb0c54693e44e7c6126ce35045e34ad0f4d4607.zip |
introduce workspace_squash
workspace_squash is container_flatten in the reverse
direction. Instead of eliminating redundant splits that are
parents of the target container, it eliminates pairs of
redundant H/V splits that are children of the workspace.
Splits are redundant if a con and its grandchild have the
same layout, and the immediate child has the opposite split.
For example, layouts are transformed like:
H[V[H[app1 app2]] app3] -> H[app1 app2 app3]
i3 uses this operation to simplify the tree after moving
heavily nested containers to a higher level in the tree via
an orthogonal move.
-rw-r--r-- | include/sway/tree/container.h | 13 | ||||
-rw-r--r-- | include/sway/tree/workspace.h | 15 | ||||
-rw-r--r-- | sway/tree/container.c | 62 | ||||
-rw-r--r-- | sway/tree/workspace.c | 26 |
4 files changed, 109 insertions, 7 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index c9290108..7e9df59f 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -374,4 +374,17 @@ bool container_is_sticky(struct sway_container *con); | |||
374 | 374 | ||
375 | bool container_is_sticky_or_child(struct sway_container *con); | 375 | bool container_is_sticky_or_child(struct sway_container *con); |
376 | 376 | ||
377 | /** | ||
378 | * This will destroy pairs of redundant H/V splits | ||
379 | * e.g. H[V[H[app app]] app] -> H[app app app] | ||
380 | * The middle "V[H[" are eliminated by a call to container_squash | ||
381 | * on the V[ con. It's grandchildren are added to it's parent. | ||
382 | * | ||
383 | * This function is roughly equivalent to i3's tree_flatten here: | ||
384 | * https://github.com/i3/i3/blob/1f0c628cde40cf87371481041b7197344e0417c6/src/tree.c#L651 | ||
385 | * | ||
386 | * Returns the number of new containers added to the parent | ||
387 | */ | ||
388 | int container_squash(struct sway_container *con); | ||
389 | |||
377 | #endif | 390 | #endif |
diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 3c9f93ed..fdd92f64 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -116,6 +116,13 @@ struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, | |||
116 | void workspace_add_floating(struct sway_workspace *workspace, | 116 | void workspace_add_floating(struct sway_workspace *workspace, |
117 | struct sway_container *con); | 117 | struct sway_container *con); |
118 | 118 | ||
119 | /** | ||
120 | * Adds a tiling container to the workspace without considering | ||
121 | * the workspace_layout, so the con will not be split. | ||
122 | */ | ||
123 | void workspace_insert_tiling_direct(struct sway_workspace *workspace, | ||
124 | struct sway_container *con, int index); | ||
125 | |||
119 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, | 126 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, |
120 | struct sway_container *con, int index); | 127 | struct sway_container *con, int index); |
121 | 128 | ||
@@ -134,4 +141,12 @@ size_t workspace_num_tiling_views(struct sway_workspace *ws); | |||
134 | 141 | ||
135 | size_t workspace_num_sticky_containers(struct sway_workspace *ws); | 142 | size_t workspace_num_sticky_containers(struct sway_workspace *ws); |
136 | 143 | ||
144 | /** | ||
145 | * workspace_squash is container_flatten in the reverse | ||
146 | * direction. Instead of eliminating redundant splits that are | ||
147 | * parents of the target container, it eliminates pairs of | ||
148 | * redundant H/V splits that are children of the workspace. | ||
149 | */ | ||
150 | void workspace_squash(struct sway_workspace *workspace); | ||
151 | |||
137 | #endif | 152 | #endif |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 23b6c997..4c573e83 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1630,3 +1630,65 @@ bool container_is_sticky(struct sway_container *con) { | |||
1630 | bool container_is_sticky_or_child(struct sway_container *con) { | 1630 | bool container_is_sticky_or_child(struct sway_container *con) { |
1631 | return container_is_sticky(container_toplevel_ancestor(con)); | 1631 | return container_is_sticky(container_toplevel_ancestor(con)); |
1632 | } | 1632 | } |
1633 | |||
1634 | static bool is_parallel(enum sway_container_layout first, | ||
1635 | enum sway_container_layout second) { | ||
1636 | switch (first) { | ||
1637 | case L_TABBED: | ||
1638 | case L_HORIZ: | ||
1639 | return second == L_TABBED || second == L_HORIZ; | ||
1640 | case L_STACKED: | ||
1641 | case L_VERT: | ||
1642 | return second == L_STACKED || second == L_VERT; | ||
1643 | default: | ||
1644 | return false; | ||
1645 | } | ||
1646 | } | ||
1647 | |||
1648 | static bool container_is_squashable(struct sway_container *con, | ||
1649 | struct sway_container *child) { | ||
1650 | enum sway_container_layout gp_layout = container_parent_layout(con); | ||
1651 | return (con->layout == L_HORIZ || con->layout == L_VERT) && | ||
1652 | (child->layout == L_HORIZ || child->layout == L_VERT) && | ||
1653 | !is_parallel(con->layout, child->layout) && | ||
1654 | is_parallel(gp_layout, child->layout); | ||
1655 | } | ||
1656 | |||
1657 | static void container_squash_children(struct sway_container *con) { | ||
1658 | for (int i = 0; i < con->children->length; i++) { | ||
1659 | struct sway_container *child = con->children->items[i]; | ||
1660 | i += container_squash(child); | ||
1661 | } | ||
1662 | } | ||
1663 | |||
1664 | int container_squash(struct sway_container *con) { | ||
1665 | if (!con->children) { | ||
1666 | return 0; | ||
1667 | } | ||
1668 | if (con->children->length != 1) { | ||
1669 | container_squash_children(con); | ||
1670 | return 0; | ||
1671 | } | ||
1672 | struct sway_container *child = con->children->items[0]; | ||
1673 | int idx = container_sibling_index(con); | ||
1674 | int change = 0; | ||
1675 | if (container_is_squashable(con, child)) { | ||
1676 | // con and child are a redundant H/V pair. Destroy them. | ||
1677 | while (child->children->length) { | ||
1678 | struct sway_container *current = child->children->items[0]; | ||
1679 | container_detach(current); | ||
1680 | if (con->parent) { | ||
1681 | container_insert_child(con->parent, current, idx); | ||
1682 | } else { | ||
1683 | workspace_insert_tiling_direct(con->workspace, current, idx); | ||
1684 | } | ||
1685 | change++; | ||
1686 | } | ||
1687 | // This will also destroy con because child was its only child | ||
1688 | container_reap_empty(child); | ||
1689 | change--; | ||
1690 | } else { | ||
1691 | container_squash_children(con); | ||
1692 | } | ||
1693 | return change; | ||
1694 | } | ||
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index e40792ae..62549434 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -714,14 +714,8 @@ void workspace_add_floating(struct sway_workspace *workspace, | |||
714 | node_set_dirty(&con->node); | 714 | node_set_dirty(&con->node); |
715 | } | 715 | } |
716 | 716 | ||
717 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, | 717 | void workspace_insert_tiling_direct(struct sway_workspace *workspace, |
718 | struct sway_container *con, int index) { | 718 | struct sway_container *con, int index) { |
719 | if (con->workspace) { | ||
720 | container_detach(con); | ||
721 | } | ||
722 | if (config->default_layout != L_NONE) { | ||
723 | con = container_split(con, config->default_layout); | ||
724 | } | ||
725 | list_insert(workspace->tiling, index, con); | 719 | list_insert(workspace->tiling, index, con); |
726 | con->workspace = workspace; | 720 | con->workspace = workspace; |
727 | container_for_each_child(con, set_workspace, NULL); | 721 | container_for_each_child(con, set_workspace, NULL); |
@@ -729,6 +723,17 @@ struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, | |||
729 | workspace_update_representation(workspace); | 723 | workspace_update_representation(workspace); |
730 | node_set_dirty(&workspace->node); | 724 | node_set_dirty(&workspace->node); |
731 | node_set_dirty(&con->node); | 725 | node_set_dirty(&con->node); |
726 | } | ||
727 | |||
728 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, | ||
729 | struct sway_container *con, int index) { | ||
730 | if (con->workspace) { | ||
731 | container_detach(con); | ||
732 | } | ||
733 | if (config->default_layout != L_NONE) { | ||
734 | con = container_split(con, config->default_layout); | ||
735 | } | ||
736 | workspace_insert_tiling_direct(workspace, con, index); | ||
732 | return con; | 737 | return con; |
733 | } | 738 | } |
734 | 739 | ||
@@ -846,3 +851,10 @@ size_t workspace_num_sticky_containers(struct sway_workspace *ws) { | |||
846 | workspace_for_each_container(ws, count_sticky_containers, &count); | 851 | workspace_for_each_container(ws, count_sticky_containers, &count); |
847 | return count; | 852 | return count; |
848 | } | 853 | } |
854 | |||
855 | void workspace_squash(struct sway_workspace *workspace) { | ||
856 | for (int i = 0; i < workspace->tiling->length; i++) { | ||
857 | struct sway_container *child = workspace->tiling->items[i]; | ||
858 | i += container_squash(child); | ||
859 | } | ||
860 | } | ||