diff options
Diffstat (limited to 'sway/output.c')
-rw-r--r-- | sway/output.c | 158 |
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 | ||
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 | } | ||