action: support NextWindow option window="root|all"

This enables all windows, not just topmost (root) ones, to be included in
the window-switcher. This is helpful when cycling through Gtk applications
with open dialogs because although these child windows will always be
shown on top of their parents, they do not get keyboard focus with the
default configuration.

This also applices to `PreviousWindow`.

Fixes: #3332
Suggested-by: @airtower-luna
This commit is contained in:
Johan Malm 2026-01-24 14:26:30 +00:00
parent 645a7b56ce
commit ff94591578
5 changed files with 29 additions and 4 deletions

View file

@ -125,8 +125,8 @@ Actions are used in menus and keyboard/mouse bindings.
Resize and move the active window back to its untiled or unmaximized
position if it had been maximized or tiled to a direction or region.
*<action name="NextWindow" workspace="current" output="all" identifier="all" />*++
*<action name="PreviousWindow" workspace="current" output="all" identifier="all" />*
*<action name="NextWindow" workspace="current" output="all" identifier="all" window="root"/>*++
*<action name="PreviousWindow" workspace="current" output="all" identifier="all" window="root"/>*
Cycle focus to next/previous window, respectively.
Default keybinds for NextWindow and PreviousWindow are Alt-Tab and
@ -145,6 +145,10 @@ Actions are used in menus and keyboard/mouse bindings.
This determines whether to cycle through all windows or only windows of the
same application as the currently focused window. Default is "all".
*window* [root|all]
This determines whether to cycle through only topmost (root) windows or
all windows including child windows such as dialogs. Default is "root".
*<action name="Reconfigure" />*
Re-load configuration and theme files.

View file

@ -133,4 +133,9 @@ enum cycle_app_id_filter {
CYCLE_APP_ID_CURRENT,
};
enum cycle_window_filter {
CYCLE_WINDOW_ROOT,
CYCLE_WINDOW_ALL,
};
#endif /* LABWC_CONFIG_TYPES_H */

View file

@ -49,6 +49,7 @@ struct cycle_filter {
enum cycle_workspace_filter workspace;
enum cycle_output_filter output;
enum cycle_app_id_filter app_id;
enum cycle_window_filter window;
};
struct cycle_state {

View file

@ -403,6 +403,17 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
}
goto cleanup;
}
if (!strcasecmp(argument, "window")) {
if (!strcasecmp(content, "root")) {
action_arg_add_int(action, argument, CYCLE_WINDOW_ROOT);
} else if (!strcasecmp(content, "all")) {
action_arg_add_int(action, argument, CYCLE_WINDOW_ALL);
} else {
wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)",
action_names[action->type], argument, content);
}
goto cleanup;
}
break;
case ACTION_TYPE_SHOW_MENU:
if (!strcmp(argument, "menu")) {
@ -1174,6 +1185,8 @@ run_action(struct view *view, struct server *server, struct action *action,
CYCLE_OUTPUT_ALL),
.app_id = action_get_int(action, "identifier",
CYCLE_APP_ID_ALL),
.window = action_get_int(action, "window",
CYCLE_WINDOW_ROOT),
};
if (server->input_mode == LAB_INPUT_STATE_CYCLE) {
cycle_step(server, dir);

View file

@ -331,8 +331,10 @@ static bool
init_cycle(struct server *server, struct cycle_filter filter)
{
enum lab_view_criteria criteria =
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER
| LAB_VIEW_CRITERIA_ROOT_TOPLEVEL;
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER;
if (filter.window == CYCLE_WINDOW_ROOT) {
criteria |= LAB_VIEW_CRITERIA_ROOT_TOPLEVEL;
}
if (filter.workspace == CYCLE_WORKSPACE_CURRENT) {
criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
}