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);