* Create a scene-tree of OSD for an output.
* This sets output->cycle_osd.{items,tree}.
*/
- void (*create)(struct output *output, struct wl_array *views);
+ void (*create)(struct output *output);
/*
* Update output->cycle_osd.tree to highlight
* server->cycle_state.selected_view.
/* Set when in cycle (alt-tab) mode */
struct cycle_state {
struct view *selected_view;
+ struct wl_list views;
bool preview_was_shaded;
bool preview_was_enabled;
struct wlr_scene_node *preview_node;
const struct view_impl *impl;
struct wl_list link;
+ /* This is cleared when the view is not in the cycle list */
+ struct wl_list cycle_link;
+
/*
* The primary output that the view is displayed on. Specifically:
*
struct view *view_prev(struct wl_list *head, struct view *view,
enum lab_view_criteria criteria);
-/*
- * Same as `view_next()` except that they iterate one whole cycle rather than
- * stopping at the list-head
- */
-struct view *view_next_no_head_stop(struct wl_list *head, struct view *from,
- enum lab_view_criteria criteria);
-struct view *view_prev_no_head_stop(struct wl_list *head, struct view *from,
- enum lab_view_criteria criteria);
-
/**
* view_array_append() - Append views that match criteria to array
* @server: server context
#include <wlr/types/wlr_scene.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
-#include "common/array.h"
#include "common/lab-scene-rect.h"
+#include "common/list.h"
#include "common/scene-helpers.h"
#include "config/rcxml.h"
#include "labwc.h"
wlr_scene_node_set_position(&rect->tree->node, geo.x, geo.y);
}
-/*
- * Returns the view to select next in the window switcher.
- * If !start_view, the second focusable view is returned.
- */
+/* Returns the view to select next in the window switcher. */
static struct view *
-get_next_selected_view(struct server *server, struct view *start_view,
- enum lab_cycle_dir dir)
+get_next_selected_view(struct server *server, enum lab_cycle_dir dir)
{
- struct view *(*iter)(struct wl_list *head, struct view *view,
- enum lab_view_criteria criteria);
- bool forwards = dir == LAB_CYCLE_DIR_FORWARD;
- iter = forwards ? view_next_no_head_stop : view_prev_no_head_stop;
-
- enum lab_view_criteria criteria = rc.window_switcher.criteria;
-
- /*
- * Views are listed in stacking order, topmost first. Usually the
- * topmost view is already focused, so when iterating in the forward
- * direction we pre-select the view second from the top:
- *
- * View #1 (on top, currently focused)
- * View #2 (pre-selected)
- * View #3
- * ...
- */
- if (!start_view && forwards) {
- start_view = iter(&server->views, NULL, criteria);
+ struct cycle_state *cycle = &server->cycle;
+ assert(cycle->selected_view);
+ assert(!wl_list_empty(&server->cycle.views));
+
+ struct wl_list *link;
+ if (dir == LAB_CYCLE_DIR_FORWARD) {
+ link = cycle->selected_view->cycle_link.next;
+ if (link == &server->cycle.views) {
+ link = link->next;
+ }
+ } else {
+ link = cycle->selected_view->cycle_link.prev;
+ if (link == &server->cycle.views) {
+ link = link->prev;
+ }
}
+ struct view *view = wl_container_of(link, view, cycle_link);
+ return view;
+}
- return iter(&server->views, start_view, criteria);
+static struct view *
+get_first_view(struct wl_list *views)
+{
+ assert(!wl_list_empty(views));
+ struct view *view = wl_container_of(views->next, view, cycle_link);
+ return view;
}
void
return;
}
+ struct view *selected_view = cycle->selected_view;
+ struct view *selected_view_prev =
+ get_next_selected_view(server, LAB_CYCLE_DIR_BACKWARD);
+
destroy_cycle(server);
if (init_cycle(server)) {
- /* TODO: try to select the same view */
- cycle->selected_view = get_next_selected_view(server, NULL,
- LAB_CYCLE_DIR_FORWARD);
+ /*
+ * Preserve the selected view (or its previous view) if it's
+ * still in the cycle list
+ */
+ if (selected_view->cycle_link.next) {
+ cycle->selected_view = selected_view;
+ } else if (selected_view_prev->cycle_link.next) {
+ cycle->selected_view = selected_view_prev;
+ } else {
+ /* should be unreachable */
+ wlr_log(WLR_ERROR, "could not find view to select");
+ cycle->selected_view = get_first_view(&server->cycle.views);
+ }
update_cycle(server);
} else {
/* Failed to re-init window switcher, exit */
return;
}
- server->cycle.selected_view = get_next_selected_view(server,
- server->cycle.selected_view, direction);
+ struct view *active_view = server->active_view;
+ if (active_view && active_view->cycle_link.next) {
+ /* Select the active view it's in the cycle list */
+ server->cycle.selected_view = active_view;
+ } else {
+ /* Otherwise, select the first view in the cycle list */
+ server->cycle.selected_view = get_first_view(&server->cycle.views);
+ }
+ /* Pre-select the next view in the given direction */
+ server->cycle.selected_view = get_next_selected_view(server, direction);
seat_focus_override_begin(&server->seat,
LAB_INPUT_STATE_CYCLE, LAB_CURSOR_DEFAULT);
{
assert(server->input_mode == LAB_INPUT_STATE_CYCLE);
- server->cycle.selected_view = get_next_selected_view(server,
- server->cycle.selected_view, direction);
+ server->cycle.selected_view = get_next_selected_view(server, direction);
update_cycle(server);
}
}
static void
-create_osd_on_output(struct output *output, struct wl_array *views)
+create_osd_on_output(struct output *output)
{
if (!output_is_usable(output)) {
return;
}
- get_osd_impl()->create(output, views);
+ get_osd_impl()->create(output);
assert(output->cycle_osd.tree);
}
static bool
init_cycle(struct server *server)
{
- struct wl_array views;
- wl_array_init(&views);
- view_array_append(server, &views, rc.window_switcher.criteria);
- if (wl_array_len(&views) <= 0) {
+ struct view *view;
+ for_each_view(view, &server->views, rc.window_switcher.criteria) {
+ 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");
- wl_array_release(&views);
return false;
}
case CYCLE_OSD_OUTPUT_ALL: {
struct output *output;
wl_list_for_each(output, &server->outputs, link) {
- create_osd_on_output(output, &views);
+ create_osd_on_output(output);
}
break;
}
case CYCLE_OSD_OUTPUT_POINTER:
- create_osd_on_output(output_nearest_to_cursor(server), &views);
+ create_osd_on_output(output_nearest_to_cursor(server));
break;
case CYCLE_OSD_OUTPUT_KEYBOARD: {
struct output *output;
/* Fallback to pointer, if there is no active_view */
output = output_nearest_to_cursor(server);
}
- create_osd_on_output(output, &views);
+ create_osd_on_output(output);
break;
}
}
}
- wl_array_release(&views);
return true;
}
server->cycle.preview_outline = NULL;
}
+ struct view *view, *tmp;
+ wl_list_for_each_safe(view, tmp, &server->cycle.views, cycle_link) {
+ wl_list_remove(&view->cycle_link);
+ view->cycle_link = (struct wl_list){0};
+ }
+
server->cycle.selected_view = NULL;
}
#include <wlr/types/wlr_scene.h>
#include <wlr/util/box.h>
#include <wlr/util/log.h>
-#include "common/array.h"
#include "common/buf.h"
#include "common/font.h"
#include "common/lab-scene-rect.h"
#include "common/list.h"
+#include "common/mem.h"
#include "common/string-helpers.h"
#include "config/rcxml.h"
#include "cycle.h"
#include "scaled-buffer/scaled-font-buffer.h"
#include "scaled-buffer/scaled-icon-buffer.h"
#include "theme.h"
+#include "view.h"
#include "workspaces.h"
struct cycle_osd_classic_item {
}
static void
-cycle_osd_classic_create(struct output *output, struct wl_array *views)
+cycle_osd_classic_create(struct output *output)
{
assert(!output->cycle_osd.tree && wl_list_empty(&output->cycle_osd.items));
int padding = theme->osd_border_width + switcher_theme->padding;
bool show_workspace = wl_list_length(&rc.workspace_config.workspaces) > 1;
const char *workspace_name = server->workspaces.current->name;
+ int nr_views = wl_list_length(&server->cycle.views);
struct wlr_box output_box;
wlr_output_layout_get_box(server->output_layout, output->wlr_output,
if (switcher_theme->width_is_percent) {
w = output_box.width * switcher_theme->width / 100;
}
- int h = wl_array_len(views) * switcher_theme->item_height + 2 * padding;
+ int h = nr_views * switcher_theme->item_height + 2 * padding;
if (show_workspace) {
/* workspace indicator */
h += switcher_theme->item_height;
}
/* Draw text for each node */
- struct view **view;
- wl_array_for_each(view, views) {
+ struct view *view;
+ wl_list_for_each(view, &server->cycle.views, cycle_link) {
struct cycle_osd_classic_item *item = znew(*item);
wl_list_append(&output->cycle_osd.items, &item->base.link);
- item->base.view = *view;
+ item->base.view = view;
item->base.tree = wlr_scene_tree_create(output->cycle_osd.tree);
node_descriptor_create(&item->base.tree->node,
LAB_NODE_CYCLE_OSD_ITEM, NULL, item);
w - 2 * padding, switcher_theme->item_height, (float[4]) {0});
wlr_scene_node_set_position(&hitbox->node, padding, y);
- create_fields_scene(server, *view, item->normal_tree,
+ create_fields_scene(server, view, item->normal_tree,
text_color, bg_color, field_widths_sum, x, y);
- create_fields_scene(server, *view, item->active_tree,
+ create_fields_scene(server, view, item->active_tree,
text_color, active_bg_color, field_widths_sum, x, y);
y += switcher_theme->item_height;
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_scene.h>
#include "config/rcxml.h"
-#include "common/array.h"
#include "common/box.h"
#include "common/buf.h"
#include "common/lab-scene-rect.h"
#include "common/list.h"
+#include "common/mem.h"
#include "cycle.h"
#include "labwc.h"
#include "node.h"
}
static void
-cycle_osd_thumbnail_create(struct output *output, struct wl_array *views)
+cycle_osd_thumbnail_create(struct output *output)
{
assert(!output->cycle_osd.tree && wl_list_empty(&output->cycle_osd.items));
output->cycle_osd.tree = wlr_scene_tree_create(output->cycle_osd_tree);
- int nr_views = wl_array_len(views);
+ int nr_views = wl_list_length(&server->cycle.views);
assert(nr_views > 0);
int nr_rows, nr_cols;
get_items_geometry(output, theme, nr_views, &nr_rows, &nr_cols);
/* items */
- struct view **view;
+ struct view *view;
int index = 0;
- wl_array_for_each(view, views) {
+ wl_list_for_each(view, &server->cycle.views, cycle_link) {
struct cycle_osd_thumbnail_item *item = create_item_scene(
- output->cycle_osd.tree, *view, output);
+ output->cycle_osd.tree, view, output);
if (!item) {
break;
}
wl_list_init(&server->views);
wl_list_init(&server->unmanaged_surfaces);
+ wl_list_init(&server->cycle.views);
server->scene = wlr_scene_create();
if (!server->scene) {
return NULL;
}
-struct view *
-view_next_no_head_stop(struct wl_list *head, struct view *from,
- enum lab_view_criteria criteria)
-{
- assert(head);
-
- struct wl_list *elm = from ? &from->link : head;
-
- struct wl_list *end = elm;
- for (elm = elm->next; elm != end; elm = elm->next) {
- if (elm == head) {
- continue;
- }
- struct view *view = wl_container_of(elm, view, link);
- if (matches_criteria(view, criteria)) {
- return view;
- }
- }
- return from;
-}
-
-struct view *
-view_prev_no_head_stop(struct wl_list *head, struct view *from,
- enum lab_view_criteria criteria)
-{
- assert(head);
-
- struct wl_list *elm = from ? &from->link : head;
-
- struct wl_list *end = elm;
- for (elm = elm->prev; elm != end; elm = elm->prev) {
- if (elm == head) {
- continue;
- }
- struct view *view = wl_container_of(elm, view, link);
- if (matches_criteria(view, criteria)) {
- return view;
- }
- }
- return from;
-}
-
void
view_array_append(struct server *server, struct wl_array *views,
enum lab_view_criteria criteria)