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 @@ #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; +} |