From 9f45a67f2cb892cb7e6f76f819737339a3ccb226 Mon Sep 17 00:00:00 2001 From: "S. Christoffer Eliesen" Date: Tue, 20 Oct 2015 19:28:45 +0200 Subject: [PATCH] Switch to adjacent output when hitting output edge. container: Add neighbours struct (for output containers). In order to move the mouse between the outputs this struct is added to keep track of each outputs' neighbours. Neighbour relationships are updated during output creation/destruction and output command invocation (e.g. via config reload). --- include/container.h | 12 ++++++++++++ sway/config.c | 35 +++++++++++++++++++++++++++++++++++ sway/container.c | 37 ++++++++++++++++++++++++++++++++++++- sway/handlers.c | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) diff --git a/include/container.h b/include/container.h index ae9a9fc5a..c6ebc92d7 100644 --- a/include/container.h +++ b/include/container.h @@ -27,6 +27,15 @@ enum swayc_layouts{ L_LAYOUTS, }; +// This is meant to be used by outputs who need to know who their adjacent +// outputs are in order for "mouse between outputs" to work. +// +// (This is obviously a naïve implementation since it assumes a single, +// perfectly aligned neighbour per edge.) +struct swayc_neighbours { + struct sway_container *top, *right, *bottom, *left; +}; + struct sway_container { wlc_handle handle; @@ -54,6 +63,8 @@ struct sway_container { struct sway_container *parent; struct sway_container *focused; + + struct swayc_neighbours *neighbours; }; enum visibility_mask { @@ -70,6 +81,7 @@ swayc_t *new_container(swayc_t *child, enum swayc_layouts layout); swayc_t *new_view(swayc_t *sibling, wlc_handle handle); // Creates view as a new floating view which is in the active workspace swayc_t *new_floating_view(wlc_handle handle); +void reset_neighbour_relations(swayc_t *output); // Container Destroying diff --git a/sway/config.c b/sway/config.c index bce074b9e..7f98d5bda 100644 --- a/sway/config.c +++ b/sway/config.c @@ -310,6 +310,41 @@ void apply_output_config(struct output_config *oc, swayc_t *output) { } output->x = x; } + + // Populate neighbours struct for given output. Will also update reverse + // relations. + reset_neighbour_relations(output); + + 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; + } + + // TODO: This implementation is naïve: We assume all outputs are + // perfectly aligned. + if (c->y == output->y) { + if (c->x + c->width == output->x) { + sway_log(L_DEBUG, "%s is right of %s", output->name, c->name); + c->neighbours->right = output; + output->neighbours->left = c; + } else if (output->x + output->width == c->x) { + sway_log(L_DEBUG, "%s is left of %s", output->name, c->name); + c->neighbours->left = output; + output->neighbours->right = c; + } + } else if (c->x == output->x) { + if (c->y + c->height == output->y) { + sway_log(L_DEBUG, "%s is below %s", output->name, c->name); + c->neighbours->bottom = output; + output->neighbours->top = c; + } else if (output->y + output->height == c->y) { + sway_log(L_DEBUG, "%s is above %s", output->name, c->name); + c->neighbours->top = output; + output->neighbours->bottom = c; + } + } + } } char *do_var_replacement(char *str) { diff --git a/sway/container.c b/sway/container.c index 6c4206fb1..85ad7543e 100644 --- a/sway/container.c +++ b/sway/container.c @@ -19,9 +19,18 @@ static swayc_t *new_swayc(enum swayc_types type) { c->gaps = -1; c->layout = L_NONE; c->type = type; + if (type != C_VIEW) { c->children = create_list(); } + if (type == C_OUTPUT) { + c->neighbours = malloc(sizeof(struct swayc_neighbours)); + c->neighbours->top = NULL; + c->neighbours->right = NULL; + c->neighbours->bottom = NULL; + c->neighbours->left = NULL; + } + return c; } @@ -49,6 +58,9 @@ static void free_swayc(swayc_t *cont) { if (cont->name) { free(cont->name); } + if (cont->neighbours) { + free(cont->neighbours); + } free(cont); } @@ -292,6 +304,8 @@ swayc_t *destroy_output(swayc_t *output) { arrange_windows(root_container.children->items[p], -1, -1); } } + + reset_neighbour_relations(output); sway_log(L_DEBUG, "OUTPUT: Destroying output '%lu'", output->handle); free_swayc(output); return &root_container; @@ -349,8 +363,29 @@ swayc_t *destroy_view(swayc_t *view) { return parent; } -// Container lookup +// Modify container +// Make output inaccesible via its neighbours. +void reset_neighbour_relations(swayc_t *output) { + if (output->neighbours->top) { + output->neighbours->top->neighbours->bottom = NULL; + output->neighbours->top = NULL; + } + if (output->neighbours->right) { + output->neighbours->right->neighbours->left = NULL; + output->neighbours->right = NULL; + } + if (output->neighbours->bottom) { + output->neighbours->bottom->neighbours->top = NULL; + output->neighbours->bottom = NULL; + } + if (output->neighbours->left) { + output->neighbours->left->neighbours->right = NULL; + output->neighbours->left = NULL; + } +} + +// Container lookup swayc_t *swayc_by_test(swayc_t *container, bool (*test)(swayc_t *view, void *data), void *data) { if (!container->children) { diff --git a/sway/handlers.c b/sway/handlers.c index cf07bc8b8..6f7c6fb79 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -353,6 +353,41 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier } static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct wlc_origin *origin) { + // Switch to adjacent output if touching output edge. + // + // Since this doesn't currently support moving windows between outputs we + // don't do the switch if the pointer is in a mode. + if (!pointer_state.mode) { + swayc_t *output = swayc_active_output(); + + if (origin->x == 0) { + swayc_t *adjacent = output->neighbours->left; + if (adjacent) { + sway_log(L_DEBUG, "%s: Left adjacent output is: %s", output->name, adjacent->name); + workspace_switch(adjacent->focused); + } + } else if ((double)origin->x == output->width) { + swayc_t *adjacent = output->neighbours->right; + if (adjacent) { + sway_log(L_DEBUG, "%s: Right adjacent output is: %s", output->name, adjacent->name); + workspace_switch(adjacent->focused); + } + } + if (origin->y == 0) { + swayc_t *adjacent = output->neighbours->top; + if (adjacent) { + sway_log(L_DEBUG, "%s: Top adjacent output is: %s", output->name, adjacent->name); + workspace_switch(adjacent->focused); + } + } else if ((double)origin->y == output->height) { + swayc_t *adjacent = output->neighbours->bottom; + if (adjacent) { + sway_log(L_DEBUG, "%s: Bottom adjacent output is: %s", output->name, adjacent->name); + workspace_switch(adjacent->focused); + } + } + } + // Update pointer origin pointer_state.delta.x = origin->x - pointer_state.origin.x; pointer_state.delta.y = origin->y - pointer_state.origin.y;