diff options
Diffstat (limited to 'swaybar')
-rw-r--r-- | swaybar/tray/sni.c | 33 | ||||
-rw-r--r-- | swaybar/tray/sni_watcher.c | 178 | ||||
-rw-r--r-- | swaybar/tray/tray.c | 128 |
3 files changed, 308 insertions, 31 deletions
diff --git a/swaybar/tray/sni.c b/swaybar/tray/sni.c index c9d00657..44d7ad91 100644 --- a/swaybar/tray/sni.c +++ b/swaybar/tray/sni.c | |||
@@ -179,7 +179,7 @@ static void send_icon_msg(struct StatusNotifierItem *item) { | |||
179 | DBusPendingCall *pending; | 179 | DBusPendingCall *pending; |
180 | DBusMessage *message = dbus_message_new_method_call( | 180 | DBusMessage *message = dbus_message_new_method_call( |
181 | item->name, | 181 | item->name, |
182 | "/StatusNotifierItem", | 182 | item->object_path, |
183 | "org.freedesktop.DBus.Properties", | 183 | "org.freedesktop.DBus.Properties", |
184 | "Get"); | 184 | "Get"); |
185 | const char *iface; | 185 | const char *iface; |
@@ -285,7 +285,7 @@ static void send_icon_name_msg(struct StatusNotifierItem *item) { | |||
285 | DBusPendingCall *pending; | 285 | DBusPendingCall *pending; |
286 | DBusMessage *message = dbus_message_new_method_call( | 286 | DBusMessage *message = dbus_message_new_method_call( |
287 | item->name, | 287 | item->name, |
288 | "/StatusNotifierItem", | 288 | item->object_path, |
289 | "org.freedesktop.DBus.Properties", | 289 | "org.freedesktop.DBus.Properties", |
290 | "Get"); | 290 | "Get"); |
291 | const char *iface; | 291 | const char *iface; |
@@ -324,7 +324,7 @@ void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { | |||
324 | : "org.freedesktop.StatusNotifierItem"); | 324 | : "org.freedesktop.StatusNotifierItem"); |
325 | DBusMessage *message = dbus_message_new_method_call( | 325 | DBusMessage *message = dbus_message_new_method_call( |
326 | item->name, | 326 | item->name, |
327 | "/StatusNotifierItem", | 327 | item->object_path, |
328 | iface, | 328 | iface, |
329 | "Activate"); | 329 | "Activate"); |
330 | 330 | ||
@@ -342,9 +342,10 @@ void sni_context_menu(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { | |||
342 | const char *iface = | 342 | const char *iface = |
343 | (item->kde_special_snowflake ? "org.kde.StatusNotifierItem" | 343 | (item->kde_special_snowflake ? "org.kde.StatusNotifierItem" |
344 | : "org.freedesktop.StatusNotifierItem"); | 344 | : "org.freedesktop.StatusNotifierItem"); |
345 | sway_log(L_INFO, "Activating context menu for item: (%s,%s)", item->name, item->object_path); | ||
345 | DBusMessage *message = dbus_message_new_method_call( | 346 | DBusMessage *message = dbus_message_new_method_call( |
346 | item->name, | 347 | item->name, |
347 | "/StatusNotifierItem", | 348 | item->object_path, |
348 | iface, | 349 | iface, |
349 | "ContextMenu"); | 350 | "ContextMenu"); |
350 | 351 | ||
@@ -363,7 +364,7 @@ void sni_secondary(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { | |||
363 | : "org.freedesktop.StatusNotifierItem"); | 364 | : "org.freedesktop.StatusNotifierItem"); |
364 | DBusMessage *message = dbus_message_new_method_call( | 365 | DBusMessage *message = dbus_message_new_method_call( |
365 | item->name, | 366 | item->name, |
366 | "/StatusNotifierItem", | 367 | item->object_path, |
367 | iface, | 368 | iface, |
368 | "SecondaryActivate"); | 369 | "SecondaryActivate"); |
369 | 370 | ||
@@ -426,6 +427,8 @@ struct StatusNotifierItem *sni_create(const char *name) { | |||
426 | struct StatusNotifierItem *item = malloc(sizeof(struct StatusNotifierItem)); | 427 | struct StatusNotifierItem *item = malloc(sizeof(struct StatusNotifierItem)); |
427 | item->name = strdup(name); | 428 | item->name = strdup(name); |
428 | item->unique_name = NULL; | 429 | item->unique_name = NULL; |
430 | // TODO use static str if the default path instead of all these god-damn strdups | ||
431 | item->object_path = strdup("/StatusNotifierItem"); | ||
429 | item->image = NULL; | 432 | item->image = NULL; |
430 | item->dirty = false; | 433 | item->dirty = false; |
431 | 434 | ||
@@ -449,6 +452,21 @@ struct StatusNotifierItem *sni_create(const char *name) { | |||
449 | 452 | ||
450 | return item; | 453 | return item; |
451 | } | 454 | } |
455 | struct StatusNotifierItem *sni_create_from_obj_path(const char *unique_name, | ||
456 | const char *object_path) { | ||
457 | struct StatusNotifierItem *item = malloc(sizeof(struct StatusNotifierItem)); | ||
458 | // XXX strdup-ing twice to avoid a double-free; see above todo | ||
459 | item->name = strdup(unique_name); | ||
460 | item->unique_name = strdup(unique_name); | ||
461 | item->object_path = strdup(object_path); | ||
462 | item->image = NULL; | ||
463 | item->dirty = false; | ||
464 | // If they're registering by obj-path they're a special snowflake | ||
465 | item->kde_special_snowflake = true; | ||
466 | |||
467 | get_icon(item); | ||
468 | return item; | ||
469 | } | ||
452 | /* Return 0 if `item` has a name of `str` */ | 470 | /* Return 0 if `item` has a name of `str` */ |
453 | int sni_str_cmp(const void *_item, const void *_str) { | 471 | int sni_str_cmp(const void *_item, const void *_str) { |
454 | const struct StatusNotifierItem *item = _item; | 472 | const struct StatusNotifierItem *item = _item; |
@@ -471,9 +489,8 @@ void sni_free(struct StatusNotifierItem *item) { | |||
471 | return; | 489 | return; |
472 | } | 490 | } |
473 | free(item->name); | 491 | free(item->name); |
474 | if (item->unique_name) { | 492 | free(item->unique_name); |
475 | free(item->unique_name); | 493 | free(item->object_path); |
476 | } | ||
477 | if (item->image) { | 494 | if (item->image) { |
478 | cairo_surface_destroy(item->image); | 495 | cairo_surface_destroy(item->image); |
479 | } | 496 | } |
diff --git a/swaybar/tray/sni_watcher.c b/swaybar/tray/sni_watcher.c index 86453e70..4c53fb99 100644 --- a/swaybar/tray/sni_watcher.c +++ b/swaybar/tray/sni_watcher.c | |||
@@ -11,6 +11,7 @@ | |||
11 | 11 | ||
12 | static list_t *items = NULL; | 12 | static list_t *items = NULL; |
13 | static list_t *hosts = NULL; | 13 | static list_t *hosts = NULL; |
14 | static list_t *object_path_items = NULL; | ||
14 | 15 | ||
15 | /** | 16 | /** |
16 | * Describes the function of the StatusNotifierWatcher | 17 | * Describes the function of the StatusNotifierWatcher |
@@ -18,6 +19,10 @@ static list_t *hosts = NULL; | |||
18 | * | 19 | * |
19 | * We also implement KDE's special snowflake protocol, it's like this but with | 20 | * We also implement KDE's special snowflake protocol, it's like this but with |
20 | * all occurrences 'freedesktop' replaced with 'kde'. There is no KDE introspect. | 21 | * all occurrences 'freedesktop' replaced with 'kde'. There is no KDE introspect. |
22 | * | ||
23 | * We _also_ support registering items by object path (even though this is a | ||
24 | * huge pain in the ass). Hosts that would like to subscribe to these items have | ||
25 | * to go through the `org.swaywm.LessSuckyStatusNotifierWatcher` interface. | ||
21 | */ | 26 | */ |
22 | static const char *interface_xml = | 27 | static const char *interface_xml = |
23 | "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'" | 28 | "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'" |
@@ -64,8 +69,59 @@ static const char *interface_xml = | |||
64 | " <arg type='' name='service' direction='out'/>" | 69 | " <arg type='' name='service' direction='out'/>" |
65 | " </signal>" | 70 | " </signal>" |
66 | " </interface>" | 71 | " </interface>" |
72 | " <interface name='org.swaywm.LessSuckyStatusNotifierWatcher'>" | ||
73 | " <property name='RegisteredObjectPathItems' type='a(os)' access='read'/>" | ||
74 | " <signal name='ObjPathItemRegistered'>" | ||
75 | " <arg type='os' name='service' direction='out'/>" | ||
76 | " </signal>" | ||
77 | " </interface>" | ||
67 | "</node>"; | 78 | "</node>"; |
68 | 79 | ||
80 | struct ObjPathItem { | ||
81 | char *obj_path; | ||
82 | char *unique_name; | ||
83 | }; | ||
84 | |||
85 | static void free_obj_path_item(struct ObjPathItem *item) { | ||
86 | if (!item) { | ||
87 | return; | ||
88 | } | ||
89 | free(item->unique_name); | ||
90 | free(item->obj_path); | ||
91 | free(item); | ||
92 | } | ||
93 | static struct ObjPathItem *create_obj_path_item(const char *unique_name, const char *obj_path) { | ||
94 | struct ObjPathItem *item = malloc(sizeof(struct ObjPathItem)); | ||
95 | if (!item) { | ||
96 | return NULL; | ||
97 | } | ||
98 | item->unique_name = strdup(unique_name); | ||
99 | item->obj_path = strdup(obj_path); | ||
100 | if (!item->unique_name || !item->obj_path) { | ||
101 | free_obj_path_item(item); | ||
102 | return NULL; | ||
103 | } | ||
104 | return item; | ||
105 | } | ||
106 | /** | ||
107 | * NOTE: This compare function does have ordering, this is because it has to | ||
108 | * comapre two strings. | ||
109 | */ | ||
110 | static int obj_path_item_cmp(const void *_item1, const void *_item2) { | ||
111 | const struct ObjPathItem *item1 = _item1; | ||
112 | const struct ObjPathItem *item2 = _item2; | ||
113 | if (strcmp(item1->unique_name,item2->unique_name) == 0 && | ||
114 | strcmp(item1->obj_path,item2->obj_path) == 0) { | ||
115 | return 0; | ||
116 | } | ||
117 | return -1; | ||
118 | } | ||
119 | static int obj_path_unique_name_cmp(const void *_item, const void *_unique_name) { | ||
120 | const struct ObjPathItem *item = _item; | ||
121 | const char *unique_name = _unique_name; | ||
122 | return strcmp(item->unique_name, unique_name); | ||
123 | } | ||
124 | |||
69 | static void host_registered_signal(DBusConnection *connection) { | 125 | static void host_registered_signal(DBusConnection *connection) { |
70 | // Send one signal for each protocol | 126 | // Send one signal for each protocol |
71 | DBusMessage *signal = dbus_message_new_signal( | 127 | DBusMessage *signal = dbus_message_new_signal( |
@@ -128,6 +184,19 @@ static void item_unregistered_signal(DBusConnection *connection, const char *nam | |||
128 | dbus_message_unref(signal); | 184 | dbus_message_unref(signal); |
129 | } | 185 | } |
130 | 186 | ||
187 | static void obj_path_item_registered_signal(DBusConnection *connection, const struct ObjPathItem *item) { | ||
188 | DBusMessage *signal = dbus_message_new_signal( | ||
189 | "/StatusNotifierWatcher", | ||
190 | "org.swaywm.LessSuckyStatusNotifierWatcher", | ||
191 | "ObjPathItemRegistered"); | ||
192 | dbus_message_append_args(signal, | ||
193 | DBUS_TYPE_OBJECT_PATH, &item->obj_path, | ||
194 | DBUS_TYPE_STRING, &item->unique_name, | ||
195 | DBUS_TYPE_INVALID); | ||
196 | dbus_connection_send(connection, signal, NULL); | ||
197 | dbus_message_unref(signal); | ||
198 | } | ||
199 | |||
131 | static void respond_to_introspect(DBusConnection *connection, DBusMessage *request) { | 200 | static void respond_to_introspect(DBusConnection *connection, DBusMessage *request) { |
132 | DBusMessage *reply; | 201 | DBusMessage *reply; |
133 | 202 | ||
@@ -147,28 +216,44 @@ static void register_item(DBusConnection *connection, DBusMessage *message) { | |||
147 | if (!dbus_message_get_args(message, &error, | 216 | if (!dbus_message_get_args(message, &error, |
148 | DBUS_TYPE_STRING, &name, | 217 | DBUS_TYPE_STRING, &name, |
149 | DBUS_TYPE_INVALID)) { | 218 | DBUS_TYPE_INVALID)) { |
150 | sway_log(L_ERROR, "Error parsing method args: %s\n", error.message); | 219 | sway_log(L_ERROR, "Error parsing method args: %s", error.message); |
151 | } | 220 | } |
152 | 221 | ||
153 | sway_log(L_INFO, "RegisterStatusNotifierItem called with \"%s\"\n", name); | 222 | sway_log(L_INFO, "RegisterStatusNotifierItem called with \"%s\"", name); |
154 | 223 | ||
155 | // Don't add duplicate or not real item | 224 | // Don't add duplicate or not real item |
156 | if (!dbus_validate_bus_name(name, NULL)) { | 225 | if (!dbus_validate_bus_name(name, NULL)) { |
157 | sway_log(L_INFO, "This item is not valid, we cannot keep track of it."); | 226 | if (dbus_validate_path(name, NULL)) { |
158 | return; | 227 | // Item is registered by object path |
159 | } | 228 | struct ObjPathItem *item = |
229 | create_obj_path_item(dbus_message_get_sender(message), name); | ||
230 | |||
231 | // Add ObjPathItem | ||
232 | if (list_seq_find(object_path_items, obj_path_item_cmp, item) != -1) { | ||
233 | free_obj_path_item(item); | ||
234 | return; | ||
235 | } | ||
236 | list_add(object_path_items, item); | ||
237 | obj_path_item_registered_signal(connection, item); | ||
238 | return; | ||
239 | } else { | ||
240 | sway_log(L_INFO, "This item is not valid, we cannot keep track of it."); | ||
241 | return; | ||
242 | } | ||
243 | } else { | ||
160 | 244 | ||
161 | if (list_seq_find(items, (int (*)(const void *, const void *))strcmp, name) != -1) { | 245 | if (list_seq_find(items, (int (*)(const void *, const void *))strcmp, name) != -1) { |
162 | return; | 246 | return; |
163 | } | 247 | } |
164 | if (!dbus_bus_name_has_owner(connection, name, &error)) { | 248 | if (!dbus_bus_name_has_owner(connection, name, &error)) { |
165 | return; | 249 | return; |
166 | } | 250 | } |
167 | 251 | ||
168 | list_add(items, strdup(name)); | 252 | list_add(items, strdup(name)); |
169 | item_registered_signal(connection, name); | 253 | item_registered_signal(connection, name); |
254 | } | ||
170 | 255 | ||
171 | // It's silly, but xembedsniproxy wants a reply for this function | 256 | // It's silly, but clients want a reply for this function |
172 | DBusMessage *reply = dbus_message_new_method_return(message); | 257 | DBusMessage *reply = dbus_message_new_method_return(message); |
173 | dbus_connection_send(connection, reply, NULL); | 258 | dbus_connection_send(connection, reply, NULL); |
174 | dbus_message_unref(reply); | 259 | dbus_message_unref(reply); |
@@ -182,10 +267,10 @@ static void register_host(DBusConnection *connection, DBusMessage *message) { | |||
182 | if (!dbus_message_get_args(message, &error, | 267 | if (!dbus_message_get_args(message, &error, |
183 | DBUS_TYPE_STRING, &name, | 268 | DBUS_TYPE_STRING, &name, |
184 | DBUS_TYPE_INVALID)) { | 269 | DBUS_TYPE_INVALID)) { |
185 | sway_log(L_ERROR, "Error parsing method args: %s\n", error.message); | 270 | sway_log(L_ERROR, "Error parsing method args: %s", error.message); |
186 | } | 271 | } |
187 | 272 | ||
188 | sway_log(L_INFO, "RegisterStatusNotifierHost called with \"%s\"\n", name); | 273 | sway_log(L_INFO, "RegisterStatusNotifierHost called with \"%s\"", name); |
189 | 274 | ||
190 | // Don't add duplicate or not real host | 275 | // Don't add duplicate or not real host |
191 | if (!dbus_validate_bus_name(name, NULL)) { | 276 | if (!dbus_validate_bus_name(name, NULL)) { |
@@ -215,12 +300,12 @@ static void get_property(DBusConnection *connection, DBusMessage *message) { | |||
215 | DBUS_TYPE_STRING, &interface, | 300 | DBUS_TYPE_STRING, &interface, |
216 | DBUS_TYPE_STRING, &property, | 301 | DBUS_TYPE_STRING, &property, |
217 | DBUS_TYPE_INVALID)) { | 302 | DBUS_TYPE_INVALID)) { |
218 | sway_log(L_ERROR, "Error parsing prop args: %s\n", error.message); | 303 | sway_log(L_ERROR, "Error parsing prop args: %s", error.message); |
219 | return; | 304 | return; |
220 | } | 305 | } |
221 | 306 | ||
222 | if (strcmp(property, "RegisteredStatusNotifierItems") == 0) { | 307 | if (strcmp(property, "RegisteredStatusNotifierItems") == 0) { |
223 | sway_log(L_INFO, "Replying with items\n"); | 308 | sway_log(L_INFO, "Replying with items"); |
224 | DBusMessage *reply; | 309 | DBusMessage *reply; |
225 | reply = dbus_message_new_method_return(message); | 310 | reply = dbus_message_new_method_return(message); |
226 | DBusMessageIter iter; | 311 | DBusMessageIter iter; |
@@ -281,6 +366,41 @@ static void get_property(DBusConnection *connection, DBusMessage *message) { | |||
281 | dbus_message_iter_close_container(&iter, &sub); | 366 | dbus_message_iter_close_container(&iter, &sub); |
282 | dbus_connection_send(connection, reply, NULL); | 367 | dbus_connection_send(connection, reply, NULL); |
283 | dbus_message_unref(reply); | 368 | dbus_message_unref(reply); |
369 | } else if (strcmp(property, "RegisteredObjectPathItems") == 0) { | ||
370 | sway_log(L_INFO, "Replying with ObjPathItems"); | ||
371 | DBusMessage *reply; | ||
372 | reply = dbus_message_new_method_return(message); | ||
373 | DBusMessageIter iter; | ||
374 | DBusMessageIter variant; | ||
375 | DBusMessageIter array; | ||
376 | DBusMessageIter dstruct; | ||
377 | |||
378 | dbus_message_iter_init_append(reply, &iter); | ||
379 | |||
380 | dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, | ||
381 | "a(os)", &variant); | ||
382 | dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, | ||
383 | "(os)", &array); | ||
384 | |||
385 | for (int i = 0; i < object_path_items->length; ++i) { | ||
386 | struct ObjPathItem *item = object_path_items->items[i]; | ||
387 | |||
388 | dbus_message_iter_open_container(&array, | ||
389 | DBUS_TYPE_STRUCT, NULL, &dstruct); | ||
390 | |||
391 | dbus_message_iter_append_basic(&dstruct, | ||
392 | DBUS_TYPE_OBJECT_PATH, item->obj_path); | ||
393 | dbus_message_iter_append_basic(&dstruct, | ||
394 | DBUS_TYPE_STRING, item->unique_name); | ||
395 | |||
396 | dbus_message_iter_close_container(&array, &dstruct); | ||
397 | } | ||
398 | |||
399 | dbus_message_iter_close_container(&variant, &array); | ||
400 | dbus_message_iter_close_container(&iter, &variant); | ||
401 | |||
402 | dbus_connection_send(connection, reply, NULL); | ||
403 | dbus_message_unref(reply); | ||
284 | } | 404 | } |
285 | } | 405 | } |
286 | 406 | ||
@@ -289,6 +409,8 @@ static void set_property(DBusConnection *connection, DBusMessage *message) { | |||
289 | return; | 409 | return; |
290 | } | 410 | } |
291 | 411 | ||
412 | // TODO clean me up please or get rid of me | ||
413 | // also add LessSuckyStatusNotifierWatcher props | ||
292 | static void get_all(DBusConnection *connection, DBusMessage *message) { | 414 | static void get_all(DBusConnection *connection, DBusMessage *message) { |
293 | DBusMessage *reply; | 415 | DBusMessage *reply; |
294 | reply = dbus_message_new_method_return(message); | 416 | reply = dbus_message_new_method_return(message); |
@@ -400,6 +522,8 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, | |||
400 | const char *old_owner; | 522 | const char *old_owner; |
401 | const char *new_owner; | 523 | const char *new_owner; |
402 | int index; | 524 | int index; |
525 | bool found_obj_path_item = false; | ||
526 | |||
403 | if (!dbus_message_get_args(message, NULL, | 527 | if (!dbus_message_get_args(message, NULL, |
404 | DBUS_TYPE_STRING, &name, | 528 | DBUS_TYPE_STRING, &name, |
405 | DBUS_TYPE_STRING, &old_owner, | 529 | DBUS_TYPE_STRING, &old_owner, |
@@ -427,6 +551,17 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, | |||
427 | 551 | ||
428 | return DBUS_HANDLER_RESULT_HANDLED; | 552 | return DBUS_HANDLER_RESULT_HANDLED; |
429 | } | 553 | } |
554 | while ((index = list_seq_find(object_path_items, obj_path_unique_name_cmp, name)) != -1) { | ||
555 | found_obj_path_item = true; | ||
556 | struct ObjPathItem *item = object_path_items->items[index]; | ||
557 | sway_log(L_INFO, "ObjPathItem lost %s", item->obj_path); | ||
558 | list_del(object_path_items, index); | ||
559 | free_obj_path_item(item); | ||
560 | } | ||
561 | if (found_obj_path_item) { | ||
562 | item_unregistered_signal(connection, name); | ||
563 | return DBUS_HANDLER_RESULT_HANDLED; | ||
564 | } | ||
430 | } | 565 | } |
431 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 566 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
432 | } | 567 | } |
@@ -446,6 +581,7 @@ int init_sni_watcher() { | |||
446 | 581 | ||
447 | items = create_list(); | 582 | items = create_list(); |
448 | hosts = create_list(); | 583 | hosts = create_list(); |
584 | object_path_items = create_list(); | ||
449 | 585 | ||
450 | int status = dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher", | 586 | int status = dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher", |
451 | DBUS_NAME_FLAG_REPLACE_EXISTING, | 587 | DBUS_NAME_FLAG_REPLACE_EXISTING, |
@@ -456,7 +592,7 @@ int init_sni_watcher() { | |||
456 | sway_log(L_INFO, "Could not get watcher name, it may start later"); | 592 | sway_log(L_INFO, "Could not get watcher name, it may start later"); |
457 | } | 593 | } |
458 | if (dbus_error_is_set(&error)) { | 594 | if (dbus_error_is_set(&error)) { |
459 | sway_log(L_ERROR, "dbus err getting watcher name: %s\n", error.message); | 595 | sway_log(L_ERROR, "dbus err getting watcher name: %s", error.message); |
460 | return -1; | 596 | return -1; |
461 | } | 597 | } |
462 | 598 | ||
@@ -469,7 +605,7 @@ int init_sni_watcher() { | |||
469 | sway_log(L_INFO, "Could not get kde watcher name, it may start later"); | 605 | sway_log(L_INFO, "Could not get kde watcher name, it may start later"); |
470 | } | 606 | } |
471 | if (dbus_error_is_set(&error)) { | 607 | if (dbus_error_is_set(&error)) { |
472 | sway_log(L_ERROR, "dbus err getting kde watcher name: %s\n", error.message); | 608 | sway_log(L_ERROR, "dbus err getting kde watcher name: %s", error.message); |
473 | return -1; | 609 | return -1; |
474 | } | 610 | } |
475 | 611 | ||
@@ -477,7 +613,7 @@ int init_sni_watcher() { | |||
477 | "/StatusNotifierWatcher", | 613 | "/StatusNotifierWatcher", |
478 | &vtable, NULL, &error); | 614 | &vtable, NULL, &error); |
479 | if (dbus_error_is_set(&error)) { | 615 | if (dbus_error_is_set(&error)) { |
480 | sway_log(L_ERROR, "dbus_err: %s\n", error.message); | 616 | sway_log(L_ERROR, "dbus_err: %s", error.message); |
481 | return -1; | 617 | return -1; |
482 | } | 618 | } |
483 | 619 | ||
diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index 91c3af06..01532e1c 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c | |||
@@ -102,6 +102,70 @@ bail: | |||
102 | dbus_pending_call_unref(pending); | 102 | dbus_pending_call_unref(pending); |
103 | return; | 103 | return; |
104 | } | 104 | } |
105 | static void get_obj_items_reply(DBusPendingCall *pending, void *_data) { | ||
106 | DBusMessage *reply = dbus_pending_call_steal_reply(pending); | ||
107 | |||
108 | if (!reply) { | ||
109 | sway_log(L_ERROR, "Got no object path items reply from sni watcher"); | ||
110 | goto bail; | ||
111 | } | ||
112 | |||
113 | int message_type = dbus_message_get_type(reply); | ||
114 | |||
115 | if (message_type == DBUS_MESSAGE_TYPE_ERROR) { | ||
116 | char *msg; | ||
117 | |||
118 | dbus_message_get_args(reply, NULL, | ||
119 | DBUS_TYPE_STRING, &msg, | ||
120 | DBUS_TYPE_INVALID); | ||
121 | |||
122 | sway_log(L_ERROR, "Message is error: %s", msg); | ||
123 | goto bail; | ||
124 | } | ||
125 | |||
126 | DBusMessageIter iter; | ||
127 | DBusMessageIter variant; | ||
128 | DBusMessageIter array; | ||
129 | DBusMessageIter dstruct; | ||
130 | |||
131 | dbus_message_iter_init(reply, &iter); | ||
132 | if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { | ||
133 | sway_log(L_ERROR, "Replyed with wrong type, not v(a(os))"); | ||
134 | goto bail; | ||
135 | } | ||
136 | dbus_message_iter_recurse(&iter, &variant); | ||
137 | if (strcmp(dbus_message_iter_get_signature(&variant), "a(os)") != 0) { | ||
138 | sway_log(L_ERROR, "Replyed with wrong type not a(os)"); | ||
139 | goto bail; | ||
140 | } | ||
141 | |||
142 | int len = dbus_message_iter_get_element_count(&variant); | ||
143 | |||
144 | dbus_message_iter_recurse(&variant, &array); | ||
145 | for (int i = 0; i < len; i++) { | ||
146 | const char *object_path; | ||
147 | const char *unique_name; | ||
148 | |||
149 | dbus_message_iter_recurse(&array, &dstruct); | ||
150 | |||
151 | dbus_message_iter_get_basic(&dstruct, &object_path); | ||
152 | dbus_message_iter_get_basic(&dstruct, &unique_name); | ||
153 | |||
154 | struct StatusNotifierItem *item = | ||
155 | sni_create_from_obj_path(unique_name, object_path); | ||
156 | |||
157 | if (item) { | ||
158 | sway_log(L_DEBUG, "Item registered with host: %s", unique_name); | ||
159 | list_add(tray->items, item); | ||
160 | dirty = true; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | bail: | ||
165 | dbus_message_unref(reply); | ||
166 | dbus_pending_call_unref(pending); | ||
167 | } | ||
168 | |||
105 | static void get_items() { | 169 | static void get_items() { |
106 | DBusPendingCall *pending; | 170 | DBusPendingCall *pending; |
107 | DBusMessage *message = dbus_message_new_method_call( | 171 | DBusMessage *message = dbus_message_new_method_call( |
@@ -127,6 +191,28 @@ static void get_items() { | |||
127 | } | 191 | } |
128 | 192 | ||
129 | dbus_pending_call_set_notify(pending, get_items_reply, NULL, NULL); | 193 | dbus_pending_call_set_notify(pending, get_items_reply, NULL, NULL); |
194 | |||
195 | message = dbus_message_new_method_call( | ||
196 | "org.freedesktop.StatusNotifierWatcher", | ||
197 | "/StatusNotifierWatcher", | ||
198 | "org.freedesktop.DBus.Properties", | ||
199 | "Get"); | ||
200 | |||
201 | iface = "org.swaywm.LessSuckyStatusNotifierWatcher"; | ||
202 | prop = "RegisteredObjectPathItems"; | ||
203 | dbus_message_append_args(message, | ||
204 | DBUS_TYPE_STRING, &iface, | ||
205 | DBUS_TYPE_STRING, &prop, | ||
206 | DBUS_TYPE_INVALID); | ||
207 | |||
208 | status = dbus_connection_send_with_reply(conn, message, &pending, -1); | ||
209 | dbus_message_unref(message); | ||
210 | |||
211 | if (!(pending || status)) { | ||
212 | sway_log(L_ERROR, "Could not get items"); | ||
213 | return; | ||
214 | } | ||
215 | dbus_pending_call_set_notify(pending, get_obj_items_reply, NULL, NULL); | ||
130 | } | 216 | } |
131 | 217 | ||
132 | static DBusHandlerResult signal_handler(DBusConnection *connection, | 218 | static DBusHandlerResult signal_handler(DBusConnection *connection, |
@@ -162,11 +248,14 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, | |||
162 | } | 248 | } |
163 | 249 | ||
164 | int index; | 250 | int index; |
165 | if ((index = list_seq_find(tray->items, sni_str_cmp, name)) != -1) { | 251 | bool found_item = false; |
252 | while ((index = list_seq_find(tray->items, sni_str_cmp, name)) != -1) { | ||
253 | found_item = true; | ||
166 | sni_free(tray->items->items[index]); | 254 | sni_free(tray->items->items[index]); |
167 | list_del(tray->items, index); | 255 | list_del(tray->items, index); |
168 | dirty = true; | 256 | dirty = true; |
169 | } else { | 257 | } |
258 | if (found_item == false) { | ||
170 | // If it's not in our list, then our list is incorrect. | 259 | // If it's not in our list, then our list is incorrect. |
171 | // Fetch all items again | 260 | // Fetch all items again |
172 | sway_log(L_INFO, "Host item list incorrect, refreshing"); | 261 | sway_log(L_INFO, "Host item list incorrect, refreshing"); |
@@ -189,6 +278,32 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, | |||
189 | } | 278 | } |
190 | 279 | ||
191 | return DBUS_HANDLER_RESULT_HANDLED; | 280 | return DBUS_HANDLER_RESULT_HANDLED; |
281 | } else if (dbus_message_is_signal(message, | ||
282 | "org.swaywm.LessSuckyStatusNotifierWatcher", | ||
283 | "ObjPathItemRegistered")) { | ||
284 | const char *object_path; | ||
285 | const char *unique_name; | ||
286 | if (!dbus_message_get_args(message, NULL, | ||
287 | DBUS_TYPE_OBJECT_PATH, &object_path, | ||
288 | DBUS_TYPE_STRING, &unique_name, | ||
289 | DBUS_TYPE_INVALID)) { | ||
290 | sway_log(L_ERROR, "Error getting ObjPathItemRegistered args"); | ||
291 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | ||
292 | } | ||
293 | |||
294 | // TODO allow one unique name to have multiple items | ||
295 | if (list_seq_find(tray->items, sni_str_cmp, unique_name) == -1) { | ||
296 | struct StatusNotifierItem *item = | ||
297 | sni_create_from_obj_path(unique_name, | ||
298 | object_path); | ||
299 | |||
300 | if (item) { | ||
301 | list_add(tray->items, item); | ||
302 | dirty = true; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | return DBUS_HANDLER_RESULT_HANDLED; | ||
192 | } | 307 | } |
193 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 308 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
194 | } | 309 | } |
@@ -255,6 +370,15 @@ static int init_host() { | |||
255 | sway_log(L_ERROR, "dbus_err: %s", error.message); | 370 | sway_log(L_ERROR, "dbus_err: %s", error.message); |
256 | return -1; | 371 | return -1; |
257 | } | 372 | } |
373 | dbus_bus_add_match(conn, | ||
374 | "type='signal',\ | ||
375 | sender='org.freedesktop.StatusNotifierWatcher',\ | ||
376 | member='ObjPathItemRegistered'", | ||
377 | &error); | ||
378 | if (dbus_error_is_set(&error)) { | ||
379 | sway_log(L_ERROR, "dbus_err: %s", error.message); | ||
380 | return -1; | ||
381 | } | ||
258 | 382 | ||
259 | // SNI matches | 383 | // SNI matches |
260 | dbus_bus_add_match(conn, | 384 | dbus_bus_add_match(conn, |