diff options
Diffstat (limited to 'swaybar/tray/sni_watcher.c')
-rw-r--r-- | swaybar/tray/sni_watcher.c | 182 |
1 files changed, 160 insertions, 22 deletions
diff --git a/swaybar/tray/sni_watcher.c b/swaybar/tray/sni_watcher.c index 86453e70..41a95c47 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 | ||
@@ -141,35 +210,53 @@ static void respond_to_introspect(DBusConnection *connection, DBusMessage *reque | |||
141 | 210 | ||
142 | static void register_item(DBusConnection *connection, DBusMessage *message) { | 211 | static void register_item(DBusConnection *connection, DBusMessage *message) { |
143 | DBusError error; | 212 | DBusError error; |
213 | DBusMessage *reply; | ||
144 | char *name; | 214 | char *name; |
145 | 215 | ||
146 | dbus_error_init(&error); | 216 | dbus_error_init(&error); |
147 | if (!dbus_message_get_args(message, &error, | 217 | if (!dbus_message_get_args(message, &error, |
148 | DBUS_TYPE_STRING, &name, | 218 | DBUS_TYPE_STRING, &name, |
149 | DBUS_TYPE_INVALID)) { | 219 | DBUS_TYPE_INVALID)) { |
150 | sway_log(L_ERROR, "Error parsing method args: %s\n", error.message); | 220 | sway_log(L_ERROR, "Error parsing method args: %s", error.message); |
151 | } | 221 | } |
152 | 222 | ||
153 | sway_log(L_INFO, "RegisterStatusNotifierItem called with \"%s\"\n", name); | 223 | sway_log(L_INFO, "RegisterStatusNotifierItem called with \"%s\"", name); |
154 | 224 | ||
155 | // Don't add duplicate or not real item | 225 | // Don't add duplicate or not real item |
156 | if (!dbus_validate_bus_name(name, NULL)) { | 226 | if (!dbus_validate_bus_name(name, NULL)) { |
157 | sway_log(L_INFO, "This item is not valid, we cannot keep track of it."); | 227 | if (dbus_validate_path(name, NULL)) { |
158 | return; | 228 | // Item is registered by object path |
159 | } | 229 | struct ObjPathItem *item = |
230 | create_obj_path_item(dbus_message_get_sender(message), name); | ||
231 | |||
232 | // Add ObjPathItem | ||
233 | if (list_seq_find(object_path_items, obj_path_item_cmp, item) != -1) { | ||
234 | free_obj_path_item(item); | ||
235 | return; | ||
236 | } | ||
237 | list_add(object_path_items, item); | ||
238 | obj_path_item_registered_signal(connection, item); | ||
239 | goto send_reply; | ||
240 | } else { | ||
241 | sway_log(L_INFO, "This item is not valid, we cannot keep track of it."); | ||
242 | return; | ||
243 | } | ||
244 | } else { | ||
160 | 245 | ||
161 | if (list_seq_find(items, (int (*)(const void *, const void *))strcmp, name) != -1) { | 246 | if (list_seq_find(items, (int (*)(const void *, const void *))strcmp, name) != -1) { |
162 | return; | 247 | return; |
163 | } | 248 | } |
164 | if (!dbus_bus_name_has_owner(connection, name, &error)) { | 249 | if (!dbus_bus_name_has_owner(connection, name, &error)) { |
165 | return; | 250 | return; |
166 | } | 251 | } |
167 | 252 | ||
168 | list_add(items, strdup(name)); | 253 | list_add(items, strdup(name)); |
169 | item_registered_signal(connection, name); | 254 | item_registered_signal(connection, name); |
255 | } | ||
170 | 256 | ||
171 | // It's silly, but xembedsniproxy wants a reply for this function | 257 | send_reply: |
172 | DBusMessage *reply = dbus_message_new_method_return(message); | 258 | // It's silly, but clients want a reply for this function |
259 | reply = dbus_message_new_method_return(message); | ||
173 | dbus_connection_send(connection, reply, NULL); | 260 | dbus_connection_send(connection, reply, NULL); |
174 | dbus_message_unref(reply); | 261 | dbus_message_unref(reply); |
175 | } | 262 | } |
@@ -182,10 +269,10 @@ static void register_host(DBusConnection *connection, DBusMessage *message) { | |||
182 | if (!dbus_message_get_args(message, &error, | 269 | if (!dbus_message_get_args(message, &error, |
183 | DBUS_TYPE_STRING, &name, | 270 | DBUS_TYPE_STRING, &name, |
184 | DBUS_TYPE_INVALID)) { | 271 | DBUS_TYPE_INVALID)) { |
185 | sway_log(L_ERROR, "Error parsing method args: %s\n", error.message); | 272 | sway_log(L_ERROR, "Error parsing method args: %s", error.message); |
186 | } | 273 | } |
187 | 274 | ||
188 | sway_log(L_INFO, "RegisterStatusNotifierHost called with \"%s\"\n", name); | 275 | sway_log(L_INFO, "RegisterStatusNotifierHost called with \"%s\"", name); |
189 | 276 | ||
190 | // Don't add duplicate or not real host | 277 | // Don't add duplicate or not real host |
191 | if (!dbus_validate_bus_name(name, NULL)) { | 278 | if (!dbus_validate_bus_name(name, NULL)) { |
@@ -215,12 +302,12 @@ static void get_property(DBusConnection *connection, DBusMessage *message) { | |||
215 | DBUS_TYPE_STRING, &interface, | 302 | DBUS_TYPE_STRING, &interface, |
216 | DBUS_TYPE_STRING, &property, | 303 | DBUS_TYPE_STRING, &property, |
217 | DBUS_TYPE_INVALID)) { | 304 | DBUS_TYPE_INVALID)) { |
218 | sway_log(L_ERROR, "Error parsing prop args: %s\n", error.message); | 305 | sway_log(L_ERROR, "Error parsing prop args: %s", error.message); |
219 | return; | 306 | return; |
220 | } | 307 | } |
221 | 308 | ||
222 | if (strcmp(property, "RegisteredStatusNotifierItems") == 0) { | 309 | if (strcmp(property, "RegisteredStatusNotifierItems") == 0) { |
223 | sway_log(L_INFO, "Replying with items\n"); | 310 | sway_log(L_INFO, "Replying with items"); |
224 | DBusMessage *reply; | 311 | DBusMessage *reply; |
225 | reply = dbus_message_new_method_return(message); | 312 | reply = dbus_message_new_method_return(message); |
226 | DBusMessageIter iter; | 313 | DBusMessageIter iter; |
@@ -281,6 +368,41 @@ static void get_property(DBusConnection *connection, DBusMessage *message) { | |||
281 | dbus_message_iter_close_container(&iter, &sub); | 368 | dbus_message_iter_close_container(&iter, &sub); |
282 | dbus_connection_send(connection, reply, NULL); | 369 | dbus_connection_send(connection, reply, NULL); |
283 | dbus_message_unref(reply); | 370 | dbus_message_unref(reply); |
371 | } else if (strcmp(property, "RegisteredObjectPathItems") == 0) { | ||
372 | sway_log(L_INFO, "Replying with ObjPathItems"); | ||
373 | DBusMessage *reply; | ||
374 | reply = dbus_message_new_method_return(message); | ||
375 | DBusMessageIter iter; | ||
376 | DBusMessageIter variant; | ||
377 | DBusMessageIter array; | ||
378 | DBusMessageIter dstruct; | ||
379 | |||
380 | dbus_message_iter_init_append(reply, &iter); | ||
381 | |||
382 | dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, | ||
383 | "a(os)", &variant); | ||
384 | dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, | ||
385 | "(os)", &array); | ||
386 | |||
387 | for (int i = 0; i < object_path_items->length; ++i) { | ||
388 | struct ObjPathItem *item = object_path_items->items[i]; | ||
389 | |||
390 | dbus_message_iter_open_container(&array, | ||
391 | DBUS_TYPE_STRUCT, NULL, &dstruct); | ||
392 | |||
393 | dbus_message_iter_append_basic(&dstruct, | ||
394 | DBUS_TYPE_OBJECT_PATH, &item->obj_path); | ||
395 | dbus_message_iter_append_basic(&dstruct, | ||
396 | DBUS_TYPE_STRING, &item->unique_name); | ||
397 | |||
398 | dbus_message_iter_close_container(&array, &dstruct); | ||
399 | } | ||
400 | |||
401 | dbus_message_iter_close_container(&variant, &array); | ||
402 | dbus_message_iter_close_container(&iter, &variant); | ||
403 | |||
404 | dbus_connection_send(connection, reply, NULL); | ||
405 | dbus_message_unref(reply); | ||
284 | } | 406 | } |
285 | } | 407 | } |
286 | 408 | ||
@@ -289,6 +411,8 @@ static void set_property(DBusConnection *connection, DBusMessage *message) { | |||
289 | return; | 411 | return; |
290 | } | 412 | } |
291 | 413 | ||
414 | // TODO clean me up please or get rid of me | ||
415 | // also add LessSuckyStatusNotifierWatcher props | ||
292 | static void get_all(DBusConnection *connection, DBusMessage *message) { | 416 | static void get_all(DBusConnection *connection, DBusMessage *message) { |
293 | DBusMessage *reply; | 417 | DBusMessage *reply; |
294 | reply = dbus_message_new_method_return(message); | 418 | reply = dbus_message_new_method_return(message); |
@@ -400,6 +524,8 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, | |||
400 | const char *old_owner; | 524 | const char *old_owner; |
401 | const char *new_owner; | 525 | const char *new_owner; |
402 | int index; | 526 | int index; |
527 | bool found_obj_path_item = false; | ||
528 | |||
403 | if (!dbus_message_get_args(message, NULL, | 529 | if (!dbus_message_get_args(message, NULL, |
404 | DBUS_TYPE_STRING, &name, | 530 | DBUS_TYPE_STRING, &name, |
405 | DBUS_TYPE_STRING, &old_owner, | 531 | DBUS_TYPE_STRING, &old_owner, |
@@ -427,6 +553,17 @@ static DBusHandlerResult signal_handler(DBusConnection *connection, | |||
427 | 553 | ||
428 | return DBUS_HANDLER_RESULT_HANDLED; | 554 | return DBUS_HANDLER_RESULT_HANDLED; |
429 | } | 555 | } |
556 | while ((index = list_seq_find(object_path_items, obj_path_unique_name_cmp, name)) != -1) { | ||
557 | found_obj_path_item = true; | ||
558 | struct ObjPathItem *item = object_path_items->items[index]; | ||
559 | sway_log(L_INFO, "ObjPathItem lost %s", item->obj_path); | ||
560 | list_del(object_path_items, index); | ||
561 | free_obj_path_item(item); | ||
562 | } | ||
563 | if (found_obj_path_item) { | ||
564 | item_unregistered_signal(connection, name); | ||
565 | return DBUS_HANDLER_RESULT_HANDLED; | ||
566 | } | ||
430 | } | 567 | } |
431 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; | 568 | return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; |
432 | } | 569 | } |
@@ -446,6 +583,7 @@ int init_sni_watcher() { | |||
446 | 583 | ||
447 | items = create_list(); | 584 | items = create_list(); |
448 | hosts = create_list(); | 585 | hosts = create_list(); |
586 | object_path_items = create_list(); | ||
449 | 587 | ||
450 | int status = dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher", | 588 | int status = dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher", |
451 | DBUS_NAME_FLAG_REPLACE_EXISTING, | 589 | DBUS_NAME_FLAG_REPLACE_EXISTING, |
@@ -456,7 +594,7 @@ int init_sni_watcher() { | |||
456 | sway_log(L_INFO, "Could not get watcher name, it may start later"); | 594 | sway_log(L_INFO, "Could not get watcher name, it may start later"); |
457 | } | 595 | } |
458 | if (dbus_error_is_set(&error)) { | 596 | if (dbus_error_is_set(&error)) { |
459 | sway_log(L_ERROR, "dbus err getting watcher name: %s\n", error.message); | 597 | sway_log(L_ERROR, "dbus err getting watcher name: %s", error.message); |
460 | return -1; | 598 | return -1; |
461 | } | 599 | } |
462 | 600 | ||
@@ -469,7 +607,7 @@ int init_sni_watcher() { | |||
469 | sway_log(L_INFO, "Could not get kde watcher name, it may start later"); | 607 | sway_log(L_INFO, "Could not get kde watcher name, it may start later"); |
470 | } | 608 | } |
471 | if (dbus_error_is_set(&error)) { | 609 | if (dbus_error_is_set(&error)) { |
472 | sway_log(L_ERROR, "dbus err getting kde watcher name: %s\n", error.message); | 610 | sway_log(L_ERROR, "dbus err getting kde watcher name: %s", error.message); |
473 | return -1; | 611 | return -1; |
474 | } | 612 | } |
475 | 613 | ||
@@ -477,7 +615,7 @@ int init_sni_watcher() { | |||
477 | "/StatusNotifierWatcher", | 615 | "/StatusNotifierWatcher", |
478 | &vtable, NULL, &error); | 616 | &vtable, NULL, &error); |
479 | if (dbus_error_is_set(&error)) { | 617 | if (dbus_error_is_set(&error)) { |
480 | sway_log(L_ERROR, "dbus_err: %s\n", error.message); | 618 | sway_log(L_ERROR, "dbus_err: %s", error.message); |
481 | return -1; | 619 | return -1; |
482 | } | 620 | } |
483 | 621 | ||