Add FocusOutput action

Fixes #806

Suggested-by: @EysseW
Tested-by: @EysseW
This commit is contained in:
Consolatis 2023-03-05 17:16:23 +01:00 committed by Johan Malm
parent 037dace5bc
commit a0b5a80ce1
5 changed files with 76 additions and 0 deletions

View file

@ -80,6 +80,11 @@ Actions are used in menus and keyboard/mouse bindings.
to Virtual Machines, VNC clients or nested compositors. to Virtual Machines, VNC clients or nested compositors.
A second call will restore all original keybinds. A second call will restore all original keybinds.
*<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="GoToDesktop" to="value" />* *<action name="GoToDesktop" to="value" />*
Switch to workspace. Supported values are "last", "left", "right" or the Switch to workspace. Supported values are "last", "left", "right" or the
full name of a workspace or its index (starting at 1) as configured in full name of a workspace or its index (starting at 1) as configured in

View file

@ -372,6 +372,7 @@ void desktop_move_to_front(struct view *view);
void desktop_move_to_back(struct view *view); void desktop_move_to_back(struct view *view);
void desktop_focus_and_activate_view(struct seat *seat, struct view *view); void desktop_focus_and_activate_view(struct seat *seat, struct view *view);
void desktop_arrange_all_views(struct server *server); void desktop_arrange_all_views(struct server *server);
void desktop_focus_output(struct output *output);
enum lab_cycle_dir { enum lab_cycle_dir {
LAB_CYCLE_DIR_NONE, LAB_CYCLE_DIR_NONE,
@ -418,6 +419,7 @@ void output_init(struct server *server);
void output_manager_init(struct server *server); void output_manager_init(struct server *server);
struct output *output_from_wlr_output(struct server *server, struct output *output_from_wlr_output(struct server *server,
struct wlr_output *wlr_output); struct wlr_output *wlr_output);
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(struct server *server, int lx, int ly);
struct output *output_nearest_to_cursor(struct server *server); struct output *output_nearest_to_cursor(struct server *server);
bool output_is_usable(struct output *output); bool output_is_usable(struct output *output);

View file

@ -61,6 +61,7 @@ enum action_type {
ACTION_TYPE_SEND_TO_DESKTOP, ACTION_TYPE_SEND_TO_DESKTOP,
ACTION_TYPE_SNAP_TO_REGION, ACTION_TYPE_SNAP_TO_REGION,
ACTION_TYPE_TOGGLE_KEYBINDS, ACTION_TYPE_TOGGLE_KEYBINDS,
ACTION_TYPE_FOCUS_OUTPUT,
}; };
const char *action_names[] = { const char *action_names[] = {
@ -90,6 +91,7 @@ const char *action_names[] = {
"SendToDesktop", "SendToDesktop",
"SnapToRegion", "SnapToRegion",
"ToggleKeybinds", "ToggleKeybinds",
"FocusOutput",
NULL NULL
}; };
@ -119,6 +121,9 @@ action_arg_from_xml_node(struct action *action, char *nodename, char *content)
} else if (!strcmp(nodename, "region.action")) { } else if (!strcmp(nodename, "region.action")) {
/* SnapToRegion */ /* SnapToRegion */
action_arg_add_str(action, NULL, content); action_arg_add_str(action, NULL, content);
} else if (!strcmp(nodename, "output.action")) {
/* FocusOutput */
action_arg_add_str(action, NULL, content);
} }
} }
@ -470,6 +475,14 @@ actions_run(struct view *activator, struct server *server,
wlr_log(WLR_DEBUG, "%s keybinds", wlr_log(WLR_DEBUG, "%s keybinds",
server->seat.inhibit_keybinds ? "Disabled" : "Enabled"); server->seat.inhibit_keybinds ? "Disabled" : "Enabled");
break; break;
case ACTION_TYPE_FOCUS_OUTPUT:
if (!arg) {
wlr_log(WLR_ERROR, "Missing argument for FocusOutput");
break;
}
const char *output_name = action_str_from_arg(arg);
desktop_focus_output(output_from_name(server, output_name));
break;
case ACTION_TYPE_INVALID: case ACTION_TYPE_INVALID:
wlr_log(WLR_ERROR, "Not executing unknown action"); wlr_log(WLR_ERROR, "Not executing unknown action");
break; break;

View file

@ -268,6 +268,46 @@ desktop_focus_topmost_mapped_view(struct server *server)
desktop_move_to_front(view); desktop_move_to_front(view);
} }
void
desktop_focus_output(struct output *output)
{
if (!output_is_usable(output) || output->server->input_mode
!= LAB_INPUT_STATE_PASSTHROUGH) {
return;
}
struct view *view;
struct wlr_scene_node *node;
struct wlr_output_layout *layout = output->server->output_layout;
struct wl_list *list_head =
&output->server->workspace_current->tree->children;
wl_list_for_each_reverse(node, list_head, link) {
if (!node->data) {
continue;
}
view = node_view_from_node(node);
if (!isfocusable(view)) {
continue;
}
if (wlr_output_layout_intersects(layout,
output->wlr_output, &view->current)) {
desktop_focus_and_activate_view(&output->server->seat, view);
wlr_cursor_warp(output->server->seat.cursor, NULL,
view->current.x + view->current.width / 2,
view->current.y + view->current.height / 2);
cursor_update_focus(output->server);
return;
}
}
/* No view found on desired output */
struct wlr_box layout_box;
wlr_output_layout_get_box(output->server->output_layout,
output->wlr_output, &layout_box);
wlr_cursor_warp(output->server->seat.cursor, NULL,
layout_box.x + output->usable_area.x + output->usable_area.width / 2,
layout_box.y + output->usable_area.y + output->usable_area.height / 2);
cursor_update_focus(output->server);
}
static struct wlr_surface * static struct wlr_surface *
get_surface_from_layer_node(struct wlr_scene_node *node) get_surface_from_layer_node(struct wlr_scene_node *node)
{ {

View file

@ -8,6 +8,7 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h> #include <assert.h>
#include <strings.h>
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_drm_lease_v1.h> #include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
@ -458,6 +459,21 @@ output_from_wlr_output(struct server *server, struct wlr_output *wlr_output)
return NULL; return NULL;
} }
struct output *
output_from_name(struct server *server, const char *name)
{
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
if (!output_is_usable(output) || !output->wlr_output->name) {
continue;
}
if (!strcasecmp(name, output->wlr_output->name)) {
return output;
}
}
return NULL;
}
struct output * struct output *
output_nearest_to(struct server *server, int lx, int ly) output_nearest_to(struct server *server, int lx, int ly)
{ {