diff options
author | Ian Fan <ianfan0@gmail.com> | 2018-07-31 11:38:34 +0100 |
---|---|---|
committer | Ian Fan <ianfan0@gmail.com> | 2018-08-06 14:17:58 +0100 |
commit | 69e1a421fc2ccecd93f79c9dd0537671138bb0a9 (patch) | |
tree | 4102876eb5f08897e03250929af5754410b0ca96 | |
parent | commands: complete layout implementation (diff) | |
download | sway-69e1a421fc2ccecd93f79c9dd0537671138bb0a9.tar.gz sway-69e1a421fc2ccecd93f79c9dd0537671138bb0a9.tar.zst sway-69e1a421fc2ccecd93f79c9dd0537671138bb0a9.zip |
commands: complete move implementation
-rw-r--r-- | include/sway/tree/view.h | 5 | ||||
-rw-r--r-- | sway/commands/move.c | 138 | ||||
-rw-r--r-- | sway/sway.5.scd | 17 | ||||
-rw-r--r-- | sway/tree/view.c | 9 |
4 files changed, 103 insertions, 66 deletions
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 37fd02bc..4a3f01e7 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -316,6 +316,11 @@ void view_update_title(struct sway_view *view, bool force); | |||
316 | void view_execute_criteria(struct sway_view *view); | 316 | void view_execute_criteria(struct sway_view *view); |
317 | 317 | ||
318 | /** | 318 | /** |
319 | * Find any view that has the given mark and return it. | ||
320 | */ | ||
321 | struct sway_view *view_find_mark(char *mark); | ||
322 | |||
323 | /** | ||
319 | * Find any view that has the given mark and remove the mark from the view. | 324 | * Find any view that has the given mark and remove the mark from the view. |
320 | * Returns true if it matched a view. | 325 | * Returns true if it matched a view. |
321 | */ | 326 | */ |
diff --git a/sway/commands/move.c b/sway/commands/move.c index 841da4c4..b80ce936 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -20,6 +20,7 @@ static const char* expected_syntax = | |||
20 | "Expected 'move <left|right|up|down> <[px] px>' or " | 20 | "Expected 'move <left|right|up|down> <[px] px>' or " |
21 | "'move <container|window> to workspace <name>' or " | 21 | "'move <container|window> to workspace <name>' or " |
22 | "'move <container|window|workspace> to output <name|direction>' or " | 22 | "'move <container|window|workspace> to output <name|direction>' or " |
23 | "'move <container|window> to mark <mark>' or " | ||
23 | "'move position mouse'"; | 24 | "'move position mouse'"; |
24 | 25 | ||
25 | static struct sway_container *output_in_direction(const char *direction, | 26 | static struct sway_container *output_in_direction(const char *direction, |
@@ -54,19 +55,27 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
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, 4))) { |
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 | } |
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", | ||
68 | "Can only move containers and views."); | ||
69 | } | ||
70 | |||
71 | struct sway_container *old_parent = current->parent; | ||
72 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | ||
73 | struct sway_container *destination = NULL; | ||
74 | |||
75 | // determine destination | ||
76 | if (strcasecmp(argv[1], "to") == 0 | ||
77 | && strcasecmp(argv[2], "workspace") == 0) { | ||
78 | // move container to workspace x | ||
70 | struct sway_container *ws; | 79 | struct sway_container *ws; |
71 | char *ws_name = NULL; | 80 | char *ws_name = NULL; |
72 | if (argc == 5 && strcasecmp(argv[3], "number") == 0) { | 81 | if (argc == 5 && strcasecmp(argv[3], "number") == 0) { |
@@ -80,8 +89,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
80 | 89 | ||
81 | if (config->auto_back_and_forth && prev_workspace_name) { | 90 | if (config->auto_back_and_forth && prev_workspace_name) { |
82 | // auto back and forth move | 91 | // auto back and forth move |
83 | struct sway_container *curr_ws = container_parent(current, C_WORKSPACE); | 92 | if (old_ws->name && strcmp(old_ws->name, ws_name) == 0) { |
84 | if (curr_ws->name && strcmp(curr_ws->name, ws_name) == 0) { | ||
85 | // if target workspace is the current one | 93 | // if target workspace is the current one |
86 | free(ws_name); | 94 | free(ws_name); |
87 | ws_name = strdup(prev_workspace_name); | 95 | ws_name = strdup(prev_workspace_name); |
@@ -93,63 +101,50 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, | |||
93 | ws = workspace_create(NULL, ws_name); | 101 | ws = workspace_create(NULL, ws_name); |
94 | } | 102 | } |
95 | free(ws_name); | 103 | free(ws_name); |
96 | struct sway_container *old_parent = current->parent; | ||
97 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | ||
98 | struct sway_container *destination = seat_get_focus_inactive( | ||
99 | config->handler_context.seat, ws); | ||
100 | container_move_to(current, destination); | ||
101 | struct sway_container *focus = seat_get_focus_inactive( | ||
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 | 104 | ||
113 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 105 | destination = seat_get_focus_inactive(config->handler_context.seat, ws); |
114 | } else if (strcasecmp(argv[1], "to") == 0 | 106 | } else if (strcasecmp(argv[1], "to") == 0 |
115 | && strcasecmp(argv[2], "output") == 0) { | 107 | && strcasecmp(argv[2], "output") == 0) { |
116 | if (current->type == C_WORKSPACE) { | ||
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 | } | ||
124 | struct sway_container *source = container_parent(current, C_OUTPUT); | 108 | struct sway_container *source = container_parent(current, C_OUTPUT); |
125 | struct sway_container *destination = output_in_direction(argv[3], | 109 | struct sway_container *dest_output = output_in_direction(argv[3], |
126 | source->sway_output->wlr_output, current->x, current->y); | 110 | source->sway_output->wlr_output, current->x, current->y); |
127 | if (!destination) { | 111 | if (!dest_output) { |
128 | return cmd_results_new(CMD_FAILURE, "move workspace", | 112 | return cmd_results_new(CMD_FAILURE, "move workspace", |
129 | "Can't find output with name/direction '%s'", argv[3]); | 113 | "Can't find output with name/direction '%s'", argv[3]); |
130 | } | 114 | } |
131 | struct sway_container *focus = seat_get_focus_inactive( | 115 | destination = seat_get_focus_inactive( |
132 | config->handler_context.seat, destination); | 116 | config->handler_context.seat, dest_output); |
133 | if (!focus) { | 117 | if (!destination) { |
134 | // We've never been to this output before | 118 | // We've never been to this output before |
135 | focus = destination->children->items[0]; | 119 | destination = dest_output->children->items[0]; |
136 | } | 120 | } |
137 | struct sway_container *old_parent = current->parent; | 121 | } else if (strcasecmp(argv[1], "to") == 0 |
138 | struct sway_container *old_ws = container_parent(current, C_WORKSPACE); | 122 | && strcasecmp(argv[2], "mark") == 0) { |
139 | container_move_to(current, focus); | 123 | struct sway_view *dest_view = view_find_mark(argv[3]); |
140 | seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); | 124 | if (dest_view == NULL) { |
141 | container_reap_empty(old_parent); | 125 | return cmd_results_new(CMD_FAILURE, "move", |
142 | container_reap_empty(focus->parent); | 126 | "Mark '%s' not found", argv[3]); |
127 | } | ||
128 | destination = dest_view->swayc; | ||
129 | } else { | ||
130 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | ||
131 | } | ||
143 | 132 | ||
144 | // TODO: Ideally we would arrange the surviving parent after reaping, | 133 | // move container, arrange windows and return focus |
145 | // but container_reap_empty does not return it, so we arrange the | 134 | container_move_to(current, destination); |
146 | // workspace instead. | 135 | struct sway_container *focus = |
147 | arrange_windows(old_ws); | 136 | seat_get_focus_inactive(config->handler_context.seat, old_parent); |
148 | arrange_windows(focus->parent); | 137 | seat_set_focus_warp(config->handler_context.seat, focus, true, false); |
138 | container_reap_empty(old_parent); | ||
139 | container_reap_empty(destination->parent); | ||
149 | 140 | ||
150 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 141 | // TODO: Ideally we would arrange the surviving parent after reaping, |
151 | } | 142 | // but container_reap_empty does not return it, so we arrange the |
152 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 143 | // workspace instead. |
144 | arrange_windows(old_ws); | ||
145 | arrange_windows(destination->parent); | ||
146 | |||
147 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
153 | } | 148 | } |
154 | 149 | ||
155 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, | 150 | static struct cmd_results *cmd_move_workspace(struct sway_container *current, |
@@ -243,8 +238,8 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
243 | } | 238 | } |
244 | 239 | ||
245 | static const char* expected_position_syntax = | 240 | static const char* expected_position_syntax = |
246 | "Expected 'move [absolute] position <x> <y>' or " | 241 | "Expected 'move [absolute] position <x> [px] <y> [px]' or " |
247 | "'move [absolute] position mouse'"; | 242 | "'move [absolute] position center|mouse'"; |
248 | 243 | ||
249 | static struct cmd_results *move_to_position(struct sway_container *container, | 244 | static struct cmd_results *move_to_position(struct sway_container *container, |
250 | int argc, char **argv) { | 245 | int argc, char **argv) { |
@@ -279,10 +274,18 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
279 | double ly = seat->cursor->cursor->y - container->height / 2; | 274 | double ly = seat->cursor->cursor->y - container->height / 2; |
280 | container_floating_move_to(container, lx, ly); | 275 | container_floating_move_to(container, lx, ly); |
281 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 276 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
277 | } else if (strcmp(argv[0], "center") == 0) { | ||
278 | struct sway_container *ws = container_parent(container, C_WORKSPACE); | ||
279 | double lx = ws->x + (ws->width - container->width) / 2; | ||
280 | double ly = ws->y + (ws->height - container->height) / 2; | ||
281 | container_floating_move_to(container, lx, ly); | ||
282 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
282 | } | 283 | } |
283 | if (argc != 2) { | 284 | |
285 | if (argc < 2) { | ||
284 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | 286 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); |
285 | } | 287 | } |
288 | |||
286 | double lx, ly; | 289 | double lx, ly; |
287 | char *inv; | 290 | char *inv; |
288 | lx = (double)strtol(argv[0], &inv, 10); | 291 | lx = (double)strtol(argv[0], &inv, 10); |
@@ -290,11 +293,22 @@ static struct cmd_results *move_to_position(struct sway_container *container, | |||
290 | return cmd_results_new(CMD_FAILURE, "move", | 293 | return cmd_results_new(CMD_FAILURE, "move", |
291 | "Invalid position specified"); | 294 | "Invalid position specified"); |
292 | } | 295 | } |
296 | if (strcmp(argv[1], "px") == 0) { | ||
297 | --argc; | ||
298 | ++argv; | ||
299 | } | ||
300 | |||
301 | if (argc > 3) { | ||
302 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
303 | } | ||
304 | |||
293 | ly = (double)strtol(argv[1], &inv, 10); | 305 | ly = (double)strtol(argv[1], &inv, 10); |
294 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | 306 | if ((*inv != '\0' && strcasecmp(inv, "px") != 0) || |
307 | (argc == 3 && strcmp(argv[2], "px") != 0)) { | ||
295 | return cmd_results_new(CMD_FAILURE, "move", | 308 | return cmd_results_new(CMD_FAILURE, "move", |
296 | "Invalid position specified"); | 309 | "Invalid position specified"); |
297 | } | 310 | } |
311 | |||
298 | container_floating_move_to(container, lx, ly); | 312 | container_floating_move_to(container, lx, ly); |
299 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 313 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
300 | } | 314 | } |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index a580c7d6..8083106b 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -123,18 +123,27 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
123 | *layout* toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]... | 123 | *layout* toggle [split|tabbed|stacking|splitv|splith] [split|tabbed|stacking|splitv|splith]... |
124 | Cycles the layout mode of the focused container through a list of layouts. | 124 | Cycles the layout mode of the focused container through a list of layouts. |
125 | 125 | ||
126 | *move* left|right|up|down [<px>] | 126 | *move* left|right|up|down [<px> px] |
127 | Moves the focused container in the direction specified. If the container, | 127 | Moves the focused container in the direction specified. If the container, |
128 | the optional _px_ argument specifies how many pixels to move the container. | 128 | the optional _px_ argument specifies how many pixels to move the container. |
129 | If unspecified, the default is 10 pixels. Pixels are ignored when moving | 129 | If unspecified, the default is 10 pixels. Pixels are ignored when moving |
130 | tiled containers. | 130 | tiled containers. |
131 | 131 | ||
132 | *move* [absolute] position <pos_x> [px] <pos_y> [px] | ||
133 | Moves the focused container to the specified position. | ||
134 | |||
135 | *move* [absolute] position center|mouse | ||
136 | Moves the focused container to be centered on the workspace or mouse. | ||
137 | |||
138 | *move* container|window to mark <mark> | ||
139 | Moves the focused container to the specified mark. | ||
140 | |||
132 | *move* container|window to workspace <name> | 141 | *move* container|window to workspace <name> |
133 | Moves the focused container to the specified workspace. | 142 | Moves the focused container to the specified workspace. |
134 | 143 | ||
135 | *move* container|window to workspace prev|next | 144 | *move* container|window to workspace prev|next|current |
136 | Moves the focused container to the previous or next workspace on this | 145 | Moves the focused container to the previous, next or current workspace on |
137 | output, or if no workspaces remain, the previous or next output. | 146 | this output, or if no workspaces remain, the previous or next output. |
138 | 147 | ||
139 | *move* container|window to workspace prev\_on\_output|next\_on\_output | 148 | *move* container|window to workspace prev\_on\_output|next\_on\_output |
140 | Moves the focused container to the previous or next workspace on this | 149 | Moves the focused container to the previous or next workspace on this |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 9465b3a1..48bd7ac0 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -891,6 +891,15 @@ static bool find_by_mark_iterator(struct sway_container *con, | |||
891 | return con->type == C_VIEW && view_has_mark(con->sway_view, mark); | 891 | return con->type == C_VIEW && view_has_mark(con->sway_view, mark); |
892 | } | 892 | } |
893 | 893 | ||
894 | struct sway_view *view_find_mark(char *mark) { | ||
895 | struct sway_container *container = container_find(&root_container, | ||
896 | find_by_mark_iterator, mark); | ||
897 | if (!container) { | ||
898 | return NULL; | ||
899 | } | ||
900 | return container->sway_view; | ||
901 | } | ||
902 | |||
894 | bool view_find_and_unmark(char *mark) { | 903 | bool view_find_and_unmark(char *mark) { |
895 | struct sway_container *container = container_find(&root_container, | 904 | struct sway_container *container = container_find(&root_container, |
896 | find_by_mark_iterator, mark); | 905 | find_by_mark_iterator, mark); |