by introducing scaled_icon_buffer.
--- /dev/null
+/* 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 */
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);
*/
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;
};
'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',
--- /dev/null
+// 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;
+}
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)
{
#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"
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,
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;
- }
+ 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_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;
+ 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);
}
- /* Initially show non-hover, non-toggled, unrounded variant */
- wlr_scene_node_set_enabled(nodes[0], 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;
}
#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"
/* 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);
}
}
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(
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
}
.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,
.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,