From 5ba89ca6f873caaca78f2e0029cb95947e407f4c Mon Sep 17 00:00:00 2001 From: Droc Date: Mon, 29 Jan 2024 07:21:01 -0600 Subject: [PATCH] desktop: support switching to windows in other workspaces --- include/view.h | 19 +++++++++++++ src/desktop.c | 76 ++++++++++++++++++++++---------------------------- src/osd.c | 4 +-- src/view.c | 16 +++++++++++ 4 files changed, 70 insertions(+), 45 deletions(-) diff --git a/include/view.h b/include/view.h index 866b6928..02080fc1 100644 --- a/include/view.h +++ b/include/view.h @@ -299,6 +299,22 @@ bool view_matches_query(struct view *view, struct view_query *query); view; \ view = view_next(head, view, criteria)) +/** + * for_each_view_iter() - iterate in given direction against criteria + * @view: Iterator. + * @head: Head of list to iterate over. + * @iter: Iterator function to get next or previous view + * @criteria: Criteria to match against. + * Example: + * stuct view *(*iter)(struct wl_list *head, struct view *view, + enum lab_view_criteria criteria); + * iter = forwards ? view_next : view_prev; + */ +#define for_each_view_iter(view, head, iter, criteria) \ + for (view = iter(head, NULL, criteria); \ + view; \ + view = iter(head, view, criteria)) + /** * view_next() - Get next view which matches criteria. * @head: Head of list to iterate over. @@ -311,6 +327,9 @@ bool view_matches_query(struct view *view, struct view_query *query); struct view *view_next(struct wl_list *head, struct view *view, enum lab_view_criteria criteria); +struct view *view_prev(struct wl_list *head, struct view *view, + enum lab_view_criteria criteria); + /** * view_array_append() - Append views that match criteria to array * @server: server context diff --git a/src/desktop.c b/src/desktop.c index f7c61ac9..e8672509 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -106,18 +106,6 @@ desktop_focus_view_or_surface(struct seat *seat, struct view *view, } } -static struct wl_list * -get_prev_item(struct wl_list *item) -{ - return item->prev; -} - -static struct wl_list * -get_next_item(struct wl_list *item) -{ - return item->next; -} - static struct view * first_view(struct server *server) { @@ -167,48 +155,52 @@ desktop_cycle_view(struct server *server, struct view *start_view, * - Otherwise select the view second from the top */ + int views = wl_list_length(&server->views); + /* Make sure to have all nodes in their actual ordering */ osd_preview_restore(server); if (!start_view) { - start_view = first_view(server); - if (!start_view || start_view != server->active_view) { + struct view *view1; + enum lab_view_criteria criteria1 = LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER; + for_each_view(view1, &server->views, criteria1) { + if (view_is_focusable(view1)) { + if (server->workspace_current != view1->workspace) { + workspaces_switch_to(view1->workspace, true); + } + start_view = view1; + break; + } + } + if (!start_view || views < 2) { return start_view; /* may be NULL */ } } - struct view *view = start_view; - struct wlr_scene_node *node = &view->scene_tree->node; + struct view *(*iter)(struct wl_list *head, struct view *view, + enum lab_view_criteria criteria); + iter = dir == LAB_CYCLE_DIR_FORWARD ? view_next : view_prev; - assert(node->parent); - struct wl_list *list_head = &node->parent->children; - struct wl_list *list_item = &node->link; - struct wl_list *(*iter)(struct wl_list *list); - - /* Scene nodes are ordered like last node == displayed topmost */ - iter = dir == LAB_CYCLE_DIR_FORWARD ? get_prev_item : get_next_item; - - do { - list_item = iter(list_item); - if (list_item == list_head) { - /* Start / End of list reached. Roll over */ - list_item = iter(list_item); - } - node = wl_container_of(list_item, node, link); - if (!node->data) { - /* We found some non-view, most likely the region overlay */ - view = NULL; - continue; - } - view = node_view_from_node(node); - - enum property skip = window_rules_get_property(view, "skipWindowSwitcher"); - if (view_is_focusable(view) && skip != LAB_PROP_TRUE) { + /* + * TODO: These criteria are the same as in display_osd() in osd.c + * for the time being. + * + * A future improvement could be to make this configurable for example + * in rc.xml and then use rc.cycle_view_criteria (or whatever) both + * here and in the osd.c window-switcher code + */ + enum lab_view_criteria criteria = LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER; + if (views < 2) { + return start_view; + } + struct view *view; + for_each_view_iter(view, &start_view->link, iter, criteria) { + if (view_is_focusable(view)) { return view; } - } while (view != start_view); + } /* No focusable views found, including the one we started with */ - return NULL; + return start_view; } struct view * diff --git a/src/osd.c b/src/osd.c index cff3b429..0dc3dc5a 100644 --- a/src/osd.c +++ b/src/osd.c @@ -409,9 +409,7 @@ display_osd(struct output *output) struct wl_array views; wl_array_init(&views); view_array_append(server, &views, - LAB_VIEW_CRITERIA_CURRENT_WORKSPACE - | LAB_VIEW_CRITERIA_NO_ALWAYS_ON_TOP - | LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER); + LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER); float scale = output->wlr_output->scale; int w = theme->osd_window_switcher_width; diff --git a/src/view.c b/src/view.c index 8a42b304..701556f8 100644 --- a/src/view.c +++ b/src/view.c @@ -136,6 +136,22 @@ view_next(struct wl_list *head, struct view *view, enum lab_view_criteria criter return NULL; } +struct view * +view_prev(struct wl_list *head, struct view *view, enum lab_view_criteria criteria) +{ + assert(head); + + struct wl_list *elm = view ? &view->link : head; + + for (elm = elm->prev; elm != head; elm = elm->prev) { + view = wl_container_of(elm, view, link); + if (matches_criteria(view, criteria)) { + return view; + } + } + return NULL; +} + void view_array_append(struct server *server, struct wl_array *views, enum lab_view_criteria criteria)