aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-04-05 00:17:47 -0400
committerLibravatar GitHub <noreply@github.com>2018-04-05 00:17:47 -0400
commit9e89daf21353d3739d84ed25ae99aab82704df97 (patch)
treed7e3d910fc6646515c7869f5177a8c26cb6e35ca
parentMerge pull request #1736 from acrisci/ipc-container-type (diff)
parentImplement resize command (diff)
downloadsway-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.in16
-rw-r--r--include/sway/tree/layout.h10
-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
6 files changed, 351 insertions, 27 deletions
diff --git a/config.in b/config.in
index 086b66dc..54817f2a 100644
--- a/config.in
+++ b/config.in
@@ -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
16enum resize_edge {
17 RESIZE_EDGE_LEFT,
18 RESIZE_EDGE_RIGHT,
19 RESIZE_EDGE_TOP,
20 RESIZE_EDGE_BOTTOM,
21};
22
16struct sway_container; 23struct sway_container;
17 24
18struct sway_root { 25struct sway_root {
@@ -63,4 +70,7 @@ struct sway_container *container_get_in_direction(struct sway_container
63struct sway_container *container_split(struct sway_container *child, 70struct sway_container *container_split(struct sway_container *child,
64 enum sway_container_layout layout); 71 enum sway_container_layout layout);
65 72
73void 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
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}