summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sway/commands/layout.c202
-rw-r--r--sway/container.c7
-rw-r--r--sway/layout.c46
-rw-r--r--sway/sway.5.txt12
4 files changed, 159 insertions, 108 deletions
diff --git a/sway/commands/layout.c b/sway/commands/layout.c
index 0cdac1b4..ff097fef 100644
--- a/sway/commands/layout.c
+++ b/sway/commands/layout.c
@@ -3,6 +3,11 @@
3#include "sway/container.h" 3#include "sway/container.h"
4#include "sway/layout.h" 4#include "sway/layout.h"
5 5
6/**
7 * handle "layout auto" command group
8 */
9static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv);
10
6struct cmd_results *cmd_layout(int argc, char **argv) { 11struct cmd_results *cmd_layout(int argc, char **argv) {
7 struct cmd_results *error = NULL; 12 struct cmd_results *error = NULL;
8 if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file."); 13 if (config->reading) return cmd_results_new(CMD_FAILURE, "layout", "Can't be used in config file.");
@@ -49,88 +54,14 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
49 } else if (strcasecmp(argv[0], "splitv") == 0) { 54 } else if (strcasecmp(argv[0], "splitv") == 0) {
50 swayc_change_layout(parent, L_VERT); 55 swayc_change_layout(parent, L_VERT);
51 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) { 56 } else if (strcasecmp(argv[0], "toggle") == 0 && argc == 2 && strcasecmp(argv[1], "split") == 0) {
52 if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE || 57 if (parent->layout == L_HORIZ && (parent->workspace_layout == L_NONE
53 parent->workspace_layout == L_HORIZ)) { 58 || parent->workspace_layout == L_HORIZ)) {
54 swayc_change_layout(parent, L_VERT); 59 swayc_change_layout(parent, L_VERT);
55 } else { 60 } else {
56 swayc_change_layout(parent, L_HORIZ); 61 swayc_change_layout(parent, L_HORIZ);
57 } 62 }
58 } else if (strcasecmp(argv[0], "auto_left") == 0) {
59 swayc_change_layout(parent, L_AUTO_LEFT);
60 } else if (strcasecmp(argv[0], "auto_right") == 0) {
61 swayc_change_layout(parent, L_AUTO_RIGHT);
62 } else if (strcasecmp(argv[0], "auto_top") == 0) {
63 swayc_change_layout(parent, L_AUTO_TOP);
64 } else if (strcasecmp(argv[0], "auto_bot") == 0) {
65 swayc_change_layout(parent, L_AUTO_BOTTOM);
66 } else if (strcasecmp(argv[0], "incnmaster") == 0) {
67 const char *name = "layout incnmaster";
68 if ((error = checkarg(argc, name,
69 EXPECTED_EQUAL_TO, 2))) {
70 return error;
71 }
72 char *end;
73 int inc = (int) strtol(argv[1], &end, 10);
74 if (*end) {
75 return cmd_results_new(CMD_INVALID, name, "Invalid %s command "
76 "(argument must be an integer)", name);
77
78 }
79 swayc_t *container = get_focused_view(swayc_active_workspace());
80 if (container && inc &&
81 is_auto_layout(container->parent->layout) &&
82 ((int)container->parent->nb_master + inc >= 0)) {
83 for (int i = container->parent->nb_master;
84 i >= 0 && i < container->parent->children->length &&
85 i != (int) container->parent->nb_master + inc;) {
86 ((swayc_t *) container->parent->children->items[i])->height = -1;
87 ((swayc_t *) container->parent->children->items[i])->width = -1;
88 i += inc > 0 ? 1 : -1;
89 }
90 container->parent->nb_master += inc;
91 }
92 } else if ((strcasecmp(argv[0], "incncol") == 0) && argc ==2) {
93 const char *name = "layout incncol";
94 if ((error = checkarg(argc, name,
95 EXPECTED_EQUAL_TO, 2))) {
96 return error;
97 }
98 char *end;
99 int inc = (int) strtol(argv[1], &end, 10);
100 if (*end) {
101 return cmd_results_new(CMD_INVALID, name, "Invalid %s command "
102 "(argument must be an integer)", name);
103
104 }
105 swayc_t *container = get_focused_view(swayc_active_workspace());
106 if (container && inc && is_auto_layout(container->parent->layout) &&
107 ((int)container->parent->nb_slave_groups + inc >= 1)) {
108 container->parent->nb_slave_groups += inc;
109 }
110 } else if (strcasecmp(argv[0], "auto") == 0) { 63 } else if (strcasecmp(argv[0], "auto") == 0) {
111 if ((error = checkarg(argc, "auto", EXPECTED_EQUAL_TO, 2))) { 64 return cmd_layout_auto(parent, argc, argv);
112 return error;
113 }
114 swayc_t *container = get_focused_view(swayc_active_workspace());
115 swayc_t *parent = container->parent;
116 enum swayc_layouts layout;
117 if (strcasecmp(argv[1], "next") == 0) {
118 if (is_auto_layout(parent->layout) && parent->layout < L_AUTO_LAST) {
119 layout = parent->layout + 1;
120 } else {
121 layout = L_AUTO_FIRST;
122 }
123 } else if (strcasecmp(argv[1], "prev") == 0) {
124 if (is_auto_layout(parent->layout) && parent->layout > L_AUTO_FIRST) {
125 layout = parent->layout - 1;
126 } else {
127 layout = L_AUTO_LAST;
128 }
129 } else {
130 return cmd_results_new(CMD_FAILURE, "layout auto",
131 "Must be one of <prev|next>.");
132 }
133 swayc_change_layout(parent, layout);
134 } 65 }
135 } 66 }
136 67
@@ -141,3 +72,120 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
141 72
142 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 73 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
143} 74}
75
76static struct cmd_results *cmd_layout_auto(swayc_t *container, int argc, char **argv) {
77 // called after checking that argv[0] is auto, so just continue parsing from there
78 struct cmd_results *error = NULL;
79 const char *cmd_name = "layout auto";
80 const char *set_inc_cmd_name = "layout auto [master|ncol] [set|inc]";
81 const char *err_msg = "Allowed arguments are <right|left|top|bot|next|prev|master|ncol>";
82
83 bool need_layout_update = false;
84 enum swayc_layouts old_layout = container->layout;
85 enum swayc_layouts layout = old_layout;
86
87 if (strcasecmp(argv[1], "left") == 0) {
88 layout = L_AUTO_LEFT;
89 } else if (strcasecmp(argv[1], "right") == 0) {
90 layout = L_AUTO_RIGHT;
91 } else if (strcasecmp(argv[1], "top") == 0) {
92 layout = L_AUTO_TOP;
93 } else if (strcasecmp(argv[1], "bot") == 0) {
94 layout = L_AUTO_BOTTOM;
95 } else if (strcasecmp(argv[1], "next") == 0) {
96 if (is_auto_layout(container->layout) && container->layout < L_AUTO_LAST) {
97 layout = container->layout + 1;
98 } else {
99 layout = L_AUTO_FIRST;
100 }
101 } else if (strcasecmp(argv[1], "prev") == 0) {
102 if (is_auto_layout(container->layout) && container->layout > L_AUTO_FIRST) {
103 layout = container->layout - 1;
104 } else {
105 layout = L_AUTO_LAST;
106 }
107 } else {
108 bool is_nmaster;
109 bool is_set;
110 if (strcasecmp(argv[1], "master") == 0) {
111 is_nmaster = true;
112 } else if (strcasecmp(argv[1], "ncol") == 0) {
113 is_nmaster = false;
114 } else {
115 return cmd_results_new(CMD_INVALID, cmd_name, "Invalid %s command. %s",
116 cmd_name, err_msg);
117 }
118 if ((error = checkarg(argc, "auto <master|ncol>", EXPECTED_EQUAL_TO, 4))) {
119 return error;
120 }
121 if (strcasecmp(argv[2], "set") == 0) {
122 is_set = true;
123 } else if (strcasecmp(argv[2], "inc") == 0) {
124 is_set = false;
125 } else {
126 return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command. %s, "
127 "Argument must be on of <set|inc>",
128 set_inc_cmd_name);
129 }
130 char *end;
131 int n = (int)strtol(argv[3], &end, 10);
132 if (*end) {
133 return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command "
134 "(argument must be an integer)", set_inc_cmd_name);
135 }
136 if (is_auto_layout(container->layout)) {
137 int inc = 0; /* difference between current master/ncol and requested value */
138 if (is_nmaster) {
139 if (is_set) {
140 if (n < 0) {
141 return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command "
142 "(master must be >= 0)", set_inc_cmd_name);
143 }
144 inc = n - (int)container->nb_master;
145 } else { /* inc command */
146 if ((int)container->nb_master + n >= 0) {
147 inc = n;
148 }
149 }
150 if (inc) {
151 for (int i = container->nb_master;
152 i >= 0 && i < container->children->length
153 && i != (int)container->nb_master + inc;) {
154 ((swayc_t *)container->children->items[i])->height = -1;
155 ((swayc_t *)container->children->items[i])->width = -1;
156 i += inc > 0 ? 1 : -1;
157 }
158 container->nb_master += inc;
159 need_layout_update = true;
160 }
161 } else { /* ncol modification */
162 if (is_set) {
163 if (n <= 0) {
164 return cmd_results_new(CMD_INVALID, set_inc_cmd_name, "Invalid %s command "
165 "(ncol must be > 0)", set_inc_cmd_name);
166 }
167 inc = n - (int)container->nb_slave_groups;
168 } else { /* inc command */
169 if ((int)container->nb_slave_groups + n > 0) {
170 inc = n;
171 }
172 }
173 if (inc) {
174 container->nb_slave_groups += inc;
175 need_layout_update = true;
176 }
177 }
178 }
179 }
180
181 if (layout != old_layout) {
182 swayc_change_layout(container, layout);
183 update_layout_geometry(container, old_layout);
184 need_layout_update = true;
185 }
186 if (need_layout_update) {
187 update_geometry(container);
188 arrange_windows(container, container->width, container->height);
189 }
190 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
191}
diff --git a/sway/container.c b/sway/container.c
index 3bdc8b6c..cf7d7dda 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -965,10 +965,11 @@ swayc_t *swayc_change_layout(swayc_t *container, enum swayc_layouts layout) {
965 // if layout change modifies the auto layout's major axis, swap width and height 965 // if layout change modifies the auto layout's major axis, swap width and height
966 // to preserve current ratios. 966 // to preserve current ratios.
967 if (is_auto_layout(layout) && is_auto_layout(container->layout)) { 967 if (is_auto_layout(layout) && is_auto_layout(container->layout)) {
968 enum swayc_layouts prev_major = (container->layout == L_AUTO_LEFT || 968 enum swayc_layouts prev_major =
969 container->layout == L_AUTO_RIGHT) 969 container->layout == L_AUTO_LEFT || container->layout == L_AUTO_RIGHT
970 ? L_HORIZ : L_VERT; 970 ? L_HORIZ : L_VERT;
971 enum swayc_layouts new_major = (layout == L_AUTO_LEFT || layout == L_AUTO_RIGHT) 971 enum swayc_layouts new_major =
972 layout == L_AUTO_LEFT || layout == L_AUTO_RIGHT
972 ? L_HORIZ : L_VERT; 973 ? L_HORIZ : L_VERT;
973 if (new_major != prev_major) { 974 if (new_major != prev_major) {
974 for (int i = 0; i < container->children->length; ++i) { 975 for (int i = 0; i < container->children->length; ++i) {
diff --git a/sway/layout.c b/sway/layout.c
index e2f31848..fdd2fe6b 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -296,7 +296,7 @@ void move_container(swayc_t *container, enum movement_direction dir) {
296 sway_log(L_DEBUG, "container:%p, parent:%p, child %p,", 296 sway_log(L_DEBUG, "container:%p, parent:%p, child %p,",
297 container,parent,child); 297 container,parent,child);
298 if (parent->layout == layout 298 if (parent->layout == layout
299 || layout == L_NONE /* accept any layout for next/prev direction */ 299 || (layout == L_NONE && parent->type == C_CONTAINER) /* accept any layout for next/prev direction */
300 || (parent->layout == L_TABBED && layout == L_HORIZ) 300 || (parent->layout == L_TABBED && layout == L_HORIZ)
301 || (parent->layout == L_STACKED && layout == L_VERT) 301 || (parent->layout == L_STACKED && layout == L_VERT)
302 || is_auto_layout(parent->layout)) { 302 || is_auto_layout(parent->layout)) {
@@ -321,16 +321,16 @@ void move_container(swayc_t *container, enum movement_direction dir) {
321 } 321 }
322 // if move command makes container change from master to slave 322 // if move command makes container change from master to slave
323 // (or the contrary), reset its geometry an the one of the replaced item. 323 // (or the contrary), reset its geometry an the one of the replaced item.
324 if (parent->nb_master && 324 if (parent->nb_master
325 (size_t) parent->children->length > parent->nb_master) { 325 && (size_t)parent->children->length > parent->nb_master) {
326 swayc_t *swap_geom = NULL; 326 swayc_t *swap_geom = NULL;
327 // if child is being promoted/demoted, it will swap geometry 327 // if child is being promoted/demoted, it will swap geometry
328 // with the sibling being demoted/promoted. 328 // with the sibling being demoted/promoted.
329 if ((dir == MOVE_NEXT && desired == 0) 329 if ((dir == MOVE_NEXT && desired == 0)
330 || (dir == MOVE_PREV && (size_t) desired == parent->nb_master - 1)) { 330 || (dir == MOVE_PREV && (size_t)desired == parent->nb_master - 1)) {
331 swap_geom = parent->children->items[parent->nb_master - 1]; 331 swap_geom = parent->children->items[parent->nb_master - 1];
332 } else if ((dir == MOVE_NEXT && (size_t) desired == parent->nb_master) 332 } else if ((dir == MOVE_NEXT && (size_t)desired == parent->nb_master)
333 || (dir == MOVE_PREV && desired == parent->children->length - 1)) { 333 || (dir == MOVE_PREV && desired == parent->children->length - 1)) {
334 swap_geom = parent->children->items[parent->nb_master]; 334 swap_geom = parent->children->items[parent->nb_master];
335 } 335 }
336 if (swap_geom) { 336 if (swap_geom) {
@@ -837,9 +837,9 @@ static void apply_tabbed_or_stacked_layout(swayc_t *container, double x,
837 double height); 837 double height);
838 838
839static void apply_auto_layout(swayc_t *container, const double x, const double y, 839static void apply_auto_layout(swayc_t *container, const double x, const double y,
840 const double width, const double height, 840 const double width, const double height,
841 enum swayc_layouts group_layout, 841 enum swayc_layouts group_layout,
842 bool master_first); 842 bool master_first);
843 843
844static void arrange_windows_r(swayc_t *container, double width, double height) { 844static void arrange_windows_r(swayc_t *container, double width, double height) {
845 int i; 845 int i;
@@ -972,11 +972,11 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
972 case L_HORIZ: 972 case L_HORIZ:
973 default: 973 default:
974 apply_horiz_layout(container, x, y, width, height, 0, 974 apply_horiz_layout(container, x, y, width, height, 0,
975 container->children->length); 975 container->children->length);
976 break; 976 break;
977 case L_VERT: 977 case L_VERT:
978 apply_vert_layout(container, x, y, width, height, 0, 978 apply_vert_layout(container, x, y, width, height, 0,
979 container->children->length); 979 container->children->length);
980 break; 980 break;
981 case L_TABBED: 981 case L_TABBED:
982 case L_STACKED: 982 case L_STACKED:
@@ -1007,7 +1007,7 @@ static void arrange_windows_r(swayc_t *container, double width, double height) {
1007 if (swayc_is_fullscreen(view)) { 1007 if (swayc_is_fullscreen(view)) {
1008 wlc_view_bring_to_front(view->handle); 1008 wlc_view_bring_to_front(view->handle);
1009 } else if (!container->focused || 1009 } else if (!container->focused ||
1010 !swayc_is_fullscreen(container->focused)) { 1010 !swayc_is_fullscreen(container->focused)) {
1011 wlc_view_bring_to_front(view->handle); 1011 wlc_view_bring_to_front(view->handle);
1012 } 1012 }
1013 } 1013 }
@@ -1068,8 +1068,8 @@ void apply_horiz_layout(swayc_t *container, const double x, const double y,
1068} 1068}
1069 1069
1070void apply_vert_layout(swayc_t *container, const double x, const double y, 1070void apply_vert_layout(swayc_t *container, const double x, const double y,
1071 const double width, const double height, const int start, 1071 const double width, const double height, const int start,
1072 const int end) { 1072 const int end) {
1073 int i; 1073 int i;
1074 double scale = 0; 1074 double scale = 0;
1075 // Calculate total height 1075 // Calculate total height
@@ -1121,7 +1121,7 @@ void apply_vert_layout(swayc_t *container, const double x, const double y,
1121} 1121}
1122 1122
1123void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y, 1123void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y,
1124 double width, double height) { 1124 double width, double height) {
1125 int i; 1125 int i;
1126 swayc_t *focused = NULL; 1126 swayc_t *focused = NULL;
1127 for (i = 0; i < container->children->length; ++i) { 1127 for (i = 0; i < container->children->length; ++i) {
@@ -1141,9 +1141,9 @@ void apply_tabbed_or_stacked_layout(swayc_t *container, double x, double y,
1141} 1141}
1142 1142
1143void apply_auto_layout(swayc_t *container, const double x, const double y, 1143void apply_auto_layout(swayc_t *container, const double x, const double y,
1144 const double width, const double height, 1144 const double width, const double height,
1145 enum swayc_layouts group_layout, 1145 enum swayc_layouts group_layout,
1146 bool master_first) { 1146 bool master_first) {
1147 // Auto layout "container" in width x height @ x, y 1147 // Auto layout "container" in width x height @ x, y
1148 // using "group_layout" for each of the groups in the container. 1148 // using "group_layout" for each of the groups in the container.
1149 // There is one "master" group, plus container->nb_slave_groups. 1149 // There is one "master" group, plus container->nb_slave_groups.
@@ -1342,7 +1342,7 @@ swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_directio
1342 return NULL; 1342 return NULL;
1343 } else { 1343 } else {
1344 int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) % 1344 int desired = (focused_idx + (dir == MOVE_NEXT ? 1 : -1)) %
1345 parent->children->length; 1345 parent->children->length;
1346 if (desired < 0) { 1346 if (desired < 0) {
1347 desired += parent->children->length; 1347 desired += parent->children->length;
1348 } 1348 }
@@ -1504,7 +1504,9 @@ bool is_auto_layout(enum swayc_layouts layout) {
1504 * Return the number of master elements in a container 1504 * Return the number of master elements in a container
1505 */ 1505 */
1506static inline size_t auto_master_count(const swayc_t *container) { 1506static inline size_t auto_master_count(const swayc_t *container) {
1507 return MIN(container->nb_master, container->children->length); 1507 sway_assert(container->children->length >= 0, "Container %p has (negative) children %d",
1508 container, container->children->length);
1509 return MIN(container->nb_master, (size_t)container->children->length);
1508} 1510}
1509 1511
1510/** 1512/**
@@ -1535,7 +1537,7 @@ size_t auto_group_count(const swayc_t *container) {
1535 */ 1537 */
1536int auto_group_start_index(const swayc_t *container, int index) { 1538int auto_group_start_index(const swayc_t *container, int index) {
1537 if (index < 0 || ! is_auto_layout(container->layout) 1539 if (index < 0 || ! is_auto_layout(container->layout)
1538 || (size_t) index < container->nb_master) { 1540 || (size_t)index < container->nb_master) {
1539 return 0; 1541 return 0;
1540 } else { 1542 } else {
1541 size_t nb_slaves = auto_slave_count(container); 1543 size_t nb_slaves = auto_slave_count(container);
@@ -1591,7 +1593,7 @@ size_t auto_group_index(const swayc_t *container, int index) {
1591 } 1593 }
1592 bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP); 1594 bool master_first = (container->layout == L_AUTO_LEFT || container->layout == L_AUTO_TOP);
1593 size_t nb_slaves = auto_slave_count(container); 1595 size_t nb_slaves = auto_slave_count(container);
1594 if ((size_t) index < container->nb_master) { 1596 if ((size_t)index < container->nb_master) {
1595 if (master_first || nb_slaves <= 0) { 1597 if (master_first || nb_slaves <= 0) {
1596 return 0; 1598 return 0;
1597 } else { 1599 } else {
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index cbff6cef..5e0a07bd 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -84,13 +84,16 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**(
84 84
85**layout** <mode>:: 85**layout** <mode>::
86 Sets the layout mode of the focused container. _mode_ can be one of _splith_, 86 Sets the layout mode of the focused container. _mode_ can be one of _splith_,
87 _splitv_, _toggle split_, _stacking_, _tabbed_, _auto_left_, _auto_right_, 87 _splitv_, _toggle split_, _stacking_, _tabbed_.
88 _auto_top, _auto_bottom_. 88
89**layout** auto <mode>::
90 Sets layout to one of the auto modes, i.e. one of _left_, right_, _top_,
91 or _bot_.
89 92
90**layout** auto <next|prev>:: 93**layout** auto <next|prev>::
91 Cycles between available auto layouts. 94 Cycles between available auto layouts.
92 95
93**layout** <incnmaster|incncol> <n>:: 96**layout** auto [master|ncol] [inc|set] <n>::
94 Modify the number of master elements, respectively slave columns, in the 97 Modify the number of master elements, respectively slave columns, in the
95 focused container. <n> can be a positive or negative integer. These commands 98 focused container. <n> can be a positive or negative integer. These commands
96 only have an effect if the focused container uses one of the "auto" layouts. 99 only have an effect if the focused container uses one of the "auto" layouts.
@@ -98,9 +101,6 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**(
98**layout** toggle split:: 101**layout** toggle split::
99 Cycles between available split layouts. 102 Cycles between available split layouts.
100 103
101**layout** promote::
102 Swap the focused element with the first in the one of the auto layouts.
103
104**move** <left|right|up|down|next|prev|first>:: 104**move** <left|right|up|down|next|prev|first>::
105 Moves the focused container _left_, _right_, _up_, or _down_. Moving to _prev_ 105 Moves the focused container _left_, _right_, _up_, or _down_. Moving to _prev_
106 or _next_ swaps the container with its sibling in the same container. Move 106 or _next_ swaps the container with its sibling in the same container. Move