Add Next/PreviousWindowImmediate to switch windows without OSD
Some checks failed
labwc.github.io / notify (push) Has been cancelled

Co-authored-by: @johanmalm
This commit is contained in:
elviosak 2026-04-28 22:42:39 -03:00 committed by Johan Malm
parent bc7498dc6f
commit 6ce25978e7
7 changed files with 94 additions and 9 deletions

View file

@ -84,6 +84,8 @@ struct action_arg_list {
X(SHRINK_TO_EDGE, "ShrinkToEdge") \
X(NEXT_WINDOW, "NextWindow") \
X(PREVIOUS_WINDOW, "PreviousWindow") \
X(NEXT_WINDOW_IMMEDIATE, "NextWindowImmediate") \
X(PREVIOUS_WINDOW_IMMEDIATE, "PreviousWindowImmediate") \
X(RECONFIGURE, "Reconfigure") \
X(SHOW_MENU, "ShowMenu") \
X(TOGGLE_MAXIMIZE, "ToggleMaximize") \
@ -337,6 +339,8 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char
break;
case ACTION_TYPE_NEXT_WINDOW:
case ACTION_TYPE_PREVIOUS_WINDOW:
case ACTION_TYPE_NEXT_WINDOW_IMMEDIATE:
case ACTION_TYPE_PREVIOUS_WINDOW_IMMEDIATE:
if (!strcasecmp(argument, "workspace")) {
if (!strcasecmp(content, "all")) {
action_arg_add_int(action, argument, CYCLE_WORKSPACE_ALL);
@ -1146,6 +1150,21 @@ run_action(struct view *view, struct action *action,
}
break;
}
case ACTION_TYPE_NEXT_WINDOW_IMMEDIATE:
case ACTION_TYPE_PREVIOUS_WINDOW_IMMEDIATE: {
enum lab_cycle_dir dir = (action->type == ACTION_TYPE_NEXT_WINDOW_IMMEDIATE) ?
LAB_CYCLE_DIR_FORWARD : LAB_CYCLE_DIR_BACKWARD;
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),
};
cycle_immediate(dir, filter);
break;
}
case ACTION_TYPE_RECONFIGURE:
kill(getpid(), SIGHUP);
break;

View file

@ -322,6 +322,61 @@ handle_osd_tree_destroy(struct wl_listener *listener, void *data)
free(osd_output);
}
static struct wl_list *prev(struct wl_list *elm) { return elm->prev; }
static struct wl_list *next(struct wl_list *elm) { return elm->next; }
void
cycle_immediate(enum lab_cycle_dir direction, struct cycle_filter filter)
{
if (wl_list_empty(&server.views)) {
return;
}
enum lab_view_criteria criteria =
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER
| LAB_VIEW_CRITERIA_NO_DIALOG;
if (filter.workspace == CYCLE_WORKSPACE_CURRENT) {
criteria |= LAB_VIEW_CRITERIA_CURRENT_WORKSPACE;
}
uint64_t cycle_outputs = get_outputs_by_filter(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 wl_list *head = &server.views;
struct wl_list *(*iter)(struct wl_list *list);
iter = direction == LAB_CYCLE_DIR_FORWARD ? next : prev;
struct wl_list *from = (direction == LAB_CYCLE_DIR_FORWARD) && server.active_view
? &server.active_view->link : head;
for (struct wl_list *elm = iter(from); elm != head; elm = iter(elm)) {
struct view *view = wl_container_of(elm, view, link);
if (!view_matches_criteria(view, criteria)) {
continue;
}
if (filter.output != CYCLE_OUTPUT_ALL) {
if (!view->output || !(cycle_outputs & view->output->id_bit)) {
continue;
}
}
if (cycle_app_id && strcmp(view->app_id, cycle_app_id) != 0) {
continue;
}
if (server.active_view && direction == LAB_CYCLE_DIR_FORWARD) {
/*
* When cycling forward, the current active view needs to be
* sent to back to keep the same sequence and avoid getting
* stuck in the 2 topmost views.
*/
view_move_to_back(server.active_view);
}
desktop_focus_view(view, true);
break;
}
cursor_update_focus();
}
/* Return false on failure */
static bool
init_cycle(struct cycle_filter filter)

View file

@ -80,7 +80,7 @@ struct view_query *
view_query_create(void)
{
struct view_query *query = znew(*query);
/* Must be synced with view_matches_criteria() in window-rules.c */
/* Must be synced with view_matches_rule() in window-rules.c */
query->window_type = LAB_WINDOW_TYPE_INVALID;
query->maximized = VIEW_AXIS_INVALID;
query->decoration = LAB_SSD_MODE_INVALID;
@ -263,8 +263,8 @@ view_get_root(struct view *view)
return view;
}
static bool
matches_criteria(struct view *view, enum lab_view_criteria criteria)
bool
view_matches_criteria(struct view *view, enum lab_view_criteria criteria)
{
if (!view_is_focusable(view)) {
return false;
@ -316,7 +316,7 @@ view_next(struct wl_list *head, struct view *view, enum lab_view_criteria criter
for (elm = elm->next; elm != head; elm = elm->next) {
view = wl_container_of(elm, view, link);
if (matches_criteria(view, criteria)) {
if (view_matches_criteria(view, criteria)) {
return view;
}
}
@ -332,7 +332,7 @@ view_prev(struct wl_list *head, struct view *view, enum lab_view_criteria criter
for (elm = elm->prev; elm != head; elm = elm->prev) {
view = wl_container_of(elm, view, link);
if (matches_criteria(view, criteria)) {
if (view_matches_criteria(view, criteria)) {
return view;
}
}

View file

@ -24,7 +24,7 @@ other_instances_exist(struct view *self, struct view_query *query)
}
static bool
view_matches_criteria(struct window_rule *rule, struct view *view)
view_matches_rule(struct window_rule *rule, struct view *view)
{
struct view_query query = {
.identifier = rule->identifier,
@ -52,7 +52,7 @@ window_rules_apply(struct view *view, enum window_rule_event event)
if (rule->event != event) {
continue;
}
if (view_matches_criteria(rule, view)) {
if (view_matches_rule(rule, view)) {
actions_run(view, &rule->actions, NULL);
}
}
@ -81,7 +81,7 @@ window_rules_get_property(struct view *view, const char *property)
* attribute would still return here if that property was asked
* for.
*/
if (view_matches_criteria(rule, view)) {
if (view_matches_rule(rule, view)) {
if (rule->server_decoration
&& !strcasecmp(property, "serverDecoration")) {
return rule->server_decoration;