From fa0abaf7cfecf1dc433717d53379d6942226c2bb Mon Sep 17 00:00:00 2001 From: Konstantin Pospelov Date: Sat, 8 Jun 2019 18:11:32 +0300 Subject: [PATCH] swaybar: do not retry search for tray icons In case a tray icon cannot be found or does not have a desirable size, swaybar retries the search again and again, which increases load on disk and CPU. This commit solves it by storing target_size for each icon, so that swaybar does not search for an icon of some size if it already tried to. Fixes #3789. --- include/swaybar/tray/item.h | 1 + swaybar/tray/item.c | 109 +++++++++++++++++++----------------- swaybar/tray/tray.c | 4 +- 3 files changed, 62 insertions(+), 52 deletions(-) diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h index 4238bdb8e..5ffd83634 100644 --- a/include/swaybar/tray/item.h +++ b/include/swaybar/tray/item.h @@ -20,6 +20,7 @@ struct swaybar_sni { cairo_surface_t *icon; int min_size; int max_size; + int target_size; // dbus properties char *watcher_id; diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index c8fcd3827..1a7672c9a 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include #include +#include #include #include #include @@ -27,7 +28,7 @@ static bool sni_ready(struct swaybar_sni *sni) { static void set_sni_dirty(struct swaybar_sni *sni) { if (sni_ready(sni)) { - sni->min_size = sni->max_size = 0; // invalidate previous icon + sni->target_size = sni->min_size = sni->max_size = 0; // invalidate previous icon set_bar_dirty(sni->tray->bar); } } @@ -401,69 +402,75 @@ static enum hotspot_event_handling icon_hotspot_callback( 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) { + 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_name, target_size, icon_theme, + &sni->min_size, &sni->max_size); + list_free(icon_search_paths); + if (!icon_path && sni->icon_theme_path) { + icon_path = find_icon_in_dir(icon_name, sni->icon_theme_path, + &sni->min_size, &sni->max_size); + } + if (icon_path) { + cairo_surface_destroy(sni->icon); + sni->icon = load_background_image(icon_path); + free(icon_path); + return; + } + } + + 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 - pixmap->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 ideal_size = height - 2*padding; - if ((ideal_size < sni->min_size || ideal_size > sni->max_size) && sni_ready(sni)) { - bool icon_found = false; - char *icon_name = sni->status[0] == 'N' ? - sni->attention_icon_name : sni->icon_name; - if (icon_name) { - 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_name, ideal_size, output->bar->config->icon_theme, - &sni->min_size, &sni->max_size); - list_free(icon_search_paths); - if (!icon_path && sni->icon_theme_path) { - icon_path = find_icon_in_dir(icon_name, sni->icon_theme_path, - &sni->min_size, &sni->max_size); - } - if (icon_path) { - cairo_surface_destroy(sni->icon); - sni->icon = load_background_image(icon_path); - free(icon_path); - icon_found = true; - } - } - if (!icon_found) { - list_t *pixmaps = sni->status[0] == 'N' ? - sni->attention_icon_pixmap : sni->icon_pixmap; - if (pixmaps) { - int idx = -1; - unsigned smallest_error = -1; // UINT_MAX - for (int i = 0; i < pixmaps->length; ++i) { - struct swaybar_pixmap *pixmap = pixmaps->items[i]; - unsigned error = (ideal_size - pixmap->size) * - (ideal_size < pixmap->size ? -1 : 1); - if (error < smallest_error) { - smallest_error = error; - idx = i; - } - } - struct swaybar_pixmap *pixmap = pixmaps->items[idx]; - 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)); - } + 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; } int icon_size; cairo_surface_t *icon; if (sni->icon) { int actual_size = cairo_image_surface_get_height(sni->icon); - icon_size = actual_size < ideal_size ? - actual_size*(ideal_size/actual_size) : ideal_size; + 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 = ideal_size*0.8; + 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); diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index fcf8114f0..5fe6f9c31 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -124,7 +124,9 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { struct swaybar_tray *tray = output->bar->tray; for (int i = 0; i < tray->items->length; ++i) { uint32_t h = render_sni(cairo, output, x, tray->items->items[i]); - max_height = h > max_height ? h : max_height; + if (h > max_height) { + max_height = h; + } } return max_height;