]> git.mdlowis.com Git - proto/labwc.git/commitdiff
feat: add left-occupied and right-occupied to workspaces_find
authorDreamMaoMao <2523610504@qq.com>
Fri, 6 Jun 2025 00:10:18 +0000 (08:10 +0800)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Fri, 6 Jun 2025 16:35:32 +0000 (18:35 +0200)
docs/labwc-actions.5.scd
src/workspaces.c

index a3c6c6d113bb49ef6b2003806e6c1764e96d1810..bf760fdb417570b1a7ec851797ea05e5b3ad2550 100644 (file)
@@ -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
index 8e9881bc14e1a2f4be56266641213a6a2f57f8cd..2ce1f3768be566a5e359b39c80ea56a8689fa110 100644 (file)
@@ -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 = &current->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)) {