aboutsummaryrefslogtreecommitdiff
path: root/sway/output.c
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2015-11-16 15:57:02 -0500
committerDrew DeVault <sir@cmpwn.com>2015-11-16 15:57:02 -0500
commit6850174049b9b8ffc00aac7051d82b3489bcc948 (patch)
treebdac5630c32099785a6eade4dfa8ceb04a3c11dd /sway/output.c
parent95c65ee33ea05963e334555311414e0d834de4b7 (diff)
parent236f26f62e56cef8278d88f6111720b738d4a85f (diff)
Merge pull request #233 from sce/multiple_adjacent_outputs
output: Support multiple adjacent outputs.
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 @@
#include "output.h"
#include "log.h"
-swayc_t *output_by_name(const char* name) {
+swayc_t *output_by_name(const char* name, const struct wlc_point *abs_pos) {
if (strcasecmp(name, "left") == 0) {
- return swayc_adjacent_output(NULL, MOVE_LEFT);
+ return swayc_adjacent_output(NULL, MOVE_LEFT, abs_pos, true);
} else if (strcasecmp(name, "right") == 0) {
- return swayc_adjacent_output(NULL, MOVE_RIGHT);
+ return swayc_adjacent_output(NULL, MOVE_RIGHT, abs_pos, true);
} else if (strcasecmp(name, "up") == 0) {
- return swayc_adjacent_output(NULL, MOVE_UP);
+ return swayc_adjacent_output(NULL, MOVE_UP, abs_pos, true);
} else if (strcasecmp(name, "down") == 0) {
- return swayc_adjacent_output(NULL, MOVE_DOWN);
+ return swayc_adjacent_output(NULL, MOVE_DOWN, abs_pos, true);
} else {
for(int i = 0; i < root_container.children->length; ++i) {
swayc_t *c = root_container.children->items[i];
@@ -22,66 +22,126 @@ swayc_t *output_by_name(const char* name) {
return NULL;
}
-swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir) {
- // TODO: This implementation is naïve: We assume all outputs are
- // perfectly aligned (ie. only a single output per edge which covers
- // the whole edge).
+// Position is where on the edge (as absolute position) the adjacent output should be searched for.
+swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir,
+ const struct wlc_point *abs_pos, bool pick_closest) {
+
if (!output) {
output = swayc_active_output();
}
+ // In order to find adjacent outputs we need to test that the outputs are
+ // aligned on one axis (decided by the direction given) and that the given
+ // position is within the edge of the adjacent output. If no such output
+ // exists we pick the adjacent output within the edge that is closest to
+ // the given position, if any.
swayc_t *adjacent = NULL;
+ char *dir_text = NULL;
switch(dir) {
case MOVE_LEFT:
+ case MOVE_RIGHT: ;
+ double delta_y = 0;
for(int i = 0; i < root_container.children->length; ++i) {
swayc_t *c = root_container.children->items[i];
if (c == output || c->type != C_OUTPUT) {
continue;
}
- if (c->y == output->y && c->x + c->width == output->x) {
- sway_log(L_DEBUG, "%s is left of current output %s", c->name, output->name);
- adjacent = c;
- break;
- }
- }
- break;
- case MOVE_RIGHT:
- for(int i = 0; i < root_container.children->length; ++i) {
- swayc_t *c = root_container.children->items[i];
- if (c == output || c->type != C_OUTPUT) {
+ bool x_aligned = dir == MOVE_LEFT ?
+ c->x + c->width == output->x :
+ c->x == output->x + output->width;
+ if (!x_aligned) {
continue;
}
- if (c->y == output->y && output->x + output->width == c->x) {
- sway_log(L_DEBUG, "%s is right of current output %s", c->name, output->name);
+ if (abs_pos->y >= c->y && abs_pos->y <= c->y + c->height) {
+ delta_y = 0;
adjacent = c;
break;
+ } else if (pick_closest) {
+ // track closest adjacent output
+ double top_y = c->y, bottom_y = c->y + c->height;
+ if (top_y >= output->y && top_y <= output->y + output->height) {
+ double delta = top_y - abs_pos->y;
+ if (delta < 0) delta = -delta;
+ if (delta < delta_y || !adjacent) {
+ delta_y = delta;
+ adjacent = c;
+ }
+ }
+ // we check both points and pick the closest
+ if (bottom_y >= output->y && bottom_y <= output->y + output->height) {
+ double delta = bottom_y - abs_pos->y;
+ if (delta < 0) delta = -delta;
+ if (delta < delta_y || !adjacent) {
+ delta_y = delta;
+ adjacent = c;
+ }
+ }
}
}
+ dir_text = dir == MOVE_LEFT ? "left of" : "right of";
+ if (adjacent && delta_y == 0) {
+ sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i)",
+ adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y,
+ dir_text, output->name, abs_pos->y);
+ } else if (adjacent) {
+ // so we end up picking the closest adjacent output because
+ // there is no directly adjacent to the given position
+ sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (y-position %i, delta: %.0f)",
+ adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y,
+ dir_text, output->name, abs_pos->y, delta_y);
+ }
break;
case MOVE_UP:
+ case MOVE_DOWN: ;
+ double delta_x = 0;
for(int i = 0; i < root_container.children->length; ++i) {
swayc_t *c = root_container.children->items[i];
if (c == output || c->type != C_OUTPUT) {
continue;
}
- if (output->x == c->x && c->y + c->height == output->y) {
- sway_log(L_DEBUG, "%s is above current output %s", c->name, output->name);
- adjacent = c;
- break;
- }
- }
- break;
- case MOVE_DOWN:
- for(int i = 0; i < root_container.children->length; ++i) {
- swayc_t *c = root_container.children->items[i];
- if (c == output || c->type != C_OUTPUT) {
+ bool y_aligned = dir == MOVE_UP ?
+ c->y + c->height == output->y :
+ c->y == output->y + output->height;
+ if (!y_aligned) {
continue;
}
- if (output->x == c->x && output->y + output->height == c->y) {
- sway_log(L_DEBUG, "%s is below current output %s", c->name, output->name);
+ if (abs_pos->x >= c->x && abs_pos->x <= c->x + c->width) {
+ delta_x = 0;
adjacent = c;
break;
+ } else if (pick_closest) {
+ // track closest adjacent output
+ double left_x = c->x, right_x = c->x + c->width;
+ if (left_x >= output->x && left_x <= output->x + output->width) {
+ double delta = left_x - abs_pos->x;
+ if (delta < 0) delta = -delta;
+ if (delta < delta_x || !adjacent) {
+ delta_x = delta;
+ adjacent = c;
+ }
+ }
+ // we check both points and pick the closest
+ if (right_x >= output->x && right_x <= output->x + output->width) {
+ double delta = right_x - abs_pos->x;
+ if (delta < 0) delta = -delta;
+ if (delta < delta_x || !adjacent) {
+ delta_x = delta;
+ adjacent = c;
+ }
+ }
}
}
+ dir_text = dir == MOVE_UP ? "above" : "below";
+ if (adjacent && delta_x == 0) {
+ sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i)",
+ adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y,
+ dir_text, output->name, abs_pos->x);
+ } else if (adjacent) {
+ // so we end up picking the closest adjacent output because
+ // there is no directly adjacent to the given position
+ sway_log(L_DEBUG, "%s (%.0fx%.0f+%.0f+%.0f) is %s current output %s (x-position %i, delta: %.0f)",
+ adjacent->name, adjacent->width, adjacent->height, adjacent->x, adjacent->y,
+ dir_text, output->name, abs_pos->x, delta_x);
+ }
break;
default:
sway_abort("Function called with invalid argument.");
@@ -89,3 +149,31 @@ swayc_t *swayc_adjacent_output(swayc_t *output, enum movement_direction dir) {
}
return adjacent;
}
+
+void get_absolute_position(swayc_t *container, struct wlc_point *point) {
+ if (!container || !point)
+ sway_abort("Need container and wlc_point (was %p, %p).", container, point);
+
+ if (container->type == C_OUTPUT) {
+ // Coordinates are already absolute.
+ point->x = container->x;
+ point->y = container->y;
+ } else {
+ swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
+ if (container->type == C_WORKSPACE) {
+ // Workspace coordinates are actually wrong/arbitrary, but should
+ // be same as output.
+ point->x = output->x;
+ point->y = output->y;
+ } else {
+ point->x = output->x + container->x;
+ point->y = output->y + container->y;
+ }
+ }
+}
+
+void get_absolute_center_position(swayc_t *container, struct wlc_point *point) {
+ get_absolute_position(container, point);
+ point->x += container->width/2;
+ point->y += container->height/2;
+}