From 00f0a46ef7587afe4aec4c070cf3bb781fa43120 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Thu, 30 Oct 2025 02:51:05 +0900 Subject: [PATCH] osd: generalize osd_{classic,thumbnail}_item This allows us to share common codes for dealing with osd items. For example: - Get the clicked osd item to focus its associated window - Scroll the items when their total height is taller than output height --- include/osd.h | 6 ++++++ include/output.h | 2 +- src/osd/osd-classic.c | 23 ++++++++++++----------- src/osd/osd-thumbnail.c | 34 ++++++++++++++++++---------------- src/osd/osd.c | 7 +++++-- src/output.c | 2 +- 6 files changed, 43 insertions(+), 31 deletions(-) diff --git a/include/osd.h b/include/osd.h index 2af02ee6..3397ccf3 100644 --- a/include/osd.h +++ b/include/osd.h @@ -69,6 +69,12 @@ bool osd_field_is_valid(struct window_switcher_field *field); void osd_field_free(struct window_switcher_field *field); /* Internal API */ +struct osd_item { + struct view *view; + struct wlr_scene_tree *tree; + struct wl_list link; +}; + struct osd_impl { /* * Create a scene-tree of OSD for an output. diff --git a/include/output.h b/include/output.h index 888f62c7..7c34abc5 100644 --- a/include/output.h +++ b/include/output.h @@ -20,7 +20,7 @@ struct output { struct wlr_scene_buffer *workspace_osd; struct osd_scene { - struct wl_array items; /* struct osd_scene_item */ + struct wl_list items; /* struct osd_item */ struct wlr_scene_tree *tree; } osd_scene; diff --git a/src/osd/osd-classic.c b/src/osd/osd-classic.c index 4ed05c41..df33caac 100644 --- a/src/osd/osd-classic.c +++ b/src/osd/osd-classic.c @@ -8,9 +8,11 @@ #include "common/buf.h" #include "common/font.h" #include "common/lab-scene-rect.h" +#include "common/list.h" #include "common/string-helpers.h" #include "config/rcxml.h" #include "labwc.h" +#include "node.h" #include "osd.h" #include "output.h" #include "scaled-buffer/scaled-font-buffer.h" @@ -19,7 +21,7 @@ #include "workspaces.h" struct osd_classic_item { - struct view *view; + struct osd_item base; struct wlr_scene_tree *normal_tree, *active_tree; }; @@ -76,7 +78,7 @@ create_fields_scene(struct server *server, struct view *view, static void osd_classic_create(struct output *output, struct wl_array *views) { - assert(!output->osd_scene.tree); + assert(!output->osd_scene.tree && wl_list_empty(&output->osd_scene.items)); struct server *server = output->server; struct theme *theme = server->theme; @@ -155,9 +157,10 @@ osd_classic_create(struct output *output, struct wl_array *views) /* Draw text for each node */ struct view **view; wl_array_for_each(view, views) { - struct osd_classic_item *item = - wl_array_add(&output->osd_scene.items, sizeof(*item)); - item->view = *view; + struct osd_classic_item *item = znew(*item); + wl_list_append(&output->osd_scene.items, &item->base.link); + item->base.view = *view; + item->base.tree = wlr_scene_tree_create(output->osd_scene.tree); /* * OSD border * +---------------------------------+ @@ -177,10 +180,8 @@ osd_classic_create(struct output *output, struct wl_array *views) int x = padding + switcher_theme->item_active_border_width + switcher_theme->item_padding_x; - struct wlr_scene_tree *item_root = - wlr_scene_tree_create(output->osd_scene.tree); - item->normal_tree = wlr_scene_tree_create(item_root); - item->active_tree = wlr_scene_tree_create(item_root); + item->normal_tree = wlr_scene_tree_create(item->base.tree); + item->active_tree = wlr_scene_tree_create(item->base.tree); wlr_scene_node_set_enabled(&item->active_tree->node, false); float *active_bg_color = switcher_theme->item_active_bg_color; @@ -219,8 +220,8 @@ static void osd_classic_update(struct output *output) { struct osd_classic_item *item; - wl_array_for_each(item, &output->osd_scene.items) { - bool active = item->view == output->server->osd_state.cycle_view; + wl_list_for_each(item, &output->osd_scene.items, base.link) { + bool active = item->base.view == output->server->osd_state.cycle_view; wlr_scene_node_set_enabled(&item->normal_tree->node, !active); wlr_scene_node_set_enabled(&item->active_tree->node, active); } diff --git a/src/osd/osd-thumbnail.c b/src/osd/osd-thumbnail.c index ad29ebe8..14d7c846 100644 --- a/src/osd/osd-thumbnail.c +++ b/src/osd/osd-thumbnail.c @@ -8,7 +8,9 @@ #include "common/array.h" #include "common/box.h" #include "common/lab-scene-rect.h" +#include "common/list.h" #include "labwc.h" +#include "node.h" #include "osd.h" #include "output.h" #include "scaled-buffer/scaled-font-buffer.h" @@ -17,8 +19,7 @@ #include "view.h" struct osd_thumbnail_item { - struct view *view; - struct wlr_scene_tree *tree; + struct osd_item base; struct scaled_font_buffer *normal_title; struct scaled_font_buffer *active_title; struct lab_scene_rect *active_bg; @@ -124,10 +125,11 @@ create_item_scene(struct wlr_scene_tree *parent, struct view *view, return NULL; } - struct osd_thumbnail_item *item = - wl_array_add(&output->osd_scene.items, sizeof(*item)); - item->tree = wlr_scene_tree_create(parent); - item->view = view; + struct osd_thumbnail_item *item = znew(*item); + wl_list_append(&output->osd_scene.items, &item->base.link); + struct wlr_scene_tree *tree = wlr_scene_tree_create(parent); + item->base.tree = tree; + item->base.view = view; /* background for selected item */ struct lab_scene_rect_options opts = { @@ -138,13 +140,13 @@ create_item_scene(struct wlr_scene_tree *parent, struct view *view, .width = switcher_theme->item_width, .height = switcher_theme->item_height, }; - item->active_bg = lab_scene_rect_create(item->tree, &opts); + item->active_bg = lab_scene_rect_create(tree, &opts); /* thumbnail */ struct wlr_buffer *thumb_buffer = render_thumb(output, view); if (thumb_buffer) { struct wlr_scene_buffer *thumb_scene_buffer = - wlr_scene_buffer_create(item->tree, thumb_buffer); + wlr_scene_buffer_create(tree, thumb_buffer); wlr_buffer_drop(thumb_buffer); struct wlr_box thumb_box = box_fit_within( thumb_buffer->width, thumb_buffer->height, @@ -156,17 +158,17 @@ create_item_scene(struct wlr_scene_tree *parent, struct view *view, } /* title */ - item->normal_title = create_title(item->tree, switcher_theme, + item->normal_title = create_title(tree, switcher_theme, view->title, theme->osd_label_text_color, theme->osd_bg_color, title_y); - item->active_title = create_title(item->tree, switcher_theme, + item->active_title = create_title(tree, switcher_theme, view->title, theme->osd_label_text_color, switcher_theme->item_active_bg_color, title_y); /* icon */ int icon_size = switcher_theme->item_icon_size; - struct scaled_icon_buffer *icon_buffer = scaled_icon_buffer_create( - item->tree, server, icon_size, icon_size); + struct scaled_icon_buffer *icon_buffer = + scaled_icon_buffer_create(tree, server, icon_size, icon_size); scaled_icon_buffer_set_view(icon_buffer, view); int x = (switcher_theme->item_width - icon_size) / 2; int y = title_y - padding - icon_size + 10; /* slide by 10px */ @@ -210,7 +212,7 @@ get_items_geometry(struct output *output, struct theme *theme, static void osd_thumbnail_create(struct output *output, struct wl_array *views) { - assert(!output->osd_scene.tree); + assert(!output->osd_scene.tree && wl_list_empty(&output->osd_scene.items)); struct server *server = output->server; struct theme *theme = server->theme; @@ -236,7 +238,7 @@ osd_thumbnail_create(struct output *output, struct wl_array *views) } int x = (index % nr_cols) * switcher_theme->item_width + padding; int y = (index / nr_cols) * switcher_theme->item_height + padding; - wlr_scene_node_set_position(&item->tree->node, x, y); + wlr_scene_node_set_position(&item->base.tree->node, x, y); index++; } @@ -266,8 +268,8 @@ static void osd_thumbnail_update(struct output *output) { struct osd_thumbnail_item *item; - wl_array_for_each(item, &output->osd_scene.items) { - bool active = (item->view == output->server->osd_state.cycle_view); + wl_list_for_each(item, &output->osd_scene.items, base.link) { + bool active = (item->base.view == output->server->osd_state.cycle_view); wlr_scene_node_set_enabled(&item->active_bg->tree->node, active); wlr_scene_node_set_enabled( &item->active_title->scene_buffer->node, active); diff --git a/src/osd/osd.c b/src/osd/osd.c index 865a58dd..6191640e 100644 --- a/src/osd/osd.c +++ b/src/osd/osd.c @@ -24,12 +24,15 @@ destroy_osd_scenes(struct server *server) { struct output *output; wl_list_for_each(output, &server->outputs, link) { + struct osd_item *item, *tmp; + wl_list_for_each_safe(item, tmp, &output->osd_scene.items, link) { + wl_list_remove(&item->link); + free(item); + } if (output->osd_scene.tree) { wlr_scene_node_destroy(&output->osd_scene.tree->node); output->osd_scene.tree = NULL; } - wl_array_release(&output->osd_scene.items); - wl_array_init(&output->osd_scene.items); } } diff --git a/src/output.c b/src/output.c index adee3f9d..70266d5c 100644 --- a/src/output.c +++ b/src/output.c @@ -500,7 +500,7 @@ handle_new_output(struct wl_listener *listener, void *data) wl_signal_add(&wlr_output->events.request_state, &output->request_state); wl_list_init(&output->regions); - wl_array_init(&output->osd_scene.items); + wl_list_init(&output->osd_scene.items); /* * Create layer-trees (background, bottom, top and overlay) and