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.c262
1 files changed, 165 insertions, 97 deletions
diff --git a/sway/commands/move.c b/sway/commands/move.c
index 841da4c4..af3dc538 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -1,4 +1,5 @@
1#define _XOPEN_SOURCE 500 1#define _XOPEN_SOURCE 500
2#include <stdbool.h>
2#include <string.h> 3#include <string.h>
3#include <strings.h> 4#include <strings.h>
4#include <wlr/types/wlr_cursor.h> 5#include <wlr/types/wlr_cursor.h>
@@ -16,11 +17,11 @@
16#include "stringop.h" 17#include "stringop.h"
17#include "list.h" 18#include "list.h"
18 19
19static const char* expected_syntax = 20static const char *expected_syntax =
20 "Expected 'move <left|right|up|down> <[px] px>' or " 21 "Expected 'move <left|right|up|down> <[px] px>' or "
21 "'move <container|window> to workspace <name>' or " 22 "'move [--no-auto-back-and-forth] <container|window> [to] workspace <name>' or "
22 "'move <container|window|workspace> to output <name|direction>' or " 23 "'move [--no-auto-back-and-forth] <container|window|workspace> [to] output <name|direction>' or "
23 "'move position mouse'"; 24 "'move <container|window> [to] mark <mark>'";
24 25
25static struct sway_container *output_in_direction(const char *direction, 26static struct sway_container *output_in_direction(const char *direction,
26 struct wlr_output *reference, int ref_lx, int ref_ly) { 27 struct wlr_output *reference, int ref_lx, int ref_ly) {
@@ -52,123 +53,168 @@ static struct cmd_results *cmd_move_container(struct sway_container *current,
52 int argc, char **argv) { 53 int argc, char **argv) {
53 struct cmd_results *error = NULL; 54 struct cmd_results *error = NULL;
54 if ((error = checkarg(argc, "move container/window", 55 if ((error = checkarg(argc, "move container/window",
55 EXPECTED_AT_LEAST, 4))) { 56 EXPECTED_AT_LEAST, 3))) {
56 return error; 57 return error;
57 } else if (strcasecmp(argv[1], "to") == 0 58 }
58 && strcasecmp(argv[2], "workspace") == 0) { 59
59 // move container to workspace x 60 if (current->type == C_WORKSPACE) {
60 if (current->type == C_WORKSPACE) { 61 if (current->children->length == 0) {
61 if (current->children->length == 0) {
62 return cmd_results_new(CMD_FAILURE, "move",
63 "Can't move an empty workspace");
64 }
65 current = container_wrap_children(current);
66 } else if (current->type != C_CONTAINER && current->type != C_VIEW) {
67 return cmd_results_new(CMD_FAILURE, "move", 62 return cmd_results_new(CMD_FAILURE, "move",
68 "Can only move containers and views."); 63 "Can't move an empty workspace");
69 } 64 }
70 struct sway_container *ws; 65 current = container_wrap_children(current);
71 char *ws_name = NULL; 66 } else if (current->type != C_CONTAINER && current->type != C_VIEW) {
72 if (argc == 5 && strcasecmp(argv[3], "number") == 0) { 67 return cmd_results_new(CMD_FAILURE, "move",
73 // move "container to workspace number x" 68 "Can only move containers and views.");
74 ws_name = strdup(argv[4]); 69 }
75 ws = workspace_by_number(ws_name); 70
76 } else { 71 bool no_auto_back_and_forth = false;
77 ws_name = join_args(argv + 3, argc - 3); 72 while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) {
78 ws = workspace_by_name(ws_name); 73 no_auto_back_and_forth = true;
74 if (--argc < 3) {
75 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
76 }
77 ++argv;
78 }
79 while (strcasecmp(argv[1], "--no-auto-back-and-forth") == 0) {
80 no_auto_back_and_forth = true;
81 if (--argc < 3) {
82 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
79 } 83 }
84 argv++;
85 }
86
87 while (strcasecmp(argv[1], "to") == 0) {
88 if (--argc < 3) {
89 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
90 }
91 argv++;
92 }
80 93
81 if (config->auto_back_and_forth && prev_workspace_name) { 94 struct sway_container *old_parent = current->parent;
82 // auto back and forth move 95 struct sway_container *old_ws = container_parent(current, C_WORKSPACE);
83 struct sway_container *curr_ws = container_parent(current, C_WORKSPACE); 96 struct sway_container *destination = NULL;
84 if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) { 97
85 // if target workspace is the current one 98 // determine destination
86 free(ws_name); 99 if (strcasecmp(argv[1], "workspace") == 0) {
87 ws_name = strdup(prev_workspace_name); 100 // move container to workspace x
101 struct sway_container *ws;
102 if (strcasecmp(argv[2], "next") == 0 ||
103 strcasecmp(argv[2], "prev") == 0 ||
104 strcasecmp(argv[2], "next_on_output") == 0 ||
105 strcasecmp(argv[2], "prev_on_output") == 0 ||
106 strcasecmp(argv[2], "back_and_forth") == 0 ||
107 strcasecmp(argv[2], "current") == 0) {
108 ws = workspace_by_name(argv[2]);
109 } else if (strcasecmp(argv[2], "back_and_forth") == 0) {
110 if (!(ws = workspace_by_name(argv[2]))) {
111 if (prev_workspace_name) {
112 ws = workspace_create(NULL, prev_workspace_name);
113 } else {
114 return cmd_results_new(CMD_FAILURE, "move",
115 "No workspace was previously active.");
116 }
117 }
118 } else {
119 char *ws_name = NULL;
120 if (strcasecmp(argv[2], "number") == 0) {
121 // move "container to workspace number x"
122 if (argc < 4) {
123 return cmd_results_new(CMD_INVALID, "move",
124 expected_syntax);
125 }
126 ws_name = strdup(argv[3]);
127 ws = workspace_by_number(ws_name);
128 } else {
129 ws_name = join_args(argv + 2, argc - 2);
88 ws = workspace_by_name(ws_name); 130 ws = workspace_by_name(ws_name);
89 } 131 }
90 }
91 132
92 if (!ws) { 133 if (!no_auto_back_and_forth && config->auto_back_and_forth &&
93 ws = workspace_create(NULL, ws_name); 134 prev_workspace_name) {
94 } 135 // auto back and forth move
95 free(ws_name); 136 if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) {
96 struct sway_container *old_parent = current->parent; 137 // if target workspace is the current one
97 struct sway_container *old_ws = container_parent(current, C_WORKSPACE); 138 free(ws_name);
98 struct sway_container *destination = seat_get_focus_inactive( 139 ws_name = strdup(prev_workspace_name);
99 config->handler_context.seat, ws); 140 ws = workspace_by_name(ws_name);
100 container_move_to(current, destination); 141 }
101 struct sway_container *focus = seat_get_focus_inactive( 142 }
102 config->handler_context.seat, old_parent);
103 seat_set_focus_warp(config->handler_context.seat, focus, true, false);
104 container_reap_empty(old_parent);
105 container_reap_empty(destination->parent);
106
107 // TODO: Ideally we would arrange the surviving parent after reaping,
108 // but container_reap_empty does not return it, so we arrange the
109 // workspace instead.
110 arrange_windows(old_ws);
111 arrange_windows(destination->parent);
112 143
113 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 144 if (!ws) {
114 } else if (strcasecmp(argv[1], "to") == 0 145 ws = workspace_create(NULL, ws_name);
115 && strcasecmp(argv[2], "output") == 0) { 146 }
116 if (current->type == C_WORKSPACE) { 147 free(ws_name);
117 // TODO: Wrap children in a container and move that
118 return cmd_results_new(CMD_FAILURE, "move", "Unimplemented");
119 } else if (current->type != C_CONTAINER
120 && current->type != C_VIEW) {
121 return cmd_results_new(CMD_FAILURE, "move",
122 "Can only move containers and views.");
123 } 148 }
149 destination = seat_get_focus_inactive(config->handler_context.seat, ws);
150 } else if (strcasecmp(argv[1], "output") == 0) {
124 struct sway_container *source = container_parent(current, C_OUTPUT); 151 struct sway_container *source = container_parent(current, C_OUTPUT);
125 struct sway_container *destination = output_in_direction(argv[3], 152 struct sway_container *dest_output = output_in_direction(argv[2],
126 source->sway_output->wlr_output, current->x, current->y); 153 source->sway_output->wlr_output, current->x, current->y);
127 if (!destination) { 154 if (!dest_output) {
128 return cmd_results_new(CMD_FAILURE, "move workspace", 155 return cmd_results_new(CMD_FAILURE, "move workspace",
129 "Can't find output with name/direction '%s'", argv[3]); 156 "Can't find output with name/direction '%s'", argv[2]);
130 } 157 }
131 struct sway_container *focus = seat_get_focus_inactive( 158 destination = seat_get_focus_inactive(
132 config->handler_context.seat, destination); 159 config->handler_context.seat, dest_output);
133 if (!focus) { 160 if (!destination) {
134 // We've never been to this output before 161 // We've never been to this output before
135 focus = destination->children->items[0]; 162 destination = dest_output->children->items[0];
136 } 163 }
137 struct sway_container *old_parent = current->parent; 164 } else if (strcasecmp(argv[1], "mark") == 0) {
138 struct sway_container *old_ws = container_parent(current, C_WORKSPACE); 165 struct sway_view *dest_view = view_find_mark(argv[2]);
139 container_move_to(current, focus); 166 if (dest_view == NULL) {
140 seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); 167 return cmd_results_new(CMD_FAILURE, "move",
141 container_reap_empty(old_parent); 168 "Mark '%s' not found", argv[2]);
142 container_reap_empty(focus->parent); 169 }
143 170 destination = dest_view->swayc;
144 // TODO: Ideally we would arrange the surviving parent after reaping, 171 } else {
145 // but container_reap_empty does not return it, so we arrange the 172 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
146 // workspace instead.
147 arrange_windows(old_ws);
148 arrange_windows(focus->parent);
149
150 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
151 } 173 }
152 return cmd_results_new(CMD_INVALID, "move", expected_syntax); 174
175 // move container, arrange windows and return focus
176 container_move_to(current, destination);
177 struct sway_container *focus =
178 seat_get_focus_inactive(config->handler_context.seat, old_parent);
179 seat_set_focus_warp(config->handler_context.seat, focus, true, false);
180 container_reap_empty(old_parent);
181 container_reap_empty(destination->parent);
182
183 // TODO: Ideally we would arrange the surviving parent after reaping,
184 // but container_reap_empty does not return it, so we arrange the
185 // workspace instead.
186 arrange_windows(old_ws);
187 arrange_windows(destination->parent);
188
189 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
153} 190}
154 191
155static struct cmd_results *cmd_move_workspace(struct sway_container *current, 192static struct cmd_results *cmd_move_workspace(struct sway_container *current,
156 int argc, char **argv) { 193 int argc, char **argv) {
157 struct cmd_results *error = NULL; 194 struct cmd_results *error = NULL;
158 if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { 195 if ((error = checkarg(argc, "move workspace", EXPECTED_AT_LEAST, 2))) {
159 return error; 196 return error;
160 } else if (strcasecmp(argv[1], "to") != 0 197 }
161 || strcasecmp(argv[2], "output") != 0) { 198
199 while (strcasecmp(argv[1], "to") == 0) {
200 if (--argc < 3) {
201 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
202 }
203 ++argv;
204 }
205
206 if (strcasecmp(argv[1], "output") != 0) {
162 return cmd_results_new(CMD_INVALID, "move", expected_syntax); 207 return cmd_results_new(CMD_INVALID, "move", expected_syntax);
163 } 208 }
209
164 struct sway_container *source = container_parent(current, C_OUTPUT); 210 struct sway_container *source = container_parent(current, C_OUTPUT);
165 int center_x = current->width / 2 + current->x, 211 int center_x = current->width / 2 + current->x,
166 center_y = current->height / 2 + current->y; 212 center_y = current->height / 2 + current->y;
167 struct sway_container *destination = output_in_direction(argv[3], 213 struct sway_container *destination = output_in_direction(argv[2],
168 source->sway_output->wlr_output, center_x, center_y); 214 source->sway_output->wlr_output, center_x, center_y);
169 if (!destination) { 215 if (!destination) {
170 return cmd_results_new(CMD_FAILURE, "move workspace", 216 return cmd_results_new(CMD_FAILURE, "move workspace",
171 "Can't find output with name/direction '%s'", argv[3]); 217 "Can't find output with name/direction '%s'", argv[2]);
172 } 218 }
173 if (current->type != C_WORKSPACE) { 219 if (current->type != C_WORKSPACE) {
174 current = container_parent(current, C_WORKSPACE); 220 current = container_parent(current, C_WORKSPACE);
@@ -242,9 +288,9 @@ static struct cmd_results *move_in_direction(struct sway_container *container,
242 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 288 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
243} 289}
244 290
245static const char* expected_position_syntax = 291static const char *expected_position_syntax =
246 "Expected 'move [absolute] position <x> <y>' or " 292 "Expected 'move [absolute] position <x> [px] <y> [px]' or "
247 "'move [absolute] position mouse'"; 293 "'move [absolute] position center|mouse'";
248 294
249static struct cmd_results *move_to_position(struct sway_container *container, 295static struct cmd_results *move_to_position(struct sway_container *container,
250 int argc, char **argv) { 296 int argc, char **argv) {
@@ -279,10 +325,18 @@ static struct cmd_results *move_to_position(struct sway_container *container,
279 double ly = seat->cursor->cursor->y - container->height / 2; 325 double ly = seat->cursor->cursor->y - container->height / 2;
280 container_floating_move_to(container, lx, ly); 326 container_floating_move_to(container, lx, ly);
281 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 327 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
328 } else if (strcmp(argv[0], "center") == 0) {
329 struct sway_container *ws = container_parent(container, C_WORKSPACE);
330 double lx = ws->x + (ws->width - container->width) / 2;
331 double ly = ws->y + (ws->height - container->height) / 2;
332 container_floating_move_to(container, lx, ly);
333 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
282 } 334 }
283 if (argc != 2) { 335
336 if (argc < 2) {
284 return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); 337 return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
285 } 338 }
339
286 double lx, ly; 340 double lx, ly;
287 char *inv; 341 char *inv;
288 lx = (double)strtol(argv[0], &inv, 10); 342 lx = (double)strtol(argv[0], &inv, 10);
@@ -290,11 +344,22 @@ static struct cmd_results *move_to_position(struct sway_container *container,
290 return cmd_results_new(CMD_FAILURE, "move", 344 return cmd_results_new(CMD_FAILURE, "move",
291 "Invalid position specified"); 345 "Invalid position specified");
292 } 346 }
347 if (strcmp(argv[1], "px") == 0) {
348 --argc;
349 ++argv;
350 }
351
352 if (argc > 3) {
353 return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax);
354 }
355
293 ly = (double)strtol(argv[1], &inv, 10); 356 ly = (double)strtol(argv[1], &inv, 10);
294 if (*inv != '\0' && strcasecmp(inv, "px") != 0) { 357 if ((*inv != '\0' && strcasecmp(inv, "px") != 0) ||
358 (argc == 3 && strcmp(argv[2], "px") != 0)) {
295 return cmd_results_new(CMD_FAILURE, "move", 359 return cmd_results_new(CMD_FAILURE, "move",
296 "Invalid position specified"); 360 "Invalid position specified");
297 } 361 }
362
298 container_floating_move_to(container, lx, ly); 363 container_floating_move_to(container, lx, ly);
299 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 364 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
300} 365}
@@ -342,8 +407,11 @@ struct cmd_results *cmd_move(int argc, char **argv) {
342 return move_in_direction(current, MOVE_UP, argc, argv); 407 return move_in_direction(current, MOVE_UP, argc, argv);
343 } else if (strcasecmp(argv[0], "down") == 0) { 408 } else if (strcasecmp(argv[0], "down") == 0) {
344 return move_in_direction(current, MOVE_DOWN, argc, argv); 409 return move_in_direction(current, MOVE_DOWN, argc, argv);
345 } else if (strcasecmp(argv[0], "container") == 0 410 } else if ((strcasecmp(argv[0], "container") == 0
346 || strcasecmp(argv[0], "window") == 0) { 411 || strcasecmp(argv[0], "window") == 0) ||
412 (strcasecmp(argv[0], "--no-auto-back-and-forth") &&
413 (strcasecmp(argv[0], "container") == 0
414 || strcasecmp(argv[0], "window") == 0))) {
347 return cmd_move_container(current, argc, argv); 415 return cmd_move_container(current, argc, argv);
348 } else if (strcasecmp(argv[0], "workspace") == 0) { 416 } else if (strcasecmp(argv[0], "workspace") == 0) {
349 return cmd_move_workspace(current, argc, argv); 417 return cmd_move_workspace(current, argc, argv);