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 {