Skip to content

Commit bdc5d04

Browse files
committed
sni: support pixmaps
1 parent 38fd75a commit bdc5d04

File tree

2 files changed

+116
-5
lines changed

2 files changed

+116
-5
lines changed

include/swaybar/tray/item.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,15 @@
55
#include <stdbool.h>
66
#include <stdint.h>
77
#include "swaybar/tray/tray.h"
8+
#include "list.h"
89

910
struct swaybar_output;
1011

12+
struct swaybar_pixmap {
13+
int size;
14+
unsigned char pixels[];
15+
};
16+
1117
struct swaybar_sni {
1218
// icon properties
1319
struct swaybar_tray *tray;
@@ -23,7 +29,9 @@ struct swaybar_sni {
2329

2430
char *status;
2531
char *icon_name;
32+
list_t *icon_pixmap; // struct pixmap *
2633
char *attention_icon_name;
34+
list_t *attention_icon_pixmap; // struct pixmap *
2735
bool item_is_menu;
2836
char *menu;
2937
};

swaybar/tray/item.c

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#define _POSIX_C_SOURCE 200809L
22
#include <cairo.h>
3+
#include <stdbool.h>
34
#include <stdlib.h>
45
#include <string.h>
56
#include "swaybar/bar.h"
@@ -11,11 +12,72 @@
1112
#include "swaybar/tray/tray.h"
1213
#include "background-image.h"
1314
#include "cairo.h"
15+
#include "list.h"
1416
#include "log.h"
1517
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
1618

1719
// TODO implement menu, and use IconThemePath
1820

21+
static void sni_get_pixmap(struct swaybar_sni *sni, char *prop, list_t **dest) {
22+
sd_bus_error error = SD_BUS_ERROR_NULL;
23+
sd_bus_message *msg;
24+
int ret = sd_bus_get_property(sni->tray->bus, sni->service, sni->path,
25+
sni->interface, prop, &error, &msg, "a(iiay)");
26+
if (ret < 0) {
27+
wlr_log(WLR_DEBUG, "Failed to get property %s: %s", prop, error.message);
28+
sd_bus_error_free(&error);
29+
return;
30+
}
31+
32+
ret = sd_bus_message_enter_container(msg, 'a', "(iiay)");
33+
if (ret < 0) {
34+
wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret));
35+
return;
36+
}
37+
38+
list_t *pixmaps = create_list();
39+
if (!pixmaps) {
40+
return;
41+
}
42+
43+
while (!sd_bus_message_at_end(msg, 0)) {
44+
ret = sd_bus_message_enter_container(msg, 'r', "iiay");
45+
if (ret < 0) {
46+
wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret));
47+
goto cleanup;
48+
}
49+
int size;
50+
ret = sd_bus_message_read(msg, "ii", NULL, &size);
51+
if (ret < 0) {
52+
wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret));
53+
goto cleanup;
54+
}
55+
56+
const void *pixels;
57+
size_t npixels;
58+
ret = sd_bus_message_read_array(msg, 'y', &pixels, &npixels);
59+
if (ret < 0) {
60+
wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret));
61+
goto cleanup;
62+
}
63+
64+
struct swaybar_pixmap *pixmap =
65+
malloc(sizeof(struct swaybar_pixmap) + npixels);
66+
pixmap->size = size;
67+
memcpy(pixmap->pixels, pixels, npixels);
68+
list_add(pixmaps, pixmap);
69+
70+
sd_bus_message_exit_container(msg);
71+
}
72+
*dest = pixmaps;
73+
74+
sd_bus_message_unref(msg);
75+
return;
76+
cleanup:
77+
sd_bus_message_unref(msg);
78+
list_free_items_and_destroy(pixmaps);
79+
}
80+
1981
static void sni_get_property(struct swaybar_sni *sni, char *prop, char *type,
2082
void *dest) {
2183
sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -46,6 +108,8 @@ static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error)
46108
struct swaybar_sni *sni = data;
47109
free(sni->icon_name);
48110
sni_get_property(sni, "IconName", "s", &sni->icon_name);
111+
list_free_items_and_destroy(sni->icon_pixmap);
112+
sni_get_pixmap(sni, "IconPixmap", &sni->icon_pixmap);
49113
wlr_log(WLR_DEBUG, "%s has new IconName='%s'", sni->watcher_id, sni->icon_name);
50114

51115
if (sni->status[0] != 'N') {
@@ -60,6 +124,8 @@ static int handle_new_attention_icon(sd_bus_message *msg, void *data,
60124
struct swaybar_sni *sni = data;
61125
free(sni->attention_icon_name);
62126
sni_get_property(sni, "AttentionIconName", "s", &sni->attention_icon_name);
127+
list_free_items_and_destroy(sni->attention_icon_pixmap);
128+
sni_get_pixmap(sni, "IconPixmap", &sni->attention_icon_pixmap);
63129
wlr_log(WLR_DEBUG, "%s has new AttentionIconName='%s'", sni->watcher_id,
64130
sni->attention_icon_name);
65131

@@ -118,7 +184,9 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) {
118184
// AttentionIconPixap, AttentionMovieName, ToolTip
119185
sni_get_property(sni, "Status", "s", &sni->status);
120186
sni_get_property(sni, "IconName", "s", &sni->icon_name);
187+
sni_get_pixmap(sni, "IconPixmap", &sni->icon_pixmap);
121188
sni_get_property(sni, "AttentionIconName", "s", &sni->attention_icon_name);
189+
sni_get_pixmap(sni, "AttentionIconPixmap", &sni->attention_icon_pixmap);
122190
sni_get_property(sni, "ItemIsMenu", "b", &sni->item_is_menu);
123191
sni_get_property(sni, "Menu", "o", &sni->menu);
124192

@@ -144,6 +212,7 @@ void destroy_sni(struct swaybar_sni *sni) {
144212
free(sni->path);
145213
free(sni->status);
146214
free(sni->icon_name);
215+
free(sni->icon_pixmap);
147216
free(sni->attention_icon_name);
148217
free(sni->menu);
149218
free(sni);
@@ -224,35 +293,46 @@ static enum hotspot_event_handling icon_hotspot_callback(
224293
return HOTSPOT_PROCESS;
225294
}
226295

227-
static char *get_icon_name(struct swaybar_sni *sni) {
296+
static bool sni_ready(struct swaybar_sni *sni) { // TODO remove
228297
if (!sni->status) {
229298
sni_get_property(sni, "Status", "s", &sni->status);
230299
if (!sni->status) {
231-
return NULL;
300+
return false;
232301
}
233302
}
234303

235304
if (sni->status[0] == 'N') { // NeedsAttention
236305
if (!sni->attention_icon_name) {
237306
sni_get_property(sni, "AttentionIconName", "s", &sni->attention_icon_name);
238307
}
239-
return sni->attention_icon_name;
308+
if (!sni->attention_icon_name && !sni->attention_icon_pixmap) {
309+
sni_get_pixmap(sni, "AttentionIconPixmap", &sni->attention_icon_pixmap);
310+
}
311+
return sni->attention_icon_name || sni->attention_icon_pixmap;
240312
} else {
241313
if (!sni->icon_name) {
242314
sni_get_property(sni, "IconName", "s", &sni->icon_name);
243315
}
244-
return sni->icon_name;
316+
if (!sni->icon_name && !sni->icon_pixmap) {
317+
sni_get_pixmap(sni, "IconPixmap", &sni->icon_pixmap);
318+
}
319+
return sni->icon_name || sni->icon_pixmap;
245320
}
246321
}
247322

248323
uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
249324
struct swaybar_sni *sni) {
325+
if (!sni_ready(sni)) {
326+
return 0;
327+
}
250328
uint32_t height = output->height * output->scale;
251329
int padding = output->bar->config->tray_padding;
252330
int ideal_size = height - 2*padding;
253331

254332
if (ideal_size < sni->min_size || ideal_size > sni->max_size) {
255-
char *icon_name = get_icon_name(sni);
333+
bool icon_found = false;
334+
char *icon_name = sni->status[0] == 'N' ?
335+
sni->attention_icon_name : sni->icon_name;
256336
if (icon_name) {
257337
char *icon_path = find_icon(sni->tray->themes, sni->tray->basedirs,
258338
icon_name, ideal_size, output->bar->config->icon_theme,
@@ -261,6 +341,29 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
261341
cairo_surface_destroy(sni->icon);
262342
sni->icon = load_background_image(icon_path);
263343
free(icon_path);
344+
icon_found = true;
345+
}
346+
}
347+
if (!icon_found) {
348+
list_t *pixmaps = sni->status[0] == 'N' ?
349+
sni->attention_icon_pixmap : sni->icon_pixmap;
350+
if (pixmaps) {
351+
unsigned smallest_error = -1; // UINT_MAX
352+
int idx = -1;
353+
for (int i = 0; i < pixmaps->length; ++i) {
354+
struct swaybar_pixmap *pixmap = pixmaps->items[i];
355+
unsigned error = (ideal_size - pixmap->size) *
356+
(ideal_size < pixmap->size ? -1 : 1);
357+
if (error < smallest_error) {
358+
smallest_error = error;
359+
idx = i;
360+
}
361+
}
362+
struct swaybar_pixmap *pixmap = pixmaps->items[idx];
363+
cairo_surface_destroy(sni->icon);
364+
sni->icon = cairo_image_surface_create_for_data(pixmap->pixels,
365+
CAIRO_FORMAT_ARGB32, pixmap->size, pixmap->size,
366+
cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, pixmap->size));
264367
}
265368
}
266369
}

0 commit comments

Comments
 (0)