From 2dc1a41e6d5ef497f45f449098225e9176c0de38 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. Rebased from origin/master. --- common/sfdo.c | 187 +++++---- include/sway/server.h | 5 - sway/server.c | 26 +- swaybar/tray/item.c | 928 ++++++++++++++++++++++-------------------- 4 files changed, 593 insertions(+), 553 deletions(-) diff --git a/common/sfdo.c b/common/sfdo.c index e2e685650..732256f33 100644 --- a/common/sfdo.c +++ b/common/sfdo.c @@ -1,104 +1,123 @@ -#include -#include #include #include #include +#include +#include #include "log.h" #include "sfdo.h" -// this extends libsfdo's behavior to also handle icons specified as absolute paths -char *sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, int target_size, int scale) { - char *icon_path = NULL; - if (icon_name[0] == '/') { - struct stat sb; - if (!stat(icon_name, &sb)) { - icon_path = strdup(icon_name); - } - } else { - 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); - 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; -} +<<<<<<< HEAD + // this extends libsfdo's behavior to also handle icons specified as + // absolute paths + char * + sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, + int target_size, int scale) { + char *icon_path = NULL; + if (icon_name[0] == '/') { + struct stat sb; + if (!stat(icon_name, &sb)) { + icon_path = strdup(icon_name); + } + } else { + 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); + 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); + } +======= + 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); +>>>>>>> 92e27bd9 (Finds paths to icon files using libsfdo. Libsfdo is currently an) + return icon_path; + } -struct sfdo *sfdo_create(char *icon_theme) { - if (!icon_theme) { - goto error_null; - } + 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 *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; - } + 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->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->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; - } + 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; + 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->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); + sfdo_basedir_ctx_destroy(basedir_ctx); - sway_log(SWAY_INFO, "Successfully setup sfdo with icon theme %s", icon_theme); - return sfdo; + 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; -} + 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; - } + 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"); -} + 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/sway/server.h b/include/sway/server.h index ab4caac62..6402206f7 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -211,9 +211,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/sway/server.c b/sway/server.c index 3b77dc88e..71ffcd49f 100644 --- a/sway/server.c +++ b/sway/server.c @@ -71,12 +71,16 @@ #if HAVE_LIBSFDO <<<<<<< HEAD +<<<<<<< HEAD #include "sfdo.h" -======= + ======= #include #include #include ->>>>>>> 8b3ea59a (Clean up build scaffolding for libsfdo and add the creation and) + >>>>>>> 8b3ea59a (Clean up build scaffolding for libsfdo and add the creation and) +======= +#include "sfdo.h" + >>>>>>> 92e27bd9 (Finds paths to icon files using libsfdo. Libsfdo is currently an) #endif #define SWAY_XDG_SHELL_VERSION 5 @@ -84,7 +88,7 @@ #define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1 #define SWAY_PRESENTATION_VERSION 2 -bool allow_unsupported_gpu = false; + bool allow_unsupported_gpu = false; #if WLR_HAS_DRM_BACKEND static void handle_drm_lease_request(struct wl_listener *listener, void *data) { @@ -532,25 +536,13 @@ void server_fini(struct sway_server *server) { wl_list_remove(&server->drm_lease_request.link); } #endif -<<<<<<< HEAD - <<<<<<< HEAD wl_list_remove(&server->tearing_control_new_object.link); - wl_list_remove(&server->xdg_activation_v1_request_activate.link); - wl_list_remove(&server->xdg_activation_v1_new_token.link); - wl_list_remove(&server->request_set_cursor_shape.link); - input_manager_finish(server->input); -======= -======= ->>>>>>> 8b3ea59a (Clean up build scaffolding for libsfdo and add the creation and) + wl_list_remove(&server->tearing_control_new_object.link); wl_list_remove(&server->xdg_activation_v1_request_activate.link); wl_list_remove(&server->xdg_activation_v1_new_token.link); wl_list_remove(&server->request_set_cursor_shape.link); wl_list_remove(&server->new_foreign_toplevel_capture_request.link); input_manager_finish(server->input); -<<<<<<< HEAD ->>>>>>> 170c9c95 (Add support for toplevel capture) -======= ->>>>>>> 8b3ea59a (Clean up build scaffolding for libsfdo and add the creation and) // TODO: free sway-specific resources #if WLR_HAS_XWAYLAND @@ -580,7 +572,7 @@ void server_fini(struct sway_server *server) { #if HAVE_LIBSFDO sfdo_destroy(server->sfdo); #endif ->>>>>>> 8b3ea59a (Clean up build scaffolding for libsfdo and add the creation and) + >>>>>>> 8b3ea59a (Clean up build scaffolding for libsfdo and add the creation and) } bool server_start(struct sway_server *server) { diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index e7b8d4231..c657a6dfb 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -1,3 +1,16 @@ +#include "swaybar/tray/item.h" +#include "cairo_util.h" +#include "list.h" +#include "log.h" +#include "stringop.h" +#include "swaybar/bar.h" +#include "swaybar/config.h" +#include "swaybar/image.h" +#include "swaybar/input.h" +#include "swaybar/tray/host.h" +#include "swaybar/tray/icon.h" +#include "swaybar/tray/tray.h" +#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include #include #include @@ -6,19 +19,6 @@ #include #include #include -#include "swaybar/bar.h" -#include "swaybar/config.h" -#include "swaybar/image.h" -#include "swaybar/input.h" -#include "swaybar/tray/host.h" -#include "swaybar/tray/icon.h" -#include "swaybar/tray/item.h" -#include "swaybar/tray/tray.h" -#include "cairo_util.h" -#include "list.h" -#include "log.h" -#include "stringop.h" -#include "wlr-layer-shell-unstable-v1-client-protocol.h" #if HAVE_LIBSFDO #include "sfdo.h" @@ -27,172 +27,178 @@ // TODO menu static bool sni_ready(struct swaybar_sni *sni) { - return sni->status && (sni->status[0] == 'N' ? // NeedsAttention - sni->attention_icon_name || sni->attention_icon_pixmap : - sni->icon_name || sni->icon_pixmap); + return sni->status && + (sni->status[0] == 'N' ? // NeedsAttention + sni->attention_icon_name || sni->attention_icon_pixmap + : sni->icon_name || sni->icon_pixmap); } static void set_sni_dirty(struct swaybar_sni *sni) { - if (sni_ready(sni)) { - sni->target_size = sni->min_size = sni->max_size = 0; // invalidate previous icon - set_bar_dirty(sni->tray->bar); - } + if (sni_ready(sni)) { + sni->target_size = sni->min_size = sni->max_size = + 0; // invalidate previous icon + set_bar_dirty(sni->tray->bar); + } } static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, - const char *prop, list_t **dest) { - int ret = sd_bus_message_enter_container(msg, 'a', "(iiay)"); - if (ret < 0) { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - return ret; - } + const char *prop, list_t **dest) { + int ret = sd_bus_message_enter_container(msg, 'a', "(iiay)"); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + return ret; + } - if (sd_bus_message_at_end(msg, 0)) { - sway_log(SWAY_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); - return ret; - } + if (sd_bus_message_at_end(msg, 0)) { + sway_log(SWAY_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); + return ret; + } - list_t *pixmaps = create_list(); - if (!pixmaps) { - return -12; // -ENOMEM - } + list_t *pixmaps = create_list(); + if (!pixmaps) { + return -12; // -ENOMEM + } - while (!sd_bus_message_at_end(msg, 0)) { - ret = sd_bus_message_enter_container(msg, 'r', "iiay"); - if (ret < 0) { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - goto error; - } + while (!sd_bus_message_at_end(msg, 0)) { + ret = sd_bus_message_enter_container(msg, 'r', "iiay"); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + goto error; + } - int width, height; - ret = sd_bus_message_read(msg, "ii", &width, &height); - if (ret < 0) { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - goto error; - } + int width, height; + ret = sd_bus_message_read(msg, "ii", &width, &height); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + goto error; + } - const void *pixels; - size_t npixels; - ret = sd_bus_message_read_array(msg, 'y', &pixels, &npixels); - if (ret < 0) { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - goto error; - } + const void *pixels; + size_t npixels; + ret = sd_bus_message_read_array(msg, 'y', &pixels, &npixels); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + goto error; + } - if (height > 0 && width == height) { - sway_log(SWAY_DEBUG, "%s %s: found icon w:%d h:%d", sni->watcher_id, prop, width, height); - struct swaybar_pixmap *pixmap = - malloc(sizeof(struct swaybar_pixmap) + npixels); - pixmap->size = height; + if (height > 0 && width == height) { + sway_log(SWAY_DEBUG, "%s %s: found icon w:%d h:%d", sni->watcher_id, prop, + width, height); + struct swaybar_pixmap *pixmap = + malloc(sizeof(struct swaybar_pixmap) + npixels); + pixmap->size = height; - // convert from network byte order to host byte order - for (int i = 0; i < height * width; ++i) { - ((uint32_t *)pixmap->pixels)[i] = ntohl(((uint32_t *)pixels)[i]); - } + // convert from network byte order to host byte order + for (int i = 0; i < height * width; ++i) { + ((uint32_t *)pixmap->pixels)[i] = ntohl(((uint32_t *)pixels)[i]); + } - list_add(pixmaps, pixmap); - } else { - sway_log(SWAY_DEBUG, "%s %s: discard invalid icon w:%d h:%d", sni->watcher_id, prop, width, height); - } + list_add(pixmaps, pixmap); + } else { + sway_log(SWAY_DEBUG, "%s %s: discard invalid icon w:%d h:%d", + sni->watcher_id, prop, width, height); + } - sd_bus_message_exit_container(msg); - } + sd_bus_message_exit_container(msg); + } - if (pixmaps->length < 1) { - sway_log(SWAY_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); - goto error; - } + if (pixmaps->length < 1) { + sway_log(SWAY_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); + goto error; + } - list_free_items_and_destroy(*dest); - *dest = pixmaps; - sway_log(SWAY_DEBUG, "%s %s no. of icons = %d", sni->watcher_id, prop, - pixmaps->length); + list_free_items_and_destroy(*dest); + *dest = pixmaps; + sway_log(SWAY_DEBUG, "%s %s no. of icons = %d", sni->watcher_id, prop, + pixmaps->length); - return ret; + return ret; error: - list_free_items_and_destroy(pixmaps); - return ret; + list_free_items_and_destroy(pixmaps); + return ret; } static int get_property_callback(sd_bus_message *msg, void *data, - sd_bus_error *error) { - struct swaybar_sni_slot *d = data; - struct swaybar_sni *sni = d->sni; - const char *prop = d->prop; - const char *type = d->type; - void *dest = d->dest; + sd_bus_error *error) { + struct swaybar_sni_slot *d = data; + struct swaybar_sni *sni = d->sni; + const char *prop = d->prop; + const char *type = d->type; + void *dest = d->dest; - int ret; - if (sd_bus_message_is_method_error(msg, NULL)) { - const sd_bus_error *err = sd_bus_message_get_error(msg); - sway_log_importance_t log_lv = SWAY_ERROR; - if ((!strcmp(prop, "IconThemePath")) && - (!strcmp(err->name, SD_BUS_ERROR_UNKNOWN_PROPERTY))) { - log_lv = SWAY_DEBUG; - } - sway_log(log_lv, "%s %s: %s", sni->watcher_id, prop, err->message); - ret = sd_bus_message_get_errno(msg); - goto cleanup; - } + int ret; + if (sd_bus_message_is_method_error(msg, NULL)) { + const sd_bus_error *err = sd_bus_message_get_error(msg); + sway_log_importance_t log_lv = SWAY_ERROR; + if ((!strcmp(prop, "IconThemePath")) && + (!strcmp(err->name, SD_BUS_ERROR_UNKNOWN_PROPERTY))) { + log_lv = SWAY_DEBUG; + } + sway_log(log_lv, "%s %s: %s", sni->watcher_id, prop, err->message); + ret = sd_bus_message_get_errno(msg); + goto cleanup; + } - ret = sd_bus_message_enter_container(msg, 'v', type); - if (ret < 0) { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - goto cleanup; - } + ret = sd_bus_message_enter_container(msg, 'v', type); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + goto cleanup; + } - if (!type) { - ret = read_pixmap(msg, sni, prop, dest); - if (ret < 0) { - goto cleanup; - } - } else { - if (*type == 's' || *type == 'o') { - free(*(char **)dest); - } + if (!type) { + ret = read_pixmap(msg, sni, prop, dest); + if (ret < 0) { + goto cleanup; + } + } else { + if (*type == 's' || *type == 'o') { + free(*(char **)dest); + } - ret = sd_bus_message_read(msg, type, dest); - if (ret < 0) { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - goto cleanup; - } + ret = sd_bus_message_read(msg, type, dest); + if (ret < 0) { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + goto cleanup; + } - if (*type == 's' || *type == 'o') { - char **str = dest; - *str = strdup(*str); - sway_log(SWAY_DEBUG, "%s %s = '%s'", sni->watcher_id, prop, *str); - } else if (*type == 'b') { - sway_log(SWAY_DEBUG, "%s %s = %s", sni->watcher_id, prop, - *(bool *)dest ? "true" : "false"); - } - } + if (*type == 's' || *type == 'o') { + char **str = dest; + *str = strdup(*str); + sway_log(SWAY_DEBUG, "%s %s = '%s'", sni->watcher_id, prop, *str); + } else if (*type == 'b') { + sway_log(SWAY_DEBUG, "%s %s = %s", sni->watcher_id, prop, + *(bool *)dest ? "true" : "false"); + } + } - if (strcmp(prop, "Status") == 0 || (sni->status && (sni->status[0] == 'N' ? - prop[0] == 'A' : has_prefix(prop, "Icon")))) { - set_sni_dirty(sni); - } + if (strcmp(prop, "Status") == 0 || + (sni->status && + (sni->status[0] == 'N' ? prop[0] == 'A' : has_prefix(prop, "Icon")))) { + set_sni_dirty(sni); + } cleanup: - wl_list_remove(&d->link); - free(data); - return ret; + wl_list_remove(&d->link); + free(data); + return ret; } static void sni_get_property_async(struct swaybar_sni *sni, const char *prop, - const char *type, void *dest) { - struct swaybar_sni_slot *data = calloc(1, sizeof(struct swaybar_sni_slot)); - data->sni = sni; - data->prop = prop; - data->type = type; - data->dest = dest; - int ret = sd_bus_call_method_async(sni->tray->bus, &data->slot, sni->service, - sni->path, "org.freedesktop.DBus.Properties", "Get", - get_property_callback, data, "ss", sni->interface, prop); - if (ret >= 0) { - wl_list_insert(&sni->slots, &data->link); - } else { - sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); - free(data); - } + const char *type, void *dest) { + struct swaybar_sni_slot *data = calloc(1, sizeof(struct swaybar_sni_slot)); + data->sni = sni; + data->prop = prop; + data->type = type; + data->dest = dest; + int ret = sd_bus_call_method_async( + sni->tray->bus, &data->slot, sni->service, sni->path, + "org.freedesktop.DBus.Properties", "Get", get_property_callback, data, + "ss", sni->interface, prop); + if (ret >= 0) { + wl_list_insert(&sni->slots, &data->link); + } else { + sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); + free(data); + } } /* @@ -210,362 +216,390 @@ static void sni_get_property_async(struct swaybar_sni *sni, const char *prop, * returns 0, which allows matching to continue. */ static int sni_check_msg_sender(struct swaybar_sni *sni, sd_bus_message *msg, - const char *signal) { - bool has_well_known_names = - sd_bus_creds_get_mask(sd_bus_message_get_creds(msg)) & SD_BUS_CREDS_WELL_KNOWN_NAMES; - if (sni->service[0] == ':' || has_well_known_names) { - sway_log(SWAY_DEBUG, "%s has new %s", sni->watcher_id, signal); - return 1; - } else { - sway_log(SWAY_DEBUG, "%s may have new %s", sni->watcher_id, signal); - return 0; - } + const char *signal) { + bool has_well_known_names = + sd_bus_creds_get_mask(sd_bus_message_get_creds(msg)) & + SD_BUS_CREDS_WELL_KNOWN_NAMES; + if (sni->service[0] == ':' || has_well_known_names) { + sway_log(SWAY_DEBUG, "%s has new %s", sni->watcher_id, signal); + return 1; + } else { + sway_log(SWAY_DEBUG, "%s may have new %s", sni->watcher_id, signal); + return 0; + } } -static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { - struct swaybar_sni *sni = data; - sni_get_property_async(sni, "IconName", "s", &sni->icon_name); - sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); - if (!strcmp(sni->interface, "org.kde.StatusNotifierItem")) { - sni_get_property_async(sni, "IconThemePath", "s", &sni->icon_theme_path); - } - return sni_check_msg_sender(sni, msg, "icon"); +static int handle_new_icon(sd_bus_message *msg, void *data, + sd_bus_error *error) { + struct swaybar_sni *sni = data; + sni_get_property_async(sni, "IconName", "s", &sni->icon_name); + sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); + if (!strcmp(sni->interface, "org.kde.StatusNotifierItem")) { + sni_get_property_async(sni, "IconThemePath", "s", &sni->icon_theme_path); + } + return sni_check_msg_sender(sni, msg, "icon"); } static int handle_new_attention_icon(sd_bus_message *msg, void *data, - sd_bus_error *error) { - struct swaybar_sni *sni = data; - sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); - sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); - return sni_check_msg_sender(sni, msg, "attention icon"); + sd_bus_error *error) { + struct swaybar_sni *sni = data; + sni_get_property_async(sni, "AttentionIconName", "s", + &sni->attention_icon_name); + sni_get_property_async(sni, "AttentionIconPixmap", NULL, + &sni->attention_icon_pixmap); + return sni_check_msg_sender(sni, msg, "attention icon"); } -static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { - struct swaybar_sni *sni = data; - int ret = sni_check_msg_sender(sni, msg, "status"); - if (ret == 1) { - char *status; - int r = sd_bus_message_read(msg, "s", &status); - if (r < 0) { - sway_log(SWAY_ERROR, "%s new status error: %s", sni->watcher_id, strerror(-ret)); - ret = r; - } else { - free(sni->status); - sni->status = strdup(status); - sway_log(SWAY_DEBUG, "%s has new status = '%s'", sni->watcher_id, status); - set_sni_dirty(sni); - } - } else { - sni_get_property_async(sni, "Status", "s", &sni->status); - } +static int handle_new_status(sd_bus_message *msg, void *data, + sd_bus_error *error) { + struct swaybar_sni *sni = data; + int ret = sni_check_msg_sender(sni, msg, "status"); + if (ret == 1) { + char *status; + int r = sd_bus_message_read(msg, "s", &status); + if (r < 0) { + sway_log(SWAY_ERROR, "%s new status error: %s", sni->watcher_id, + strerror(-ret)); + ret = r; + } else { + free(sni->status); + sni->status = strdup(status); + sway_log(SWAY_DEBUG, "%s has new status = '%s'", sni->watcher_id, status); + set_sni_dirty(sni); + } + } else { + sni_get_property_async(sni, "Status", "s", &sni->status); + } - return ret; + return ret; } static void sni_match_signal_async(struct swaybar_sni *sni, char *signal, - sd_bus_message_handler_t callback) { - struct swaybar_sni_slot *slot = calloc(1, sizeof(struct swaybar_sni_slot)); - int ret = sd_bus_match_signal_async(sni->tray->bus, &slot->slot, - sni->service, sni->path, sni->interface, signal, callback, NULL, sni); - if (ret >= 0) { - wl_list_insert(&sni->slots, &slot->link); - } else { - sway_log(SWAY_ERROR, "%s failed to subscribe to signal %s: %s", - sni->service, signal, strerror(-ret)); - free(slot); - } + sd_bus_message_handler_t callback) { + struct swaybar_sni_slot *slot = calloc(1, sizeof(struct swaybar_sni_slot)); + int ret = sd_bus_match_signal_async(sni->tray->bus, &slot->slot, sni->service, + sni->path, sni->interface, signal, + callback, NULL, sni); + if (ret >= 0) { + wl_list_insert(&sni->slots, &slot->link); + } else { + sway_log(SWAY_ERROR, "%s failed to subscribe to signal %s: %s", + sni->service, signal, strerror(-ret)); + free(slot); + } } struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { - struct swaybar_sni *sni = calloc(1, sizeof(struct swaybar_sni)); - if (!sni) { - return NULL; - } - sni->tray = tray; - wl_list_init(&sni->slots); - sni->watcher_id = strdup(id); - char *path_ptr = strchr(id, '/'); - if (!path_ptr) { - sni->service = strdup(id); - sni->path = strdup("/StatusNotifierItem"); - sni->interface = "org.freedesktop.StatusNotifierItem"; - } else { - sni->service = strndup(id, path_ptr - id); - sni->path = strdup(path_ptr); - sni->interface = "org.kde.StatusNotifierItem"; - sni_get_property_async(sni, "IconThemePath", "s", &sni->icon_theme_path); - } + struct swaybar_sni *sni = calloc(1, sizeof(struct swaybar_sni)); + if (!sni) { + return NULL; + } + sni->tray = tray; + wl_list_init(&sni->slots); + sni->watcher_id = strdup(id); + char *path_ptr = strchr(id, '/'); + if (!path_ptr) { + sni->service = strdup(id); + sni->path = strdup("/StatusNotifierItem"); + sni->interface = "org.freedesktop.StatusNotifierItem"; + } else { + sni->service = strndup(id, path_ptr - id); + sni->path = strdup(path_ptr); + sni->interface = "org.kde.StatusNotifierItem"; + sni_get_property_async(sni, "IconThemePath", "s", &sni->icon_theme_path); + } - // Ignored: Category, Id, Title, WindowId, OverlayIconName, - // OverlayIconPixmap, AttentionMovieName, ToolTip - sni_get_property_async(sni, "Status", "s", &sni->status); - sni_get_property_async(sni, "IconName", "s", &sni->icon_name); - sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); - sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); - sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); - sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); - sni_get_property_async(sni, "Menu", "o", &sni->menu); + // Ignored: Category, Id, Title, WindowId, OverlayIconName, + // OverlayIconPixmap, AttentionMovieName, ToolTip + sni_get_property_async(sni, "Status", "s", &sni->status); + sni_get_property_async(sni, "IconName", "s", &sni->icon_name); + sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); + sni_get_property_async(sni, "AttentionIconName", "s", + &sni->attention_icon_name); + sni_get_property_async(sni, "AttentionIconPixmap", NULL, + &sni->attention_icon_pixmap); + sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); + sni_get_property_async(sni, "Menu", "o", &sni->menu); - sni_match_signal_async(sni, "NewIcon", handle_new_icon); - sni_match_signal_async(sni, "NewAttentionIcon", handle_new_attention_icon); - sni_match_signal_async(sni, "NewStatus", handle_new_status); + sni_match_signal_async(sni, "NewIcon", handle_new_icon); + sni_match_signal_async(sni, "NewAttentionIcon", handle_new_attention_icon); + sni_match_signal_async(sni, "NewStatus", handle_new_status); - return sni; + return sni; } void destroy_sni(struct swaybar_sni *sni) { - if (!sni) { - return; - } + if (!sni) { + return; + } - cairo_surface_destroy(sni->icon); - free(sni->watcher_id); - free(sni->service); - free(sni->path); - free(sni->status); - free(sni->icon_name); - list_free_items_and_destroy(sni->icon_pixmap); - free(sni->attention_icon_name); - list_free_items_and_destroy(sni->attention_icon_pixmap); - free(sni->menu); - free(sni->icon_theme_path); + cairo_surface_destroy(sni->icon); + free(sni->watcher_id); + free(sni->service); + free(sni->path); + free(sni->status); + free(sni->icon_name); + list_free_items_and_destroy(sni->icon_pixmap); + free(sni->attention_icon_name); + list_free_items_and_destroy(sni->attention_icon_pixmap); + free(sni->menu); + free(sni->icon_theme_path); - struct swaybar_sni_slot *slot, *slot_tmp; - wl_list_for_each_safe(slot, slot_tmp, &sni->slots, link) { - sd_bus_slot_unref(slot->slot); - free(slot); - } + struct swaybar_sni_slot *slot, *slot_tmp; + wl_list_for_each_safe(slot, slot_tmp, &sni->slots, link) { + sd_bus_slot_unref(slot->slot); + free(slot); + } - free(sni); + free(sni); } -static void handle_click(struct swaybar_sni *sni, int x, int y, - uint32_t button, int delta) { - const char *method = NULL; - struct tray_binding *binding = NULL; - wl_list_for_each(binding, &sni->tray->bar->config->tray_bindings, link) { - if (binding->button == button) { - method = binding->command; - break; - } - } - if (!method) { - static const char *default_bindings[10] = { - "nop", - "Activate", - "SecondaryActivate", - "ContextMenu", - "ScrollUp", - "ScrollDown", - "ScrollLeft", - "ScrollRight", - "nop", - "nop" - }; - method = default_bindings[event_to_x11_button(button)]; - } - if (strcmp(method, "nop") == 0) { - return; - } - if (sni->item_is_menu && strcmp(method, "Activate") == 0) { - method = "ContextMenu"; - } +static void handle_click(struct swaybar_sni *sni, int x, int y, uint32_t button, + int delta) { + const char *method = NULL; + struct tray_binding *binding = NULL; + wl_list_for_each(binding, &sni->tray->bar->config->tray_bindings, link) { + if (binding->button == button) { + method = binding->command; + break; + } + } + if (!method) { + static const char *default_bindings[10] = { + "nop", "Activate", "SecondaryActivate", "ContextMenu", + "ScrollUp", "ScrollDown", "ScrollLeft", "ScrollRight", + "nop", "nop"}; + method = default_bindings[event_to_x11_button(button)]; + } + if (strcmp(method, "nop") == 0) { + return; + } + if (sni->item_is_menu && strcmp(method, "Activate") == 0) { + method = "ContextMenu"; + } - if (has_prefix(method, "Scroll")) { - char dir = method[strlen("Scroll")]; - char *orientation = (dir == 'U' || dir == 'D') ? "vertical" : "horizontal"; - int sign = (dir == 'U' || dir == 'L') ? -1 : 1; + if (has_prefix(method, "Scroll")) { + char dir = method[strlen("Scroll")]; + char *orientation = (dir == 'U' || dir == 'D') ? "vertical" : "horizontal"; + int sign = (dir == 'U' || dir == 'L') ? -1 : 1; - sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, - sni->interface, "Scroll", NULL, NULL, "is", delta*sign, orientation); - } else { - sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, - sni->interface, method, NULL, NULL, "ii", x, y); - } + sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, + sni->interface, "Scroll", NULL, NULL, "is", + delta * sign, orientation); + } else { + sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, + sni->interface, method, NULL, NULL, "ii", x, y); + } } static int cmp_sni_id(const void *item, const void *cmp_to) { - const struct swaybar_sni *sni = item; - return strcmp(sni->watcher_id, cmp_to); + const struct swaybar_sni *sni = item; + return strcmp(sni->watcher_id, cmp_to); } -static enum hotspot_event_handling icon_hotspot_callback( - struct swaybar_output *output, struct swaybar_hotspot *hotspot, - double x, double y, uint32_t button, bool released, void *data) { - sway_log(SWAY_DEBUG, "Clicked on %s", (char *)data); +static enum hotspot_event_handling +icon_hotspot_callback(struct swaybar_output *output, + struct swaybar_hotspot *hotspot, double x, double y, + uint32_t button, bool released, void *data) { + sway_log(SWAY_DEBUG, "Clicked on %s", (char *)data); - struct swaybar_tray *tray = output->bar->tray; - int idx = list_seq_find(tray->items, cmp_sni_id, data); + struct swaybar_tray *tray = output->bar->tray; + int idx = list_seq_find(tray->items, cmp_sni_id, data); - if (idx != -1) { - if (released) { - // Since we handle the pressed event, also handle the released event - // to block it from falling through to a binding in the bar - return HOTSPOT_IGNORE; - } - struct swaybar_sni *sni = tray->items->items[idx]; - // guess global position since wayland doesn't expose it - struct swaybar_config *config = tray->bar->config; - int global_x = output->output_x + config->gaps.left + x; - bool top_bar = config->position & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; - int global_y = output->output_y + (top_bar ? config->gaps.top + y: - (int) output->output_height - config->gaps.bottom - y); + if (idx != -1) { + if (released) { + // Since we handle the pressed event, also handle the released event + // to block it from falling through to a binding in the bar + return HOTSPOT_IGNORE; + } + struct swaybar_sni *sni = tray->items->items[idx]; + // guess global position since wayland doesn't expose it + struct swaybar_config *config = tray->bar->config; + int global_x = output->output_x + config->gaps.left + x; + bool top_bar = config->position & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + int global_y = output->output_y + (top_bar ? config->gaps.top + y + : (int)output->output_height - + config->gaps.bottom - y); - sway_log(SWAY_DEBUG, "Guessing click position at (%d, %d)", global_x, global_y); - handle_click(sni, global_x, global_y, button, 1); // TODO get delta from event - return HOTSPOT_IGNORE; - } else { - sway_log(SWAY_DEBUG, "but it doesn't exist"); - } + sway_log(SWAY_DEBUG, "Guessing click position at (%d, %d)", global_x, + global_y); + handle_click(sni, global_x, global_y, button, + 1); // TODO get delta from event + return HOTSPOT_IGNORE; + } else { + sway_log(SWAY_DEBUG, "but it doesn't exist"); + } - return HOTSPOT_PROCESS; + return HOTSPOT_PROCESS; } -static void reload_sni(struct swaybar_sni *sni, char *icon_theme, int target_size) { - char *icon_name = sni->status[0] == 'N' ? - sni->attention_icon_name : sni->icon_name; - if (icon_name) { - char *icon_path = NULL; +static void reload_sni(struct swaybar_sni *sni, char *icon_theme, + int target_size) { + 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); - } - icon_path = find_icon(sni->tray->themes, icon_search_paths, - icon_name, target_size, icon_theme, - &sni->min_size, &sni->max_size); + 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); + } + icon_path = + find_icon(sni->tray->themes, icon_search_paths, icon_name, target_size, + icon_theme, &sni->min_size, &sni->max_size); #else - // TODO: at some point we will need to make this scaling-aware - int scale = 1; - struct sfdo *sfdo = sni->tray->bar->config->sfdo; - if (sfdo) { - icon_path = sfdo_icon_lookup_extended(sfdo, icon_name, target_size, scale); - if (!icon_path) { - sway_log(SWAY_DEBUG, "sfdo: icon %s invalid or not found in theme %s at size %d", \ - icon_name, icon_theme, target_size); - } - } + // TODO: at some point we will need to make this scaling-aware + int scale = 1; + struct sfdo *sfdo = sni->tray->bar->config->sfdo; + if (sfdo) { + icon_path = + sfdo_icon_lookup_extended(sfdo, icon_name, target_size, scale); + if (!icon_path) { + sway_log(SWAY_DEBUG, + "sfdo: icon %s invalid or not found in theme %s at size %d", + icon_name, icon_theme, target_size); + } +======= + 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); + list_free(icon_search_paths); #endif - if (icon_path) { - cairo_surface_destroy(sni->icon); - sni->icon = load_image(icon_path, target_size, scale); - free(icon_path); - return; - } else { - // the :( icon won't be drawn for a missing icon and whichever old icon was - // loaded will persist if this is not done. one might not have noticed this - // for tray items that have only one icon loaded only once, successfully or - // unsuccessfully. items with multiple icons, such as fcitx5 or other input - // method frameworks make the problem apparent - free(sni->icon); - sni->icon = NULL; - } - } + if (icon_path) { + cairo_surface_destroy(sni->icon); + sni->icon = load_image(icon_path, target_size, scale); + free(icon_path); + return; + } else { + // the :( icon won't be drawn for a missing icon and whichever old icon + // was loaded will persist if this is not done. one might not have noticed + // this for tray items that have only one icon loaded only once, + // successfully or unsuccessfully. items with multiple icons, such as + // fcitx5 or other input method frameworks make the problem apparent + free(sni->icon); + sni->icon = NULL; + } + } - list_t *pixmaps = sni->status[0] == 'N' ? - sni->attention_icon_pixmap : sni->icon_pixmap; - if (pixmaps) { - struct swaybar_pixmap *pixmap = NULL; - int min_error = INT_MAX; - for (int i = 0; i < pixmaps->length; ++i) { - struct swaybar_pixmap *p = pixmaps->items[i]; - int e = abs(target_size - p->size); - if (e < min_error) { - pixmap = p; - min_error = e; - } - } - cairo_surface_destroy(sni->icon); - sni->icon = cairo_image_surface_create_for_data(pixmap->pixels, - CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size, - cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size)); - } + list_t *pixmaps = + sni->status[0] == 'N' ? sni->attention_icon_pixmap : sni->icon_pixmap; + if (pixmaps) { + struct swaybar_pixmap *pixmap = NULL; + int min_error = INT_MAX; + for (int i = 0; i < pixmaps->length; ++i) { + struct swaybar_pixmap *p = pixmaps->items[i]; + int e = abs(target_size - p->size); + if (e < min_error) { + pixmap = p; + min_error = e; + } + } + cairo_surface_destroy(sni->icon); + sni->icon = cairo_image_surface_create_for_data( + pixmap->pixels, CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size, + cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size)); + } } uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, - struct swaybar_sni *sni) { - uint32_t height = output->height * output->scale; - int padding = output->bar->config->tray_padding; - int target_size = height - 2*padding; - if (target_size != sni->target_size && sni_ready(sni)) { - // check if another icon should be loaded - if (target_size < sni->min_size || target_size > sni->max_size) { - reload_sni(sni, output->bar->config->icon_theme, target_size); - } + struct swaybar_sni *sni) { + uint32_t height = output->height * output->scale; + int padding = output->bar->config->tray_padding; + int target_size = height - 2 * padding; + if (target_size != sni->target_size && sni_ready(sni)) { + // check if another icon should be loaded + if (target_size < sni->min_size || target_size > sni->max_size) { + reload_sni(sni, output->bar->config->icon_theme, target_size); + } - sni->target_size = target_size; - } + sni->target_size = target_size; + } - // Passive - if (sni->status && sni->status[0] == 'P') { - return 0; - } + // Passive + if (sni->status && sni->status[0] == 'P') { + return 0; + } - int icon_size; - cairo_surface_t *icon; - if (sni->icon) { - int actual_size = cairo_image_surface_get_height(sni->icon); - icon_size = actual_size < target_size ? - actual_size*(target_size/actual_size) : target_size; - icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); - } else { // draw a :( - icon_size = target_size*0.8; - icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); - cairo_t *cairo_icon = cairo_create(icon); - cairo_set_source_u32(cairo_icon, 0xFF0000FF); - cairo_translate(cairo_icon, icon_size/2, icon_size/2); - cairo_scale(cairo_icon, icon_size/2, icon_size/2); - cairo_arc(cairo_icon, 0, 0, 1, 0, 7); - cairo_fill(cairo_icon); - cairo_set_operator(cairo_icon, CAIRO_OPERATOR_CLEAR); - cairo_arc(cairo_icon, 0.35, -0.3, 0.1, 0, 7); - cairo_fill(cairo_icon); - cairo_arc(cairo_icon, -0.35, -0.3, 0.1, 0, 7); - cairo_fill(cairo_icon); - cairo_arc(cairo_icon, 0, 0.75, 0.5, 3.71238898038469, 5.71238898038469); - cairo_set_line_width(cairo_icon, 0.1); - cairo_stroke(cairo_icon); - cairo_destroy(cairo_icon); - } + int icon_size; + cairo_surface_t *icon; + if (sni->icon) { + int actual_size = cairo_image_surface_get_height(sni->icon); + icon_size = actual_size < target_size + ? actual_size * (target_size / actual_size) + : target_size; + icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); + } else { // draw a :( + icon_size = target_size * 0.8; + icon = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); + cairo_t *cairo_icon = cairo_create(icon); + cairo_set_source_u32(cairo_icon, 0xFF0000FF); + cairo_translate(cairo_icon, icon_size / 2, icon_size / 2); + cairo_scale(cairo_icon, icon_size / 2, icon_size / 2); + cairo_arc(cairo_icon, 0, 0, 1, 0, 7); + cairo_fill(cairo_icon); + cairo_set_operator(cairo_icon, CAIRO_OPERATOR_CLEAR); + cairo_arc(cairo_icon, 0.35, -0.3, 0.1, 0, 7); + cairo_fill(cairo_icon); + cairo_arc(cairo_icon, -0.35, -0.3, 0.1, 0, 7); + cairo_fill(cairo_icon); + cairo_arc(cairo_icon, 0, 0.75, 0.5, 3.71238898038469, 5.71238898038469); + cairo_set_line_width(cairo_icon, 0.1); + cairo_stroke(cairo_icon); + cairo_destroy(cairo_icon); + } - double descaled_padding = (double)padding / output->scale; - double descaled_icon_size = (double)icon_size / output->scale; + double descaled_padding = (double)padding / output->scale; + double descaled_icon_size = (double)icon_size / output->scale; - int size = descaled_icon_size + 2 * descaled_padding; - *x -= size; - int icon_y = floor((output->height - size) / 2.0); + int size = descaled_icon_size + 2 * descaled_padding; + *x -= size; + int icon_y = floor((output->height - size) / 2.0); - cairo_operator_t op = cairo_get_operator(cairo); - cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); + cairo_operator_t op = cairo_get_operator(cairo); + cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); - cairo_matrix_t scale_matrix; - cairo_pattern_t *icon_pattern = cairo_pattern_create_for_surface(icon); - // TODO: check cairo_pattern_status for "ENOMEM" - cairo_matrix_init_scale(&scale_matrix, output->scale, output->scale); - cairo_matrix_translate(&scale_matrix, -(*x + descaled_padding), -(icon_y + descaled_padding)); - cairo_pattern_set_matrix(icon_pattern, &scale_matrix); - cairo_set_source(cairo, icon_pattern); - cairo_rectangle(cairo, *x, icon_y, size, size); - cairo_fill(cairo); + cairo_matrix_t scale_matrix; + cairo_pattern_t *icon_pattern = cairo_pattern_create_for_surface(icon); + // TODO: check cairo_pattern_status for "ENOMEM" + cairo_matrix_init_scale(&scale_matrix, output->scale, output->scale); + cairo_matrix_translate(&scale_matrix, -(*x + descaled_padding), + -(icon_y + descaled_padding)); + cairo_pattern_set_matrix(icon_pattern, &scale_matrix); + cairo_set_source(cairo, icon_pattern); + cairo_rectangle(cairo, *x, icon_y, size, size); + cairo_fill(cairo); - cairo_set_operator(cairo, op); + cairo_set_operator(cairo, op); - cairo_pattern_destroy(icon_pattern); - cairo_surface_destroy(icon); + cairo_pattern_destroy(icon_pattern); + cairo_surface_destroy(icon); - struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); - hotspot->x = *x; - hotspot->y = 0; - hotspot->width = size; - hotspot->height = output->height; - hotspot->callback = icon_hotspot_callback; - hotspot->destroy = free; - hotspot->data = strdup(sni->watcher_id); - wl_list_insert(&output->hotspots, &hotspot->link); + struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); + hotspot->x = *x; + hotspot->y = 0; + hotspot->width = size; + hotspot->height = output->height; + hotspot->callback = icon_hotspot_callback; + hotspot->destroy = free; + hotspot->data = strdup(sni->watcher_id); + wl_list_insert(&output->hotspots, &hotspot->link); - return output->height; + return output->height; }