]> git.mdlowis.com Git - proto/labwc.git/commitdiff
action: make "FocusOutput" behave like "MoveToOutput"
authorOrfeas <38209077+0xfea5@users.noreply.github.com>
Wed, 21 Aug 2024 04:38:44 +0000 (07:38 +0300)
committerAndrew J. Hesford <ajh@sideband.org>
Sat, 24 Aug 2024 18:59:42 +0000 (14:59 -0400)
docs/labwc-actions.5.scd
include/common/direction.h [new file with mode: 0644]
include/labwc.h
include/view.h
src/action.c
src/common/direction.c [new file with mode: 0644]
src/common/meson.build
src/desktop.c
src/output.c
src/view.c

index 1c9e2ec1c812fe7ce345f374883f0b0ee5731da1..6b9dfe8d26db71cc5b8052df1b0e49bd69e1596e 100644 (file)
@@ -194,10 +194,20 @@ Actions are used in menus and keyboard/mouse bindings.
        to 'fullscreen' or 'fullscreenForced', tearing will still only be
        enabled if the active window is in fullscreen mode.
 
-*<action name="FocusOutput" output="HDMI-A-1" />*
-       Give focus to topmost window on given output and warp the cursor
-       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="FocusOutput" output="HDMI-A-1" direction="value" wrap="no" />*
+       Give focus to topmost window on other output and warp the cursor
+       to the center of the window.
+
+       If *output* is specified, the focus is given to the specified output and
+       *direction* is ignored. If *output* is omitted, *direction* may be one
+       of "left", "right", "up" or "down" to indicate that the focus should be
+       given 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 is no.
+
+       If the target output does not contain any windows, the cursor will
+       be centered on the output.
 
 *<action name="MoveToOutput" output="HDMI-A-1" direction="value" wrap="no" />*
        Moves active window to other output, unless the window state is
diff --git a/include/common/direction.h b/include/common/direction.h
new file mode 100644 (file)
index 0000000..bc8cbd0
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_DIRECTION_H
+#define LABWC_DIRECTION_H
+
+#include "view.h"
+
+enum wlr_direction direction_from_view_edge(enum view_edge edge);
+enum wlr_direction direction_get_opposite(enum wlr_direction direction);
+
+#endif /* LABWC_DIRECTION_H */
index 30f9fbafe776d497e8bb21770594d29477464099..810fed13a50a1ea33eeef38389537dac37a1daa7 100644 (file)
@@ -460,6 +460,7 @@ void desktop_focus_view_or_surface(struct seat *seat, struct view *view,
 
 void desktop_arrange_all_views(struct server *server);
 void desktop_focus_output(struct output *output);
+void warp_cursor(struct view *view);
 struct view *desktop_topmost_focusable_view(struct server *server);
 
 /**
@@ -539,6 +540,21 @@ struct output *output_from_wlr_output(struct server *server,
 struct output *output_from_name(struct server *server, const char *name);
 struct output *output_nearest_to(struct server *server, int lx, int ly);
 struct output *output_nearest_to_cursor(struct server *server);
+
+/**
+ * output_get_adjacent() - get next output, in a given direction,
+ * from a given output
+ *
+ * @output: reference output
+ * @edge: direction in which to look for the nearest output
+ * @wrap: if true, wrap around at layout edge
+ *
+ * Note: if output is NULL, the output nearest the cursor will be used as the
+ * reference instead.
+ */
+struct output *output_get_adjacent(struct output *output,
+       enum view_edge edge, bool wrap);
+
 bool output_is_usable(struct output *output);
 void output_update_usable_area(struct output *output);
 void output_update_all_usable_areas(struct server *server, bool layout_changed);
index 0fde958e76335f1183ececdbc29770c80b37413d..6f47f2a77ed6dc988a73e09dcddc9ef1462bdbfe 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef LABWC_VIEW_H
 #define LABWC_VIEW_H
 
+#include "config/rcxml.h"
 #include "config.h"
 #include "ssd.h"
 #include <stdbool.h>
@@ -482,7 +483,7 @@ void view_center(struct view *view, const struct wlr_box *ref);
  * @policy: placement policy to apply
  */
 void view_place_by_policy(struct view *view, bool allow_cursor,
-       enum view_placement_policy);
+       enum view_placement_policy policy);
 void view_constrain_size_to_that_of_usable_area(struct view *view);
 
 void view_restore_to(struct view *view, struct wlr_box geometry);
@@ -548,8 +549,6 @@ 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,
-       bool wrap);
 enum view_axis view_axis_parse(const char *direction);
 enum view_edge view_edge_parse(const char *direction);
 enum view_placement_policy view_placement_parse(const char *policy);
index c38cba70027cfacb2e7eab33eab96a8b3bdddda0..79008566b03ea5a44d32702e64014b7aa2a23b70 100644 (file)
@@ -19,7 +19,6 @@
 #include "menu/menu.h"
 #include "osd.h"
 #include "output-virtual.h"
-#include "placement.h"
 #include "regions.h"
 #include "ssd.h"
 #include "view.h"
@@ -413,11 +412,6 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
                }
                break;
        case ACTION_TYPE_FOCUS_OUTPUT:
-               if (!strcmp(argument, "output")) {
-                       action_arg_add_str(action, argument, content);
-                       goto cleanup;
-               }
-               break;
        case ACTION_TYPE_MOVE_TO_OUTPUT:
                if (!strcmp(argument, "output")) {
                        action_arg_add_str(action, argument, content);
@@ -552,9 +546,6 @@ action_is_valid(struct action *action)
        case ACTION_TYPE_SNAP_TO_REGION:
                arg_name = "region";
                break;
-       case ACTION_TYPE_FOCUS_OUTPUT:
-               arg_name = "output";
-               break;
        case ACTION_TYPE_IF:
        case ACTION_TYPE_FOR_EACH:
                ; /* works around "a label can only be part of a statement" */
@@ -725,6 +716,29 @@ start_window_cycling(struct server *server, enum lab_cycle_dir direction)
        osd_update(server);
 }
 
+static struct output *
+get_target_output(struct output *output, struct server *server,
+       struct action *action)
+{
+       const char *output_name = action_get_str(action, "output", NULL);
+       struct output *target = NULL;
+
+       if (output_name) {
+               target = output_from_name(server, output_name);
+       } else {
+               enum view_edge edge =
+                       action_get_int(action, "direction", VIEW_EDGE_INVALID);
+               bool wrap = action_get_bool(action, "wrap", false);
+               target = output_get_adjacent(output, edge, wrap);
+       }
+
+       if (!target) {
+               wlr_log(WLR_DEBUG, "Invalid output");
+       }
+
+       return target;
+}
+
 void
 actions_run(struct view *activator, struct server *server,
        struct wl_list *actions, uint32_t resize_edges)
@@ -739,6 +753,9 @@ actions_run(struct view *activator, struct server *server,
 
        struct view *view;
        struct action *action;
+       struct output *output;
+       struct output *target;
+
        wl_list_for_each(action, actions, link) {
                wlr_log(WLR_DEBUG, "Handling action %u: %s", action->type,
                        action_names[action->type]);
@@ -1009,25 +1026,10 @@ actions_run(struct view *activator, struct server *server,
                        if (!view) {
                                break;
                        }
-                       const char *output_name = action_get_str(action, "output", NULL);
-                       struct output *target = NULL;
-                       if (output_name) {
-                               target = output_from_name(view->server, output_name);
-                       } else {
-                               enum view_edge edge = action_get_int(action, "direction", 0);
-                               bool wrap = action_get_bool(action, "wrap", false);
-                               target = view_get_adjacent_output(view, edge, wrap);
+                       target = get_target_output(view->output, server, action);
+                       if (target) {
+                               view_move_to_output(view, target);
                        }
-                       if (!target) {
-                               /*
-                                * Most likely because we're already on the
-                                * output furthest in the requested direction
-                                * or the output or direction was invalid.
-                                */
-                               wlr_log(WLR_DEBUG, "Invalid output");
-                               break;
-                       }
-                       view_move_to_output(view, target);
                        break;
                case ACTION_TYPE_FIT_TO_OUTPUT:
                        if (!view) {
@@ -1039,7 +1041,7 @@ actions_run(struct view *activator, struct server *server,
                        if (!view) {
                                break;
                        }
-                       struct output *output = view->output;
+                       output = view->output;
                        if (!output) {
                                break;
                        }
@@ -1058,9 +1060,10 @@ actions_run(struct view *activator, struct server *server,
                        }
                        break;
                case ACTION_TYPE_FOCUS_OUTPUT:
-                       {
-                               const char *output_name = action_get_str(action, "output", NULL);
-                               desktop_focus_output(output_from_name(server, output_name));
+                       output = output_nearest_to_cursor(server);
+                       target = get_target_output(output, server, action);
+                       if (target) {
+                               desktop_focus_output(target);
                        }
                        break;
                case ACTION_TYPE_IF:
diff --git a/src/common/direction.c b/src/common/direction.c
new file mode 100644 (file)
index 0000000..fa88eee
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <assert.h>
+#include <wlr/types/wlr_output_layout.h>
+#include "common/direction.h"
+#include "view.h"
+
+enum wlr_direction
+direction_from_view_edge(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 WLR_DIRECTION_UP;
+       }
+}
+
+enum wlr_direction
+direction_get_opposite(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:
+               assert(0); /* Unreachable */
+               return WLR_DIRECTION_UP;
+       }
+}
index 1569f77555088d45e459554ffde1a8539f5bde87..d9be1d1adc470b3f1b6fe32557b5185ab18061d4 100644 (file)
@@ -1,5 +1,6 @@
 labwc_sources += files(
-       'box.c',
+  'direction.c',
+  'box.c',
   'buf.c',
   'dir.c',
   'fd-util.c',
index 2c0db207817f537eb3dfcb0ca4caebaedd6ffbeb..e30154b3d88a75d56d3b47a7e48bd3ffe29f7fcc 100644 (file)
@@ -197,10 +197,10 @@ desktop_focus_output(struct output *output)
                if (wlr_output_layout_intersects(layout,
                                output->wlr_output, &view->current)) {
                        desktop_focus_view(view, /*raise*/ false);
-                       wlr_cursor_warp(output->server->seat.cursor, NULL,
+                       wlr_cursor_warp(view->server->seat.cursor, NULL,
                                view->current.x + view->current.width / 2,
                                view->current.y + view->current.height / 2);
-                       cursor_update_focus(output->server);
+                       cursor_update_focus(view->server);
                        return;
                }
        }
index a94c7c2dbc20b6bbb47801aaf13aaf56e9ca202f..15c8ed46e9b8857062e78382c6b21aa424c6a3f9 100644 (file)
@@ -18,6 +18,7 @@
 #include <wlr/types/wlr_scene.h>
 #include <wlr/util/region.h>
 #include <wlr/util/log.h>
+#include "common/direction.h"
 #include "common/macros.h"
 #include "common/mem.h"
 #include "common/scene-helpers.h"
@@ -880,6 +881,53 @@ output_nearest_to_cursor(struct server *server)
                server->seat.cursor->y);
 }
 
+struct output *
+output_get_adjacent(struct output *output, enum view_edge edge, bool wrap)
+{
+       if (!output_is_usable(output)) {
+               wlr_log(WLR_ERROR,
+                       "output is not usable, cannot find adjacent output");
+               return NULL;
+       }
+
+       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;
+
+       /* Determine any adjacent output in the appropriate direction */
+       struct wlr_output *new_output = NULL;
+       struct wlr_output *current_output = output->wlr_output;
+       struct wlr_output_layout *layout = output->server->output_layout;
+       enum wlr_direction direction = direction_from_view_edge(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,
+                       direction_get_opposite(direction), current_output, lx, ly);
+       }
+
+       /*
+        * When "adjacent" output is the same as the original, there is no
+        * adjacent
+        */
+       if (!new_output || new_output == current_output) {
+               return NULL;
+       }
+
+       output = output_from_wlr_output(output->server, new_output);
+       if (!output_is_usable(output)) {
+               wlr_log(WLR_ERROR, "invalid output in layout");
+               return NULL;
+       }
+
+       return output;
+}
+
 bool
 output_is_usable(struct output *output)
 {
index 4d8586b834eaa308e195746f701ac2eb6078b949..b1b4265a07779583f9590c1c95b296d943de3124 100644 (file)
@@ -1790,91 +1790,6 @@ 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, bool wrap)
-{
-       assert(view);
-       struct output *output = view->output;
-       if (!output_is_usable(output)) {
-               wlr_log(WLR_ERROR,
-                       "view has no output, cannot find adjacent output");
-               return NULL;
-       }
-
-       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;
-
-       /* Determine any adjacent output in the appropriate direction */
-       struct wlr_output *new_output = NULL;
-       struct wlr_output *current_output = output->wlr_output;
-       struct wlr_output_layout *layout = view->server->output_layout;
-       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
-        */
-       if (!new_output || new_output == current_output) {
-               return NULL;
-       }
-
-       output = output_from_wlr_output(view->server, new_output);
-       if (!output_is_usable(output)) {
-               wlr_log(WLR_ERROR, "invalid output in layout");
-               return NULL;
-       }
-
-       return output;
-}
-
 static int
 shift_view_to_usable_1d(int size,
                int cur_pos, int cur_lo, int cur_extent,
@@ -1936,7 +1851,7 @@ 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, /* wrap */ false);
+               output_get_adjacent(view->output, direction, /* wrap */ false);
        if (!output) {
                return;
        }
@@ -2115,7 +2030,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, /* wrap */ false);
+               output = output_get_adjacent(view->output, edge, /* wrap */ false);
 
                if (!output) {
                        /*