diff options
Diffstat (limited to 'swaybar/tray/item.c')
-rw-r--r-- | swaybar/tray/item.c | 151 |
1 files changed, 90 insertions, 61 deletions
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 41cacd16..0833dcb9 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c | |||
@@ -19,7 +19,7 @@ | |||
19 | // TODO menu | 19 | // TODO menu |
20 | 20 | ||
21 | static bool sni_ready(struct swaybar_sni *sni) { | 21 | static bool sni_ready(struct swaybar_sni *sni) { |
22 | return sni->status && (sni->status[0] == 'N' ? | 22 | return sni->status && (sni->status[0] == 'N' ? // NeedsAttention |
23 | sni->attention_icon_name || sni->attention_icon_pixmap : | 23 | sni->attention_icon_name || sni->attention_icon_pixmap : |
24 | sni->icon_name || sni->icon_pixmap); | 24 | sni->icon_name || sni->icon_pixmap); |
25 | } | 25 | } |
@@ -35,11 +35,12 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, | |||
35 | const char *prop, list_t **dest) { | 35 | const char *prop, list_t **dest) { |
36 | int ret = sd_bus_message_enter_container(msg, 'a', "(iiay)"); | 36 | int ret = sd_bus_message_enter_container(msg, 'a', "(iiay)"); |
37 | if (ret < 0) { | 37 | if (ret < 0) { |
38 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); | 38 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
39 | return ret; | 39 | return ret; |
40 | } | 40 | } |
41 | 41 | ||
42 | if (sd_bus_message_at_end(msg, 0)) { | 42 | if (sd_bus_message_at_end(msg, 0)) { |
43 | wlr_log(WLR_DEBUG, "%s %s no. of icons = 0", sni->watcher_id, prop); | ||
43 | return ret; | 44 | return ret; |
44 | } | 45 | } |
45 | 46 | ||
@@ -51,14 +52,14 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, | |||
51 | while (!sd_bus_message_at_end(msg, 0)) { | 52 | while (!sd_bus_message_at_end(msg, 0)) { |
52 | ret = sd_bus_message_enter_container(msg, 'r', "iiay"); | 53 | ret = sd_bus_message_enter_container(msg, 'r', "iiay"); |
53 | if (ret < 0) { | 54 | if (ret < 0) { |
54 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); | 55 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
55 | goto error; | 56 | goto error; |
56 | } | 57 | } |
57 | 58 | ||
58 | int size; | 59 | int size; |
59 | ret = sd_bus_message_read(msg, "ii", NULL, &size); | 60 | ret = sd_bus_message_read(msg, "ii", NULL, &size); |
60 | if (ret < 0) { | 61 | if (ret < 0) { |
61 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); | 62 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
62 | goto error; | 63 | goto error; |
63 | } | 64 | } |
64 | 65 | ||
@@ -66,7 +67,7 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, | |||
66 | size_t npixels; | 67 | size_t npixels; |
67 | ret = sd_bus_message_read_array(msg, 'y', &pixels, &npixels); | 68 | ret = sd_bus_message_read_array(msg, 'y', &pixels, &npixels); |
68 | if (ret < 0) { | 69 | if (ret < 0) { |
69 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); | 70 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
70 | goto error; | 71 | goto error; |
71 | } | 72 | } |
72 | 73 | ||
@@ -78,7 +79,10 @@ static int read_pixmap(sd_bus_message *msg, struct swaybar_sni *sni, | |||
78 | 79 | ||
79 | sd_bus_message_exit_container(msg); | 80 | sd_bus_message_exit_container(msg); |
80 | } | 81 | } |
82 | list_free_items_and_destroy(*dest); | ||
81 | *dest = pixmaps; | 83 | *dest = pixmaps; |
84 | wlr_log(WLR_DEBUG, "%s %s no. of icons = %d", sni->watcher_id, prop, | ||
85 | pixmaps->length); | ||
82 | 86 | ||
83 | return ret; | 87 | return ret; |
84 | error: | 88 | error: |
@@ -103,15 +107,15 @@ static int get_property_callback(sd_bus_message *msg, void *data, | |||
103 | 107 | ||
104 | int ret; | 108 | int ret; |
105 | if (sd_bus_message_is_method_error(msg, NULL)) { | 109 | if (sd_bus_message_is_method_error(msg, NULL)) { |
106 | sd_bus_error err = *sd_bus_message_get_error(msg); | 110 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, |
107 | wlr_log(WLR_DEBUG, "Failed to get property %s: %s", prop, err.message); | 111 | sd_bus_message_get_error(msg)->message); |
108 | ret = -sd_bus_error_get_errno(&err); | 112 | ret = sd_bus_message_get_errno(msg); |
109 | goto cleanup; | 113 | goto cleanup; |
110 | } | 114 | } |
111 | 115 | ||
112 | ret = sd_bus_message_enter_container(msg, 'v', type); | 116 | ret = sd_bus_message_enter_container(msg, 'v', type); |
113 | if (ret < 0) { | 117 | if (ret < 0) { |
114 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, strerror(-ret)); | 118 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
115 | goto cleanup; | 119 | goto cleanup; |
116 | } | 120 | } |
117 | 121 | ||
@@ -121,14 +125,23 @@ static int get_property_callback(sd_bus_message *msg, void *data, | |||
121 | goto cleanup; | 125 | goto cleanup; |
122 | } | 126 | } |
123 | } else { | 127 | } else { |
128 | if (*type == 's' || *type == 'o') { | ||
129 | free(*(char **)dest); | ||
130 | } | ||
131 | |||
124 | ret = sd_bus_message_read(msg, type, dest); | 132 | ret = sd_bus_message_read(msg, type, dest); |
125 | if (ret < 0) { | 133 | if (ret < 0) { |
126 | wlr_log(WLR_DEBUG, "Failed to read property %s: %s", prop, | 134 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
127 | strerror(-ret)); | ||
128 | goto cleanup; | 135 | goto cleanup; |
129 | } else if (*type == 's' || *type == 'o') { | 136 | } |
137 | |||
138 | if (*type == 's' || *type == 'o') { | ||
130 | char **str = dest; | 139 | char **str = dest; |
131 | *str = strdup(*str); | 140 | *str = strdup(*str); |
141 | wlr_log(WLR_DEBUG, "%s %s = '%s'", sni->watcher_id, prop, *str); | ||
142 | } else if (*type == 'b') { | ||
143 | wlr_log(WLR_DEBUG, "%s %s = %s", sni->watcher_id, prop, | ||
144 | *(bool *)dest ? "true" : "false"); | ||
132 | } | 145 | } |
133 | } | 146 | } |
134 | 147 | ||
@@ -152,62 +165,80 @@ static void sni_get_property_async(struct swaybar_sni *sni, const char *prop, | |||
152 | sni->path, "org.freedesktop.DBus.Properties", "Get", | 165 | sni->path, "org.freedesktop.DBus.Properties", "Get", |
153 | get_property_callback, data, "ss", sni->interface, prop); | 166 | get_property_callback, data, "ss", sni->interface, prop); |
154 | if (ret < 0) { | 167 | if (ret < 0) { |
155 | wlr_log(WLR_DEBUG, "Failed to get property %s: %s", prop, strerror(-ret)); | 168 | wlr_log(WLR_ERROR, "%s %s: %s", sni->watcher_id, prop, strerror(-ret)); |
169 | } | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * There is a quirk in sd-bus that in some systems, it is unable to get the | ||
174 | * well-known names on the bus, so it cannot identify if an incoming signal, | ||
175 | * which uses the sender's unique name, actually matches the callback's matching | ||
176 | * sender if the callback uses a well-known name, in which case it just calls | ||
177 | * the callback and hopes for the best, resulting in false positives. In the | ||
178 | * case of NewIcon & NewAttentionIcon, this doesn't affect anything, but it | ||
179 | * means that for NewStatus, if the SNI does not definitely match the sender, | ||
180 | * then the safe thing to do is to query the status independently. | ||
181 | * This function returns 1 if the SNI definitely matches the signal sender, | ||
182 | * which is returned by the calling function to indicate that signal matching | ||
183 | * can stop since it has already found the required callback, otherwise, it | ||
184 | * returns 0, which allows matching to continue. | ||
185 | */ | ||
186 | static int sni_check_msg_sender(struct swaybar_sni *sni, sd_bus_message *msg, | ||
187 | const char *signal) { | ||
188 | bool has_well_known_names = | ||
189 | sd_bus_creds_get_mask(sd_bus_message_get_creds(msg)) & SD_BUS_CREDS_WELL_KNOWN_NAMES; | ||
190 | if (sni->service[0] == ':' || has_well_known_names) { | ||
191 | wlr_log(WLR_DEBUG, "%s has new %s", sni->watcher_id, signal); | ||
192 | return 1; | ||
193 | } else { | ||
194 | wlr_log(WLR_DEBUG, "%s may have new %s", sni->watcher_id, signal); | ||
195 | return 0; | ||
156 | } | 196 | } |
157 | } | 197 | } |
158 | 198 | ||
159 | static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { | 199 | static int handle_new_icon(sd_bus_message *msg, void *data, sd_bus_error *error) { |
160 | struct swaybar_sni *sni = data; | 200 | struct swaybar_sni *sni = data; |
161 | wlr_log(WLR_DEBUG, "%s has new IconName", sni->watcher_id); | ||
162 | |||
163 | free(sni->icon_name); | ||
164 | sni->icon_name = NULL; | ||
165 | sni_get_property_async(sni, "IconName", "s", &sni->icon_name); | 201 | sni_get_property_async(sni, "IconName", "s", &sni->icon_name); |
166 | |||
167 | list_free_items_and_destroy(sni->icon_pixmap); | ||
168 | sni->icon_pixmap = NULL; | ||
169 | sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); | 202 | sni_get_property_async(sni, "IconPixmap", NULL, &sni->icon_pixmap); |
170 | 203 | return sni_check_msg_sender(sni, msg, "icon"); | |
171 | return 0; | ||
172 | } | 204 | } |
173 | 205 | ||
174 | static int handle_new_attention_icon(sd_bus_message *msg, void *data, | 206 | static int handle_new_attention_icon(sd_bus_message *msg, void *data, |
175 | sd_bus_error *error) { | 207 | sd_bus_error *error) { |
176 | struct swaybar_sni *sni = data; | 208 | struct swaybar_sni *sni = data; |
177 | wlr_log(WLR_DEBUG, "%s has new AttentionIconName", sni->watcher_id); | ||
178 | |||
179 | free(sni->attention_icon_name); | ||
180 | sni->attention_icon_name = NULL; | ||
181 | sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); | 209 | sni_get_property_async(sni, "AttentionIconName", "s", &sni->attention_icon_name); |
182 | |||
183 | list_free_items_and_destroy(sni->attention_icon_pixmap); | ||
184 | sni->attention_icon_pixmap = NULL; | ||
185 | sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); | 210 | sni_get_property_async(sni, "AttentionIconPixmap", NULL, &sni->attention_icon_pixmap); |
186 | 211 | return sni_check_msg_sender(sni, msg, "attention icon"); | |
187 | return 0; | ||
188 | } | 212 | } |
189 | 213 | ||
190 | static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { | 214 | static int handle_new_status(sd_bus_message *msg, void *data, sd_bus_error *error) { |
191 | char *status; | 215 | struct swaybar_sni *sni = data; |
192 | int ret = sd_bus_message_read(msg, "s", &status); | 216 | int ret = sni_check_msg_sender(sni, msg, "status"); |
193 | if (ret < 0) { | 217 | if (ret == 1) { |
194 | wlr_log(WLR_DEBUG, "Failed to read new status message: %s", strerror(-ret)); | 218 | char *status; |
219 | int r = sd_bus_message_read(msg, "s", &status); | ||
220 | if (r < 0) { | ||
221 | wlr_log(WLR_ERROR, "%s new status error: %s", sni->watcher_id, strerror(-ret)); | ||
222 | ret = r; | ||
223 | } else { | ||
224 | free(sni->status); | ||
225 | sni->status = strdup(status); | ||
226 | wlr_log(WLR_DEBUG, "%s has new status = '%s'", sni->watcher_id, status); | ||
227 | set_sni_dirty(sni); | ||
228 | } | ||
195 | } else { | 229 | } else { |
196 | struct swaybar_sni *sni = data; | 230 | sni_get_property_async(sni, "Status", "s", &sni->status); |
197 | free(sni->status); | ||
198 | sni->status = strdup(status); | ||
199 | wlr_log(WLR_DEBUG, "%s has new Status '%s'", sni->watcher_id, status); | ||
200 | set_sni_dirty(sni); | ||
201 | } | 231 | } |
232 | |||
202 | return ret; | 233 | return ret; |
203 | } | 234 | } |
204 | 235 | ||
205 | static void sni_match_signal(struct swaybar_sni *sni, char *signal, | 236 | static void sni_match_signal(struct swaybar_sni *sni, sd_bus_slot **slot, |
206 | sd_bus_message_handler_t callback) { | 237 | char *signal, sd_bus_message_handler_t callback) { |
207 | int ret = sd_bus_match_signal(sni->tray->bus, NULL, sni->service, sni->path, | 238 | int ret = sd_bus_match_signal(sni->tray->bus, slot, sni->service, sni->path, |
208 | sni->interface, signal, callback, sni); | 239 | sni->interface, signal, callback, sni); |
209 | if (ret < 0) { | 240 | if (ret < 0) { |
210 | wlr_log(WLR_DEBUG, "Failed to subscribe to signal %s: %s", signal, | 241 | wlr_log(WLR_ERROR, "Failed to subscribe to signal %s: %s", signal, |
211 | strerror(-ret)); | 242 | strerror(-ret)); |
212 | } | 243 | } |
213 | } | 244 | } |
@@ -241,9 +272,10 @@ struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray) { | |||
241 | sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); | 272 | sni_get_property_async(sni, "ItemIsMenu", "b", &sni->item_is_menu); |
242 | sni_get_property_async(sni, "Menu", "o", &sni->menu); | 273 | sni_get_property_async(sni, "Menu", "o", &sni->menu); |
243 | 274 | ||
244 | sni_match_signal(sni, "NewIcon", handle_new_icon); | 275 | sni_match_signal(sni, &sni->new_icon_slot, "NewIcon", handle_new_icon); |
245 | sni_match_signal(sni, "NewAttentionIcon", handle_new_attention_icon); | 276 | sni_match_signal(sni, &sni->new_attention_icon_slot, "NewAttentionIcon", |
246 | sni_match_signal(sni, "NewStatus", handle_new_status); | 277 | handle_new_attention_icon); |
278 | sni_match_signal(sni, &sni->new_status_slot, "NewStatus", handle_new_status); | ||
247 | 279 | ||
248 | return sni; | 280 | return sni; |
249 | } | 281 | } |
@@ -253,6 +285,10 @@ void destroy_sni(struct swaybar_sni *sni) { | |||
253 | return; | 285 | return; |
254 | } | 286 | } |
255 | 287 | ||
288 | sd_bus_slot_unref(sni->new_icon_slot); | ||
289 | sd_bus_slot_unref(sni->new_attention_icon_slot); | ||
290 | sd_bus_slot_unref(sni->new_status_slot); | ||
291 | |||
256 | free(sni->watcher_id); | 292 | free(sni->watcher_id); |
257 | free(sni->service); | 293 | free(sni->service); |
258 | free(sni->path); | 294 | free(sni->path); |
@@ -294,18 +330,11 @@ static void handle_click(struct swaybar_sni *sni, int x, int y, | |||
294 | char *orientation = (dir = 'U' || dir == 'D') ? "vertical" : "horizontal"; | 330 | char *orientation = (dir = 'U' || dir == 'D') ? "vertical" : "horizontal"; |
295 | int sign = (dir == 'U' || dir == 'L') ? -1 : 1; | 331 | int sign = (dir == 'U' || dir == 'L') ? -1 : 1; |
296 | 332 | ||
297 | int ret = sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, | 333 | sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, |
298 | sni->path, sni->interface, "Scroll", NULL, NULL, "is", | 334 | sni->interface, "Scroll", NULL, NULL, "is", delta*sign, orientation); |
299 | delta*sign, orientation); | ||
300 | if (ret < 0) { | ||
301 | wlr_log(WLR_DEBUG, "Failed to scroll on SNI: %s", strerror(-ret)); | ||
302 | } | ||
303 | } else { | 335 | } else { |
304 | int ret = sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, | 336 | sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, sni->path, |
305 | sni->path, sni->interface, method, NULL, NULL, "ii", x, y); | 337 | sni->interface, method, NULL, NULL, "ii", x, y); |
306 | if (ret < 0) { | ||
307 | wlr_log(WLR_DEBUG, "Failed to click on SNI: %s", strerror(-ret)); | ||
308 | } | ||
309 | } | 338 | } |
310 | } | 339 | } |
311 | 340 | ||
@@ -317,7 +346,7 @@ static int cmp_sni_id(const void *item, const void *cmp_to) { | |||
317 | static enum hotspot_event_handling icon_hotspot_callback( | 346 | static enum hotspot_event_handling icon_hotspot_callback( |
318 | struct swaybar_output *output, struct swaybar_hotspot *hotspot, | 347 | struct swaybar_output *output, struct swaybar_hotspot *hotspot, |
319 | int x, int y, enum x11_button button, void *data) { | 348 | int x, int y, enum x11_button button, void *data) { |
320 | wlr_log(WLR_DEBUG, "Clicked on Status Notifier Item '%s'", (char *)data); | 349 | wlr_log(WLR_DEBUG, "Clicked on %s", (char *)data); |
321 | 350 | ||
322 | struct swaybar_tray *tray = output->bar->tray; | 351 | struct swaybar_tray *tray = output->bar->tray; |
323 | int idx = list_seq_find(tray->items, cmp_sni_id, data); | 352 | int idx = list_seq_find(tray->items, cmp_sni_id, data); |
@@ -331,7 +360,7 @@ static enum hotspot_event_handling icon_hotspot_callback( | |||
331 | int global_y = output->output_y + (top_bar ? config->gaps.top + y: | 360 | int global_y = output->output_y + (top_bar ? config->gaps.top + y: |
332 | (int) output->output_height - config->gaps.bottom - y); | 361 | (int) output->output_height - config->gaps.bottom - y); |
333 | 362 | ||
334 | wlr_log(WLR_DEBUG, "Guessing click at (%d, %d)", global_x, global_y); | 363 | wlr_log(WLR_DEBUG, "Guessing click position at (%d, %d)", global_x, global_y); |
335 | handle_click(sni, global_x, global_y, button, 1); // TODO get delta from event | 364 | handle_click(sni, global_x, global_y, button, 1); // TODO get delta from event |
336 | return HOTSPOT_IGNORE; | 365 | return HOTSPOT_IGNORE; |
337 | } else { | 366 | } else { |
@@ -396,7 +425,7 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, | |||
396 | icon_size = actual_size < ideal_size ? | 425 | icon_size = actual_size < ideal_size ? |
397 | actual_size*(ideal_size/actual_size) : ideal_size; | 426 | actual_size*(ideal_size/actual_size) : ideal_size; |
398 | icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); | 427 | icon = cairo_image_surface_scale(sni->icon, icon_size, icon_size); |
399 | } else { // draw a sad face | 428 | } else { // draw a :( |
400 | icon_size = ideal_size*0.8; | 429 | icon_size = ideal_size*0.8; |
401 | icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); | 430 | icon = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, icon_size, icon_size); |
402 | cairo_t *cairo_icon = cairo_create(icon); | 431 | cairo_t *cairo_icon = cairo_create(icon); |