diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h index 57affb78..53d7e48c 100644 --- a/include/swaybar/tray/item.h +++ b/include/swaybar/tray/item.h @@ -1,10 +1,14 @@ #ifndef _SWAYBAR_TRAY_ITEM_H #define _SWAYBAR_TRAY_ITEM_H +#include #include +#include #include "swaybar/tray/tray.h" #include "list.h" +struct swaybar_output; + struct swaybar_pixmap { int size; unsigned char pixels[]; @@ -34,5 +38,7 @@ struct swaybar_sni { struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray); void destroy_sni(struct swaybar_sni *sni); +uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, + struct swaybar_sni *sni); #endif diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 561a3425..019e8ed0 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -1,14 +1,27 @@ #define _POSIX_C_SOURCE 200809L +#include +#include #include #include +#include "swaybar/bar.h" +#include "swaybar/config.h" #include "swaybar/tray/host.h" +#include "swaybar/tray/icon.h" #include "swaybar/tray/item.h" #include "swaybar/tray/tray.h" +#include "background-image.h" +#include "cairo.h" #include "list.h" #include "log.h" // TODO menu +static bool sni_ready(struct swaybar_sni *sni) { + return sni->status && (sni->status[0] == 'N' ? + sni->attention_icon_name || sni->attention_icon_pixmap : + sni->icon_name || sni->icon_pixmap); +} + 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)"); @@ -234,3 +247,74 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni->menu); free(sni); } + +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) { + char *icon_path = find_icon(sni->tray->themes, sni->tray->basedirs, + icon_name, ideal_size, output->bar->config->icon_theme, + &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)); + } + } + } + + if (!sni->icon) { + // TODO fallback + return 0; + } + + cairo_surface_t *icon; + int actual_size = cairo_image_surface_get_height(sni->icon); + int icon_size = actual_size < ideal_size ? + actual_size * (ideal_size / actual_size) : ideal_size; + icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); + + int padded_size = icon_size + 2*padding; + *x -= padded_size; + int y = floor((height - padded_size) / 2.0); + + cairo_operator_t op = cairo_get_operator(cairo); + cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); + cairo_set_source_surface(cairo, icon, *x + padding, y + padding); + cairo_rectangle(cairo, *x, y, padded_size, padded_size); + cairo_fill(cairo); + cairo_set_operator(cairo, op); + + cairo_surface_destroy(icon); + + return output->height; +} diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index 4ef28a78..f186ed86 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -2,6 +2,7 @@ #include #include #include +#include "swaybar/config.h" #include "swaybar/bar.h" #include "swaybar/tray/icon.h" #include "swaybar/tray/host.h" @@ -70,6 +71,28 @@ void tray_in(int fd, short mask, void *data) { } } -uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { - return 0; // placeholder +static int cmp_output(const void *item, const void *cmp_to) { + return strcmp(item, cmp_to); +} + +uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { + struct swaybar_config *config = output->bar->config; + if (config->tray_outputs) { + if (list_seq_find(config->tray_outputs, cmp_output, output->name) == -1) { + return 0; + } + } // else display on all + + if ((int) output->height*output->scale <= 2*config->tray_padding) { + return 2*config->tray_padding + 1; + } + + uint32_t max_height = 0; + 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; + } + + return max_height; }