mirror of
https://github.com/labwc/labwc.git
synced 2025-11-02 09:01:47 -05:00
ssd: dynamically look up window icons in titlebar for output scales
by introducing scaled_icon_buffer.
This commit is contained in:
parent
5e29f79258
commit
dc474521ab
9 changed files with 225 additions and 102 deletions
40
include/common/scaled-icon-buffer.h
Normal file
40
include/common/scaled-icon-buffer.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
#ifndef LABWC_SCALED_ICON_BUFFER_H
|
||||
#define LABWC_SCALED_ICON_BUFFER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct wlr_scene_tree;
|
||||
struct wlr_scene_node;
|
||||
struct wlr_scene_buffer;
|
||||
|
||||
struct scaled_icon_buffer {
|
||||
struct scaled_scene_buffer *scaled_buffer;
|
||||
struct wlr_scene_buffer *scene_buffer;
|
||||
struct server *server;
|
||||
char *app_id;
|
||||
char *icon_name;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
/*
|
||||
* Create an auto scaling icon buffer, providing a wlr_scene_buffer node for
|
||||
* display. It gets destroyed automatically when the backing scaled_scene_buffer
|
||||
* is being destroyed which in turn happens automatically when the backing
|
||||
* wlr_scene_buffer (or one of its parents) is being destroyed.
|
||||
*/
|
||||
struct scaled_icon_buffer *scaled_icon_buffer_create(
|
||||
struct wlr_scene_tree *parent, struct server *server,
|
||||
int width, int height);
|
||||
|
||||
void scaled_icon_buffer_set_app_id(struct scaled_icon_buffer *self,
|
||||
const char *app_id);
|
||||
|
||||
void scaled_icon_buffer_set_icon_name(struct scaled_icon_buffer *self,
|
||||
const char *icon_name);
|
||||
|
||||
/* Obtain scaled_icon_buffer from wlr_scene_node */
|
||||
struct scaled_icon_buffer *scaled_icon_buffer_from_node(struct wlr_scene_node *node);
|
||||
|
||||
#endif /* LABWC_SCALED_ICON_BUFFER_H */
|
||||
|
|
@ -66,10 +66,6 @@ struct scaled_img_buffer {
|
|||
struct scaled_img_buffer *scaled_img_buffer_create(struct wlr_scene_tree *parent,
|
||||
struct lab_img *img, int width, int height);
|
||||
|
||||
/* Update image, width and height of the scaled_img_buffer */
|
||||
void scaled_img_buffer_update(struct scaled_img_buffer *self,
|
||||
struct lab_img *img, int width, int height);
|
||||
|
||||
/* Obtain scaled_img_buffer from wlr_scene_node */
|
||||
struct scaled_img_buffer *scaled_img_buffer_from_node(struct wlr_scene_node *node);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,16 @@ struct ssd_button {
|
|||
*/
|
||||
uint8_t state_set;
|
||||
/*
|
||||
* Button nodes for each combination of hover/toggled/rounded states.
|
||||
* nodes[state_set] should be displayed.
|
||||
* Image buffers for each combination of hover/toggled/rounded states.
|
||||
* img_buffers[state_set] is displayed. Some of these can be NULL
|
||||
* (e.g. img_buffers[LAB_BS_ROUNDED] is set only for corner buttons).
|
||||
*
|
||||
* When "type" is LAB_SSD_BUTTON_WINDOW_ICON, these are all NULL and
|
||||
* window_icon is used instead.
|
||||
*/
|
||||
struct wlr_scene_node *nodes[LAB_BS_ALL + 1];
|
||||
struct scaled_img_buffer *img_buffers[LAB_BS_ALL + 1];
|
||||
|
||||
struct scaled_icon_buffer *window_icon;
|
||||
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ labwc_sources += files(
|
|||
'parse-bool.c',
|
||||
'parse-double.c',
|
||||
'scaled-font-buffer.c',
|
||||
'scaled-icon-buffer.c',
|
||||
'scaled-img-buffer.c',
|
||||
'scaled-rect-buffer.c',
|
||||
'scaled-scene-buffer.c',
|
||||
|
|
|
|||
123
src/common/scaled-icon-buffer.c
Normal file
123
src/common/scaled-icon-buffer.c
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "common/macros.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/scaled-icon-buffer.h"
|
||||
#include "common/scaled-scene-buffer.h"
|
||||
#include "common/string-helpers.h"
|
||||
#include "config.h"
|
||||
#include "config/rcxml.h"
|
||||
#include "desktop-entry.h"
|
||||
#include "img/img.h"
|
||||
#include "node.h"
|
||||
|
||||
static struct lab_data_buffer *
|
||||
_create_buffer(struct scaled_scene_buffer *scaled_buffer, double scale)
|
||||
{
|
||||
#if HAVE_LIBSFDO
|
||||
struct scaled_icon_buffer *self = scaled_buffer->data;
|
||||
int icon_size = MIN(self->width, self->height);
|
||||
struct lab_img *img = NULL;
|
||||
|
||||
if (self->icon_name) {
|
||||
img = desktop_entry_load_icon(self->server,
|
||||
self->icon_name, icon_size, scale);
|
||||
} else if (self->app_id) {
|
||||
img = desktop_entry_load_icon_from_app_id(self->server,
|
||||
self->app_id, icon_size, scale);
|
||||
}
|
||||
|
||||
if (!img) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lab_data_buffer *buffer =
|
||||
lab_img_render(img, self->width, self->height, scale);
|
||||
lab_img_destroy(img);
|
||||
|
||||
return buffer;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
_destroy(struct scaled_scene_buffer *scaled_buffer)
|
||||
{
|
||||
struct scaled_icon_buffer *self = scaled_buffer->data;
|
||||
free(self->app_id);
|
||||
free(self->icon_name);
|
||||
free(self);
|
||||
}
|
||||
|
||||
static bool
|
||||
_equal(struct scaled_scene_buffer *scaled_buffer_a,
|
||||
struct scaled_scene_buffer *scaled_buffer_b)
|
||||
{
|
||||
struct scaled_icon_buffer *a = scaled_buffer_a->data;
|
||||
struct scaled_icon_buffer *b = scaled_buffer_b->data;
|
||||
|
||||
return str_equal(a->app_id, b->app_id)
|
||||
&& str_equal(a->icon_name, b->icon_name)
|
||||
&& a->width == b->width
|
||||
&& a->height == b->height;
|
||||
}
|
||||
|
||||
static struct scaled_scene_buffer_impl impl = {
|
||||
.create_buffer = _create_buffer,
|
||||
.destroy = _destroy,
|
||||
.equal = _equal,
|
||||
};
|
||||
|
||||
struct scaled_icon_buffer *
|
||||
scaled_icon_buffer_create(struct wlr_scene_tree *parent, struct server *server,
|
||||
int width, int height)
|
||||
{
|
||||
struct scaled_scene_buffer *scaled_buffer = scaled_scene_buffer_create(
|
||||
parent, &impl, /* drop_buffer */ true);
|
||||
struct scaled_icon_buffer *self = znew(*self);
|
||||
self->scaled_buffer = scaled_buffer;
|
||||
self->scene_buffer = scaled_buffer->scene_buffer;
|
||||
self->server = server;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
scaled_buffer->data = self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
scaled_icon_buffer_set_app_id(struct scaled_icon_buffer *self,
|
||||
const char *app_id)
|
||||
{
|
||||
assert(app_id);
|
||||
if (str_equal(self->app_id, app_id)) {
|
||||
return;
|
||||
}
|
||||
xstrdup_replace(self->app_id, app_id);
|
||||
scaled_scene_buffer_request_update(self->scaled_buffer, self->width, self->height);
|
||||
}
|
||||
|
||||
void
|
||||
scaled_icon_buffer_set_icon_name(struct scaled_icon_buffer *self,
|
||||
const char *icon_name)
|
||||
{
|
||||
assert(icon_name);
|
||||
if (str_equal(self->icon_name, icon_name)) {
|
||||
return;
|
||||
}
|
||||
xstrdup_replace(self->icon_name, icon_name);
|
||||
scaled_scene_buffer_request_update(self->scaled_buffer, self->width, self->height);
|
||||
}
|
||||
|
||||
struct scaled_icon_buffer *
|
||||
scaled_icon_buffer_from_node(struct wlr_scene_node *node)
|
||||
{
|
||||
struct scaled_scene_buffer *scaled_buffer =
|
||||
node_scaled_scene_buffer_from_node(node);
|
||||
assert(scaled_buffer->impl == &impl);
|
||||
return scaled_buffer->data;
|
||||
}
|
||||
|
|
@ -66,18 +66,6 @@ scaled_img_buffer_create(struct wlr_scene_tree *parent, struct lab_img *img,
|
|||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
scaled_img_buffer_update(struct scaled_img_buffer *self, struct lab_img *img,
|
||||
int width, int height)
|
||||
{
|
||||
assert(img);
|
||||
lab_img_destroy(self->img);
|
||||
self->img = lab_img_copy(img);
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
scaled_scene_buffer_request_update(self->scaled_buffer, width, height);
|
||||
}
|
||||
|
||||
struct scaled_img_buffer *
|
||||
scaled_img_buffer_from_node(struct wlr_scene_node *node)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "common/box.h"
|
||||
#include "common/list.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/scaled-icon-buffer.h"
|
||||
#include "common/scaled-img-buffer.h"
|
||||
#include "labwc.h"
|
||||
#include "node.h"
|
||||
|
|
@ -92,6 +93,10 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
|
|||
button_root->node = &parent->node;
|
||||
wlr_scene_node_set_position(button_root->node, x, y);
|
||||
|
||||
struct ssd_button *button = ssd_button_descriptor_create(button_root->node);
|
||||
button->type = type;
|
||||
button->view = view;
|
||||
|
||||
/* Hitbox */
|
||||
float invisible[4] = { 0, 0, 0, 0 };
|
||||
add_scene_rect(part_list, type, parent,
|
||||
|
|
@ -99,29 +104,47 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
|
|||
invisible);
|
||||
|
||||
/* Icons */
|
||||
struct wlr_scene_node *nodes[LAB_BS_ALL + 1] = {0};
|
||||
for (uint8_t state_set = LAB_BS_DEFAULT;
|
||||
state_set <= LAB_BS_ALL; state_set++) {
|
||||
if (!imgs[state_set]) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
/* Initially show non-hover, non-toggled, unrounded variant */
|
||||
wlr_scene_node_set_enabled(nodes[0], true);
|
||||
int button_width = rc.theme->window_button_width;
|
||||
int button_height = rc.theme->window_button_height;
|
||||
/*
|
||||
* Ensure a small amount of horizontal padding within the button
|
||||
* area (2px on each side with the default 26px button width).
|
||||
* A new theme setting could be added to configure this. Using
|
||||
* an existing setting (padding.width or window.button.spacing)
|
||||
* was considered, but these settings have distinct purposes
|
||||
* already and are zero by default.
|
||||
*/
|
||||
int icon_padding = button_width / 10;
|
||||
|
||||
if (type == LAB_SSD_BUTTON_WINDOW_ICON) {
|
||||
struct ssd_part *icon_part = add_scene_part(part_list, type);
|
||||
struct scaled_icon_buffer *icon_buffer =
|
||||
scaled_icon_buffer_create(parent, view->server,
|
||||
button_width - 2 * icon_padding, button_height);
|
||||
assert(icon_buffer);
|
||||
icon_part->node = &icon_buffer->scene_buffer->node;
|
||||
wlr_scene_node_set_position(icon_part->node, icon_padding, 0);
|
||||
button->window_icon = icon_buffer;
|
||||
} else {
|
||||
for (uint8_t state_set = LAB_BS_DEFAULT;
|
||||
state_set <= LAB_BS_ALL; state_set++) {
|
||||
if (!imgs[state_set]) {
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
assert(img_buffer);
|
||||
icon_part->node = &img_buffer->scene_buffer->node;
|
||||
wlr_scene_node_set_enabled(icon_part->node, false);
|
||||
button->img_buffers[state_set] = img_buffer;
|
||||
}
|
||||
/* Initially show non-hover, non-toggled, unrounded variant */
|
||||
wlr_scene_node_set_enabled(
|
||||
&button->img_buffers[LAB_BS_DEFAULT]->scene_buffer->node, true);
|
||||
}
|
||||
|
||||
struct ssd_button *button = ssd_button_descriptor_create(button_root->node);
|
||||
button->type = type;
|
||||
button->view = view;
|
||||
button->state_set = 0;
|
||||
memcpy(button->nodes, nodes, sizeof(nodes));
|
||||
return button_root;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "config.h"
|
||||
#include "common/mem.h"
|
||||
#include "common/scaled-font-buffer.h"
|
||||
#include "common/scaled-icon-buffer.h"
|
||||
#include "common/scaled-img-buffer.h"
|
||||
#include "common/scene-helpers.h"
|
||||
#include "common/string-helpers.h"
|
||||
|
|
@ -127,11 +128,12 @@ update_button_state(struct ssd_button *button, enum lab_button_state state,
|
|||
/* Switch the displayed icon buffer to the new one */
|
||||
for (uint8_t state_set = LAB_BS_DEFAULT;
|
||||
state_set <= LAB_BS_ALL; state_set++) {
|
||||
if (!button->nodes[state_set]) {
|
||||
struct scaled_img_buffer *buffer = button->img_buffers[state_set];
|
||||
if (!buffer) {
|
||||
continue;
|
||||
}
|
||||
wlr_scene_node_set_enabled(
|
||||
button->nodes[state_set], button->state_set == state_set);
|
||||
wlr_scene_node_set_enabled(&buffer->scene_buffer->node,
|
||||
state_set == button->state_set);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -584,37 +586,6 @@ ssd_update_window_icon(struct ssd *ssd)
|
|||
free(ssd->state.app_id);
|
||||
ssd->state.app_id = xstrdup(app_id);
|
||||
|
||||
struct theme *theme = ssd->view->server->theme;
|
||||
|
||||
/*
|
||||
* Ensure a small amount of horizontal padding within the button
|
||||
* area (2px on each side with the default 26px button width).
|
||||
* A new theme setting could be added to configure this. Using
|
||||
* an existing setting (padding.width or window.button.spacing)
|
||||
* was considered, but these settings have distinct purposes
|
||||
* already and are zero by default.
|
||||
*/
|
||||
int icon_padding = theme->window_button_width / 10;
|
||||
int icon_size = MIN(theme->window_button_width - 2 * icon_padding,
|
||||
theme->window_button_height);
|
||||
|
||||
/*
|
||||
* Load/render icons at the max scale of any usable output (at
|
||||
* this point in time). We don't want to be constantly reloading
|
||||
* icons as views are moved between outputs.
|
||||
*
|
||||
* TODO: currently there's no signal to reload/render icons if
|
||||
* outputs are reconfigured and the max scale changes.
|
||||
*/
|
||||
float icon_scale = output_max_scale(ssd->view->server);
|
||||
|
||||
struct lab_img *icon_img = desktop_entry_load_icon_from_app_id(
|
||||
ssd->view->server, app_id, icon_size, icon_scale);
|
||||
if (!icon_img) {
|
||||
wlr_log(WLR_DEBUG, "icon could not be loaded for %s", app_id);
|
||||
return;
|
||||
}
|
||||
|
||||
struct ssd_sub_tree *subtree;
|
||||
FOR_EACH_STATE(ssd, subtree) {
|
||||
struct ssd_part *part = ssd_get_part(
|
||||
|
|
@ -623,23 +594,10 @@ ssd_update_window_icon(struct ssd *ssd)
|
|||
break;
|
||||
}
|
||||
|
||||
/* 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 = LAB_BS_DEFAULT;
|
||||
state_set <= LAB_BS_ALL; state_set++) {
|
||||
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 - 2 * icon_padding,
|
||||
theme->window_button_height);
|
||||
wlr_scene_node_set_position(node, icon_padding, 0);
|
||||
}
|
||||
}
|
||||
assert(button->window_icon);
|
||||
scaled_icon_buffer_set_app_id(button->window_icon, app_id);
|
||||
} FOR_EACH_END
|
||||
|
||||
lab_img_destroy(icon_img);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
12
src/theme.c
12
src/theme.c
|
|
@ -293,12 +293,6 @@ load_buttons(struct theme *theme)
|
|||
.type = LAB_SSD_BUTTON_WINDOW_MENU,
|
||||
.state_set = 0,
|
||||
.fallback_button = (const char[]){ 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 },
|
||||
}, {
|
||||
/* menu icon is loaded again as a fallback of window icon */
|
||||
.name = "menu",
|
||||
.type = LAB_SSD_BUTTON_WINDOW_ICON,
|
||||
.state_set = 0,
|
||||
.fallback_button = (const char[]){ 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 },
|
||||
}, {
|
||||
.name = "iconify",
|
||||
.type = LAB_SSD_BUTTON_ICONIFY,
|
||||
|
|
@ -344,12 +338,6 @@ load_buttons(struct theme *theme)
|
|||
.type = LAB_SSD_BUTTON_WINDOW_MENU,
|
||||
.state_set = LAB_BS_HOVERD,
|
||||
/* no fallback (non-hover variant is used instead) */
|
||||
}, {
|
||||
/* menu_hover icon is loaded again as a fallback of window icon */
|
||||
.name = "menu_hover",
|
||||
.type = LAB_SSD_BUTTON_WINDOW_ICON,
|
||||
.state_set = LAB_BS_HOVERD,
|
||||
/* no fallback (non-hover variant is used instead) */
|
||||
}, {
|
||||
.name = "iconify_hover",
|
||||
.type = LAB_SSD_BUTTON_ICONIFY,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue