]> git.mdlowis.com Git - proto/labwc.git/commitdiff
ssd: dynamically look up window icons in titlebar for output scales
authortokyo4j <hrak1529@gmail.com>
Sun, 12 Jan 2025 07:43:49 +0000 (16:43 +0900)
committerConsolatis <35009135+Consolatis@users.noreply.github.com>
Sun, 26 Jan 2025 10:46:32 +0000 (11:46 +0100)
by introducing scaled_icon_buffer.

include/common/scaled-icon-buffer.h [new file with mode: 0644]
include/common/scaled-img-buffer.h
include/ssd-internal.h
src/common/meson.build
src/common/scaled-icon-buffer.c [new file with mode: 0644]
src/common/scaled-img-buffer.c
src/ssd/ssd-part.c
src/ssd/ssd-titlebar.c
src/theme.c

diff --git a/include/common/scaled-icon-buffer.h b/include/common/scaled-icon-buffer.h
new file mode 100644 (file)
index 0000000..54f9f17
--- /dev/null
@@ -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 */
index 27569a243be7892b3a709a3e8fb11c1386a52f47..938baeb2cd8e941f0782d1ab0b1e861f0e251592 100644 (file)
@@ -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);
 
index 6d1d7ae746d1d05536e9a16ce584d166683a0d95..d46e7280d78d120890c651e80d5e24016705a84a 100644 (file)
@@ -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;
 };
index 457cffa1a2a236f504cc6e8b2614d1ee6cd1402c..15910f327020c4dfd5d5e3657e0d9c9aa2dd4b47 100644 (file)
@@ -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',
diff --git a/src/common/scaled-icon-buffer.c b/src/common/scaled-icon-buffer.c
new file mode 100644 (file)
index 0000000..1ecc12b
--- /dev/null
@@ -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;
+}
index 99ab7b24398ffafe18ca971c95ebe768b2d273e7..94465d7d734d23f9edf680b226c936812e197c04 100644 (file)
@@ -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)
 {
index 37176cd71f4654391154db3cfe07ec0b109014c6..28bd130cbed2cd80a9a677408fe6a9390f32146f 100644 (file)
@@ -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;
-               }
+       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;
 }
 
index 6ffb1ce136c41128f3e225d696d40948c09331f9..2879b203e7f232ffa349bd0c99ff6a91d0411be6 100644 (file)
@@ -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
 }
 
index cb7809a71e543dfa95c20bf5186fdc7d534c50e0..511bc92326f29bebaa0f228e056b91f2051c8866 100644 (file)
@@ -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,