diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 56c840a6..fe468cd1 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -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. -**++ -** +**++ +** Cycle focus to next/previous window, respectively. Default keybinds for NextWindow and PreviousWindow are Alt-Tab and @@ -137,6 +137,14 @@ Actions are used in menus and keyboard/mouse bindings. This determines whether to cycle through windows on all workspaces or the current workspace. Default is "current". + *output* [all|focused|cursor] + This determines whether to cycle through windows on all outputs, the focused + output, or the output under the cursor. Default is "all". + + *identifier* [all|current] + This determines whether to cycle through all windows or only windows of the + same application as the currently focused window. Default is "all". + ** Re-load configuration and theme files. diff --git a/docs/rc.xml.all b/docs/rc.xml.all index dd348300..bc9566fe 100644 --- a/docs/rc.xml.all +++ b/docs/rc.xml.all @@ -98,7 +98,7 @@ Some contents are fixed-length and others are variable-length. See "man 5 labwc-config" for details. - + diff --git a/include/config/types.h b/include/config/types.h index 81d8fd36..fc293cd8 100644 --- a/include/config/types.h +++ b/include/config/types.h @@ -128,4 +128,9 @@ enum cycle_output_filter { CYCLE_OUTPUT_FOCUSED, }; +enum cycle_app_id_filter { + CYCLE_APP_ID_ALL, + CYCLE_APP_ID_CURRENT, +}; + #endif /* LABWC_CONFIG_TYPES_H */ diff --git a/include/cycle.h b/include/cycle.h index 2f2c5a2a..d5430cb4 100644 --- a/include/cycle.h +++ b/include/cycle.h @@ -45,6 +45,8 @@ struct cycle_osd_field { struct cycle_filter { enum cycle_workspace_filter workspace; + enum cycle_output_filter output; + enum cycle_app_id_filter app_id; }; struct buf; diff --git a/src/action.c b/src/action.c index 9fb7ca22..5a01d157 100644 --- a/src/action.c +++ b/src/action.c @@ -379,6 +379,30 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char } goto cleanup; } + if (!strcasecmp(argument, "output")) { + if (!strcasecmp(content, "all")) { + action_arg_add_int(action, argument, CYCLE_OUTPUT_ALL); + } else if (!strcasecmp(content, "cursor")) { + action_arg_add_int(action, argument, CYCLE_OUTPUT_CURSOR); + } else if (!strcasecmp(content, "focused")) { + action_arg_add_int(action, argument, CYCLE_OUTPUT_FOCUSED); + } else { + wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)", + action_names[action->type], argument, content); + } + goto cleanup; + } + if (!strcasecmp(argument, "identifier")) { + if (!strcasecmp(content, "all")) { + action_arg_add_int(action, argument, CYCLE_APP_ID_ALL); + } else if (!strcasecmp(content, "current")) { + action_arg_add_int(action, argument, CYCLE_APP_ID_CURRENT); + } 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")) { @@ -1146,6 +1170,10 @@ run_action(struct view *view, struct server *server, struct action *action, struct cycle_filter filter = { .workspace = action_get_int(action, "workspace", rc.window_switcher.workspace_filter), + .output = action_get_int(action, "output", + CYCLE_OUTPUT_ALL), + .app_id = action_get_int(action, "identifier", + CYCLE_APP_ID_ALL), }; if (server->input_mode == LAB_INPUT_STATE_CYCLE) { cycle_step(server, dir); diff --git a/src/cycle/cycle.c b/src/cycle/cycle.c index 9ae5b9b0..e0391f1d 100644 --- a/src/cycle/cycle.c +++ b/src/cycle/cycle.c @@ -325,8 +325,23 @@ init_cycle(struct server *server, struct cycle_filter filter) criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE; } + uint64_t cycle_outputs = + get_outputs_by_filter(server, filter.output); + + const char *cycle_app_id = NULL; + if (filter.app_id == CYCLE_APP_ID_CURRENT && server->active_view) { + cycle_app_id = server->active_view->app_id; + } + struct view *view; for_each_view(view, &server->views, criteria) { + if (!(cycle_outputs & view->output->id_bit)) { + continue; + } + if (cycle_app_id && strcmp(view->app_id, cycle_app_id) != 0) { + continue; + } + if (rc.window_switcher.order == WINDOW_SWITCHER_ORDER_AGE) { insert_view_ordered_by_age(&server->cycle.views, view); } else {