diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-04-05 00:17:47 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-05 00:17:47 -0400 |
commit | 9e89daf21353d3739d84ed25ae99aab82704df97 (patch) | |
tree | d7e3d910fc6646515c7869f5177a8c26cb6e35ca | |
parent | Merge pull request #1736 from acrisci/ipc-container-type (diff) | |
parent | Implement resize command (diff) | |
download | sway-9e89daf21353d3739d84ed25ae99aab82704df97.tar.gz sway-9e89daf21353d3739d84ed25ae99aab82704df97.tar.zst sway-9e89daf21353d3739d84ed25ae99aab82704df97.zip |
Merge pull request #1734 from swaywm/resize-cmd
Implement resize command
-rw-r--r-- | config.in | 16 | ||||
-rw-r--r-- | include/sway/tree/layout.h | 10 | ||||
-rw-r--r-- | sway/commands.c | 1 | ||||
-rw-r--r-- | sway/commands/resize.c | 284 | ||||
-rw-r--r-- | sway/meson.build | 46 | ||||
-rw-r--r-- | sway/tree/layout.c | 21 |
6 files changed, 351 insertions, 27 deletions
@@ -164,16 +164,16 @@ mode "resize" { | |||
164 | # right will grow the containers width | 164 | # right will grow the containers width |
165 | # up will shrink the containers height | 165 | # up will shrink the containers height |
166 | # down will grow the containers height | 166 | # down will grow the containers height |
167 | bindsym $left resize shrink width 10 px or 10 ppt | 167 | bindsym $left resize shrink width 10px |
168 | bindsym $down resize grow height 10 px or 10 ppt | 168 | bindsym $down resize grow height 10px |
169 | bindsym $up resize shrink height 10 px or 10 ppt | 169 | bindsym $up resize shrink height 10px |
170 | bindsym $right resize grow width 10 px or 10 ppt | 170 | bindsym $right resize grow width 10px |
171 | 171 | ||
172 | # ditto, with arrow keys | 172 | # ditto, with arrow keys |
173 | bindsym Left resize shrink width 10 px or 10 ppt | 173 | bindsym Left resize shrink width 10px |
174 | bindsym Down resize grow height 10 px or 10 ppt | 174 | bindsym Down resize grow height 10px |
175 | bindsym Up resize shrink height 10 px or 10 ppt | 175 | bindsym Up resize shrink height 10px |
176 | bindsym Right resize grow width 10 px or 10 ppt | 176 | bindsym Right resize grow width 10px |
177 | 177 | ||
178 | # return to default mode | 178 | # return to default mode |
179 | bindsym Return mode "default" | 179 | bindsym Return mode "default" |
diff --git a/include/sway/tree/layout.h b/include/sway/tree/layout.h index 784dcc9b..fc5ce21f 100644 --- a/include/sway/tree/layout.h +++ b/include/sway/tree/layout.h | |||
@@ -13,6 +13,13 @@ enum movement_direction { | |||
13 | MOVE_CHILD, | 13 | MOVE_CHILD, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | enum resize_edge { | ||
17 | RESIZE_EDGE_LEFT, | ||
18 | RESIZE_EDGE_RIGHT, | ||
19 | RESIZE_EDGE_TOP, | ||
20 | RESIZE_EDGE_BOTTOM, | ||
21 | }; | ||
22 | |||
16 | struct sway_container; | 23 | struct sway_container; |
17 | 24 | ||
18 | struct sway_root { | 25 | struct sway_root { |
@@ -63,4 +70,7 @@ struct sway_container *container_get_in_direction(struct sway_container | |||
63 | struct sway_container *container_split(struct sway_container *child, | 70 | struct sway_container *container_split(struct sway_container *child, |
64 | enum sway_container_layout layout); | 71 | enum sway_container_layout layout); |
65 | 72 | ||
73 | void container_recursive_resize(struct sway_container *container, | ||
74 | double amount, enum resize_edge edge); | ||
75 | |||
66 | #endif | 76 | #endif |
diff --git a/sway/commands.c b/sway/commands.c index 2786a879..22decef3 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -165,6 +165,7 @@ static struct cmd_handler command_handlers[] = { | |||
165 | { "move", cmd_move }, | 165 | { "move", cmd_move }, |
166 | { "opacity", cmd_opacity }, | 166 | { "opacity", cmd_opacity }, |
167 | { "reload", cmd_reload }, | 167 | { "reload", cmd_reload }, |
168 | { "resize", cmd_resize }, | ||
168 | { "split", cmd_split }, | 169 | { "split", cmd_split }, |
169 | { "splith", cmd_splith }, | 170 | { "splith", cmd_splith }, |
170 | { "splitt", cmd_splitt }, | 171 | { "splitt", cmd_splitt }, |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c new file mode 100644 index 00000000..93c1fe7d --- /dev/null +++ b/sway/commands/resize.c | |||
@@ -0,0 +1,284 @@ | |||
1 | #include <errno.h> | ||
2 | #include <math.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | #include <strings.h> | ||
7 | #include <wlr/util/log.h> | ||
8 | #include "sway/commands.h" | ||
9 | #include "sway/tree/layout.h" | ||
10 | #include "log.h" | ||
11 | |||
12 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; | ||
13 | |||
14 | enum resize_unit { | ||
15 | RESIZE_UNIT_PX, | ||
16 | RESIZE_UNIT_PPT, | ||
17 | RESIZE_UNIT_DEFAULT, | ||
18 | RESIZE_UNIT_INVALID, | ||
19 | }; | ||
20 | |||
21 | enum resize_axis { | ||
22 | RESIZE_AXIS_HORIZONTAL, | ||
23 | RESIZE_AXIS_VERTICAL, | ||
24 | RESIZE_AXIS_INVALID, | ||
25 | }; | ||
26 | |||
27 | static enum resize_unit parse_resize_unit(const char *unit) { | ||
28 | if (strcasecmp(unit, "px") == 0) { | ||
29 | return RESIZE_UNIT_PX; | ||
30 | } | ||
31 | if (strcasecmp(unit, "ppt") == 0) { | ||
32 | return RESIZE_UNIT_PPT; | ||
33 | } | ||
34 | if (strcasecmp(unit, "default") == 0) { | ||
35 | return RESIZE_UNIT_DEFAULT; | ||
36 | } | ||
37 | return RESIZE_UNIT_INVALID; | ||
38 | } | ||
39 | |||
40 | static enum resize_axis parse_resize_axis(const char *axis) { | ||
41 | if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { | ||
42 | return RESIZE_AXIS_HORIZONTAL; | ||
43 | } | ||
44 | if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { | ||
45 | return RESIZE_AXIS_VERTICAL; | ||
46 | } | ||
47 | return RESIZE_AXIS_INVALID; | ||
48 | } | ||
49 | |||
50 | static int parallel_coord(struct sway_container *c, enum resize_axis a) { | ||
51 | return a == RESIZE_AXIS_HORIZONTAL ? c->x : c->y; | ||
52 | } | ||
53 | |||
54 | static int parallel_size(struct sway_container *c, enum resize_axis a) { | ||
55 | return a == RESIZE_AXIS_HORIZONTAL ? c->width : c->height; | ||
56 | } | ||
57 | |||
58 | static void resize_tiled(int amount, enum resize_axis axis) { | ||
59 | struct sway_container *parent = config->handler_context.current_container; | ||
60 | struct sway_container *focused = parent; | ||
61 | if (!parent) { | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | enum sway_container_layout parallel_layout = | ||
66 | axis == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; | ||
67 | int minor_weight = 0; | ||
68 | int major_weight = 0; | ||
69 | while (parent->parent) { | ||
70 | struct sway_container *next = parent->parent; | ||
71 | if (next->layout == parallel_layout) { | ||
72 | for (int i = 0; i < next->children->length; i++) { | ||
73 | struct sway_container *sibling = next->children->items[i]; | ||
74 | |||
75 | int sibling_pos = parallel_coord(sibling, axis); | ||
76 | int focused_pos = parallel_coord(focused, axis); | ||
77 | int parent_pos = parallel_coord(parent, axis); | ||
78 | |||
79 | if (sibling_pos != focused_pos) { | ||
80 | if (sibling_pos < parent_pos) { | ||
81 | minor_weight++; | ||
82 | } else if (sibling_pos > parent_pos) { | ||
83 | major_weight++; | ||
84 | } | ||
85 | } | ||
86 | } | ||
87 | if (major_weight || minor_weight) { | ||
88 | break; | ||
89 | } | ||
90 | } | ||
91 | parent = next; | ||
92 | } | ||
93 | |||
94 | if (parent->type == C_ROOT) { | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | wlr_log(L_DEBUG, | ||
99 | "Found the proper parent: %p. It has %d l conts, and %d r conts", | ||
100 | parent->parent, minor_weight, major_weight); | ||
101 | |||
102 | int min_sane = axis == RESIZE_AXIS_HORIZONTAL ? MIN_SANE_W : MIN_SANE_H; | ||
103 | |||
104 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks | ||
105 | // ^ ????? | ||
106 | |||
107 | for (int i = 0; i < parent->parent->children->length; i++) { | ||
108 | struct sway_container *sibling = parent->parent->children->items[i]; | ||
109 | |||
110 | int sibling_pos = parallel_coord(sibling, axis); | ||
111 | int focused_pos = parallel_coord(focused, axis); | ||
112 | int parent_pos = parallel_coord(parent, axis); | ||
113 | |||
114 | int sibling_size = parallel_size(sibling, axis); | ||
115 | int parent_size = parallel_size(parent, axis); | ||
116 | |||
117 | if (sibling_pos != focused_pos) { | ||
118 | if (sibling_pos < parent_pos) { | ||
119 | double pixels = -amount / minor_weight; | ||
120 | if (major_weight && (sibling_size + pixels / 2) < min_sane) { | ||
121 | return; // Too small | ||
122 | } else if ((sibling_size + pixels) < min_sane) { | ||
123 | return; // Too small | ||
124 | } | ||
125 | } else if (sibling_pos > parent_pos) { | ||
126 | double pixels = -amount / major_weight; | ||
127 | if (minor_weight && (sibling_size + pixels / 2) < min_sane) { | ||
128 | return; // Too small | ||
129 | } else if ((sibling_size + pixels) < min_sane) { | ||
130 | return; // Too small | ||
131 | } | ||
132 | } | ||
133 | } else { | ||
134 | double pixels = amount; | ||
135 | if (parent_size + pixels < min_sane) { | ||
136 | return; // Too small | ||
137 | } | ||
138 | } | ||
139 | } | ||
140 | |||
141 | enum resize_edge minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? | ||
142 | RESIZE_EDGE_LEFT : RESIZE_EDGE_TOP; | ||
143 | enum resize_edge major_edge = axis == RESIZE_AXIS_HORIZONTAL ? | ||
144 | RESIZE_EDGE_RIGHT : RESIZE_EDGE_BOTTOM; | ||
145 | |||
146 | for (int i = 0; i < parent->parent->children->length; i++) { | ||
147 | struct sway_container *sibling = parent->parent->children->items[i]; | ||
148 | |||
149 | int sibling_pos = parallel_coord(sibling, axis); | ||
150 | int focused_pos = parallel_coord(focused, axis); | ||
151 | int parent_pos = parallel_coord(parent, axis); | ||
152 | |||
153 | if (sibling_pos != focused_pos) { | ||
154 | if (sibling_pos < parent_pos) { | ||
155 | double pixels = -1 * amount; | ||
156 | pixels /= minor_weight; | ||
157 | if (major_weight) { | ||
158 | container_recursive_resize(sibling, pixels / 2, major_edge); | ||
159 | } else { | ||
160 | container_recursive_resize(sibling, pixels, major_edge); | ||
161 | } | ||
162 | } else if (sibling_pos > parent_pos) { | ||
163 | double pixels = -1 * amount; | ||
164 | pixels /= major_weight; | ||
165 | if (minor_weight) { | ||
166 | container_recursive_resize(sibling, pixels / 2, minor_edge); | ||
167 | } else { | ||
168 | container_recursive_resize(sibling, pixels, minor_edge); | ||
169 | } | ||
170 | } | ||
171 | } else { | ||
172 | if (major_weight != 0 && minor_weight != 0) { | ||
173 | double pixels = amount; | ||
174 | pixels /= 2; | ||
175 | container_recursive_resize(parent, pixels, minor_edge); | ||
176 | container_recursive_resize(parent, pixels, major_edge); | ||
177 | } else if (major_weight) { | ||
178 | container_recursive_resize(parent, amount, major_edge); | ||
179 | } else if (minor_weight) { | ||
180 | container_recursive_resize(parent, amount, minor_edge); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | arrange_windows(parent->parent, -1, -1); | ||
186 | } | ||
187 | |||
188 | static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { | ||
189 | struct sway_container *current = config->handler_context.current_container; | ||
190 | if (unit == RESIZE_UNIT_DEFAULT) { | ||
191 | // Default for tiling; TODO floating should be px | ||
192 | unit = RESIZE_UNIT_PPT; | ||
193 | } | ||
194 | |||
195 | if (unit == RESIZE_UNIT_PPT) { | ||
196 | float pct = amount / 100.0f; | ||
197 | switch (axis) { | ||
198 | case RESIZE_AXIS_HORIZONTAL: | ||
199 | amount = (float)current->width * pct; | ||
200 | break; | ||
201 | case RESIZE_AXIS_VERTICAL: | ||
202 | amount = (float)current->height * pct; | ||
203 | break; | ||
204 | default: | ||
205 | sway_assert(0, "invalid resize axis"); | ||
206 | return; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | return resize_tiled(amount, axis); | ||
211 | } | ||
212 | |||
213 | struct cmd_results *cmd_resize(int argc, char **argv) { | ||
214 | struct sway_container *current = config->handler_context.current_container; | ||
215 | if (!current) { | ||
216 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); | ||
217 | } | ||
218 | if (current->type != C_VIEW && current->type != C_CONTAINER) { | ||
219 | return cmd_results_new(CMD_INVALID, "resize", | ||
220 | "Can only resize views/containers"); | ||
221 | } | ||
222 | if (strcasecmp(argv[0], "set") == 0) { | ||
223 | // TODO | ||
224 | //return cmd_resize_set(argc - 1, &argv[1]); | ||
225 | return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented"); | ||
226 | } | ||
227 | struct cmd_results *error; | ||
228 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { | ||
229 | return error; | ||
230 | } | ||
231 | |||
232 | // TODO: resize grow|shrink left|right|up|down | ||
233 | |||
234 | const char *usage = "Expected 'resize <shrink|grow> " | ||
235 | "<width|height> [<amount>] [px|ppt]'"; | ||
236 | |||
237 | int multiplier = 0; | ||
238 | if (strcasecmp(*argv, "grow") == 0) { | ||
239 | multiplier = 1; | ||
240 | } else if (strcasecmp(*argv, "shrink") == 0) { | ||
241 | multiplier = -1; | ||
242 | } else { | ||
243 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
244 | } | ||
245 | --argc; ++argv; | ||
246 | |||
247 | enum resize_axis axis = parse_resize_axis(*argv); | ||
248 | if (axis == RESIZE_AXIS_INVALID) { | ||
249 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
250 | } | ||
251 | --argc; ++argv; | ||
252 | |||
253 | int amount = 10; // Default amount | ||
254 | enum resize_unit unit = RESIZE_UNIT_DEFAULT; | ||
255 | |||
256 | if (argc) { | ||
257 | char *err; | ||
258 | amount = (int)strtol(*argv, &err, 10); | ||
259 | if (*err) { | ||
260 | // e.g. `resize grow width 10px` | ||
261 | unit = parse_resize_unit(err); | ||
262 | if (unit == RESIZE_UNIT_INVALID) { | ||
263 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
264 | } | ||
265 | } | ||
266 | --argc; ++argv; | ||
267 | } | ||
268 | |||
269 | if (argc) { | ||
270 | unit = parse_resize_unit(*argv); | ||
271 | if (unit == RESIZE_UNIT_INVALID) { | ||
272 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
273 | } | ||
274 | --argc; ++argv; | ||
275 | } | ||
276 | |||
277 | if (argc) { | ||
278 | // Provied too many args, the bastard | ||
279 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
280 | } | ||
281 | |||
282 | resize(amount * multiplier, axis, unit); | ||
283 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
284 | } | ||
diff --git a/sway/meson.build b/sway/meson.build index f210c195..ec7b4c42 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -2,10 +2,28 @@ sway_sources = files( | |||
2 | 'main.c', | 2 | 'main.c', |
3 | 'server.c', | 3 | 'server.c', |
4 | 'commands.c', | 4 | 'commands.c', |
5 | 'config.c', | ||
6 | 'criteria.c', | ||
7 | 'ipc-json.c', | ||
8 | 'ipc-server.c', | ||
9 | 'security.c', | ||
10 | |||
11 | 'desktop/output.c', | ||
12 | 'desktop/layer_shell.c', | ||
13 | 'desktop/wl_shell.c', | ||
14 | 'desktop/xdg_shell_v6.c', | ||
15 | 'desktop/xwayland.c', | ||
16 | |||
5 | 'input/input-manager.c', | 17 | 'input/input-manager.c', |
6 | 'input/seat.c', | 18 | 'input/seat.c', |
7 | 'input/cursor.c', | 19 | 'input/cursor.c', |
8 | 'input/keyboard.c', | 20 | 'input/keyboard.c', |
21 | |||
22 | 'config/bar.c', | ||
23 | 'config/output.c', | ||
24 | 'config/seat.c', | ||
25 | 'config/input.c', | ||
26 | |||
9 | 'commands/bar.c', | 27 | 'commands/bar.c', |
10 | 'commands/bind.c', | 28 | 'commands/bind.c', |
11 | 'commands/default_orientation.c', | 29 | 'commands/default_orientation.c', |
@@ -20,13 +38,19 @@ sway_sources = files( | |||
20 | 'commands/input.c', | 38 | 'commands/input.c', |
21 | 'commands/layout.c', | 39 | 'commands/layout.c', |
22 | 'commands/mode.c', | 40 | 'commands/mode.c', |
23 | 'commands/split.c', | 41 | 'commands/mouse_warping.c', |
24 | 'commands/move.c', | 42 | 'commands/move.c', |
43 | 'commands/output.c', | ||
44 | 'commands/reload.c', | ||
45 | 'commands/resize.c', | ||
25 | 'commands/seat.c', | 46 | 'commands/seat.c', |
26 | 'commands/seat/attach.c', | 47 | 'commands/seat/attach.c', |
27 | 'commands/seat/fallback.c', | 48 | 'commands/seat/fallback.c', |
28 | 'commands/set.c', | 49 | 'commands/set.c', |
50 | 'commands/split.c', | ||
29 | 'commands/swaybg_command.c', | 51 | 'commands/swaybg_command.c', |
52 | 'commands/workspace.c', | ||
53 | |||
30 | 'commands/bar/activate_button.c', | 54 | 'commands/bar/activate_button.c', |
31 | 'commands/bar/binding_mode_indicator.c', | 55 | 'commands/bar/binding_mode_indicator.c', |
32 | 'commands/bar/bindsym.c', | 56 | 'commands/bar/bindsym.c', |
@@ -51,6 +75,7 @@ sway_sources = files( | |||
51 | 'commands/bar/tray_padding.c', | 75 | 'commands/bar/tray_padding.c', |
52 | 'commands/bar/workspace_buttons.c', | 76 | 'commands/bar/workspace_buttons.c', |
53 | 'commands/bar/wrap_scroll.c', | 77 | 'commands/bar/wrap_scroll.c', |
78 | |||
54 | 'commands/input/accel_profile.c', | 79 | 'commands/input/accel_profile.c', |
55 | 'commands/input/click_method.c', | 80 | 'commands/input/click_method.c', |
56 | 'commands/input/drag_lock.c', | 81 | 'commands/input/drag_lock.c', |
@@ -67,24 +92,7 @@ sway_sources = files( | |||
67 | 'commands/input/xkb_options.c', | 92 | 'commands/input/xkb_options.c', |
68 | 'commands/input/xkb_rules.c', | 93 | 'commands/input/xkb_rules.c', |
69 | 'commands/input/xkb_variant.c', | 94 | 'commands/input/xkb_variant.c', |
70 | 'commands/mouse_warping.c', | 95 | |
71 | 'commands/output.c', | ||
72 | 'commands/reload.c', | ||
73 | 'commands/workspace.c', | ||
74 | 'config.c', | ||
75 | 'config/bar.c', | ||
76 | 'config/output.c', | ||
77 | 'config/seat.c', | ||
78 | 'config/input.c', | ||
79 | 'criteria.c', | ||
80 | 'ipc-json.c', | ||
81 | 'ipc-server.c', | ||
82 | 'desktop/output.c', | ||
83 | 'desktop/layer_shell.c', | ||
84 | 'desktop/wl_shell.c', | ||
85 | 'desktop/xdg_shell_v6.c', | ||
86 | 'desktop/xwayland.c', | ||
87 | 'security.c', | ||
88 | 'tree/container.c', | 96 | 'tree/container.c', |
89 | 'tree/layout.c', | 97 | 'tree/layout.c', |
90 | 'tree/view.c', | 98 | 'tree/view.c', |
diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 1769609b..65fd5d4a 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c | |||
@@ -729,3 +729,24 @@ struct sway_container *container_split(struct sway_container *child, | |||
729 | 729 | ||
730 | return cont; | 730 | return cont; |
731 | } | 731 | } |
732 | |||
733 | void container_recursive_resize(struct sway_container *container, | ||
734 | double amount, enum resize_edge edge) { | ||
735 | bool layout_match = true; | ||
736 | wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); | ||
737 | if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { | ||
738 | container->width += amount; | ||
739 | layout_match = container->layout == L_HORIZ; | ||
740 | } else if (edge == RESIZE_EDGE_TOP || edge == RESIZE_EDGE_BOTTOM) { | ||
741 | container->height += amount; | ||
742 | layout_match = container->layout == L_VERT; | ||
743 | } | ||
744 | if (container->children) { | ||
745 | for (int i = 0; i < container->children->length; i++) { | ||
746 | struct sway_container *child = container->children->items[i]; | ||
747 | double amt = layout_match ? | ||
748 | amount / container->children->length : amount; | ||
749 | container_recursive_resize(child, amt, edge); | ||
750 | } | ||
751 | } | ||
752 | } | ||