diff options
Diffstat (limited to 'sway/commands/resize.c')
-rw-r--r-- | sway/commands/resize.c | 515 |
1 files changed, 212 insertions, 303 deletions
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index ef52bb07..93c1fe7d 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -4,372 +4,281 @@ | |||
4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <strings.h> | 6 | #include <strings.h> |
7 | #include <wlc/wlc.h> | 7 | #include <wlr/util/log.h> |
8 | #include "sway/commands.h" | 8 | #include "sway/commands.h" |
9 | #include "sway/layout.h" | 9 | #include "sway/tree/layout.h" |
10 | #include "sway/focus.h" | ||
11 | #include "sway/input_state.h" | ||
12 | #include "sway/handlers.h" | ||
13 | #include "log.h" | 10 | #include "log.h" |
14 | 11 | ||
15 | enum resize_dim_types { | 12 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; |
16 | RESIZE_DIM_PX, | ||
17 | RESIZE_DIM_PPT, | ||
18 | RESIZE_DIM_DEFAULT, | ||
19 | }; | ||
20 | |||
21 | static bool set_size_floating(int new_dimension, bool use_width) { | ||
22 | swayc_t *view = current_container; | ||
23 | if (view) { | ||
24 | if (use_width) { | ||
25 | int current_width = view->width; | ||
26 | view->desired_width = new_dimension; | ||
27 | floating_view_sane_size(view); | ||
28 | |||
29 | int new_x = view->x + (int)(((view->desired_width - current_width) / 2) * -1); | ||
30 | view->width = view->desired_width; | ||
31 | view->x = new_x; | ||
32 | 13 | ||
33 | update_geometry(view); | 14 | enum resize_unit { |
34 | } else { | 15 | RESIZE_UNIT_PX, |
35 | int current_height = view->height; | 16 | RESIZE_UNIT_PPT, |
36 | view->desired_height = new_dimension; | 17 | RESIZE_UNIT_DEFAULT, |
37 | floating_view_sane_size(view); | 18 | RESIZE_UNIT_INVALID, |
38 | 19 | }; | |
39 | int new_y = view->y + (int)(((view->desired_height - current_height) / 2) * -1); | ||
40 | view->height = view->desired_height; | ||
41 | view->y = new_y; | ||
42 | 20 | ||
43 | update_geometry(view); | 21 | enum resize_axis { |
44 | } | 22 | RESIZE_AXIS_HORIZONTAL, |
23 | RESIZE_AXIS_VERTICAL, | ||
24 | RESIZE_AXIS_INVALID, | ||
25 | }; | ||
45 | 26 | ||
46 | return true; | 27 | static enum resize_unit parse_resize_unit(const char *unit) { |
28 | if (strcasecmp(unit, "px") == 0) { | ||
29 | return RESIZE_UNIT_PX; | ||
47 | } | 30 | } |
48 | 31 | if (strcasecmp(unit, "ppt") == 0) { | |
49 | return false; | 32 | return RESIZE_UNIT_PPT; |
33 | } | ||
34 | if (strcasecmp(unit, "default") == 0) { | ||
35 | return RESIZE_UNIT_DEFAULT; | ||
36 | } | ||
37 | return RESIZE_UNIT_INVALID; | ||
50 | } | 38 | } |
51 | 39 | ||
52 | static bool resize_floating(int amount, bool use_width) { | 40 | static enum resize_axis parse_resize_axis(const char *axis) { |
53 | swayc_t *view = current_container; | 41 | if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { |
54 | 42 | return RESIZE_AXIS_HORIZONTAL; | |
55 | if (view) { | 43 | } |
56 | if (use_width) { | 44 | if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { |
57 | return set_size_floating(view->width + amount, true); | 45 | return RESIZE_AXIS_VERTICAL; |
58 | } else { | ||
59 | return set_size_floating(view->height + amount, false); | ||
60 | } | ||
61 | } | 46 | } |
47 | return RESIZE_AXIS_INVALID; | ||
48 | } | ||
62 | 49 | ||
63 | return false; | 50 | static int parallel_coord(struct sway_container *c, enum resize_axis a) { |
51 | return a == RESIZE_AXIS_HORIZONTAL ? c->x : c->y; | ||
64 | } | 52 | } |
65 | 53 | ||
66 | static bool resize_tiled(int amount, bool use_width) { | 54 | static int parallel_size(struct sway_container *c, enum resize_axis a) { |
67 | swayc_t *container = current_container; | 55 | return a == RESIZE_AXIS_HORIZONTAL ? c->width : c->height; |
68 | swayc_t *parent = container->parent; | 56 | } |
69 | int idx_focused = 0; | ||
70 | bool use_major = false; | ||
71 | size_t nb_before = 0; | ||
72 | size_t nb_after = 0; | ||
73 | |||
74 | // 1. Identify a container ancestor that will allow the focused child to grow in the requested | ||
75 | // direction. | ||
76 | while (container->parent) { | ||
77 | parent = container->parent; | ||
78 | if ((parent->children && parent->children->length > 1) | ||
79 | && (is_auto_layout(parent->layout) | ||
80 | || (use_width ? parent->layout == L_HORIZ : parent->layout == L_VERT))) { | ||
81 | // check if container has siblings that can provide/absorb the space needed for | ||
82 | // the resize operation. | ||
83 | use_major = use_width | ||
84 | ? parent->layout == L_AUTO_LEFT || parent->layout == L_AUTO_RIGHT | ||
85 | : parent->layout == L_AUTO_TOP || parent->layout == L_AUTO_BOTTOM; | ||
86 | // Note: use_major will be false for L_HORIZ and L_VERT | ||
87 | |||
88 | idx_focused = index_child(container); | ||
89 | if (idx_focused < 0) { | ||
90 | sway_log(L_ERROR, "Something weird is happening, child container not " | ||
91 | "present in its parent's children list."); | ||
92 | continue; | ||
93 | } | ||
94 | if (use_major) { | ||
95 | nb_before = auto_group_index(parent, idx_focused); | ||
96 | nb_after = auto_group_count(parent) - nb_before - 1; | ||
97 | } else { | ||
98 | nb_before = idx_focused - auto_group_start_index(parent, idx_focused); | ||
99 | nb_after = auto_group_end_index(parent, idx_focused) - idx_focused - 1; | ||
100 | sway_log(L_DEBUG, "+++ focused: %d, start: %d, end: %d, before: %d, after: %d", | ||
101 | idx_focused, | ||
102 | (int)auto_group_start_index(parent, idx_focused), | ||
103 | (int)auto_group_end_index(parent, idx_focused), | ||
104 | (int)nb_before, (int)nb_after); | ||
105 | 57 | ||
106 | } | 58 | static void resize_tiled(int amount, enum resize_axis axis) { |
107 | if (nb_before || nb_after) { | 59 | struct sway_container *parent = config->handler_context.current_container; |
108 | break; | 60 | struct sway_container *focused = parent; |
109 | } | 61 | if (!parent) { |
110 | } | 62 | return; |
111 | container = parent; /* continue up the tree to the next ancestor */ | ||
112 | } | ||
113 | if (parent == &root_container) { | ||
114 | return true; | ||
115 | } | 63 | } |
116 | sway_log(L_DEBUG, "Found the proper parent: %p. It has %zu before conts, " | 64 | |
117 | "and %zu after conts", parent, nb_before, nb_after); | 65 | enum sway_container_layout parallel_layout = |
118 | // 2. Ensure that the resize operation will not make one of the resized containers drop | 66 | axis == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; |
119 | // below the "sane" size threshold. | 67 | int minor_weight = 0; |
120 | bool valid = true; | 68 | int major_weight = 0; |
121 | swayc_t *focused = parent->children->items[idx_focused]; | 69 | while (parent->parent) { |
122 | int start = use_major ? 0 : auto_group_start_index(parent, idx_focused); | 70 | struct sway_container *next = parent->parent; |
123 | int end = use_major ? parent->children->length : auto_group_end_index(parent, idx_focused); | 71 | if (next->layout == parallel_layout) { |
124 | sway_log(L_DEBUG, "Check children of container %p [%d,%d[", container, start, end); | 72 | for (int i = 0; i < next->children->length; i++) { |
125 | for (int i = start; i < end; ) { | 73 | struct sway_container *sibling = next->children->items[i]; |
126 | swayc_t *sibling = parent->children->items[i]; | 74 | |
127 | double pixels = amount; | 75 | int sibling_pos = parallel_coord(sibling, axis); |
128 | bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; | 76 | int focused_pos = parallel_coord(focused, axis); |
129 | bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; | 77 | int parent_pos = parallel_coord(parent, axis); |
130 | if (is_before || is_after) { | 78 | |
131 | pixels = -pixels; | 79 | if (sibling_pos != focused_pos) { |
132 | pixels /= is_before ? nb_before : nb_after; | 80 | if (sibling_pos < parent_pos) { |
133 | if (nb_after != 0 && nb_before != 0) { | 81 | minor_weight++; |
134 | pixels /= 2; | 82 | } else if (sibling_pos > parent_pos) { |
135 | } | 83 | major_weight++; |
136 | } | ||
137 | sway_log(L_DEBUG, "Check container %p: width %g vs %d, height %g vs %d", sibling, sibling->width + pixels, min_sane_w, sibling->height + pixels, min_sane_h); | ||
138 | if (use_width ? | ||
139 | sibling->width + pixels < min_sane_w : | ||
140 | sibling->height + pixels < min_sane_h) { | ||
141 | valid = false; | ||
142 | sway_log(L_DEBUG, "Container size no longer sane"); | ||
143 | break; | ||
144 | } | ||
145 | i = use_major ? auto_group_end_index(parent, i) : (i + 1); | ||
146 | sway_log(L_DEBUG, "+++++ check %i", i); | ||
147 | } | ||
148 | // 3. Apply the size change | ||
149 | if (valid) { | ||
150 | for (int i = start; i < end; ) { | ||
151 | int next_i = use_major ? auto_group_end_index(parent, i) : (i + 1); | ||
152 | swayc_t *sibling = parent->children->items[i]; | ||
153 | double pixels = amount; | ||
154 | bool is_before = use_width ? sibling->x < focused->x : sibling->y < focused->y; | ||
155 | bool is_after = use_width ? sibling->x > focused->x : sibling->y > focused->y; | ||
156 | if (is_before || is_after) { | ||
157 | pixels = -pixels; | ||
158 | pixels /= is_before ? nb_before : nb_after; | ||
159 | if (nb_after != 0 && nb_before != 0) { | ||
160 | pixels /= 2; | ||
161 | } | ||
162 | sway_log(L_DEBUG, "%p: %s", sibling, is_before ? "before" : "after"); | ||
163 | if (use_major) { | ||
164 | for (int j = i; j < next_i; ++j) { | ||
165 | recursive_resize(parent->children->items[j], pixels, | ||
166 | use_width ? | ||
167 | (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : | ||
168 | (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); | ||
169 | } | ||
170 | } else { | ||
171 | recursive_resize(sibling, pixels, | ||
172 | use_width ? | ||
173 | (is_before ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_LEFT) : | ||
174 | (is_before ? WLC_RESIZE_EDGE_BOTTOM : WLC_RESIZE_EDGE_TOP)); | ||
175 | } | ||
176 | } else { | ||
177 | if (use_major) { | ||
178 | for (int j = i; j < next_i; ++j) { | ||
179 | recursive_resize(parent->children->items[j], pixels / 2, | ||
180 | use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); | ||
181 | recursive_resize(parent->children->items[j], pixels / 2, | ||
182 | use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); | ||
183 | } | 84 | } |
184 | } else { | ||
185 | recursive_resize(sibling, pixels / 2, | ||
186 | use_width ? WLC_RESIZE_EDGE_LEFT : WLC_RESIZE_EDGE_TOP); | ||
187 | recursive_resize(sibling, pixels / 2, | ||
188 | use_width ? WLC_RESIZE_EDGE_RIGHT : WLC_RESIZE_EDGE_BOTTOM); | ||
189 | } | 85 | } |
190 | } | 86 | } |
191 | i = next_i; | 87 | if (major_weight || minor_weight) { |
88 | break; | ||
89 | } | ||
192 | } | 90 | } |
193 | // Recursive resize does not handle positions, let arrange_windows | 91 | parent = next; |
194 | // take care of that. | ||
195 | arrange_windows(swayc_active_workspace(), -1, -1); | ||
196 | } | 92 | } |
197 | return true; | ||
198 | } | ||
199 | |||
200 | static bool set_size_tiled(int amount, bool use_width) { | ||
201 | int desired; | ||
202 | swayc_t *focused = current_container; | ||
203 | 93 | ||
204 | if (use_width) { | 94 | if (parent->type == C_ROOT) { |
205 | desired = amount - focused->width; | 95 | return; |
206 | } else { | ||
207 | desired = amount - focused->height; | ||
208 | } | 96 | } |
209 | 97 | ||
210 | return resize_tiled(desired, use_width); | 98 | wlr_log(L_DEBUG, |
211 | } | 99 | "Found the proper parent: %p. It has %d l conts, and %d r conts", |
212 | 100 | parent->parent, minor_weight, major_weight); | |
213 | static bool set_size(int dimension, bool use_width) { | ||
214 | swayc_t *focused = current_container; | ||
215 | 101 | ||
216 | if (focused) { | 102 | int min_sane = axis == RESIZE_AXIS_HORIZONTAL ? MIN_SANE_W : MIN_SANE_H; |
217 | if (focused->is_floating) { | ||
218 | return set_size_floating(dimension, use_width); | ||
219 | } else { | ||
220 | return set_size_tiled(dimension, use_width); | ||
221 | } | ||
222 | } | ||
223 | 103 | ||
224 | return false; | 104 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks |
225 | } | 105 | // ^ ????? |
226 | 106 | ||
227 | static bool resize(int dimension, bool use_width, enum resize_dim_types dim_type) { | 107 | for (int i = 0; i < parent->parent->children->length; i++) { |
228 | swayc_t *focused = current_container; | 108 | struct sway_container *sibling = parent->parent->children->items[i]; |
229 | 109 | ||
230 | // translate "10 ppt" (10%) to appropriate # of pixels in case we need it | 110 | int sibling_pos = parallel_coord(sibling, axis); |
231 | float ppt_dim = (float)dimension / 100; | 111 | int focused_pos = parallel_coord(focused, axis); |
112 | int parent_pos = parallel_coord(parent, axis); | ||
232 | 113 | ||
233 | if (use_width) { | 114 | int sibling_size = parallel_size(sibling, axis); |
234 | ppt_dim = focused->width * ppt_dim; | 115 | int parent_size = parallel_size(parent, axis); |
235 | } else { | ||
236 | ppt_dim = focused->height * ppt_dim; | ||
237 | } | ||
238 | 116 | ||
239 | if (focused) { | 117 | if (sibling_pos != focused_pos) { |
240 | if (focused->is_floating) { | 118 | if (sibling_pos < parent_pos) { |
241 | // floating view resize dimensions should default to px, so only | 119 | double pixels = -amount / minor_weight; |
242 | // use ppt if specified | 120 | if (major_weight && (sibling_size + pixels / 2) < min_sane) { |
243 | if (dim_type == RESIZE_DIM_PPT) { | 121 | return; // Too small |
244 | dimension = (int)ppt_dim; | 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 | } | ||
245 | } | 132 | } |
246 | |||
247 | return resize_floating(dimension, use_width); | ||
248 | } else { | 133 | } else { |
249 | // tiled view resize dimensions should default to ppt, so only use | 134 | double pixels = amount; |
250 | // px if specified | 135 | if (parent_size + pixels < min_sane) { |
251 | if (dim_type != RESIZE_DIM_PX) { | 136 | return; // Too small |
252 | dimension = (int)ppt_dim; | ||
253 | } | 137 | } |
254 | |||
255 | return resize_tiled(dimension, use_width); | ||
256 | } | 138 | } |
257 | } | 139 | } |
258 | 140 | ||
259 | return false; | 141 | enum resize_edge minor_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
260 | } | 142 | RESIZE_EDGE_LEFT : RESIZE_EDGE_TOP; |
143 | enum resize_edge major_edge = axis == RESIZE_AXIS_HORIZONTAL ? | ||
144 | RESIZE_EDGE_RIGHT : RESIZE_EDGE_BOTTOM; | ||
261 | 145 | ||
262 | static struct cmd_results *cmd_resize_set(int argc, char **argv) { | 146 | for (int i = 0; i < parent->parent->children->length; i++) { |
263 | struct cmd_results *error = NULL; | 147 | struct sway_container *sibling = parent->parent->children->items[i]; |
264 | if ((error = checkarg(argc, "resize set", EXPECTED_AT_LEAST, 2))) { | ||
265 | return error; | ||
266 | } | ||
267 | 148 | ||
268 | if (strcasecmp(argv[0], "width") == 0 || strcasecmp(argv[0], "height") == 0) { | 149 | int sibling_pos = parallel_coord(sibling, axis); |
269 | // handle `reset set width 100 px height 100 px` syntax, also allows | 150 | int focused_pos = parallel_coord(focused, axis); |
270 | // specifying only one dimension for a `resize set` | 151 | int parent_pos = parallel_coord(parent, axis); |
271 | int cmd_num = 0; | ||
272 | int dim; | ||
273 | |||
274 | while ((cmd_num + 1) < argc) { | ||
275 | dim = (int)strtol(argv[cmd_num + 1], NULL, 10); | ||
276 | if (errno == ERANGE || dim == 0) { | ||
277 | errno = 0; | ||
278 | return cmd_results_new(CMD_INVALID, "resize set", | ||
279 | "Expected 'resize set <width|height> <amount> [px] [<width|height> <amount> [px]]'"); | ||
280 | } | ||
281 | 152 | ||
282 | if (strcasecmp(argv[cmd_num], "width") == 0) { | 153 | if (sibling_pos != focused_pos) { |
283 | set_size(dim, true); | 154 | if (sibling_pos < parent_pos) { |
284 | } else if (strcasecmp(argv[cmd_num], "height") == 0) { | 155 | double pixels = -1 * amount; |
285 | set_size(dim, false); | 156 | pixels /= minor_weight; |
286 | } else { | 157 | if (major_weight) { |
287 | return cmd_results_new(CMD_INVALID, "resize set", | 158 | container_recursive_resize(sibling, pixels / 2, major_edge); |
288 | "Expected 'resize set <width|height> <amount> [px] [<width|height> <amount> [px]]'"); | 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 | } | ||
289 | } | 170 | } |
290 | 171 | } else { | |
291 | cmd_num += 2; | 172 | if (major_weight != 0 && minor_weight != 0) { |
292 | 173 | double pixels = amount; | |
293 | if (cmd_num < argc && strcasecmp(argv[cmd_num], "px") == 0) { | 174 | pixels /= 2; |
294 | // if this was `resize set width 400 px height 300 px`, disregard the `px` arg | 175 | container_recursive_resize(parent, pixels, minor_edge); |
295 | cmd_num++; | 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); | ||
296 | } | 181 | } |
297 | } | 182 | } |
298 | } else { | 183 | } |
299 | // handle `reset set 100 px 100 px` syntax | ||
300 | int width = (int)strtol(argv[0], NULL, 10); | ||
301 | if (errno == ERANGE || width == 0) { | ||
302 | errno = 0; | ||
303 | return cmd_results_new(CMD_INVALID, "resize set", | ||
304 | "Expected 'resize set <width> [px] <height> [px]'"); | ||
305 | } | ||
306 | 184 | ||
307 | int height_arg = 1; | 185 | arrange_windows(parent->parent, -1, -1); |
308 | if (strcasecmp(argv[1], "px") == 0) { | 186 | } |
309 | height_arg = 2; | ||
310 | } | ||
311 | 187 | ||
312 | int height = (int)strtol(argv[height_arg], NULL, 10); | 188 | static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { |
313 | if (errno == ERANGE || height == 0) { | 189 | struct sway_container *current = config->handler_context.current_container; |
314 | errno = 0; | 190 | if (unit == RESIZE_UNIT_DEFAULT) { |
315 | return cmd_results_new(CMD_INVALID, "resize set", | 191 | // Default for tiling; TODO floating should be px |
316 | "Expected 'resize set <width> [px] <height> [px]'"); | 192 | unit = RESIZE_UNIT_PPT; |
317 | } | 193 | } |
318 | 194 | ||
319 | set_size(width, true); | 195 | if (unit == RESIZE_UNIT_PPT) { |
320 | set_size(height, false); | 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 | } | ||
321 | } | 208 | } |
322 | 209 | ||
323 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 210 | return resize_tiled(amount, axis); |
324 | } | 211 | } |
325 | 212 | ||
326 | struct cmd_results *cmd_resize(int argc, char **argv) { | 213 | struct cmd_results *cmd_resize(int argc, char **argv) { |
327 | struct cmd_results *error = NULL; | 214 | struct sway_container *current = config->handler_context.current_container; |
328 | if (config->reading) return cmd_results_new(CMD_FAILURE, "resize", "Can't be used in config file."); | 215 | if (!current) { |
329 | if (!config->active) return cmd_results_new(CMD_FAILURE, "resize", "Can only be used when sway is running."); | 216 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); |
330 | 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 | } | ||
331 | if (strcasecmp(argv[0], "set") == 0) { | 222 | if (strcasecmp(argv[0], "set") == 0) { |
332 | return cmd_resize_set(argc - 1, &argv[1]); | 223 | // TODO |
224 | //return cmd_resize_set(argc - 1, &argv[1]); | ||
225 | return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented"); | ||
333 | } | 226 | } |
334 | 227 | struct cmd_results *error; | |
335 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { | 228 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { |
336 | return error; | 229 | return error; |
337 | } | 230 | } |
338 | 231 | ||
339 | int dim_arg = argc - 1; | 232 | // TODO: resize grow|shrink left|right|up|down |
340 | 233 | ||
341 | enum resize_dim_types dim_type = RESIZE_DIM_DEFAULT; | 234 | const char *usage = "Expected 'resize <shrink|grow> " |
342 | if (strcasecmp(argv[dim_arg], "ppt") == 0) { | 235 | "<width|height> [<amount>] [px|ppt]'"; |
343 | dim_type = RESIZE_DIM_PPT; | 236 | |
344 | dim_arg--; | 237 | int multiplier = 0; |
345 | } else if (strcasecmp(argv[dim_arg], "px") == 0) { | 238 | if (strcasecmp(*argv, "grow") == 0) { |
346 | dim_type = RESIZE_DIM_PX; | 239 | multiplier = 1; |
347 | dim_arg--; | 240 | } else if (strcasecmp(*argv, "shrink") == 0) { |
241 | multiplier = -1; | ||
242 | } else { | ||
243 | return cmd_results_new(CMD_INVALID, "resize", usage); | ||
348 | } | 244 | } |
245 | --argc; ++argv; | ||
349 | 246 | ||
350 | int amount = (int)strtol(argv[dim_arg], NULL, 10); | 247 | enum resize_axis axis = parse_resize_axis(*argv); |
351 | if (errno == ERANGE || amount == 0) { | 248 | if (axis == RESIZE_AXIS_INVALID) { |
352 | errno = 0; | 249 | return cmd_results_new(CMD_INVALID, "resize", usage); |
353 | amount = 10; // this is the default resize dimension used by i3 for both px and ppt | 250 | } |
354 | sway_log(L_DEBUG, "Tried to get resize dimension out of '%s' but failed; setting dimension to default %d", | 251 | --argc; ++argv; |
355 | argv[dim_arg], amount); | 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; | ||
356 | } | 267 | } |
357 | 268 | ||
358 | bool use_width = false; | 269 | if (argc) { |
359 | if (strcasecmp(argv[1], "width") == 0) { | 270 | unit = parse_resize_unit(*argv); |
360 | use_width = true; | 271 | if (unit == RESIZE_UNIT_INVALID) { |
361 | } else if (strcasecmp(argv[1], "height") != 0) { | 272 | return cmd_results_new(CMD_INVALID, "resize", usage); |
362 | return cmd_results_new(CMD_INVALID, "resize", | 273 | } |
363 | "Expected 'resize <shrink|grow> <width|height> [<amount>] [px|ppt]'"); | 274 | --argc; ++argv; |
364 | } | 275 | } |
365 | 276 | ||
366 | if (strcasecmp(argv[0], "shrink") == 0) { | 277 | if (argc) { |
367 | amount *= -1; | 278 | // Provied too many args, the bastard |
368 | } else if (strcasecmp(argv[0], "grow") != 0) { | 279 | return cmd_results_new(CMD_INVALID, "resize", usage); |
369 | return cmd_results_new(CMD_INVALID, "resize", | ||
370 | "Expected 'resize <shrink|grow> <width|height> [<amount>] [px|ppt]'"); | ||
371 | } | 280 | } |
372 | 281 | ||
373 | resize(amount, use_width, dim_type); | 282 | resize(amount * multiplier, axis, unit); |
374 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 283 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
375 | } | 284 | } |