1
1
#define _POSIX_C_SOURCE 200809L
2
2
#include <cairo.h>
3
+ #include <stdbool.h>
3
4
#include <stdlib.h>
4
5
#include <string.h>
5
6
#include "swaybar/bar.h"
11
12
#include "swaybar/tray/tray.h"
12
13
#include "background-image.h"
13
14
#include "cairo.h"
15
+ #include "list.h"
14
16
#include "log.h"
15
17
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
16
18
17
19
// TODO implement menu, and use IconThemePath
18
20
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
+
19
81
static void sni_get_property (struct swaybar_sni * sni , char * prop , char * type ,
20
82
void * dest ) {
21
83
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)
46
108
struct swaybar_sni * sni = data ;
47
109
free (sni -> icon_name );
48
110
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 );
49
113
wlr_log (WLR_DEBUG , "%s has new IconName='%s'" , sni -> watcher_id , sni -> icon_name );
50
114
51
115
if (sni -> status [0 ] != 'N' ) {
@@ -60,6 +124,8 @@ static int handle_new_attention_icon(sd_bus_message *msg, void *data,
60
124
struct swaybar_sni * sni = data ;
61
125
free (sni -> attention_icon_name );
62
126
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 );
63
129
wlr_log (WLR_DEBUG , "%s has new AttentionIconName='%s'" , sni -> watcher_id ,
64
130
sni -> attention_icon_name );
65
131
@@ -118,7 +184,9 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) {
118
184
// AttentionIconPixap, AttentionMovieName, ToolTip
119
185
sni_get_property (sni , "Status" , "s" , & sni -> status );
120
186
sni_get_property (sni , "IconName" , "s" , & sni -> icon_name );
187
+ sni_get_pixmap (sni , "IconPixmap" , & sni -> icon_pixmap );
121
188
sni_get_property (sni , "AttentionIconName" , "s" , & sni -> attention_icon_name );
189
+ sni_get_pixmap (sni , "AttentionIconPixmap" , & sni -> attention_icon_pixmap );
122
190
sni_get_property (sni , "ItemIsMenu" , "b" , & sni -> item_is_menu );
123
191
sni_get_property (sni , "Menu" , "o" , & sni -> menu );
124
192
@@ -144,6 +212,7 @@ void destroy_sni(struct swaybar_sni *sni) {
144
212
free (sni -> path );
145
213
free (sni -> status );
146
214
free (sni -> icon_name );
215
+ free (sni -> icon_pixmap );
147
216
free (sni -> attention_icon_name );
148
217
free (sni -> menu );
149
218
free (sni );
@@ -224,35 +293,46 @@ static enum hotspot_event_handling icon_hotspot_callback(
224
293
return HOTSPOT_PROCESS ;
225
294
}
226
295
227
- static char * get_icon_name (struct swaybar_sni * sni ) {
296
+ static bool sni_ready (struct swaybar_sni * sni ) { // TODO remove
228
297
if (!sni -> status ) {
229
298
sni_get_property (sni , "Status" , "s" , & sni -> status );
230
299
if (!sni -> status ) {
231
- return NULL ;
300
+ return false ;
232
301
}
233
302
}
234
303
235
304
if (sni -> status [0 ] == 'N' ) { // NeedsAttention
236
305
if (!sni -> attention_icon_name ) {
237
306
sni_get_property (sni , "AttentionIconName" , "s" , & sni -> attention_icon_name );
238
307
}
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 ;
240
312
} else {
241
313
if (!sni -> icon_name ) {
242
314
sni_get_property (sni , "IconName" , "s" , & sni -> icon_name );
243
315
}
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 ;
245
320
}
246
321
}
247
322
248
323
uint32_t render_sni (cairo_t * cairo , struct swaybar_output * output , double * x ,
249
324
struct swaybar_sni * sni ) {
325
+ if (!sni_ready (sni )) {
326
+ return 0 ;
327
+ }
250
328
uint32_t height = output -> height * output -> scale ;
251
329
int padding = output -> bar -> config -> tray_padding ;
252
330
int ideal_size = height - 2 * padding ;
253
331
254
332
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 ;
256
336
if (icon_name ) {
257
337
char * icon_path = find_icon (sni -> tray -> themes , sni -> tray -> basedirs ,
258
338
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,
261
341
cairo_surface_destroy (sni -> icon );
262
342
sni -> icon = load_background_image (icon_path );
263
343
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 ));
264
367
}
265
368
}
266
369
}
0 commit comments