diff options
| author | Calvin Lee <cyrus296@gmail.com> | 2017-11-09 12:58:32 -0700 |
|---|---|---|
| committer | Calvin Lee <cyrus296@gmail.com> | 2017-12-29 12:11:51 -0700 |
| commit | 87035380e33c7da10b53c6da713c56f3d89a1577 (patch) | |
| tree | 4b31ad282fe07227f5720928b1ba07715bc7ea48 | |
| parent | b9f36716b52d4566609ac64be88b8a1f65602214 (diff) | |
Add `dbus_get_prop_async` utility
This drastically reduces the amount of boilerplate needed to get a
property from a bus object.
| -rw-r--r-- | include/swaybar/tray/dbus.h | 17 | ||||
| -rw-r--r-- | swaybar/tray/dbus.c | 90 | ||||
| -rw-r--r-- | swaybar/tray/sni.c | 184 | ||||
| -rw-r--r-- | swaybar/tray/tray.c | 139 |
4 files changed, 137 insertions, 293 deletions
diff --git a/include/swaybar/tray/dbus.h b/include/swaybar/tray/dbus.h index 51754464..125ce96f 100644 --- a/include/swaybar/tray/dbus.h +++ b/include/swaybar/tray/dbus.h @@ -12,6 +12,23 @@ extern DBusConnection *conn; bool dbus_message_iter_check_signature(DBusMessageIter *iter, const char *sig); /** + * Fetches the property and calls `callback` with a message iter pointing it. + * Performs error handling and signature checking. + * + * Returns: true if message is successfully sent (will not necessarily arrive) + * and false otherwise + * + * NOTE: `expected_signature` must remain valid until the message reply is + * received, please only use 'static signatures. + */ +bool dbus_get_prop_async(const char *destination, + const char *path, + const char *iface, + const char *prop, + const char *expected_signature, + void(*callback)(DBusMessageIter *iter, void *data), + void *data); +/** * Should be called in main loop to dispatch events */ void dispatch_dbus(); diff --git a/swaybar/tray/dbus.c b/swaybar/tray/dbus.c index 46a1c807..4439fb83 100644 --- a/swaybar/tray/dbus.c +++ b/swaybar/tray/dbus.c @@ -136,7 +136,58 @@ static void dispatch_status(DBusConnection *connection, DBusDispatchStatus new_s } } -/* Public functions below */ +struct async_prop_data { + char const *sig; + void(*callback)(DBusMessageIter *, void *); + void *usr_data; +}; + +static void get_prop_callback(DBusPendingCall *pending, void *_data) { + struct async_prop_data *data = _data; + + DBusMessage *reply = dbus_pending_call_steal_reply(pending); + + if (!reply) { + sway_log(L_INFO, "Got no icon name reply from item"); + goto bail; + } + + if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { + char *msg; + + dbus_message_get_args(reply, NULL, + DBUS_TYPE_STRING, &msg, + DBUS_TYPE_INVALID); + + sway_log(L_INFO, "Failure to get property: %s", msg); + goto bail; + } + + DBusMessageIter iter; + DBusMessageIter variant; + + dbus_message_iter_init(reply, &iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { + sway_log(L_ERROR, "Property relpy type incorrect"); + goto bail; + } + dbus_message_iter_recurse(&iter, &variant); + + if (!dbus_message_iter_check_signature(&variant, data->sig)) { + sway_log(L_INFO, "Property returned has incorrect signatue."); + goto bail; + } + + data->callback(&variant, data->usr_data); + +bail: + if (reply) { + dbus_message_unref(reply); + } + dbus_pending_call_unref(pending); +} + +/* Public functions below -- see header for docs*/ bool dbus_message_iter_check_signature(DBusMessageIter *iter, const char *sig) { char *msg_sig = dbus_message_iter_get_signature(iter); @@ -145,6 +196,43 @@ bool dbus_message_iter_check_signature(DBusMessageIter *iter, const char *sig) { return (result == 0); } +bool dbus_get_prop_async(const char *destination, + const char *path, const char *iface, + const char *prop, const char *expected_signature, + void(*callback)(DBusMessageIter *, void *), void *usr_data) { + struct async_prop_data *data = malloc(sizeof(struct async_prop_data)); + if (!data) { + return false; + } + DBusPendingCall *pending; + DBusMessage *message = dbus_message_new_method_call( + destination, path, + "org.freedesktop.DBus.Properties", + "Get"); + + dbus_message_append_args(message, + DBUS_TYPE_STRING, &iface, + DBUS_TYPE_STRING, &prop, + DBUS_TYPE_INVALID); + + bool status = + dbus_connection_send_with_reply(conn, message, &pending, -1); + + dbus_message_unref(message); + + if (!(pending || status)) { + sway_log(L_ERROR, "Could not get property"); + return false; + } + + data->sig = expected_signature; + data->callback = callback; + data->usr_data = usr_data; + dbus_pending_call_set_notify(pending, get_prop_callback, data, free); + + return true; +} + void dispatch_dbus() { if (!should_dispatch || !conn) { return; diff --git a/swaybar/tray/sni.c b/swaybar/tray/sni.c index 401a0091..200422da 100644 --- a/swaybar/tray/sni.c +++ b/swaybar/tray/sni.c @@ -14,6 +14,9 @@ #include "client/cairo.h" #include "log.h" +static const char *KDE_IFACE = "org.kde.StatusNotifierItem"; +static const char *FD_IFACE = "org.freedesktop.StatusNotifierItem"; + // Not sure what this is but cairo needs it. static const cairo_user_data_key_t cairo_user_data_key; @@ -38,57 +41,19 @@ void sni_icon_ref_free(struct sni_icon_ref *sni_ref) { } /* Gets the pixmap of an icon */ -static void reply_icon(DBusPendingCall *pending, void *_data) { +static void reply_icon(DBusMessageIter *iter /* a(iiay) */, void *_data) { struct StatusNotifierItem *item = _data; - DBusMessage *reply = dbus_pending_call_steal_reply(pending); - - if (!reply) { - sway_log(L_ERROR, "Did not get reply"); - goto bail; - } - - int message_type = dbus_message_get_type(reply); - - if (message_type == DBUS_MESSAGE_TYPE_ERROR) { - char *msg; - - dbus_message_get_args(reply, NULL, - DBUS_TYPE_STRING, &msg, - DBUS_TYPE_INVALID); - - sway_log(L_ERROR, "Message is error: %s", msg); - goto bail; - } - - DBusMessageIter iter; - DBusMessageIter variant; /* v[a(iiay)] */ - DBusMessageIter array; /* a(iiay) */ DBusMessageIter d_struct; /* (iiay) */ DBusMessageIter icon; /* ay */ - dbus_message_iter_init(reply, &iter); - - // Each if here checks the types above before recursing - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - sway_log(L_ERROR, "Icon relpy type incorrect"); - goto bail; - } - dbus_message_iter_recurse(&iter, &variant); - - if (dbus_message_iter_check_signature(&variant, "a(iiay)")) { - sway_log(L_ERROR, "Icon relpy type incorrect"); - goto bail; - } - - if (dbus_message_iter_get_element_count(&variant) == 0) { + if (dbus_message_iter_get_element_count(iter) == 0) { // Can't recurse if there are no items sway_log(L_INFO, "Item has no icon"); - goto bail; + return; } - dbus_message_iter_recurse(&variant, &array); - dbus_message_iter_recurse(&array, &d_struct); + dbus_message_iter_recurse(iter, &d_struct); int width; dbus_message_iter_get_basic(&d_struct, &width); @@ -102,13 +67,13 @@ static void reply_icon(DBusPendingCall *pending, void *_data) { if (!len) { sway_log(L_ERROR, "No icon data"); - goto bail; + return; } // Also implies len % 4 == 0, useful below if (len != width * height * 4) { sway_log(L_ERROR, "Incorrect array size passed"); - goto bail; + return; } dbus_message_iter_recurse(&d_struct, &icon); @@ -117,7 +82,7 @@ static void reply_icon(DBusPendingCall *pending, void *_data) { // FIXME support a variable stride // (works on my machine though for all tested widths) if (!sway_assert(stride == width * 4, "Stride must be equal to byte length")) { - goto bail; + return; } // Data is by reference, no need to free @@ -127,7 +92,7 @@ static void reply_icon(DBusPendingCall *pending, void *_data) { uint8_t *image_data = malloc(stride * height); if (!image_data) { sway_log(L_ERROR, "Could not allocate memory for icon"); - goto bail; + return; } // Transform from network byte order to host byte order @@ -155,97 +120,22 @@ static void reply_icon(DBusPendingCall *pending, void *_data) { item->dirty = true; dirty = true; - dbus_message_unref(reply); - dbus_pending_call_unref(pending); return; } else { sway_log(L_ERROR, "Could not create image surface"); free(image_data); } -bail: - if (reply) { - dbus_message_unref(reply); - } - dbus_pending_call_unref(pending); sway_log(L_ERROR, "Could not get icon from item"); return; } -static void send_icon_msg(struct StatusNotifierItem *item) { - DBusPendingCall *pending; - DBusMessage *message = dbus_message_new_method_call( - item->name, - item->object_path, - "org.freedesktop.DBus.Properties", - "Get"); - const char *iface; - if (item->kde_special_snowflake) { - iface = "org.kde.StatusNotifierItem"; - } else { - iface = "org.freedesktop.StatusNotifierItem"; - } - const char *prop = "IconPixmap"; - - dbus_message_append_args(message, - DBUS_TYPE_STRING, &iface, - DBUS_TYPE_STRING, &prop, - DBUS_TYPE_INVALID); - - bool status = - dbus_connection_send_with_reply(conn, message, &pending, -1); - - dbus_message_unref(message); - - if (!(pending || status)) { - sway_log(L_ERROR, "Could not get item icon"); - return; - } - - dbus_pending_call_set_notify(pending, reply_icon, item, NULL); -} /* Get an icon by its name */ -static void reply_icon_name(DBusPendingCall *pending, void *_data) { +static void reply_icon_name(DBusMessageIter *iter, void *_data) { struct StatusNotifierItem *item = _data; - DBusMessage *reply = dbus_pending_call_steal_reply(pending); - - if (!reply) { - sway_log(L_INFO, "Got no icon name reply from item"); - goto bail; - } - - int message_type = dbus_message_get_type(reply); - - if (message_type == DBUS_MESSAGE_TYPE_ERROR) { - char *msg; - - dbus_message_get_args(reply, NULL, - DBUS_TYPE_STRING, &msg, - DBUS_TYPE_INVALID); - - sway_log(L_INFO, "Could not get icon name: %s", msg); - goto bail; - } - - DBusMessageIter iter; /* v[s] */ - DBusMessageIter variant; /* s */ - - dbus_message_iter_init(reply, &iter); - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - sway_log(L_ERROR, "Icon name relpy type incorrect"); - goto bail; - } - dbus_message_iter_recurse(&iter, &variant); - - - if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_STRING) { - sway_log(L_ERROR, "Icon name relpy type incorrect"); - goto bail; - } - char *icon_name; - dbus_message_iter_get_basic(&variant, &icon_name); + dbus_message_iter_get_basic(iter, &icon_name); cairo_surface_t *image = find_icon(icon_name, 256); @@ -259,55 +149,19 @@ static void reply_icon_name(DBusPendingCall *pending, void *_data) { item->dirty = true; dirty = true; - dbus_message_unref(reply); - dbus_pending_call_unref(pending); return; } -bail: - if (reply) { - dbus_message_unref(reply); - } - dbus_pending_call_unref(pending); // Now try the pixmap - send_icon_msg(item); - return; -} -static void send_icon_name_msg(struct StatusNotifierItem *item) { - DBusPendingCall *pending; - DBusMessage *message = dbus_message_new_method_call( - item->name, - item->object_path, - "org.freedesktop.DBus.Properties", - "Get"); - const char *iface; - if (item->kde_special_snowflake) { - iface = "org.kde.StatusNotifierItem"; - } else { - iface = "org.freedesktop.StatusNotifierItem"; - } - const char *prop = "IconName"; - - dbus_message_append_args(message, - DBUS_TYPE_STRING, &iface, - DBUS_TYPE_STRING, &prop, - DBUS_TYPE_INVALID); - - bool status = - dbus_connection_send_with_reply(conn, message, &pending, -1); - - dbus_message_unref(message); - - if (!(pending || status)) { - sway_log(L_ERROR, "Could not get item icon name"); - return; - } - - dbus_pending_call_set_notify(pending, reply_icon_name, item, NULL); + dbus_get_prop_async(item->name, item->object_path, + (item->kde_special_snowflake ? KDE_IFACE : FD_IFACE), + "IconPixmap", "a(iiay)", reply_icon, item); } void get_icon(struct StatusNotifierItem *item) { - send_icon_name_msg(item); + dbus_get_prop_async(item->name, item->object_path, + (item->kde_special_snowflake ? KDE_IFACE : FD_IFACE), + "IconName", "s", reply_icon_name, item); } void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index f1ecb429..89e7c3e2 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -38,47 +38,13 @@ static void register_host(char *name) { dbus_message_unref(message); } -static void get_items_reply(DBusPendingCall *pending, void *_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(pending); - - if (!reply) { - sway_log(L_ERROR, "Got no items reply from sni watcher"); - goto bail; - } - - int message_type = dbus_message_get_type(reply); - - if (message_type == DBUS_MESSAGE_TYPE_ERROR) { - char *msg; - - dbus_message_get_args(reply, NULL, - DBUS_TYPE_STRING, &msg, - DBUS_TYPE_INVALID); - - sway_log(L_ERROR, "Message is error: %s", msg); - goto bail; - } - - DBusMessageIter iter; - DBusMessageIter variant; +static void get_items_reply(DBusMessageIter *iter, void *_data) { DBusMessageIter array; - dbus_message_iter_init(reply, &iter); - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - sway_log(L_ERROR, "Replyed with wrong type, not v(as)"); - goto bail; - } - dbus_message_iter_recurse(&iter, &variant); - if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_ARRAY || - dbus_message_iter_get_element_type(&variant) != DBUS_TYPE_STRING) { - sway_log(L_ERROR, "Replyed with wrong type, not v(as)"); - goto bail; - } - // O(n) function, could be faster dynamically reading values - int len = dbus_message_iter_get_element_count(&variant); + int len = dbus_message_iter_get_element_count(iter); - dbus_message_iter_recurse(&variant, &array); + dbus_message_iter_recurse(iter, &array); for (int i = 0; i < len; i++) { const char *name; dbus_message_iter_get_basic(&array, &name); @@ -93,52 +59,14 @@ static void get_items_reply(DBusPendingCall *pending, void *_data) { } } } - -bail: - dbus_message_unref(reply); - dbus_pending_call_unref(pending); - return; } -static void get_obj_items_reply(DBusPendingCall *pending, void *_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(pending); - - if (!reply) { - sway_log(L_ERROR, "Got no object path items reply from sni watcher"); - goto bail; - } - - int message_type = dbus_message_get_type(reply); - - if (message_type == DBUS_MESSAGE_TYPE_ERROR) { - char *msg; - - dbus_message_get_args(reply, NULL, - DBUS_TYPE_STRING, &msg, - DBUS_TYPE_INVALID); - - sway_log(L_ERROR, "Message is error: %s", msg); - goto bail; - } - - DBusMessageIter iter; - DBusMessageIter variant; +static void get_obj_items_reply(DBusMessageIter *iter, void *_data) { DBusMessageIter array; DBusMessageIter dstruct; - dbus_message_iter_init(reply, &iter); - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { - sway_log(L_ERROR, "Replyed with wrong type, not v(a(os))"); - goto bail; - } - dbus_message_iter_recurse(&iter, &variant); - if (dbus_message_iter_check_signature(&iter, "a(os)")) { - sway_log(L_ERROR, "Replyed with wrong type not a(os)"); - goto bail; - } - - int len = dbus_message_iter_get_element_count(&variant); + int len = dbus_message_iter_get_element_count(iter); - dbus_message_iter_recurse(&variant, &array); + dbus_message_iter_recurse(iter, &array); for (int i = 0; i < len; i++) { const char *object_path; const char *unique_name; @@ -164,10 +92,6 @@ static void get_obj_items_reply(DBusPendingCall *pending, void *_data) { } } } - -bail: - dbus_message_unref(reply); - dbus_pending_call_unref(pending); } static void get_items() { @@ -176,52 +100,13 @@ static void get_items() { list_free(tray->items); tray->items = create_list(); - DBusPendingCall *pending; - DBusMessage *message = dbus_message_new_method_call( - "org.freedesktop.StatusNotifierWatcher", - "/StatusNotifierWatcher", - "org.freedesktop.DBus.Properties", - "Get"); - - const char *iface = "org.freedesktop.StatusNotifierWatcher"; - const char *prop = "RegisteredStatusNotifierItems"; - dbus_message_append_args(message, - DBUS_TYPE_STRING, &iface, - DBUS_TYPE_STRING, &prop, - DBUS_TYPE_INVALID); - - bool status = - dbus_connection_send_with_reply(conn, message, &pending, -1); - dbus_message_unref(message); - - if (!(pending || status)) { - sway_log(L_ERROR, "Could not get items"); - return; - } - - dbus_pending_call_set_notify(pending, get_items_reply, NULL, NULL); + dbus_get_prop_async("org.freedesktop.StatusNotifierWatcher", + "/StatusNotifierWatcher","org.freedesktop.StatusNotifierWatcher", + "RegisteredStatusNotifierItems", "as", get_items_reply, NULL); - message = dbus_message_new_method_call( - "org.freedesktop.StatusNotifierWatcher", - "/StatusNotifierWatcher", - "org.freedesktop.DBus.Properties", - "Get"); - - iface = "org.swaywm.LessSuckyStatusNotifierWatcher"; - prop = "RegisteredObjectPathItems"; - dbus_message_append_args(message, - DBUS_TYPE_STRING, &iface, - DBUS_TYPE_STRING, &prop, - DBUS_TYPE_INVALID); - - status = dbus_connection_send_with_reply(conn, message, &pending, -1); - dbus_message_unref(message); - - if (!(pending || status)) { - sway_log(L_ERROR, "Could not get items"); - return; - } - dbus_pending_call_set_notify(pending, get_obj_items_reply, NULL, NULL); + dbus_get_prop_async("org.freedesktop.StatusNotifierWatcher", + "/StatusNotifierWatcher","org.swaywm.LessSuckyStatusNotifierWatcher", + "RegisteredObjectPathItems", "a(os)", get_obj_items_reply, NULL); } static DBusHandlerResult signal_handler(DBusConnection *connection, |
