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) {
/*