summaryrefslogtreecommitdiffstats
path: root/swaybar
diff options
context:
space:
mode:
authorLibravatar Calvin Lee <cyrus296@gmail.com>2017-10-24 11:59:42 -0600
committerLibravatar Calvin Lee <cyrus296@gmail.com>2017-12-29 12:11:51 -0700
commitad99d9dff8f8e8ee78b5195d6ca440af130f6ab6 (patch)
treec8ca022e7a61922dc6d3303e944c9b364ed89848 /swaybar
parentMerge pull request #1544 from CedricCabessa/fix1056-swaylock-allow-popup-to-c... (diff)
downloadsway-ad99d9dff8f8e8ee78b5195d6ca440af130f6ab6.tar.gz
sway-ad99d9dff8f8e8ee78b5195d6ca440af130f6ab6.tar.zst
sway-ad99d9dff8f8e8ee78b5195d6ca440af130f6ab6.zip
Allow registering StatusNotifierItems by obj path
This commit impliments a KDE hidden feature where a SNI could be registered by object path instead of well-known name. This should allow libappindicator programs to work correctly under sway. See #1372
Diffstat (limited to 'swaybar')
-rw-r--r--swaybar/tray/sni.c33
-rw-r--r--swaybar/tray/sni_watcher.c178
-rw-r--r--swaybar/tray/tray.c128
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}
455struct 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` */
453int sni_str_cmp(const void *_item, const void *_str) { 471int 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
12static list_t *items = NULL; 12static list_t *items = NULL;
13static list_t *hosts = NULL; 13static list_t *hosts = NULL;
14static 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 */
22static const char *interface_xml = 27static 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
80struct ObjPathItem {
81 char *obj_path;
82 char *unique_name;
83};
84
85static 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}
93static 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 */
110static 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}
119static 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
69static void host_registered_signal(DBusConnection *connection) { 125static 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
187static 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
131static void respond_to_introspect(DBusConnection *connection, DBusMessage *request) { 200static 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
292static void get_all(DBusConnection *connection, DBusMessage *message) { 414static 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}
105static 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
164bail:
165 dbus_message_unref(reply);
166 dbus_pending_call_unref(pending);
167}
168
105static void get_items() { 169static 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
132static DBusHandlerResult signal_handler(DBusConnection *connection, 218static 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,