summaryrefslogtreecommitdiffstats
path: root/sway/output.c
diff options
context:
space:
mode:
authorLibravatar S. Christoffer Eliesen <christoffer@eliesen.no>2015-11-16 00:35:25 +0100
committerLibravatar S. Christoffer Eliesen <christoffer@eliesen.no>2015-11-16 21:32:18 +0100
commit236f26f62e56cef8278d88f6111720b738d4a85f (patch)
treebdac5630c32099785a6eade4dfa8ceb04a3c11dd /sway/output.c
parentMerge pull request #232 from sce/replace_output_config (diff)
downloadsway-236f26f62e56cef8278d88f6111720b738d4a85f.tar.gz
sway-236f26f62e56cef8278d88f6111720b738d4a85f.tar.zst
sway-236f26f62e56cef8278d88f6111720b738d4a85f.zip
output: Support multiple adjacent outputs.
When querying for an adjacent output we now need an absolute position in order to know which adjacent output that matches. (The position is either the current mouse position or the center of the currently focused container, depending on context.) If two outputs have one edge each that at least partially align with each other they now count as adjacent. Seamless mouse is affected by this and now properly moves and positions itself between outputs with "uneven" placement (as long as they have at least some part of the edge adjacent to each other). When focusing or moving a container in a specified direction the center of the current focused container decides where to look for an adjacent output. So if e.g. an output has two adjacent outputs to the right and a "focus right" command is issued then it's the placement of the currently focused container that decides which output actually gets focused. Also, if an output has at least one output adjacent in some direction but the entire edge is not covered (ie. it has "holes" with no outputs), then the algorithm will choose the output that is closest to the currently focused container (this does not apply to seamless mouse, the pointer will just stop at the edge in that case).
Diffstat (limited to 'sway/output.c')
-rw-r--r--sway/output.c158
1 files changed, 123 insertions, 35 deletions
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}