diff options
Diffstat (limited to 'sway')
-rw-r--r-- | sway/commands.c | 18 | ||||
-rw-r--r-- | sway/handlers.c | 19 | ||||
-rw-r--r-- | sway/layout.c | 6 | ||||
-rw-r--r-- | sway/output.c | 158 |
4 files changed, 155 insertions, 46 deletions
diff --git a/sway/commands.c b/sway/commands.c index f194681e..dfb3c12d 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -377,11 +377,13 @@ static struct cmd_results *cmd_focus(int argc, char **argv) { | |||
377 | struct cmd_results *error = NULL; | 377 | struct cmd_results *error = NULL; |
378 | if (argc > 0 && strcasecmp(argv[0], "output") == 0) { | 378 | if (argc > 0 && strcasecmp(argv[0], "output") == 0) { |
379 | swayc_t *output = NULL; | 379 | swayc_t *output = NULL; |
380 | struct wlc_point abs_pos; | ||
381 | get_absolute_center_position(get_focused_container(&root_container), &abs_pos); | ||
380 | if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 2))) { | 382 | if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 2))) { |
381 | return error; | 383 | return error; |
382 | } else if (!(output = output_by_name(argv[1]))) { | 384 | } else if (!(output = output_by_name(argv[1], &abs_pos))) { |
383 | return cmd_results_new(CMD_FAILURE, "focus output", | 385 | return cmd_results_new(CMD_FAILURE, "focus output", |
384 | "Can't find output with name/at direction %s", argv[1]); | 386 | "Can't find output with name/at direction '%s' @ (%i,%i)", argv[1], abs_pos.x, abs_pos.y); |
385 | } else if (!workspace_switch(swayc_active_workspace_for(output))) { | 387 | } else if (!workspace_switch(swayc_active_workspace_for(output))) { |
386 | return cmd_results_new(CMD_FAILURE, "focus output", | 388 | return cmd_results_new(CMD_FAILURE, "focus output", |
387 | "Switching to workspace on output '%s' was blocked", argv[1]); | 389 | "Switching to workspace on output '%s' was blocked", argv[1]); |
@@ -591,11 +593,13 @@ static struct cmd_results *cmd_move(int argc, char **argv) { | |||
591 | } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { | 593 | } else if (strcasecmp(argv[1], "to") == 0 && strcasecmp(argv[2], "output") == 0) { |
592 | // move container to output x | 594 | // move container to output x |
593 | swayc_t *output = NULL; | 595 | swayc_t *output = NULL; |
596 | struct wlc_point abs_pos; | ||
597 | get_absolute_center_position(view, &abs_pos); | ||
594 | if (view->type != C_CONTAINER && view->type != C_VIEW) { | 598 | if (view->type != C_CONTAINER && view->type != C_VIEW) { |
595 | return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); | 599 | return cmd_results_new(CMD_FAILURE, "move", "Can only move containers and views."); |
596 | } else if (!(output = output_by_name(argv[3]))) { | 600 | } else if (!(output = output_by_name(argv[3], &abs_pos))) { |
597 | return cmd_results_new(CMD_FAILURE, "move", | 601 | return cmd_results_new(CMD_FAILURE, "move", |
598 | "Can't find output with name/direction '%s'", argv[3]); | 602 | "Can't find output with name/direction '%s' @ (%i,%i)", argv[3], abs_pos.x, abs_pos.y); |
599 | } else { | 603 | } else { |
600 | swayc_t *container = get_focused_container(output); | 604 | swayc_t *container = get_focused_container(output); |
601 | if (container->is_floating) { | 605 | if (container->is_floating) { |
@@ -610,13 +614,15 @@ static struct cmd_results *cmd_move(int argc, char **argv) { | |||
610 | } else if (strcasecmp(argv[0], "workspace") == 0) { | 614 | } else if (strcasecmp(argv[0], "workspace") == 0) { |
611 | // move workspace (to output x) | 615 | // move workspace (to output x) |
612 | swayc_t *output = NULL; | 616 | swayc_t *output = NULL; |
617 | struct wlc_point abs_pos; | ||
618 | get_absolute_center_position(view, &abs_pos); | ||
613 | if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { | 619 | if ((error = checkarg(argc, "move workspace", EXPECTED_EQUAL_TO, 4))) { |
614 | return error; | 620 | return error; |
615 | } else if (strcasecmp(argv[1], "to") != 0 || strcasecmp(argv[2], "output") != 0) { | 621 | } else if (strcasecmp(argv[1], "to") != 0 || strcasecmp(argv[2], "output") != 0) { |
616 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); | 622 | return cmd_results_new(CMD_INVALID, "move", expected_syntax); |
617 | } else if (!(output = output_by_name(argv[3]))) { | 623 | } else if (!(output = output_by_name(argv[3], &abs_pos))) { |
618 | return cmd_results_new(CMD_FAILURE, "move workspace", | 624 | return cmd_results_new(CMD_FAILURE, "move workspace", |
619 | "Can't find output with name/at direction '%s'", argv[3]); | 625 | "Can't find output with name/direction '%s' @ (%i,%i)", argv[3], abs_pos.x, abs_pos.y); |
620 | } | 626 | } |
621 | if (view->type == C_WORKSPACE) { | 627 | if (view->type == C_WORKSPACE) { |
622 | // This probably means we're moving an empty workspace, but | 628 | // This probably means we're moving an empty workspace, but |
diff --git a/sway/handlers.c b/sway/handlers.c index cadfce5c..3f3c1bdd 100644 --- a/sway/handlers.c +++ b/sway/handlers.c | |||
@@ -305,28 +305,39 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct | |||
305 | !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { | 305 | !pointer_state.left.held && !pointer_state.right.held && !pointer_state.scroll.held) { |
306 | 306 | ||
307 | swayc_t *output = swayc_active_output(), *adjacent = NULL; | 307 | swayc_t *output = swayc_active_output(), *adjacent = NULL; |
308 | struct wlc_point abs_pos = *origin; | ||
309 | abs_pos.x += output->x; | ||
310 | abs_pos.y += output->y; | ||
308 | if (origin->x == 0) { // Left edge | 311 | if (origin->x == 0) { // Left edge |
309 | if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT))) { | 312 | if ((adjacent = swayc_adjacent_output(output, MOVE_LEFT, &abs_pos, false))) { |
310 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 313 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
311 | new_origin.x = adjacent->width; | 314 | new_origin.x = adjacent->width; |
315 | // adjust for differently aligned outputs (well, this is | ||
316 | // only correct when the two outputs have the same | ||
317 | // resolution or the same dpi I guess, it should take | ||
318 | // physical attributes into account) | ||
319 | new_origin.y += (output->y - adjacent->y); | ||
312 | } | 320 | } |
313 | } | 321 | } |
314 | } else if ((double)origin->x == output->width) { // Right edge | 322 | } else if ((double)origin->x == output->width) { // Right edge |
315 | if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT))) { | 323 | if ((adjacent = swayc_adjacent_output(output, MOVE_RIGHT, &abs_pos, false))) { |
316 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 324 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
317 | new_origin.x = 0; | 325 | new_origin.x = 0; |
326 | new_origin.y += (output->y - adjacent->y); | ||
318 | } | 327 | } |
319 | } | 328 | } |
320 | } else if (origin->y == 0) { // Top edge | 329 | } else if (origin->y == 0) { // Top edge |
321 | if ((adjacent = swayc_adjacent_output(output, MOVE_UP))) { | 330 | if ((adjacent = swayc_adjacent_output(output, MOVE_UP, &abs_pos, false))) { |
322 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 331 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
323 | new_origin.y = adjacent->height; | 332 | new_origin.y = adjacent->height; |
333 | new_origin.x += (output->x - adjacent->x); | ||
324 | } | 334 | } |
325 | } | 335 | } |
326 | } else if ((double)origin->y == output->height) { // Bottom edge | 336 | } else if ((double)origin->y == output->height) { // Bottom edge |
327 | if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN))) { | 337 | if ((adjacent = swayc_adjacent_output(output, MOVE_DOWN, &abs_pos, false))) { |
328 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { | 338 | if (workspace_switch(swayc_active_workspace_for(adjacent))) { |
329 | new_origin.y = 0; | 339 | new_origin.y = 0; |
340 | new_origin.x += (output->x - adjacent->x); | ||
330 | } | 341 | } |
331 | } | 342 | } |
332 | } | 343 | } |
diff --git a/sway/layout.c b/sway/layout.c index fe7d820a..741addf1 100644 --- a/sway/layout.c +++ b/sway/layout.c | |||
@@ -533,13 +533,17 @@ swayc_t *get_swayc_in_direction_under(swayc_t *container, enum movement_directio | |||
533 | return parent; | 533 | return parent; |
534 | } | 534 | } |
535 | } | 535 | } |
536 | // If moving to an adjacent output we need a starting position (since this | ||
537 | // output might border to multiple outputs). | ||
538 | struct wlc_point abs_pos; | ||
539 | get_absolute_center_position(container, &abs_pos); | ||
536 | while (true) { | 540 | while (true) { |
537 | // Test if we can even make a difference here | 541 | // Test if we can even make a difference here |
538 | bool can_move = false; | 542 | bool can_move = false; |
539 | int diff = 0; | 543 | int diff = 0; |
540 | if (parent->type == C_ROOT) { | 544 | if (parent->type == C_ROOT) { |
541 | sway_log(L_DEBUG, "Moving between outputs"); | 545 | sway_log(L_DEBUG, "Moving between outputs"); |
542 | return swayc_adjacent_output(container, dir); | 546 | return swayc_adjacent_output(container, dir, &abs_pos, true); |
543 | } else { | 547 | } else { |
544 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { | 548 | if (dir == MOVE_LEFT || dir == MOVE_RIGHT) { |
545 | if (parent->layout == L_HORIZ) { | 549 | if (parent->layout == L_HORIZ) { |
diff --git a/sway/output.c b/sway/output.c index 5044b7aa..cf8ed9a5 100644 --- a/sway/output.c +++ b/sway/output.c | |||
@@ -2,15 +2,15 @@ | |||
2 | #include "output.h" | 2 | #include "output.h" |
3 | #include "log.h" | 3 | #include "log.h" |
4 | 4 | ||
5 | swayc_t *output_by_name(const char* name) { | 5 | swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos) { |
6 | if (strcasecmp(name, "left") == 0) { | 6 | if (strcasecmp(name, "left") == 0) { |
7 | return swayc_adjacent_output(NULL, MOVE_LEFT); | 7 | return swayc_adjacent_output(NULL, MOVE_LEFT, abs_pos, true); |
8 | } else if (strcasecmp(name, "right") == 0) { | 8 | } else if (strcasecmp(name, "right") == 0) { |
9 | return swayc_adjacent_output(NULL, MOVE_RIGHT); | 9 | return swayc_adjacent_output(NULL, MOVE_RIGHT, abs_pos, true); |
10 | } else if (strcasecmp(name, "up") == 0) { | 10 | } else if (strcasecmp(name, "up") == 0) { |
11 | return swayc_adjacent_output(NULL, MOVE_UP); | 11 | return swayc_adjacent_output(NULL, MOVE_UP, abs_pos, true); |
12 | } else if (strcasecmp(name, "down") == 0) { | 12 | } else if (strcasecmp(name, "down") == 0) { |
13 | return swayc_adjacent_output(NULL, MOVE_DOWN); | 13 | return swayc_adjacent_output(NULL, MOVE_DOWN, abs_pos, true); |
14 | } else { | 14 | } else { |
15 | for(int i = 0; i < root_container.children->length; ++i) { | 15 | for(int i = 0; i < root_container.children->length; ++i) { |
16 | swayc_t *c = root_container.children->items[i]; | 16 | swayc_t *c = root_container.children->items[i]; |
@@ -22,66 +22,126 @@ swayc_t *output_by_name(const char* name) { | |||
22 | return NULL; | 22 | return NULL; |
23 | } | 23 | } |
24 | 24 | ||
25 | swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir) { | 25 | // Position is where on the edge (as absolute position) the adjacent output should be searched for. |
26 | // TODO: This implementation is naïve: We assume all outputs are | 26 | swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, |
27 | // perfectly aligned (ie. only a single output per edge which covers | 27 | const struct wlc_point *abs_pos, bool pick_closest) { |
28 | // the whole edge). | 28 | |
29 | if (!output) { | 29 | if (!output) { |
30 | output = swayc_active_output(); | 30 | output = swayc_active_output(); |
31 | } | 31 | } |
32 | // In order to find adjacent outputs we need to test that the outputs are | ||
33 | // aligned on one axis (decided by the direction given) and that the given | ||
34 | // position is within the edge of the adjacent output. If no such output | ||
35 | // exists we pick the adjacent output within the edge that is closest to | ||
36 | // the given position, if any. | ||
32 | swayc_t *adjacent = NULL; | 37 | swayc_t *adjacent = NULL; |
38 | char *dir_text = NULL; | ||
33 | switch(dir) { | 39 | switch(dir) { |
34 | case MOVE_LEFT: | 40 | case MOVE_LEFT: |
41 | case MOVE_RIGHT: ; | ||
42 | double delta_y = 0; | ||
35 | for(int i = 0; i < root_container.children->length; ++i) { | 43 | for(int i = 0; i < root_container.children->length; ++i) { |
36 | swayc_t *c = root_container.children->items[i]; | 44 | swayc_t *c = root_container.children->items[i]; |
37 | if (c == output || c->type != C_OUTPUT) { | 45 | if (c == output || c->type != C_OUTPUT) { |
38 | continue; | 46 | continue; |
39 | } | 47 | } |
40 | if (c->y == output->y && c->x + c->width == output->x) { | 48 | bool x_aligned = dir == MOVE_LEFT ? |
41 | sway_log(L_DEBUG, "%s is left of current output %s", c->name, output->name); | 49 | c->x + c->width == output->x : |
42 | adjacent = c; | 50 | c->x == output->x + output->width; |
43 | break; | 51 | if (!x_aligned) { |
44 | } | ||
45 | } | ||
46 | break; | ||
47 | case MOVE_RIGHT: | ||
48 | for(int i = 0; i < root_container.children->length; ++i) { | ||
49 | swayc_t *c = root_container.children->items[i]; | ||
50 | if (c == output || c->type != C_OUTPUT) { | ||
51 | continue; | 52 | continue; |
52 | } | 53 | } |
53 | if (c->y == output->y && output->x + output->width == c->x) { | 54 | if (abs_pos->y >= c->y && abs_pos->y <= c->y + c->height) { |
54 | sway_log(L_DEBUG, "%s is right of current output %s", c->name, output->name); | 55 | delta_y = 0; |
55 | adjacent = c; | 56 | adjacent = c; |
56 | break; | 57 | break; |
58 | } else if (pick_closest) { | ||
59 | // track closest adjacent output | ||
60 | double top_y = c->y, bottom_y = c->y + c->height; | ||
61 | if (top_y >= output->y && top_y <= output->y + output->height) { | ||
62 | double delta = top_y - abs_pos->y; | ||
63 | if (delta < 0) delta = -delta; | ||
64 | if (delta < delta_y || !adjacent) { | ||
65 | delta_y = delta; | ||
66 | adjacent = c; | ||
67 | } | ||
68 | } | ||
69 | // we check both points and pick the closest | ||
70 | if (bottom_y >= output->y && bottom_y <= output->y + output->height) { | ||
71 | double delta = bottom_y - abs_pos->y; | ||
72 | if (delta < 0) delta = -delta; | ||
73 | if (delta < delta_y || !adjacent) { | ||
74 | delta_y = delta; | ||
75 | adjacent = c; | ||
76 | } | ||
77 | } | ||
57 | } | 78 | } |
58 | } | 79 | } |
80 | dir_text = dir == MOVE_LEFT ? "left of" : "right of"; | ||
81 | if (adjacent && delta_y == 0) { | ||
82 | sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i)", | ||
83 | adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, | ||
84 | dir_text, output->name, abs_pos->y); | ||
85 | } else if (adjacent) { | ||
86 | // so we end up picking the closest adjacent output because | ||
87 | // there is no directly adjacent to the given position | ||
88 | sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i, delta: %.0f)", | ||
89 | adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, | ||
90 | dir_text, output->name, abs_pos->y, delta_y); | ||
91 | } | ||
59 | break; | 92 | break; |
60 | case MOVE_UP: | 93 | case MOVE_UP: |
94 | case MOVE_DOWN: ; | ||
95 | double delta_x = 0; | ||
61 | for(int i = 0; i < root_container.children->length; ++i) { | 96 | for(int i = 0; i < root_container.children->length; ++i) { |
62 | swayc_t *c = root_container.children->items[i]; | 97 | swayc_t *c = root_container.children->items[i]; |
63 | if (c == output || c->type != C_OUTPUT) { | 98 | if (c == output || c->type != C_OUTPUT) { |
64 | continue; | 99 | continue; |
65 | } | 100 | } |
66 | if (output->x == c->x && c->y + c->height == output->y) { | 101 | bool y_aligned = dir == MOVE_UP ? |
67 | sway_log(L_DEBUG, "%s is above current output %s", c->name, output->name); | 102 | c->y + c->height == output->y : |
68 | adjacent = c; | 103 | c->y == output->y + output->height; |
69 | break; | 104 | if (!y_aligned) { |
70 | } | ||
71 | } | ||
72 | break; | ||
73 | case MOVE_DOWN: | ||
74 | for(int i = 0; i < root_container.children->length; ++i) { | ||
75 | swayc_t *c = root_container.children->items[i]; | ||
76 | if (c == output || c->type != C_OUTPUT) { | ||
77 | continue; | 105 | continue; |
78 | } | 106 | } |
79 | if (output->x == c->x && output->y + output->height == c->y) { | 107 | if (abs_pos->x >= c->x && abs_pos->x <= c->x + c->width) { |
80 | sway_log(L_DEBUG, "%s is below current output %s", c->name, output->name); | 108 | delta_x = 0; |
81 | adjacent = c; | 109 | adjacent = c; |
82 | break; | 110 | break; |
111 | } else if (pick_closest) { | ||
112 | // track closest adjacent output | ||
113 | double left_x = c->x, right_x = c->x + c->width; | ||
114 | if (left_x >= output->x && left_x <= output->x + output->width) { | ||
115 | double delta = left_x - abs_pos->x; | ||
116 | if (delta < 0) delta = -delta; | ||
117 | if (delta < delta_x || !adjacent) { | ||
118 | delta_x = delta; | ||
119 | adjacent = c; | ||
120 | } | ||
121 | } | ||
122 | // we check both points and pick the closest | ||
123 | if (right_x >= output->x && right_x <= output->x + output->width) { | ||
124 | double delta = right_x - abs_pos->x; | ||
125 | if (delta < 0) delta = -delta; | ||
126 | if (delta < delta_x || !adjacent) { | ||
127 | delta_x = delta; | ||
128 | adjacent = c; | ||
129 | } | ||
130 | } | ||
83 | } | 131 | } |
84 | } | 132 | } |
133 | dir_text = dir == MOVE_UP ? "above" : "below"; | ||
134 | if (adjacent && delta_x == 0) { | ||
135 | sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i)", | ||
136 | adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, | ||
137 | dir_text, output->name, abs_pos->x); | ||
138 | } else if (adjacent) { | ||
139 | // so we end up picking the closest adjacent output because | ||
140 | // there is no directly adjacent to the given position | ||
141 | sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i, delta: %.0f)", | ||
142 | adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y, | ||
143 | dir_text, output->name, abs_pos->x, delta_x); | ||
144 | } | ||
85 | break; | 145 | break; |
86 | default: | 146 | default: |
87 | sway_abort("Function called with invalid argument."); | 147 | sway_abort("Function called with invalid argument."); |
@@ -89,3 +149,31 @@ swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir) { | |||
89 | } | 149 | } |
90 | return adjacent; | 150 | return adjacent; |
91 | } | 151 | } |
152 | |||
153 | void get_absolute_position(swayc_t *container, struct wlc_point *point) { | ||
154 | if (!container || !point) | ||
155 | sway_abort("Need container and wlc_point (was %p, %p).", container, point); | ||
156 | |||
157 | if (container->type == C_OUTPUT) { | ||
158 | // Coordinates are already absolute. | ||
159 | point->x = container->x; | ||
160 | point->y = container->y; | ||
161 | } else { | ||
162 | swayc_t *output = swayc_parent_by_type(container, C_OUTPUT); | ||
163 | if (container->type == C_WORKSPACE) { | ||
164 | // Workspace coordinates are actually wrong/arbitrary, but should | ||
165 | // be same as output. | ||
166 | point->x = output->x; | ||
167 | point->y = output->y; | ||
168 | } else { | ||
169 | point->x = output->x + container->x; | ||
170 | point->y = output->y + container->y; | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
175 | void get_absolute_center_position(swayc_t *container, struct wlc_point *point) { | ||
176 | get_absolute_position(container, point); | ||
177 | point->x += container->width/2; | ||
178 | point->y += container->height/2; | ||
179 | } | ||