aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/tray/sni_watcher.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar/tray/sni_watcher.c')
-rw-r--r--swaybar/tray/sni_watcher.c182
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
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
@@ -141,35 +210,53 @@ static void respond_to_introspect(DBusConnection *connection, DBusMessage *reque
141 210
142static void register_item(DBusConnection *connection, DBusMessage *message) { 211static 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 257send_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
292static void get_all(DBusConnection *connection, DBusMessage *message) { 416static 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