diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 4e7d7ad8..4cb89cd5 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -349,7 +349,7 @@ this is for compatibility with Openbox. ``` -** +** *preview* [yes|no] Preview the contents of the selected window when switching between windows. Default is yes. @@ -363,6 +363,11 @@ this is for compatibility with Openbox. *unshade* [yes|no] Temporarily unshade windows when switching between them and permanently unshade on the final selection. Default is yes. + *order* [focus|age] The order in which windows are cycled. *focus* cycles by + recent focus history, starting with the previously focused window. *age* cycles + by creation/open order, a stable taskbar-style ordering that doesn’t change on + focus. Default is *focus*. + ** *show* [yes|no] Draw the OnScreenDisplay when switching between windows. Default is yes. diff --git a/include/config/rcxml.h b/include/config/rcxml.h index 3e4f15a2..94eb6ebe 100644 --- a/include/config/rcxml.h +++ b/include/config/rcxml.h @@ -186,6 +186,7 @@ struct rcxml { enum cycle_osd_style style; enum cycle_osd_output_criteria output_criteria; char *thumbnail_label_format; + enum window_switcher_order order; } window_switcher; struct wl_list window_rules; /* struct window_rule.link */ diff --git a/include/config/types.h b/include/config/types.h index 757796a6..99c5929e 100644 --- a/include/config/types.h +++ b/include/config/types.h @@ -107,6 +107,11 @@ enum lab_window_type { LAB_WINDOW_TYPE_LEN }; +enum window_switcher_order { + WINDOW_SWITCHER_ORDER_FOCUS, + WINDOW_SWITCHER_ORDER_AGE, +}; + enum cycle_osd_style { CYCLE_OSD_STYLE_CLASSIC, CYCLE_OSD_STYLE_THUMBNAIL, diff --git a/include/labwc.h b/include/labwc.h index 40bff876..3d3ca2a3 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -188,6 +188,7 @@ struct server { struct wl_listener xdg_toplevel_icon_set_icon; struct wl_list views; + uint64_t next_view_creation_id; struct wl_list unmanaged_surfaces; struct seat seat; diff --git a/include/view.h b/include/view.h index 2f8aac85..fae462db 100644 --- a/include/view.h +++ b/include/view.h @@ -174,6 +174,7 @@ struct view { bool mapped; bool been_mapped; + uint64_t creation_id; enum lab_ssd_mode ssd_mode; enum ssd_preference ssd_preference; bool shaded; diff --git a/src/config/rcxml.c b/src/config/rcxml.c index d3694337..eacd3d64 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -1240,6 +1240,15 @@ entry(xmlNode *node, char *nodename, char *content) wlr_log(WLR_ERROR, "Invalid windowSwitcher output %s: " "should be one of all|focused|cursor", content); } + } else if (!strcasecmp(nodename, "order.windowSwitcher")) { + if (!strcasecmp(content, "focus")) { + rc.window_switcher.order = WINDOW_SWITCHER_ORDER_FOCUS; + } else if (!strcasecmp(content, "age")) { + rc.window_switcher.order = WINDOW_SWITCHER_ORDER_AGE; + } else { + wlr_log(WLR_ERROR, "Invalid windowSwitcher order %s: " + "should be one of focus|age", content); + } /* The following two are for backward compatibility only. */ } else if (!strcasecmp(nodename, "show.windowSwitcher")) { @@ -1485,6 +1494,7 @@ rcxml_init(void) rc.window_switcher.criteria = LAB_VIEW_CRITERIA_CURRENT_WORKSPACE | LAB_VIEW_CRITERIA_ROOT_TOPLEVEL | LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER; + rc.window_switcher.order = WINDOW_SWITCHER_ORDER_FOCUS; rc.resize_indicator = LAB_RESIZE_INDICATOR_NEVER; rc.resize_draw_contents = true; diff --git a/src/cycle/cycle.c b/src/cycle/cycle.c index 8eabaf6c..adf9b05e 100644 --- a/src/cycle/cycle.c +++ b/src/cycle/cycle.c @@ -276,13 +276,31 @@ create_osd_on_output(struct output *output) assert(output->cycle_osd.tree); } +static void +insert_view_ordered_by_age(struct wl_list *views, struct view *new_view) +{ + struct wl_list *link = views; + struct view *view; + wl_list_for_each(view, views, cycle_link) { + if (view->creation_id >= new_view->creation_id) { + break; + } + link = &view->cycle_link; + } + wl_list_insert(link, &new_view->cycle_link); +} + /* Return false on failure */ static bool init_cycle(struct server *server) { struct view *view; for_each_view(view, &server->views, rc.window_switcher.criteria) { - wl_list_append(&server->cycle.views, &view->cycle_link); + if (rc.window_switcher.order == WINDOW_SWITCHER_ORDER_AGE) { + insert_view_ordered_by_age(&server->cycle.views, view); + } else { + wl_list_append(&server->cycle.views, &view->cycle_link); + } } if (wl_list_empty(&server->cycle.views)) { wlr_log(WLR_DEBUG, "no views to switch between"); diff --git a/src/xdg.c b/src/xdg.c index 668dfe45..9ff24541 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -1085,6 +1085,7 @@ handle_new_xdg_toplevel(struct wl_listener *listener, void *data) CONNECT_SIGNAL(xdg_surface, xdg_toplevel_view, new_popup); wl_list_insert(&server->views, &view->link); + view->creation_id = server->next_view_creation_id++; } static void diff --git a/src/xwayland.c b/src/xwayland.c index 564fa3e2..17eb995e 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -1036,6 +1036,7 @@ xwayland_view_create(struct server *server, CONNECT_SIGNAL(xsurface, xwayland_view, map_request); wl_list_insert(&view->server->views, &view->link); + view->creation_id = view->server->next_view_creation_id++; if (xsurface->surface) { handle_associate(&xwayland_view->associate, NULL);