diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 9d55f63f..facb2d68 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -163,7 +163,7 @@ Actions are used in menus and keyboard/mouse bindings. to the center of the window. If the given output does not contain any windows, the cursor is centered on the given output. -** +** Moves active window to other output, unless the window state is fullscreen. @@ -172,6 +172,9 @@ Actions are used in menus and keyboard/mouse bindings. be one of "left", "right", "up" or "down" to indicate that the window should be moved to the next output in that direction (if one exists). + *wrap* [yes|no] When using the direction attribute, wrap around from + right-to-left or top-to-bottom, and vice versa. Default no. + ** Resizes active window size to width and height of the output when the window size exceeds the output size. diff --git a/include/view.h b/include/view.h index c24fa3d3..b0cb8471 100644 --- a/include/view.h +++ b/include/view.h @@ -503,7 +503,8 @@ void view_on_output_destroy(struct view *view); void view_connect_map(struct view *view, struct wlr_surface *surface); void view_destroy(struct view *view); -struct output *view_get_adjacent_output(struct view *view, enum view_edge edge); +struct output *view_get_adjacent_output(struct view *view, enum view_edge edge, + bool wrap); enum view_axis view_axis_parse(const char *direction); enum view_edge view_edge_parse(const char *direction); diff --git a/src/action.c b/src/action.c index e1187906..953f62e7 100644 --- a/src/action.c +++ b/src/action.c @@ -397,6 +397,10 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char } goto cleanup; } + if (!strcmp(argument, "wrap")) { + action_arg_add_bool(action, argument, parse_bool(content, false)); + goto cleanup; + } break; case ACTION_TYPE_VIRTUAL_OUTPUT_ADD: case ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE: @@ -924,7 +928,8 @@ actions_run(struct view *activator, struct server *server, } else { /* Config parsing makes sure that direction is a valid direction */ enum view_edge edge = action_get_int(action, "direction", 0); - target = view_get_adjacent_output(view, edge); + bool wrap = action_get_bool(action, "wrap", false); + target = view_get_adjacent_output(view, edge, wrap); } if (!target) { wlr_log(WLR_ERROR, "Invalid output."); diff --git a/src/view.c b/src/view.c index e297b725..52627643 100644 --- a/src/view.c +++ b/src/view.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "common/macros.h" #include "common/match.h" #include "common/mem.h" @@ -1519,8 +1520,44 @@ view_on_output_destroy(struct view *view) view->output = NULL; } +static enum wlr_direction +opposite_direction(enum wlr_direction direction) +{ + switch (direction) { + case WLR_DIRECTION_RIGHT: + return WLR_DIRECTION_LEFT; + case WLR_DIRECTION_LEFT: + return WLR_DIRECTION_RIGHT; + case WLR_DIRECTION_DOWN: + return WLR_DIRECTION_UP; + case WLR_DIRECTION_UP: + return WLR_DIRECTION_DOWN; + default: + return 0; + } +} + +static enum wlr_direction +get_wlr_direction(enum view_edge edge) +{ + switch (edge) { + case VIEW_EDGE_LEFT: + return WLR_DIRECTION_LEFT; + case VIEW_EDGE_RIGHT: + return WLR_DIRECTION_RIGHT; + case VIEW_EDGE_UP: + return WLR_DIRECTION_UP; + case VIEW_EDGE_DOWN: + return WLR_DIRECTION_DOWN; + case VIEW_EDGE_CENTER: + case VIEW_EDGE_INVALID: + default: + return 0; + } +} + struct output * -view_get_adjacent_output(struct view *view, enum view_edge edge) +view_get_adjacent_output(struct view *view, enum view_edge edge, bool wrap) { assert(view); struct output *output = view->output; @@ -1530,7 +1567,7 @@ view_get_adjacent_output(struct view *view, enum view_edge edge) return NULL; } - struct wlr_box box = output_usable_area_in_layout_coords(view->output); + struct wlr_box box = output_usable_area_in_layout_coords(output); int lx = box.x + box.width / 2; int ly = box.y + box.height / 2; @@ -1538,28 +1575,23 @@ view_get_adjacent_output(struct view *view, enum view_edge edge) struct wlr_output *new_output = NULL; struct wlr_output *current_output = output->wlr_output; struct wlr_output_layout *layout = view->server->output_layout; - switch (edge) { - case VIEW_EDGE_LEFT: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_LEFT, current_output, lx, ly); - break; - case VIEW_EDGE_RIGHT: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_RIGHT, current_output, lx, ly); - break; - case VIEW_EDGE_UP: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_UP, current_output, lx, ly); - break; - case VIEW_EDGE_DOWN: - new_output = wlr_output_layout_adjacent_output( - layout, WLR_DIRECTION_DOWN, current_output, lx, ly); - break; - default: - break; + enum wlr_direction direction = get_wlr_direction(edge); + new_output = wlr_output_layout_adjacent_output(layout, direction, + current_output, lx, ly); + + /* + * Optionally wrap around from top-to-bottom or left-to-right, and vice + * versa. + */ + if (wrap && !new_output) { + new_output = wlr_output_layout_farthest_output(layout, + opposite_direction(direction), current_output, lx, ly); } - /* When "adjacent" output is the same as the original, there is no adjacent */ + /* + * When "adjacent" output is the same as the original, there is no + * adjacent + */ if (!new_output || new_output == current_output) { return NULL; } @@ -1633,7 +1665,8 @@ view_move_to_edge(struct view *view, enum view_edge direction, bool snap_to_wind } /* Otherwise, move to edge of next adjacent display, if possible */ - struct output *output = view_get_adjacent_output(view, direction); + struct output *output = + view_get_adjacent_output(view, direction, /* wrap */ false); if (!output) { return; } @@ -1792,7 +1825,7 @@ view_snap_to_edge(struct view *view, enum view_edge edge, if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) { /* We are already tiled for this edge; try to switch outputs */ - output = view_get_adjacent_output(view, edge); + output = view_get_adjacent_output(view, edge, /* wrap */ false); if (!output) { /*