aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar')
-rw-r--r--swaybar/bar.c22
-rw-r--r--swaybar/config.c5
-rw-r--r--swaybar/i3bar.c8
-rw-r--r--swaybar/image.c136
-rw-r--r--swaybar/input.c52
-rw-r--r--swaybar/ipc.c19
-rw-r--r--swaybar/main.c1
-rw-r--r--swaybar/meson.build5
-rw-r--r--swaybar/render.c81
-rw-r--r--swaybar/status_line.c1
-rw-r--r--swaybar/tray/host.c11
-rw-r--r--swaybar/tray/icon.c27
-rw-r--r--swaybar/tray/item.c12
-rw-r--r--swaybar/tray/watcher.c12
14 files changed, 267 insertions, 125 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 5e4ebd97..5b1213a8 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 1#include <assert.h>
3#include <errno.h> 2#include <errno.h>
4#include <fcntl.h> 3#include <fcntl.h>
@@ -362,6 +361,9 @@ static void handle_global(void *data, struct wl_registry *registry,
362 } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { 361 } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
363 bar->xdg_output_manager = wl_registry_bind(registry, name, 362 bar->xdg_output_manager = wl_registry_bind(registry, name,
364 &zxdg_output_manager_v1_interface, 2); 363 &zxdg_output_manager_v1_interface, 2);
364 } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
365 bar->cursor_shape_manager = wl_registry_bind(registry, name,
366 &wp_cursor_shape_manager_v1_interface, 1);
365 } 367 }
366} 368}
367 369
@@ -425,15 +427,17 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) {
425 // Second roundtrip for xdg-output 427 // Second roundtrip for xdg-output
426 wl_display_roundtrip(bar->display); 428 wl_display_roundtrip(bar->display);
427 429
428 struct swaybar_seat *seat; 430 if (!bar->cursor_shape_manager) {
429 wl_list_for_each(seat, &bar->seats, link) { 431 struct swaybar_seat *seat;
430 struct swaybar_pointer *pointer = &seat->pointer; 432 wl_list_for_each(seat, &bar->seats, link) {
431 if (!pointer) { 433 struct swaybar_pointer *pointer = &seat->pointer;
432 continue; 434 if (!pointer) {
435 continue;
436 }
437 pointer->cursor_surface =
438 wl_compositor_create_surface(bar->compositor);
439 assert(pointer->cursor_surface);
433 } 440 }
434 pointer->cursor_surface =
435 wl_compositor_create_surface(bar->compositor);
436 assert(pointer->cursor_surface);
437 } 441 }
438 442
439 if (bar->config->status_command) { 443 if (bar->config->status_command) {
diff --git a/swaybar/config.c b/swaybar/config.c
index abedaec0..55bfcb72 100644
--- a/swaybar/config.c
+++ b/swaybar/config.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdlib.h> 1#include <stdlib.h>
3#include <string.h> 2#include <string.h>
4#include "swaybar/config.h" 3#include "swaybar/config.h"
@@ -26,7 +25,7 @@ struct swaybar_config *init_config(void) {
26 config->status_command = NULL; 25 config->status_command = NULL;
27 config->pango_markup = false; 26 config->pango_markup = false;
28 config->position = parse_position("bottom"); 27 config->position = parse_position("bottom");
29 config->font = strdup("monospace 10"); 28 config->font_description = pango_font_description_from_string("monospace 10");
30 config->mode = strdup("dock"); 29 config->mode = strdup("dock");
31 config->hidden_state = strdup("hide"); 30 config->hidden_state = strdup("hide");
32 config->sep_symbol = NULL; 31 config->sep_symbol = NULL;
@@ -105,7 +104,7 @@ void free_tray_binding(struct tray_binding *binding) {
105 104
106void free_config(struct swaybar_config *config) { 105void free_config(struct swaybar_config *config) {
107 free(config->status_command); 106 free(config->status_command);
108 free(config->font); 107 pango_font_description_free(config->font_description);
109 free(config->mode); 108 free(config->mode);
110 free(config->hidden_state); 109 free(config->hidden_state);
111 free(config->sep_symbol); 110 free(config->sep_symbol);
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c
index 6d00befb..62c22d43 100644
--- a/swaybar/i3bar.c
+++ b/swaybar/i3bar.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <json.h> 1#include <json.h>
3#include <linux/input-event-codes.h> 2#include <linux/input-event-codes.h>
4#include <ctype.h> 3#include <ctype.h>
@@ -269,11 +268,16 @@ bool i3bar_handle_readable(struct status_line *status) {
269 268
270enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, 269enum hotspot_event_handling i3bar_block_send_click(struct status_line *status,
271 struct i3bar_block *block, double x, double y, double rx, double ry, 270 struct i3bar_block *block, double x, double y, double rx, double ry,
272 double w, double h, int scale, uint32_t button) { 271 double w, double h, int scale, uint32_t button, bool released) {
273 sway_log(SWAY_DEBUG, "block %s clicked", block->name); 272 sway_log(SWAY_DEBUG, "block %s clicked", block->name);
274 if (!block->name || !status->click_events) { 273 if (!block->name || !status->click_events) {
275 return HOTSPOT_PROCESS; 274 return HOTSPOT_PROCESS;
276 } 275 }
276 if (released) {
277 // Since we handle the pressed event, also handle the released event
278 // to block it from falling through to a binding in the bar
279 return HOTSPOT_IGNORE;
280 }
277 281
278 struct json_object *event_json = json_object_new_object(); 282 struct json_object *event_json = json_object_new_object();
279 json_object_object_add(event_json, "name", 283 json_object_object_add(event_json, "name",
diff --git a/swaybar/image.c b/swaybar/image.c
new file mode 100644
index 00000000..ed24b9f9
--- /dev/null
+++ b/swaybar/image.c
@@ -0,0 +1,136 @@
1#include <assert.h>
2#include "config.h"
3#include "log.h"
4#include "swaybar/image.h"
5
6#if HAVE_GDK_PIXBUF
7#include <gdk-pixbuf/gdk-pixbuf.h>
8#endif
9
10#if HAVE_GDK_PIXBUF
11static cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf(
12 const GdkPixbuf *gdkbuf) {
13 int chan = gdk_pixbuf_get_n_channels(gdkbuf);
14 if (chan < 3) {
15 return NULL;
16 }
17
18 const guint8* gdkpix = gdk_pixbuf_read_pixels(gdkbuf);
19 if (!gdkpix) {
20 return NULL;
21 }
22 gint w = gdk_pixbuf_get_width(gdkbuf);
23 gint h = gdk_pixbuf_get_height(gdkbuf);
24 int stride = gdk_pixbuf_get_rowstride(gdkbuf);
25
26 cairo_format_t fmt = (chan == 3) ? CAIRO_FORMAT_RGB24 : CAIRO_FORMAT_ARGB32;
27 cairo_surface_t * cs = cairo_image_surface_create (fmt, w, h);
28 cairo_surface_flush (cs);
29 if ( !cs || cairo_surface_status(cs) != CAIRO_STATUS_SUCCESS) {
30 return NULL;
31 }
32
33 int cstride = cairo_image_surface_get_stride(cs);
34 unsigned char * cpix = cairo_image_surface_get_data(cs);
35
36 if (chan == 3) {
37 int i;
38 for (i = h; i; --i) {
39 const guint8 *gp = gdkpix;
40 unsigned char *cp = cpix;
41 const guint8* end = gp + 3*w;
42 while (gp < end) {
43#if G_BYTE_ORDER == G_LITTLE_ENDIAN
44 cp[0] = gp[2];
45 cp[1] = gp[1];
46 cp[2] = gp[0];
47#else
48 cp[1] = gp[0];
49 cp[2] = gp[1];
50 cp[3] = gp[2];
51#endif
52 gp += 3;
53 cp += 4;
54 }
55 gdkpix += stride;
56 cpix += cstride;
57 }
58 } else {
59 /* premul-color = alpha/255 * color/255 * 255 = (alpha*color)/255
60 * (z/255) = z/256 * 256/255 = z/256 (1 + 1/255)
61 * = z/256 + (z/256)/255 = (z + z/255)/256
62 * # recurse once
63 * = (z + (z + z/255)/256)/256
64 * = (z + z/256 + z/256/255) / 256
65 * # only use 16bit uint operations, loose some precision,
66 * # result is floored.
67 * -> (z + z>>8)>>8
68 * # add 0x80/255 = 0.5 to convert floor to round
69 * => (z+0x80 + (z+0x80)>>8 ) >> 8
70 * ------
71 * tested as equal to lround(z/255.0) for uint z in [0..0xfe02]
72 */
73#define PREMUL_ALPHA(x,a,b,z) \
74 G_STMT_START { z = a * b + 0x80; x = (z + (z >> 8)) >> 8; } \
75 G_STMT_END
76 int i;
77 for (i = h; i; --i) {
78 const guint8 *gp = gdkpix;
79 unsigned char *cp = cpix;
80 const guint8* end = gp + 4*w;
81 guint z1, z2, z3;
82 while (gp < end) {
83#if G_BYTE_ORDER == G_LITTLE_ENDIAN
84 PREMUL_ALPHA(cp[0], gp[2], gp[3], z1);
85 PREMUL_ALPHA(cp[1], gp[1], gp[3], z2);
86 PREMUL_ALPHA(cp[2], gp[0], gp[3], z3);
87 cp[3] = gp[3];
88#else
89 PREMUL_ALPHA(cp[1], gp[0], gp[3], z1);
90 PREMUL_ALPHA(cp[2], gp[1], gp[3], z2);
91 PREMUL_ALPHA(cp[3], gp[2], gp[3], z3);
92 cp[0] = gp[3];
93#endif
94 gp += 4;
95 cp += 4;
96 }
97 gdkpix += stride;
98 cpix += cstride;
99 }
100#undef PREMUL_ALPHA
101 }
102 cairo_surface_mark_dirty(cs);
103 return cs;
104}
105#endif // HAVE_GDK_PIXBUF
106
107cairo_surface_t *load_image(const char *path) {
108 cairo_surface_t *image;
109#if HAVE_GDK_PIXBUF
110 GError *err = NULL;
111 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err);
112 if (!pixbuf) {
113 sway_log(SWAY_ERROR, "Failed to load background image (%s).",
114 err->message);
115 return NULL;
116 }
117 image = gdk_cairo_image_surface_create_from_pixbuf(pixbuf);
118 g_object_unref(pixbuf);
119#else
120 image = cairo_image_surface_create_from_png(path);
121#endif // HAVE_GDK_PIXBUF
122 if (!image) {
123 sway_log(SWAY_ERROR, "Failed to read background image.");
124 return NULL;
125 }
126 if (cairo_surface_status(image) != CAIRO_STATUS_SUCCESS) {
127 sway_log(SWAY_ERROR, "Failed to read background image: %s."
128#if !HAVE_GDK_PIXBUF
129 "\nSway was compiled without gdk_pixbuf support, so only"
130 "\nPNG images can be loaded. This is the likely cause."
131#endif // !HAVE_GDK_PIXBUF
132 , cairo_status_to_string(cairo_surface_status(image)));
133 return NULL;
134 }
135 return image;
136}
diff --git a/swaybar/input.c b/swaybar/input.c
index c8c8f0d4..ada4bc86 100644
--- a/swaybar/input.c
+++ b/swaybar/input.c
@@ -81,8 +81,16 @@ void update_cursor(struct swaybar_seat *seat) {
81 int scale = pointer->current ? pointer->current->scale : 1; 81 int scale = pointer->current ? pointer->current->scale : 1;
82 pointer->cursor_theme = wl_cursor_theme_load( 82 pointer->cursor_theme = wl_cursor_theme_load(
83 cursor_theme, cursor_size * scale, seat->bar->shm); 83 cursor_theme, cursor_size * scale, seat->bar->shm);
84 if (!pointer->cursor_theme) {
85 sway_log(SWAY_ERROR, "Failed to load cursor theme");
86 return;
87 }
84 struct wl_cursor *cursor; 88 struct wl_cursor *cursor;
85 cursor = wl_cursor_theme_get_cursor(pointer->cursor_theme, "left_ptr"); 89 cursor = wl_cursor_theme_get_cursor(pointer->cursor_theme, "default");
90 if (!cursor) {
91 sway_log(SWAY_ERROR, "Failed to get default cursor from theme");
92 return;
93 }
86 pointer->cursor_image = cursor->images[0]; 94 pointer->cursor_image = cursor->images[0];
87 wl_surface_set_buffer_scale(pointer->cursor_surface, scale); 95 wl_surface_set_buffer_scale(pointer->cursor_surface, scale);
88 wl_surface_attach(pointer->cursor_surface, 96 wl_surface_attach(pointer->cursor_surface,
@@ -103,7 +111,7 @@ static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
103 struct swaybar_pointer *pointer = &seat->pointer; 111 struct swaybar_pointer *pointer = &seat->pointer;
104 seat->pointer.x = wl_fixed_to_double(surface_x); 112 seat->pointer.x = wl_fixed_to_double(surface_x);
105 seat->pointer.y = wl_fixed_to_double(surface_y); 113 seat->pointer.y = wl_fixed_to_double(surface_y);
106 pointer->serial = serial; 114
107 struct swaybar_output *output; 115 struct swaybar_output *output;
108 wl_list_for_each(output, &seat->bar->outputs, link) { 116 wl_list_for_each(output, &seat->bar->outputs, link) {
109 if (output->surface == surface) { 117 if (output->surface == surface) {
@@ -111,7 +119,18 @@ static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
111 break; 119 break;
112 } 120 }
113 } 121 }
114 update_cursor(seat); 122
123 if (seat->bar->cursor_shape_manager) {
124 struct wp_cursor_shape_device_v1 *device =
125 wp_cursor_shape_manager_v1_get_pointer(
126 seat->bar->cursor_shape_manager, wl_pointer);
127 wp_cursor_shape_device_v1_set_shape(device, serial,
128 WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT);
129 wp_cursor_shape_device_v1_destroy(device);
130 } else {
131 pointer->serial = serial;
132 update_cursor(seat);
133 }
115} 134}
116 135
117static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, 136static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
@@ -141,14 +160,15 @@ static bool check_bindings(struct swaybar *bar, uint32_t button,
141} 160}
142 161
143static bool process_hotspots(struct swaybar_output *output, 162static bool process_hotspots(struct swaybar_output *output,
144 double x, double y, uint32_t button) { 163 double x, double y, uint32_t button, uint32_t state) {
164 bool released = state == WL_POINTER_BUTTON_STATE_RELEASED;
145 struct swaybar_hotspot *hotspot; 165 struct swaybar_hotspot *hotspot;
146 wl_list_for_each(hotspot, &output->hotspots, link) { 166 wl_list_for_each(hotspot, &output->hotspots, link) {
147 if (x >= hotspot->x && y >= hotspot->y 167 if (x >= hotspot->x && y >= hotspot->y
148 && x < hotspot->x + hotspot->width 168 && x < hotspot->x + hotspot->width
149 && y < hotspot->y + hotspot->height) { 169 && y < hotspot->y + hotspot->height) {
150 if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y, 170 if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y,
151 button, hotspot->data)) { 171 button, released, hotspot->data)) {
152 return true; 172 return true;
153 } 173 }
154 } 174 }
@@ -166,14 +186,11 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
166 return; 186 return;
167 } 187 }
168 188
169 if (check_bindings(seat->bar, button, state)) { 189 if (process_hotspots(output, pointer->x, pointer->y, button, state)) {
170 return; 190 return;
171 } 191 }
172 192
173 if (state != WL_POINTER_BUTTON_STATE_PRESSED) { 193 check_bindings(seat->bar, button, state);
174 return;
175 }
176 process_hotspots(output, pointer->x, pointer->y, button);
177} 194}
178 195
179static void workspace_next(struct swaybar *bar, struct swaybar_output *output, 196static void workspace_next(struct swaybar *bar, struct swaybar_output *output,
@@ -209,7 +226,7 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output,
209 } 226 }
210 } 227 }
211 228
212 if (new) { 229 if (new && new != active) {
213 ipc_send_workspace_command(bar, new->name); 230 ipc_send_workspace_command(bar, new->name);
214 231
215 // Since we're asking Sway to switch to 'new', it should become visible. 232 // Since we're asking Sway to switch to 'new', it should become visible.
@@ -222,15 +239,15 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output,
222static void process_discrete_scroll(struct swaybar_seat *seat, 239static void process_discrete_scroll(struct swaybar_seat *seat,
223 struct swaybar_output *output, struct swaybar_pointer *pointer, 240 struct swaybar_output *output, struct swaybar_pointer *pointer,
224 uint32_t axis, wl_fixed_t value) { 241 uint32_t axis, wl_fixed_t value) {
225 // If there is a button press binding, execute it, skip default behavior,
226 // and check button release bindings
227 uint32_t button = wl_axis_to_button(axis, value); 242 uint32_t button = wl_axis_to_button(axis, value);
228 if (check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_PRESSED)) { 243 if (process_hotspots(output, pointer->x, pointer->y, button, WL_POINTER_BUTTON_STATE_PRESSED)) {
229 check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_RELEASED); 244 // (Currently hotspots don't do anything on release events, so no need to emit one)
230 return; 245 return;
231 } 246 }
232 247
233 if (process_hotspots(output, pointer->x, pointer->y, button)) { 248 // If there is a button press binding, execute it, and check button release bindings
249 if (check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_PRESSED)) {
250 check_bindings(seat->bar, button, WL_POINTER_BUTTON_STATE_RELEASED);
234 return; 251 return;
235 } 252 }
236 253
@@ -403,7 +420,8 @@ static void wl_touch_up(void *data, struct wl_touch *wl_touch,
403 } 420 }
404 if (time - slot->time < 500) { 421 if (time - slot->time < 500) {
405 // Tap, treat it like a pointer click 422 // Tap, treat it like a pointer click
406 process_hotspots(slot->output, slot->x, slot->y, BTN_LEFT); 423 process_hotspots(slot->output, slot->x, slot->y, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
424 // (Currently hotspots don't do anything on release events, so no need to emit one)
407 } 425 }
408 slot->output = NULL; 426 slot->output = NULL;
409} 427}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index 2cb235bf..03500bdf 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809
2#include <limits.h> 1#include <limits.h>
3#include <poll.h> 2#include <poll.h>
4#include <stdio.h> 3#include <stdio.h>
@@ -147,8 +146,10 @@ static bool ipc_parse_config(
147 146
148 json_object *font = json_object_object_get(bar_config, "font"); 147 json_object *font = json_object_object_get(bar_config, "font");
149 if (font) { 148 if (font) {
150 free(config->font); 149 pango_font_description_free(config->font_description);
151 config->font = parse_font(json_object_get_string(font)); 150 char *font_value = parse_font(json_object_get_string(font));
151 config->font_description = pango_font_description_from_string(font_value);
152 free(font_value);
152 } 153 }
153 154
154 json_object *gaps = json_object_object_get(bar_config, "gaps"); 155 json_object *gaps = json_object_object_get(bar_config, "gaps");
@@ -424,12 +425,9 @@ bool ipc_initialize(struct swaybar *bar) {
424 } 425 }
425 free(res); 426 free(res);
426 427
427 struct swaybar_config *config = bar->config; 428 char *subscribe =
428 char subscribe[128]; // suitably large buffer 429 "[ \"barconfig_update\", \"bar_state_update\", \"mode\", \"workspace\" ]";
429 len = snprintf(subscribe, 128, 430 len = strlen(subscribe);
430 "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]",
431 config->binding_mode_indicator ? ", \"mode\"" : "",
432 config->workspace_buttons ? ", \"workspace\"" : "");
433 free(ipc_single_command(bar->ipc_event_socketfd, 431 free(ipc_single_command(bar->ipc_event_socketfd,
434 IPC_SUBSCRIBE, subscribe, &len)); 432 IPC_SUBSCRIBE, subscribe, &len));
435 return true; 433 return true;
@@ -485,8 +483,7 @@ static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
485 destroy_layer_surface(output); 483 destroy_layer_surface(output);
486 wl_list_remove(&output->link); 484 wl_list_remove(&output->link);
487 wl_list_insert(&bar->unused_outputs, &output->link); 485 wl_list_insert(&bar->unused_outputs, &output->link);
488 } else if (!oldcfg->font || !newcfg->font || 486 } else if (!pango_font_description_equal(oldcfg->font_description, newcfg->font_description)) {
489 strcmp(oldcfg->font, newcfg->font) != 0) {
490 output->height = 0; // force update height 487 output->height = 0; // force update height
491 } 488 }
492 } 489 }
diff --git a/swaybar/main.c b/swaybar/main.c
index a44c1e63..3dc67233 100644
--- a/swaybar/main.c
+++ b/swaybar/main.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdio.h> 1#include <stdio.h>
3#include <stdlib.h> 2#include <stdlib.h>
4#include <string.h> 3#include <string.h>
diff --git a/swaybar/meson.build b/swaybar/meson.build
index 9feb3cd2..34bbdeea 100644
--- a/swaybar/meson.build
+++ b/swaybar/meson.build
@@ -8,7 +8,6 @@ tray_files = have_tray ? [
8 8
9swaybar_deps = [ 9swaybar_deps = [
10 cairo, 10 cairo,
11 client_protos,
12 gdk_pixbuf, 11 gdk_pixbuf,
13 jsonc, 12 jsonc,
14 math, 13 math,
@@ -27,12 +26,14 @@ executable(
27 'bar.c', 26 'bar.c',
28 'config.c', 27 'config.c',
29 'i3bar.c', 28 'i3bar.c',
29 'image.c',
30 'input.c', 30 'input.c',
31 'ipc.c', 31 'ipc.c',
32 'main.c', 32 'main.c',
33 'render.c', 33 'render.c',
34 'status_line.c', 34 'status_line.c',
35 tray_files 35 tray_files,
36 wl_protos_src,
36 ], 37 ],
37 include_directories: [sway_inc], 38 include_directories: [sway_inc],
38 dependencies: swaybar_deps, 39 dependencies: swaybar_deps,
diff --git a/swaybar/render.c b/swaybar/render.c
index 7e2f97b7..879a4e42 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 1#include <assert.h>
3#include <linux/input-event-codes.h> 2#include <linux/input-event-codes.h>
4#include <limits.h> 3#include <limits.h>
@@ -62,7 +61,7 @@ static uint32_t render_status_line_error(struct render_context *ctx, double *x)
62 int margin = 3; 61 int margin = 3;
63 double ws_vertical_padding = output->bar->config->status_padding; 62 double ws_vertical_padding = output->bar->config->status_padding;
64 63
65 char *font = output->bar->config->font; 64 PangoFontDescription *font = output->bar->config->font_description;
66 int text_width, text_height; 65 int text_width, text_height;
67 get_text_size(cairo, font, &text_width, &text_height, NULL, 66 get_text_size(cairo, font, &text_width, &text_height, NULL,
68 1, false, "%s", error); 67 1, false, "%s", error);
@@ -97,7 +96,7 @@ static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
97 cairo_set_source_u32(cairo, fontcolor); 96 cairo_set_source_u32(cairo, fontcolor);
98 97
99 int text_width, text_height; 98 int text_width, text_height;
100 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 99 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
101 1, config->pango_markup, "%s", text); 100 1, config->pango_markup, "%s", text);
102 101
103 double ws_vertical_padding = config->status_padding; 102 double ws_vertical_padding = config->status_padding;
@@ -115,7 +114,7 @@ static uint32_t render_status_line_text(struct render_context *ctx, double *x) {
115 double text_y = height / 2.0 - text_height / 2.0; 114 double text_y = height / 2.0 - text_height / 2.0;
116 cairo_move_to(cairo, *x, (int)floor(text_y)); 115 cairo_move_to(cairo, *x, (int)floor(text_y));
117 choose_text_aa_mode(ctx, fontcolor); 116 choose_text_aa_mode(ctx, fontcolor);
118 render_text(cairo, config->font, 1, config->pango_markup, "%s", text); 117 render_text(cairo, config->font_description, 1, config->pango_markup, "%s", text);
119 *x -= margin; 118 *x -= margin;
120 return output->height; 119 return output->height;
121} 120}
@@ -160,7 +159,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color,
160 159
161static enum hotspot_event_handling block_hotspot_callback( 160static enum hotspot_event_handling block_hotspot_callback(
162 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 161 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
163 double x, double y, uint32_t button, void *data) { 162 double x, double y, uint32_t button, bool released, void *data) {
164 struct i3bar_block *block = data; 163 struct i3bar_block *block = data;
165 struct status_line *status = output->bar->status; 164 struct status_line *status = output->bar->status;
166 return i3bar_block_send_click(status, block, x, y, 165 return i3bar_block_send_click(status, block, x, y,
@@ -168,7 +167,7 @@ static enum hotspot_event_handling block_hotspot_callback(
168 y - (double)hotspot->y, 167 y - (double)hotspot->y,
169 (double)hotspot->width, 168 (double)hotspot->width,
170 (double)hotspot->height, 169 (double)hotspot->height,
171 output->scale, button); 170 output->scale, button, released);
172} 171}
173 172
174static void i3bar_block_unref_callback(void *data) { 173static void i3bar_block_unref_callback(void *data) {
@@ -190,7 +189,7 @@ static uint32_t render_status_block(struct render_context *ctx,
190 struct swaybar_output *output = ctx->output; 189 struct swaybar_output *output = ctx->output;
191 struct swaybar_config *config = output->bar->config; 190 struct swaybar_config *config = output->bar->config;
192 int text_width, text_height; 191 int text_width, text_height;
193 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 1, 192 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1,
194 block->markup, "%s", text); 193 block->markup, "%s", text);
195 194
196 int margin = 3; 195 int margin = 3;
@@ -199,7 +198,7 @@ static uint32_t render_status_block(struct render_context *ctx,
199 int width = text_width; 198 int width = text_width;
200 if (block->min_width_str) { 199 if (block->min_width_str) {
201 int w; 200 int w;
202 get_text_size(cairo, config->font, &w, NULL, NULL, 1, block->markup, 201 get_text_size(cairo, config->font_description, &w, NULL, NULL, 1, block->markup,
203 "%s", block->min_width_str); 202 "%s", block->min_width_str);
204 block->min_width = w; 203 block->min_width = w;
205 } 204 }
@@ -229,7 +228,7 @@ static uint32_t render_status_block(struct render_context *ctx,
229 int sep_block_width = block->separator_block_width; 228 int sep_block_width = block->separator_block_width;
230 if (!edge) { 229 if (!edge) {
231 if (config->sep_symbol) { 230 if (config->sep_symbol) {
232 get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, 231 get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL,
233 1, false, "%s", config->sep_symbol); 232 1, false, "%s", config->sep_symbol);
234 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 233 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
235 uint32_t _ideal_surface_height = _ideal_height; 234 uint32_t _ideal_surface_height = _ideal_height;
@@ -292,7 +291,7 @@ static uint32_t render_status_block(struct render_context *ctx,
292 } 291 }
293 292
294 double offset = 0; 293 double offset = 0;
295 if (strncmp(block->align, "left", 5) == 0) { 294 if (strncmp(block->align, "left", 4) == 0) {
296 offset = x_pos; 295 offset = x_pos;
297 } else if (strncmp(block->align, "right", 5) == 0) { 296 } else if (strncmp(block->align, "right", 5) == 0) {
298 offset = x_pos + width - text_width; 297 offset = x_pos + width - text_width;
@@ -307,7 +306,7 @@ static uint32_t render_status_block(struct render_context *ctx,
307 color = block->urgent ? config->colors.urgent_workspace.text : color; 306 color = block->urgent ? config->colors.urgent_workspace.text : color;
308 cairo_set_source_u32(cairo, color); 307 cairo_set_source_u32(cairo, color);
309 choose_text_aa_mode(ctx, color); 308 choose_text_aa_mode(ctx, color);
310 render_text(cairo, config->font, 1, block->markup, "%s", text); 309 render_text(cairo, config->font_description, 1, block->markup, "%s", text);
311 x_pos += width; 310 x_pos += width;
312 311
313 if (block->border_set || block->urgent) { 312 if (block->border_set || block->urgent) {
@@ -331,7 +330,7 @@ static uint32_t render_status_block(struct render_context *ctx,
331 double sep_y = height / 2.0 - sep_height / 2.0; 330 double sep_y = height / 2.0 - sep_height / 2.0;
332 cairo_move_to(cairo, offset, (int)floor(sep_y)); 331 cairo_move_to(cairo, offset, (int)floor(sep_y));
333 choose_text_aa_mode(ctx, color); 332 choose_text_aa_mode(ctx, color);
334 render_text(cairo, config->font, 1, false, 333 render_text(cairo, config->font_description, 1, false,
335 "%s", config->sep_symbol); 334 "%s", config->sep_symbol);
336 } else { 335 } else {
337 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); 336 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
@@ -354,7 +353,7 @@ static void predict_status_block_pos(cairo_t *cairo,
354 struct swaybar_config *config = output->bar->config; 353 struct swaybar_config *config = output->bar->config;
355 354
356 int text_width, text_height; 355 int text_width, text_height;
357 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 1, 356 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1,
358 block->markup, "%s", block->full_text); 357 block->markup, "%s", block->full_text);
359 358
360 int margin = 3; 359 int margin = 3;
@@ -364,7 +363,7 @@ static void predict_status_block_pos(cairo_t *cairo,
364 363
365 if (block->min_width_str) { 364 if (block->min_width_str) {
366 int w; 365 int w;
367 get_text_size(cairo, config->font, &w, NULL, NULL, 366 get_text_size(cairo, config->font_description, &w, NULL, NULL,
368 1, block->markup, "%s", block->min_width_str); 367 1, block->markup, "%s", block->min_width_str);
369 block->min_width = w; 368 block->min_width = w;
370 } 369 }
@@ -391,7 +390,7 @@ static void predict_status_block_pos(cairo_t *cairo,
391 int sep_block_width = block->separator_block_width; 390 int sep_block_width = block->separator_block_width;
392 if (!edge) { 391 if (!edge) {
393 if (config->sep_symbol) { 392 if (config->sep_symbol) {
394 get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, 393 get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL,
395 1, false, "%s", config->sep_symbol); 394 1, false, "%s", config->sep_symbol);
396 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; 395 uint32_t _ideal_height = sep_height + ws_vertical_padding * 2;
397 uint32_t _ideal_surface_height = _ideal_height; 396 uint32_t _ideal_surface_height = _ideal_height;
@@ -426,7 +425,7 @@ static uint32_t predict_workspace_button_length(cairo_t *cairo,
426 struct swaybar_config *config = output->bar->config; 425 struct swaybar_config *config = output->bar->config;
427 426
428 int text_width, text_height; 427 int text_width, text_height;
429 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 1, 428 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1,
430 config->pango_markup, "%s", ws->label); 429 config->pango_markup, "%s", ws->label);
431 430
432 int ws_vertical_padding = WS_VERTICAL_PADDING; 431 int ws_vertical_padding = WS_VERTICAL_PADDING;
@@ -474,7 +473,7 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo,
474 } 473 }
475 474
476 int text_width, text_height; 475 int text_width, text_height;
477 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 476 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
478 1, output->bar->mode_pango_markup, 477 1, output->bar->mode_pango_markup,
479 "%s", mode); 478 "%s", mode);
480 479
@@ -551,7 +550,7 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx,
551 cairo_t *cairo = ctx->cairo; 550 cairo_t *cairo = ctx->cairo;
552 struct swaybar_config *config = output->bar->config; 551 struct swaybar_config *config = output->bar->config;
553 int text_width, text_height; 552 int text_width, text_height;
554 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 553 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
555 1, output->bar->mode_pango_markup, 554 1, output->bar->mode_pango_markup,
556 "%s", mode); 555 "%s", mode);
557 556
@@ -592,17 +591,22 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx,
592 cairo_set_source_u32(cairo, config->colors.binding_mode.text); 591 cairo_set_source_u32(cairo, config->colors.binding_mode.text);
593 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); 592 cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
594 choose_text_aa_mode(ctx, config->colors.binding_mode.text); 593 choose_text_aa_mode(ctx, config->colors.binding_mode.text);
595 render_text(cairo, config->font, 1, output->bar->mode_pango_markup, 594 render_text(cairo, config->font_description, 1, output->bar->mode_pango_markup,
596 "%s", mode); 595 "%s", mode);
597 return output->height; 596 return output->height;
598} 597}
599 598
600static enum hotspot_event_handling workspace_hotspot_callback( 599static enum hotspot_event_handling workspace_hotspot_callback(
601 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 600 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
602 double x, double y, uint32_t button, void *data) { 601 double x, double y, uint32_t button, bool released, void *data) {
603 if (button != BTN_LEFT) { 602 if (button != BTN_LEFT) {
604 return HOTSPOT_PROCESS; 603 return HOTSPOT_PROCESS;
605 } 604 }
605 if (released) {
606 // Since we handle the pressed event, also handle the released event
607 // to block it from falling through to a binding in the bar
608 return HOTSPOT_IGNORE;
609 }
606 ipc_send_workspace_command(output->bar, (const char *)data); 610 ipc_send_workspace_command(output->bar, (const char *)data);
607 return HOTSPOT_IGNORE; 611 return HOTSPOT_IGNORE;
608} 612}
@@ -626,7 +630,7 @@ static uint32_t render_workspace_button(struct render_context *ctx,
626 630
627 cairo_t *cairo = ctx->cairo; 631 cairo_t *cairo = ctx->cairo;
628 int text_width, text_height; 632 int text_width, text_height;
629 get_text_size(cairo, config->font, &text_width, &text_height, NULL, 633 get_text_size(cairo, config->font_description, &text_width, &text_height, NULL,
630 1, config->pango_markup, "%s", ws->label); 634 1, config->pango_markup, "%s", ws->label);
631 635
632 int ws_vertical_padding = WS_VERTICAL_PADDING; 636 int ws_vertical_padding = WS_VERTICAL_PADDING;
@@ -666,7 +670,7 @@ static uint32_t render_workspace_button(struct render_context *ctx,
666 cairo_set_source_u32(cairo, box_colors.text); 670 cairo_set_source_u32(cairo, box_colors.text);
667 cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y)); 671 cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y));
668 choose_text_aa_mode(ctx, box_colors.text); 672 choose_text_aa_mode(ctx, box_colors.text);
669 render_text(cairo, config->font, 1, config->pango_markup, 673 render_text(cairo, config->font_description, 1, config->pango_markup,
670 "%s", ws->label); 674 "%s", ws->label);
671 675
672 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); 676 struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
@@ -688,18 +692,9 @@ static uint32_t render_to_cairo(struct render_context *ctx) {
688 struct swaybar_output *output = ctx->output; 692 struct swaybar_output *output = ctx->output;
689 struct swaybar *bar = output->bar; 693 struct swaybar *bar = output->bar;
690 struct swaybar_config *config = bar->config; 694 struct swaybar_config *config = bar->config;
691 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
692 if (output->focused) {
693 ctx->background_color = config->colors.focused_background;
694 } else {
695 ctx->background_color = config->colors.background;
696 }
697
698 cairo_set_source_u32(cairo, ctx->background_color);
699 cairo_paint(cairo);
700 695
701 int th; 696 int th;
702 get_text_size(cairo, config->font, NULL, &th, NULL, 1, false, ""); 697 get_text_size(cairo, config->font_description, NULL, &th, NULL, 1, false, "");
703 uint32_t max_height = (th + WS_VERTICAL_PADDING * 4); 698 uint32_t max_height = (th + WS_VERTICAL_PADDING * 4);
704 /* 699 /*
705 * Each render_* function takes the actual height of the bar, and returns 700 * Each render_* function takes the actual height of the bar, and returns
@@ -758,8 +753,17 @@ void render_frame(struct swaybar_output *output) {
758 753
759 free_hotspots(&output->hotspots); 754 free_hotspots(&output->hotspots);
760 755
756 uint32_t background_color;
757 if (output->focused) {
758 background_color = output->bar->config->colors.focused_background;
759 } else {
760 background_color = output->bar->config->colors.background;
761 }
762
761 struct render_context ctx = { 0 }; 763 struct render_context ctx = { 0 };
762 ctx.output = output; 764 ctx.output = output;
765 // initial background color used for deciding the best way to antialias text
766 ctx.background_color = background_color;
763 767
764 cairo_surface_t *recorder = cairo_recording_surface_create( 768 cairo_surface_t *recorder = cairo_recording_surface_create(
765 CAIRO_CONTENT_COLOR_ALPHA, NULL); 769 CAIRO_CONTENT_COLOR_ALPHA, NULL);
@@ -769,24 +773,23 @@ void render_frame(struct swaybar_output *output) {
769 ctx.cairo = cairo; 773 ctx.cairo = cairo;
770 774
771 cairo_font_options_t *fo = cairo_font_options_create(); 775 cairo_font_options_t *fo = cairo_font_options_create();
772 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
773 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); 776 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
774 ctx.textaa_safe = fo; 777 ctx.textaa_safe = fo;
775 if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { 778 if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
776 ctx.textaa_sharp = ctx.textaa_safe; 779 ctx.textaa_sharp = ctx.textaa_safe;
777 } else { 780 } else {
778 fo = cairo_font_options_create(); 781 fo = cairo_font_options_create();
779 cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL);
780 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); 782 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
781 cairo_font_options_set_subpixel_order(fo, 783 cairo_font_options_set_subpixel_order(fo,
782 to_cairo_subpixel_order(output->subpixel)); 784 to_cairo_subpixel_order(output->subpixel));
783 ctx.textaa_sharp = fo; 785 ctx.textaa_sharp = fo;
784 } 786 }
785 787
786 cairo_save(cairo); 788
787 cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); 789 cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
790 cairo_set_source_u32(cairo, background_color);
788 cairo_paint(cairo); 791 cairo_paint(cairo);
789 cairo_restore(cairo); 792
790 uint32_t height = render_to_cairo(&ctx); 793 uint32_t height = render_to_cairo(&ctx);
791 int config_height = output->bar->config->height; 794 int config_height = output->bar->config->height;
792 if (config_height > 0) { 795 if (config_height > 0) {
@@ -831,13 +834,15 @@ void render_frame(struct swaybar_output *output) {
831 wl_surface_damage(output->surface, 0, 0, 834 wl_surface_damage(output->surface, 0, 0,
832 output->width, output->height); 835 output->width, output->height);
833 836
834 uint32_t bg_alpha = ctx.background_color & 0xFF; 837 uint32_t bg_alpha = background_color & 0xFF;
835 if (bg_alpha == 0xFF) { 838 if (bg_alpha == 0xFF) {
836 struct wl_region *region = 839 struct wl_region *region =
837 wl_compositor_create_region(output->bar->compositor); 840 wl_compositor_create_region(output->bar->compositor);
838 wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); 841 wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
839 wl_surface_set_opaque_region(output->surface, region); 842 wl_surface_set_opaque_region(output->surface, region);
840 wl_region_destroy(region); 843 wl_region_destroy(region);
844 } else {
845 wl_surface_set_opaque_region(output->surface, NULL);
841 } 846 }
842 847
843 struct wl_callback *frame_callback = wl_surface_frame(output->surface); 848 struct wl_callback *frame_callback = wl_surface_frame(output->surface);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index 2e9bb7f1..e542e606 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 1#include <assert.h>
3#include <fcntl.h> 2#include <fcntl.h>
4#include <sys/ioctl.h> 3#include <sys/ioctl.h>
diff --git a/swaybar/tray/host.c b/swaybar/tray/host.c
index ddf2416d..79b54606 100644
--- a/swaybar/tray/host.c
+++ b/swaybar/tray/host.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdbool.h> 1#include <stdbool.h>
3#include <stdio.h> 2#include <stdio.h>
4#include <stdlib.h> 3#include <stdlib.h>
@@ -10,6 +9,7 @@
10#include "swaybar/tray/tray.h" 9#include "swaybar/tray/tray.h"
11#include "list.h" 10#include "list.h"
12#include "log.h" 11#include "log.h"
12#include "stringop.h"
13 13
14static const char *watcher_path = "/StatusNotifierWatcher"; 14static const char *watcher_path = "/StatusNotifierWatcher";
15 15
@@ -138,12 +138,10 @@ static int handle_new_watcher(sd_bus_message *msg,
138 138
139bool init_host(struct swaybar_host *host, char *protocol, 139bool init_host(struct swaybar_host *host, char *protocol,
140 struct swaybar_tray *tray) { 140 struct swaybar_tray *tray) {
141 size_t len = snprintf(NULL, 0, "org.%s.StatusNotifierWatcher", protocol) + 1; 141 host->watcher_interface = format_str("org.%s.StatusNotifierWatcher", protocol);
142 host->watcher_interface = malloc(len);
143 if (!host->watcher_interface) { 142 if (!host->watcher_interface) {
144 return false; 143 return false;
145 } 144 }
146 snprintf(host->watcher_interface, len, "org.%s.StatusNotifierWatcher", protocol);
147 145
148 sd_bus_slot *reg_slot = NULL, *unreg_slot = NULL, *watcher_slot = NULL; 146 sd_bus_slot *reg_slot = NULL, *unreg_slot = NULL, *watcher_slot = NULL;
149 int ret = sd_bus_match_signal(tray->bus, &reg_slot, host->watcher_interface, 147 int ret = sd_bus_match_signal(tray->bus, &reg_slot, host->watcher_interface,
@@ -173,13 +171,10 @@ bool init_host(struct swaybar_host *host, char *protocol,
173 } 171 }
174 172
175 pid_t pid = getpid(); 173 pid_t pid = getpid();
176 size_t service_len = snprintf(NULL, 0, "org.%s.StatusNotifierHost-%d", 174 host->service = format_str("org.%s.StatusNotifierHost-%d", protocol, pid);
177 protocol, pid) + 1;
178 host->service = malloc(service_len);
179 if (!host->service) { 175 if (!host->service) {
180 goto error; 176 goto error;
181 } 177 }
182 snprintf(host->service, service_len, "org.%s.StatusNotifierHost-%d", protocol, pid);
183 ret = sd_bus_request_name(tray->bus, host->service, 0); 178 ret = sd_bus_request_name(tray->bus, host->service, 0);
184 if (ret < 0) { 179 if (ret < 0) {
185 sway_log(SWAY_DEBUG, "Failed to acquire service name: %s", strerror(-ret)); 180 sway_log(SWAY_DEBUG, "Failed to acquire service name: %s", strerror(-ret));
diff --git a/swaybar/tray/icon.c b/swaybar/tray/icon.c
index c426c3d4..659edd86 100644
--- a/swaybar/tray/icon.c
+++ b/swaybar/tray/icon.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <ctype.h> 1#include <ctype.h>
3#include <dirent.h> 2#include <dirent.h>
4#include <stdbool.h> 3#include <stdbool.h>
@@ -40,9 +39,7 @@ static list_t *get_basedirs(void) {
40 data_dirs = strdup(data_dirs); 39 data_dirs = strdup(data_dirs);
41 char *dir = strtok(data_dirs, ":"); 40 char *dir = strtok(data_dirs, ":");
42 do { 41 do {
43 size_t path_len = snprintf(NULL, 0, "%s/icons", dir) + 1; 42 char *path = format_str("%s/icons", dir);
44 char *path = malloc(path_len);
45 snprintf(path, path_len, "%s/icons", dir);
46 list_add(basedirs, path); 43 list_add(basedirs, path);
47 } while ((dir = strtok(NULL, ":"))); 44 } while ((dir = strtok(NULL, ":")));
48 free(data_dirs); 45 free(data_dirs);
@@ -206,13 +203,7 @@ static const char *entry_handler(char *group, char *key, char *value,
206 */ 203 */
207static struct icon_theme *read_theme_file(char *basedir, char *theme_name) { 204static struct icon_theme *read_theme_file(char *basedir, char *theme_name) {
208 // look for index.theme file 205 // look for index.theme file
209 size_t path_len = snprintf(NULL, 0, "%s/%s/index.theme", basedir, 206 char *path = format_str("%s/%s/index.theme", basedir, theme_name);
210 theme_name) + 1;
211 char *path = malloc(path_len);
212 if (!path) {
213 return NULL;
214 }
215 snprintf(path, path_len, "%s/%s/index.theme", basedir, theme_name);
216 FILE *theme_file = fopen(path, "r"); 207 FILE *theme_file = fopen(path, "r");
217 free(path); 208 free(path);
218 if (!theme_file) { 209 if (!theme_file) {
@@ -416,26 +407,20 @@ static char *find_icon_in_subdir(char *name, char *basedir, char *theme,
416#endif 407#endif
417 }; 408 };
418 409
419 size_t path_len = snprintf(NULL, 0, "%s/%s/%s/%s.EXT", basedir, theme,
420 subdir, name) + 1;
421 char *path = malloc(path_len);
422
423 for (size_t i = 0; i < sizeof(extensions) / sizeof(*extensions); ++i) { 410 for (size_t i = 0; i < sizeof(extensions) / sizeof(*extensions); ++i) {
424 snprintf(path, path_len, "%s/%s/%s/%s.%s", basedir, theme, subdir, 411 char *path = format_str("%s/%s/%s/%s.%s",
425 name, extensions[i]); 412 basedir, theme, subdir, name, extensions[i]);
426 if (access(path, R_OK) == 0) { 413 if (access(path, R_OK) == 0) {
427 return path; 414 return path;
428 } 415 }
416 free(path);
429 } 417 }
430 418
431 free(path);
432 return NULL; 419 return NULL;
433} 420}
434 421
435static bool theme_exists_in_basedir(char *theme, char *basedir) { 422static bool theme_exists_in_basedir(char *theme, char *basedir) {
436 size_t path_len = snprintf(NULL, 0, "%s/%s", basedir, theme) + 1; 423 char *path = format_str("%s/%s", basedir, theme);
437 char *path = malloc(path_len);
438 snprintf(path, path_len, "%s/%s", basedir, theme);
439 bool ret = dir_exists(path); 424 bool ret = dir_exists(path);
440 free(path); 425 free(path);
441 return ret; 426 return ret;
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c
index 0cb5ee9d..ca6c03ad 100644
--- a/swaybar/tray/item.c
+++ b/swaybar/tray/item.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <arpa/inet.h> 1#include <arpa/inet.h>
3#include <cairo.h> 2#include <cairo.h>
4#include <limits.h> 3#include <limits.h>
@@ -7,12 +6,12 @@
7#include <string.h> 6#include <string.h>
8#include "swaybar/bar.h" 7#include "swaybar/bar.h"
9#include "swaybar/config.h" 8#include "swaybar/config.h"
9#include "swaybar/image.h"
10#include "swaybar/input.h" 10#include "swaybar/input.h"
11#include "swaybar/tray/host.h" 11#include "swaybar/tray/host.h"
12#include "swaybar/tray/icon.h" 12#include "swaybar/tray/icon.h"
13#include "swaybar/tray/item.h" 13#include "swaybar/tray/item.h"
14#include "swaybar/tray/tray.h" 14#include "swaybar/tray/tray.h"
15#include "background-image.h"
16#include "cairo_util.h" 15#include "cairo_util.h"
17#include "list.h" 16#include "list.h"
18#include "log.h" 17#include "log.h"
@@ -385,13 +384,18 @@ static int cmp_sni_id(const void *item, const void *cmp_to) {
385 384
386static enum hotspot_event_handling icon_hotspot_callback( 385static enum hotspot_event_handling icon_hotspot_callback(
387 struct swaybar_output *output, struct swaybar_hotspot *hotspot, 386 struct swaybar_output *output, struct swaybar_hotspot *hotspot,
388 double x, double y, uint32_t button, void *data) { 387 double x, double y, uint32_t button, bool released, void *data) {
389 sway_log(SWAY_DEBUG, "Clicked on %s", (char *)data); 388 sway_log(SWAY_DEBUG, "Clicked on %s", (char *)data);
390 389
391 struct swaybar_tray *tray = output->bar->tray; 390 struct swaybar_tray *tray = output->bar->tray;
392 int idx = list_seq_find(tray->items, cmp_sni_id, data); 391 int idx = list_seq_find(tray->items, cmp_sni_id, data);
393 392
394 if (idx != -1) { 393 if (idx != -1) {
394 if (released) {
395 // Since we handle the pressed event, also handle the released event
396 // to block it from falling through to a binding in the bar
397 return HOTSPOT_IGNORE;
398 }
395 struct swaybar_sni *sni = tray->items->items[idx]; 399 struct swaybar_sni *sni = tray->items->items[idx];
396 // guess global position since wayland doesn't expose it 400 // guess global position since wayland doesn't expose it
397 struct swaybar_config *config = tray->bar->config; 401 struct swaybar_config *config = tray->bar->config;
@@ -426,7 +430,7 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme,
426 list_free(icon_search_paths); 430 list_free(icon_search_paths);
427 if (icon_path) { 431 if (icon_path) {
428 cairo_surface_destroy(sni->icon); 432 cairo_surface_destroy(sni->icon);
429 sni->icon = load_background_image(icon_path); 433 sni->icon = load_image(icon_path);
430 free(icon_path); 434 free(icon_path);
431 return; 435 return;
432 } 436 }
diff --git a/swaybar/tray/watcher.c b/swaybar/tray/watcher.c
index 16afc27c..3cfea8d8 100644
--- a/swaybar/tray/watcher.c
+++ b/swaybar/tray/watcher.c
@@ -1,4 +1,3 @@
1#define _POSIX_C_SOURCE 200809L
2#include <stdbool.h> 1#include <stdbool.h>
3#include <stddef.h> 2#include <stddef.h>
4#include <stdio.h> 3#include <stdio.h>
@@ -6,6 +5,7 @@
6#include <string.h> 5#include <string.h>
7#include "list.h" 6#include "list.h"
8#include "log.h" 7#include "log.h"
8#include "stringop.h"
9#include "swaybar/tray/watcher.h" 9#include "swaybar/tray/watcher.h"
10 10
11static const char *obj_path = "/StatusNotifierWatcher"; 11static const char *obj_path = "/StatusNotifierWatcher";
@@ -76,9 +76,7 @@ static int register_sni(sd_bus_message *msg, void *data, sd_bus_error *error) {
76 service = service_or_path; 76 service = service_or_path;
77 path = "/StatusNotifierItem"; 77 path = "/StatusNotifierItem";
78 } 78 }
79 size_t id_len = snprintf(NULL, 0, "%s%s", service, path) + 1; 79 id = format_str("%s%s", service, path);
80 id = malloc(id_len);
81 snprintf(id, id_len, "%s%s", service, path);
82 } 80 }
83 81
84 if (list_seq_find(watcher->items, cmp_id, id) == -1) { 82 if (list_seq_find(watcher->items, cmp_id, id) == -1) {
@@ -107,7 +105,7 @@ static int register_host(sd_bus_message *msg, void *data, sd_bus_error *error) {
107 sway_log(SWAY_DEBUG, "Registering Status Notifier Host '%s'", service); 105 sway_log(SWAY_DEBUG, "Registering Status Notifier Host '%s'", service);
108 list_add(watcher->hosts, strdup(service)); 106 list_add(watcher->hosts, strdup(service));
109 sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, 107 sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
110 "StatusNotifierHostRegistered", "s", service); 108 "StatusNotifierHostRegistered", "");
111 } else { 109 } else {
112 sway_log(SWAY_DEBUG, "Status Notifier Host '%s' already registered", service); 110 sway_log(SWAY_DEBUG, "Status Notifier Host '%s' already registered", service);
113 } 111 }
@@ -159,9 +157,7 @@ struct swaybar_watcher *create_watcher(char *protocol, sd_bus *bus) {
159 return NULL; 157 return NULL;
160 } 158 }
161 159
162 size_t len = snprintf(NULL, 0, "org.%s.StatusNotifierWatcher", protocol) + 1; 160 watcher->interface = format_str("org.%s.StatusNotifierWatcher", protocol);
163 watcher->interface = malloc(len);
164 snprintf(watcher->interface, len, "org.%s.StatusNotifierWatcher", protocol);
165 161
166 sd_bus_slot *signal_slot = NULL, *vtable_slot = NULL; 162 sd_bus_slot *signal_slot = NULL, *vtable_slot = NULL;
167 int ret = sd_bus_add_object_vtable(bus, &vtable_slot, obj_path, 163 int ret = sd_bus_add_object_vtable(bus, &vtable_slot, obj_path,