diff options
-rw-r--r-- | include/sway/desktop.h | 4 | ||||
-rw-r--r-- | include/sway/output.h | 2 | ||||
-rw-r--r-- | include/sway/tree/container.h | 6 | ||||
-rw-r--r-- | sway/commands/move.c | 122 | ||||
-rw-r--r-- | sway/desktop/desktop.c | 9 | ||||
-rw-r--r-- | sway/tree/container.c | 82 |
6 files changed, 208 insertions, 17 deletions
diff --git a/include/sway/desktop.h b/include/sway/desktop.h index f1ad759a..348fb187 100644 --- a/include/sway/desktop.h +++ b/include/sway/desktop.h | |||
@@ -1,4 +1,8 @@ | |||
1 | #include <wlr/types/wlr_surface.h> | 1 | #include <wlr/types/wlr_surface.h> |
2 | 2 | ||
3 | struct sway_container; | ||
4 | |||
3 | void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, | 5 | void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, |
4 | bool whole); | 6 | bool whole); |
7 | |||
8 | void desktop_damage_whole_container(struct sway_container *con); | ||
diff --git a/include/sway/output.h b/include/sway/output.h index b6cda83c..bd25e76e 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -97,4 +97,6 @@ void output_drag_icons_for_each_surface(struct wl_list *drag_icons, | |||
97 | struct sway_output *output, struct root_geometry *geo, | 97 | struct sway_output *output, struct root_geometry *geo, |
98 | wlr_surface_iterator_func_t iterator, void *user_data); | 98 | wlr_surface_iterator_func_t iterator, void *user_data); |
99 | 99 | ||
100 | struct sway_container *output_get_active_workspace(struct sway_output *output); | ||
101 | |||
100 | #endif | 102 | #endif |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 728daa84..a69da9db 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -297,4 +297,10 @@ bool container_is_floating(struct sway_container *container); | |||
297 | */ | 297 | */ |
298 | void container_get_box(struct sway_container *container, struct wlr_box *box); | 298 | void container_get_box(struct sway_container *container, struct wlr_box *box); |
299 | 299 | ||
300 | /** | ||
301 | * Move a floating container to a new layout-local position. | ||
302 | */ | ||
303 | void container_floating_move_to(struct sway_container *con, | ||
304 | double lx, double ly); | ||
305 | |||
300 | #endif | 306 | #endif |
diff --git a/sway/commands/move.c b/sway/commands/move.c index a4fae388..a1c1e018 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -1,11 +1,13 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <string.h> | 2 | #include <string.h> |
3 | #include <strings.h> | 3 | #include <strings.h> |
4 | #include <wlr/types/wlr_cursor.h> | ||
4 | #include <wlr/types/wlr_output.h> | 5 | #include <wlr/types/wlr_output.h> |
5 | #include <wlr/types/wlr_output_layout.h> | 6 | #include <wlr/types/wlr_output_layout.h> |
6 | #include <wlr/util/log.h> | 7 | #include <wlr/util/log.h> |
7 | #include "sway/commands.h" | 8 | #include "sway/commands.h" |
8 | #include "sway/desktop/transaction.h" | 9 | #include "sway/desktop/transaction.h" |
10 | #include "sway/input/cursor.h" | ||
9 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
10 | #include "sway/output.h" | 12 | #include "sway/output.h" |
11 | #include "sway/tree/arrange.h" | 13 | #include "sway/tree/arrange.h" |
@@ -184,11 +186,49 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, | |||
184 | } | 186 | } |
185 | 187 | ||
186 | static struct cmd_results *move_in_direction(struct sway_container *container, | 188 | static struct cmd_results *move_in_direction(struct sway_container *container, |
187 | enum movement_direction direction, int move_amt) { | 189 | enum movement_direction direction, int argc, char **argv) { |
190 | int move_amt = 10; | ||
191 | if (argc > 1) { | ||
192 | char *inv; | ||
193 | move_amt = (int)strtol(argv[1], &inv, 10); | ||
194 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | ||
195 | return cmd_results_new(CMD_FAILURE, "move", | ||
196 | "Invalid distance specified"); | ||
197 | } | ||
198 | } | ||
199 | |||
188 | if (container->type == C_WORKSPACE) { | 200 | if (container->type == C_WORKSPACE) { |
189 | return cmd_results_new(CMD_FAILURE, "move", | 201 | return cmd_results_new(CMD_FAILURE, "move", |
190 | "Cannot move workspaces in a direction"); | 202 | "Cannot move workspaces in a direction"); |
191 | } | 203 | } |
204 | if (container_is_floating(container)) { | ||
205 | if (container->type == C_VIEW && container->sway_view->is_fullscreen) { | ||
206 | return cmd_results_new(CMD_FAILURE, "move", | ||
207 | "Cannot move fullscreen floating container"); | ||
208 | } | ||
209 | double lx = container->x; | ||
210 | double ly = container->y; | ||
211 | switch (direction) { | ||
212 | case MOVE_LEFT: | ||
213 | lx -= move_amt; | ||
214 | break; | ||
215 | case MOVE_RIGHT: | ||
216 | lx += move_amt; | ||
217 | break; | ||
218 | case MOVE_UP: | ||
219 | ly -= move_amt; | ||
220 | break; | ||
221 | case MOVE_DOWN: | ||
222 | ly += move_amt; | ||
223 | break; | ||
224 | case MOVE_PARENT: | ||
225 | case MOVE_CHILD: | ||
226 | return cmd_results_new(CMD_FAILURE, "move", | ||
227 | "Cannot move floating container to parent or child"); | ||
228 | } | ||
229 | container_floating_move_to(container, lx, ly); | ||
230 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
231 | } | ||
192 | // For simplicity, we'll arrange the entire workspace. The reason for this | 232 | // For simplicity, we'll arrange the entire workspace. The reason for this |
193 | // is moving the container might reap the old parent, and container_move | 233 | // is moving the container might reap the old parent, and container_move |
194 | // does not return a surviving parent. | 234 | // does not return a surviving parent. |
@@ -208,31 +248,78 @@ static struct cmd_results *move_in_direction(struct sway_container *container, | |||
208 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 248 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
209 | } | 249 | } |
210 | 250 | ||
251 | static const char* expected_position_syntax = | ||
252 | "Expected 'move [absolute] position <x> <y>' or " | ||
253 | "'move [absolute] position mouse'"; | ||
254 | |||
255 | static struct cmd_results *move_to_position(struct sway_container *container, | ||
256 | int argc, char **argv) { | ||
257 | if (!container_is_floating(container)) { | ||
258 | return cmd_results_new(CMD_FAILURE, "move", | ||
259 | "Only floating containers " | ||
260 | "can be moved to an absolute position"); | ||
261 | } | ||
262 | if (!argc) { | ||
263 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
264 | } | ||
265 | if (strcmp(argv[0], "absolute") == 0) { | ||
266 | --argc; | ||
267 | ++argv; | ||
268 | } | ||
269 | if (!argc) { | ||
270 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
271 | } | ||
272 | if (strcmp(argv[0], "position") == 0) { | ||
273 | --argc; | ||
274 | ++argv; | ||
275 | } | ||
276 | if (!argc) { | ||
277 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
278 | } | ||
279 | if (strcmp(argv[0], "mouse") == 0) { | ||
280 | struct sway_seat *seat = config->handler_context.seat; | ||
281 | if (!seat->cursor) { | ||
282 | return cmd_results_new(CMD_FAILURE, "move", "No cursor device"); | ||
283 | } | ||
284 | double lx = seat->cursor->cursor->x - container->width / 2; | ||
285 | double ly = seat->cursor->cursor->y - container->height / 2; | ||
286 | container_floating_move_to(container, lx, ly); | ||
287 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
288 | } | ||
289 | if (argc != 2) { | ||
290 | return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); | ||
291 | } | ||
292 | double lx, ly; | ||
293 | char *inv; | ||
294 | lx = (double)strtol(argv[0], &inv, 10); | ||
295 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | ||
296 | return cmd_results_new(CMD_FAILURE, "move", | ||
297 | "Invalid position specified"); | ||
298 | } | ||
299 | ly = (double)strtol(argv[1], &inv, 10); | ||
300 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | ||
301 | return cmd_results_new(CMD_FAILURE, "move", | ||
302 | "Invalid position specified"); | ||
303 | } | ||
304 | container_floating_move_to(container, lx, ly); | ||
305 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
306 | } | ||
307 | |||
211 | struct cmd_results *cmd_move(int argc, char **argv) { | 308 | struct cmd_results *cmd_move(int argc, char **argv) { |
212 | struct cmd_results *error = NULL; | 309 | struct cmd_results *error = NULL; |
213 | int move_amt = 10; | ||
214 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { | 310 | if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { |
215 | return error; | 311 | return error; |
216 | } | 312 | } |
217 | struct sway_container *current = config->handler_context.current_container; | 313 | struct sway_container *current = config->handler_context.current_container; |
218 | 314 | ||
219 | if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) { | ||
220 | char *inv; | ||
221 | move_amt = (int)strtol(argv[1], &inv, 10); | ||
222 | if (*inv != '\0' && strcasecmp(inv, "px") != 0) { | ||
223 | return cmd_results_new(CMD_FAILURE, "move", | ||
224 | "Invalid distance specified"); | ||
225 | } | ||
226 | } | ||
227 | |||
228 | if (strcasecmp(argv[0], "left") == 0) { | 315 | if (strcasecmp(argv[0], "left") == 0) { |
229 | return move_in_direction(current, MOVE_LEFT, move_amt); | 316 | return move_in_direction(current, MOVE_LEFT, argc, argv); |
230 | } else if (strcasecmp(argv[0], "right") == 0) { | 317 | } else if (strcasecmp(argv[0], "right") == 0) { |
231 | return move_in_direction(current, MOVE_RIGHT, move_amt); | 318 | return move_in_direction(current, MOVE_RIGHT, argc, argv); |
232 | } else if (strcasecmp(argv[0], "up") == 0) { | 319 | } else if (strcasecmp(argv[0], "up") == 0) { |
233 | return move_in_direction(current, MOVE_UP, move_amt); | 320 | return move_in_direction(current, MOVE_UP, argc, argv); |
234 | } else if (strcasecmp(argv[0], "down") == 0) { | 321 | } else if (strcasecmp(argv[0], "down") == 0) { |
235 | return move_in_direction(current, MOVE_DOWN, move_amt); | 322 | return move_in_direction(current, MOVE_DOWN, argc, argv); |
236 | } else if (strcasecmp(argv[0], "container") == 0 | 323 | } else if (strcasecmp(argv[0], "container") == 0 |
237 | || strcasecmp(argv[0], "window") == 0) { | 324 | || strcasecmp(argv[0], "window") == 0) { |
238 | return cmd_move_container(current, argc, argv); | 325 | return cmd_move_container(current, argc, argv); |
@@ -244,8 +331,9 @@ struct cmd_results *cmd_move(int argc, char **argv) { | |||
244 | // TODO: scratchpad | 331 | // TODO: scratchpad |
245 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | 332 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); |
246 | } else if (strcasecmp(argv[0], "position") == 0) { | 333 | } else if (strcasecmp(argv[0], "position") == 0) { |
247 | // TODO: floating | 334 | return move_to_position(current, argc, argv); |
248 | return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); | 335 | } else if (strcasecmp(argv[0], "absolute") == 0) { |
336 | return move_to_position(current, argc, argv); | ||
249 | } else { | 337 | } else { |
250 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 338 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
251 | } | 339 | } |
diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index e495790c..6575519d 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c | |||
@@ -13,3 +13,12 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, | |||
13 | } | 13 | } |
14 | } | 14 | } |
15 | } | 15 | } |
16 | |||
17 | void desktop_damage_whole_container(struct sway_container *con) { | ||
18 | for (int i = 0; i < root_container.children->length; ++i) { | ||
19 | struct sway_container *cont = root_container.children->items[i]; | ||
20 | if (cont->type == C_OUTPUT) { | ||
21 | output_damage_whole_container(cont->sway_output, con); | ||
22 | } | ||
23 | } | ||
24 | } | ||
diff --git a/sway/tree/container.c b/sway/tree/container.c index 5fdcb6e3..2df2332c 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -11,11 +11,14 @@ | |||
11 | #include "cairo.h" | 11 | #include "cairo.h" |
12 | #include "pango.h" | 12 | #include "pango.h" |
13 | #include "sway/config.h" | 13 | #include "sway/config.h" |
14 | #include "sway/desktop.h" | ||
15 | #include "sway/desktop/transaction.h" | ||
14 | #include "sway/input/input-manager.h" | 16 | #include "sway/input/input-manager.h" |
15 | #include "sway/input/seat.h" | 17 | #include "sway/input/seat.h" |
16 | #include "sway/ipc-server.h" | 18 | #include "sway/ipc-server.h" |
17 | #include "sway/output.h" | 19 | #include "sway/output.h" |
18 | #include "sway/server.h" | 20 | #include "sway/server.h" |
21 | #include "sway/tree/arrange.h" | ||
19 | #include "sway/tree/layout.h" | 22 | #include "sway/tree/layout.h" |
20 | #include "sway/tree/view.h" | 23 | #include "sway/tree/view.h" |
21 | #include "sway/tree/workspace.h" | 24 | #include "sway/tree/workspace.h" |
@@ -989,3 +992,82 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) { | |||
989 | box->width = container->width; | 992 | box->width = container->width; |
990 | box->height = container->height; | 993 | box->height = container->height; |
991 | } | 994 | } |
995 | |||
996 | /** | ||
997 | * Translate the container's position as well as all children. | ||
998 | */ | ||
999 | static void container_floating_translate(struct sway_container *con, | ||
1000 | double x_amount, double y_amount) { | ||
1001 | con->x += x_amount; | ||
1002 | con->y += y_amount; | ||
1003 | con->current.swayc_x += x_amount; | ||
1004 | con->current.swayc_y += y_amount; | ||
1005 | if (con->type == C_VIEW) { | ||
1006 | con->sway_view->x += x_amount; | ||
1007 | con->sway_view->y += y_amount; | ||
1008 | con->current.view_x += x_amount; | ||
1009 | con->current.view_y += y_amount; | ||
1010 | } else { | ||
1011 | for (int i = 0; i < con->children->length; ++i) { | ||
1012 | struct sway_container *child = con->children->items[i]; | ||
1013 | container_floating_translate(child, x_amount, y_amount); | ||
1014 | } | ||
1015 | } | ||
1016 | } | ||
1017 | |||
1018 | /** | ||
1019 | * Choose an output for the floating container's new position. | ||
1020 | * | ||
1021 | * If the center of the container intersects an output then we'll choose that | ||
1022 | * one, otherwise we'll choose whichever output is closest to the container's | ||
1023 | * center. | ||
1024 | */ | ||
1025 | static struct sway_container *container_floating_find_output( | ||
1026 | struct sway_container *con) { | ||
1027 | double center_x = con->x + con->width / 2; | ||
1028 | double center_y = con->y + con->height / 2; | ||
1029 | struct sway_container *closest_output = NULL; | ||
1030 | double closest_distance = DBL_MAX; | ||
1031 | for (int i = 0; i < root_container.children->length; ++i) { | ||
1032 | struct sway_container *output = root_container.children->items[i]; | ||
1033 | struct wlr_box output_box; | ||
1034 | double closest_x, closest_y; | ||
1035 | container_get_box(output, &output_box); | ||
1036 | wlr_box_closest_point(&output_box, center_x, center_y, | ||
1037 | &closest_x, &closest_y); | ||
1038 | if (center_x == closest_x && center_y == closest_y) { | ||
1039 | // The center of the floating container is on this output | ||
1040 | return output; | ||
1041 | } | ||
1042 | double x_dist = closest_x - center_x; | ||
1043 | double y_dist = closest_y - center_y; | ||
1044 | double distance = x_dist * x_dist + y_dist * y_dist; | ||
1045 | if (distance < closest_distance) { | ||
1046 | closest_output = output; | ||
1047 | closest_distance = distance; | ||
1048 | } | ||
1049 | } | ||
1050 | return closest_output; | ||
1051 | } | ||
1052 | |||
1053 | void container_floating_move_to(struct sway_container *con, | ||
1054 | double lx, double ly) { | ||
1055 | desktop_damage_whole_container(con); | ||
1056 | container_floating_translate(con, lx - con->x, ly - con->y); | ||
1057 | desktop_damage_whole_container(con); | ||
1058 | struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); | ||
1059 | struct sway_container *new_output = container_floating_find_output(con); | ||
1060 | if (!sway_assert(new_output, "Unable to find any output")) { | ||
1061 | return; | ||
1062 | } | ||
1063 | struct sway_container *new_workspace = | ||
1064 | output_get_active_workspace(new_output->sway_output); | ||
1065 | if (old_workspace != new_workspace) { | ||
1066 | container_remove_child(con); | ||
1067 | container_add_child(new_workspace->sway_workspace->floating, con); | ||
1068 | struct sway_transaction *transaction = transaction_create(); | ||
1069 | arrange_windows(old_workspace, transaction); | ||
1070 | arrange_windows(new_workspace, transaction); | ||
1071 | transaction_commit(transaction); | ||
1072 | } | ||
1073 | } | ||