ssd: rework titlebar button rendering

- fix that icons for normal/hovered/rounded buttons are not placed
  exactly the same position
- fix blurry window button icons in scaled outputs

This commit introduces lab_img and scaled_img_buffer and uses them for
rendering icons in the window titlebar. Now the process of rendering
button icons are split into 2 phases: loading with lab_img_load() and
creating scene-nodes for them with scaled_img_buffer_create(). This
might incur some additional overhead since we no longer preload icon
textures, but the rendering of icon only happens for the first window
as backing buffers are shared and the overhead won't be noticeable.
This commit also simplifies the process of centering icon buffer in the
button, by creating icon buffers in a fixed geometry via
lab_img_render().
This commit is contained in:
tokyo4j 2024-11-28 19:21:18 +09:00 committed by Hiroaki Yamamoto
parent 9a3412324d
commit 16dbdc64e5
25 changed files with 647 additions and 391 deletions

View file

@ -5,6 +5,7 @@
#include "common/box.h"
#include "common/list.h"
#include "common/mem.h"
#include "common/scaled-img-buffer.h"
#include "labwc.h"
#include "node.h"
#include "ssd-internal.h"
@ -80,35 +81,10 @@ add_scene_buffer(struct wl_list *list, enum ssd_part_type type,
return part;
}
static struct wlr_box
get_scale_box(struct lab_data_buffer *buffer, int container_width,
int container_height)
{
return box_fit_within(buffer->logical_width, buffer->logical_height,
container_width, container_height);
}
void
update_window_icon_buffer(struct wlr_scene_node *button_node,
struct lab_data_buffer *buffer)
{
struct wlr_scene_buffer *scene_buffer =
wlr_scene_buffer_from_node(button_node);
struct wlr_box icon_geo = get_scale_box(buffer,
rc.theme->window_button_width,
rc.theme->window_button_height);
wlr_scene_buffer_set_buffer(scene_buffer, &buffer->base);
wlr_scene_buffer_set_dest_size(scene_buffer,
icon_geo.width, icon_geo.height);
wlr_scene_node_set_position(button_node, icon_geo.x, icon_geo.y);
}
struct ssd_part *
add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
struct wlr_scene_tree *parent,
struct lab_data_buffer *buffers[LAB_BS_ALL + 1],
struct lab_img *imgs[LAB_BS_ALL + 1],
int x, int y, struct view *view)
{
struct ssd_part *button_root = add_scene_part(part_list, type);
@ -125,18 +101,15 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
/* Icons */
struct wlr_scene_node *nodes[LAB_BS_ALL + 1] = {0};
for (uint8_t state_set = 0; state_set <= LAB_BS_ALL; state_set++) {
if (!buffers[state_set]) {
if (!imgs[state_set]) {
continue;
}
struct lab_data_buffer *icon_buffer = buffers[state_set];
struct wlr_box icon_geo = get_scale_box(icon_buffer,
rc.theme->window_button_width, rc.theme->window_button_height);
struct ssd_part *icon_part = add_scene_buffer(part_list, type,
parent, &icon_buffer->base, icon_geo.x, icon_geo.y);
/* Make sure big icons are scaled down if necessary */
wlr_scene_buffer_set_dest_size(
wlr_scene_buffer_from_node(icon_part->node),
icon_geo.width, icon_geo.height);
struct ssd_part *icon_part = add_scene_part(part_list, type);
struct scaled_img_buffer *img_buffer = scaled_img_buffer_create(
parent, imgs[state_set], rc.theme->window_button_width,
rc.theme->window_button_height, /* padding */ 0);
assert(img_buffer);
icon_part->node = &img_buffer->scene_buffer->node;
wlr_scene_node_set_enabled(icon_part->node, false);
nodes[state_set] = icon_part->node;
}

View file

@ -7,11 +7,13 @@
#include "config.h"
#include "common/mem.h"
#include "common/scaled-font-buffer.h"
#include "common/scaled-img-buffer.h"
#include "common/scene-helpers.h"
#include "common/string-helpers.h"
#if HAVE_LIBSFDO
#include "desktop-entry.h"
#endif
#include "img/img.h"
#include "labwc.h"
#include "node.h"
#include "ssd-internal.h"
@ -73,20 +75,20 @@ ssd_titlebar_create(struct ssd *ssd)
int y = (theme->titlebar_height - theme->window_button_height) / 2;
wl_list_for_each(b, &rc.title_buttons_left, link) {
struct lab_data_buffer **buffers =
theme->window[active].buttons[b->type];
struct lab_img **imgs =
theme->window[active].button_imgs[b->type];
add_scene_button(&subtree->parts, b->type, parent,
buffers, x, y, view);
imgs, x, y, view);
x += theme->window_button_width + theme->window_button_spacing;
}
x = width - theme->window_titlebar_padding_width + theme->window_button_spacing;
wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
x -= theme->window_button_width + theme->window_button_spacing;
struct lab_data_buffer **buffers =
theme->window[active].buttons[b->type];
struct lab_img **imgs =
theme->window[active].button_imgs[b->type];
add_scene_button(&subtree->parts, b->type, parent,
buffers, x, y, view);
imgs, x, y, view);
}
} FOR_EACH_END
@ -343,6 +345,9 @@ ssd_titlebar_destroy(struct ssd *ssd)
if (ssd->state.app_id) {
zfree(ssd->state.app_id);
}
if (ssd->state.icon_img) {
lab_img_destroy(ssd->state.icon_img);
}
wlr_scene_node_destroy(&ssd->titlebar.tree->node);
ssd->titlebar.tree = NULL;
@ -593,9 +598,9 @@ ssd_update_window_icon(struct ssd *ssd)
* was considered, but these settings have distinct purposes
* already and are zero by default.
*/
int hpad = theme->window_button_width / 10;
int icon_size = MIN(theme->window_button_width - 2 * hpad,
theme->window_button_height);
int icon_padding = theme->window_button_width / 10;
int icon_size = MIN(theme->window_button_width - 2 * icon_padding,
theme->window_button_height - 2 * icon_padding);
/*
* Load/render icons at the max scale of any usable output (at
@ -607,9 +612,9 @@ ssd_update_window_icon(struct ssd *ssd)
*/
float icon_scale = output_max_scale(ssd->view->server);
struct lab_data_buffer *icon_buffer = desktop_entry_icon_lookup(
struct lab_img *icon_img = desktop_entry_icon_lookup(
ssd->view->server, app_id, icon_size, icon_scale);
if (!icon_buffer) {
if (!icon_img) {
wlr_log(WLR_DEBUG, "icon could not be loaded for %s", app_id);
return;
}
@ -625,14 +630,22 @@ ssd_update_window_icon(struct ssd *ssd)
/* Replace all the buffers in the button with the window icon */
struct ssd_button *button = node_ssd_button_from_node(part->node);
for (uint8_t state_set = 0; state_set <= LAB_BS_ALL; state_set++) {
if (button->nodes[state_set]) {
update_window_icon_buffer(button->nodes[state_set],
icon_buffer);
struct wlr_scene_node *node = button->nodes[state_set];
if (node) {
struct scaled_img_buffer *img_buffer =
scaled_img_buffer_from_node(node);
scaled_img_buffer_update(img_buffer, icon_img,
theme->window_button_width,
theme->window_button_height,
icon_padding);
}
}
} FOR_EACH_END
wlr_buffer_drop(&icon_buffer->base);
if (ssd->state.icon_img) {
lab_img_destroy(ssd->state.icon_img);
}
ssd->state.icon_img = icon_img;
#endif
}