diff options
Diffstat (limited to 'sway/commands')
-rw-r--r-- | sway/commands/border.c | 13 | ||||
-rw-r--r-- | sway/commands/floating.c | 18 | ||||
-rw-r--r-- | sway/commands/focus.c | 284 | ||||
-rw-r--r-- | sway/commands/fullscreen.c | 18 | ||||
-rw-r--r-- | sway/commands/gaps.c | 35 | ||||
-rw-r--r-- | sway/commands/hide_edge_borders.c | 4 | ||||
-rw-r--r-- | sway/commands/kill.c | 20 | ||||
-rw-r--r-- | sway/commands/layout.c | 185 | ||||
-rw-r--r-- | sway/commands/mark.c | 7 | ||||
-rw-r--r-- | sway/commands/move.c | 887 | ||||
-rw-r--r-- | sway/commands/opacity.c | 3 | ||||
-rw-r--r-- | sway/commands/reload.c | 2 | ||||
-rw-r--r-- | sway/commands/rename.c | 11 | ||||
-rw-r--r-- | sway/commands/resize.c | 86 | ||||
-rw-r--r-- | sway/commands/scratchpad.c | 42 | ||||
-rw-r--r-- | sway/commands/seat/cursor.c | 4 | ||||
-rw-r--r-- | sway/commands/show_marks.c | 10 | ||||
-rw-r--r-- | sway/commands/smart_gaps.c | 2 | ||||
-rw-r--r-- | sway/commands/split.c | 23 | ||||
-rw-r--r-- | sway/commands/sticky.c | 27 | ||||
-rw-r--r-- | sway/commands/swap.c | 76 | ||||
-rw-r--r-- | sway/commands/title_format.c | 7 | ||||
-rw-r--r-- | sway/commands/unmark.c | 13 | ||||
-rw-r--r-- | sway/commands/urgent.c | 7 | ||||
-rw-r--r-- | sway/commands/workspace.c | 2 |
25 files changed, 867 insertions, 919 deletions
diff --git a/sway/commands/border.c b/sway/commands/border.c index 9502c877..95498b2f 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -13,13 +13,12 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
13 | return error; | 13 | return error; |
14 | } | 14 | } |
15 | 15 | ||
16 | struct sway_container *container = | 16 | struct sway_container *container = config->handler_context.container; |
17 | config->handler_context.current_container; | 17 | if (!container->view) { |
18 | if (container->type != C_VIEW) { | ||
19 | return cmd_results_new(CMD_INVALID, "border", | 18 | return cmd_results_new(CMD_INVALID, "border", |
20 | "Only views can have borders"); | 19 | "Only views can have borders"); |
21 | } | 20 | } |
22 | struct sway_view *view = container->sway_view; | 21 | struct sway_view *view = container->view; |
23 | 22 | ||
24 | if (strcmp(argv[0], "none") == 0) { | 23 | if (strcmp(argv[0], "none") == 0) { |
25 | view->border = B_NONE; | 24 | view->border = B_NONE; |
@@ -38,11 +37,11 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
38 | view->border_thickness = atoi(argv[1]); | 37 | view->border_thickness = atoi(argv[1]); |
39 | } | 38 | } |
40 | 39 | ||
41 | if (container_is_floating(view->swayc)) { | 40 | if (container_is_floating(view->container)) { |
42 | container_set_geometry_from_floating_view(view->swayc); | 41 | container_set_geometry_from_floating_view(view->container); |
43 | } | 42 | } |
44 | 43 | ||
45 | arrange_windows(view->swayc); | 44 | arrange_container(view->container); |
46 | 45 | ||
47 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 46 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
48 | if (seat->cursor) { | 47 | if (seat->cursor) { |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index 436376e3..d8729094 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -15,24 +15,23 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
15 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { | 15 | if ((error = checkarg(argc, "floating", EXPECTED_EQUAL_TO, 1))) { |
16 | return error; | 16 | return error; |
17 | } | 17 | } |
18 | struct sway_container *container = | 18 | struct sway_container *container = config->handler_context.container; |
19 | config->handler_context.current_container; | 19 | struct sway_workspace *workspace = config->handler_context.workspace; |
20 | if (container->type == C_WORKSPACE && container->children->length == 0) { | 20 | if (!container && workspace->tiling->length == 0) { |
21 | return cmd_results_new(CMD_INVALID, "floating", | 21 | return cmd_results_new(CMD_INVALID, "floating", |
22 | "Can't float an empty workspace"); | 22 | "Can't float an empty workspace"); |
23 | } | 23 | } |
24 | if (container->type == C_WORKSPACE) { | 24 | if (!container) { |
25 | // Wrap the workspace's children in a container so we can float it | 25 | // Wrap the workspace's children in a container so we can float it |
26 | struct sway_container *workspace = container; | 26 | container = workspace_wrap_children(workspace); |
27 | container = workspace_wrap_children(container); | ||
28 | workspace->layout = L_HORIZ; | 27 | workspace->layout = L_HORIZ; |
29 | seat_set_focus(config->handler_context.seat, container); | 28 | seat_set_focus(config->handler_context.seat, &container->node); |
30 | } | 29 | } |
31 | 30 | ||
32 | // If the container is in a floating split container, | 31 | // If the container is in a floating split container, |
33 | // operate on the split container instead of the child. | 32 | // operate on the split container instead of the child. |
34 | if (container_is_floating_or_child(container)) { | 33 | if (container_is_floating_or_child(container)) { |
35 | while (container->parent->type != C_WORKSPACE) { | 34 | while (container->parent) { |
36 | container = container->parent; | 35 | container = container->parent; |
37 | } | 36 | } |
38 | } | 37 | } |
@@ -51,8 +50,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
51 | 50 | ||
52 | container_set_floating(container, wants_floating); | 51 | container_set_floating(container, wants_floating); |
53 | 52 | ||
54 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | 53 | arrange_workspace(container->workspace); |
55 | arrange_windows(workspace); | ||
56 | 54 | ||
57 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 55 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
58 | } | 56 | } |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index f342e524..83b8c64a 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -34,58 +34,49 @@ static bool parse_movement_direction(const char *name, | |||
34 | } | 34 | } |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * Get swayc in the direction of newly entered output. | 37 | * Get node in the direction of newly entered output. |
38 | */ | 38 | */ |
39 | static struct sway_container *get_swayc_in_output_direction( | 39 | static struct sway_node *get_node_in_output_direction( |
40 | struct sway_container *output, enum movement_direction dir, | 40 | struct sway_output *output, enum movement_direction dir) { |
41 | struct sway_seat *seat) { | 41 | struct sway_seat *seat = config->handler_context.seat; |
42 | if (!output) { | 42 | struct sway_workspace *ws = output_get_active_workspace(output); |
43 | return NULL; | 43 | if (ws->fullscreen) { |
44 | } | 44 | return seat_get_focus_inactive(seat, &ws->fullscreen->node); |
45 | |||
46 | struct sway_container *ws = seat_get_focus_inactive(seat, output); | ||
47 | if (ws->type != C_WORKSPACE) { | ||
48 | ws = container_parent(ws, C_WORKSPACE); | ||
49 | } | ||
50 | |||
51 | if (ws == NULL) { | ||
52 | wlr_log(WLR_ERROR, "got an output without a workspace"); | ||
53 | return NULL; | ||
54 | } | 45 | } |
46 | struct sway_container *container = NULL; | ||
55 | 47 | ||
56 | if (ws->children->length > 0) { | 48 | if (ws->tiling->length > 0) { |
57 | switch (dir) { | 49 | switch (dir) { |
58 | case MOVE_LEFT: | 50 | case MOVE_LEFT: |
59 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { | 51 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { |
60 | // get most right child of new output | 52 | // get most right child of new output |
61 | return ws->children->items[ws->children->length-1]; | 53 | container = ws->tiling->items[ws->tiling->length-1]; |
62 | } else { | 54 | } else { |
63 | return seat_get_focus_inactive(seat, ws); | 55 | container = seat_get_focus_inactive_tiling(seat, ws); |
64 | } | 56 | } |
57 | break; | ||
65 | case MOVE_RIGHT: | 58 | case MOVE_RIGHT: |
66 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { | 59 | if (ws->layout == L_HORIZ || ws->layout == L_TABBED) { |
67 | // get most left child of new output | 60 | // get most left child of new output |
68 | return ws->children->items[0]; | 61 | container = ws->tiling->items[0]; |
69 | } else { | 62 | } else { |
70 | return seat_get_focus_inactive(seat, ws); | 63 | container = seat_get_focus_inactive_tiling(seat, ws); |
71 | } | 64 | } |
65 | break; | ||
72 | case MOVE_UP: | 66 | case MOVE_UP: |
67 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { | ||
68 | // get most bottom child of new output | ||
69 | container = ws->tiling->items[ws->tiling->length-1]; | ||
70 | } else { | ||
71 | container = seat_get_focus_inactive_tiling(seat, ws); | ||
72 | } | ||
73 | break; | ||
73 | case MOVE_DOWN: { | 74 | case MOVE_DOWN: { |
74 | struct sway_container *focused = | 75 | if (ws->layout == L_VERT || ws->layout == L_STACKED) { |
75 | seat_get_focus_inactive(seat, ws); | 76 | // get most top child of new output |
76 | if (focused && focused->parent) { | 77 | container = ws->tiling->items[0]; |
77 | struct sway_container *parent = focused->parent; | 78 | } else { |
78 | if (parent->layout == L_VERT) { | 79 | container = seat_get_focus_inactive_tiling(seat, ws); |
79 | if (dir == MOVE_UP) { | ||
80 | // get child furthest down on new output | ||
81 | int idx = parent->children->length - 1; | ||
82 | return parent->children->items[idx]; | ||
83 | } else if (dir == MOVE_DOWN) { | ||
84 | // get child furthest up on new output | ||
85 | return parent->children->items[0]; | ||
86 | } | ||
87 | } | ||
88 | return focused; | ||
89 | } | 80 | } |
90 | break; | 81 | break; |
91 | } | 82 | } |
@@ -94,151 +85,90 @@ static struct sway_container *get_swayc_in_output_direction( | |||
94 | } | 85 | } |
95 | } | 86 | } |
96 | 87 | ||
97 | return ws; | 88 | if (container) { |
98 | } | 89 | container = seat_get_focus_inactive_view(seat, &container->node); |
90 | return &container->node; | ||
91 | } | ||
99 | 92 | ||
100 | static struct sway_container *container_get_in_direction( | 93 | return &ws->node; |
101 | struct sway_container *container, struct sway_seat *seat, | 94 | } |
102 | enum movement_direction dir) { | ||
103 | struct sway_container *parent = container->parent; | ||
104 | 95 | ||
105 | if (dir == MOVE_CHILD) { | 96 | static struct sway_node *node_get_in_direction(struct sway_container *container, |
106 | return seat_get_focus_inactive(seat, container); | 97 | struct sway_seat *seat, enum movement_direction dir) { |
107 | } | ||
108 | if (container->is_fullscreen) { | 98 | if (container->is_fullscreen) { |
109 | if (dir == MOVE_PARENT) { | 99 | if (dir == MOVE_PARENT) { |
110 | return NULL; | 100 | return NULL; |
111 | } | 101 | } |
112 | container = container_parent(container, C_OUTPUT); | 102 | // Fullscreen container with a direction - go straight to outputs |
113 | parent = container->parent; | 103 | struct sway_output *output = container->workspace->output; |
114 | } else { | 104 | struct sway_output *new_output = output_get_in_direction(output, dir); |
115 | if (dir == MOVE_PARENT) { | 105 | return get_node_in_output_direction(new_output, dir); |
116 | if (parent->type == C_OUTPUT || container_is_floating(container)) { | 106 | } |
117 | return NULL; | 107 | if (dir == MOVE_PARENT) { |
118 | } else { | 108 | return node_get_parent(&container->node); |
119 | return parent; | ||
120 | } | ||
121 | } | ||
122 | } | 109 | } |
123 | 110 | ||
124 | struct sway_container *wrap_candidate = NULL; | 111 | struct sway_container *wrap_candidate = NULL; |
125 | while (true) { | 112 | struct sway_container *current = container; |
113 | while (current) { | ||
126 | bool can_move = false; | 114 | bool can_move = false; |
127 | int desired; | 115 | int desired; |
128 | int idx = list_find(container->parent->children, container); | 116 | int idx = container_sibling_index(current); |
129 | if (idx == -1) { | 117 | enum sway_container_layout parent_layout = |
130 | return NULL; | 118 | container_parent_layout(current); |
131 | } | 119 | list_t *siblings = container_get_siblings(current); |
132 | if (parent->type == C_ROOT) { | ||
133 | enum wlr_direction wlr_dir = 0; | ||
134 | if (!sway_assert(sway_dir_to_wlr(dir, &wlr_dir), | ||
135 | "got invalid direction: %d", dir)) { | ||
136 | return NULL; | ||
137 | } | ||
138 | int lx = container->x + container->width / 2; | ||
139 | int ly = container->y + container->height / 2; | ||
140 | struct wlr_output_layout *layout = | ||
141 | root_container.sway_root->output_layout; | ||
142 | struct wlr_output *wlr_adjacent = | ||
143 | wlr_output_layout_adjacent_output(layout, wlr_dir, | ||
144 | container->sway_output->wlr_output, lx, ly); | ||
145 | struct sway_container *adjacent = | ||
146 | output_from_wlr_output(wlr_adjacent); | ||
147 | 120 | ||
148 | if (!adjacent || adjacent == container) { | 121 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { |
149 | if (!wrap_candidate) { | 122 | if (parent_layout == L_HORIZ || parent_layout == L_TABBED) { |
150 | return NULL; | 123 | can_move = true; |
151 | } | 124 | desired = idx + (dir == MOVE_LEFT ? -1 : 1); |
152 | return seat_get_focus_inactive_view(seat, wrap_candidate); | ||
153 | } | ||
154 | struct sway_container *next = | ||
155 | get_swayc_in_output_direction(adjacent, dir, seat); | ||
156 | if (next == NULL) { | ||
157 | return NULL; | ||
158 | } | ||
159 | struct sway_container *next_workspace = next; | ||
160 | if (next_workspace->type != C_WORKSPACE) { | ||
161 | next_workspace = container_parent(next_workspace, C_WORKSPACE); | ||
162 | } | ||
163 | sway_assert(next_workspace, "Next container has no workspace"); | ||
164 | if (next_workspace->sway_workspace->fullscreen) { | ||
165 | return seat_get_focus_inactive(seat, | ||
166 | next_workspace->sway_workspace->fullscreen); | ||
167 | } | ||
168 | if (next->children && next->children->length) { | ||
169 | // TODO consider floating children as well | ||
170 | return seat_get_focus_inactive_view(seat, next); | ||
171 | } else { | ||
172 | return next; | ||
173 | } | 125 | } |
174 | } else { | 126 | } else { |
175 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { | 127 | if (parent_layout == L_VERT || parent_layout == L_STACKED) { |
176 | if (parent->layout == L_HORIZ || parent->layout == L_TABBED) { | 128 | can_move = true; |
177 | can_move = true; | 129 | desired = idx + (dir == MOVE_UP ? -1 : 1); |
178 | desired = idx + (dir == MOVE_LEFT ? -1 : 1); | ||
179 | } | ||
180 | } else { | ||
181 | if (parent->layout == L_VERT || parent->layout == L_STACKED) { | ||
182 | can_move = true; | ||
183 | desired = idx + (dir == MOVE_UP ? -1 : 1); | ||
184 | } | ||
185 | } | 130 | } |
186 | } | 131 | } |
187 | 132 | ||
188 | if (can_move) { | 133 | if (can_move) { |
189 | // TODO handle floating | 134 | if (desired < 0 || desired >= siblings->length) { |
190 | if (desired < 0 || desired >= parent->children->length) { | ||
191 | can_move = false; | 135 | can_move = false; |
192 | int len = parent->children->length; | 136 | int len = siblings->length; |
193 | if (config->focus_wrapping != WRAP_NO && !wrap_candidate | 137 | if (config->focus_wrapping != WRAP_NO && !wrap_candidate |
194 | && len > 1) { | 138 | && len > 1) { |
195 | if (desired < 0) { | 139 | if (desired < 0) { |
196 | wrap_candidate = parent->children->items[len-1]; | 140 | wrap_candidate = siblings->items[len-1]; |
197 | } else { | 141 | } else { |
198 | wrap_candidate = parent->children->items[0]; | 142 | wrap_candidate = siblings->items[0]; |
199 | } | 143 | } |
200 | if (config->focus_wrapping == WRAP_FORCE) { | 144 | if (config->focus_wrapping == WRAP_FORCE) { |
201 | return seat_get_focus_inactive_view(seat, | 145 | struct sway_container *c = seat_get_focus_inactive_view( |
202 | wrap_candidate); | 146 | seat, &wrap_candidate->node); |
147 | return &c->node; | ||
203 | } | 148 | } |
204 | } | 149 | } |
205 | } else { | 150 | } else { |
206 | struct sway_container *desired_con = | 151 | struct sway_container *desired_con = siblings->items[desired]; |
207 | parent->children->items[desired]; | 152 | struct sway_container *c = seat_get_focus_inactive_view( |
208 | wlr_log(WLR_DEBUG, | 153 | seat, &desired_con->node); |
209 | "cont %d-%p dir %i sibling %d: %p", idx, | 154 | return &c->node; |
210 | container, dir, desired, desired_con); | ||
211 | return seat_get_focus_inactive_view(seat, desired_con); | ||
212 | } | 155 | } |
213 | } | 156 | } |
214 | 157 | ||
215 | if (!can_move) { | 158 | current = current->parent; |
216 | container = parent; | ||
217 | parent = parent->parent; | ||
218 | if (!parent) { | ||
219 | // wrapping is the last chance | ||
220 | if (!wrap_candidate) { | ||
221 | return NULL; | ||
222 | } | ||
223 | return seat_get_focus_inactive_view(seat, wrap_candidate); | ||
224 | } | ||
225 | } | ||
226 | } | 159 | } |
227 | } | ||
228 | |||
229 | static struct cmd_results *focus_mode(struct sway_container *con, | ||
230 | struct sway_seat *seat, bool floating) { | ||
231 | struct sway_container *ws = con->type == C_WORKSPACE ? | ||
232 | con : container_parent(con, C_WORKSPACE); | ||
233 | 160 | ||
234 | // If the container is in a floating split container, | 161 | // Check a different output |
235 | // operate on the split container instead of the child. | 162 | struct sway_output *output = container->workspace->output; |
236 | if (container_is_floating_or_child(con)) { | 163 | struct sway_output *new_output = output_get_in_direction(output, dir); |
237 | while (con->parent->type != C_WORKSPACE) { | 164 | if (new_output) { |
238 | con = con->parent; | 165 | return get_node_in_output_direction(new_output, dir); |
239 | } | ||
240 | } | 166 | } |
167 | return NULL; | ||
168 | } | ||
241 | 169 | ||
170 | static struct cmd_results *focus_mode(struct sway_workspace *ws, | ||
171 | struct sway_seat *seat, bool floating) { | ||
242 | struct sway_container *new_focus = NULL; | 172 | struct sway_container *new_focus = NULL; |
243 | if (floating) { | 173 | if (floating) { |
244 | new_focus = seat_get_focus_inactive_floating(seat, ws); | 174 | new_focus = seat_get_focus_inactive_floating(seat, ws); |
@@ -246,7 +176,7 @@ static struct cmd_results *focus_mode(struct sway_container *con, | |||
246 | new_focus = seat_get_focus_inactive_tiling(seat, ws); | 176 | new_focus = seat_get_focus_inactive_tiling(seat, ws); |
247 | } | 177 | } |
248 | if (new_focus) { | 178 | if (new_focus) { |
249 | seat_set_focus(seat, new_focus); | 179 | seat_set_focus(seat, &new_focus->node); |
250 | } else { | 180 | } else { |
251 | return cmd_results_new(CMD_FAILURE, "focus", | 181 | return cmd_results_new(CMD_FAILURE, "focus", |
252 | "Failed to find a %s container in workspace", | 182 | "Failed to find a %s container in workspace", |
@@ -255,14 +185,14 @@ static struct cmd_results *focus_mode(struct sway_container *con, | |||
255 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 185 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
256 | } | 186 | } |
257 | 187 | ||
258 | static struct cmd_results *focus_output(struct sway_container *con, | 188 | static struct cmd_results *focus_output(struct sway_seat *seat, |
259 | struct sway_seat *seat, int argc, char **argv) { | 189 | int argc, char **argv) { |
260 | if (!argc) { | 190 | if (!argc) { |
261 | return cmd_results_new(CMD_INVALID, "focus", | 191 | return cmd_results_new(CMD_INVALID, "focus", |
262 | "Expected 'focus output <direction|name>'"); | 192 | "Expected 'focus output <direction|name>'"); |
263 | } | 193 | } |
264 | char *identifier = join_args(argv, argc); | 194 | char *identifier = join_args(argv, argc); |
265 | struct sway_container *output = output_by_name(identifier); | 195 | struct sway_output *output = output_by_name(identifier); |
266 | 196 | ||
267 | if (!output) { | 197 | if (!output) { |
268 | enum movement_direction direction; | 198 | enum movement_direction direction; |
@@ -272,14 +202,13 @@ static struct cmd_results *focus_output(struct sway_container *con, | |||
272 | return cmd_results_new(CMD_INVALID, "focus", | 202 | return cmd_results_new(CMD_INVALID, "focus", |
273 | "There is no output with that name"); | 203 | "There is no output with that name"); |
274 | } | 204 | } |
275 | struct sway_container *focus = seat_get_focus(seat); | 205 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
276 | focus = container_parent(focus, C_OUTPUT); | 206 | output = output_get_in_direction(ws->output, direction); |
277 | output = container_get_in_direction(focus, seat, direction); | ||
278 | } | 207 | } |
279 | 208 | ||
280 | free(identifier); | 209 | free(identifier); |
281 | if (output) { | 210 | if (output) { |
282 | seat_set_focus(seat, seat_get_focus_inactive(seat, output)); | 211 | seat_set_focus(seat, seat_get_focus_inactive(seat, &output->node)); |
283 | } | 212 | } |
284 | 213 | ||
285 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 214 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
@@ -289,29 +218,32 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
289 | if (config->reading || !config->active) { | 218 | if (config->reading || !config->active) { |
290 | return cmd_results_new(CMD_DEFER, NULL, NULL); | 219 | return cmd_results_new(CMD_DEFER, NULL, NULL); |
291 | } | 220 | } |
292 | struct sway_container *con = config->handler_context.current_container; | 221 | struct sway_node *node = config->handler_context.node; |
222 | struct sway_container *container = config->handler_context.container; | ||
223 | struct sway_workspace *workspace = config->handler_context.workspace; | ||
293 | struct sway_seat *seat = config->handler_context.seat; | 224 | struct sway_seat *seat = config->handler_context.seat; |
294 | if (con->type < C_WORKSPACE) { | 225 | if (node->type < N_WORKSPACE) { |
295 | return cmd_results_new(CMD_FAILURE, "focus", | 226 | return cmd_results_new(CMD_FAILURE, "focus", |
296 | "Command 'focus' cannot be used above the workspace level"); | 227 | "Command 'focus' cannot be used above the workspace level"); |
297 | } | 228 | } |
298 | 229 | ||
299 | if (argc == 0) { | 230 | if (argc == 0) { |
300 | seat_set_focus(seat, con); | 231 | seat_set_focus(seat, node); |
301 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 232 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
302 | } | 233 | } |
303 | 234 | ||
304 | if (strcmp(argv[0], "floating") == 0) { | 235 | if (strcmp(argv[0], "floating") == 0) { |
305 | return focus_mode(con, seat, true); | 236 | return focus_mode(workspace, seat, true); |
306 | } else if (strcmp(argv[0], "tiling") == 0) { | 237 | } else if (strcmp(argv[0], "tiling") == 0) { |
307 | return focus_mode(con, seat, false); | 238 | return focus_mode(workspace, seat, false); |
308 | } else if (strcmp(argv[0], "mode_toggle") == 0) { | 239 | } else if (strcmp(argv[0], "mode_toggle") == 0) { |
309 | return focus_mode(con, seat, !container_is_floating_or_child(con)); | 240 | bool floating = container && container_is_floating_or_child(container); |
241 | return focus_mode(workspace, seat, !floating); | ||
310 | } | 242 | } |
311 | 243 | ||
312 | if (strcmp(argv[0], "output") == 0) { | 244 | if (strcmp(argv[0], "output") == 0) { |
313 | argc--; argv++; | 245 | argc--; argv++; |
314 | return focus_output(con, seat, argc, argv); | 246 | return focus_output(seat, argc, argv); |
315 | } | 247 | } |
316 | 248 | ||
317 | enum movement_direction direction = 0; | 249 | enum movement_direction direction = 0; |
@@ -321,8 +253,34 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
321 | "or 'focus output <direction|name>'"); | 253 | "or 'focus output <direction|name>'"); |
322 | } | 254 | } |
323 | 255 | ||
324 | struct sway_container *next_focus = container_get_in_direction( | 256 | if (direction == MOVE_CHILD) { |
325 | con, seat, direction); | 257 | struct sway_node *focus = seat_get_active_child(seat, node); |
258 | if (focus) { | ||
259 | seat_set_focus(seat, focus); | ||
260 | } | ||
261 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
262 | } | ||
263 | |||
264 | if (node->type == N_WORKSPACE) { | ||
265 | if (direction == MOVE_PARENT) { | ||
266 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
267 | } | ||
268 | |||
269 | // Jump to the next output | ||
270 | struct sway_output *new_output = | ||
271 | output_get_in_direction(workspace->output, direction); | ||
272 | if (!new_output) { | ||
273 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
274 | } | ||
275 | |||
276 | struct sway_node *node = | ||
277 | get_node_in_output_direction(new_output, direction); | ||
278 | seat_set_focus(seat, node); | ||
279 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
280 | } | ||
281 | |||
282 | struct sway_node *next_focus = | ||
283 | node_get_in_direction(container, seat, direction); | ||
326 | if (next_focus) { | 284 | if (next_focus) { |
327 | seat_set_focus(seat, next_focus); | 285 | seat_set_focus(seat, next_focus); |
328 | } | 286 | } |
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index ac65dffb..3bbe00c5 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -12,18 +12,18 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
12 | if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { | 12 | if ((error = checkarg(argc, "fullscreen", EXPECTED_LESS_THAN, 2))) { |
13 | return error; | 13 | return error; |
14 | } | 14 | } |
15 | struct sway_container *container = | 15 | struct sway_node *node = config->handler_context.node; |
16 | config->handler_context.current_container; | 16 | struct sway_container *container = config->handler_context.container; |
17 | if (container->type == C_WORKSPACE && container->children->length == 0) { | 17 | struct sway_workspace *workspace = config->handler_context.workspace; |
18 | if (node->type == N_WORKSPACE && workspace->tiling->length == 0) { | ||
18 | return cmd_results_new(CMD_INVALID, "fullscreen", | 19 | return cmd_results_new(CMD_INVALID, "fullscreen", |
19 | "Can't fullscreen an empty workspace"); | 20 | "Can't fullscreen an empty workspace"); |
20 | } | 21 | } |
21 | if (container->type == C_WORKSPACE) { | 22 | if (node->type == N_WORKSPACE) { |
22 | // Wrap the workspace's children in a container so we can fullscreen it | 23 | // Wrap the workspace's children in a container so we can fullscreen it |
23 | struct sway_container *workspace = container; | 24 | container = workspace_wrap_children(workspace); |
24 | container = workspace_wrap_children(container); | ||
25 | workspace->layout = L_HORIZ; | 25 | workspace->layout = L_HORIZ; |
26 | seat_set_focus(config->handler_context.seat, container); | 26 | seat_set_focus(config->handler_context.seat, &container->node); |
27 | } | 27 | } |
28 | bool enable = !container->is_fullscreen; | 28 | bool enable = !container->is_fullscreen; |
29 | 29 | ||
@@ -32,9 +32,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
32 | } | 32 | } |
33 | 33 | ||
34 | container_set_fullscreen(container, enable); | 34 | container_set_fullscreen(container, enable); |
35 | 35 | arrange_workspace(workspace); | |
36 | struct sway_container *workspace = container_parent(container, C_WORKSPACE); | ||
37 | arrange_windows(workspace->parent); | ||
38 | 36 | ||
39 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 37 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
40 | } | 38 | } |
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 3906eb70..d676e475 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include "sway/commands.h" | 2 | #include "sway/commands.h" |
3 | #include "sway/config.h" | 3 | #include "sway/config.h" |
4 | #include "sway/tree/arrange.h" | 4 | #include "sway/tree/arrange.h" |
5 | #include "sway/tree/workspace.h" | ||
5 | #include "log.h" | 6 | #include "log.h" |
6 | #include "stringop.h" | 7 | #include "stringop.h" |
7 | #include <math.h> | 8 | #include <math.h> |
@@ -43,7 +44,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
43 | return cmd_results_new(CMD_INVALID, "gaps", | 44 | return cmd_results_new(CMD_INVALID, "gaps", |
44 | "gaps edge_gaps on|off|toggle"); | 45 | "gaps edge_gaps on|off|toggle"); |
45 | } | 46 | } |
46 | arrange_windows(&root_container); | 47 | arrange_root(); |
47 | } else { | 48 | } else { |
48 | int amount_idx = 0; // the current index in argv | 49 | int amount_idx = 0; // the current index in argv |
49 | enum gaps_op op = GAPS_OP_SET; | 50 | enum gaps_op op = GAPS_OP_SET; |
@@ -124,7 +125,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
124 | if (amount_idx == 0) { // gaps <amount> | 125 | if (amount_idx == 0) { // gaps <amount> |
125 | config->gaps_inner = val; | 126 | config->gaps_inner = val; |
126 | config->gaps_outer = val; | 127 | config->gaps_outer = val; |
127 | arrange_windows(&root_container); | 128 | arrange_root(); |
128 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 129 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
129 | } | 130 | } |
130 | // Other variants. The middle-length variant (gaps inner|outer <amount>) | 131 | // Other variants. The middle-length variant (gaps inner|outer <amount>) |
@@ -155,21 +156,27 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
155 | } else { | 156 | } else { |
156 | config->gaps_outer = total; | 157 | config->gaps_outer = total; |
157 | } | 158 | } |
158 | arrange_windows(&root_container); | 159 | arrange_root(); |
159 | } else { | 160 | } else { |
160 | struct sway_container *c = | 161 | if (scope == GAPS_SCOPE_WORKSPACE) { |
161 | config->handler_context.current_container; | 162 | struct sway_workspace *ws = config->handler_context.workspace; |
162 | if (scope == GAPS_SCOPE_WORKSPACE && c->type != C_WORKSPACE) { | 163 | ws->has_gaps = true; |
163 | c = container_parent(c, C_WORKSPACE); | 164 | if (inner) { |
164 | } | 165 | ws->gaps_inner = total; |
165 | c->has_gaps = true; | 166 | } else { |
166 | if (inner) { | 167 | ws->gaps_outer = total; |
167 | c->gaps_inner = total; | 168 | } |
169 | arrange_workspace(ws); | ||
168 | } else { | 170 | } else { |
169 | c->gaps_outer = total; | 171 | struct sway_container *c = config->handler_context.container; |
172 | c->has_gaps = true; | ||
173 | if (inner) { | ||
174 | c->gaps_inner = total; | ||
175 | } else { | ||
176 | c->gaps_outer = total; | ||
177 | } | ||
178 | arrange_workspace(c->workspace); | ||
170 | } | 179 | } |
171 | |||
172 | arrange_windows(c->parent ? c->parent : &root_container); | ||
173 | } | 180 | } |
174 | } | 181 | } |
175 | 182 | ||
diff --git a/sway/commands/hide_edge_borders.c b/sway/commands/hide_edge_borders.c index e494f6aa..0a5c7f28 100644 --- a/sway/commands/hide_edge_borders.c +++ b/sway/commands/hide_edge_borders.c | |||
@@ -5,8 +5,8 @@ | |||
5 | #include "sway/tree/view.h" | 5 | #include "sway/tree/view.h" |
6 | 6 | ||
7 | static void _configure_view(struct sway_container *con, void *data) { | 7 | static void _configure_view(struct sway_container *con, void *data) { |
8 | if (con->type == C_VIEW) { | 8 | if (con->view) { |
9 | view_autoconfigure(con->sway_view); | 9 | view_autoconfigure(con->view); |
10 | } | 10 | } |
11 | } | 11 | } |
12 | 12 | ||
diff --git a/sway/commands/kill.c b/sway/commands/kill.c index f3fa52f1..85ca0f33 100644 --- a/sway/commands/kill.c +++ b/sway/commands/kill.c | |||
@@ -2,15 +2,27 @@ | |||
2 | #include "log.h" | 2 | #include "log.h" |
3 | #include "sway/input/input-manager.h" | 3 | #include "sway/input/input-manager.h" |
4 | #include "sway/input/seat.h" | 4 | #include "sway/input/seat.h" |
5 | #include "sway/tree/view.h" | ||
6 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | ||
7 | #include "sway/tree/workspace.h" | ||
7 | #include "sway/commands.h" | 8 | #include "sway/commands.h" |
8 | 9 | ||
10 | static void close_container_iterator(struct sway_container *con, void *data) { | ||
11 | if (con->view) { | ||
12 | view_close(con->view); | ||
13 | } | ||
14 | } | ||
15 | |||
9 | struct cmd_results *cmd_kill(int argc, char **argv) { | 16 | struct cmd_results *cmd_kill(int argc, char **argv) { |
10 | struct sway_container *con = | 17 | struct sway_container *con = config->handler_context.container; |
11 | config->handler_context.current_container; | 18 | struct sway_workspace *ws = config->handler_context.workspace; |
12 | 19 | ||
13 | container_close(con); | 20 | if (con) { |
21 | close_container_iterator(con, NULL); | ||
22 | container_for_each_child(con, close_container_iterator, NULL); | ||
23 | } else { | ||
24 | workspace_for_each_container(ws, close_container_iterator, NULL); | ||
25 | } | ||
14 | 26 | ||
15 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
16 | } | 28 | } |
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index a06832de..44ce2970 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -4,21 +4,20 @@ | |||
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/tree/arrange.h" | 5 | #include "sway/tree/arrange.h" |
6 | #include "sway/tree/container.h" | 6 | #include "sway/tree/container.h" |
7 | #include "sway/tree/workspace.h" | ||
7 | #include "log.h" | 8 | #include "log.h" |
8 | 9 | ||
9 | static bool parse_layout_string(char *s, enum sway_container_layout *ptr) { | 10 | static enum sway_container_layout parse_layout_string(char *s) { |
10 | if (strcasecmp(s, "splith") == 0) { | 11 | if (strcasecmp(s, "splith") == 0) { |
11 | *ptr = L_HORIZ; | 12 | return L_HORIZ; |
12 | } else if (strcasecmp(s, "splitv") == 0) { | 13 | } else if (strcasecmp(s, "splitv") == 0) { |
13 | *ptr = L_VERT; | 14 | return L_VERT; |
14 | } else if (strcasecmp(s, "tabbed") == 0) { | 15 | } else if (strcasecmp(s, "tabbed") == 0) { |
15 | *ptr = L_TABBED; | 16 | return L_TABBED; |
16 | } else if (strcasecmp(s, "stacking") == 0) { | 17 | } else if (strcasecmp(s, "stacking") == 0) { |
17 | *ptr = L_STACKED; | 18 | return L_STACKED; |
18 | } else { | ||
19 | return false; | ||
20 | } | 19 | } |
21 | return true; | 20 | return L_NONE; |
22 | } | 21 | } |
23 | 22 | ||
24 | static const char* expected_syntax = | 23 | static const char* expected_syntax = |
@@ -26,84 +25,128 @@ static const char* expected_syntax = | |||
26 | "'layout toggle [split|all]' or " | 25 | "'layout toggle [split|all]' or " |
27 | "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; | 26 | "'layout toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]...'"; |
28 | 27 | ||
28 | static enum sway_container_layout get_layout_toggle(int argc, char **argv, | ||
29 | enum sway_container_layout layout, | ||
30 | enum sway_container_layout prev_split_layout) { | ||
31 | // "layout toggle" | ||
32 | if (argc == 0) { | ||
33 | return layout == L_HORIZ ? L_VERT : L_HORIZ; | ||
34 | } | ||
35 | |||
36 | if (argc == 2) { | ||
37 | // "layout toggle split" (same as "layout toggle") | ||
38 | if (strcasecmp(argv[1], "split") == 0) { | ||
39 | return layout == L_HORIZ ? L_VERT : L_HORIZ; | ||
40 | } | ||
41 | // "layout toggle all" | ||
42 | if (strcasecmp(argv[1], "all") == 0) { | ||
43 | return layout == L_HORIZ ? L_VERT : | ||
44 | layout == L_VERT ? L_STACKED : | ||
45 | layout == L_STACKED ? L_TABBED : L_HORIZ; | ||
46 | } | ||
47 | return L_NONE; | ||
48 | } | ||
49 | |||
50 | enum sway_container_layout parsed; | ||
51 | int curr = 1; | ||
52 | for (; curr < argc; curr++) { | ||
53 | parsed = parse_layout_string(argv[curr]); | ||
54 | if (parsed == layout || (strcmp(argv[curr], "split") == 0 && | ||
55 | (layout == L_VERT || layout == L_HORIZ))) { | ||
56 | break; | ||
57 | } | ||
58 | } | ||
59 | for (int i = curr + 1; i != curr; ++i) { | ||
60 | // cycle round to find next valid layout | ||
61 | if (i >= argc) { | ||
62 | i = 1; | ||
63 | } | ||
64 | parsed = parse_layout_string(argv[i]); | ||
65 | if (parsed != L_NONE) { | ||
66 | return parsed; | ||
67 | } | ||
68 | if (strcmp(argv[i], "split") == 0) { | ||
69 | return layout == L_HORIZ ? L_VERT : | ||
70 | layout == L_VERT ? L_HORIZ : prev_split_layout; | ||
71 | } | ||
72 | // invalid layout strings are silently ignored | ||
73 | } | ||
74 | return L_NONE; | ||
75 | } | ||
76 | |||
77 | static enum sway_container_layout get_layout(int argc, char **argv, | ||
78 | enum sway_container_layout layout, | ||
79 | enum sway_container_layout prev_split_layout) { | ||
80 | // Check if assigned directly | ||
81 | enum sway_container_layout parsed = parse_layout_string(argv[0]); | ||
82 | if (parsed != L_NONE) { | ||
83 | return parsed; | ||
84 | } | ||
85 | |||
86 | if (strcasecmp(argv[0], "default") == 0) { | ||
87 | return prev_split_layout; | ||
88 | } | ||
89 | |||
90 | if (strcasecmp(argv[0], "toggle") == 0) { | ||
91 | return get_layout_toggle(argc, argv, layout, prev_split_layout); | ||
92 | } | ||
93 | |||
94 | return L_NONE; | ||
95 | } | ||
96 | |||
29 | struct cmd_results *cmd_layout(int argc, char **argv) { | 97 | struct cmd_results *cmd_layout(int argc, char **argv) { |
30 | struct cmd_results *error = NULL; | 98 | struct cmd_results *error = NULL; |
31 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { | 99 | if ((error = checkarg(argc, "layout", EXPECTED_MORE_THAN, 0))) { |
32 | return error; | 100 | return error; |
33 | } | 101 | } |
34 | struct sway_container *parent = config->handler_context.current_container; | 102 | struct sway_container *container = config->handler_context.container; |
103 | struct sway_workspace *workspace = config->handler_context.workspace; | ||
35 | 104 | ||
36 | if (container_is_floating(parent)) { | 105 | if (container && container_is_floating(container)) { |
37 | return cmd_results_new(CMD_FAILURE, "layout", | 106 | return cmd_results_new(CMD_FAILURE, "layout", |
38 | "Unable to change layout of floating windows"); | 107 | "Unable to change layout of floating windows"); |
39 | } | 108 | } |
40 | 109 | ||
41 | while (parent->type == C_VIEW) { | 110 | // Typically we change the layout of the current container, but if the |
42 | parent = parent->parent; | 111 | // current container is a view (it usually is) then we'll change the layout |
112 | // of the parent instead, as it doesn't make sense for views to have layout. | ||
113 | if (container && container->view) { | ||
114 | container = container->parent; | ||
43 | } | 115 | } |
44 | 116 | ||
45 | enum sway_container_layout prev = parent->layout; | 117 | // We could be working with a container OR a workspace. These are different |
46 | bool assigned_directly = parse_layout_string(argv[0], &parent->layout); | 118 | // structures, so we set up pointers to they layouts so we can refer them in |
47 | if (!assigned_directly) { | 119 | // an abstract way. |
48 | if (strcasecmp(argv[0], "default") == 0) { | 120 | enum sway_container_layout new_layout = L_NONE; |
49 | parent->layout = parent->prev_split_layout; | 121 | enum sway_container_layout old_layout = L_NONE; |
50 | } else if (strcasecmp(argv[0], "toggle") == 0) { | 122 | if (container) { |
51 | if (argc == 1) { | 123 | old_layout = container->layout; |
52 | parent->layout = | 124 | new_layout = get_layout(argc, argv, |
53 | parent->layout == L_STACKED ? L_TABBED : | 125 | container->layout, container->prev_split_layout); |
54 | parent->layout == L_TABBED ? parent->prev_split_layout : L_STACKED; | 126 | } else { |
55 | } else if (argc == 2) { | 127 | old_layout = workspace->layout; |
56 | if (strcasecmp(argv[1], "all") == 0) { | 128 | new_layout = get_layout(argc, argv, |
57 | parent->layout = | 129 | workspace->layout, workspace->prev_split_layout); |
58 | parent->layout == L_HORIZ ? L_VERT : | ||
59 | parent->layout == L_VERT ? L_STACKED : | ||
60 | parent->layout == L_STACKED ? L_TABBED : L_HORIZ; | ||
61 | } else if (strcasecmp(argv[1], "split") == 0) { | ||
62 | parent->layout = | ||
63 | parent->layout == L_HORIZ ? L_VERT : | ||
64 | parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; | ||
65 | } else { | ||
66 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); | ||
67 | } | ||
68 | } else { | ||
69 | enum sway_container_layout parsed_layout; | ||
70 | int curr = 1; | ||
71 | for (; curr < argc; curr++) { | ||
72 | bool valid = parse_layout_string(argv[curr], &parsed_layout); | ||
73 | if ((valid && parsed_layout == parent->layout) || | ||
74 | (strcmp(argv[curr], "split") == 0 && | ||
75 | (parent->layout == L_VERT || parent->layout == L_HORIZ))) { | ||
76 | break; | ||
77 | } | ||
78 | } | ||
79 | for (int i = curr + 1; i != curr; ++i) { | ||
80 | // cycle round to find next valid layout | ||
81 | if (i >= argc) { | ||
82 | i = 1; | ||
83 | } | ||
84 | if (parse_layout_string(argv[i], &parent->layout)) { | ||
85 | break; | ||
86 | } else if (strcmp(argv[i], "split") == 0) { | ||
87 | parent->layout = | ||
88 | parent->layout == L_HORIZ ? L_VERT : | ||
89 | parent->layout == L_VERT ? L_HORIZ : parent->prev_split_layout; | ||
90 | break; | ||
91 | } // invalid layout strings are silently ignored | ||
92 | } | ||
93 | } | ||
94 | } else { | ||
95 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); | ||
96 | } | ||
97 | } | 130 | } |
98 | if (parent->layout == L_NONE) { | 131 | if (new_layout == L_NONE) { |
99 | parent->layout = container_get_default_layout(parent); | 132 | return cmd_results_new(CMD_INVALID, "layout", expected_syntax); |
100 | } | 133 | } |
101 | if (prev != parent->layout) { | 134 | if (new_layout != old_layout) { |
102 | if (prev != L_TABBED && prev != L_STACKED) { | 135 | if (container) { |
103 | parent->prev_split_layout = prev; | 136 | if (old_layout != L_TABBED && old_layout != L_STACKED) { |
137 | container->prev_split_layout = old_layout; | ||
138 | } | ||
139 | container->layout = new_layout; | ||
140 | container_update_representation(container); | ||
141 | arrange_container(container); | ||
142 | } else { | ||
143 | if (old_layout != L_TABBED && old_layout != L_STACKED) { | ||
144 | workspace->prev_split_layout = old_layout; | ||
145 | } | ||
146 | workspace->layout = new_layout; | ||
147 | workspace_update_representation(workspace); | ||
148 | arrange_workspace(workspace); | ||
104 | } | 149 | } |
105 | container_notify_subtree_changed(parent); | ||
106 | arrange_windows(parent->parent); | ||
107 | } | 150 | } |
108 | 151 | ||
109 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 152 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 9ea8c301..fb95a7d0 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c | |||
@@ -18,13 +18,12 @@ struct cmd_results *cmd_mark(int argc, char **argv) { | |||
18 | if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { | 18 | if ((error = checkarg(argc, "mark", EXPECTED_AT_LEAST, 1))) { |
19 | return error; | 19 | return error; |
20 | } | 20 | } |
21 | struct sway_container *container = | 21 | struct sway_container *container = config->handler_context.container; |
22 | config->handler_context.current_container; | 22 | if (!container->view) { |
23 | if (container->type != C_VIEW) { | ||
24 | return cmd_results_new(CMD_INVALID, "mark", | 23 | return cmd_results_new(CMD_INVALID, "mark", |
25 | "Only views can have marks"); | 24 | "Only views can have marks"); |
26 | } | 25 | } |
27 | struct sway_view *view = container->sway_view; | 26 | struct sway_view *view = container->view; |
28 | 27 | ||
29 | bool add = false, toggle = false; | 28 | bool add = false, toggle = false; |
30 | while (argc > 0 && strncmp(*argv, "--", 2) == 0) { | 29 | while (argc > 0 && strncmp(*argv, "--", 2) == 0) { |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 4426f24e..7b503624 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -40,8 +40,8 @@ enum wlr_direction opposite_direction(enum wlr_direction d) { | |||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | static struct sway_container *output_in_direction(const char *direction_string, | 43 | static struct sway_output *output_in_direction(const char *direction_string, |
44 | struct wlr_output *reference, int ref_lx, int ref_ly) { | 44 | struct sway_output *reference, int ref_lx, int ref_ly) { |
45 | struct { | 45 | struct { |
46 | char *name; | 46 | char *name; |
47 | enum wlr_direction direction; | 47 | enum wlr_direction direction; |
@@ -61,449 +61,370 @@ static struct sway_container *output_in_direction(const char *direction_string, | |||
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
64 | if (direction) { | 64 | if (reference && direction) { |
65 | struct wlr_output *target = wlr_output_layout_adjacent_output( | 65 | struct wlr_output *target = wlr_output_layout_adjacent_output( |
66 | root_container.sway_root->output_layout, | 66 | root->output_layout, direction, reference->wlr_output, |
67 | direction, reference, ref_lx, ref_ly); | 67 | ref_lx, ref_ly); |
68 | 68 | ||
69 | if (!target) { | 69 | if (!target) { |
70 | target = wlr_output_layout_farthest_output( | 70 | target = wlr_output_layout_farthest_output( |
71 | root_container.sway_root->output_layout, | 71 | root->output_layout, opposite_direction(direction), |
72 | opposite_direction(direction), reference, ref_lx, ref_ly); | 72 | reference->wlr_output, ref_lx, ref_ly); |
73 | } | 73 | } |
74 | 74 | ||
75 | if (target) { | 75 | if (target) { |
76 | struct sway_output *sway_output = target->data; | 76 | return target->data; |
77 | return sway_output->swayc; | ||
78 | } | 77 | } |
79 | } | 78 | } |
80 | 79 | ||
81 | return output_by_name(direction_string); | 80 | return output_by_name(direction_string); |
82 | } | 81 | } |
83 | 82 | ||
84 | static void container_move_to(struct sway_container *container, | 83 | static bool is_parallel(enum sway_container_layout layout, |
85 | struct sway_container *destination) { | 84 | enum movement_direction dir) { |
86 | if (!sway_assert(container->type == C_CONTAINER || | 85 | switch (layout) { |
87 | container->type == C_VIEW, "Expected a container or view")) { | 86 | case L_TABBED: |
88 | return; | 87 | case L_HORIZ: |
88 | return dir == MOVE_LEFT || dir == MOVE_RIGHT; | ||
89 | case L_STACKED: | ||
90 | case L_VERT: | ||
91 | return dir == MOVE_UP || dir == MOVE_DOWN; | ||
92 | default: | ||
93 | return false; | ||
89 | } | 94 | } |
90 | if (container == destination | 95 | } |
91 | || container_has_ancestor(container, destination)) { | 96 | |
97 | /** | ||
98 | * Ensures all seats focus the fullscreen container if needed. | ||
99 | */ | ||
100 | static void workspace_focus_fullscreen(struct sway_workspace *workspace) { | ||
101 | if (!workspace->fullscreen) { | ||
92 | return; | 102 | return; |
93 | } | 103 | } |
94 | struct sway_container *old_parent = NULL; | 104 | struct sway_seat *seat; |
95 | struct sway_container *new_parent = NULL; | 105 | struct sway_workspace *focus_ws; |
96 | if (container_is_floating(container)) { | 106 | wl_list_for_each(seat, &input_manager->seats, link) { |
97 | // Resolve destination into a workspace | 107 | focus_ws = seat_get_focused_workspace(seat); |
98 | struct sway_container *new_ws = NULL; | 108 | if (focus_ws == workspace) { |
99 | if (destination->type == C_OUTPUT) { | 109 | struct sway_node *new_focus = |
100 | new_ws = output_get_active_workspace(destination->sway_output); | 110 | seat_get_focus_inactive(seat, &workspace->fullscreen->node); |
101 | } else if (destination->type == C_WORKSPACE) { | 111 | seat_set_focus(seat, new_focus); |
102 | new_ws = destination; | ||
103 | } else { | ||
104 | new_ws = container_parent(destination, C_WORKSPACE); | ||
105 | } | 112 | } |
106 | if (!new_ws) { | 113 | } |
107 | // This can happen if the user has run "move container to mark foo", | 114 | } |
108 | // where mark foo is on a hidden scratchpad container. | 115 | |
109 | return; | 116 | static void container_move_to_container_from_direction( |
117 | struct sway_container *container, struct sway_container *destination, | ||
118 | enum movement_direction move_dir) { | ||
119 | if (destination->view) { | ||
120 | if (destination->parent == container->parent) { | ||
121 | wlr_log(WLR_DEBUG, "Swapping siblings"); | ||
122 | list_t *siblings = container_get_siblings(container); | ||
123 | int container_index = list_find(siblings, container); | ||
124 | int destination_index = list_find(siblings, destination); | ||
125 | list_swap(siblings, container_index, destination_index); | ||
126 | } else { | ||
127 | wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); | ||
128 | int offset = move_dir == MOVE_LEFT || move_dir == MOVE_UP; | ||
129 | int index = container_sibling_index(destination) + offset; | ||
130 | if (destination->parent) { | ||
131 | container_insert_child(destination->parent, container, index); | ||
132 | } else { | ||
133 | workspace_insert_tiling(destination->workspace, | ||
134 | container, index); | ||
135 | } | ||
136 | container->width = container->height = 0; | ||
110 | } | 137 | } |
111 | struct sway_container *old_output = | 138 | return; |
112 | container_parent(container, C_OUTPUT); | 139 | } |
113 | old_parent = container_remove_child(container); | 140 | |
114 | workspace_add_floating(new_ws, container); | 141 | if (is_parallel(destination->layout, move_dir)) { |
115 | container_handle_fullscreen_reparent(container, old_parent); | 142 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); |
143 | int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? | ||
144 | 0 : destination->children->length; | ||
145 | container_insert_child(destination, container, index); | ||
146 | container->width = container->height = 0; | ||
147 | return; | ||
148 | } | ||
149 | |||
150 | wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); | ||
151 | struct sway_node *focus_inactive = seat_get_active_child( | ||
152 | config->handler_context.seat, &destination->node); | ||
153 | if (!focus_inactive || focus_inactive == &destination->node) { | ||
154 | // The container has no children | ||
155 | container_add_child(destination, container); | ||
156 | return; | ||
157 | } | ||
158 | |||
159 | // Try again but with the child | ||
160 | container_move_to_container_from_direction(container, | ||
161 | focus_inactive->sway_container, move_dir); | ||
162 | } | ||
163 | |||
164 | static void container_move_to_workspace_from_direction( | ||
165 | struct sway_container *container, struct sway_workspace *workspace, | ||
166 | enum movement_direction move_dir) { | ||
167 | if (is_parallel(workspace->layout, move_dir)) { | ||
168 | wlr_log(WLR_DEBUG, "Reparenting container (parallel)"); | ||
169 | int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ? | ||
170 | 0 : workspace->tiling->length; | ||
171 | workspace_insert_tiling(workspace, container, index); | ||
172 | return; | ||
173 | } | ||
174 | |||
175 | wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); | ||
176 | struct sway_container *focus_inactive = seat_get_focus_inactive_tiling( | ||
177 | config->handler_context.seat, workspace); | ||
178 | if (!focus_inactive) { | ||
179 | // The workspace has no tiling children | ||
180 | workspace_add_tiling(workspace, container); | ||
181 | return; | ||
182 | } | ||
183 | while (focus_inactive->parent) { | ||
184 | focus_inactive = focus_inactive->parent; | ||
185 | } | ||
186 | container_move_to_container_from_direction(container, focus_inactive, | ||
187 | move_dir); | ||
188 | } | ||
189 | |||
190 | static void container_move_to_workspace(struct sway_container *container, | ||
191 | struct sway_workspace *workspace) { | ||
192 | if (container->workspace == workspace) { | ||
193 | return; | ||
194 | } | ||
195 | struct sway_workspace *old_workspace = container->workspace; | ||
196 | if (container_is_floating(container)) { | ||
197 | struct sway_output *old_output = container->workspace->output; | ||
198 | container_detach(container); | ||
199 | workspace_add_floating(workspace, container); | ||
200 | container_handle_fullscreen_reparent(container); | ||
116 | // If changing output, center it within the workspace | 201 | // If changing output, center it within the workspace |
117 | if (old_output != new_ws->parent && !container->is_fullscreen) { | 202 | if (old_output != workspace->output && !container->is_fullscreen) { |
118 | container_floating_move_to_center(container); | 203 | container_floating_move_to_center(container); |
119 | } | 204 | } |
120 | } else { | 205 | } else { |
121 | old_parent = container_remove_child(container); | 206 | container_detach(container); |
122 | container->width = container->height = 0; | 207 | container->width = container->height = 0; |
123 | container->saved_width = container->saved_height = 0; | 208 | container->saved_width = container->saved_height = 0; |
124 | 209 | workspace_add_tiling(workspace, container); | |
125 | if (destination->type == C_VIEW) { | 210 | container_update_representation(container); |
126 | new_parent = container_add_sibling(destination, container); | ||
127 | } else { | ||
128 | new_parent = destination; | ||
129 | container_add_child(destination, container); | ||
130 | } | ||
131 | } | 211 | } |
132 | 212 | if (container->view) { | |
133 | if (container->type == C_VIEW) { | ||
134 | ipc_event_window(container, "move"); | 213 | ipc_event_window(container, "move"); |
135 | } | 214 | } |
136 | container_notify_subtree_changed(old_parent); | 215 | workspace_detect_urgent(old_workspace); |
137 | container_notify_subtree_changed(new_parent); | 216 | workspace_detect_urgent(workspace); |
138 | 217 | workspace_focus_fullscreen(workspace); | |
139 | // If view was moved to a fullscreen workspace, refocus the fullscreen view | 218 | } |
140 | struct sway_container *new_workspace = container; | 219 | |
141 | if (new_workspace->type != C_WORKSPACE) { | 220 | static void container_move_to_container(struct sway_container *container, |
142 | new_workspace = container_parent(new_workspace, C_WORKSPACE); | 221 | struct sway_container *destination) { |
143 | } | 222 | if (container == destination |
144 | if (new_workspace->sway_workspace->fullscreen) { | 223 | || container_has_ancestor(container, destination) |
145 | struct sway_seat *seat; | 224 | || container_has_ancestor(destination, container)) { |
146 | struct sway_container *focus, *focus_ws; | 225 | return; |
147 | wl_list_for_each(seat, &input_manager->seats, link) { | ||
148 | focus = seat_get_focus(seat); | ||
149 | focus_ws = focus; | ||
150 | if (focus_ws->type != C_WORKSPACE) { | ||
151 | focus_ws = container_parent(focus_ws, C_WORKSPACE); | ||
152 | } | ||
153 | if (focus_ws == new_workspace) { | ||
154 | struct sway_container *new_focus = seat_get_focus_inactive(seat, | ||
155 | new_workspace->sway_workspace->fullscreen); | ||
156 | seat_set_focus(seat, new_focus); | ||
157 | } | ||
158 | } | ||
159 | } | 226 | } |
160 | // Update workspace urgent state | 227 | if (container_is_floating(container)) { |
161 | struct sway_container *old_workspace = old_parent; | 228 | return; |
162 | if (old_workspace->type != C_WORKSPACE) { | ||
163 | old_workspace = container_parent(old_workspace, C_WORKSPACE); | ||
164 | } | ||
165 | if (new_workspace != old_workspace) { | ||
166 | workspace_detect_urgent(new_workspace); | ||
167 | if (old_workspace) { | ||
168 | workspace_detect_urgent(old_workspace); | ||
169 | } | ||
170 | } | 229 | } |
171 | } | 230 | struct sway_workspace *old_workspace = container->workspace; |
172 | 231 | ||
173 | static bool is_parallel(enum sway_container_layout layout, | 232 | container_detach(container); |
174 | enum movement_direction dir) { | 233 | container->width = container->height = 0; |
175 | switch (layout) { | 234 | container->saved_width = container->saved_height = 0; |
176 | case L_TABBED: | 235 | |
177 | case L_HORIZ: | 236 | if (destination->view) { |
178 | return dir == MOVE_LEFT || dir == MOVE_RIGHT; | 237 | container_add_sibling(destination, container); |
179 | case L_STACKED: | 238 | } else { |
180 | case L_VERT: | 239 | container_add_child(destination, container); |
181 | return dir == MOVE_UP || dir == MOVE_DOWN; | ||
182 | default: | ||
183 | return false; | ||
184 | } | 240 | } |
185 | } | ||
186 | 241 | ||
187 | static enum movement_direction invert_movement(enum movement_direction dir) { | 242 | if (container->view) { |
188 | switch (dir) { | 243 | ipc_event_window(container, "move"); |
189 | case MOVE_LEFT: | ||
190 | return MOVE_RIGHT; | ||
191 | case MOVE_RIGHT: | ||
192 | return MOVE_LEFT; | ||
193 | case MOVE_UP: | ||
194 | return MOVE_DOWN; | ||
195 | case MOVE_DOWN: | ||
196 | return MOVE_UP; | ||
197 | default: | ||
198 | sway_assert(0, "This function expects left|right|up|down"); | ||
199 | return MOVE_LEFT; | ||
200 | } | 244 | } |
201 | } | ||
202 | 245 | ||
203 | static int move_offs(enum movement_direction move_dir) { | 246 | workspace_focus_fullscreen(destination->workspace); |
204 | return move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; | ||
205 | } | ||
206 | 247 | ||
207 | /* Gets the index of the most extreme member based on the movement offset */ | 248 | // Update workspace urgent state |
208 | static int container_limit(struct sway_container *container, | 249 | workspace_detect_urgent(destination->workspace); |
209 | enum movement_direction move_dir) { | 250 | if (old_workspace && old_workspace != destination->workspace) { |
210 | return move_offs(move_dir) < 0 ? 0 : container->children->length; | 251 | workspace_detect_urgent(old_workspace); |
252 | } | ||
211 | } | 253 | } |
212 | 254 | ||
213 | /* Takes one child, sets it aside, wraps the rest of the children in a new | 255 | /* Takes one child, sets it aside, wraps the rest of the children in a new |
214 | * container, switches the layout of the workspace, and drops the child back in. | 256 | * container, switches the layout of the workspace, and drops the child back in. |
215 | * In other words, rejigger it. */ | 257 | * In other words, rejigger it. */ |
216 | static void workspace_rejigger(struct sway_container *ws, | 258 | static void workspace_rejigger(struct sway_workspace *ws, |
217 | struct sway_container *child, enum movement_direction move_dir) { | 259 | struct sway_container *child, enum movement_direction move_dir) { |
218 | struct sway_container *original_parent = child->parent; | 260 | if (!sway_assert(child->parent == NULL, "Expected a root child")) { |
219 | struct sway_container *new_parent = | 261 | return; |
220 | container_split(ws, ws->layout); | ||
221 | |||
222 | container_remove_child(child); | ||
223 | for (int i = 0; i < ws->children->length; ++i) { | ||
224 | struct sway_container *_child = ws->children->items[i]; | ||
225 | container_move_to(new_parent, _child); | ||
226 | } | 262 | } |
263 | container_detach(child); | ||
264 | workspace_wrap_children(ws); | ||
227 | 265 | ||
228 | int index = move_offs(move_dir); | 266 | int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1; |
229 | container_insert_child(ws, child, index < 0 ? 0 : 1); | 267 | workspace_insert_tiling(ws, child, index); |
230 | ws->layout = | 268 | ws->layout = |
231 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 269 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; |
232 | 270 | workspace_update_representation(ws); | |
233 | container_flatten(ws); | ||
234 | container_reap_empty(original_parent); | ||
235 | container_create_notify(new_parent); | ||
236 | } | 271 | } |
237 | 272 | ||
238 | static void move_out_of_tabs_stacks(struct sway_container *container, | 273 | static void move_out_of_tabs_stacks(struct sway_container *container, |
239 | struct sway_container *current, enum movement_direction move_dir, | 274 | struct sway_container *current, enum movement_direction move_dir, |
240 | int offs) { | 275 | int offs) { |
241 | if (container->parent == current->parent | 276 | enum sway_container_layout layout = move_dir == |
242 | && current->parent->children->length == 1) { | 277 | MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; |
243 | wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); | 278 | list_t *siblings = container_get_siblings(container); |
244 | current->parent->layout = move_dir == | 279 | if (container == current && siblings->length == 1) { |
245 | MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; | 280 | wlr_log(WLR_DEBUG, "Changing layout of parent"); |
281 | if (container->parent) { | ||
282 | container->parent->layout = layout; | ||
283 | container_update_representation(container); | ||
284 | } else { | ||
285 | container->workspace->layout = layout; | ||
286 | workspace_update_representation(container->workspace); | ||
287 | } | ||
246 | return; | 288 | return; |
247 | } | 289 | } |
248 | 290 | ||
249 | wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); | 291 | wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); |
250 | bool is_workspace = current->parent->type == C_WORKSPACE; | 292 | if (container->parent) { |
251 | struct sway_container *new_parent = container_split(current->parent, | 293 | struct sway_container *new_parent = |
252 | move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); | 294 | container_split(current->parent, layout); |
253 | if (is_workspace) { | ||
254 | container_insert_child(new_parent->parent, container, offs < 0 ? 0 : 1); | ||
255 | } else { | ||
256 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); | 295 | container_insert_child(new_parent, container, offs < 0 ? 0 : 1); |
257 | container_reap_empty(new_parent->parent); | 296 | container_reap_empty(new_parent); |
258 | container_flatten(new_parent->parent); | 297 | container_flatten(new_parent); |
298 | } else { | ||
299 | // Changing a workspace | ||
300 | struct sway_workspace *workspace = container->workspace; | ||
301 | workspace_split(workspace, layout); | ||
302 | workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1); | ||
259 | } | 303 | } |
260 | container_create_notify(new_parent); | ||
261 | container_notify_subtree_changed(new_parent); | ||
262 | } | 304 | } |
263 | 305 | ||
264 | static void container_move(struct sway_container *container, | 306 | // Returns true if moved |
265 | enum movement_direction move_dir, int move_amt) { | 307 | static bool container_move_in_direction(struct sway_container *container, |
266 | if (!sway_assert( | 308 | enum movement_direction move_dir) { |
267 | container->type != C_CONTAINER || container->type != C_VIEW, | ||
268 | "Can only move containers and views")) { | ||
269 | return; | ||
270 | } | ||
271 | int offs = move_offs(move_dir); | ||
272 | |||
273 | struct sway_container *sibling = NULL; | ||
274 | struct sway_container *current = container; | ||
275 | struct sway_container *parent = current->parent; | ||
276 | struct sway_container *top = &root_container; | ||
277 | |||
278 | // If moving a fullscreen view, only consider outputs | 309 | // If moving a fullscreen view, only consider outputs |
279 | if (container->is_fullscreen) { | 310 | if (container->is_fullscreen) { |
280 | current = container_parent(container, C_OUTPUT); | 311 | struct sway_output *new_output = |
281 | } else if (container_is_fullscreen_or_child(container) || | 312 | output_get_in_direction(container->workspace->output, move_dir); |
282 | container_is_floating_or_child(container)) { | 313 | if (!new_output) { |
283 | // If we've fullscreened a split container, only allow the child to move | 314 | return false; |
284 | // around within the fullscreen parent. | 315 | } |
285 | // Same with floating a split container. | 316 | struct sway_workspace *ws = output_get_active_workspace(new_output); |
286 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 317 | container_move_to_workspace(container, ws); |
287 | top = ws->sway_workspace->fullscreen; | 318 | return true; |
288 | } | ||
289 | |||
290 | struct sway_container *new_parent = container_flatten(parent); | ||
291 | if (new_parent != parent) { | ||
292 | // Special case: we were the last one in this container, so leave | ||
293 | return; | ||
294 | } | 319 | } |
295 | 320 | ||
296 | while (!sibling) { | 321 | // If container is in a split container by itself, move out of the split |
297 | if (current == top) { | 322 | if (container->parent) { |
298 | return; | 323 | struct sway_container *new_parent = |
324 | container_flatten(container->parent); | ||
325 | if (new_parent != container->parent) { | ||
326 | return true; | ||
299 | } | 327 | } |
328 | } | ||
300 | 329 | ||
301 | parent = current->parent; | 330 | // Look for a suitable *container* sibling or parent. |
302 | wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, | 331 | // The below loop stops once we hit the workspace because current->parent |
303 | container_type_to_str(current->type), current->name); | 332 | // is NULL for the topmost containers in a workspace. |
304 | 333 | struct sway_container *current = container; | |
305 | int index = container_sibling_index(current); | 334 | int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1; |
306 | 335 | ||
307 | switch (current->type) { | 336 | while (current) { |
308 | case C_OUTPUT: { | 337 | struct sway_container *parent = current->parent; |
309 | enum wlr_direction wlr_dir = 0; | 338 | list_t *siblings = container_get_siblings(current); |
310 | if (!sway_assert(sway_dir_to_wlr(move_dir, &wlr_dir), | 339 | enum sway_container_layout layout = container_parent_layout(current); |
311 | "got invalid direction: %d", move_dir)) { | 340 | int index = list_find(siblings, current); |
312 | return; | 341 | int desired = index + offs; |
313 | } | 342 | |
314 | double ref_lx = current->x + current->width / 2; | 343 | if (is_parallel(layout, move_dir)) { |
315 | double ref_ly = current->y + current->height / 2; | 344 | if (desired == -1 || desired == siblings->length) { |
316 | struct wlr_output *next = wlr_output_layout_adjacent_output( | 345 | if (current->parent == container->parent) { |
317 | root_container.sway_root->output_layout, wlr_dir, | 346 | if (!(parent && parent->is_fullscreen) && |
318 | current->sway_output->wlr_output, ref_lx, ref_ly); | 347 | (layout == L_TABBED || layout == L_STACKED)) { |
319 | if (!next) { | 348 | move_out_of_tabs_stacks(container, current, |
320 | wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); | 349 | move_dir, offs); |
321 | return; | 350 | return true; |
322 | } | ||
323 | struct sway_output *next_output = next->data; | ||
324 | current = next_output->swayc; | ||
325 | wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name); | ||
326 | // Select workspace and get outta here | ||
327 | current = seat_get_focus_inactive( | ||
328 | config->handler_context.seat, current); | ||
329 | if (current->type != C_WORKSPACE) { | ||
330 | current = container_parent(current, C_WORKSPACE); | ||
331 | } | ||
332 | sibling = current; | ||
333 | break; | ||
334 | } | ||
335 | case C_WORKSPACE: | ||
336 | if (!is_parallel(current->layout, move_dir)) { | ||
337 | if (current->children->length >= 2) { | ||
338 | wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)", | ||
339 | current->children->length); | ||
340 | workspace_rejigger(current, container, move_dir); | ||
341 | return; | ||
342 | } else { | ||
343 | wlr_log(WLR_DEBUG, "Selecting output"); | ||
344 | current = current->parent; | ||
345 | } | ||
346 | } else if (current->layout == L_TABBED | ||
347 | || current->layout == L_STACKED) { | ||
348 | wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks"); | ||
349 | workspace_rejigger(current, container, move_dir); | ||
350 | } else { | ||
351 | wlr_log(WLR_DEBUG, "Selecting output"); | ||
352 | current = current->parent; | ||
353 | } | ||
354 | break; | ||
355 | case C_CONTAINER: | ||
356 | case C_VIEW: | ||
357 | if (is_parallel(parent->layout, move_dir)) { | ||
358 | if ((index == parent->children->length - 1 && offs > 0) | ||
359 | || (index == 0 && offs < 0)) { | ||
360 | if (current->parent == container->parent) { | ||
361 | if (!parent->is_fullscreen && | ||
362 | (parent->layout == L_TABBED || | ||
363 | parent->layout == L_STACKED)) { | ||
364 | move_out_of_tabs_stacks(container, current, | ||
365 | move_dir, offs); | ||
366 | return; | ||
367 | } else { | ||
368 | wlr_log(WLR_DEBUG, "Hit limit, selecting parent"); | ||
369 | current = current->parent; | ||
370 | } | ||
371 | } else { | 351 | } else { |
372 | wlr_log(WLR_DEBUG, "Hit limit, " | 352 | current = current->parent; |
373 | "promoting descendant to sibling"); | 353 | continue; |
374 | // Special case | 354 | } |
355 | } else { | ||
356 | // Special case | ||
357 | if (current->parent) { | ||
375 | container_insert_child(current->parent, container, | 358 | container_insert_child(current->parent, container, |
376 | index + (offs < 0 ? 0 : 1)); | 359 | index + (offs < 0 ? 0 : 1)); |
377 | container->width = container->height = 0; | 360 | } else { |
378 | return; | 361 | workspace_insert_tiling(current->workspace, container, |
362 | index + (offs < 0 ? 0 : 1)); | ||
379 | } | 363 | } |
380 | } else { | 364 | return true; |
381 | sibling = parent->children->items[index + offs]; | ||
382 | wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); | ||
383 | } | 365 | } |
384 | } else if (!parent->is_fullscreen && (parent->layout == L_TABBED || | ||
385 | parent->layout == L_STACKED)) { | ||
386 | move_out_of_tabs_stacks(container, current, move_dir, offs); | ||
387 | return; | ||
388 | } else { | 366 | } else { |
389 | wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); | 367 | // Container can move within its siblings |
390 | current = current->parent; | 368 | container_move_to_container_from_direction(container, |
369 | siblings->items[desired], move_dir); | ||
370 | return true; | ||
391 | } | 371 | } |
392 | break; | 372 | } else if (!(parent && parent->is_fullscreen) && |
393 | default: | 373 | (layout == L_TABBED || layout == L_STACKED)) { |
394 | sway_assert(0, "Not expecting to see container of type %s here", | 374 | move_out_of_tabs_stacks(container, current, move_dir, offs); |
395 | container_type_to_str(current->type)); | 375 | return true; |
396 | return; | ||
397 | } | 376 | } |
398 | } | ||
399 | 377 | ||
400 | // Part two: move stuff around | 378 | current = current->parent; |
401 | int index = container_sibling_index(container); | ||
402 | struct sway_container *old_parent = container->parent; | ||
403 | 379 | ||
404 | while (sibling) { | 380 | // Don't allow containers to move out of their |
405 | switch (sibling->type) { | 381 | // fullscreen or floating parent |
406 | case C_VIEW: | 382 | if (current && |
407 | if (sibling->parent == container->parent) { | 383 | (current->is_fullscreen || container_is_floating(current))) { |
408 | wlr_log(WLR_DEBUG, "Swapping siblings"); | 384 | return false; |
409 | sibling->parent->children->items[index + offs] = container; | ||
410 | sibling->parent->children->items[index] = sibling; | ||
411 | } else { | ||
412 | wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); | ||
413 | container_insert_child(sibling->parent, container, | ||
414 | container_sibling_index(sibling) + (offs > 0 ? 0 : 1)); | ||
415 | container->width = container->height = 0; | ||
416 | } | ||
417 | sibling = NULL; | ||
418 | break; | ||
419 | case C_WORKSPACE: // Note: only in the case of moving between outputs | ||
420 | case C_CONTAINER: | ||
421 | if (is_parallel(sibling->layout, move_dir)) { | ||
422 | int limit = container_limit(sibling, invert_movement(move_dir)); | ||
423 | wlr_log(WLR_DEBUG, "limit: %d", limit); | ||
424 | wlr_log(WLR_DEBUG, | ||
425 | "Reparenting container (parallel) to index %d " | ||
426 | "(move dir: %d)", limit, move_dir); | ||
427 | container_insert_child(sibling, container, limit); | ||
428 | container->width = container->height = 0; | ||
429 | sibling = NULL; | ||
430 | } else { | ||
431 | wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); | ||
432 | struct sway_container *focus_inactive = seat_get_focus_inactive( | ||
433 | config->handler_context.seat, sibling); | ||
434 | if (focus_inactive && focus_inactive != sibling) { | ||
435 | while (focus_inactive->parent != sibling) { | ||
436 | focus_inactive = focus_inactive->parent; | ||
437 | } | ||
438 | wlr_log(WLR_DEBUG, "Focus inactive: id:%zd", | ||
439 | focus_inactive->id); | ||
440 | sibling = focus_inactive; | ||
441 | continue; | ||
442 | } else if (sibling->children->length) { | ||
443 | wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily"); | ||
444 | container_remove_child(container); | ||
445 | container_add_sibling(sibling->children->items[0], container); | ||
446 | } else { | ||
447 | wlr_log(WLR_DEBUG, "No kiddos, adding container alone"); | ||
448 | container_remove_child(container); | ||
449 | container_add_child(sibling, container); | ||
450 | } | ||
451 | container->width = container->height = 0; | ||
452 | sibling = NULL; | ||
453 | } | ||
454 | break; | ||
455 | default: | ||
456 | sway_assert(0, "Not expecting to see container of type %s here", | ||
457 | container_type_to_str(sibling->type)); | ||
458 | return; | ||
459 | } | 385 | } |
460 | } | 386 | } |
461 | 387 | ||
462 | container_notify_subtree_changed(old_parent); | 388 | // Maybe rejigger the workspace |
463 | container_notify_subtree_changed(container->parent); | 389 | struct sway_workspace *ws = container->workspace; |
464 | 390 | if (!is_parallel(ws->layout, move_dir)) { | |
465 | if (container->type == C_VIEW) { | 391 | if (ws->tiling->length >= 2) { |
466 | ipc_event_window(container, "move"); | 392 | workspace_rejigger(ws, container, move_dir); |
467 | } | 393 | return true; |
468 | 394 | } | |
469 | if (old_parent) { | 395 | } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) { |
470 | seat_set_focus(config->handler_context.seat, old_parent); | 396 | workspace_rejigger(ws, container, move_dir); |
471 | seat_set_focus(config->handler_context.seat, container); | 397 | return true; |
472 | } | 398 | } |
473 | 399 | ||
474 | struct sway_container *last_ws = old_parent; | 400 | // Try adjacent output |
475 | struct sway_container *next_ws = container->parent; | 401 | struct sway_output *output = |
476 | if (last_ws && last_ws->type != C_WORKSPACE) { | 402 | output_get_in_direction(container->workspace->output, move_dir); |
477 | last_ws = container_parent(last_ws, C_WORKSPACE); | 403 | if (output) { |
404 | struct sway_workspace *ws = output_get_active_workspace(output); | ||
405 | container_move_to_workspace_from_direction(container, ws, move_dir); | ||
406 | return true; | ||
478 | } | 407 | } |
479 | if (next_ws && next_ws->type != C_WORKSPACE) { | 408 | wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); |
480 | next_ws = container_parent(next_ws, C_WORKSPACE); | 409 | return false; |
481 | } | ||
482 | if (last_ws && next_ws && last_ws != next_ws) { | ||
483 | ipc_event_workspace(last_ws, next_ws, "focus"); | ||
484 | workspace_detect_urgent(last_ws); | ||
485 | workspace_detect_urgent(next_ws); | ||
486 | } | ||
487 | container_end_mouse_operation(container); | ||
488 | } | 410 | } |
489 | 411 | ||
490 | static struct cmd_results *cmd_move_container(struct sway_container *current, | 412 | static struct cmd_results *cmd_move_container(int argc, char **argv) { |
491 | int argc, char **argv) { | ||
492 | struct cmd_results *error = NULL; | 413 | struct cmd_results *error = NULL; |
493 | if ((error = checkarg(argc, "move container/window", | 414 | if ((error = checkarg(argc, "move container/window", |
494 | EXPECTED_AT_LEAST, 3))) { | 415 | EXPECTED_AT_LEAST, 3))) { |
495 | return error; | 416 | return error; |
496 | } | 417 | } |
497 | 418 | ||
498 | if (current->type == C_WORKSPACE) { | 419 | struct sway_node *node = config->handler_context.node; |
499 | if (current->children->length == 0) { | 420 | struct sway_workspace *workspace = config->handler_context.workspace; |
421 | struct sway_container *container = config->handler_context.container; | ||
422 | if (node->type == N_WORKSPACE) { | ||
423 | if (workspace->tiling->length == 0) { | ||
500 | return cmd_results_new(CMD_FAILURE, "move", | 424 | return cmd_results_new(CMD_FAILURE, "move", |
501 | "Can't move an empty workspace"); | 425 | "Can't move an empty workspace"); |
502 | } | 426 | } |
503 | current = workspace_wrap_children(current); | 427 | container = workspace_wrap_children(workspace); |
504 | } else if (current->type != C_CONTAINER && current->type != C_VIEW) { | ||
505 | return cmd_results_new(CMD_FAILURE, "move", | ||
506 | "Can only move containers and views."); | ||
507 | } | 428 | } |
508 | 429 | ||
509 | bool no_auto_back_and_forth = false; | 430 | bool no_auto_back_and_forth = false; |
@@ -530,15 +451,15 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
530 | } | 451 | } |
531 | 452 | ||
532 | struct sway_seat *seat = config->handler_context.seat; | 453 | struct sway_seat *seat = config->handler_context.seat; |
533 | struct sway_container *old_parent = current->parent; | 454 | struct sway_container *old_parent = container->parent; |
534 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 455 | struct sway_workspace *old_ws = container->workspace; |
535 | struct sway_container *old_output = container_parent(current, C_OUTPUT); | 456 | struct sway_output *old_output = old_ws ? old_ws->output : NULL; |
536 | struct sway_container *destination = NULL; | 457 | struct sway_node *destination = NULL; |
537 | 458 | ||
538 | // determine destination | 459 | // determine destination |
539 | if (strcasecmp(argv[1], "workspace") == 0) { | 460 | if (strcasecmp(argv[1], "workspace") == 0) { |
540 | // move container to workspace x | 461 | // move container to workspace x |
541 | struct sway_container *ws = NULL; | 462 | struct sway_workspace *ws = NULL; |
542 | char *ws_name = NULL; | 463 | char *ws_name = NULL; |
543 | if (strcasecmp(argv[2], "next") == 0 || | 464 | if (strcasecmp(argv[2], "next") == 0 || |
544 | strcasecmp(argv[2], "prev") == 0 || | 465 | strcasecmp(argv[2], "prev") == 0 || |
@@ -576,7 +497,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
576 | if (!no_auto_back_and_forth && config->auto_back_and_forth && | 497 | if (!no_auto_back_and_forth && config->auto_back_and_forth && |
577 | prev_workspace_name) { | 498 | prev_workspace_name) { |
578 | // auto back and forth move | 499 | // auto back and forth move |
579 | if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) { | 500 | if (old_ws && old_ws->name && |
501 | strcmp(old_ws->name, ws_name) == 0) { | ||
580 | // if target workspace is the current one | 502 | // if target workspace is the current one |
581 | free(ws_name); | 503 | free(ws_name); |
582 | ws_name = strdup(prev_workspace_name); | 504 | ws_name = strdup(prev_workspace_name); |
@@ -588,8 +510,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
588 | // We have to create the workspace, but if the container is | 510 | // We have to create the workspace, but if the container is |
589 | // sticky and the workspace is going to be created on the same | 511 | // sticky and the workspace is going to be created on the same |
590 | // output, we'll bail out first. | 512 | // output, we'll bail out first. |
591 | if (current->is_sticky) { | 513 | if (container->is_sticky) { |
592 | struct sway_container *new_output = | 514 | struct sway_output *new_output = |
593 | workspace_get_initial_output(ws_name); | 515 | workspace_get_initial_output(ws_name); |
594 | if (old_output == new_output) { | 516 | if (old_output == new_output) { |
595 | free(ws_name); | 517 | free(ws_name); |
@@ -601,105 +523,119 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
601 | ws = workspace_create(NULL, ws_name); | 523 | ws = workspace_create(NULL, ws_name); |
602 | } | 524 | } |
603 | free(ws_name); | 525 | free(ws_name); |
604 | destination = seat_get_focus_inactive(seat, ws); | 526 | destination = seat_get_focus_inactive(seat, &ws->node); |
605 | } else if (strcasecmp(argv[1], "output") == 0) { | 527 | } else if (strcasecmp(argv[1], "output") == 0) { |
606 | struct sway_container *dest_output = output_in_direction(argv[2], | 528 | struct sway_output *new_output = output_in_direction(argv[2], |
607 | old_output->sway_output->wlr_output, current->x, current->y); | 529 | old_output, container->x, container->y); |
608 | if (!dest_output) { | 530 | if (!new_output) { |
609 | return cmd_results_new(CMD_FAILURE, "move workspace", | 531 | return cmd_results_new(CMD_FAILURE, "move workspace", |
610 | "Can't find output with name/direction '%s'", argv[2]); | 532 | "Can't find output with name/direction '%s'", argv[2]); |
611 | } | 533 | } |
612 | destination = seat_get_focus_inactive(seat, dest_output); | 534 | destination = seat_get_focus_inactive(seat, &new_output->node); |
613 | if (!destination) { | ||
614 | // We've never been to this output before | ||
615 | destination = dest_output->children->items[0]; | ||
616 | } | ||
617 | } else if (strcasecmp(argv[1], "mark") == 0) { | 535 | } else if (strcasecmp(argv[1], "mark") == 0) { |
618 | struct sway_view *dest_view = view_find_mark(argv[2]); | 536 | struct sway_view *dest_view = view_find_mark(argv[2]); |
619 | if (dest_view == NULL) { | 537 | if (dest_view == NULL) { |
620 | return cmd_results_new(CMD_FAILURE, "move", | 538 | return cmd_results_new(CMD_FAILURE, "move", |
621 | "Mark '%s' not found", argv[2]); | 539 | "Mark '%s' not found", argv[2]); |
622 | } | 540 | } |
623 | destination = dest_view->swayc; | 541 | destination = &dest_view->container->node; |
624 | } else { | 542 | } else { |
625 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 543 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
626 | } | 544 | } |
627 | 545 | ||
628 | struct sway_container *new_output = destination->type == C_OUTPUT ? | 546 | if (container->is_sticky && old_output && |
629 | destination : container_parent(destination, C_OUTPUT); | 547 | node_has_ancestor(destination, &old_output->node)) { |
630 | if (current->is_sticky && old_output == new_output) { | ||
631 | return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky " | 548 | return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky " |
632 | "container to another workspace on the same output"); | 549 | "container to another workspace on the same output"); |
633 | } | 550 | } |
634 | 551 | ||
635 | struct sway_container *new_output_last_ws = old_output == new_output ? | 552 | struct sway_output *new_output = node_get_output(destination); |
636 | NULL : seat_get_active_child(seat, new_output); | 553 | struct sway_workspace *new_output_last_ws = old_output == new_output ? |
637 | struct sway_container *new_workspace = destination->type == C_WORKSPACE ? | 554 | NULL : output_get_active_workspace(new_output); |
638 | destination : container_parent(destination, C_WORKSPACE); | ||
639 | 555 | ||
640 | // move container, arrange windows and return focus | 556 | // move container, arrange windows and return focus |
641 | container_move_to(current, destination); | 557 | if (container->scratchpad) { |
558 | root_scratchpad_remove_container(container); | ||
559 | } | ||
560 | switch (destination->type) { | ||
561 | case N_WORKSPACE: | ||
562 | container_move_to_workspace(container, destination->sway_workspace); | ||
563 | break; | ||
564 | case N_OUTPUT: { | ||
565 | struct sway_output *output = destination->sway_output; | ||
566 | struct sway_workspace *ws = output_get_active_workspace(output); | ||
567 | container_move_to_workspace(container, ws); | ||
568 | } | ||
569 | break; | ||
570 | case N_CONTAINER: | ||
571 | container_move_to_container(container, destination->sway_container); | ||
572 | break; | ||
573 | case N_ROOT: | ||
574 | break; | ||
575 | } | ||
576 | struct sway_workspace *new_workspace = | ||
577 | output_get_active_workspace(new_output); | ||
642 | if (new_output_last_ws && new_output_last_ws != new_workspace) { | 578 | if (new_output_last_ws && new_output_last_ws != new_workspace) { |
643 | // change focus on destination output back to its last active workspace | 579 | // change focus on destination output back to its last active workspace |
644 | struct sway_container *new_output_last_focus = | 580 | struct sway_node *new_output_last_focus = |
645 | seat_get_focus_inactive(seat, new_output_last_ws); | 581 | seat_get_focus_inactive(seat, &new_output_last_ws->node); |
646 | seat_set_focus_warp(seat, new_output_last_focus, false, false); | 582 | seat_set_focus_warp(seat, new_output_last_focus, false, false); |
647 | } | 583 | } |
648 | struct sway_container *focus = seat_get_focus_inactive(seat, old_parent); | 584 | |
585 | struct sway_node *focus = NULL; | ||
586 | if (old_parent) { | ||
587 | focus = seat_get_focus_inactive(seat, &old_parent->node); | ||
588 | } else if (old_ws) { | ||
589 | focus = seat_get_focus_inactive(seat, &old_ws->node); | ||
590 | } | ||
649 | seat_set_focus_warp(seat, focus, true, false); | 591 | seat_set_focus_warp(seat, focus, true, false); |
650 | container_reap_empty(old_parent); | ||
651 | container_reap_empty(destination->parent); | ||
652 | 592 | ||
653 | // TODO: Ideally we would arrange the surviving parent after reaping, | 593 | if (old_parent) { |
654 | // but container_reap_empty does not return it, so we arrange the | 594 | container_reap_empty(old_parent); |
655 | // workspace instead. | 595 | } else if (old_ws) { |
656 | arrange_windows(old_ws); | 596 | workspace_consider_destroy(old_ws); |
657 | arrange_windows(destination->parent); | 597 | } |
598 | |||
599 | if (old_ws) { | ||
600 | arrange_workspace(old_ws); | ||
601 | } | ||
602 | arrange_node(node_get_parent(destination)); | ||
658 | 603 | ||
659 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 604 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
660 | } | 605 | } |
661 | 606 | ||
662 | static void workspace_move_to_output(struct sway_container *workspace, | 607 | static void workspace_move_to_output(struct sway_workspace *workspace, |
663 | struct sway_container *output) { | 608 | struct sway_output *output) { |
664 | if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { | 609 | if (workspace->output == output) { |
665 | return; | 610 | return; |
666 | } | 611 | } |
667 | if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { | 612 | struct sway_output *old_output = workspace->output; |
668 | return; | 613 | workspace_detach(workspace); |
669 | } | 614 | struct sway_workspace *new_output_old_ws = |
670 | if (workspace->parent == output) { | 615 | output_get_active_workspace(output); |
671 | return; | ||
672 | } | ||
673 | struct sway_container *old_output = container_remove_child(workspace); | ||
674 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | ||
675 | struct sway_container *new_output_focus = | ||
676 | seat_get_focus_inactive(seat, output); | ||
677 | 616 | ||
678 | container_add_child(output, workspace); | 617 | output_add_workspace(output, workspace); |
679 | 618 | ||
680 | // If moving the last workspace from the old output, create a new workspace | 619 | // If moving the last workspace from the old output, create a new workspace |
681 | // on the old output | 620 | // on the old output |
682 | if (old_output->children->length == 0) { | 621 | struct sway_seat *seat = config->handler_context.seat; |
683 | char *ws_name = workspace_next_name(old_output->name); | 622 | if (old_output->workspaces->length == 0) { |
684 | struct sway_container *ws = workspace_create(old_output, ws_name); | 623 | char *ws_name = workspace_next_name(old_output->wlr_output->name); |
624 | struct sway_workspace *ws = workspace_create(old_output, ws_name); | ||
685 | free(ws_name); | 625 | free(ws_name); |
686 | seat_set_focus(seat, ws); | 626 | seat_set_focus(seat, &ws->node); |
687 | } | 627 | } |
688 | 628 | ||
689 | // Try to remove an empty workspace from the destination output. | 629 | workspace_consider_destroy(new_output_old_ws); |
690 | container_reap_empty(new_output_focus); | ||
691 | 630 | ||
692 | output_sort_workspaces(output); | 631 | output_sort_workspaces(output); |
693 | seat_set_focus(seat, output); | 632 | struct sway_node *focus = seat_get_focus_inactive(seat, &workspace->node); |
633 | seat_set_focus(seat, focus); | ||
694 | workspace_output_raise_priority(workspace, old_output, output); | 634 | workspace_output_raise_priority(workspace, old_output, output); |
695 | ipc_event_workspace(NULL, workspace, "move"); | 635 | ipc_event_workspace(NULL, workspace, "move"); |
696 | |||
697 | container_notify_subtree_changed(old_output); | ||
698 | container_notify_subtree_changed(output); | ||
699 | } | 636 | } |
700 | 637 | ||
701 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, | 638 | static struct cmd_results *cmd_move_workspace(int argc, char **argv) { |
702 | int argc, char **argv) { | ||
703 | struct cmd_results *error = NULL; | 639 | struct cmd_results *error = NULL; |
704 | if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { | 640 | if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { |
705 | return error; | 641 | return error; |
@@ -716,27 +652,25 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, | |||
716 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 652 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
717 | } | 653 | } |
718 | 654 | ||
719 | struct sway_container *source = container_parent(current, C_OUTPUT); | 655 | struct sway_workspace *workspace = config->handler_context.workspace; |
720 | int center_x = current->width / 2 + current->x, | 656 | struct sway_output *old_output = workspace->output; |
721 | center_y = current->height / 2 + current->y; | 657 | int center_x = workspace->width / 2 + workspace->x, |
722 | struct sway_container *destination = output_in_direction(argv[2], | 658 | center_y = workspace->height / 2 + workspace->y; |
723 | source->sway_output->wlr_output, center_x, center_y); | 659 | struct sway_output *new_output = output_in_direction(argv[2], |
724 | if (!destination) { | 660 | old_output, center_x, center_y); |
661 | if (!new_output) { | ||
725 | return cmd_results_new(CMD_FAILURE, "move workspace", | 662 | return cmd_results_new(CMD_FAILURE, "move workspace", |
726 | "Can't find output with name/direction '%s'", argv[2]); | 663 | "Can't find output with name/direction '%s'", argv[2]); |
727 | } | 664 | } |
728 | if (current->type != C_WORKSPACE) { | 665 | workspace_move_to_output(workspace, new_output); |
729 | current = container_parent(current, C_WORKSPACE); | ||
730 | } | ||
731 | workspace_move_to_output(current, destination); | ||
732 | 666 | ||
733 | arrange_windows(source); | 667 | arrange_output(old_output); |
734 | arrange_windows(destination); | 668 | arrange_output(new_output); |
735 | 669 | ||
736 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 670 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
737 | } | 671 | } |
738 | 672 | ||
739 | static struct cmd_results *move_in_direction(struct sway_container *container, | 673 | static struct cmd_results *cmd_move_in_direction( |
740 | enum movement_direction direction, int argc, char **argv) { | 674 | enum movement_direction direction, int argc, char **argv) { |
741 | int move_amt = 10; | 675 | int move_amt = 10; |
742 | if (argc > 1) { | 676 | if (argc > 1) { |
@@ -748,7 +682,8 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
748 | } | 682 | } |
749 | } | 683 | } |
750 | 684 | ||
751 | if (container->type == C_WORKSPACE) { | 685 | struct sway_container *container = config->handler_context.container; |
686 | if (!container) { | ||
752 | return cmd_results_new(CMD_FAILURE, "move", | 687 | return cmd_results_new(CMD_FAILURE, "move", |
753 | "Cannot move workspaces in a direction"); | 688 | "Cannot move workspaces in a direction"); |
754 | } | 689 | } |
@@ -780,20 +715,34 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
780 | container_floating_move_to(container, lx, ly); | 715 | container_floating_move_to(container, lx, ly); |
781 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 716 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
782 | } | 717 | } |
783 | // For simplicity, we'll arrange the entire workspace. The reason for this | 718 | struct sway_workspace *old_ws = container->workspace; |
784 | // is moving the container might reap the old parent, and container_move | ||
785 | // does not return a surviving parent. | ||
786 | // TODO: Make container_move return the surviving parent so we can arrange | ||
787 | // just that. | ||
788 | struct sway_container *old_ws = container_parent(container, C_WORKSPACE); | ||
789 | container_move(container, direction, move_amt); | ||
790 | struct sway_container *new_ws = container_parent(container, C_WORKSPACE); | ||
791 | 719 | ||
792 | arrange_windows(old_ws); | 720 | if (!container_move_in_direction(container, direction)) { |
721 | // Container didn't move | ||
722 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
723 | } | ||
724 | |||
725 | struct sway_workspace *new_ws = container->workspace; | ||
726 | |||
727 | arrange_workspace(old_ws); | ||
793 | if (new_ws != old_ws) { | 728 | if (new_ws != old_ws) { |
794 | arrange_windows(new_ws); | 729 | arrange_workspace(new_ws); |
730 | } | ||
731 | |||
732 | if (container->view) { | ||
733 | ipc_event_window(container, "move"); | ||
795 | } | 734 | } |
796 | 735 | ||
736 | seat_set_focus(config->handler_context.seat, &new_ws->node); | ||
737 | seat_set_focus(config->handler_context.seat, &container->node); | ||
738 | |||
739 | if (old_ws != new_ws) { | ||
740 | ipc_event_workspace(old_ws, new_ws, "focus"); | ||
741 | workspace_detect_urgent(old_ws); | ||
742 | workspace_detect_urgent(new_ws); | ||
743 | } | ||
744 | container_end_mouse_operation(container); | ||
745 | |||
797 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 746 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
798 | } | 747 | } |
799 | 748 | ||
@@ -802,9 +751,9 @@ static const char *expected_position_syntax = | |||
802 | "'move [absolute] position center' or " | 751 | "'move [absolute] position center' or " |
803 | "'move position cursor|mouse|pointer'"; | 752 | "'move position cursor|mouse|pointer'"; |
804 | 753 | ||
805 | static struct cmd_results *move_to_position(struct sway_container *container, | 754 | static struct cmd_results *cmd_move_to_position(int argc, char **argv) { |
806 | int argc, char **argv) { | 755 | struct sway_container *container = config->handler_context.container; |
807 | if (!container_is_floating(container)) { | 756 | if (!container || !container_is_floating(container)) { |
808 | return cmd_results_new(CMD_FAILURE, "move", | 757 | return cmd_results_new(CMD_FAILURE, "move", |
809 | "Only floating containers " | 758 | "Only floating containers " |
810 | "can be moved to an absolute position"); | 759 | "can be moved to an absolute position"); |
@@ -842,10 +791,10 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
842 | } else if (strcmp(argv[0], "center") == 0) { | 791 | } else if (strcmp(argv[0], "center") == 0) { |
843 | double lx, ly; | 792 | double lx, ly; |
844 | if (absolute) { | 793 | if (absolute) { |
845 | lx = root_container.x + (root_container.width - container->width) / 2; | 794 | lx = root->x + (root->width - container->width) / 2; |
846 | ly = root_container.y + (root_container.height - container->height) / 2; | 795 | ly = root->y + (root->height - container->height) / 2; |
847 | } else { | 796 | } else { |
848 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 797 | struct sway_workspace *ws = container->workspace; |
849 | lx = ws->x + (ws->width - container->width) / 2; | 798 | lx = ws->x + (ws->width - container->width) / 2; |
850 | ly = ws->y + (ws->height - container->height) / 2; | 799 | ly = ws->y + (ws->height - container->height) / 2; |
851 | } | 800 | } |
@@ -881,30 +830,31 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
881 | } | 830 | } |
882 | 831 | ||
883 | if (!absolute) { | 832 | if (!absolute) { |
884 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | 833 | lx += container->workspace->x; |
885 | lx += ws->x; | 834 | ly += container->workspace->y; |
886 | ly += ws->y; | ||
887 | } | 835 | } |
888 | container_floating_move_to(container, lx, ly); | 836 | container_floating_move_to(container, lx, ly); |
889 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 837 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
890 | } | 838 | } |
891 | 839 | ||
892 | static struct cmd_results *move_to_scratchpad(struct sway_container *con) { | 840 | static struct cmd_results *cmd_move_to_scratchpad(void) { |
893 | if (con->type == C_WORKSPACE && con->children->length == 0) { | 841 | struct sway_node *node = config->handler_context.node; |
842 | struct sway_container *con = config->handler_context.container; | ||
843 | struct sway_workspace *ws = config->handler_context.workspace; | ||
844 | if (node->type == N_WORKSPACE && ws->tiling->length == 0) { | ||
894 | return cmd_results_new(CMD_INVALID, "move", | 845 | return cmd_results_new(CMD_INVALID, "move", |
895 | "Can't move an empty workspace to the scratchpad"); | 846 | "Can't move an empty workspace to the scratchpad"); |
896 | } | 847 | } |
897 | if (con->type == C_WORKSPACE) { | 848 | if (node->type == N_WORKSPACE) { |
898 | // Wrap the workspace's children in a container | 849 | // Wrap the workspace's children in a container |
899 | struct sway_container *workspace = con; | 850 | con = workspace_wrap_children(ws); |
900 | con = workspace_wrap_children(con); | 851 | ws->layout = L_HORIZ; |
901 | workspace->layout = L_HORIZ; | ||
902 | } | 852 | } |
903 | 853 | ||
904 | // If the container is in a floating split container, | 854 | // If the container is in a floating split container, |
905 | // operate on the split container instead of the child. | 855 | // operate on the split container instead of the child. |
906 | if (container_is_floating_or_child(con)) { | 856 | if (container_is_floating_or_child(con)) { |
907 | while (con->parent->type != C_WORKSPACE) { | 857 | while (con->parent) { |
908 | con = con->parent; | 858 | con = con->parent; |
909 | } | 859 | } |
910 | } | 860 | } |
@@ -922,32 +872,31 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
922 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { | 872 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { |
923 | return error; | 873 | return error; |
924 | } | 874 | } |
925 | struct sway_container *current = config->handler_context.current_container; | ||
926 | 875 | ||
927 | if (strcasecmp(argv[0], "left") == 0) { | 876 | if (strcasecmp(argv[0], "left") == 0) { |
928 | return move_in_direction(current, MOVE_LEFT, argc, argv); | 877 | return cmd_move_in_direction(MOVE_LEFT, argc, argv); |
929 | } else if (strcasecmp(argv[0], "right") == 0) { | 878 | } else if (strcasecmp(argv[0], "right") == 0) { |
930 | return move_in_direction(current, MOVE_RIGHT, argc, argv); | 879 | return cmd_move_in_direction(MOVE_RIGHT, argc, argv); |
931 | } else if (strcasecmp(argv[0], "up") == 0) { | 880 | } else if (strcasecmp(argv[0], "up") == 0) { |
932 | return move_in_direction(current, MOVE_UP, argc, argv); | 881 | return cmd_move_in_direction(MOVE_UP, argc, argv); |
933 | } else if (strcasecmp(argv[0], "down") == 0) { | 882 | } else if (strcasecmp(argv[0], "down") == 0) { |
934 | return move_in_direction(current, MOVE_DOWN, argc, argv); | 883 | return cmd_move_in_direction(MOVE_DOWN, argc, argv); |
935 | } else if ((strcasecmp(argv[0], "container") == 0 | 884 | } else if ((strcasecmp(argv[0], "container") == 0 |
936 | || strcasecmp(argv[0], "window") == 0) || | 885 | || strcasecmp(argv[0], "window") == 0) || |
937 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && | 886 | (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2 |
938 | (strcasecmp(argv[0], "container") == 0 | 887 | && (strcasecmp(argv[1], "container") == 0 |
939 | || strcasecmp(argv[0], "window") == 0))) { | 888 | || strcasecmp(argv[1], "window") == 0))) { |
940 | return cmd_move_container(current, argc, argv); | 889 | return cmd_move_container(argc, argv); |
941 | } else if (strcasecmp(argv[0], "workspace") == 0) { | 890 | } else if (strcasecmp(argv[0], "workspace") == 0) { |
942 | return cmd_move_workspace(current, argc, argv); | 891 | return cmd_move_workspace(argc, argv); |
943 | } else if (strcasecmp(argv[0], "scratchpad") == 0 | 892 | } else if (strcasecmp(argv[0], "scratchpad") == 0 |
944 | || (strcasecmp(argv[0], "to") == 0 && argc == 2 | 893 | || (strcasecmp(argv[0], "to") == 0 && argc == 2 |
945 | && strcasecmp(argv[1], "scratchpad") == 0)) { | 894 | && strcasecmp(argv[1], "scratchpad") == 0)) { |
946 | return move_to_scratchpad(current); | 895 | return cmd_move_to_scratchpad(); |
947 | } else if (strcasecmp(argv[0], "position") == 0) { | 896 | } else if (strcasecmp(argv[0], "position") == 0) { |
948 | return move_to_position(current, argc, argv); | 897 | return cmd_move_to_position(argc, argv); |
949 | } else if (strcasecmp(argv[0], "absolute") == 0) { | 898 | } else if (strcasecmp(argv[0], "absolute") == 0) { |
950 | return move_to_position(current, argc, argv); | 899 | return cmd_move_to_position(argc, argv); |
951 | } else { | 900 | } else { |
952 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 901 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
953 | } | 902 | } |
diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c index 68fd9f42..9cdaad7f 100644 --- a/sway/commands/opacity.c +++ b/sway/commands/opacity.c | |||
@@ -19,8 +19,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) { | |||
19 | return error; | 19 | return error; |
20 | } | 20 | } |
21 | 21 | ||
22 | struct sway_container *con = | 22 | struct sway_container *con = config->handler_context.container; |
23 | config->handler_context.current_container; | ||
24 | 23 | ||
25 | float opacity = 0.0f; | 24 | float opacity = 0.0f; |
26 | 25 | ||
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index f8ca374d..36fb9092 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -42,7 +42,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) { | |||
42 | } | 42 | } |
43 | list_free(bar_ids); | 43 | list_free(bar_ids); |
44 | 44 | ||
45 | arrange_windows(&root_container); | 45 | arrange_root(); |
46 | 46 | ||
47 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 47 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
48 | } | 48 | } |
diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 21d2aa64..d982f941 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c | |||
@@ -25,14 +25,11 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | int argn = 1; | 27 | int argn = 1; |
28 | struct sway_container *workspace; | 28 | struct sway_workspace *workspace = NULL; |
29 | 29 | ||
30 | if (strcasecmp(argv[1], "to") == 0) { | 30 | if (strcasecmp(argv[1], "to") == 0) { |
31 | // 'rename workspace to new_name' | 31 | // 'rename workspace to new_name' |
32 | workspace = config->handler_context.current_container; | 32 | workspace = config->handler_context.workspace; |
33 | if (workspace->type != C_WORKSPACE) { | ||
34 | workspace = container_parent(workspace, C_WORKSPACE); | ||
35 | } | ||
36 | } else if (strcasecmp(argv[1], "number") == 0) { | 33 | } else if (strcasecmp(argv[1], "number") == 0) { |
37 | // 'rename workspace number x to new_name' | 34 | // 'rename workspace number x to new_name' |
38 | if (!isdigit(argv[2][0])) { | 35 | if (!isdigit(argv[2][0])) { |
@@ -78,7 +75,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
78 | return cmd_results_new(CMD_INVALID, "rename", | 75 | return cmd_results_new(CMD_INVALID, "rename", |
79 | "Cannot use special workspace name '%s'", argv[argn]); | 76 | "Cannot use special workspace name '%s'", argv[argn]); |
80 | } | 77 | } |
81 | struct sway_container *tmp_workspace = workspace_by_name(new_name); | 78 | struct sway_workspace *tmp_workspace = workspace_by_name(new_name); |
82 | if (tmp_workspace) { | 79 | if (tmp_workspace) { |
83 | free(new_name); | 80 | free(new_name); |
84 | return cmd_results_new(CMD_INVALID, "rename", | 81 | return cmd_results_new(CMD_INVALID, "rename", |
@@ -89,7 +86,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { | |||
89 | free(workspace->name); | 86 | free(workspace->name); |
90 | workspace->name = new_name; | 87 | workspace->name = new_name; |
91 | 88 | ||
92 | output_sort_workspaces(workspace->parent); | 89 | output_sort_workspaces(workspace->output); |
93 | ipc_event_workspace(NULL, workspace, "rename"); | 90 | ipc_event_workspace(NULL, workspace, "rename"); |
94 | 91 | ||
95 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 92 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index ad659ef5..99e9dbda 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include "sway/commands.h" | 10 | #include "sway/commands.h" |
11 | #include "sway/tree/arrange.h" | 11 | #include "sway/tree/arrange.h" |
12 | #include "sway/tree/view.h" | 12 | #include "sway/tree/view.h" |
13 | #include "sway/tree/workspace.h" | ||
13 | #include "log.h" | 14 | #include "log.h" |
14 | 15 | ||
15 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; | 16 | static const int MIN_SANE_W = 100, MIN_SANE_H = 60; |
@@ -75,7 +76,7 @@ static int parse_resize_amount(int argc, char **argv, | |||
75 | 76 | ||
76 | static void calculate_constraints(int *min_width, int *max_width, | 77 | static void calculate_constraints(int *min_width, int *max_width, |
77 | int *min_height, int *max_height) { | 78 | int *min_height, int *max_height) { |
78 | struct sway_container *con = config->handler_context.current_container; | 79 | struct sway_container *con = config->handler_context.container; |
79 | 80 | ||
80 | if (config->floating_minimum_width == -1) { // no minimum | 81 | if (config->floating_minimum_width == -1) { // no minimum |
81 | *min_width = 0; | 82 | *min_width = 0; |
@@ -96,8 +97,7 @@ static void calculate_constraints(int *min_width, int *max_width, | |||
96 | if (config->floating_maximum_width == -1) { // no maximum | 97 | if (config->floating_maximum_width == -1) { // no maximum |
97 | *max_width = INT_MAX; | 98 | *max_width = INT_MAX; |
98 | } else if (config->floating_maximum_width == 0) { // automatic | 99 | } else if (config->floating_maximum_width == 0) { // automatic |
99 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 100 | *max_width = con->workspace->width; |
100 | *max_width = ws->width; | ||
101 | } else { | 101 | } else { |
102 | *max_width = config->floating_maximum_width; | 102 | *max_width = config->floating_maximum_width; |
103 | } | 103 | } |
@@ -105,8 +105,7 @@ static void calculate_constraints(int *min_width, int *max_width, | |||
105 | if (config->floating_maximum_height == -1) { // no maximum | 105 | if (config->floating_maximum_height == -1) { // no maximum |
106 | *max_height = INT_MAX; | 106 | *max_height = INT_MAX; |
107 | } else if (config->floating_maximum_height == 0) { // automatic | 107 | } else if (config->floating_maximum_height == 0) { // automatic |
108 | struct sway_container *ws = container_parent(con, C_WORKSPACE); | 108 | *max_height = con->workspace->height; |
109 | *max_height = ws->height; | ||
110 | } else { | 109 | } else { |
111 | *max_height = config->floating_maximum_height; | 110 | *max_height = config->floating_maximum_height; |
112 | } | 111 | } |
@@ -191,11 +190,11 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
191 | normalize_axis(axis) == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; | 190 | normalize_axis(axis) == RESIZE_AXIS_HORIZONTAL ? L_HORIZ : L_VERT; |
192 | int minor_weight = 0; | 191 | int minor_weight = 0; |
193 | int major_weight = 0; | 192 | int major_weight = 0; |
194 | while (parent->parent) { | 193 | while (parent) { |
195 | struct sway_container *next = parent->parent; | 194 | list_t *siblings = container_get_siblings(parent); |
196 | if (next->layout == parallel_layout) { | 195 | if (container_parent_layout(parent) == parallel_layout) { |
197 | for (int i = 0; i < next->children->length; i++) { | 196 | for (int i = 0; i < siblings->length; i++) { |
198 | struct sway_container *sibling = next->children->items[i]; | 197 | struct sway_container *sibling = siblings->items[i]; |
199 | 198 | ||
200 | int sibling_pos = parallel_coord(sibling, axis); | 199 | int sibling_pos = parallel_coord(sibling, axis); |
201 | int focused_pos = parallel_coord(focused, axis); | 200 | int focused_pos = parallel_coord(focused, axis); |
@@ -213,17 +212,13 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
213 | break; | 212 | break; |
214 | } | 213 | } |
215 | } | 214 | } |
216 | parent = next; | 215 | parent = parent->parent; |
217 | } | 216 | } |
218 | 217 | if (!parent) { | |
219 | if (parent->type == C_ROOT) { | 218 | // Can't resize in this direction |
220 | return; | 219 | return; |
221 | } | 220 | } |
222 | 221 | ||
223 | wlr_log(WLR_DEBUG, | ||
224 | "Found the proper parent: %p. It has %d l conts, and %d r conts", | ||
225 | parent->parent, minor_weight, major_weight); | ||
226 | |||
227 | // Implement up/down/left/right direction by zeroing one of the weights, | 222 | // Implement up/down/left/right direction by zeroing one of the weights, |
228 | // then setting the axis to be horizontal or vertical | 223 | // then setting the axis to be horizontal or vertical |
229 | if (axis == RESIZE_AXIS_UP || axis == RESIZE_AXIS_LEFT) { | 224 | if (axis == RESIZE_AXIS_UP || axis == RESIZE_AXIS_LEFT) { |
@@ -237,9 +232,10 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
237 | 232 | ||
238 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks | 233 | //TODO: Ensure rounding is done in such a way that there are NO pixel leaks |
239 | // ^ ????? | 234 | // ^ ????? |
235 | list_t *siblings = container_get_siblings(parent); | ||
240 | 236 | ||
241 | for (int i = 0; i < parent->parent->children->length; i++) { | 237 | for (int i = 0; i < siblings->length; i++) { |
242 | struct sway_container *sibling = parent->parent->children->items[i]; | 238 | struct sway_container *sibling = siblings->items[i]; |
243 | 239 | ||
244 | int sibling_pos = parallel_coord(sibling, axis); | 240 | int sibling_pos = parallel_coord(sibling, axis); |
245 | int focused_pos = parallel_coord(focused, axis); | 241 | int focused_pos = parallel_coord(focused, axis); |
@@ -277,8 +273,8 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
277 | enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? | 273 | enum wlr_edges major_edge = axis == RESIZE_AXIS_HORIZONTAL ? |
278 | WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; | 274 | WLR_EDGE_RIGHT : WLR_EDGE_BOTTOM; |
279 | 275 | ||
280 | for (int i = 0; i < parent->parent->children->length; i++) { | 276 | for (int i = 0; i < siblings->length; i++) { |
281 | struct sway_container *sibling = parent->parent->children->items[i]; | 277 | struct sway_container *sibling = siblings->items[i]; |
282 | 278 | ||
283 | int sibling_pos = parallel_coord(sibling, axis); | 279 | int sibling_pos = parallel_coord(sibling, axis); |
284 | int focused_pos = parallel_coord(focused, axis); | 280 | int focused_pos = parallel_coord(focused, axis); |
@@ -316,7 +312,11 @@ static void resize_tiled(struct sway_container *parent, int amount, | |||
316 | } | 312 | } |
317 | } | 313 | } |
318 | 314 | ||
319 | arrange_windows(parent->parent); | 315 | if (parent->parent) { |
316 | arrange_container(parent->parent); | ||
317 | } else { | ||
318 | arrange_workspace(parent->workspace); | ||
319 | } | ||
320 | } | 320 | } |
321 | 321 | ||
322 | void container_resize_tiled(struct sway_container *parent, | 322 | void container_resize_tiled(struct sway_container *parent, |
@@ -346,7 +346,7 @@ void container_resize_tiled(struct sway_container *parent, | |||
346 | */ | 346 | */ |
347 | static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | 347 | static struct cmd_results *resize_adjust_floating(enum resize_axis axis, |
348 | struct resize_amount *amount) { | 348 | struct resize_amount *amount) { |
349 | struct sway_container *con = config->handler_context.current_container; | 349 | struct sway_container *con = config->handler_context.container; |
350 | int grow_width = 0, grow_height = 0; | 350 | int grow_width = 0, grow_height = 0; |
351 | switch (axis) { | 351 | switch (axis) { |
352 | case RESIZE_AXIS_HORIZONTAL: | 352 | case RESIZE_AXIS_HORIZONTAL: |
@@ -400,15 +400,15 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | |||
400 | con->width += grow_width; | 400 | con->width += grow_width; |
401 | con->height += grow_height; | 401 | con->height += grow_height; |
402 | 402 | ||
403 | if (con->type == C_VIEW) { | 403 | if (con->view) { |
404 | struct sway_view *view = con->sway_view; | 404 | struct sway_view *view = con->view; |
405 | view->x += grow_x; | 405 | view->x += grow_x; |
406 | view->y += grow_y; | 406 | view->y += grow_y; |
407 | view->width += grow_width; | 407 | view->width += grow_width; |
408 | view->height += grow_height; | 408 | view->height += grow_height; |
409 | } | 409 | } |
410 | 410 | ||
411 | arrange_windows(con); | 411 | arrange_container(con); |
412 | 412 | ||
413 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 413 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
414 | } | 414 | } |
@@ -418,7 +418,7 @@ static struct cmd_results *resize_adjust_floating(enum resize_axis axis, | |||
418 | */ | 418 | */ |
419 | static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, | 419 | static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, |
420 | struct resize_amount *amount) { | 420 | struct resize_amount *amount) { |
421 | struct sway_container *current = config->handler_context.current_container; | 421 | struct sway_container *current = config->handler_context.container; |
422 | 422 | ||
423 | if (amount->unit == RESIZE_UNIT_DEFAULT) { | 423 | if (amount->unit == RESIZE_UNIT_DEFAULT) { |
424 | amount->unit = RESIZE_UNIT_PPT; | 424 | amount->unit = RESIZE_UNIT_PPT; |
@@ -456,13 +456,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
456 | width->unit == RESIZE_UNIT_DEFAULT) { | 456 | width->unit == RESIZE_UNIT_DEFAULT) { |
457 | // Convert to px | 457 | // Convert to px |
458 | struct sway_container *parent = con->parent; | 458 | struct sway_container *parent = con->parent; |
459 | while (parent->type >= C_WORKSPACE && parent->layout != L_HORIZ) { | 459 | while (parent && parent->layout != L_HORIZ) { |
460 | parent = parent->parent; | 460 | parent = parent->parent; |
461 | } | 461 | } |
462 | if (parent->type >= C_WORKSPACE) { | 462 | if (parent) { |
463 | width->amount = parent->width * width->amount / 100; | 463 | width->amount = parent->width * width->amount / 100; |
464 | width->unit = RESIZE_UNIT_PX; | 464 | } else { |
465 | width->amount = con->workspace->width * width->amount / 100; | ||
465 | } | 466 | } |
467 | width->unit = RESIZE_UNIT_PX; | ||
466 | } | 468 | } |
467 | if (width->unit == RESIZE_UNIT_PX) { | 469 | if (width->unit == RESIZE_UNIT_PX) { |
468 | resize_tiled(con, width->amount - con->width, | 470 | resize_tiled(con, width->amount - con->width, |
@@ -475,13 +477,15 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
475 | height->unit == RESIZE_UNIT_DEFAULT) { | 477 | height->unit == RESIZE_UNIT_DEFAULT) { |
476 | // Convert to px | 478 | // Convert to px |
477 | struct sway_container *parent = con->parent; | 479 | struct sway_container *parent = con->parent; |
478 | while (parent->type >= C_WORKSPACE && parent->layout != L_VERT) { | 480 | while (parent && parent->layout != L_VERT) { |
479 | parent = parent->parent; | 481 | parent = parent->parent; |
480 | } | 482 | } |
481 | if (parent->type >= C_WORKSPACE) { | 483 | if (parent) { |
482 | height->amount = parent->height * height->amount / 100; | 484 | height->amount = parent->height * height->amount / 100; |
483 | height->unit = RESIZE_UNIT_PX; | 485 | } else { |
486 | height->amount = con->workspace->height * height->amount / 100; | ||
484 | } | 487 | } |
488 | height->unit = RESIZE_UNIT_PX; | ||
485 | } | 489 | } |
486 | if (height->unit == RESIZE_UNIT_PX) { | 490 | if (height->unit == RESIZE_UNIT_PX) { |
487 | resize_tiled(con, height->amount - con->height, | 491 | resize_tiled(con, height->amount - con->height, |
@@ -508,15 +512,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, | |||
508 | con->width = width->amount; | 512 | con->width = width->amount; |
509 | con->height = height->amount; | 513 | con->height = height->amount; |
510 | 514 | ||
511 | if (con->type == C_VIEW) { | 515 | if (con->view) { |
512 | struct sway_view *view = con->sway_view; | 516 | struct sway_view *view = con->view; |
513 | view->x -= grow_width / 2; | 517 | view->x -= grow_width / 2; |
514 | view->y -= grow_height / 2; | 518 | view->y -= grow_height / 2; |
515 | view->width += grow_width; | 519 | view->width += grow_width; |
516 | view->height += grow_height; | 520 | view->height += grow_height; |
517 | } | 521 | } |
518 | 522 | ||
519 | arrange_windows(con); | 523 | arrange_container(con); |
520 | 524 | ||
521 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 525 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
522 | } | 526 | } |
@@ -555,7 +559,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { | |||
555 | } | 559 | } |
556 | 560 | ||
557 | // If 0, don't resize that dimension | 561 | // If 0, don't resize that dimension |
558 | struct sway_container *con = config->handler_context.current_container; | 562 | struct sway_container *con = config->handler_context.container; |
559 | if (width.amount <= 0) { | 563 | if (width.amount <= 0) { |
560 | width.amount = con->width; | 564 | width.amount = con->width; |
561 | } | 565 | } |
@@ -624,7 +628,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, | |||
624 | first_amount.amount *= multiplier; | 628 | first_amount.amount *= multiplier; |
625 | second_amount.amount *= multiplier; | 629 | second_amount.amount *= multiplier; |
626 | 630 | ||
627 | struct sway_container *con = config->handler_context.current_container; | 631 | struct sway_container *con = config->handler_context.container; |
628 | if (container_is_floating(con)) { | 632 | if (container_is_floating(con)) { |
629 | // Floating containers can only resize in px. Choose an amount which | 633 | // Floating containers can only resize in px. Choose an amount which |
630 | // uses px, with fallback to an amount that specified no unit. | 634 | // uses px, with fallback to an amount that specified no unit. |
@@ -657,14 +661,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv, | |||
657 | } | 661 | } |
658 | 662 | ||
659 | struct cmd_results *cmd_resize(int argc, char **argv) { | 663 | struct cmd_results *cmd_resize(int argc, char **argv) { |
660 | struct sway_container *current = config->handler_context.current_container; | 664 | struct sway_container *current = config->handler_context.container; |
661 | if (!current) { | 665 | if (!current) { |
662 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); | 666 | return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); |
663 | } | 667 | } |
664 | if (current->type != C_VIEW && current->type != C_CONTAINER) { | ||
665 | return cmd_results_new(CMD_INVALID, "resize", | ||
666 | "Can only resize views/containers"); | ||
667 | } | ||
668 | 668 | ||
669 | struct cmd_results *error; | 669 | struct cmd_results *error; |
670 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { | 670 | if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { |
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 7da20015..d8bae615 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c | |||
@@ -9,36 +9,34 @@ | |||
9 | 9 | ||
10 | static void scratchpad_toggle_auto(void) { | 10 | static void scratchpad_toggle_auto(void) { |
11 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 11 | struct sway_seat *seat = input_manager_current_seat(input_manager); |
12 | struct sway_container *focus = seat_get_focus(seat); | 12 | struct sway_container *focus = seat_get_focused_container(seat); |
13 | struct sway_container *ws = focus->type == C_WORKSPACE ? | 13 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
14 | focus : container_parent(focus, C_WORKSPACE); | ||
15 | 14 | ||
16 | // If the focus is in a floating split container, | 15 | // If the focus is in a floating split container, |
17 | // operate on the split container instead of the child. | 16 | // operate on the split container instead of the child. |
18 | if (container_is_floating_or_child(focus)) { | 17 | if (focus && container_is_floating_or_child(focus)) { |
19 | while (focus->parent->type != C_WORKSPACE) { | 18 | while (focus->parent) { |
20 | focus = focus->parent; | 19 | focus = focus->parent; |
21 | } | 20 | } |
22 | } | 21 | } |
23 | 22 | ||
24 | |||
25 | // Check if the currently focused window is a scratchpad window and should | 23 | // Check if the currently focused window is a scratchpad window and should |
26 | // be hidden again. | 24 | // be hidden again. |
27 | if (focus->scratchpad) { | 25 | if (focus && focus->scratchpad) { |
28 | wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", | 26 | wlr_log(WLR_DEBUG, "Focus is a scratchpad window - hiding %s", |
29 | focus->name); | 27 | focus->title); |
30 | root_scratchpad_hide(focus); | 28 | root_scratchpad_hide(focus); |
31 | return; | 29 | return; |
32 | } | 30 | } |
33 | 31 | ||
34 | // Check if there is an unfocused scratchpad window on the current workspace | 32 | // Check if there is an unfocused scratchpad window on the current workspace |
35 | // and focus it. | 33 | // and focus it. |
36 | for (int i = 0; i < ws->sway_workspace->floating->length; ++i) { | 34 | for (int i = 0; i < ws->floating->length; ++i) { |
37 | struct sway_container *floater = ws->sway_workspace->floating->items[i]; | 35 | struct sway_container *floater = ws->floating->items[i]; |
38 | if (floater->scratchpad && focus != floater) { | 36 | if (floater->scratchpad && focus != floater) { |
39 | wlr_log(WLR_DEBUG, | 37 | wlr_log(WLR_DEBUG, |
40 | "Focusing other scratchpad window (%s) in this workspace", | 38 | "Focusing other scratchpad window (%s) in this workspace", |
41 | floater->name); | 39 | floater->title); |
42 | root_scratchpad_show(floater); | 40 | root_scratchpad_show(floater); |
43 | return; | 41 | return; |
44 | } | 42 | } |
@@ -46,25 +44,23 @@ static void scratchpad_toggle_auto(void) { | |||
46 | 44 | ||
47 | // Check if there is a visible scratchpad window on another workspace. | 45 | // Check if there is a visible scratchpad window on another workspace. |
48 | // In this case we move it to the current workspace. | 46 | // In this case we move it to the current workspace. |
49 | for (int i = 0; i < root_container.sway_root->scratchpad->length; ++i) { | 47 | for (int i = 0; i < root->scratchpad->length; ++i) { |
50 | struct sway_container *con = | 48 | struct sway_container *con = root->scratchpad->items[i]; |
51 | root_container.sway_root->scratchpad->items[i]; | ||
52 | if (con->parent) { | 49 | if (con->parent) { |
53 | wlr_log(WLR_DEBUG, | 50 | wlr_log(WLR_DEBUG, |
54 | "Moving a visible scratchpad window (%s) to this workspace", | 51 | "Moving a visible scratchpad window (%s) to this workspace", |
55 | con->name); | 52 | con->title); |
56 | root_scratchpad_show(con); | 53 | root_scratchpad_show(con); |
57 | return; | 54 | return; |
58 | } | 55 | } |
59 | } | 56 | } |
60 | 57 | ||
61 | // Take the container at the bottom of the scratchpad list | 58 | // Take the container at the bottom of the scratchpad list |
62 | if (!sway_assert(root_container.sway_root->scratchpad->length, | 59 | if (!sway_assert(root->scratchpad->length, "Scratchpad is empty")) { |
63 | "Scratchpad is empty")) { | ||
64 | return; | 60 | return; |
65 | } | 61 | } |
66 | struct sway_container *con = root_container.sway_root->scratchpad->items[0]; | 62 | struct sway_container *con = root->scratchpad->items[0]; |
67 | wlr_log(WLR_DEBUG, "Showing %s from list", con->name); | 63 | wlr_log(WLR_DEBUG, "Showing %s from list", con->title); |
68 | root_scratchpad_show(con); | 64 | root_scratchpad_show(con); |
69 | } | 65 | } |
70 | 66 | ||
@@ -74,7 +70,7 @@ static void scratchpad_toggle_container(struct sway_container *con) { | |||
74 | } | 70 | } |
75 | 71 | ||
76 | // Check if it matches a currently visible scratchpad window and hide it. | 72 | // Check if it matches a currently visible scratchpad window and hide it. |
77 | if (con->parent) { | 73 | if (con->workspace) { |
78 | root_scratchpad_hide(con); | 74 | root_scratchpad_hide(con); |
79 | return; | 75 | return; |
80 | } | 76 | } |
@@ -91,18 +87,18 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { | |||
91 | return cmd_results_new(CMD_INVALID, "scratchpad", | 87 | return cmd_results_new(CMD_INVALID, "scratchpad", |
92 | "Expected 'scratchpad show'"); | 88 | "Expected 'scratchpad show'"); |
93 | } | 89 | } |
94 | if (!root_container.sway_root->scratchpad->length) { | 90 | if (!root->scratchpad->length) { |
95 | return cmd_results_new(CMD_INVALID, "scratchpad", | 91 | return cmd_results_new(CMD_INVALID, "scratchpad", |
96 | "Scratchpad is empty"); | 92 | "Scratchpad is empty"); |
97 | } | 93 | } |
98 | 94 | ||
99 | if (config->handler_context.using_criteria) { | 95 | if (config->handler_context.using_criteria) { |
100 | struct sway_container *con = config->handler_context.current_container; | 96 | struct sway_container *con = config->handler_context.container; |
101 | 97 | ||
102 | // If the container is in a floating split container, | 98 | // If the container is in a floating split container, |
103 | // operate on the split container instead of the child. | 99 | // operate on the split container instead of the child. |
104 | if (container_is_floating_or_child(con)) { | 100 | if (container_is_floating_or_child(con)) { |
105 | while (con->parent->type != C_WORKSPACE) { | 101 | while (con->parent) { |
106 | con = con->parent; | 102 | con = con->parent; |
107 | } | 103 | } |
108 | } | 104 | } |
diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 4d0a22c7..cd6630e0 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c | |||
@@ -42,8 +42,8 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { | |||
42 | return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); | 42 | return cmd_results_new(CMD_INVALID, "cursor", expected_syntax); |
43 | } | 43 | } |
44 | // map absolute coords (0..1,0..1) to root container coords | 44 | // map absolute coords (0..1,0..1) to root container coords |
45 | float x = strtof(argv[1], NULL) / root_container.width; | 45 | float x = strtof(argv[1], NULL) / root->width; |
46 | float y = strtof(argv[2], NULL) / root_container.height; | 46 | float y = strtof(argv[2], NULL) / root->height; |
47 | wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); | 47 | wlr_cursor_warp_absolute(cursor->cursor, NULL, x, y); |
48 | cursor_send_pointer_motion(cursor, 0, true); | 48 | cursor_send_pointer_motion(cursor, 0, true); |
49 | } else { | 49 | } else { |
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c index 1844e917..d501584a 100644 --- a/sway/commands/show_marks.c +++ b/sway/commands/show_marks.c | |||
@@ -11,8 +11,8 @@ | |||
11 | #include "util.h" | 11 | #include "util.h" |
12 | 12 | ||
13 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { | 13 | static void rebuild_marks_iterator(struct sway_container *con, void *data) { |
14 | if (con->type == C_VIEW) { | 14 | if (con->view) { |
15 | view_update_marks_textures(con->sway_view); | 15 | view_update_marks_textures(con->view); |
16 | } | 16 | } |
17 | } | 17 | } |
18 | 18 | ||
@@ -28,9 +28,9 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) { | |||
28 | root_for_each_container(rebuild_marks_iterator, NULL); | 28 | root_for_each_container(rebuild_marks_iterator, NULL); |
29 | } | 29 | } |
30 | 30 | ||
31 | for (int i = 0; i < root_container.children->length; ++i) { | 31 | for (int i = 0; i < root->outputs->length; ++i) { |
32 | struct sway_container *con = root_container.children->items[i]; | 32 | struct sway_output *output = root->outputs->items[i]; |
33 | output_damage_whole(con->sway_output); | 33 | output_damage_whole(output); |
34 | } | 34 | } |
35 | 35 | ||
36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c index 7d27e571..273905df 100644 --- a/sway/commands/smart_gaps.c +++ b/sway/commands/smart_gaps.c | |||
@@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) { | |||
23 | "Expected 'smart_gaps <on|off>' "); | 23 | "Expected 'smart_gaps <on|off>' "); |
24 | } | 24 | } |
25 | 25 | ||
26 | arrange_windows(&root_container); | 26 | arrange_root(); |
27 | 27 | ||
28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 28 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
29 | } | 29 | } |
diff --git a/sway/commands/split.c b/sway/commands/split.c index a8eddf54..9a53f3d3 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c | |||
@@ -4,15 +4,21 @@ | |||
4 | #include "sway/tree/arrange.h" | 4 | #include "sway/tree/arrange.h" |
5 | #include "sway/tree/container.h" | 5 | #include "sway/tree/container.h" |
6 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
7 | #include "sway/tree/workspace.h" | ||
7 | #include "sway/input/input-manager.h" | 8 | #include "sway/input/input-manager.h" |
8 | #include "sway/input/seat.h" | 9 | #include "sway/input/seat.h" |
9 | #include "log.h" | 10 | #include "log.h" |
10 | 11 | ||
11 | static struct cmd_results *do_split(int layout) { | 12 | static struct cmd_results *do_split(int layout) { |
12 | struct sway_container *con = config->handler_context.current_container; | 13 | struct sway_container *con = config->handler_context.container; |
13 | struct sway_container *parent = container_split(con, layout); | 14 | struct sway_workspace *ws = config->handler_context.workspace; |
14 | container_create_notify(parent); | 15 | if (con) { |
15 | arrange_windows(parent->parent); | 16 | container_split(con, layout); |
17 | } else { | ||
18 | workspace_split(ws, layout); | ||
19 | } | ||
20 | |||
21 | arrange_workspace(ws); | ||
16 | 22 | ||
17 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 23 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
18 | } | 24 | } |
@@ -29,10 +35,9 @@ struct cmd_results *cmd_split(int argc, char **argv) { | |||
29 | return do_split(L_HORIZ); | 35 | return do_split(L_HORIZ); |
30 | } else if (strcasecmp(argv[0], "t") == 0 || | 36 | } else if (strcasecmp(argv[0], "t") == 0 || |
31 | strcasecmp(argv[0], "toggle") == 0) { | 37 | strcasecmp(argv[0], "toggle") == 0) { |
32 | struct sway_container *focused = | 38 | struct sway_container *focused = config->handler_context.container; |
33 | config->handler_context.current_container; | ||
34 | 39 | ||
35 | if (focused->parent->layout == L_VERT) { | 40 | if (focused && container_parent_layout(focused) == L_VERT) { |
36 | return do_split(L_HORIZ); | 41 | return do_split(L_HORIZ); |
37 | } else { | 42 | } else { |
38 | return do_split(L_VERT); | 43 | return do_split(L_VERT); |
@@ -66,9 +71,9 @@ struct cmd_results *cmd_splitt(int argc, char **argv) { | |||
66 | return error; | 71 | return error; |
67 | } | 72 | } |
68 | 73 | ||
69 | struct sway_container *con = config->handler_context.current_container; | 74 | struct sway_container *con = config->handler_context.container; |
70 | 75 | ||
71 | if (con->parent->layout == L_VERT) { | 76 | if (con && container_parent_layout(con) == L_VERT) { |
72 | return do_split(L_HORIZ); | 77 | return do_split(L_HORIZ); |
73 | } else { | 78 | } else { |
74 | return do_split(L_VERT); | 79 | return do_split(L_VERT); |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 8692e08d..7995cdd6 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c | |||
@@ -15,8 +15,7 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
15 | if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { | 15 | if ((error = checkarg(argc, "sticky", EXPECTED_EQUAL_TO, 1))) { |
16 | return error; | 16 | return error; |
17 | } | 17 | } |
18 | struct sway_container *container = | 18 | struct sway_container *container = config->handler_context.container; |
19 | config->handler_context.current_container; | ||
20 | if (!container_is_floating(container)) { | 19 | if (!container_is_floating(container)) { |
21 | return cmd_results_new(CMD_FAILURE, "sticky", | 20 | return cmd_results_new(CMD_FAILURE, "sticky", |
22 | "Can't set sticky on a tiled container"); | 21 | "Can't set sticky on a tiled container"); |
@@ -37,20 +36,16 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
37 | container->is_sticky = wants_sticky; | 36 | container->is_sticky = wants_sticky; |
38 | 37 | ||
39 | if (wants_sticky) { | 38 | if (wants_sticky) { |
40 | // move container to focused workspace | 39 | // move container to active workspace |
41 | struct sway_container *output = container_parent(container, C_OUTPUT); | 40 | struct sway_workspace *active_workspace = |
42 | struct sway_seat *seat = input_manager_current_seat(input_manager); | 41 | output_get_active_workspace(container->workspace->output); |
43 | struct sway_container *focus = seat_get_focus_inactive(seat, output); | 42 | if (container->workspace != active_workspace) { |
44 | struct sway_container *focused_workspace = container_parent(focus, C_WORKSPACE); | 43 | struct sway_workspace *old_workspace = container->workspace; |
45 | struct sway_container *current_workspace = container_parent(container, C_WORKSPACE); | 44 | container_detach(container); |
46 | if (current_workspace != focused_workspace) { | 45 | workspace_add_floating(active_workspace, container); |
47 | container_remove_child(container); | 46 | container_handle_fullscreen_reparent(container); |
48 | workspace_add_floating(focused_workspace, container); | 47 | arrange_workspace(active_workspace); |
49 | container_handle_fullscreen_reparent(container, current_workspace); | 48 | workspace_consider_destroy(old_workspace); |
50 | arrange_windows(focused_workspace); | ||
51 | if (!container_reap_empty(current_workspace)) { | ||
52 | arrange_windows(current_workspace); | ||
53 | } | ||
54 | } | 49 | } |
55 | } | 50 | } |
56 | 51 | ||
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index f25c43a1..a0ffbda8 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include "config.h" | 4 | #include "config.h" |
5 | #include "log.h" | 5 | #include "log.h" |
6 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
7 | #include "sway/output.h" | ||
7 | #include "sway/tree/arrange.h" | 8 | #include "sway/tree/arrange.h" |
8 | #include "sway/tree/root.h" | 9 | #include "sway/tree/root.h" |
9 | #include "sway/tree/view.h" | 10 | #include "sway/tree/view.h" |
@@ -43,27 +44,28 @@ static void swap_focus(struct sway_container *con1, | |||
43 | struct sway_container *con2, struct sway_seat *seat, | 44 | struct sway_container *con2, struct sway_seat *seat, |
44 | struct sway_container *focus) { | 45 | struct sway_container *focus) { |
45 | if (focus == con1 || focus == con2) { | 46 | if (focus == con1 || focus == con2) { |
46 | struct sway_container *ws1 = container_parent(con1, C_WORKSPACE); | 47 | struct sway_workspace *ws1 = con1->workspace; |
47 | struct sway_container *ws2 = container_parent(con2, C_WORKSPACE); | 48 | struct sway_workspace *ws2 = con2->workspace; |
48 | if (focus == con1 && (con2->parent->layout == L_TABBED | 49 | enum sway_container_layout layout1 = container_parent_layout(con1); |
49 | || con2->parent->layout == L_STACKED)) { | 50 | enum sway_container_layout layout2 = container_parent_layout(con2); |
51 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { | ||
50 | if (workspace_is_visible(ws2)) { | 52 | if (workspace_is_visible(ws2)) { |
51 | seat_set_focus_warp(seat, con2, false, true); | 53 | seat_set_focus_warp(seat, &con2->node, false, true); |
52 | } | 54 | } |
53 | seat_set_focus(seat, ws1 != ws2 ? con2 : con1); | 55 | seat_set_focus(seat, ws1 != ws2 ? &con2->node : &con1->node); |
54 | } else if (focus == con2 && (con1->parent->layout == L_TABBED | 56 | } else if (focus == con2 && (layout1 == L_TABBED |
55 | || con1->parent->layout == L_STACKED)) { | 57 | || layout1 == L_STACKED)) { |
56 | if (workspace_is_visible(ws1)) { | 58 | if (workspace_is_visible(ws1)) { |
57 | seat_set_focus_warp(seat, con1, false, true); | 59 | seat_set_focus_warp(seat, &con1->node, false, true); |
58 | } | 60 | } |
59 | seat_set_focus(seat, ws1 != ws2 ? con1 : con2); | 61 | seat_set_focus(seat, ws1 != ws2 ? &con1->node : &con2->node); |
60 | } else if (ws1 != ws2) { | 62 | } else if (ws1 != ws2) { |
61 | seat_set_focus(seat, focus == con1 ? con2 : con1); | 63 | seat_set_focus(seat, focus == con1 ? &con2->node : &con1->node); |
62 | } else { | 64 | } else { |
63 | seat_set_focus(seat, focus); | 65 | seat_set_focus(seat, &focus->node); |
64 | } | 66 | } |
65 | } else { | 67 | } else { |
66 | seat_set_focus(seat, focus); | 68 | seat_set_focus(seat, &focus->node); |
67 | } | 69 | } |
68 | } | 70 | } |
69 | 71 | ||
@@ -72,10 +74,6 @@ static void container_swap(struct sway_container *con1, | |||
72 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { | 74 | if (!sway_assert(con1 && con2, "Cannot swap with nothing")) { |
73 | return; | 75 | return; |
74 | } | 76 | } |
75 | if (!sway_assert(con1->type >= C_CONTAINER && con2->type >= C_CONTAINER, | ||
76 | "Can only swap containers and views")) { | ||
77 | return; | ||
78 | } | ||
79 | if (!sway_assert(!container_has_ancestor(con1, con2) | 77 | if (!sway_assert(!container_has_ancestor(con1, con2) |
80 | && !container_has_ancestor(con2, con1), | 78 | && !container_has_ancestor(con2, con1), |
81 | "Cannot swap ancestor and descendant")) { | 79 | "Cannot swap ancestor and descendant")) { |
@@ -87,10 +85,11 @@ static void container_swap(struct sway_container *con1, | |||
87 | return; | 85 | return; |
88 | } | 86 | } |
89 | 87 | ||
90 | wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); | 88 | wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", |
89 | con1->node.id, con2->node.id); | ||
91 | 90 | ||
92 | int fs1 = con1->is_fullscreen; | 91 | bool fs1 = con1->is_fullscreen; |
93 | int fs2 = con2->is_fullscreen; | 92 | bool fs2 = con2->is_fullscreen; |
94 | if (fs1) { | 93 | if (fs1) { |
95 | container_set_fullscreen(con1, false); | 94 | container_set_fullscreen(con1, false); |
96 | } | 95 | } |
@@ -99,13 +98,11 @@ static void container_swap(struct sway_container *con1, | |||
99 | } | 98 | } |
100 | 99 | ||
101 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 100 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
102 | struct sway_container *focus = seat_get_focus(seat); | 101 | struct sway_container *focus = seat_get_focused_container(seat); |
103 | struct sway_container *vis1 = container_parent( | 102 | struct sway_workspace *vis1 = |
104 | seat_get_focus_inactive(seat, container_parent(con1, C_OUTPUT)), | 103 | output_get_active_workspace(con1->workspace->output); |
105 | C_WORKSPACE); | 104 | struct sway_workspace *vis2 = |
106 | struct sway_container *vis2 = container_parent( | 105 | output_get_active_workspace(con2->workspace->output); |
107 | seat_get_focus_inactive(seat, container_parent(con2, C_OUTPUT)), | ||
108 | C_WORKSPACE); | ||
109 | 106 | ||
110 | char *stored_prev_name = NULL; | 107 | char *stored_prev_name = NULL; |
111 | if (prev_workspace_name) { | 108 | if (prev_workspace_name) { |
@@ -115,10 +112,10 @@ static void container_swap(struct sway_container *con1, | |||
115 | swap_places(con1, con2); | 112 | swap_places(con1, con2); |
116 | 113 | ||
117 | if (!workspace_is_visible(vis1)) { | 114 | if (!workspace_is_visible(vis1)) { |
118 | seat_set_focus(seat, seat_get_focus_inactive(seat, vis1)); | 115 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis1->node)); |
119 | } | 116 | } |
120 | if (!workspace_is_visible(vis2)) { | 117 | if (!workspace_is_visible(vis2)) { |
121 | seat_set_focus(seat, seat_get_focus_inactive(seat, vis2)); | 118 | seat_set_focus(seat, seat_get_focus_inactive(seat, &vis2->node)); |
122 | } | 119 | } |
123 | 120 | ||
124 | swap_focus(con1, con2, seat, focus); | 121 | swap_focus(con1, con2, seat, focus); |
@@ -137,23 +134,22 @@ static void container_swap(struct sway_container *con1, | |||
137 | } | 134 | } |
138 | 135 | ||
139 | static bool test_con_id(struct sway_container *container, void *con_id) { | 136 | static bool test_con_id(struct sway_container *container, void *con_id) { |
140 | return container->id == (size_t)con_id; | 137 | return container->node.id == (size_t)con_id; |
141 | } | 138 | } |
142 | 139 | ||
143 | static bool test_id(struct sway_container *container, void *id) { | 140 | static bool test_id(struct sway_container *container, void *id) { |
144 | #ifdef HAVE_XWAYLAND | 141 | #ifdef HAVE_XWAYLAND |
145 | xcb_window_t *wid = id; | 142 | xcb_window_t *wid = id; |
146 | return (container->type == C_VIEW | 143 | return (container->view && container->view->type == SWAY_VIEW_XWAYLAND |
147 | && container->sway_view->type == SWAY_VIEW_XWAYLAND | 144 | && container->view->wlr_xwayland_surface->window_id == *wid); |
148 | && container->sway_view->wlr_xwayland_surface->window_id == *wid); | ||
149 | #else | 145 | #else |
150 | return false; | 146 | return false; |
151 | #endif | 147 | #endif |
152 | } | 148 | } |
153 | 149 | ||
154 | static bool test_mark(struct sway_container *container, void *mark) { | 150 | static bool test_mark(struct sway_container *container, void *mark) { |
155 | if (container->type == C_VIEW && container->sway_view->marks->length) { | 151 | if (container->view && container->view->marks->length) { |
156 | return !list_seq_find(container->sway_view->marks, | 152 | return !list_seq_find(container->view->marks, |
157 | (int (*)(const void *, const void *))strcmp, mark); | 153 | (int (*)(const void *, const void *))strcmp, mark); |
158 | } | 154 | } |
159 | return false; | 155 | return false; |
@@ -169,7 +165,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
169 | return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); | 165 | return cmd_results_new(CMD_INVALID, "swap", EXPECTED_SYNTAX); |
170 | } | 166 | } |
171 | 167 | ||
172 | struct sway_container *current = config->handler_context.current_container; | 168 | struct sway_container *current = config->handler_context.container; |
173 | struct sway_container *other; | 169 | struct sway_container *other; |
174 | 170 | ||
175 | char *value = join_args(argv + 3, argc - 3); | 171 | char *value = join_args(argv + 3, argc - 3); |
@@ -191,7 +187,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
191 | if (!other) { | 187 | if (!other) { |
192 | error = cmd_results_new(CMD_FAILURE, "swap", | 188 | error = cmd_results_new(CMD_FAILURE, "swap", |
193 | "Failed to find %s '%s'", argv[2], value); | 189 | "Failed to find %s '%s'", argv[2], value); |
194 | } else if (current->type < C_CONTAINER || other->type < C_CONTAINER) { | 190 | } else if (!current) { |
195 | error = cmd_results_new(CMD_FAILURE, "swap", | 191 | error = cmd_results_new(CMD_FAILURE, "swap", |
196 | "Can only swap with containers and views"); | 192 | "Can only swap with containers and views"); |
197 | } else if (container_has_ancestor(current, other) | 193 | } else if (container_has_ancestor(current, other) |
@@ -211,9 +207,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) { | |||
211 | 207 | ||
212 | container_swap(current, other); | 208 | container_swap(current, other); |
213 | 209 | ||
214 | arrange_windows(current->parent); | 210 | arrange_node(node_get_parent(¤t->node)); |
215 | if (other->parent != current->parent) { | 211 | if (node_get_parent(&other->node) != node_get_parent(¤t->node)) { |
216 | arrange_windows(other->parent); | 212 | arrange_node(node_get_parent(&other->node)); |
217 | } | 213 | } |
218 | 214 | ||
219 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 215 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 3d1c578c..c9ffe8fa 100644 --- a/sway/commands/title_format.c +++ b/sway/commands/title_format.c | |||
@@ -11,13 +11,12 @@ struct cmd_results *cmd_title_format(int argc, char **argv) { | |||
11 | if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { | 11 | if ((error = checkarg(argc, "title_format", EXPECTED_AT_LEAST, 1))) { |
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct sway_container *container = | 14 | struct sway_container *container = config->handler_context.container; |
15 | config->handler_context.current_container; | 15 | if (!container->view) { |
16 | if (container->type != C_VIEW) { | ||
17 | return cmd_results_new(CMD_INVALID, "title_format", | 16 | return cmd_results_new(CMD_INVALID, "title_format", |
18 | "Only views can have a title_format"); | 17 | "Only views can have a title_format"); |
19 | } | 18 | } |
20 | struct sway_view *view = container->sway_view; | 19 | struct sway_view *view = container->view; |
21 | char *format = join_args(argv, argc); | 20 | char *format = join_args(argv, argc); |
22 | if (view->title_format) { | 21 | if (view->title_format) { |
23 | free(view->title_format); | 22 | free(view->title_format); |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index 62127c97..c6251dc8 100644 --- a/sway/commands/unmark.c +++ b/sway/commands/unmark.c | |||
@@ -9,9 +9,9 @@ | |||
9 | #include "stringop.h" | 9 | #include "stringop.h" |
10 | 10 | ||
11 | static void remove_all_marks_iterator(struct sway_container *con, void *data) { | 11 | static void remove_all_marks_iterator(struct sway_container *con, void *data) { |
12 | if (con->type == C_VIEW) { | 12 | if (con->view) { |
13 | view_clear_marks(con->sway_view); | 13 | view_clear_marks(con->view); |
14 | view_update_marks_textures(con->sway_view); | 14 | view_update_marks_textures(con->view); |
15 | } | 15 | } |
16 | } | 16 | } |
17 | 17 | ||
@@ -24,13 +24,12 @@ struct cmd_results *cmd_unmark(int argc, char **argv) { | |||
24 | // Determine the view | 24 | // Determine the view |
25 | struct sway_view *view = NULL; | 25 | struct sway_view *view = NULL; |
26 | if (config->handler_context.using_criteria) { | 26 | if (config->handler_context.using_criteria) { |
27 | struct sway_container *container = | 27 | struct sway_container *container = config->handler_context.container; |
28 | config->handler_context.current_container; | 28 | if (!container->view) { |
29 | if (container->type != C_VIEW) { | ||
30 | return cmd_results_new(CMD_INVALID, "unmark", | 29 | return cmd_results_new(CMD_INVALID, "unmark", |
31 | "Only views can have marks"); | 30 | "Only views can have marks"); |
32 | } | 31 | } |
33 | view = container->sway_view; | 32 | view = container->view; |
34 | } | 33 | } |
35 | 34 | ||
36 | // Determine the mark | 35 | // Determine the mark |
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index bccb33fe..53c37d4d 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c | |||
@@ -11,13 +11,12 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { | |||
11 | if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { | 11 | if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { |
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct sway_container *container = | 14 | struct sway_container *container = config->handler_context.container; |
15 | config->handler_context.current_container; | 15 | if (!container->view) { |
16 | if (container->type != C_VIEW) { | ||
17 | return cmd_results_new(CMD_INVALID, "urgent", | 16 | return cmd_results_new(CMD_INVALID, "urgent", |
18 | "Only views can be urgent"); | 17 | "Only views can be urgent"); |
19 | } | 18 | } |
20 | struct sway_view *view = container->sway_view; | 19 | struct sway_view *view = container->view; |
21 | 20 | ||
22 | if (strcmp(argv[0], "allow") == 0) { | 21 | if (strcmp(argv[0], "allow") == 0) { |
23 | view->allow_request_urgent = true; | 22 | view->allow_request_urgent = true; |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index ceb4cd6e..f026a39d 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -58,7 +58,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | 60 | ||
61 | struct sway_container *ws = NULL; | 61 | struct sway_workspace *ws = NULL; |
62 | if (strcasecmp(argv[0], "number") == 0) { | 62 | if (strcasecmp(argv[0], "number") == 0) { |
63 | if (argc < 2) { | 63 | if (argc < 2) { |
64 | return cmd_results_new(CMD_INVALID, "workspace", | 64 | return cmd_results_new(CMD_INVALID, "workspace", |