summaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
Diffstat (limited to 'sway')
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/resize.c284
-rw-r--r--sway/meson.build46
-rw-r--r--sway/tree/layout.c21
4 files changed, 333 insertions, 19 deletions
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
12static const int MIN_SANE_W = 100, MIN_SANE_H = 60;
13
14enum resize_unit {
15 RESIZE_UNIT_PX,
16 RESIZE_UNIT_PPT,
17 RESIZE_UNIT_DEFAULT,
18 RESIZE_UNIT_INVALID,
19};
20
21enum resize_axis {
22 RESIZE_AXIS_HORIZONTAL,
23 RESIZE_AXIS_VERTICAL,
24 RESIZE_AXIS_INVALID,
25};
26
27static 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
40static 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
50static int parallel_coord(struct sway_container *c, enum resize_axis a) {
51 return a == RESIZE_AXIS_HORIZONTAL ? c->x : c->y;
52}
53
54static int parallel_size(struct sway_container *c, enum resize_axis a) {
55 return a == RESIZE_AXIS_HORIZONTAL ? c->width : c->height;
56}
57
58static 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
188static 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
213struct 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
733void 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}