]> git.mdlowis.com Git - proto/labwc.git/commitdiff
view: add MoveToOutput `wrap` attribute
authorJohan Malm <jgm323@gmail.com>
Sat, 2 Mar 2024 15:42:05 +0000 (15:42 +0000)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sat, 2 Mar 2024 21:23:01 +0000 (21:23 +0000)
Support `wrap` in view_get_adjacent_output(). This means that when seeking
an adjacent output in a particular direction from an output that is
already furthest in that direction within the layout, rather than
returning NULL, wrap around from the leftmost to the rightmost, or topmost
to the bottommost and vice versa.

Example usage:

    <action name="MoveToOutput" direction="right" wrap="yes" />

Wrap is disabled by default to keep the user interface consistent.

docs/labwc-actions.5.scd
include/view.h
src/action.c
src/view.c

index 9d55f63f02710653b78b19b6df8a89607923dae5..facb2d68fb10a82807c20153ce2dbf0ea0948664 100644 (file)
@@ -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.
 
-*<action name="MoveToOutput" name="HDMI-A-1" direction="value" />*
+*<action name="MoveToOutput" name="HDMI-A-1" direction="value" wrap="no" />*
        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.
+
 *<action name="FitToOutput" />*
        Resizes active window size to width and height of the output when the
        window size exceeds the output size.
index c24fa3d32ce72dcb2cc5b1dacb9c76700245b5b2..b0cb84710313330257dbedfb6a475930ecf3503d 100644 (file)
@@ -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);
 
index e118790633dfcff99b6e03c79828b04251083b69..953f62e752bf4cc331695c5729c7327882e959f8 100644 (file)
@@ -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.");
index e297b725ff4bb3ec830ed72fa355ad50e3d2c910..52627643c236d72a58ddd19512574e7d4d4ce87a 100644 (file)
@@ -2,6 +2,7 @@
 #include <assert.h>
 #include <stdio.h>
 #include <strings.h>
+#include <wlr/types/wlr_output_layout.h>
 #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) {
                        /*