diff options
Diffstat (limited to 'swaybar/tray/item.c')
-rw-r--r-- | swaybar/tray/item.c | 109 |
1 files changed, 58 insertions, 51 deletions
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index c8fcd382..1a7672c9 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <arpa/inet.h> | 2 | #include <arpa/inet.h> |
3 | #include <cairo.h> | 3 | #include <cairo.h> |
4 | #include <limits.h> | ||
4 | #include <stdbool.h> | 5 | #include <stdbool.h> |
5 | #include <stdlib.h> | 6 | #include <stdlib.h> |
6 | #include <string.h> | 7 | #include <string.h> |
@@ -27,7 +28,7 @@ static bool sni_ready(struct swaybar_sni *sni) { | |||
27 | 28 | ||
28 | static void set_sni_dirty(struct swaybar_sni *sni) { | 29 | static void set_sni_dirty(struct swaybar_sni *sni) { |
29 | if (sni_ready(sni)) { | 30 | if (sni_ready(sni)) { |
30 | sni->min_size = sni->max_size = 0; // invalidate previous icon | 31 | sni->target_size = sni->min_size = sni->max_size = 0; // invalidate previous icon |
31 | set_bar_dirty(sni->tray->bar); | 32 | set_bar_dirty(sni->tray->bar); |
32 | } | 33 | } |
33 | } | 34 | } |
@@ -401,69 +402,75 @@ static enum hotspot_event_handling icon_hotspot_callback( | |||
401 | return HOTSPOT_PROCESS; | 402 | return HOTSPOT_PROCESS; |
402 | } | 403 | } |
403 | 404 | ||
405 | static void reload_sni(struct swaybar_sni *sni, char *icon_theme, | ||
406 | int target_size) { | ||
407 | char *icon_name = sni->status[0] == 'N' ? | ||
408 | sni->attention_icon_name : sni->icon_name; | ||
409 | if (icon_name) { | ||
410 | list_t *icon_search_paths = create_list(); | ||
411 | list_cat(icon_search_paths, sni->tray->basedirs); | ||
412 | if (sni->icon_theme_path) { | ||
413 | list_add(icon_search_paths, sni->icon_theme_path); | ||
414 | } | ||
415 | char *icon_path = find_icon(sni->tray->themes, icon_search_paths, | ||
416 | icon_name, target_size, icon_theme, | ||
417 | &sni->min_size, &sni->max_size); | ||
418 | list_free(icon_search_paths); | ||
419 | if (!icon_path && sni->icon_theme_path) { | ||
420 | icon_path = find_icon_in_dir(icon_name, sni->icon_theme_path, | ||
421 | &sni->min_size, &sni->max_size); | ||
422 | } | ||
423 | if (icon_path) { | ||
424 | cairo_surface_destroy(sni->icon); | ||
425 | sni->icon = load_background_image(icon_path); | ||
426 | free(icon_path); | ||
427 | return; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | list_t *pixmaps = sni->status[0] == 'N' ? | ||
432 | sni->attention_icon_pixmap : sni->icon_pixmap; | ||
433 | if (pixmaps) { | ||
434 | struct swaybar_pixmap *pixmap = NULL; | ||
435 | int min_error = INT_MAX; | ||
436 | for (int i = 0; i < pixmaps->length; ++i) { | ||
437 | struct swaybar_pixmap *p = pixmaps->items[i]; | ||
438 | int e = abs(target_size - pixmap->size); | ||
439 | if (e < min_error) { | ||
440 | pixmap = p; | ||
441 | min_error = e; | ||
442 | } | ||
443 | } | ||
444 | cairo_surface_destroy(sni->icon); | ||
445 | sni->icon = cairo_image_surface_create_for_data(pixmap->pixels, | ||
446 | CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size, | ||
447 | cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size)); | ||
448 | } | ||
449 | } | ||
450 | |||
404 | uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, | 451 | uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, |
405 | struct swaybar_sni *sni) { | 452 | struct swaybar_sni *sni) { |
406 | uint32_t height = output->height * output->scale; | 453 | uint32_t height = output->height * output->scale; |
407 | int padding = output->bar->config->tray_padding; | 454 | int padding = output->bar->config->tray_padding; |
408 | int ideal_size = height - 2*padding; | 455 | int target_size = height - 2*padding; |
409 | if ((ideal_size < sni->min_size || ideal_size > sni->max_size) && sni_ready(sni)) { | 456 | if (target_size != sni->target_size && sni_ready(sni)) { |
410 | bool icon_found = false; | 457 | // check if another icon should be loaded |
411 | char *icon_name = sni->status[0] == 'N' ? | 458 | if (target_size < sni->min_size || target_size > sni->max_size) { |
412 | sni->attention_icon_name : sni->icon_name; | 459 | reload_sni(sni, output->bar->config->icon_theme, target_size); |
413 | if (icon_name) { | ||
414 | list_t *icon_search_paths = create_list(); | ||
415 | list_cat(icon_search_paths, sni->tray->basedirs); | ||
416 | if (sni->icon_theme_path) { | ||
417 | list_add(icon_search_paths, sni->icon_theme_path); | ||
418 | } | ||
419 | char *icon_path = find_icon(sni->tray->themes, icon_search_paths, | ||
420 | icon_name, ideal_size, output->bar->config->icon_theme, | ||
421 | &sni->min_size, &sni->max_size); | ||
422 | list_free(icon_search_paths); | ||
423 | if (!icon_path && sni->icon_theme_path) { | ||
424 | icon_path = find_icon_in_dir(icon_name, sni->icon_theme_path, | ||
425 | &sni->min_size, &sni->max_size); | ||
426 | } | ||
427 | if (icon_path) { | ||
428 | cairo_surface_destroy(sni->icon); | ||
429 | sni->icon = load_background_image(icon_path); | ||
430 | free(icon_path); | ||
431 | icon_found = true; | ||
432 | } | ||
433 | } | ||
434 | if (!icon_found) { | ||
435 | list_t *pixmaps = sni->status[0] == 'N' ? | ||
436 | sni->attention_icon_pixmap : sni->icon_pixmap; | ||
437 | if (pixmaps) { | ||
438 | int idx = -1; | ||
439 | unsigned smallest_error = -1; // UINT_MAX | ||
440 | for (int i = 0; i < pixmaps->length; ++i) { | ||
441 | struct swaybar_pixmap *pixmap = pixmaps->items[i]; | ||
442 | unsigned error = (ideal_size - pixmap->size) * | ||
443 | (ideal_size < pixmap->size ? -1 : 1); | ||
444 | if (error < smallest_error) { | ||
445 | smallest_error = error; | ||
446 | idx = i; | ||
447 | } | ||
448 | } | ||
449 | struct swaybar_pixmap *pixmap = pixmaps->items[idx]; | ||
450 | cairo_surface_destroy(sni->icon); | ||
451 | sni->icon = cairo_image_surface_create_for_data(pixmap->pixels, | ||
452 | CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size, | ||
453 | cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size)); | ||
454 | } | ||
455 | } | 460 | } |
461 | |||
462 | sni->target_size = target_size; | ||
456 | } | 463 | } |
457 | 464 | ||
458 | int icon_size; | 465 | int icon_size; |
459 | cairo_surface_t *icon; | 466 | cairo_surface_t *icon; |
460 | if (sni->icon) { | 467 | if (sni->icon) { |
461 | int actual_size = cairo_image_surface_get_height(sni->icon); | 468 | int actual_size = cairo_image_surface_get_height(sni->icon); |
462 | icon_size = actual_size < ideal_size ? | 469 | icon_size = actual_size < target_size ? |
463 | actual_size*(ideal_size/actual_size) : ideal_size; | 470 | actual_size*(target_size/actual_size) : target_size; |
464 | icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); | 471 | icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); |
465 | } else { // draw a :( | 472 | } else { // draw a :( |
466 | icon_size = ideal_size*0.8; | 473 | icon_size = target_size*0.8; |
467 | icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); | 474 | icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); |
468 | cairo_t *cairo_icon = cairo_create(icon); | 475 | cairo_t *cairo_icon = cairo_create(icon); |
469 | cairo_set_source_u32(cairo_icon, 0xFF0000FF); | 476 | cairo_set_source_u32(cairo_icon, 0xFF0000FF); |