summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/container.h2
-rw-r--r--include/output.h13
-rw-r--r--sway/commands.c18
-rw-r--r--sway/handlers.c19
-rw-r--r--sway/layout.c6
-rw-r--r--sway/output.c158
6 files changed, 167 insertions, 49 deletions
diff --git a/include/container.h b/include/container.h
index 8c54ee24..cb18de49 100644
--- a/include/container.h
+++ b/include/container.h
@@ -63,7 +63,7 @@ struct sway_container {
63 63
64 /** 64 /**
65 * The coordinates that this view appear at, relative to the output they 65 * The coordinates that this view appear at, relative to the output they
66 * are located on. 66 * are located on (output containers have absolute coordinates).
67 */ 67 */
68 double x, y; 68 double x, y;
69 69
diff --git a/include/output.h b/include/output.h
index 10ff0596..1307ead8 100644
--- a/include/output.h
+++ b/include/output.h
@@ -4,7 +4,16 @@
4#include "container.h" 4#include "container.h"
5#include "focus.h" 5#include "focus.h"
6 6
7swayc_t *output_by_name(const char* name); 7// Position is absolute coordinates on the edge where the adjacent output
8swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir); 8// should be searched for.
9swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos);
10swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir, const struct wlc_point *abs_pos, bool pick_closest);
11
12// Place absolute coordinates for given container into given wlc_point.
13void get_absolute_position(swayc_t *container, struct wlc_point *point);
14
15// Place absolute coordinates for the center point of given container into
16// given wlc_point.
17void get_absolute_center_position(swayc_t *container, struct wlc_point *point);
9 18
10#endif 19#endif
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
5swayc_t *output_by_name(const char* name) { 5swayc_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
25swayc_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 26swayc_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
153void 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
175void 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}