diff options
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/bar.c | 35 | ||||
-rw-r--r-- | swaybar/config.c | 5 | ||||
-rw-r--r-- | swaybar/i3bar.c | 39 | ||||
-rw-r--r-- | swaybar/image.c | 136 | ||||
-rw-r--r-- | swaybar/input.c | 60 | ||||
-rw-r--r-- | swaybar/ipc.c | 21 | ||||
-rw-r--r-- | swaybar/main.c | 1 | ||||
-rw-r--r-- | swaybar/meson.build | 5 | ||||
-rw-r--r-- | swaybar/render.c | 292 | ||||
-rw-r--r-- | swaybar/status_line.c | 14 | ||||
-rw-r--r-- | swaybar/tray/host.c | 11 | ||||
-rw-r--r-- | swaybar/tray/icon.c | 27 | ||||
-rw-r--r-- | swaybar/tray/item.c | 43 | ||||
-rw-r--r-- | swaybar/tray/tray.c | 4 | ||||
-rw-r--r-- | swaybar/tray/watcher.c | 12 |
15 files changed, 437 insertions, 268 deletions
diff --git a/swaybar/bar.c b/swaybar/bar.c index 15eab782..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> |
@@ -51,10 +50,6 @@ static void swaybar_output_free(struct swaybar_output *output) { | |||
51 | if (output->surface != NULL) { | 50 | if (output->surface != NULL) { |
52 | wl_surface_destroy(output->surface); | 51 | wl_surface_destroy(output->surface); |
53 | } | 52 | } |
54 | if (output->input_region != NULL) { | ||
55 | wl_region_destroy(output->input_region); | ||
56 | } | ||
57 | zxdg_output_v1_destroy(output->xdg_output); | ||
58 | wl_output_destroy(output->output); | 53 | wl_output_destroy(output->output); |
59 | destroy_buffer(&output->buffers[0]); | 54 | destroy_buffer(&output->buffers[0]); |
60 | destroy_buffer(&output->buffers[1]); | 55 | destroy_buffer(&output->buffers[1]); |
@@ -114,10 +109,9 @@ static void add_layer_surface(struct swaybar_output *output) { | |||
114 | 109 | ||
115 | if (overlay) { | 110 | if (overlay) { |
116 | // Empty input region | 111 | // Empty input region |
117 | output->input_region = wl_compositor_create_region(bar->compositor); | 112 | struct wl_region *region = wl_compositor_create_region(bar->compositor); |
118 | assert(output->input_region); | 113 | wl_surface_set_input_region(output->surface, region); |
119 | 114 | wl_region_destroy(region); | |
120 | wl_surface_set_input_region(output->surface, output->input_region); | ||
121 | } | 115 | } |
122 | 116 | ||
123 | zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position); | 117 | zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position); |
@@ -172,7 +166,7 @@ bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) { | |||
172 | if (bar->status) { | 166 | if (bar->status) { |
173 | sway_log(SWAY_DEBUG, "Sending %s signal to status command", | 167 | sway_log(SWAY_DEBUG, "Sending %s signal to status command", |
174 | visible ? "cont" : "stop"); | 168 | visible ? "cont" : "stop"); |
175 | kill(bar->status->pid, visible ? | 169 | kill(-bar->status->pid, visible ? |
176 | bar->status->cont_signal : bar->status->stop_signal); | 170 | bar->status->cont_signal : bar->status->stop_signal); |
177 | } | 171 | } |
178 | } | 172 | } |
@@ -367,6 +361,9 @@ static void handle_global(void *data, struct wl_registry *registry, | |||
367 | } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { | 361 | } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) { |
368 | bar->xdg_output_manager = wl_registry_bind(registry, name, | 362 | bar->xdg_output_manager = wl_registry_bind(registry, name, |
369 | &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); | ||
370 | } | 367 | } |
371 | } | 368 | } |
372 | 369 | ||
@@ -430,15 +427,17 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) { | |||
430 | // Second roundtrip for xdg-output | 427 | // Second roundtrip for xdg-output |
431 | wl_display_roundtrip(bar->display); | 428 | wl_display_roundtrip(bar->display); |
432 | 429 | ||
433 | struct swaybar_seat *seat; | 430 | if (!bar->cursor_shape_manager) { |
434 | wl_list_for_each(seat, &bar->seats, link) { | 431 | struct swaybar_seat *seat; |
435 | struct swaybar_pointer *pointer = &seat->pointer; | 432 | wl_list_for_each(seat, &bar->seats, link) { |
436 | if (!pointer) { | 433 | struct swaybar_pointer *pointer = &seat->pointer; |
437 | continue; | 434 | if (!pointer) { |
435 | continue; | ||
436 | } | ||
437 | pointer->cursor_surface = | ||
438 | wl_compositor_create_surface(bar->compositor); | ||
439 | assert(pointer->cursor_surface); | ||
438 | } | 440 | } |
439 | pointer->cursor_surface = | ||
440 | wl_compositor_create_surface(bar->compositor); | ||
441 | assert(pointer->cursor_surface); | ||
442 | } | 441 | } |
443 | 442 | ||
444 | 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 | ||
106 | void free_config(struct swaybar_config *config) { | 105 | void 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 4bcd5843..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> |
@@ -28,6 +27,19 @@ void i3bar_block_unref(struct i3bar_block *block) { | |||
28 | } | 27 | } |
29 | } | 28 | } |
30 | 29 | ||
30 | static bool i3bar_parse_json_color(json_object *json, uint32_t *color) { | ||
31 | if (!json) { | ||
32 | return false; | ||
33 | } | ||
34 | |||
35 | const char *hexstring = json_object_get_string(json); | ||
36 | bool color_set = parse_color(hexstring, color); | ||
37 | if (!color_set) { | ||
38 | sway_log(SWAY_ERROR, "Ignoring invalid block hexadecimal color string: %s", hexstring); | ||
39 | } | ||
40 | return color_set; | ||
41 | } | ||
42 | |||
31 | static void i3bar_parse_json(struct status_line *status, | 43 | static void i3bar_parse_json(struct status_line *status, |
32 | struct json_object *json_array) { | 44 | struct json_object *json_array) { |
33 | struct i3bar_block *block, *tmp; | 45 | struct i3bar_block *block, *tmp; |
@@ -68,13 +80,7 @@ static void i3bar_parse_json(struct status_line *status, | |||
68 | strdup(json_object_get_string(full_text)) : NULL; | 80 | strdup(json_object_get_string(full_text)) : NULL; |
69 | block->short_text = short_text ? | 81 | block->short_text = short_text ? |
70 | strdup(json_object_get_string(short_text)) : NULL; | 82 | strdup(json_object_get_string(short_text)) : NULL; |
71 | if (color) { | 83 | block->color_set = i3bar_parse_json_color(color, &block->color); |
72 | const char *hexstring = json_object_get_string(color); | ||
73 | block->color_set = parse_color(hexstring, &block->color); | ||
74 | if (!block->color_set) { | ||
75 | sway_log(SWAY_ERROR, "Invalid block color: %s", hexstring); | ||
76 | } | ||
77 | } | ||
78 | if (min_width) { | 84 | if (min_width) { |
79 | json_type type = json_object_get_type(min_width); | 85 | json_type type = json_object_get_type(min_width); |
80 | if (type == json_type_int) { | 86 | if (type == json_type_int) { |
@@ -100,14 +106,8 @@ static void i3bar_parse_json(struct status_line *status, | |||
100 | block->separator_block_width = separator_block_width ? | 106 | block->separator_block_width = separator_block_width ? |
101 | json_object_get_int(separator_block_width) : 9; | 107 | json_object_get_int(separator_block_width) : 9; |
102 | // Airblader features | 108 | // Airblader features |
103 | const char *hex = background ? json_object_get_string(background) : NULL; | 109 | i3bar_parse_json_color(background, &block->background); |
104 | if (hex && !parse_color(hex, &block->background)) { | 110 | block->border_set = i3bar_parse_json_color(border, &block->border); |
105 | sway_log(SWAY_ERROR, "Ignoring invalid block background: %s", hex); | ||
106 | } | ||
107 | hex = border ? json_object_get_string(border) : NULL; | ||
108 | if (hex && !parse_color(hex, &block->border)) { | ||
109 | sway_log(SWAY_ERROR, "Ignoring invalid block border: %s", hex); | ||
110 | } | ||
111 | block->border_top = border_top ? json_object_get_int(border_top) : 1; | 111 | block->border_top = border_top ? json_object_get_int(border_top) : 1; |
112 | block->border_bottom = border_bottom ? | 112 | block->border_bottom = border_bottom ? |
113 | json_object_get_int(border_bottom) : 1; | 113 | json_object_get_int(border_bottom) : 1; |
@@ -268,11 +268,16 @@ bool i3bar_handle_readable(struct status_line *status) { | |||
268 | 268 | ||
269 | enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, | 269 | enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, |
270 | 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, |
271 | double w, double h, int scale, uint32_t button) { | 271 | double w, double h, int scale, uint32_t button, bool released) { |
272 | sway_log(SWAY_DEBUG, "block %s clicked", block->name); | 272 | sway_log(SWAY_DEBUG, "block %s clicked", block->name); |
273 | if (!block->name || !status->click_events) { | 273 | if (!block->name || !status->click_events) { |
274 | return HOTSPOT_PROCESS; | 274 | return HOTSPOT_PROCESS; |
275 | } | 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 | } | ||
276 | 281 | ||
277 | struct json_object *event_json = json_object_new_object(); | 282 | struct json_object *event_json = json_object_new_object(); |
278 | 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 | ||
11 | static 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 | |||
107 | cairo_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 6e13f177..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 | ||
117 | static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, | 136 | static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, |
@@ -141,16 +160,15 @@ static bool check_bindings(struct swaybar *bar, uint32_t button, | |||
141 | } | 160 | } |
142 | 161 | ||
143 | static bool process_hotspots(struct swaybar_output *output, | 162 | static 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) { |
145 | double px = x * output->scale; | 164 | bool released = state == WL_POINTER_BUTTON_STATE_RELEASED; |
146 | double py = y * output->scale; | ||
147 | struct swaybar_hotspot *hotspot; | 165 | struct swaybar_hotspot *hotspot; |
148 | wl_list_for_each(hotspot, &output->hotspots, link) { | 166 | wl_list_for_each(hotspot, &output->hotspots, link) { |
149 | if (px >= hotspot->x && py >= hotspot->y | 167 | if (x >= hotspot->x && y >= hotspot->y |
150 | && px < hotspot->x + hotspot->width | 168 | && x < hotspot->x + hotspot->width |
151 | && py < hotspot->y + hotspot->height) { | 169 | && y < hotspot->y + hotspot->height) { |
152 | if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y, | 170 | if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y, |
153 | button, hotspot->data)) { | 171 | button, released, hotspot->data)) { |
154 | return true; | 172 | return true; |
155 | } | 173 | } |
156 | } | 174 | } |
@@ -168,14 +186,11 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, | |||
168 | return; | 186 | return; |
169 | } | 187 | } |
170 | 188 | ||
171 | if (check_bindings(seat->bar, button, state)) { | 189 | if (process_hotspots(output, pointer->x, pointer->y, button, state)) { |
172 | return; | 190 | return; |
173 | } | 191 | } |
174 | 192 | ||
175 | if (state != WL_POINTER_BUTTON_STATE_PRESSED) { | 193 | check_bindings(seat->bar, button, state); |
176 | return; | ||
177 | } | ||
178 | process_hotspots(output, pointer->x, pointer->y, button); | ||
179 | } | 194 | } |
180 | 195 | ||
181 | static void workspace_next(struct swaybar *bar, struct swaybar_output *output, | 196 | static void workspace_next(struct swaybar *bar, struct swaybar_output *output, |
@@ -211,7 +226,7 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output, | |||
211 | } | 226 | } |
212 | } | 227 | } |
213 | 228 | ||
214 | if (new) { | 229 | if (new && new != active) { |
215 | ipc_send_workspace_command(bar, new->name); | 230 | ipc_send_workspace_command(bar, new->name); |
216 | 231 | ||
217 | // 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. |
@@ -224,15 +239,15 @@ static void workspace_next(struct swaybar *bar, struct swaybar_output *output, | |||
224 | static void process_discrete_scroll(struct swaybar_seat *seat, | 239 | static void process_discrete_scroll(struct swaybar_seat *seat, |
225 | struct swaybar_output *output, struct swaybar_pointer *pointer, | 240 | struct swaybar_output *output, struct swaybar_pointer *pointer, |
226 | uint32_t axis, wl_fixed_t value) { | 241 | uint32_t axis, wl_fixed_t value) { |
227 | // If there is a button press binding, execute it, skip default behavior, | ||
228 | // and check button release bindings | ||
229 | uint32_t button = wl_axis_to_button(axis, value); | 242 | uint32_t button = wl_axis_to_button(axis, value); |
230 | 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)) { |
231 | 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) |
232 | return; | 245 | return; |
233 | } | 246 | } |
234 | 247 | ||
235 | 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); | ||
236 | return; | 251 | return; |
237 | } | 252 | } |
238 | 253 | ||
@@ -405,7 +420,8 @@ static void wl_touch_up(void *data, struct wl_touch *wl_touch, | |||
405 | } | 420 | } |
406 | if (time - slot->time < 500) { | 421 | if (time - slot->time < 500) { |
407 | // Tap, treat it like a pointer click | 422 | // Tap, treat it like a pointer click |
408 | 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) | ||
409 | } | 425 | } |
410 | slot->output = NULL; | 426 | slot->output = NULL; |
411 | } | 427 | } |
diff --git a/swaybar/ipc.c b/swaybar/ipc.c index a64aa1ab..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 | } |
@@ -550,7 +547,7 @@ bool handle_ipc_readable(struct swaybar *bar) { | |||
550 | // The default depth of 32 is too small to represent some nested layouts, but | 547 | // The default depth of 32 is too small to represent some nested layouts, but |
551 | // we can't pass INT_MAX here because json-c (as of this writing) prefaults | 548 | // we can't pass INT_MAX here because json-c (as of this writing) prefaults |
552 | // all the memory for its stack. | 549 | // all the memory for its stack. |
553 | json_tokener *tok = json_tokener_new_ex(256); | 550 | json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH); |
554 | if (!tok) { | 551 | if (!tok) { |
555 | sway_log_errno(SWAY_ERROR, "failed to create tokener"); | 552 | sway_log_errno(SWAY_ERROR, "failed to create tokener"); |
556 | free_ipc_response(resp); | 553 | free_ipc_response(resp); |
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 | ||
9 | swaybar_deps = [ | 9 | swaybar_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 fcc8be1d..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> |
@@ -14,6 +13,7 @@ | |||
14 | #include "swaybar/ipc.h" | 13 | #include "swaybar/ipc.h" |
15 | #include "swaybar/render.h" | 14 | #include "swaybar/render.h" |
16 | #include "swaybar/status_line.h" | 15 | #include "swaybar/status_line.h" |
16 | #include "log.h" | ||
17 | #if HAVE_TRAY | 17 | #if HAVE_TRAY |
18 | #include "swaybar/tray/tray.h" | 18 | #include "swaybar/tray/tray.h" |
19 | #endif | 19 | #endif |
@@ -53,22 +53,21 @@ static uint32_t render_status_line_error(struct render_context *ctx, double *x) | |||
53 | return 0; | 53 | return 0; |
54 | } | 54 | } |
55 | 55 | ||
56 | uint32_t height = output->height * output->scale; | 56 | uint32_t height = output->height; |
57 | 57 | ||
58 | cairo_t *cairo = ctx->cairo; | 58 | cairo_t *cairo = ctx->cairo; |
59 | cairo_set_source_u32(cairo, 0xFF0000FF); | 59 | cairo_set_source_u32(cairo, 0xFF0000FF); |
60 | 60 | ||
61 | int margin = 3 * output->scale; | 61 | int margin = 3; |
62 | double ws_vertical_padding = | 62 | double ws_vertical_padding = output->bar->config->status_padding; |
63 | output->bar->config->status_padding * output->scale; | ||
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 | output->scale, false, "%s", error); | 67 | 1, false, "%s", error); |
69 | 68 | ||
70 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 69 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
71 | uint32_t ideal_surface_height = ideal_height / output->scale; | 70 | uint32_t ideal_surface_height = ideal_height; |
72 | if (!output->bar->config->height && | 71 | if (!output->bar->config->height && |
73 | output->height < ideal_surface_height) { | 72 | output->height < ideal_surface_height) { |
74 | return ideal_surface_height; | 73 | return ideal_surface_height; |
@@ -78,7 +77,7 @@ static uint32_t render_status_line_error(struct render_context *ctx, double *x) | |||
78 | double text_y = height / 2.0 - text_height / 2.0; | 77 | double text_y = height / 2.0 - text_height / 2.0; |
79 | cairo_move_to(cairo, *x, (int)floor(text_y)); | 78 | cairo_move_to(cairo, *x, (int)floor(text_y)); |
80 | choose_text_aa_mode(ctx, 0xFF0000FF); | 79 | choose_text_aa_mode(ctx, 0xFF0000FF); |
81 | pango_printf(cairo, font, output->scale, false, "%s", error); | 80 | render_text(cairo, font, 1, false, "%s", error); |
82 | *x -= margin; | 81 | *x -= margin; |
83 | return output->height; | 82 | return output->height; |
84 | } | 83 | } |
@@ -97,26 +96,25 @@ 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 | output->scale, config->pango_markup, "%s", text); | 100 | 1, config->pango_markup, "%s", text); |
102 | 101 | ||
103 | double ws_vertical_padding = config->status_padding * output->scale; | 102 | double ws_vertical_padding = config->status_padding; |
104 | int margin = 3 * output->scale; | 103 | int margin = 3; |
105 | 104 | ||
106 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 105 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
107 | uint32_t ideal_surface_height = ideal_height / output->scale; | 106 | uint32_t ideal_surface_height = ideal_height; |
108 | if (!output->bar->config->height && | 107 | if (!output->bar->config->height && |
109 | output->height < ideal_surface_height) { | 108 | output->height < ideal_surface_height) { |
110 | return ideal_surface_height; | 109 | return ideal_surface_height; |
111 | } | 110 | } |
112 | 111 | ||
113 | *x -= text_width + margin; | 112 | *x -= text_width + margin; |
114 | uint32_t height = output->height * output->scale; | 113 | uint32_t height = output->height; |
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 | pango_printf(cairo, config->font, output->scale, | 117 | render_text(cairo, config->font_description, 1, config->pango_markup, "%s", text); |
119 | config->pango_markup, "%s", text); | ||
120 | *x -= margin; | 118 | *x -= margin; |
121 | return output->height; | 119 | return output->height; |
122 | } | 120 | } |
@@ -161,15 +159,15 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color, | |||
161 | 159 | ||
162 | static enum hotspot_event_handling block_hotspot_callback( | 160 | static enum hotspot_event_handling block_hotspot_callback( |
163 | struct swaybar_output *output, struct swaybar_hotspot *hotspot, | 161 | struct swaybar_output *output, struct swaybar_hotspot *hotspot, |
164 | double x, double y, uint32_t button, void *data) { | 162 | double x, double y, uint32_t button, bool released, void *data) { |
165 | struct i3bar_block *block = data; | 163 | struct i3bar_block *block = data; |
166 | struct status_line *status = output->bar->status; | 164 | struct status_line *status = output->bar->status; |
167 | return i3bar_block_send_click(status, block, x, y, | 165 | return i3bar_block_send_click(status, block, x, y, |
168 | x - (double)hotspot->x / output->scale, | 166 | x - (double)hotspot->x, |
169 | y - (double)hotspot->y / output->scale, | 167 | y - (double)hotspot->y, |
170 | (double)hotspot->width / output->scale, | 168 | (double)hotspot->width, |
171 | (double)hotspot->height / output->scale, | 169 | (double)hotspot->height, |
172 | output->scale, button); | 170 | output->scale, button, released); |
173 | } | 171 | } |
174 | 172 | ||
175 | static void i3bar_block_unref_callback(void *data) { | 173 | static void i3bar_block_unref_callback(void *data) { |
@@ -191,17 +189,17 @@ static uint32_t render_status_block(struct render_context *ctx, | |||
191 | struct swaybar_output *output = ctx->output; | 189 | struct swaybar_output *output = ctx->output; |
192 | struct swaybar_config *config = output->bar->config; | 190 | struct swaybar_config *config = output->bar->config; |
193 | int text_width, text_height; | 191 | int text_width, text_height; |
194 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 192 | get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1, |
195 | output->scale, block->markup, "%s", text); | 193 | block->markup, "%s", text); |
196 | 194 | ||
197 | int margin = 3 * output->scale; | 195 | int margin = 3; |
198 | double ws_vertical_padding = config->status_padding * output->scale; | 196 | double ws_vertical_padding = config->status_padding; |
199 | 197 | ||
200 | int width = text_width; | 198 | int width = text_width; |
201 | if (block->min_width_str) { | 199 | if (block->min_width_str) { |
202 | int w; | 200 | int w; |
203 | get_text_size(cairo, config->font, &w, NULL, NULL, | 201 | get_text_size(cairo, config->font_description, &w, NULL, NULL, 1, block->markup, |
204 | output->scale, block->markup, "%s", block->min_width_str); | 202 | "%s", block->min_width_str); |
205 | block->min_width = w; | 203 | block->min_width = w; |
206 | } | 204 | } |
207 | if (width < block->min_width) { | 205 | if (width < block->min_width) { |
@@ -210,30 +208,30 @@ static uint32_t render_status_block(struct render_context *ctx, | |||
210 | 208 | ||
211 | double block_width = width; | 209 | double block_width = width; |
212 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 210 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
213 | uint32_t ideal_surface_height = ideal_height / output->scale; | 211 | uint32_t ideal_surface_height = ideal_height; |
214 | if (!output->bar->config->height && | 212 | if (!output->bar->config->height && |
215 | output->height < ideal_surface_height) { | 213 | output->height < ideal_surface_height) { |
216 | return ideal_surface_height; | 214 | return ideal_surface_height; |
217 | } | 215 | } |
218 | 216 | ||
219 | *x -= width; | 217 | *x -= width; |
220 | if ((block->border || block->urgent) && block->border_left > 0) { | 218 | if ((block->border_set || block->urgent) && block->border_left > 0) { |
221 | *x -= (block->border_left * output->scale + margin); | 219 | *x -= (block->border_left + margin); |
222 | block_width += block->border_left * output->scale + margin; | 220 | block_width += block->border_left + margin; |
223 | } | 221 | } |
224 | if ((block->border || block->urgent) && block->border_right > 0) { | 222 | if ((block->border_set || block->urgent) && block->border_right > 0) { |
225 | *x -= (block->border_right * output->scale + margin); | 223 | *x -= (block->border_right + margin); |
226 | block_width += block->border_right * output->scale + margin; | 224 | block_width += block->border_right + margin; |
227 | } | 225 | } |
228 | 226 | ||
229 | int sep_width, sep_height; | 227 | int sep_width, sep_height; |
230 | int sep_block_width = block->separator_block_width; | 228 | int sep_block_width = block->separator_block_width; |
231 | if (!edge) { | 229 | if (!edge) { |
232 | if (config->sep_symbol) { | 230 | if (config->sep_symbol) { |
233 | get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, | 231 | get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL, |
234 | output->scale, false, "%s", config->sep_symbol); | 232 | 1, false, "%s", config->sep_symbol); |
235 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; | 233 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; |
236 | uint32_t _ideal_surface_height = _ideal_height / output->scale; | 234 | uint32_t _ideal_surface_height = _ideal_height; |
237 | if (!output->bar->config->height && | 235 | if (!output->bar->config->height && |
238 | output->height < _ideal_surface_height) { | 236 | output->height < _ideal_surface_height) { |
239 | return _ideal_surface_height; | 237 | return _ideal_surface_height; |
@@ -244,10 +242,10 @@ static uint32_t render_status_block(struct render_context *ctx, | |||
244 | } | 242 | } |
245 | *x -= sep_block_width; | 243 | *x -= sep_block_width; |
246 | } else if (config->status_edge_padding) { | 244 | } else if (config->status_edge_padding) { |
247 | *x -= config->status_edge_padding * output->scale; | 245 | *x -= config->status_edge_padding; |
248 | } | 246 | } |
249 | 247 | ||
250 | uint32_t height = output->height * output->scale; | 248 | uint32_t height = output->height; |
251 | if (output->bar->status->click_events) { | 249 | if (output->bar->status->click_events) { |
252 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 250 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
253 | hotspot->x = *x; | 251 | hotspot->x = *x; |
@@ -275,23 +273,25 @@ static uint32_t render_status_block(struct render_context *ctx, | |||
275 | 273 | ||
276 | uint32_t border_color = block->urgent | 274 | uint32_t border_color = block->urgent |
277 | ? config->colors.urgent_workspace.border : block->border; | 275 | ? config->colors.urgent_workspace.border : block->border; |
278 | if (border_color && block->border_top > 0) { | 276 | if (block->border_set || block->urgent) { |
279 | render_sharp_line(cairo, border_color, x_pos, y_pos, | 277 | if (block->border_top > 0) { |
280 | block_width, block->border_top * output->scale); | 278 | render_sharp_line(cairo, border_color, x_pos, y_pos, |
281 | } | 279 | block_width, block->border_top); |
282 | if (border_color && block->border_bottom > 0) { | 280 | } |
283 | render_sharp_line(cairo, border_color, x_pos, | 281 | if (block->border_bottom > 0) { |
284 | y_pos + render_height - block->border_bottom * output->scale, | 282 | render_sharp_line(cairo, border_color, x_pos, |
285 | block_width, block->border_bottom * output->scale); | 283 | y_pos + render_height - block->border_bottom, |
286 | } | 284 | block_width, block->border_bottom); |
287 | if (border_color && block->border_left > 0) { | 285 | } |
288 | render_sharp_line(cairo, border_color, x_pos, y_pos, | 286 | if (block->border_left > 0) { |
289 | block->border_left * output->scale, render_height); | 287 | render_sharp_line(cairo, border_color, x_pos, y_pos, |
290 | x_pos += block->border_left * output->scale + margin; | 288 | block->border_left, render_height); |
289 | } | ||
290 | x_pos += block->border_left + margin; | ||
291 | } | 291 | } |
292 | 292 | ||
293 | double offset = 0; | 293 | double offset = 0; |
294 | if (strncmp(block->align, "left", 5) == 0) { | 294 | if (strncmp(block->align, "left", 4) == 0) { |
295 | offset = x_pos; | 295 | offset = x_pos; |
296 | } else if (strncmp(block->align, "right", 5) == 0) { | 296 | } else if (strncmp(block->align, "right", 5) == 0) { |
297 | offset = x_pos + width - text_width; | 297 | offset = x_pos + width - text_width; |
@@ -306,15 +306,16 @@ static uint32_t render_status_block(struct render_context *ctx, | |||
306 | color = block->urgent ? config->colors.urgent_workspace.text : color; | 306 | color = block->urgent ? config->colors.urgent_workspace.text : color; |
307 | cairo_set_source_u32(cairo, color); | 307 | cairo_set_source_u32(cairo, color); |
308 | choose_text_aa_mode(ctx, color); | 308 | choose_text_aa_mode(ctx, color); |
309 | pango_printf(cairo, config->font, output->scale, | 309 | render_text(cairo, config->font_description, 1, block->markup, "%s", text); |
310 | block->markup, "%s", text); | ||
311 | x_pos += width; | 310 | x_pos += width; |
312 | 311 | ||
313 | if (block->border && block->border_right > 0) { | 312 | if (block->border_set || block->urgent) { |
314 | x_pos += margin; | 313 | x_pos += margin; |
315 | render_sharp_line(cairo, border_color, x_pos, y_pos, | 314 | if (block->border_right > 0) { |
316 | block->border_right * output->scale, render_height); | 315 | render_sharp_line(cairo, border_color, x_pos, y_pos, |
317 | x_pos += block->border_right * output->scale; | 316 | block->border_right, render_height); |
317 | } | ||
318 | x_pos += block->border_right; | ||
318 | } | 319 | } |
319 | 320 | ||
320 | if (!edge && block->separator) { | 321 | if (!edge && block->separator) { |
@@ -329,7 +330,7 @@ static uint32_t render_status_block(struct render_context *ctx, | |||
329 | double sep_y = height / 2.0 - sep_height / 2.0; | 330 | double sep_y = height / 2.0 - sep_height / 2.0; |
330 | cairo_move_to(cairo, offset, (int)floor(sep_y)); | 331 | cairo_move_to(cairo, offset, (int)floor(sep_y)); |
331 | choose_text_aa_mode(ctx, color); | 332 | choose_text_aa_mode(ctx, color); |
332 | pango_printf(cairo, config->font, output->scale, false, | 333 | render_text(cairo, config->font_description, 1, false, |
333 | "%s", config->sep_symbol); | 334 | "%s", config->sep_symbol); |
334 | } else { | 335 | } else { |
335 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 336 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
@@ -352,18 +353,18 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
352 | struct swaybar_config *config = output->bar->config; | 353 | struct swaybar_config *config = output->bar->config; |
353 | 354 | ||
354 | int text_width, text_height; | 355 | int text_width, text_height; |
355 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 356 | get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1, |
356 | output->scale, block->markup, "%s", block->full_text); | 357 | block->markup, "%s", block->full_text); |
357 | 358 | ||
358 | int margin = 3 * output->scale; | 359 | int margin = 3; |
359 | double ws_vertical_padding = config->status_padding * output->scale; | 360 | double ws_vertical_padding = config->status_padding; |
360 | 361 | ||
361 | int width = text_width; | 362 | int width = text_width; |
362 | 363 | ||
363 | if (block->min_width_str) { | 364 | if (block->min_width_str) { |
364 | int w; | 365 | int w; |
365 | get_text_size(cairo, config->font, &w, NULL, NULL, | 366 | get_text_size(cairo, config->font_description, &w, NULL, NULL, |
366 | output->scale, block->markup, "%s", block->min_width_str); | 367 | 1, block->markup, "%s", block->min_width_str); |
367 | block->min_width = w; | 368 | block->min_width = w; |
368 | } | 369 | } |
369 | if (width < block->min_width) { | 370 | if (width < block->min_width) { |
@@ -371,28 +372,28 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
371 | } | 372 | } |
372 | 373 | ||
373 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 374 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
374 | uint32_t ideal_surface_height = ideal_height / output->scale; | 375 | uint32_t ideal_surface_height = ideal_height; |
375 | if (!output->bar->config->height && | 376 | if (!output->bar->config->height && |
376 | output->height < ideal_surface_height) { | 377 | output->height < ideal_surface_height) { |
377 | return; | 378 | return; |
378 | } | 379 | } |
379 | 380 | ||
380 | *x -= width; | 381 | *x -= width; |
381 | if ((block->border || block->urgent) && block->border_left > 0) { | 382 | if ((block->border_set || block->urgent) && block->border_left > 0) { |
382 | *x -= (block->border_left * output->scale + margin); | 383 | *x -= (block->border_left + margin); |
383 | } | 384 | } |
384 | if ((block->border || block->urgent) && block->border_right > 0) { | 385 | if ((block->border_set || block->urgent) && block->border_right > 0) { |
385 | *x -= (block->border_right * output->scale + margin); | 386 | *x -= (block->border_right + margin); |
386 | } | 387 | } |
387 | 388 | ||
388 | int sep_width, sep_height; | 389 | int sep_width, sep_height; |
389 | int sep_block_width = block->separator_block_width; | 390 | int sep_block_width = block->separator_block_width; |
390 | if (!edge) { | 391 | if (!edge) { |
391 | if (config->sep_symbol) { | 392 | if (config->sep_symbol) { |
392 | get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, | 393 | get_text_size(cairo, config->font_description, &sep_width, &sep_height, NULL, |
393 | output->scale, false, "%s", config->sep_symbol); | 394 | 1, false, "%s", config->sep_symbol); |
394 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; | 395 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; |
395 | uint32_t _ideal_surface_height = _ideal_height / output->scale; | 396 | uint32_t _ideal_surface_height = _ideal_height; |
396 | if (!output->bar->config->height && | 397 | if (!output->bar->config->height && |
397 | output->height < _ideal_surface_height) { | 398 | output->height < _ideal_surface_height) { |
398 | return; | 399 | return; |
@@ -403,13 +404,13 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
403 | } | 404 | } |
404 | *x -= sep_block_width; | 405 | *x -= sep_block_width; |
405 | } else if (config->status_edge_padding) { | 406 | } else if (config->status_edge_padding) { |
406 | *x -= config->status_edge_padding * output->scale; | 407 | *x -= config->status_edge_padding; |
407 | } | 408 | } |
408 | } | 409 | } |
409 | 410 | ||
410 | static double predict_status_line_pos(cairo_t *cairo, | 411 | static double predict_status_line_pos(cairo_t *cairo, |
411 | struct swaybar_output *output, double x) { | 412 | struct swaybar_output *output, double x) { |
412 | bool edge = x == output->width * output->scale; | 413 | bool edge = x == output->width; |
413 | struct i3bar_block *block; | 414 | struct i3bar_block *block; |
414 | wl_list_for_each(block, &output->bar->status->blocks, link) { | 415 | wl_list_for_each(block, &output->bar->status->blocks, link) { |
415 | predict_status_block_pos(cairo, output, block, &x, edge); | 416 | predict_status_block_pos(cairo, output, block, &x, edge); |
@@ -424,24 +425,24 @@ static uint32_t predict_workspace_button_length(cairo_t *cairo, | |||
424 | struct swaybar_config *config = output->bar->config; | 425 | struct swaybar_config *config = output->bar->config; |
425 | 426 | ||
426 | int text_width, text_height; | 427 | int text_width, text_height; |
427 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 428 | get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, 1, |
428 | output->scale, config->pango_markup, "%s", ws->label); | 429 | config->pango_markup, "%s", ws->label); |
429 | 430 | ||
430 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 431 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
431 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 432 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
432 | int border_width = BORDER_WIDTH * output->scale; | 433 | int border_width = BORDER_WIDTH; |
433 | 434 | ||
434 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height | 435 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height |
435 | + border_width * 2; | 436 | + border_width * 2; |
436 | uint32_t ideal_surface_height = ideal_height / output->scale; | 437 | uint32_t ideal_surface_height = ideal_height; |
437 | if (!output->bar->config->height && | 438 | if (!output->bar->config->height && |
438 | output->height < ideal_surface_height) { | 439 | output->height < ideal_surface_height) { |
439 | return 0; | 440 | return 0; |
440 | } | 441 | } |
441 | 442 | ||
442 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 443 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
443 | if (width < config->workspace_min_width * output->scale) { | 444 | if (width < config->workspace_min_width) { |
444 | width = config->workspace_min_width * output->scale; | 445 | width = config->workspace_min_width; |
445 | } | 446 | } |
446 | return width; | 447 | return width; |
447 | } | 448 | } |
@@ -472,24 +473,24 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo, | |||
472 | } | 473 | } |
473 | 474 | ||
474 | int text_width, text_height; | 475 | int text_width, text_height; |
475 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 476 | get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, |
476 | output->scale, output->bar->mode_pango_markup, | 477 | 1, output->bar->mode_pango_markup, |
477 | "%s", mode); | 478 | "%s", mode); |
478 | 479 | ||
479 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 480 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
480 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 481 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
481 | int border_width = BORDER_WIDTH * output->scale; | 482 | int border_width = BORDER_WIDTH; |
482 | 483 | ||
483 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 | 484 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 |
484 | + border_width * 2; | 485 | + border_width * 2; |
485 | uint32_t ideal_surface_height = ideal_height / output->scale; | 486 | uint32_t ideal_surface_height = ideal_height; |
486 | if (!output->bar->config->height && | 487 | if (!output->bar->config->height && |
487 | output->height < ideal_surface_height) { | 488 | output->height < ideal_surface_height) { |
488 | return 0; | 489 | return 0; |
489 | } | 490 | } |
490 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 491 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
491 | if (width < config->workspace_min_width * output->scale) { | 492 | if (width < config->workspace_min_width) { |
492 | width = config->workspace_min_width * output->scale; | 493 | width = config->workspace_min_width; |
493 | } | 494 | } |
494 | return width; | 495 | return width; |
495 | } | 496 | } |
@@ -497,7 +498,7 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo, | |||
497 | static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) { | 498 | static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) { |
498 | struct swaybar_output *output = ctx->output; | 499 | struct swaybar_output *output = ctx->output; |
499 | uint32_t max_height = 0; | 500 | uint32_t max_height = 0; |
500 | bool edge = *x == output->width * output->scale; | 501 | bool edge = *x == output->width; |
501 | struct i3bar_block *block; | 502 | struct i3bar_block *block; |
502 | bool use_short_text = false; | 503 | bool use_short_text = false; |
503 | 504 | ||
@@ -505,7 +506,7 @@ static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) | |||
505 | double reserved_width = | 506 | double reserved_width = |
506 | predict_workspace_buttons_length(cairo, output) + | 507 | predict_workspace_buttons_length(cairo, output) + |
507 | predict_binding_mode_indicator_length(cairo, output) + | 508 | predict_binding_mode_indicator_length(cairo, output) + |
508 | 3 * output->scale; // require a bit of space for margin | 509 | 3; // require a bit of space for margin |
509 | 510 | ||
510 | double predicted_full_pos = | 511 | double predicted_full_pos = |
511 | predict_status_line_pos(cairo, output, *x); | 512 | predict_status_line_pos(cairo, output, *x); |
@@ -549,27 +550,27 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx, | |||
549 | cairo_t *cairo = ctx->cairo; | 550 | cairo_t *cairo = ctx->cairo; |
550 | struct swaybar_config *config = output->bar->config; | 551 | struct swaybar_config *config = output->bar->config; |
551 | int text_width, text_height; | 552 | int text_width, text_height; |
552 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 553 | get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, |
553 | output->scale, output->bar->mode_pango_markup, | 554 | 1, output->bar->mode_pango_markup, |
554 | "%s", mode); | 555 | "%s", mode); |
555 | 556 | ||
556 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 557 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
557 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 558 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
558 | int border_width = BORDER_WIDTH * output->scale; | 559 | int border_width = BORDER_WIDTH; |
559 | 560 | ||
560 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 | 561 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 |
561 | + border_width * 2; | 562 | + border_width * 2; |
562 | uint32_t ideal_surface_height = ideal_height / output->scale; | 563 | uint32_t ideal_surface_height = ideal_height; |
563 | if (!output->bar->config->height && | 564 | if (!output->bar->config->height && |
564 | output->height < ideal_surface_height) { | 565 | output->height < ideal_surface_height) { |
565 | return ideal_surface_height; | 566 | return ideal_surface_height; |
566 | } | 567 | } |
567 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 568 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
568 | if (width < config->workspace_min_width * output->scale) { | 569 | if (width < config->workspace_min_width) { |
569 | width = config->workspace_min_width * output->scale; | 570 | width = config->workspace_min_width; |
570 | } | 571 | } |
571 | 572 | ||
572 | uint32_t height = output->height * output->scale; | 573 | uint32_t height = output->height; |
573 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 574 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
574 | cairo_set_source_u32(cairo, config->colors.binding_mode.background); | 575 | cairo_set_source_u32(cairo, config->colors.binding_mode.background); |
575 | ctx->background_color = config->colors.binding_mode.background; | 576 | ctx->background_color = config->colors.binding_mode.background; |
@@ -590,17 +591,22 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx, | |||
590 | cairo_set_source_u32(cairo, config->colors.binding_mode.text); | 591 | cairo_set_source_u32(cairo, config->colors.binding_mode.text); |
591 | 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)); |
592 | choose_text_aa_mode(ctx, config->colors.binding_mode.text); | 593 | choose_text_aa_mode(ctx, config->colors.binding_mode.text); |
593 | pango_printf(cairo, config->font, output->scale, | 594 | render_text(cairo, config->font_description, 1, output->bar->mode_pango_markup, |
594 | output->bar->mode_pango_markup, "%s", mode); | 595 | "%s", mode); |
595 | return output->height; | 596 | return output->height; |
596 | } | 597 | } |
597 | 598 | ||
598 | static enum hotspot_event_handling workspace_hotspot_callback( | 599 | static enum hotspot_event_handling workspace_hotspot_callback( |
599 | struct swaybar_output *output, struct swaybar_hotspot *hotspot, | 600 | struct swaybar_output *output, struct swaybar_hotspot *hotspot, |
600 | double x, double y, uint32_t button, void *data) { | 601 | double x, double y, uint32_t button, bool released, void *data) { |
601 | if (button != BTN_LEFT) { | 602 | if (button != BTN_LEFT) { |
602 | return HOTSPOT_PROCESS; | 603 | return HOTSPOT_PROCESS; |
603 | } | 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 | } | ||
604 | ipc_send_workspace_command(output->bar, (const char *)data); | 610 | ipc_send_workspace_command(output->bar, (const char *)data); |
605 | return HOTSPOT_IGNORE; | 611 | return HOTSPOT_IGNORE; |
606 | } | 612 | } |
@@ -620,28 +626,28 @@ static uint32_t render_workspace_button(struct render_context *ctx, | |||
620 | box_colors = config->colors.inactive_workspace; | 626 | box_colors = config->colors.inactive_workspace; |
621 | } | 627 | } |
622 | 628 | ||
623 | uint32_t height = output->height * output->scale; | 629 | uint32_t height = output->height; |
624 | 630 | ||
625 | cairo_t *cairo = ctx->cairo; | 631 | cairo_t *cairo = ctx->cairo; |
626 | int text_width, text_height; | 632 | int text_width, text_height; |
627 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 633 | get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, |
628 | output->scale, config->pango_markup, "%s", ws->label); | 634 | 1, config->pango_markup, "%s", ws->label); |
629 | 635 | ||
630 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 636 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
631 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 637 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
632 | int border_width = BORDER_WIDTH * output->scale; | 638 | int border_width = BORDER_WIDTH; |
633 | 639 | ||
634 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height | 640 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height |
635 | + border_width * 2; | 641 | + border_width * 2; |
636 | uint32_t ideal_surface_height = ideal_height / output->scale; | 642 | uint32_t ideal_surface_height = ideal_height; |
637 | if (!output->bar->config->height && | 643 | if (!output->bar->config->height && |
638 | output->height < ideal_surface_height) { | 644 | output->height < ideal_surface_height) { |
639 | return ideal_surface_height; | 645 | return ideal_surface_height; |
640 | } | 646 | } |
641 | 647 | ||
642 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 648 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
643 | if (width < config->workspace_min_width * output->scale) { | 649 | if (width < config->workspace_min_width) { |
644 | width = config->workspace_min_width * output->scale; | 650 | width = config->workspace_min_width; |
645 | } | 651 | } |
646 | 652 | ||
647 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 653 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
@@ -664,7 +670,7 @@ static uint32_t render_workspace_button(struct render_context *ctx, | |||
664 | cairo_set_source_u32(cairo, box_colors.text); | 670 | cairo_set_source_u32(cairo, box_colors.text); |
665 | 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)); |
666 | choose_text_aa_mode(ctx, box_colors.text); | 672 | choose_text_aa_mode(ctx, box_colors.text); |
667 | pango_printf(cairo, config->font, output->scale, config->pango_markup, | 673 | render_text(cairo, config->font_description, 1, config->pango_markup, |
668 | "%s", ws->label); | 674 | "%s", ws->label); |
669 | 675 | ||
670 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 676 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
@@ -686,19 +692,10 @@ static uint32_t render_to_cairo(struct render_context *ctx) { | |||
686 | struct swaybar_output *output = ctx->output; | 692 | struct swaybar_output *output = ctx->output; |
687 | struct swaybar *bar = output->bar; | 693 | struct swaybar *bar = output->bar; |
688 | struct swaybar_config *config = bar->config; | 694 | struct swaybar_config *config = bar->config; |
689 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | ||
690 | if (output->focused) { | ||
691 | ctx->background_color = config->colors.focused_background; | ||
692 | } else { | ||
693 | ctx->background_color = config->colors.background; | ||
694 | } | ||
695 | |||
696 | cairo_set_source_u32(cairo, ctx->background_color); | ||
697 | cairo_paint(cairo); | ||
698 | 695 | ||
699 | int th; | 696 | int th; |
700 | get_text_size(cairo, config->font, NULL, &th, NULL, output->scale, false, ""); | 697 | get_text_size(cairo, config->font_description, NULL, &th, NULL, 1, false, ""); |
701 | uint32_t max_height = (th + WS_VERTICAL_PADDING * 4) / output->scale; | 698 | uint32_t max_height = (th + WS_VERTICAL_PADDING * 4); |
702 | /* | 699 | /* |
703 | * 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 |
704 | * the ideal height. If the actual height is too short, the render function | 701 | * the ideal height. If the actual height is too short, the render function |
@@ -706,7 +703,7 @@ static uint32_t render_to_cairo(struct render_context *ctx) { | |||
706 | * height is too tall, the render function should adapt its drawing to | 703 | * height is too tall, the render function should adapt its drawing to |
707 | * utilize the available space. | 704 | * utilize the available space. |
708 | */ | 705 | */ |
709 | double x = output->width * output->scale; | 706 | double x = output->width; |
710 | #if HAVE_TRAY | 707 | #if HAVE_TRAY |
711 | if (bar->tray) { | 708 | if (bar->tray) { |
712 | uint32_t h = render_tray(cairo, output, &x); | 709 | uint32_t h = render_tray(cairo, output, &x); |
@@ -756,34 +753,43 @@ void render_frame(struct swaybar_output *output) { | |||
756 | 753 | ||
757 | free_hotspots(&output->hotspots); | 754 | free_hotspots(&output->hotspots); |
758 | 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 | |||
759 | struct render_context ctx = { 0 }; | 763 | struct render_context ctx = { 0 }; |
760 | 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; | ||
761 | 767 | ||
762 | cairo_surface_t *recorder = cairo_recording_surface_create( | 768 | cairo_surface_t *recorder = cairo_recording_surface_create( |
763 | CAIRO_CONTENT_COLOR_ALPHA, NULL); | 769 | CAIRO_CONTENT_COLOR_ALPHA, NULL); |
764 | cairo_t *cairo = cairo_create(recorder); | 770 | cairo_t *cairo = cairo_create(recorder); |
771 | cairo_scale(cairo, output->scale, output->scale); | ||
765 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | 772 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); |
766 | ctx.cairo = cairo; | 773 | ctx.cairo = cairo; |
767 | 774 | ||
768 | cairo_font_options_t *fo = cairo_font_options_create(); | 775 | cairo_font_options_t *fo = cairo_font_options_create(); |
769 | cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); | ||
770 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); | 776 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); |
771 | ctx.textaa_safe = fo; | 777 | ctx.textaa_safe = fo; |
772 | if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { | 778 | if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { |
773 | ctx.textaa_sharp = ctx.textaa_safe; | 779 | ctx.textaa_sharp = ctx.textaa_safe; |
774 | } else { | 780 | } else { |
775 | fo = cairo_font_options_create(); | 781 | fo = cairo_font_options_create(); |
776 | cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); | ||
777 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); | 782 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); |
778 | cairo_font_options_set_subpixel_order(fo, | 783 | cairo_font_options_set_subpixel_order(fo, |
779 | to_cairo_subpixel_order(output->subpixel)); | 784 | to_cairo_subpixel_order(output->subpixel)); |
780 | ctx.textaa_sharp = fo; | 785 | ctx.textaa_sharp = fo; |
781 | } | 786 | } |
782 | 787 | ||
783 | cairo_save(cairo); | 788 | |
784 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); | 789 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
790 | cairo_set_source_u32(cairo, background_color); | ||
785 | cairo_paint(cairo); | 791 | cairo_paint(cairo); |
786 | cairo_restore(cairo); | 792 | |
787 | uint32_t height = render_to_cairo(&ctx); | 793 | uint32_t height = render_to_cairo(&ctx); |
788 | int config_height = output->bar->config->height; | 794 | int config_height = output->bar->config->height; |
789 | if (config_height > 0) { | 795 | if (config_height > 0) { |
@@ -810,9 +816,7 @@ void render_frame(struct swaybar_output *output) { | |||
810 | output->width * output->scale, | 816 | output->width * output->scale, |
811 | output->height * output->scale); | 817 | output->height * output->scale); |
812 | if (!output->current_buffer) { | 818 | if (!output->current_buffer) { |
813 | cairo_surface_destroy(recorder); | 819 | goto cleanup; |
814 | cairo_destroy(cairo); | ||
815 | return; | ||
816 | } | 820 | } |
817 | cairo_t *shm = output->current_buffer->cairo; | 821 | cairo_t *shm = output->current_buffer->cairo; |
818 | 822 | ||
@@ -830,6 +834,17 @@ void render_frame(struct swaybar_output *output) { | |||
830 | wl_surface_damage(output->surface, 0, 0, | 834 | wl_surface_damage(output->surface, 0, 0, |
831 | output->width, output->height); | 835 | output->width, output->height); |
832 | 836 | ||
837 | uint32_t bg_alpha = background_color & 0xFF; | ||
838 | if (bg_alpha == 0xFF) { | ||
839 | struct wl_region *region = | ||
840 | wl_compositor_create_region(output->bar->compositor); | ||
841 | wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX); | ||
842 | wl_surface_set_opaque_region(output->surface, region); | ||
843 | wl_region_destroy(region); | ||
844 | } else { | ||
845 | wl_surface_set_opaque_region(output->surface, NULL); | ||
846 | } | ||
847 | |||
833 | struct wl_callback *frame_callback = wl_surface_frame(output->surface); | 848 | struct wl_callback *frame_callback = wl_surface_frame(output->surface); |
834 | wl_callback_add_listener(frame_callback, &output_frame_listener, output); | 849 | wl_callback_add_listener(frame_callback, &output_frame_listener, output); |
835 | output->frame_scheduled = true; | 850 | output->frame_scheduled = true; |
@@ -837,6 +852,7 @@ void render_frame(struct swaybar_output *output) { | |||
837 | wl_surface_commit(output->surface); | 852 | wl_surface_commit(output->surface); |
838 | } | 853 | } |
839 | 854 | ||
855 | cleanup: | ||
840 | if (ctx.textaa_sharp != ctx.textaa_safe) { | 856 | if (ctx.textaa_sharp != ctx.textaa_safe) { |
841 | cairo_font_options_destroy(ctx.textaa_sharp); | 857 | cairo_font_options_destroy(ctx.textaa_sharp); |
842 | } | 858 | } |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index ecd91032..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> |
@@ -117,11 +116,11 @@ bool status_handle_readable(struct status_line *status) { | |||
117 | status->text = status->buffer; | 116 | status->text = status->buffer; |
118 | // intentional fall-through | 117 | // intentional fall-through |
119 | case PROTOCOL_TEXT: | 118 | case PROTOCOL_TEXT: |
120 | errno = 0; | ||
121 | while (true) { | 119 | while (true) { |
122 | if (status->buffer[read_bytes - 1] == '\n') { | 120 | if (status->buffer[read_bytes - 1] == '\n') { |
123 | status->buffer[read_bytes - 1] = '\0'; | 121 | status->buffer[read_bytes - 1] = '\0'; |
124 | } | 122 | } |
123 | errno = 0; | ||
125 | read_bytes = getline(&status->buffer, | 124 | read_bytes = getline(&status->buffer, |
126 | &status->buffer_size, status->read); | 125 | &status->buffer_size, status->read); |
127 | if (errno == EAGAIN) { | 126 | if (errno == EAGAIN) { |
@@ -157,7 +156,12 @@ struct status_line *status_line_init(char *cmd) { | |||
157 | assert(!getenv("WAYLAND_SOCKET") && "display must be initialized before " | 156 | assert(!getenv("WAYLAND_SOCKET") && "display must be initialized before " |
158 | " starting `status-command`; WAYLAND_SOCKET should not be set"); | 157 | " starting `status-command`; WAYLAND_SOCKET should not be set"); |
159 | status->pid = fork(); | 158 | status->pid = fork(); |
160 | if (status->pid == 0) { | 159 | if (status->pid < 0) { |
160 | sway_log_errno(SWAY_ERROR, "fork failed"); | ||
161 | exit(1); | ||
162 | } else if (status->pid == 0) { | ||
163 | setpgid(0, 0); | ||
164 | |||
161 | dup2(pipe_read_fd[1], STDOUT_FILENO); | 165 | dup2(pipe_read_fd[1], STDOUT_FILENO); |
162 | close(pipe_read_fd[0]); | 166 | close(pipe_read_fd[0]); |
163 | close(pipe_read_fd[1]); | 167 | close(pipe_read_fd[1]); |
@@ -185,8 +189,8 @@ struct status_line *status_line_init(char *cmd) { | |||
185 | 189 | ||
186 | void status_line_free(struct status_line *status) { | 190 | void status_line_free(struct status_line *status) { |
187 | status_line_close_fds(status); | 191 | status_line_close_fds(status); |
188 | kill(status->pid, status->cont_signal); | 192 | kill(-status->pid, status->cont_signal); |
189 | kill(status->pid, SIGTERM); | 193 | kill(-status->pid, SIGTERM); |
190 | waitpid(status->pid, NULL, 0); | 194 | waitpid(status->pid, NULL, 0); |
191 | if (status->protocol == PROTOCOL_I3BAR) { | 195 | if (status->protocol == PROTOCOL_I3BAR) { |
192 | struct i3bar_block *block, *tmp; | 196 | struct i3bar_block *block, *tmp; |
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 | ||
14 | static const char *watcher_path = "/StatusNotifierWatcher"; | 14 | static const char *watcher_path = "/StatusNotifierWatcher"; |
15 | 15 | ||
@@ -138,12 +138,10 @@ static int handle_new_watcher(sd_bus_message *msg, | |||
138 | 138 | ||
139 | bool init_host(struct swaybar_host *host, char *protocol, | 139 | bool 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, ®_slot, host->watcher_interface, | 147 | int ret = sd_bus_match_signal(tray->bus, ®_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 | */ |
207 | static struct icon_theme *read_theme_file(char *basedir, char *theme_name) { | 204 | static 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 | ||
435 | static bool theme_exists_in_basedir(char *theme, char *basedir) { | 422 | static 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 19f4beac..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 | ||
386 | static enum hotspot_event_handling icon_hotspot_callback( | 385 | static 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 | } |
@@ -466,6 +470,11 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, | |||
466 | sni->target_size = target_size; | 470 | sni->target_size = target_size; |
467 | } | 471 | } |
468 | 472 | ||
473 | // Passive | ||
474 | if (sni->status && sni->status[0] == 'P') { | ||
475 | return 0; | ||
476 | } | ||
477 | |||
469 | int icon_size; | 478 | int icon_size; |
470 | cairo_surface_t *icon; | 479 | cairo_surface_t *icon; |
471 | if (sni->icon) { | 480 | if (sni->icon) { |
@@ -493,24 +502,36 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, | |||
493 | cairo_destroy(cairo_icon); | 502 | cairo_destroy(cairo_icon); |
494 | } | 503 | } |
495 | 504 | ||
496 | int padded_size = icon_size + 2*padding; | 505 | double descaled_padding = (double)padding / output->scale; |
497 | *x -= padded_size; | 506 | double descaled_icon_size = (double)icon_size / output->scale; |
498 | int y = floor((height - padded_size) / 2.0); | 507 | |
508 | int size = descaled_icon_size + 2 * descaled_padding; | ||
509 | *x -= size; | ||
510 | int icon_y = floor((output->height - size) / 2.0); | ||
499 | 511 | ||
500 | cairo_operator_t op = cairo_get_operator(cairo); | 512 | cairo_operator_t op = cairo_get_operator(cairo); |
501 | cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); | 513 | cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); |
502 | cairo_set_source_surface(cairo, icon, *x + padding, y + padding); | 514 | |
503 | cairo_rectangle(cairo, *x, y, padded_size, padded_size); | 515 | cairo_matrix_t scale_matrix; |
516 | cairo_pattern_t *icon_pattern = cairo_pattern_create_for_surface(icon); | ||
517 | // TODO: check cairo_pattern_status for "ENOMEM" | ||
518 | cairo_matrix_init_scale(&scale_matrix, output->scale, output->scale); | ||
519 | cairo_matrix_translate(&scale_matrix, -(*x + descaled_padding), -(icon_y + descaled_padding)); | ||
520 | cairo_pattern_set_matrix(icon_pattern, &scale_matrix); | ||
521 | cairo_set_source(cairo, icon_pattern); | ||
522 | cairo_rectangle(cairo, *x, icon_y, size, size); | ||
504 | cairo_fill(cairo); | 523 | cairo_fill(cairo); |
524 | |||
505 | cairo_set_operator(cairo, op); | 525 | cairo_set_operator(cairo, op); |
506 | 526 | ||
527 | cairo_pattern_destroy(icon_pattern); | ||
507 | cairo_surface_destroy(icon); | 528 | cairo_surface_destroy(icon); |
508 | 529 | ||
509 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 530 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
510 | hotspot->x = *x; | 531 | hotspot->x = *x; |
511 | hotspot->y = 0; | 532 | hotspot->y = 0; |
512 | hotspot->width = height; | 533 | hotspot->width = size; |
513 | hotspot->height = height; | 534 | hotspot->height = output->height; |
514 | hotspot->callback = icon_hotspot_callback; | 535 | hotspot->callback = icon_hotspot_callback; |
515 | hotspot->destroy = free; | 536 | hotspot->destroy = free; |
516 | hotspot->data = strdup(sni->watcher_id); | 537 | hotspot->data = strdup(sni->watcher_id); |
diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index 5fe6f9c3..b0545f4a 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c | |||
@@ -116,8 +116,8 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { | |||
116 | } | 116 | } |
117 | } // else display on all | 117 | } // else display on all |
118 | 118 | ||
119 | if ((int) output->height*output->scale <= 2*config->tray_padding) { | 119 | if ((int)(output->height * output->scale) <= 2 * config->tray_padding) { |
120 | return 2*config->tray_padding + 1; | 120 | return (2 * config->tray_padding + 1) / output->scale; |
121 | } | 121 | } |
122 | 122 | ||
123 | uint32_t max_height = 0; | 123 | uint32_t max_height = 0; |
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 | ||
11 | static const char *obj_path = "/StatusNotifierWatcher"; | 11 | static 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, |