aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/move.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/move.c')
-rw-r--r--sway/commands/move.c873
1 files changed, 407 insertions, 466 deletions
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 4426f24e..1b2e830c 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -40,7 +40,7 @@ enum wlr_direction opposite_direction(enum wlr_direction d) {
40 } 40 }
41} 41}
42 42
43static struct sway_container *output_in_direction(const char *direction_string, 43static struct sway_output *output_in_direction(const char *direction_string,
44 struct wlr_output *reference, int ref_lx, int ref_ly) { 44 struct wlr_output *reference, int ref_lx, int ref_ly) {
45 struct { 45 struct {
46 char *name; 46 char *name;
@@ -63,447 +63,367 @@ static struct sway_container *output_in_direction(const char *direction_string,
63 63
64 if (direction) { 64 if (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, ref_lx, ref_ly);
67 direction, reference, ref_lx, ref_ly);
68 67
69 if (!target) { 68 if (!target) {
70 target = wlr_output_layout_farthest_output( 69 target = wlr_output_layout_farthest_output(
71 root_container.sway_root->output_layout, 70 root->output_layout, opposite_direction(direction),
72 opposite_direction(direction), reference, ref_lx, ref_ly); 71 reference, ref_lx, ref_ly);
73 } 72 }
74 73
75 if (target) { 74 if (target) {
76 struct sway_output *sway_output = target->data; 75 return target->data;
77 return sway_output->swayc;
78 } 76 }
79 } 77 }
80 78
81 return output_by_name(direction_string); 79 return output_by_name(direction_string);
82} 80}
83 81
84static void container_move_to(struct sway_container *container, 82static bool is_parallel(enum sway_container_layout layout,
85 struct sway_container *destination) { 83 enum movement_direction dir) {
86 if (!sway_assert(container->type == C_CONTAINER || 84 switch (layout) {
87 container->type == C_VIEW, "Expected a container or view")) { 85 case L_TABBED:
88 return; 86 case L_HORIZ:
87 return dir == MOVE_LEFT || dir == MOVE_RIGHT;
88 case L_STACKED:
89 case L_VERT:
90 return dir == MOVE_UP || dir == MOVE_DOWN;
91 default:
92 return false;
89 } 93 }
90 if (container == destination 94}
91 || container_has_ancestor(container, destination)) { 95
96/**
97 * Ensures all seats focus the fullscreen container if needed.
98 */
99static void workspace_focus_fullscreen(struct sway_workspace *workspace) {
100 if (!workspace->fullscreen) {
92 return; 101 return;
93 } 102 }
94 struct sway_container *old_parent = NULL; 103 struct sway_seat *seat;
95 struct sway_container *new_parent = NULL; 104 struct sway_workspace *focus_ws;
96 if (container_is_floating(container)) { 105 wl_list_for_each(seat, &input_manager->seats, link) {
97 // Resolve destination into a workspace 106 focus_ws = seat_get_focused_workspace(seat);
98 struct sway_container *new_ws = NULL; 107 if (focus_ws == workspace) {
99 if (destination->type == C_OUTPUT) { 108 struct sway_node *new_focus =
100 new_ws = output_get_active_workspace(destination->sway_output); 109 seat_get_focus_inactive(seat, &workspace->fullscreen->node);
101 } else if (destination->type == C_WORKSPACE) { 110 seat_set_focus(seat, new_focus);
102 new_ws = destination;
103 } else {
104 new_ws = container_parent(destination, C_WORKSPACE);
105 } 111 }
106 if (!new_ws) { 112 }
107 // This can happen if the user has run "move container to mark foo", 113}
108 // where mark foo is on a hidden scratchpad container. 114
109 return; 115static void container_move_to_container_from_direction(
116 struct sway_container *container, struct sway_container *destination,
117 enum movement_direction move_dir) {
118 if (destination->view) {
119 if (destination->parent == container->parent) {
120 wlr_log(WLR_DEBUG, "Swapping siblings");
121 list_t *siblings = container_get_siblings(container);
122 int container_index = list_find(siblings, container);
123 int destination_index = list_find(siblings, destination);
124 list_swap(siblings, container_index, destination_index);
125 } else {
126 wlr_log(WLR_DEBUG, "Promoting to sibling of cousin");
127 int offset = move_dir == MOVE_LEFT || move_dir == MOVE_UP;
128 int index = container_sibling_index(destination) + offset;
129 if (destination->parent) {
130 container_insert_child(destination->parent, container, index);
131 } else {
132 workspace_insert_tiling(destination->workspace,
133 container, index);
134 }
135 container->width = container->height = 0;
110 } 136 }
111 struct sway_container *old_output = 137 return;
112 container_parent(container, C_OUTPUT); 138 }
113 old_parent = container_remove_child(container); 139
114 workspace_add_floating(new_ws, container); 140 if (is_parallel(destination->layout, move_dir)) {
115 container_handle_fullscreen_reparent(container, old_parent); 141 wlr_log(WLR_DEBUG, "Reparenting container (parallel)");
142 int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ?
143 0 : destination->children->length;
144 container_insert_child(destination, container, index);
145 container->width = container->height = 0;
146 return;
147 }
148
149 wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)");
150 struct sway_node *focus_inactive = seat_get_active_child(
151 config->handler_context.seat, &destination->node);
152 if (!focus_inactive || focus_inactive == &destination->node) {
153 // The container has no children
154 container_add_child(destination, container);
155 return;
156 }
157
158 // Try again but with the child
159 container_move_to_container_from_direction(container,
160 focus_inactive->sway_container, move_dir);
161}
162
163static void container_move_to_workspace_from_direction(
164 struct sway_container *container, struct sway_workspace *workspace,
165 enum movement_direction move_dir) {
166 if (is_parallel(workspace->layout, move_dir)) {
167 wlr_log(WLR_DEBUG, "Reparenting container (parallel)");
168 int index = move_dir == MOVE_RIGHT || move_dir == MOVE_DOWN ?
169 0 : workspace->tiling->length;
170 workspace_insert_tiling(workspace, container, index);
171 return;
172 }
173
174 wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)");
175 struct sway_container *focus_inactive = seat_get_focus_inactive_tiling(
176 config->handler_context.seat, workspace);
177 if (!focus_inactive) {
178 // The workspace has no tiling children
179 workspace_add_tiling(workspace, container);
180 return;
181 }
182 while (focus_inactive->parent) {
183 focus_inactive = focus_inactive->parent;
184 }
185 container_move_to_container_from_direction(container, focus_inactive,
186 move_dir);
187}
188
189static void container_move_to_workspace(struct sway_container *container,
190 struct sway_workspace *workspace) {
191 if (container->workspace == workspace) {
192 return;
193 }
194 struct sway_workspace *old_workspace = container->workspace;
195 if (container_is_floating(container)) {
196 struct sway_output *old_output = container->workspace->output;
197 container_detach(container);
198 workspace_add_floating(workspace, container);
199 container_handle_fullscreen_reparent(container);
116 // If changing output, center it within the workspace 200 // If changing output, center it within the workspace
117 if (old_output != new_ws->parent && !container->is_fullscreen) { 201 if (old_output != workspace->output && !container->is_fullscreen) {
118 container_floating_move_to_center(container); 202 container_floating_move_to_center(container);
119 } 203 }
120 } else { 204 } else {
121 old_parent = container_remove_child(container); 205 container_detach(container);
122 container->width = container->height = 0; 206 container->width = container->height = 0;
123 container->saved_width = container->saved_height = 0; 207 container->saved_width = container->saved_height = 0;
124 208 workspace_add_tiling(workspace, container);
125 if (destination->type == C_VIEW) { 209 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 } 210 }
132 211 if (container->view) {
133 if (container->type == C_VIEW) {
134 ipc_event_window(container, "move"); 212 ipc_event_window(container, "move");
135 } 213 }
136 container_notify_subtree_changed(old_parent); 214 workspace_detect_urgent(old_workspace);
137 container_notify_subtree_changed(new_parent); 215 workspace_detect_urgent(workspace);
138 216 workspace_focus_fullscreen(workspace);
139 // If view was moved to a fullscreen workspace, refocus the fullscreen view 217}
140 struct sway_container *new_workspace = container; 218
141 if (new_workspace->type != C_WORKSPACE) { 219static void container_move_to_container(struct sway_container *container,
142 new_workspace = container_parent(new_workspace, C_WORKSPACE); 220 struct sway_container *destination) {
143 } 221 if (container == destination
144 if (new_workspace->sway_workspace->fullscreen) { 222 || container_has_ancestor(container, destination)
145 struct sway_seat *seat; 223 || container_has_ancestor(destination, container)) {
146 struct sway_container *focus, *focus_ws; 224 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 } 225 }
160 // Update workspace urgent state 226 if (container_is_floating(container)) {
161 struct sway_container *old_workspace = old_parent; 227 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 } 228 }
171} 229 struct sway_workspace *old_workspace = container->workspace;
172 230
173static bool is_parallel(enum sway_container_layout layout, 231 container_detach(container);
174 enum movement_direction dir) { 232 container->width = container->height = 0;
175 switch (layout) { 233 container->saved_width = container->saved_height = 0;
176 case L_TABBED: 234
177 case L_HORIZ: 235 if (destination->view) {
178 return dir == MOVE_LEFT || dir == MOVE_RIGHT; 236 container_add_sibling(destination, container, 1);
179 case L_STACKED: 237 } else {
180 case L_VERT: 238 container_add_child(destination, container);
181 return dir == MOVE_UP || dir == MOVE_DOWN;
182 default:
183 return false;
184 } 239 }
185}
186 240
187static enum movement_direction invert_movement(enum movement_direction dir) { 241 if (container->view) {
188 switch (dir) { 242 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 } 243 }
201}
202 244
203static int move_offs(enum movement_direction move_dir) { 245 workspace_focus_fullscreen(destination->workspace);
204 return move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1;
205}
206 246
207/* Gets the index of the most extreme member based on the movement offset */ 247 // Update workspace urgent state
208static int container_limit(struct sway_container *container, 248 workspace_detect_urgent(destination->workspace);
209 enum movement_direction move_dir) { 249 if (old_workspace != destination->workspace) {
210 return move_offs(move_dir) < 0 ? 0 : container->children->length; 250 workspace_detect_urgent(old_workspace);
251 }
211} 252}
212 253
213/* Takes one child, sets it aside, wraps the rest of the children in a new 254/* 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. 255 * container, switches the layout of the workspace, and drops the child back in.
215 * In other words, rejigger it. */ 256 * In other words, rejigger it. */
216static void workspace_rejigger(struct sway_container *ws, 257static void workspace_rejigger(struct sway_workspace *ws,
217 struct sway_container *child, enum movement_direction move_dir) { 258 struct sway_container *child, enum movement_direction move_dir) {
218 struct sway_container *original_parent = child->parent; 259 if (!sway_assert(child->parent == NULL, "Expected a root child")) {
219 struct sway_container *new_parent = 260 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 } 261 }
262 container_detach(child);
263 workspace_wrap_children(ws);
227 264
228 int index = move_offs(move_dir); 265 int index = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? 0 : 1;
229 container_insert_child(ws, child, index < 0 ? 0 : 1); 266 workspace_insert_tiling(ws, child, index);
230 ws->layout = 267 ws->layout =
231 move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; 268 move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
232 269 workspace_update_representation(ws);
233 container_flatten(ws);
234 container_reap_empty(original_parent);
235 container_create_notify(new_parent);
236} 270}
237 271
238static void move_out_of_tabs_stacks(struct sway_container *container, 272static void move_out_of_tabs_stacks(struct sway_container *container,
239 struct sway_container *current, enum movement_direction move_dir, 273 struct sway_container *current, enum movement_direction move_dir,
240 int offs) { 274 int offs) {
241 if (container->parent == current->parent 275 enum sway_container_layout layout = move_dir ==
242 && current->parent->children->length == 1) { 276 MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT;
243 wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); 277 list_t *siblings = container_get_siblings(container);
244 current->parent->layout = move_dir == 278 if (container == current && siblings->length == 1) {
245 MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; 279 wlr_log(WLR_DEBUG, "Changing layout of parent");
280 if (container->parent) {
281 container->parent->layout = layout;
282 container_update_representation(container);
283 } else {
284 container->workspace->layout = layout;
285 workspace_update_representation(container->workspace);
286 }
246 return; 287 return;
247 } 288 }
248 289
249 wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); 290 wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split");
250 bool is_workspace = current->parent->type == C_WORKSPACE; 291 if (container->parent) {
251 struct sway_container *new_parent = container_split(current->parent, 292 struct sway_container *new_parent =
252 move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); 293 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); 294 container_insert_child(new_parent, container, offs < 0 ? 0 : 1);
257 container_reap_empty(new_parent->parent); 295 container_reap_empty(new_parent);
258 container_flatten(new_parent->parent); 296 container_flatten(new_parent);
297 } else {
298 // Changing a workspace
299 struct sway_workspace *workspace = container->workspace;
300 workspace_split(workspace, layout);
301 workspace_insert_tiling(workspace, container, offs < 0 ? 0 : 1);
259 } 302 }
260 container_create_notify(new_parent);
261 container_notify_subtree_changed(new_parent);
262} 303}
263 304
264static void container_move(struct sway_container *container, 305// Returns true if moved
265 enum movement_direction move_dir, int move_amt) { 306static bool container_move_in_direction(struct sway_container *container,
266 if (!sway_assert( 307 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 308 // If moving a fullscreen view, only consider outputs
279 if (container->is_fullscreen) { 309 if (container->is_fullscreen) {
280 current = container_parent(container, C_OUTPUT); 310 struct sway_output *new_output =
281 } else if (container_is_fullscreen_or_child(container) || 311 output_get_in_direction(container->workspace->output, move_dir);
282 container_is_floating_or_child(container)) { 312 if (!new_output) {
283 // If we've fullscreened a split container, only allow the child to move 313 return false;
284 // around within the fullscreen parent. 314 }
285 // Same with floating a split container. 315 struct sway_workspace *ws = output_get_active_workspace(new_output);
286 struct sway_container *ws = container_parent(container, C_WORKSPACE); 316 container_move_to_workspace(container, ws);
287 top = ws->sway_workspace->fullscreen; 317 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 } 318 }
295 319
296 while (!sibling) { 320 // If container is in a split container by itself, move out of the split
297 if (current == top) { 321 if (container->parent) {
298 return; 322 struct sway_container *new_parent =
323 container_flatten(container->parent);
324 if (new_parent != container->parent) {
325 return true;
299 } 326 }
327 }
300 328
301 parent = current->parent; 329 // Look for a suitable *container* sibling or parent.
302 wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, 330 // The below loop stops once we hit the workspace because current->parent
303 container_type_to_str(current->type), current->name); 331 // is NULL for the topmost containers in a workspace.
304 332 struct sway_container *current = container;
305 int index = container_sibling_index(current); 333 int offs = move_dir == MOVE_LEFT || move_dir == MOVE_UP ? -1 : 1;
306 334
307 switch (current->type) { 335 while (current) {
308 case C_OUTPUT: { 336 struct sway_container *parent = current->parent;
309 enum wlr_direction wlr_dir = 0; 337 list_t *siblings = container_get_siblings(current);
310 if (!sway_assert(sway_dir_to_wlr(move_dir, &wlr_dir), 338 enum sway_container_layout layout = container_parent_layout(current);
311 "got invalid direction: %d", move_dir)) { 339 int index = list_find(siblings, current);
312 return; 340 int desired = index + offs;
313 } 341
314 double ref_lx = current->x + current->width / 2; 342 if (is_parallel(layout, move_dir)) {
315 double ref_ly = current->y + current->height / 2; 343 if (desired == -1 || desired == siblings->length) {
316 struct wlr_output *next = wlr_output_layout_adjacent_output( 344 if (current->parent == container->parent) {
317 root_container.sway_root->output_layout, wlr_dir, 345 if (!(parent && parent->is_fullscreen) &&
318 current->sway_output->wlr_output, ref_lx, ref_ly); 346 (layout == L_TABBED || layout == L_STACKED)) {
319 if (!next) { 347 move_out_of_tabs_stacks(container, current,
320 wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); 348 move_dir, offs);
321 return; 349 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 { 350 } else {
372 wlr_log(WLR_DEBUG, "Hit limit, " 351 current = current->parent;
373 "promoting descendant to sibling"); 352 continue;
374 // Special case 353 }
354 } else {
355 // Special case
356 if (current->parent) {
375 container_insert_child(current->parent, container, 357 container_insert_child(current->parent, container,
376 index + (offs < 0 ? 0 : 1)); 358 index + (offs < 0 ? 0 : 1));
377 container->width = container->height = 0; 359 } else {
378 return; 360 workspace_insert_tiling(current->workspace, container,
361 index + (offs < 0 ? 0 : 1));
379 } 362 }
380 } else { 363 return true;
381 sibling = parent->children->items[index + offs];
382 wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id);
383 } 364 }
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 { 365 } else {
389 wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); 366 // Container can move within its siblings
390 current = current->parent; 367 container_move_to_container_from_direction(container,
368 siblings->items[desired], move_dir);
369 return true;
391 } 370 }
392 break; 371 } else if (!(parent && parent->is_fullscreen) &&
393 default: 372 (layout == L_TABBED || layout == L_STACKED)) {
394 sway_assert(0, "Not expecting to see container of type %s here", 373 move_out_of_tabs_stacks(container, current, move_dir, offs);
395 container_type_to_str(current->type)); 374 return true;
396 return;
397 } 375 }
398 }
399 376
400 // Part two: move stuff around 377 current = current->parent;
401 int index = container_sibling_index(container);
402 struct sway_container *old_parent = container->parent;
403 378
404 while (sibling) { 379 // Don't allow containers to move out of their
405 switch (sibling->type) { 380 // fullscreen or floating parent
406 case C_VIEW: 381 if (current &&
407 if (sibling->parent == container->parent) { 382 (current->is_fullscreen || container_is_floating(current))) {
408 wlr_log(WLR_DEBUG, "Swapping siblings"); 383 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 } 384 }
460 } 385 }
461 386
462 container_notify_subtree_changed(old_parent); 387 // Maybe rejigger the workspace
463 container_notify_subtree_changed(container->parent); 388 struct sway_workspace *ws = container->workspace;
464 389 if (!is_parallel(ws->layout, move_dir)) {
465 if (container->type == C_VIEW) { 390 if (ws->tiling->length >= 2) {
466 ipc_event_window(container, "move"); 391 workspace_rejigger(ws, container, move_dir);
467 } 392 return true;
468 393 }
469 if (old_parent) { 394 } else if (ws->layout == L_TABBED || ws->layout == L_STACKED) {
470 seat_set_focus(config->handler_context.seat, old_parent); 395 workspace_rejigger(ws, container, move_dir);
471 seat_set_focus(config->handler_context.seat, container); 396 return true;
472 } 397 }
473 398
474 struct sway_container *last_ws = old_parent; 399 // Try adjacent output
475 struct sway_container *next_ws = container->parent; 400 struct sway_output *output =
476 if (last_ws && last_ws->type != C_WORKSPACE) { 401 output_get_in_direction(container->workspace->output, move_dir);
477 last_ws = container_parent(last_ws, C_WORKSPACE); 402 if (output) {
478 } 403 struct sway_workspace *ws = output_get_active_workspace(output);
479 if (next_ws && next_ws->type != C_WORKSPACE) { 404 container_move_to_workspace_from_direction(container, ws, move_dir);
480 next_ws = container_parent(next_ws, C_WORKSPACE); 405 return true;
481 } 406 }
482 if (last_ws && next_ws && last_ws != next_ws) { 407 wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go");
483 ipc_event_workspace(last_ws, next_ws, "focus"); 408 return false;
484 workspace_detect_urgent(last_ws);
485 workspace_detect_urgent(next_ws);
486 }
487 container_end_mouse_operation(container);
488} 409}
489 410
490static struct cmd_results *cmd_move_container(struct sway_container *current, 411static struct cmd_results *cmd_move_container(int argc, char **argv) {
491 int argc, char **argv) {
492 struct cmd_results *error = NULL; 412 struct cmd_results *error = NULL;
493 if ((error = checkarg(argc, "move container/window", 413 if ((error = checkarg(argc, "move container/window",
494 EXPECTED_AT_LEAST, 3))) { 414 EXPECTED_AT_LEAST, 3))) {
495 return error; 415 return error;
496 } 416 }
497 417
498 if (current->type == C_WORKSPACE) { 418 struct sway_node *node = config->handler_context.node;
499 if (current->children->length == 0) { 419 struct sway_workspace *workspace = config->handler_context.workspace;
420 struct sway_container *container = config->handler_context.container;
421 if (node->type == N_WORKSPACE) {
422 if (workspace->tiling->length == 0) {
500 return cmd_results_new(CMD_FAILURE, "move", 423 return cmd_results_new(CMD_FAILURE, "move",
501 "Can't move an empty workspace"); 424 "Can't move an empty workspace");
502 } 425 }
503 current = workspace_wrap_children(current); 426 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 } 427 }
508 428
509 bool no_auto_back_and_forth = false; 429 bool no_auto_back_and_forth = false;
@@ -530,15 +450,15 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
530 } 450 }
531 451
532 struct sway_seat *seat = config->handler_context.seat; 452 struct sway_seat *seat = config->handler_context.seat;
533 struct sway_container *old_parent = current->parent; 453 struct sway_container *old_parent = container->parent;
534 struct sway_container *old_ws = container_parent(current, C_WORKSPACE); 454 struct sway_workspace *old_ws = container->workspace;
535 struct sway_container *old_output = container_parent(current, C_OUTPUT); 455 struct sway_output *old_output = old_ws->output;
536 struct sway_container *destination = NULL; 456 struct sway_node *destination = NULL;
537 457
538 // determine destination 458 // determine destination
539 if (strcasecmp(argv[1], "workspace") == 0) { 459 if (strcasecmp(argv[1], "workspace") == 0) {
540 // move container to workspace x 460 // move container to workspace x
541 struct sway_container *ws = NULL; 461 struct sway_workspace *ws = NULL;
542 char *ws_name = NULL; 462 char *ws_name = NULL;
543 if (strcasecmp(argv[2], "next") == 0 || 463 if (strcasecmp(argv[2], "next") == 0 ||
544 strcasecmp(argv[2], "prev") == 0 || 464 strcasecmp(argv[2], "prev") == 0 ||
@@ -588,8 +508,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
588 // We have to create the workspace, but if the container is 508 // We have to create the workspace, but if the container is
589 // sticky and the workspace is going to be created on the same 509 // sticky and the workspace is going to be created on the same
590 // output, we'll bail out first. 510 // output, we'll bail out first.
591 if (current->is_sticky) { 511 if (container->is_sticky) {
592 struct sway_container *new_output = 512 struct sway_output *new_output =
593 workspace_get_initial_output(ws_name); 513 workspace_get_initial_output(ws_name);
594 if (old_output == new_output) { 514 if (old_output == new_output) {
595 free(ws_name); 515 free(ws_name);
@@ -601,105 +521,113 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
601 ws = workspace_create(NULL, ws_name); 521 ws = workspace_create(NULL, ws_name);
602 } 522 }
603 free(ws_name); 523 free(ws_name);
604 destination = seat_get_focus_inactive(seat, ws); 524 destination = seat_get_focus_inactive(seat, &ws->node);
605 } else if (strcasecmp(argv[1], "output") == 0) { 525 } else if (strcasecmp(argv[1], "output") == 0) {
606 struct sway_container *dest_output = output_in_direction(argv[2], 526 struct sway_output *new_output = output_in_direction(argv[2],
607 old_output->sway_output->wlr_output, current->x, current->y); 527 old_output->wlr_output, container->x, container->y);
608 if (!dest_output) { 528 if (!new_output) {
609 return cmd_results_new(CMD_FAILURE, "move workspace", 529 return cmd_results_new(CMD_FAILURE, "move workspace",
610 "Can't find output with name/direction '%s'", argv[2]); 530 "Can't find output with name/direction '%s'", argv[2]);
611 } 531 }
612 destination = seat_get_focus_inactive(seat, dest_output); 532 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) { 533 } else if (strcasecmp(argv[1], "mark") == 0) {
618 struct sway_view *dest_view = view_find_mark(argv[2]); 534 struct sway_view *dest_view = view_find_mark(argv[2]);
619 if (dest_view == NULL) { 535 if (dest_view == NULL) {
620 return cmd_results_new(CMD_FAILURE, "move", 536 return cmd_results_new(CMD_FAILURE, "move",
621 "Mark '%s' not found", argv[2]); 537 "Mark '%s' not found", argv[2]);
622 } 538 }
623 destination = dest_view->swayc; 539 destination = &dest_view->container->node;
624 } else { 540 } else {
625 return cmd_results_new(CMD_INVALID, "move", expected_syntax); 541 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
626 } 542 }
627 543
628 struct sway_container *new_output = destination->type == C_OUTPUT ? 544 if (container->is_sticky &&
629 destination : container_parent(destination, C_OUTPUT); 545 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 " 546 return cmd_results_new(CMD_FAILURE, "move", "Can't move sticky "
632 "container to another workspace on the same output"); 547 "container to another workspace on the same output");
633 } 548 }
634 549
635 struct sway_container *new_output_last_ws = old_output == new_output ? 550 struct sway_output *new_output = node_get_output(destination);
636 NULL : seat_get_active_child(seat, new_output); 551 struct sway_workspace *new_output_last_ws = old_output == new_output ?
637 struct sway_container *new_workspace = destination->type == C_WORKSPACE ? 552 NULL : output_get_active_workspace(new_output);
638 destination : container_parent(destination, C_WORKSPACE);
639 553
640 // move container, arrange windows and return focus 554 // move container, arrange windows and return focus
641 container_move_to(current, destination); 555 switch (destination->type) {
556 case N_WORKSPACE:
557 container_move_to_workspace(container, destination->sway_workspace);
558 break;
559 case N_OUTPUT: {
560 struct sway_output *output = destination->sway_output;
561 struct sway_workspace *ws = output_get_active_workspace(output);
562 container_move_to_workspace(container, ws);
563 }
564 break;
565 case N_CONTAINER:
566 container_move_to_container(container, destination->sway_container);
567 break;
568 case N_ROOT:
569 break;
570 }
571 struct sway_workspace *new_workspace =
572 output_get_active_workspace(new_output);
642 if (new_output_last_ws && new_output_last_ws != new_workspace) { 573 if (new_output_last_ws && new_output_last_ws != new_workspace) {
643 // change focus on destination output back to its last active workspace 574 // change focus on destination output back to its last active workspace
644 struct sway_container *new_output_last_focus = 575 struct sway_node *new_output_last_focus =
645 seat_get_focus_inactive(seat, new_output_last_ws); 576 seat_get_focus_inactive(seat, &new_output_last_ws->node);
646 seat_set_focus_warp(seat, new_output_last_focus, false, false); 577 seat_set_focus_warp(seat, new_output_last_focus, false, false);
647 } 578 }
648 struct sway_container *focus = seat_get_focus_inactive(seat, old_parent); 579
580 struct sway_node *focus = NULL;
581 if (old_parent) {
582 focus = seat_get_focus_inactive(seat, &old_parent->node);
583 } else {
584 focus = seat_get_focus_inactive(seat, &old_ws->node);
585 }
649 seat_set_focus_warp(seat, focus, true, false); 586 seat_set_focus_warp(seat, focus, true, false);
650 container_reap_empty(old_parent);
651 container_reap_empty(destination->parent);
652 587
653 // TODO: Ideally we would arrange the surviving parent after reaping, 588 if (old_parent) {
654 // but container_reap_empty does not return it, so we arrange the 589 container_reap_empty(old_parent);
655 // workspace instead. 590 } else {
656 arrange_windows(old_ws); 591 workspace_consider_destroy(old_ws);
657 arrange_windows(destination->parent); 592 }
593
594 arrange_workspace(old_ws);
595 arrange_node(node_get_parent(destination));
658 596
659 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 597 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
660} 598}
661 599
662static void workspace_move_to_output(struct sway_container *workspace, 600static void workspace_move_to_output(struct sway_workspace *workspace,
663 struct sway_container *output) { 601 struct sway_output *output) {
664 if (!sway_assert(workspace->type == C_WORKSPACE, "Expected a workspace")) { 602 if (workspace->output == output) {
665 return; 603 return;
666 } 604 }
667 if (!sway_assert(output->type == C_OUTPUT, "Expected an output")) { 605 struct sway_output *old_output = workspace->output;
668 return; 606 workspace_detach(workspace);
669 } 607 struct sway_workspace *new_output_old_ws =
670 if (workspace->parent == output) { 608 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 609
678 container_add_child(output, workspace); 610 output_add_workspace(output, workspace);
679 611
680 // If moving the last workspace from the old output, create a new workspace 612 // If moving the last workspace from the old output, create a new workspace
681 // on the old output 613 // on the old output
682 if (old_output->children->length == 0) { 614 struct sway_seat *seat = config->handler_context.seat;
683 char *ws_name = workspace_next_name(old_output->name); 615 if (old_output->workspaces->length == 0) {
684 struct sway_container *ws = workspace_create(old_output, ws_name); 616 char *ws_name = workspace_next_name(old_output->wlr_output->name);
617 struct sway_workspace *ws = workspace_create(old_output, ws_name);
685 free(ws_name); 618 free(ws_name);
686 seat_set_focus(seat, ws); 619 seat_set_focus(seat, &ws->node);
687 } 620 }
688 621
689 // Try to remove an empty workspace from the destination output. 622 workspace_consider_destroy(new_output_old_ws);
690 container_reap_empty(new_output_focus);
691 623
692 output_sort_workspaces(output); 624 output_sort_workspaces(output);
693 seat_set_focus(seat, output); 625 seat_set_focus(seat, &output->node);
694 workspace_output_raise_priority(workspace, old_output, output); 626 workspace_output_raise_priority(workspace, old_output, output);
695 ipc_event_workspace(NULL, workspace, "move"); 627 ipc_event_workspace(NULL, workspace, "move");
696
697 container_notify_subtree_changed(old_output);
698 container_notify_subtree_changed(output);
699} 628}
700 629
701static struct cmd_results *cmd_move_workspace(struct sway_container *current, 630static struct cmd_results *cmd_move_workspace(int argc, char **argv) {
702 int argc, char **argv) {
703 struct cmd_results *error = NULL; 631 struct cmd_results *error = NULL;
704 if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) { 632 if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) {
705 return error; 633 return error;
@@ -716,27 +644,25 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current,
716 return cmd_results_new(CMD_INVALID, "move", expected_syntax); 644 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
717 } 645 }
718 646
719 struct sway_container *source = container_parent(current, C_OUTPUT); 647 struct sway_workspace *workspace = config->handler_context.workspace;
720 int center_x = current->width / 2 + current->x, 648 struct sway_output *old_output = workspace->output;
721 center_y = current->height / 2 + current->y; 649 int center_x = workspace->width / 2 + workspace->x,
722 struct sway_container *destination = output_in_direction(argv[2], 650 center_y = workspace->height / 2 + workspace->y;
723 source->sway_output->wlr_output, center_x, center_y); 651 struct sway_output *new_output = output_in_direction(argv[2],
724 if (!destination) { 652 old_output->wlr_output, center_x, center_y);
653 if (!new_output) {
725 return cmd_results_new(CMD_FAILURE, "move workspace", 654 return cmd_results_new(CMD_FAILURE, "move workspace",
726 "Can't find output with name/direction '%s'", argv[2]); 655 "Can't find output with name/direction '%s'", argv[2]);
727 } 656 }
728 if (current->type != C_WORKSPACE) { 657 workspace_move_to_output(workspace, new_output);
729 current = container_parent(current, C_WORKSPACE);
730 }
731 workspace_move_to_output(current, destination);
732 658
733 arrange_windows(source); 659 arrange_output(old_output);
734 arrange_windows(destination); 660 arrange_output(new_output);
735 661
736 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 662 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
737} 663}
738 664
739static struct cmd_results *move_in_direction(struct sway_container *container, 665static struct cmd_results *cmd_move_in_direction(
740 enum movement_direction direction, int argc, char **argv) { 666 enum movement_direction direction, int argc, char **argv) {
741 int move_amt = 10; 667 int move_amt = 10;
742 if (argc > 1) { 668 if (argc > 1) {
@@ -748,7 +674,8 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
748 } 674 }
749 } 675 }
750 676
751 if (container->type == C_WORKSPACE) { 677 struct sway_container *container = config->handler_context.container;
678 if (!container) {
752 return cmd_results_new(CMD_FAILURE, "move", 679 return cmd_results_new(CMD_FAILURE, "move",
753 "Cannot move workspaces in a direction"); 680 "Cannot move workspaces in a direction");
754 } 681 }
@@ -780,20 +707,34 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
780 container_floating_move_to(container, lx, ly); 707 container_floating_move_to(container, lx, ly);
781 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 708 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
782 } 709 }
783 // For simplicity, we'll arrange the entire workspace. The reason for this 710 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 711
792 arrange_windows(old_ws); 712 if (!container_move_in_direction(container, direction)) {
713 // Container didn't move
714 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
715 }
716
717 struct sway_workspace *new_ws = container->workspace;
718
719 arrange_workspace(old_ws);
793 if (new_ws != old_ws) { 720 if (new_ws != old_ws) {
794 arrange_windows(new_ws); 721 arrange_workspace(new_ws);
722 }
723
724 if (container->view) {
725 ipc_event_window(container, "move");
795 } 726 }
796 727
728 seat_set_focus(config->handler_context.seat, &new_ws->node);
729 seat_set_focus(config->handler_context.seat, &container->node);
730
731 if (old_ws != new_ws) {
732 ipc_event_workspace(old_ws, new_ws, "focus");
733 workspace_detect_urgent(old_ws);
734 workspace_detect_urgent(new_ws);
735 }
736 container_end_mouse_operation(container);
737
797 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 738 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
798} 739}
799 740
@@ -802,9 +743,9 @@ static const char *expected_position_syntax =
802 "'move [absolute] position center' or " 743 "'move [absolute] position center' or "
803 "'move position cursor|mouse|pointer'"; 744 "'move position cursor|mouse|pointer'";
804 745
805static struct cmd_results *move_to_position(struct sway_container *container, 746static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
806 int argc, char **argv) { 747 struct sway_container *container = config->handler_context.container;
807 if (!container_is_floating(container)) { 748 if (!container || !container_is_floating(container)) {
808 return cmd_results_new(CMD_FAILURE, "move", 749 return cmd_results_new(CMD_FAILURE, "move",
809 "Only floating containers " 750 "Only floating containers "
810 "can be moved to an absolute position"); 751 "can be moved to an absolute position");
@@ -842,10 +783,10 @@ static struct cmd_results *move_to_position(struct sway_container *container,
842 } else if (strcmp(argv[0], "center") == 0) { 783 } else if (strcmp(argv[0], "center") == 0) {
843 double lx, ly; 784 double lx, ly;
844 if (absolute) { 785 if (absolute) {
845 lx = root_container.x + (root_container.width - container->width) / 2; 786 lx = root->x + (root->width - container->width) / 2;
846 ly = root_container.y + (root_container.height - container->height) / 2; 787 ly = root->y + (root->height - container->height) / 2;
847 } else { 788 } else {
848 struct sway_container *ws = container_parent(container, C_WORKSPACE); 789 struct sway_workspace *ws = container->workspace;
849 lx = ws->x + (ws->width - container->width) / 2; 790 lx = ws->x + (ws->width - container->width) / 2;
850 ly = ws->y + (ws->height - container->height) / 2; 791 ly = ws->y + (ws->height - container->height) / 2;
851 } 792 }
@@ -881,30 +822,31 @@ static struct cmd_results *move_to_position(struct sway_container *container,
881 } 822 }
882 823
883 if (!absolute) { 824 if (!absolute) {
884 struct sway_container *ws = container_parent(container, C_WORKSPACE); 825 lx += container->workspace->x;
885 lx += ws->x; 826 ly += container->workspace->y;
886 ly += ws->y;
887 } 827 }
888 container_floating_move_to(container, lx, ly); 828 container_floating_move_to(container, lx, ly);
889 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 829 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
890} 830}
891 831
892static struct cmd_results *move_to_scratchpad(struct sway_container *con) { 832static struct cmd_results *cmd_move_to_scratchpad(void) {
893 if (con->type == C_WORKSPACE && con->children->length == 0) { 833 struct sway_node *node = config->handler_context.node;
834 struct sway_container *con = config->handler_context.container;
835 struct sway_workspace *ws = config->handler_context.workspace;
836 if (node->type == N_WORKSPACE && ws->tiling->length == 0) {
894 return cmd_results_new(CMD_INVALID, "move", 837 return cmd_results_new(CMD_INVALID, "move",
895 "Can't move an empty workspace to the scratchpad"); 838 "Can't move an empty workspace to the scratchpad");
896 } 839 }
897 if (con->type == C_WORKSPACE) { 840 if (node->type == N_WORKSPACE) {
898 // Wrap the workspace's children in a container 841 // Wrap the workspace's children in a container
899 struct sway_container *workspace = con; 842 con = workspace_wrap_children(ws);
900 con = workspace_wrap_children(con); 843 ws->layout = L_HORIZ;
901 workspace->layout = L_HORIZ;
902 } 844 }
903 845
904 // If the container is in a floating split container, 846 // If the container is in a floating split container,
905 // operate on the split container instead of the child. 847 // operate on the split container instead of the child.
906 if (container_is_floating_or_child(con)) { 848 if (container_is_floating_or_child(con)) {
907 while (con->parent->type != C_WORKSPACE) { 849 while (con->parent) {
908 con = con->parent; 850 con = con->parent;
909 } 851 }
910 } 852 }
@@ -922,32 +864,31 @@ struct cmd_results *cmd_move(int argc, char **argv) {
922 if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { 864 if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) {
923 return error; 865 return error;
924 } 866 }
925 struct sway_container *current = config->handler_context.current_container;
926 867
927 if (strcasecmp(argv[0], "left") == 0) { 868 if (strcasecmp(argv[0], "left") == 0) {
928 return move_in_direction(current, MOVE_LEFT, argc, argv); 869 return cmd_move_in_direction(MOVE_LEFT, argc, argv);
929 } else if (strcasecmp(argv[0], "right") == 0) { 870 } else if (strcasecmp(argv[0], "right") == 0) {
930 return move_in_direction(current, MOVE_RIGHT, argc, argv); 871 return cmd_move_in_direction(MOVE_RIGHT, argc, argv);
931 } else if (strcasecmp(argv[0], "up") == 0) { 872 } else if (strcasecmp(argv[0], "up") == 0) {
932 return move_in_direction(current, MOVE_UP, argc, argv); 873 return cmd_move_in_direction(MOVE_UP, argc, argv);
933 } else if (strcasecmp(argv[0], "down") == 0) { 874 } else if (strcasecmp(argv[0], "down") == 0) {
934 return move_in_direction(current, MOVE_DOWN, argc, argv); 875 return cmd_move_in_direction(MOVE_DOWN, argc, argv);
935 } else if ((strcasecmp(argv[0], "container") == 0 876 } else if ((strcasecmp(argv[0], "container") == 0
936 || strcasecmp(argv[0], "window") == 0) || 877 || strcasecmp(argv[0], "window") == 0) ||
937 (strcasecmp(argv[0], "--no-auto-back-and-forth") && 878 (strcasecmp(argv[0], "--no-auto-back-and-forth") && argc >= 2
938 (strcasecmp(argv[0], "container") == 0 879 && (strcasecmp(argv[1], "container") == 0
939 || strcasecmp(argv[0], "window") == 0))) { 880 || strcasecmp(argv[1], "window") == 0))) {
940 return cmd_move_container(current, argc, argv); 881 return cmd_move_container(argc, argv);
941 } else if (strcasecmp(argv[0], "workspace") == 0) { 882 } else if (strcasecmp(argv[0], "workspace") == 0) {
942 return cmd_move_workspace(current, argc, argv); 883 return cmd_move_workspace(argc, argv);
943 } else if (strcasecmp(argv[0], "scratchpad") == 0 884 } else if (strcasecmp(argv[0], "scratchpad") == 0
944 || (strcasecmp(argv[0], "to") == 0 && argc == 2 885 || (strcasecmp(argv[0], "to") == 0 && argc == 2
945 && strcasecmp(argv[1], "scratchpad") == 0)) { 886 && strcasecmp(argv[1], "scratchpad") == 0)) {
946 return move_to_scratchpad(current); 887 return cmd_move_to_scratchpad();
947 } else if (strcasecmp(argv[0], "position") == 0) { 888 } else if (strcasecmp(argv[0], "position") == 0) {
948 return move_to_position(current, argc, argv); 889 return cmd_move_to_position(argc, argv);
949 } else if (strcasecmp(argv[0], "absolute") == 0) { 890 } else if (strcasecmp(argv[0], "absolute") == 0) {
950 return move_to_position(current, argc, argv); 891 return cmd_move_to_position(argc, argv);
951 } else { 892 } else {
952 return cmd_results_new(CMD_INVALID, "move", expected_syntax); 893 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
953 } 894 }