aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/tray/sni.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaybar/tray/sni.c')
-rw-r--r--swaybar/tray/sni.c184
1 files changed, 19 insertions, 165 deletions
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 @@
14#include "client/cairo.h" 14#include "client/cairo.h"
15#include "log.h" 15#include "log.h"
16 16
17static const char *KDE_IFACE = "org.kde.StatusNotifierItem";
18static const char *FD_IFACE = "org.freedesktop.StatusNotifierItem";
19
17// Not sure what this is but cairo needs it. 20// Not sure what this is but cairo needs it.
18static const cairo_user_data_key_t cairo_user_data_key; 21static const cairo_user_data_key_t cairo_user_data_key;
19 22
@@ -38,57 +41,19 @@ void sni_icon_ref_free(struct sni_icon_ref *sni_ref) {
38} 41}
39 42
40/* Gets the pixmap of an icon */ 43/* Gets the pixmap of an icon */
41static void reply_icon(DBusPendingCall *pending, void *_data) { 44static void reply_icon(DBusMessageIter *iter /* a(iiay) */, void *_data) {
42 struct StatusNotifierItem *item = _data; 45 struct StatusNotifierItem *item = _data;
43 46
44 DBusMessage *reply = dbus_pending_call_steal_reply(pending);
45
46 if (!reply) {
47 sway_log(L_ERROR, "Did not get reply");
48 goto bail;
49 }
50
51 int message_type = dbus_message_get_type(reply);
52
53 if (message_type == DBUS_MESSAGE_TYPE_ERROR) {
54 char *msg;
55
56 dbus_message_get_args(reply, NULL,
57 DBUS_TYPE_STRING, &msg,
58 DBUS_TYPE_INVALID);
59
60 sway_log(L_ERROR, "Message is error: %s", msg);
61 goto bail;
62 }
63
64 DBusMessageIter iter;
65 DBusMessageIter variant; /* v[a(iiay)] */
66 DBusMessageIter array; /* a(iiay) */
67 DBusMessageIter d_struct; /* (iiay) */ 47 DBusMessageIter d_struct; /* (iiay) */
68 DBusMessageIter icon; /* ay */ 48 DBusMessageIter icon; /* ay */
69 49
70 dbus_message_iter_init(reply, &iter); 50 if (dbus_message_iter_get_element_count(iter) == 0) {
71
72 // Each if here checks the types above before recursing
73 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
74 sway_log(L_ERROR, "Icon relpy type incorrect");
75 goto bail;
76 }
77 dbus_message_iter_recurse(&iter, &variant);
78
79 if (dbus_message_iter_check_signature(&variant, "a(iiay)")) {
80 sway_log(L_ERROR, "Icon relpy type incorrect");
81 goto bail;
82 }
83
84 if (dbus_message_iter_get_element_count(&variant) == 0) {
85 // Can't recurse if there are no items 51 // Can't recurse if there are no items
86 sway_log(L_INFO, "Item has no icon"); 52 sway_log(L_INFO, "Item has no icon");
87 goto bail; 53 return;
88 } 54 }
89 dbus_message_iter_recurse(&variant, &array);
90 55
91 dbus_message_iter_recurse(&array, &d_struct); 56 dbus_message_iter_recurse(iter, &d_struct);
92 57
93 int width; 58 int width;
94 dbus_message_iter_get_basic(&d_struct, &width); 59 dbus_message_iter_get_basic(&d_struct, &width);
@@ -102,13 +67,13 @@ static void reply_icon(DBusPendingCall *pending, void *_data) {
102 67
103 if (!len) { 68 if (!len) {
104 sway_log(L_ERROR, "No icon data"); 69 sway_log(L_ERROR, "No icon data");
105 goto bail; 70 return;
106 } 71 }
107 72
108 // Also implies len % 4 == 0, useful below 73 // Also implies len % 4 == 0, useful below
109 if (len != width * height * 4) { 74 if (len != width * height * 4) {
110 sway_log(L_ERROR, "Incorrect array size passed"); 75 sway_log(L_ERROR, "Incorrect array size passed");
111 goto bail; 76 return;
112 } 77 }
113 78
114 dbus_message_iter_recurse(&d_struct, &icon); 79 dbus_message_iter_recurse(&d_struct, &icon);
@@ -117,7 +82,7 @@ static void reply_icon(DBusPendingCall *pending, void *_data) {
117 // FIXME support a variable stride 82 // FIXME support a variable stride
118 // (works on my machine though for all tested widths) 83 // (works on my machine though for all tested widths)
119 if (!sway_assert(stride == width * 4, "Stride must be equal to byte length")) { 84 if (!sway_assert(stride == width * 4, "Stride must be equal to byte length")) {
120 goto bail; 85 return;
121 } 86 }
122 87
123 // Data is by reference, no need to free 88 // Data is by reference, no need to free
@@ -127,7 +92,7 @@ static void reply_icon(DBusPendingCall *pending, void *_data) {
127 uint8_t *image_data = malloc(stride * height); 92 uint8_t *image_data = malloc(stride * height);
128 if (!image_data) { 93 if (!image_data) {
129 sway_log(L_ERROR, "Could not allocate memory for icon"); 94 sway_log(L_ERROR, "Could not allocate memory for icon");
130 goto bail; 95 return;
131 } 96 }
132 97
133 // Transform from network byte order to host byte order 98 // Transform from network byte order to host byte order
@@ -155,97 +120,22 @@ static void reply_icon(DBusPendingCall *pending, void *_data) {
155 item->dirty = true; 120 item->dirty = true;
156 dirty = true; 121 dirty = true;
157 122
158 dbus_message_unref(reply);
159 dbus_pending_call_unref(pending);
160 return; 123 return;
161 } else { 124 } else {
162 sway_log(L_ERROR, "Could not create image surface"); 125 sway_log(L_ERROR, "Could not create image surface");
163 free(image_data); 126 free(image_data);
164 } 127 }
165 128
166bail:
167 if (reply) {
168 dbus_message_unref(reply);
169 }
170 dbus_pending_call_unref(pending);
171 sway_log(L_ERROR, "Could not get icon from item"); 129 sway_log(L_ERROR, "Could not get icon from item");
172 return; 130 return;
173} 131}
174static void send_icon_msg(struct StatusNotifierItem *item) {
175 DBusPendingCall *pending;
176 DBusMessage *message = dbus_message_new_method_call(
177 item->name,
178 item->object_path,
179 "org.freedesktop.DBus.Properties",
180 "Get");
181 const char *iface;
182 if (item->kde_special_snowflake) {
183 iface = "org.kde.StatusNotifierItem";
184 } else {
185 iface = "org.freedesktop.StatusNotifierItem";
186 }
187 const char *prop = "IconPixmap";
188
189 dbus_message_append_args(message,
190 DBUS_TYPE_STRING, &iface,
191 DBUS_TYPE_STRING, &prop,
192 DBUS_TYPE_INVALID);
193
194 bool status =
195 dbus_connection_send_with_reply(conn, message, &pending, -1);
196
197 dbus_message_unref(message);
198
199 if (!(pending || status)) {
200 sway_log(L_ERROR, "Could not get item icon");
201 return;
202 }
203
204 dbus_pending_call_set_notify(pending, reply_icon, item, NULL);
205}
206 132
207/* Get an icon by its name */ 133/* Get an icon by its name */
208static void reply_icon_name(DBusPendingCall *pending, void *_data) { 134static void reply_icon_name(DBusMessageIter *iter, void *_data) {
209 struct StatusNotifierItem *item = _data; 135 struct StatusNotifierItem *item = _data;
210 136
211 DBusMessage *reply = dbus_pending_call_steal_reply(pending);
212
213 if (!reply) {
214 sway_log(L_INFO, "Got no icon name reply from item");
215 goto bail;
216 }
217
218 int message_type = dbus_message_get_type(reply);
219
220 if (message_type == DBUS_MESSAGE_TYPE_ERROR) {
221 char *msg;
222
223 dbus_message_get_args(reply, NULL,
224 DBUS_TYPE_STRING, &msg,
225 DBUS_TYPE_INVALID);
226
227 sway_log(L_INFO, "Could not get icon name: %s", msg);
228 goto bail;
229 }
230
231 DBusMessageIter iter; /* v[s] */
232 DBusMessageIter variant; /* s */
233
234 dbus_message_iter_init(reply, &iter);
235 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
236 sway_log(L_ERROR, "Icon name relpy type incorrect");
237 goto bail;
238 }
239 dbus_message_iter_recurse(&iter, &variant);
240
241
242 if (dbus_message_iter_get_arg_type(&variant) != DBUS_TYPE_STRING) {
243 sway_log(L_ERROR, "Icon name relpy type incorrect");
244 goto bail;
245 }
246
247 char *icon_name; 137 char *icon_name;
248 dbus_message_iter_get_basic(&variant, &icon_name); 138 dbus_message_iter_get_basic(iter, &icon_name);
249 139
250 cairo_surface_t *image = find_icon(icon_name, 256); 140 cairo_surface_t *image = find_icon(icon_name, 256);
251 141
@@ -259,55 +149,19 @@ static void reply_icon_name(DBusPendingCall *pending, void *_data) {
259 item->dirty = true; 149 item->dirty = true;
260 dirty = true; 150 dirty = true;
261 151
262 dbus_message_unref(reply);
263 dbus_pending_call_unref(pending);
264 return; 152 return;
265 } 153 }
266 154
267bail:
268 if (reply) {
269 dbus_message_unref(reply);
270 }
271 dbus_pending_call_unref(pending);
272 // Now try the pixmap 155 // Now try the pixmap
273 send_icon_msg(item); 156 dbus_get_prop_async(item->name, item->object_path,
274 return; 157 (item->kde_special_snowflake ? KDE_IFACE : FD_IFACE),
275} 158 "IconPixmap", "a(iiay)", reply_icon, item);
276static void send_icon_name_msg(struct StatusNotifierItem *item) {
277 DBusPendingCall *pending;
278 DBusMessage *message = dbus_message_new_method_call(
279 item->name,
280 item->object_path,
281 "org.freedesktop.DBus.Properties",
282 "Get");
283 const char *iface;
284 if (item->kde_special_snowflake) {
285 iface = "org.kde.StatusNotifierItem";
286 } else {
287 iface = "org.freedesktop.StatusNotifierItem";
288 }
289 const char *prop = "IconName";
290
291 dbus_message_append_args(message,
292 DBUS_TYPE_STRING, &iface,
293 DBUS_TYPE_STRING, &prop,
294 DBUS_TYPE_INVALID);
295
296 bool status =
297 dbus_connection_send_with_reply(conn, message, &pending, -1);
298
299 dbus_message_unref(message);
300
301 if (!(pending || status)) {
302 sway_log(L_ERROR, "Could not get item icon name");
303 return;
304 }
305
306 dbus_pending_call_set_notify(pending, reply_icon_name, item, NULL);
307} 159}
308 160
309void get_icon(struct StatusNotifierItem *item) { 161void get_icon(struct StatusNotifierItem *item) {
310 send_icon_name_msg(item); 162 dbus_get_prop_async(item->name, item->object_path,
163 (item->kde_special_snowflake ? KDE_IFACE : FD_IFACE),
164 "IconName", "s", reply_icon_name, item);
311} 165}
312 166
313void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { 167void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) {