aboutsummaryrefslogtreecommitdiff
path: root/swaybar/tray/sni.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar/tray/sni.c')
-rw-r--r--swaybar/tray/sni.c481
1 files changed, 0 insertions, 481 deletions
diff --git a/swaybar/tray/sni.c b/swaybar/tray/sni.c
deleted file mode 100644
index c9d00657..00000000
--- a/swaybar/tray/sni.c
+++ /dev/null
@@ -1,481 +0,0 @@
-#define _XOPEN_SOURCE 500
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <dbus/dbus.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include "swaybar/tray/dbus.h"
-#include "swaybar/tray/sni.h"
-#include "swaybar/tray/icon.h"
-#include "swaybar/bar.h"
-#include "client/cairo.h"
-#include "log.h"
-
-// Not sure what this is but cairo needs it.
-static const cairo_user_data_key_t cairo_user_data_key;
-
-struct sni_icon_ref *sni_icon_ref_create(struct StatusNotifierItem *item,
- int height) {
- struct sni_icon_ref *sni_ref = malloc(sizeof(struct sni_icon_ref));
- if (!sni_ref) {
- return NULL;
- }
- sni_ref->icon = cairo_image_surface_scale(item->image, height, height);
- sni_ref->ref = item;
-
- return sni_ref;
-}
-
-void sni_icon_ref_free(struct sni_icon_ref *sni_ref) {
- if (!sni_ref) {
- return;
- }
- cairo_surface_destroy(sni_ref->icon);
- free(sni_ref);
-}
-
-/* Gets the pixmap of an icon */
-static void reply_icon(DBusPendingCall *pending, 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, "Relpy type incorrect");
- sway_log(L_ERROR, "Should be \"v\", is \"%s\"",
- dbus_message_iter_get_signature(&iter));
- goto bail;
- }
- dbus_message_iter_recurse(&iter, &variant);
-
- if (strcmp("a(iiay)", dbus_message_iter_get_signature(&variant)) != 0) {
- sway_log(L_ERROR, "Relpy type incorrect");
- sway_log(L_ERROR, "Should be \"a(iiay)\", is \"%s\"",
- dbus_message_iter_get_signature(&variant));
- goto bail;
- }
-
- if (dbus_message_iter_get_element_count(&variant) == 0) {
- // Can't recurse if there are no items
- sway_log(L_INFO, "Item has no icon");
- goto bail;
- }
- dbus_message_iter_recurse(&variant, &array);
-
- dbus_message_iter_recurse(&array, &d_struct);
-
- int width;
- dbus_message_iter_get_basic(&d_struct, &width);
- dbus_message_iter_next(&d_struct);
-
- int height;
- dbus_message_iter_get_basic(&d_struct, &height);
- dbus_message_iter_next(&d_struct);
-
- int len = dbus_message_iter_get_element_count(&d_struct);
-
- if (!len) {
- sway_log(L_ERROR, "No icon data");
- goto bail;
- }
-
- // Also implies len % 4 == 0, useful below
- if (len != width * height * 4) {
- sway_log(L_ERROR, "Incorrect array size passed");
- goto bail;
- }
-
- dbus_message_iter_recurse(&d_struct, &icon);
-
- int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
- // 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;
- }
-
- // Data is by reference, no need to free
- uint8_t *message_data;
- dbus_message_iter_get_fixed_array(&icon, &message_data, &len);
-
- uint8_t *image_data = malloc(stride * height);
- if (!image_data) {
- sway_log(L_ERROR, "Could not allocate memory for icon");
- goto bail;
- }
-
- // Transform from network byte order to host byte order
- // Assumptions are safe because the equality above
- uint32_t *network = (uint32_t *) message_data;
- uint32_t *host = (uint32_t *)image_data;
- for (int i = 0; i < width * height; ++i) {
- host[i] = ntohl(network[i]);
- }
-
- cairo_surface_t *image = cairo_image_surface_create_for_data(
- image_data, CAIRO_FORMAT_ARGB32,
- width, height, stride);
-
- if (image) {
- if (item->image) {
- cairo_surface_destroy(item->image);
- }
- item->image = image;
- // Free the image data on surface destruction
- cairo_surface_set_user_data(image,
- &cairo_user_data_key,
- image_data,
- free);
- 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,
- "/StatusNotifierItem",
- "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) {
- 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, "Relpy type incorrect");
- sway_log(L_ERROR, "Should be \"v\", is \"%s\"",
- dbus_message_iter_get_signature(&iter));
- goto bail;
- }
- dbus_message_iter_recurse(&iter, &variant);
-
-
- if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_STRING) {
- sway_log(L_ERROR, "Relpy type incorrect");
- sway_log(L_ERROR, "Should be \"s\", is \"%s\"",
- dbus_message_iter_get_signature(&iter));
- goto bail;
- }
-
- char *icon_name;
- dbus_message_iter_get_basic(&variant, &icon_name);
-
- cairo_surface_t *image = find_icon(icon_name, 256);
-
- if (image) {
- sway_log(L_DEBUG, "Icon for %s found with size %d", icon_name,
- cairo_image_surface_get_width(image));
- if (item->image) {
- cairo_surface_destroy(item->image);
- }
- item->image = image;
- 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,
- "/StatusNotifierItem",
- "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);
-}
-
-void get_icon(struct StatusNotifierItem *item) {
- send_icon_name_msg(item);
-}
-
-void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {
- const char *iface =
- (item->kde_special_snowflake ? "org.kde.StatusNotifierItem"
- : "org.freedesktop.StatusNotifierItem");
- DBusMessage *message = dbus_message_new_method_call(
- item->name,
- "/StatusNotifierItem",
- iface,
- "Activate");
-
- dbus_message_append_args(message,
- DBUS_TYPE_INT32, &x,
- DBUS_TYPE_INT32, &y,
- DBUS_TYPE_INVALID);
-
- dbus_connection_send(conn, message, NULL);
-
- dbus_message_unref(message);
-}
-
-void sni_context_menu(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {
- const char *iface =
- (item->kde_special_snowflake ? "org.kde.StatusNotifierItem"
- : "org.freedesktop.StatusNotifierItem");
- DBusMessage *message = dbus_message_new_method_call(
- item->name,
- "/StatusNotifierItem",
- iface,
- "ContextMenu");
-
- dbus_message_append_args(message,
- DBUS_TYPE_INT32, &x,
- DBUS_TYPE_INT32, &y,
- DBUS_TYPE_INVALID);
-
- dbus_connection_send(conn, message, NULL);
-
- dbus_message_unref(message);
-}
-void sni_secondary(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {
- const char *iface =
- (item->kde_special_snowflake ? "org.kde.StatusNotifierItem"
- : "org.freedesktop.StatusNotifierItem");
- DBusMessage *message = dbus_message_new_method_call(
- item->name,
- "/StatusNotifierItem",
- iface,
- "SecondaryActivate");
-
- dbus_message_append_args(message,
- DBUS_TYPE_INT32, &x,
- DBUS_TYPE_INT32, &y,
- DBUS_TYPE_INVALID);
-
- dbus_connection_send(conn, message, NULL);
-
- dbus_message_unref(message);
-}
-
-static void get_unique_name(struct StatusNotifierItem *item) {
- // I think that we're fine being sync here becaues the message is
- // directly to the message bus. Could be async though.
- DBusMessage *message = dbus_message_new_method_call(
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "GetNameOwner");
-
- dbus_message_append_args(message,
- DBUS_TYPE_STRING, &item->name,
- DBUS_TYPE_INVALID);
-
- DBusMessage *reply = dbus_connection_send_with_reply_and_block(
- conn, message, -1, NULL);
-
- dbus_message_unref(message);
-
- if (!reply) {
- sway_log(L_ERROR, "Could not get unique name for item: %s",
- item->name);
- return;
- }
-
- char *unique_name;
- if (!dbus_message_get_args(reply, NULL,
- DBUS_TYPE_STRING, &unique_name,
- DBUS_TYPE_INVALID)) {
- sway_log(L_ERROR, "Error parsing method args");
- } else {
- if (item->unique_name) {
- free(item->unique_name);
- }
- item->unique_name = strdup(unique_name);
- }
-
- dbus_message_unref(reply);
-}
-
-struct StatusNotifierItem *sni_create(const char *name) {
- // Make sure `name` is well formed
- if (!dbus_validate_bus_name(name, NULL)) {
- sway_log(L_INFO, "Name (%s) is not a bus name. We cannot create an item.", name);
- return NULL;
- }
-
- struct StatusNotifierItem *item = malloc(sizeof(struct StatusNotifierItem));
- item->name = strdup(name);
- item->unique_name = NULL;
- item->image = NULL;
- item->dirty = false;
-
- // If it doesn't use this name then assume that it uses the KDE spec
- // This is because xembed-sni-proxy uses neither "org.freedesktop" nor
- // "org.kde" and just gives us the items "unique name"
- //
- // We could use this to our advantage and fill out the "unique name"
- // field with the given name if it is neither freedesktop or kde, but
- // that's makes us rely on KDE hackyness which is bad practice
- const char freedesktop_name[] = "org.freedesktop";
- if (strncmp(name, freedesktop_name, sizeof(freedesktop_name) - 1) != 0) {
- item->kde_special_snowflake = true;
- } else {
- item->kde_special_snowflake = false;
- }
-
- get_icon(item);
-
- get_unique_name(item);
-
- return item;
-}
-/* Return 0 if `item` has a name of `str` */
-int sni_str_cmp(const void *_item, const void *_str) {
- const struct StatusNotifierItem *item = _item;
- const char *str = _str;
-
- return strcmp(item->name, str);
-}
-/* Returns 0 if `item` has a unique name of `str` */
-int sni_uniq_cmp(const void *_item, const void *_str) {
- const struct StatusNotifierItem *item = _item;
- const char *str = _str;
-
- if (!item->unique_name) {
- return false;
- }
- return strcmp(item->unique_name, str);
-}
-void sni_free(struct StatusNotifierItem *item) {
- if (!item) {
- return;
- }
- free(item->name);
- if (item->unique_name) {
- free(item->unique_name);
- }
- if (item->image) {
- cairo_surface_destroy(item->image);
- }
- free(item);
-}