diff options
Diffstat (limited to 'swaybar/tray/sni.c')
-rw-r--r-- | swaybar/tray/sni.c | 184 |
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 | ||
17 | static const char *KDE_IFACE = "org.kde.StatusNotifierItem"; | ||
18 | static 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. |
18 | static const cairo_user_data_key_t cairo_user_data_key; | 21 | static 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 */ |
41 | static void reply_icon(DBusPendingCall *pending, void *_data) { | 44 | static 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 | ||
166 | bail: | ||
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 | } |
174 | static 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 */ |
208 | static void reply_icon_name(DBusPendingCall *pending, void *_data) { | 134 | static 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 | ||
267 | bail: | ||
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); |
276 | static 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 | ||
309 | void get_icon(struct StatusNotifierItem *item) { | 161 | void 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 | ||
313 | void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { | 167 | void sni_activate(struct StatusNotifierItem *item, uint32_t x, uint32_t y) { |