From 614c008bea5e1c3ce366679a1048596cf31bf64c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Jun 2025 08:10:18 +0800 Subject: [PATCH] feat: add left-occupied and right-occupied to workspaces_find --- docs/labwc-actions.5.scd | 10 +++--- src/workspaces.c | 73 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index a3c6c6d1..bf760fdb 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -281,8 +281,8 @@ Actions are used in menus and keyboard/mouse bindings. Switch to workspace. *to* The workspace to switch to. Supported values are "current", "last", - "left", "right" or the full name of a workspace or its index (starting - at 1) as configured in rc.xml. + "left", "right", "left-occupied", "right-occupied" or the full name of a + workspace or its index (starting at 1) as configured in rc.xml. *wrap* [yes|no] Wrap around from last desktop to first, and vice versa. Default yes. @@ -469,8 +469,10 @@ Actions that execute other actions. Used in keyboard/mouse bindings. *desktop* The desktop the client is currently on. This can be the number or name of a desktop, or special relative values - "current", "other", "left", "right" or "last". The - "left" and "right" directions will not wrap. + "current", "other", "left", "right", "left-occupied", + "right-occupied" or "last". + The "left" , "right", "left-occupied" and + "right-occupied" directions will not wrap. *tiled* [up|right|down|left|center] Whether the client is tiled (snapped) along the the diff --git a/src/workspaces.c b/src/workspaces.c index 8e9881bc..2ce1f376 100644 --- a/src/workspaces.c +++ b/src/workspaces.c @@ -269,6 +269,75 @@ get_next(struct workspace *current, struct wl_list *workspaces, bool wrap) return wl_container_of(target_link, current, link); } +static bool +workspace_has_views(struct workspace *workspace, struct server *server) +{ + struct view *view; + + for_each_view(view, &server->views, LAB_VIEW_CRITERIA_NO_OMNIPRESENT) { + if (view->workspace == workspace) { + return true; + } + } + return false; +} + +static struct workspace * +get_adjacent_occupied(struct workspace *current, struct wl_list *workspaces, + bool wrap, bool reverse) +{ + struct server *server = current->server; + struct wl_list *start = ¤t->link; + struct wl_list *link = reverse ? start->prev : start->next; + bool has_wrapped = false; + + while (true) { + /* Handle list boundaries */ + if (link == workspaces) { + if (!wrap) { + break; /* No wrapping allowed - stop searching */ + } + if (has_wrapped) { + break; /* Already wrapped once - stop to prevent infinite loop */ + } + /* Wrap around */ + link = reverse ? workspaces->prev : workspaces->next; + has_wrapped = true; + continue; + } + + /* Get the workspace */ + struct workspace *target = wl_container_of(link, target, link); + + /* Check if we've come full circle */ + if (link == start) { + break; + } + + /* Check if it's occupied (and not current) */ + if (target != current && workspace_has_views(target, server)) { + return target; + } + + /* Move to next/prev */ + link = reverse ? link->prev : link->next; + } + + return NULL; /* No occupied workspace found */ +} + +static struct workspace * +get_prev_occupied(struct workspace *current, struct wl_list *workspaces, bool wrap) +{ + return get_adjacent_occupied(current, workspaces, wrap, true); +} + +static struct workspace * +get_next_occupied(struct workspace *current, struct wl_list *workspaces, bool wrap) +{ + return get_adjacent_occupied(current, workspaces, wrap, false); +} + static int _osd_handle_timeout(void *data) { @@ -453,6 +522,10 @@ workspaces_find(struct workspace *anchor, const char *name, bool wrap) return get_prev(anchor, workspaces, wrap); } else if (!strcasecmp(name, "right")) { return get_next(anchor, workspaces, wrap); + } else if (!strcasecmp(name, "left-occupied")) { + return get_prev_occupied(anchor, workspaces, wrap); + } else if (!strcasecmp(name, "right-occupied")) { + return get_next_occupied(anchor, workspaces, wrap); } else { wl_list_for_each(target, workspaces, link) { if (!strcasecmp(target->name, name)) { -- 2.52.0