diff --git a/include/container.h b/include/container.h index ae9a9fc5..c6ebc92d 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 bce074b9..7f98d5bd 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 6c4206fb..85ad7543 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 cf07bc8b..6f7c6fb7 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;