From: Orfeas <38209077+0xfea5@users.noreply.github.com> Date: Wed, 21 Aug 2024 04:38:44 +0000 (+0300) Subject: action: make "FocusOutput" behave like "MoveToOutput" X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=dda47a5e14b33e49ed8349cd9a6546f78fded2a9;p=proto%2Flabwc.git action: make "FocusOutput" behave like "MoveToOutput" --- diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 1c9e2ec1..6b9dfe8d 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -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. -** - 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. +** + 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. ** 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 index 00000000..bc8cbd0c --- /dev/null +++ b/include/common/direction.h @@ -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 */ diff --git a/include/labwc.h b/include/labwc.h index 30f9fbaf..810fed13 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -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); diff --git a/include/view.h b/include/view.h index 0fde958e..6f47f2a7 100644 --- a/include/view.h +++ b/include/view.h @@ -2,6 +2,7 @@ #ifndef LABWC_VIEW_H #define LABWC_VIEW_H +#include "config/rcxml.h" #include "config.h" #include "ssd.h" #include @@ -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); diff --git a/src/action.c b/src/action.c index c38cba70..79008566 100644 --- a/src/action.c +++ b/src/action.c @@ -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 index 00000000..fa88eee4 --- /dev/null +++ b/src/common/direction.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#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; + } +} diff --git a/src/common/meson.build b/src/common/meson.build index 1569f775..d9be1d1a 100644 --- a/src/common/meson.build +++ b/src/common/meson.build @@ -1,5 +1,6 @@ labwc_sources += files( - 'box.c', + 'direction.c', + 'box.c', 'buf.c', 'dir.c', 'fd-util.c', diff --git a/src/desktop.c b/src/desktop.c index 2c0db207..e30154b3 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -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; } } diff --git a/src/output.c b/src/output.c index a94c7c2d..15c8ed46 100644 --- a/src/output.c +++ b/src/output.c @@ -18,6 +18,7 @@ #include #include #include +#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) { diff --git a/src/view.c b/src/view.c index 4d8586b8..b1b4265a 100644 --- a/src/view.c +++ b/src/view.c @@ -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) { /*