From 478c77a69bb978ca69a210d97bfc1e56d42d94ad Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Tue, 29 Apr 2025 17:37:58 +0000 Subject: [PATCH] Finds paths to icon files using libsfdo. Libsfdo is currently an optional compile time dependency. This means the former code paths are all retained and new ones are wrapped in #if HAVE_LIBSFDO. Behavior should be identical now between the two code paths. Later commits will add the handling of icons specified as absolute paths which both former swaybar code and libsfdo have thus far avoided. --- common/meson.build | 1 + common/sfdo.c | 95 ++++++++++++++++++++++++++++++++++++++++ include/sfdo.h | 19 ++++++++ include/sway/config.h | 5 ++- include/sway/server.h | 20 ++------- include/swaybar/bar.h | 8 ++++ include/swaybar/config.h | 13 +++++- sway/config/bar.c | 15 +++++++ sway/server.c | 4 +- swaybar/bar.c | 3 ++ swaybar/config.c | 14 ++++++ swaybar/ipc.c | 8 ++++ swaybar/meson.build | 9 ++++ swaybar/tray/item.c | 29 +++++++++++- 14 files changed, 220 insertions(+), 23 deletions(-) create mode 100644 common/sfdo.c create mode 100644 include/sfdo.h diff --git a/common/meson.build b/common/meson.build index c0ce1f681..c21aa9e45 100644 --- a/common/meson.build +++ b/common/meson.build @@ -8,6 +8,7 @@ lib_sway_common = static_library( 'loop.c', 'list.c', 'pango.c', + 'sfdo.c', 'stringop.c', 'util.c' ), diff --git a/common/sfdo.c b/common/sfdo.c new file mode 100644 index 000000000..a31c87698 --- /dev/null +++ b/common/sfdo.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include "log.h" +#include "sfdo.h" + +char *sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, int target_size, int scale) { + int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; + struct sfdo_icon_file *icon_file = \ + sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ + target_size, scale, lookup_options); + char *icon_path = NULL; + if (icon_file && icon_file != SFDO_ICON_FILE_INVALID) { + icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); + } + sfdo_icon_file_destroy(icon_file); + return icon_path; +} + +struct sfdo *sfdo_create(char *icon_theme) { + if (!icon_theme) { + goto error_null; + } + + struct sfdo *sfdo = calloc(1, sizeof(struct sfdo)); + if (!sfdo) { + goto error_calloc; + } + + struct sfdo_basedir_ctx *basedir_ctx = sfdo_basedir_ctx_create(); + if (!basedir_ctx) { + goto error_basedir_ctx; + } + + sfdo->desktop_ctx = sfdo_desktop_ctx_create(basedir_ctx); + if (!sfdo->desktop_ctx) { + goto error_desktop_ctx; + } + + sfdo->icon_ctx = sfdo_icon_ctx_create(basedir_ctx); + if (!sfdo->icon_ctx) { + goto error_icon_ctx; + } + + sfdo->desktop_db = sfdo_desktop_db_load(sfdo->desktop_ctx, NULL); + if (!sfdo->desktop_db) { + goto error_desktop_db; + } + + int load_options = SFDO_ICON_THEME_LOAD_OPTIONS_DEFAULT + | SFDO_ICON_THEME_LOAD_OPTION_ALLOW_MISSING + | SFDO_ICON_THEME_LOAD_OPTION_RELAXED; + + sfdo->icon_theme = sfdo_icon_theme_load(sfdo->icon_ctx, icon_theme, load_options); + if (!sfdo->icon_theme) { + goto error_icon_theme; + } + + sfdo_basedir_ctx_destroy(basedir_ctx); + + sway_log(SWAY_INFO, "Successfully setup sfdo with icon theme %s", icon_theme); + return sfdo; + +error_icon_theme: + sfdo_desktop_db_destroy(sfdo->desktop_db); +error_desktop_db: + sfdo_icon_ctx_destroy(sfdo->icon_ctx); +error_icon_ctx: + sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); +error_desktop_ctx: + sfdo_basedir_ctx_destroy(basedir_ctx); +error_basedir_ctx: + free(sfdo); +error_calloc: +error_null: + // it's safe to call with null + sway_log(SWAY_ERROR, "Failed to setup sfdo with icon theme %s", icon_theme); + return NULL; +} + +void sfdo_destroy(struct sfdo *sfdo) { + if (!sfdo) { + sway_log(SWAY_DEBUG, "Null sfdo passed in"); + return; + } + + sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); + sfdo_icon_ctx_destroy(sfdo->icon_ctx); + sfdo_desktop_db_destroy(sfdo->desktop_db); + sfdo_icon_theme_destroy(sfdo->icon_theme); + free(sfdo); + sway_log(SWAY_DEBUG, "Successfully destroyed sfdo"); +} diff --git a/include/sfdo.h b/include/sfdo.h new file mode 100644 index 000000000..a009f3963 --- /dev/null +++ b/include/sfdo.h @@ -0,0 +1,19 @@ +#ifndef _SWAY_SFDO_H +#define _SWAY_SFDO_H + +#include +#include +#include + +struct sfdo { + struct sfdo_desktop_ctx *desktop_ctx; + struct sfdo_icon_ctx *icon_ctx; + struct sfdo_desktop_db *desktop_db; + struct sfdo_icon_theme *icon_theme; +}; + +char *sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, int target_size, int scale); +struct sfdo *sfdo_create(char *icon_theme); +void sfdo_destroy(struct sfdo *sfdo); + +#endif diff --git a/include/sway/config.h b/include/sway/config.h index bb770c6f7..75385b2dd 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -399,8 +399,11 @@ struct bar_config { char *binding_mode_text; } colors; -#if HAVE_TRAY +#if HAVE_TRAY || HAVE_LIBSFDO char *icon_theme; +#endif + +#if HAVE_TRAY struct wl_list tray_bindings; // struct tray_binding::link list_t *tray_outputs; // char * int tray_padding; diff --git a/include/sway/server.h b/include/sway/server.h index 13da0d605..9202cb562 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -8,11 +8,11 @@ #if WLR_HAS_XWAYLAND #include "sway/xwayland.h" #endif + #if HAVE_LIBSFDO -#include -#include -#include +#include "sfdo.h" #endif + struct sway_transaction; struct sway_session_lock { @@ -28,15 +28,6 @@ struct sway_session_lock { struct wl_listener destroy; }; -#if HAVE_LIBSFDO -struct sfdo { - struct sfdo_desktop_ctx *desktop_ctx; - struct sfdo_icon_ctx *icon_ctx; - struct sfdo_desktop_db *desktop_db; - struct sfdo_icon_theme *icon_theme; -}; -#endif - struct sway_server { struct wl_display *wl_display; struct wl_event_loop *wl_event_loop; @@ -210,9 +201,4 @@ void set_rr_scheduling(void); void handle_new_tearing_hint(struct wl_listener *listener, void *data); -#if HAVE_LIBSFDO -struct sfdo *sfdo_create(char *theme); -void sfdo_destroy(struct sfdo *sfdo); -#endif - #endif diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 197d21901..311993372 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -16,6 +16,10 @@ struct swaybar_tray; struct swaybar_workspace; struct loop; +#if HAVE_LIBSFDO +struct sfdo; +#endif + struct swaybar { char *id; char *mode; @@ -50,6 +54,10 @@ struct swaybar { struct swaybar_tray *tray; #endif +#if HAVE_LIBSFDO + struct sfdo *sfdo; +#endif + bool running; }; diff --git a/include/swaybar/config.h b/include/swaybar/config.h index ad58b3c3c..8433b8c78 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -8,6 +8,10 @@ #include "util.h" #include +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + struct box_colors { uint32_t border; uint32_t background; @@ -73,13 +77,20 @@ struct swaybar_config { struct box_colors binding_mode; } colors; -#if HAVE_TRAY +#if HAVE_TRAY || HAVE_LIBSFDO char *icon_theme; +#endif + +#if HAVE_TRAY struct wl_list tray_bindings; // struct tray_binding::link bool tray_hidden; list_t *tray_outputs; // char * int tray_padding; #endif + +#if HAVE_LIBSFDO + struct sfdo *sfdo; +#endif }; #if HAVE_TRAY diff --git a/sway/config/bar.c b/sway/config/bar.c index f4efb276c..58734a11e 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -70,6 +70,14 @@ void free_bar_config(struct bar_config *bar) { free(bar->colors.binding_mode_border); free(bar->colors.binding_mode_bg); free(bar->colors.binding_mode_text); + + // this is to cover the case where tray support is not compiled in + // but we have libsfdo support which implies at least a default + // icon_theme string was allocated +#if HAVE_LIBSFDO && !HAVE_TRAY + free(bar->icone_theme); +#endif + #if HAVE_TRAY list_free_items_and_destroy(bar->tray_outputs); free(bar->icon_theme); @@ -170,6 +178,13 @@ struct bar_config *default_bar_config(void) { bar->colors.binding_mode_bg = NULL; bar->colors.binding_mode_text = NULL; + // we need some default when we initialize sfdo +#if HAVE_LIBSFDO + if (!(bar->icon_theme = strdup("Hicolor"))) { + goto cleanup; + } +#endif + #if HAVE_TRAY bar->tray_padding = 2; wl_list_init(&bar->tray_bindings); diff --git a/sway/server.c b/sway/server.c index 4794f6f50..841c61cce 100644 --- a/sway/server.c +++ b/sway/server.c @@ -70,9 +70,7 @@ #endif #if HAVE_LIBSFDO -#include -#include -#include +#include "sfdo.h" #endif #define SWAY_XDG_SHELL_VERSION 5 diff --git a/swaybar/bar.c b/swaybar/bar.c index 4d20f20f0..5d7854b3c 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -537,6 +537,9 @@ static void free_seats(struct wl_list *list) { void bar_teardown(struct swaybar *bar) { #if HAVE_TRAY destroy_tray(bar->tray); +#endif +#if HAVE_LIBSFDO + sfdo_destroy(bar->config->sfdo); #endif free_outputs(&bar->outputs); free_outputs(&bar->unused_outputs); diff --git a/swaybar/config.c b/swaybar/config.c index 55bfcb722..9e17a7128 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -7,6 +7,10 @@ #include "list.h" #include "log.h" +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + uint32_t parse_position(const char *position) { uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; @@ -131,5 +135,15 @@ void free_config(struct swaybar_config *config) { free(config->icon_theme); #endif + +#if HAVE_LIBSFDO && !HAVE_TRAY + free(config->icon_theme); +#endif + +#if HAVE_LIBSFDO + sfdo_destroy(config->sfdo); + sway_log(SWAY_DEBUG, "Destroyed swaybar sfdo"); +#endif + free(config); } diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 68d8dd32d..e1a6283da 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -18,6 +18,10 @@ #include "stringop.h" #include "util.h" +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { uint32_t size = strlen("workspace \"\"") + strlen(ws); for (size_t i = 0; i < strlen(ws); ++i) { @@ -330,6 +334,10 @@ static bool ipc_parse_config( if ((json_object_object_get_ex(bar_config, "icon_theme", &icon_theme))) { config->icon_theme = strdup(json_object_get_string(icon_theme)); +#if HAVE_LIBSFDO + sfdo_destroy(config->sfdo); + config->sfdo = sfdo_create(config->icon_theme); +#endif } #endif diff --git a/swaybar/meson.build b/swaybar/meson.build index 34bbdeea9..6a1d17461 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build @@ -21,6 +21,15 @@ if have_tray swaybar_deps += sdbus endif +if have_libsfdo + swaybar_deps += [ + sfdo_basedir, + sfdo_desktop, + sfdo_desktop_file, + sfdo_icon + ] +endif + executable( 'swaybar', [ 'bar.c', diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 12929743b..455feda4a 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -18,6 +20,10 @@ #include "stringop.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + // TODO menu static bool sni_ready(struct swaybar_sni *sni) { @@ -420,15 +426,36 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme, char *icon_name = sni->status[0] == 'N' ? sni->attention_icon_name : sni->icon_name; if (icon_name) { + char *icon_path = NULL; +#if !HAVE_LIBSFDO list_t *icon_search_paths = create_list(); list_cat(icon_search_paths, sni->tray->basedirs); if (sni->icon_theme_path) { list_add(icon_search_paths, sni->icon_theme_path); } - char *icon_path = find_icon(sni->tray->themes, icon_search_paths, + icon_path = find_icon(sni->tray->themes, icon_search_paths, icon_name, target_size, icon_theme, &sni->min_size, &sni->max_size); +#else + struct sfdo *sfdo = sni->tray->bar->config->sfdo; + if (sfdo) { + int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; + int scale = 1; + struct sfdo_icon_file *icon_file = \ + sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ + target_size, scale, lookup_options); + if (!icon_file || icon_file == SFDO_ICON_FILE_INVALID) { + sway_log(SWAY_ERROR, "sfdo: icon %s invalid or not found in theme %s at size %d", \ + icon_name, icon_theme, target_size); + } else { + icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); + } + sfdo_icon_file_destroy(icon_file); + } +#endif +#if !HAVE_LIBSFDO list_free(icon_search_paths); +#endif if (icon_path) { cairo_surface_destroy(sni->icon); sni->icon = load_image(icon_path);