Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-3.0-or-later
2 : : // SPDX-FileCopyrightText: Andy Holmes <andrew.g.r.holmes@gmail.com>
3 : :
4 : : #define G_LOG_DOMAIN "valent-fdo-notifications"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <valent.h>
10 : :
11 : : #ifdef HAVE_GLYCIN
12 : : #include <glycin.h>
13 : : #endif /* HAVE_GLYCIN */
14 : :
15 : : #include "valent-fdo-notifications.h"
16 : :
17 : :
18 : : struct _ValentFdoNotifications
19 : : {
20 : : ValentNotificationsAdapter parent_instance;
21 : :
22 : : GHashTable *pending;
23 : : GDBusInterfaceVTable vtable;
24 : : GDBusNodeInfo *node_info;
25 : : GDBusInterfaceInfo *iface_info;
26 : : GDBusConnection *monitor;
27 : : unsigned int monitor_id;
28 : : char *name_owner;
29 : : unsigned int name_owner_id;
30 : : GDBusConnection *session;
31 : : unsigned int closed_id;
32 : : unsigned int filter_id;
33 : : };
34 : :
35 : : static void g_async_initable_iface_init (GAsyncInitableIface *iface);
36 : :
37 [ + + + - ]: 13 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentFdoNotifications, valent_fdo_notifications, VALENT_TYPE_NOTIFICATIONS_ADAPTER,
38 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, g_async_initable_iface_init))
39 : :
40 : :
41 : : /*
42 : : * Map of notification-spec urgency to GNotificationPriority
43 : : *
44 : : * See: https://developer-old.gnome.org/notification-spec/#urgency-levels
45 : : */
46 : : static const unsigned int urgencies[] = {
47 : : G_NOTIFICATION_PRIORITY_LOW,
48 : : G_NOTIFICATION_PRIORITY_NORMAL,
49 : : G_NOTIFICATION_PRIORITY_URGENT
50 : : };
51 : :
52 : :
53 : : /*
54 : : * GDBusInterfaceSkeleton
55 : : */
56 : : static const char interface_xml[] =
57 : : "<node>"
58 : : " <interface name='org.freedesktop.Notifications'>"
59 : : " <method name='Notify'>"
60 : : " <arg name='appName' type='s' direction='in'/>"
61 : : " <arg name='replacesId' type='u' direction='in'/>"
62 : : " <arg name='iconName' type='s' direction='in'/>"
63 : : " <arg name='summary' type='s' direction='in'/>"
64 : : " <arg name='body' type='s' direction='in'/>"
65 : : " <arg name='actions' type='as' direction='in'/>"
66 : : " <arg name='hints' type='a{sv}' direction='in'/>"
67 : : " <arg name='timeout' type='i' direction='in'/>"
68 : : " <arg name='id' type='u' direction='out'/>"
69 : : " </method>"
70 : : " </interface>"
71 : : "</node>";
72 : :
73 : : static const char *interface_matches[] = {
74 : : "interface='org.freedesktop.Notifications',member='Notify',type='method_call'",
75 : : "type='method_return'",
76 : : NULL
77 : : };
78 : :
79 : :
80 : : static GIcon *
81 : 0 : _g_icon_new_for_variant (GVariant *image_data)
82 : : {
83 : : #ifdef HAVE_GLYCIN
84 : 0 : int32_t width, height, rowstride;
85 : 0 : gboolean has_alpha;
86 : 0 : int32_t bits_per_sample, n_channels;
87 : 0 : g_autoptr (GVariant) data_variant = NULL;
88 : 0 : const unsigned char *data = NULL;
89 : 0 : size_t data_len = 0;
90 : 0 : size_t expected_len = 0;
91 : :
92 [ # # ]: 0 : g_autoptr (GlyCreator) creator = NULL;
93 [ # # ]: 0 : g_autoptr (GlyNewFrame) frame = NULL;
94 [ # # ]: 0 : g_autoptr (GlyEncodedImage) image = NULL;
95 [ # # ]: 0 : g_autoptr (GBytes) texture = NULL;
96 [ # # ]: 0 : g_autoptr (GBytes) encoded = NULL;
97 [ # # ]: 0 : g_autoptr (GError) error = NULL;
98 : :
99 : 0 : g_variant_get (image_data, "(iiibii@ay)",
100 : : &width,
101 : : &height,
102 : : &rowstride,
103 : : &has_alpha,
104 : : &bits_per_sample,
105 : : &n_channels,
106 : : &data_variant);
107 : :
108 : 0 : data = g_variant_get_data (data_variant);
109 : 0 : data_len = g_variant_get_size (data_variant);
110 : 0 : expected_len = (height - 1) * rowstride + width
111 : 0 : * ((n_channels * bits_per_sample + 7) / 8);
112 : :
113 [ # # ]: 0 : if (expected_len != data_len)
114 : : {
115 : 0 : g_warning ("Expected image data to be of length %zu not %zu",
116 : : expected_len,
117 : : data_len);
118 : 0 : return NULL;
119 : : }
120 : :
121 [ # # ]: 0 : g_return_val_if_fail (bits_per_sample == 8, NULL);
122 [ # # # # : 0 : g_return_val_if_fail ((has_alpha && n_channels == 4) ||
# # # # ]
123 : : (!has_alpha && n_channels == 3), NULL);
124 : :
125 : 0 : creator = gly_creator_new ("image/png", &error);
126 [ # # ]: 0 : if (creator == NULL)
127 : : {
128 : 0 : g_warning ("%s(): Creating image: %s", G_STRFUNC, error->message);
129 : 0 : return NULL;
130 : : }
131 : :
132 : 0 : texture = g_bytes_new (data, data_len);
133 : 0 : frame = gly_creator_add_frame_with_stride (creator,
134 : : width,
135 : : height,
136 : : rowstride,
137 : : has_alpha
138 [ # # ]: 0 : ? GLY_MEMORY_R8G8B8A8
139 : : : GLY_MEMORY_R8G8B8,
140 : : texture,
141 : : &error);
142 [ # # ]: 0 : if (frame == NULL)
143 : : {
144 : 0 : g_warning ("%s(): Adding frame: %s", G_STRFUNC, error->message);
145 : 0 : return NULL;
146 : : }
147 : :
148 : 0 : image = gly_creator_create (creator, &error);
149 [ # # ]: 0 : if (image == NULL)
150 : : {
151 : 0 : g_warning ("%s(): Encoding image: %s", G_STRFUNC, error->message);
152 : 0 : return NULL;
153 : : }
154 : :
155 : 0 : encoded = gly_encoded_image_get_data (image);
156 : :
157 : 0 : return g_bytes_icon_new (encoded);
158 : : #else
159 : : return NULL;
160 : : #endif /* HAVE_GLYCIN */
161 : : }
162 : :
163 : : static void
164 : 1 : _notification_closed (ValentNotificationsAdapter *adapter,
165 : : GVariant *parameters)
166 : : {
167 : 1 : uint32_t id, reason;
168 : 2 : g_autofree char *id_str = NULL;
169 : :
170 : 1 : g_variant_get (parameters, "(uu)", &id, &reason);
171 : :
172 : 1 : id_str = g_strdup_printf ("%u", id);
173 : 1 : valent_notifications_adapter_notification_removed (adapter, id_str);
174 : 1 : }
175 : :
176 : : static void
177 : 1 : _notify (ValentNotificationsAdapter *adapter,
178 : : GDBusMessage *message,
179 : : GVariant *parameters)
180 : : {
181 : 1 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (adapter);
182 : 2 : g_autoptr (ValentNotification) notification = NULL;
183 [ + - ]: 1 : g_autoptr (GIcon) icon = NULL;
184 : 1 : uint32_t serial;
185 : :
186 : 1 : const char *app_name;
187 : 1 : uint32_t replaces_id;
188 : 1 : const char *app_icon;
189 : 1 : const char *summary;
190 : 1 : const char *body;
191 [ + - ]: 1 : g_autoptr (GVariant) actions = NULL;
192 [ + - ]: 1 : g_autoptr (GVariant) hints = NULL;
193 : 1 : int32_t expire_timeout;
194 : :
195 [ + - ]: 1 : g_autofree char *replaces_id_str = NULL;
196 : 1 : g_autoptr (GVariant) image_data = NULL;
197 : 1 : const char *image_path;
198 : 1 : unsigned char urgency;
199 : :
200 : : /* Extract what we need from the parameters */
201 : 1 : g_variant_get (parameters, "(&su&s&s&s@as@a{sv}i)",
202 : : &app_name,
203 : : &replaces_id,
204 : : &app_icon,
205 : : &summary,
206 : : &body,
207 : : &actions,
208 : : &hints,
209 : : &expire_timeout);
210 : :
211 : 1 : replaces_id_str = g_strdup_printf ("%u", replaces_id);
212 : :
213 : : /* Deserialize GNotification into ValentNotification */
214 : 1 : notification = valent_notification_new (NULL);
215 : 1 : valent_notification_set_id (notification, replaces_id_str);
216 : 1 : valent_notification_set_application (notification, app_name);
217 : 1 : valent_resource_set_title (VALENT_RESOURCE (notification), summary);
218 : 1 : valent_notification_set_body (notification, body);
219 : :
220 : : /* This ordering is required by the specification.
221 : : * See: https://specifications.freedesktop.org/notification-spec/latest/icons-and-images.html
222 : : */
223 [ + - - + ]: 2 : if (g_variant_lookup (hints, "image-data", "@(iiibiiay)", &image_data) ||
224 : 1 : g_variant_lookup (hints, "image_data", "@(iiibiiay)", &image_data))
225 : : {
226 : 0 : icon = _g_icon_new_for_variant (image_data);
227 : 0 : valent_notification_set_icon (notification, icon);
228 : : }
229 [ + - - + ]: 2 : else if (g_variant_lookup (hints, "image-path", "&s", &image_path) ||
230 : 1 : g_variant_lookup (hints, "image_path", "&s", &image_path))
231 : : {
232 : 0 : icon = g_icon_new_for_string (image_path, NULL);
233 : 0 : valent_notification_set_icon (notification, icon);
234 : : }
235 [ + - ]: 1 : else if (*app_icon != '\0')
236 : : {
237 : 1 : icon = g_icon_new_for_string (app_icon, NULL);
238 : 1 : valent_notification_set_icon (notification, icon);
239 : : }
240 [ # # ]: 0 : else if (g_variant_lookup (hints, "icon_data", "@(iiibiiay)", &image_data))
241 : : {
242 : 0 : icon = _g_icon_new_for_variant (image_data);
243 : 0 : valent_notification_set_icon (notification, icon);
244 : : }
245 : :
246 : : /* Map libnotify urgency to GNotification priority */
247 [ + - + - ]: 1 : if (g_variant_lookup (hints, "urgency", "y", &urgency) && urgency < G_N_ELEMENTS (urgencies))
248 : 1 : valent_notification_set_priority (notification, urgencies[urgency]);
249 : : else
250 : 0 : valent_notification_set_priority (notification, G_NOTIFICATION_PRIORITY_NORMAL);
251 : :
252 : : /* Set a timestamp */
253 : 1 : valent_notification_set_time (notification, valent_timestamp_ms ());
254 : :
255 : : /* Wait for the reply to get the correct notification ID
256 : : */
257 : 1 : valent_object_lock (VALENT_OBJECT (self));
258 : 1 : serial = g_dbus_message_get_serial (message);
259 : 1 : g_hash_table_replace (self->pending,
260 : 1 : GUINT_TO_POINTER (serial),
261 : : g_object_ref (notification));
262 [ - + ]: 1 : valent_object_unlock (VALENT_OBJECT (self));
263 : 1 : }
264 : :
265 : : static void
266 : 1 : valent_fdo_notifications_method_call (GDBusConnection *connection,
267 : : const char *sender,
268 : : const char *object_path,
269 : : const char *interface_name,
270 : : const char *method_name,
271 : : GVariant *parameters,
272 : : GDBusMethodInvocation *invocation,
273 : : gpointer user_data)
274 : : {
275 : 1 : ValentNotificationsAdapter *adapter = VALENT_NOTIFICATIONS_ADAPTER (user_data);
276 : 1 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
277 : 1 : GDBusMessage *message;
278 : 1 : const char *destination;
279 : :
280 [ - + ]: 1 : g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
281 [ + - ]: 1 : g_assert (VALENT_IS_FDO_NOTIFICATIONS (self));
282 : :
283 : 1 : message = g_dbus_method_invocation_get_message (invocation);
284 : 1 : destination = g_dbus_message_get_destination (message);
285 : :
286 : : // TODO: accepting notifications from the well-known name causes duplicates on
287 : : // GNOME Shell where a proxy daemon is run.
288 [ - + - - ]: 1 : if (g_strcmp0 ("org.freedesktop.Notifications", destination) != 0 &&
289 : 0 : g_strcmp0 (self->name_owner, destination) != 0)
290 : 0 : goto out;
291 : :
292 [ - + ]: 1 : if (g_strcmp0 (method_name, "Notify") == 0)
293 : 1 : _notify (adapter, message, parameters);
294 : :
295 : 0 : out:
296 : 1 : g_object_unref (invocation);
297 : 1 : }
298 : :
299 : : static gboolean
300 : 1 : valent_fdo_notifications_filter_main (gpointer data)
301 : : {
302 : 1 : GTask *task = G_TASK (data);
303 : 1 : ValentFdoNotifications *self = g_task_get_source_object (task);
304 : 1 : ValentNotificationsAdapter *adapter = g_task_get_source_object (task);
305 : 1 : GDBusMessage *message = g_task_get_task_data (task);
306 : 2 : g_autoptr (ValentNotification) notification = NULL;
307 : 1 : uint32_t reply_serial;
308 : :
309 [ - + ]: 1 : g_assert (VALENT_IS_MAIN_THREAD ());
310 : :
311 : 1 : reply_serial = g_dbus_message_get_reply_serial (message);
312 : 1 : valent_object_lock (VALENT_OBJECT (self));
313 : 1 : g_hash_table_steal_extended (self->pending,
314 : 1 : GUINT_TO_POINTER (reply_serial),
315 : : NULL,
316 : : (void **)¬ification);
317 : 1 : valent_object_unlock (VALENT_OBJECT (self));
318 : :
319 [ + - ]: 1 : if (notification != NULL)
320 : : {
321 : 1 : GVariant *body = NULL;
322 : :
323 : 1 : body = g_dbus_message_get_body (message);
324 [ + - ]: 1 : if (g_variant_is_of_type (body, G_VARIANT_TYPE ("(u)")))
325 : : {
326 : 1 : g_autofree char *id_str = NULL;
327 : 1 : uint32_t notification_id;
328 : :
329 : 1 : g_variant_get (body, "(u)", ¬ification_id);
330 : 1 : id_str = g_strdup_printf ("%u", notification_id);
331 : 1 : valent_notification_set_id (notification, id_str);
332 : : }
333 : :
334 : 1 : valent_notifications_adapter_notification_added (adapter, notification);
335 : : }
336 : :
337 [ + - ]: 1 : return G_SOURCE_REMOVE;
338 : : }
339 : :
340 : : static GDBusMessage *
341 : 5 : valent_fdo_notifications_filter (GDBusConnection *connection,
342 : : GDBusMessage *message,
343 : : gboolean incoming,
344 : : gpointer user_data)
345 : : {
346 : 5 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
347 : 5 : GDBusMessageType message_type;
348 : :
349 [ - + ]: 5 : g_assert (VALENT_IS_FDO_NOTIFICATIONS (self));
350 : :
351 : 5 : message_type = g_dbus_message_get_message_type (message);
352 [ + + ]: 5 : if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN)
353 : : {
354 : 4 : uint32_t reply_serial;
355 : 4 : gboolean pending;
356 : :
357 : 4 : reply_serial = g_dbus_message_get_reply_serial (message);
358 : 4 : valent_object_lock (VALENT_OBJECT (self));
359 : 8 : pending = g_hash_table_contains (self->pending,
360 : 4 : GUINT_TO_POINTER (reply_serial));
361 : 4 : valent_object_unlock (VALENT_OBJECT (self));
362 : :
363 [ + + ]: 4 : if (pending)
364 : : {
365 : 6 : g_autoptr (GTask) task = NULL;
366 : :
367 : 1 : task = g_task_new (self, NULL, NULL, NULL);
368 [ + - ]: 1 : g_task_set_source_tag (task, valent_fdo_notifications_filter);
369 : 1 : g_task_set_task_data (task, g_object_ref (message), g_object_unref);
370 : :
371 [ + - ]: 1 : g_main_context_invoke_full (NULL,
372 : : g_task_get_priority (task),
373 : : valent_fdo_notifications_filter_main,
374 : : g_object_ref (task),
375 : : g_object_unref);
376 : : }
377 : : }
378 : :
379 : 5 : return message;
380 : : }
381 : :
382 : : static void
383 : 1 : on_notification_closed (GDBusConnection *connection,
384 : : const char *sender_name,
385 : : const char *object_path,
386 : : const char *interface_name,
387 : : const char *signal_name,
388 : : GVariant *parameters,
389 : : gpointer user_data)
390 : : {
391 : 1 : ValentNotificationsAdapter *adapter = VALENT_NOTIFICATIONS_ADAPTER (user_data);
392 : :
393 [ - + ]: 1 : g_assert (VALENT_IS_NOTIFICATIONS_ADAPTER (adapter));
394 [ + - ]: 1 : g_assert (g_strcmp0 (signal_name, "NotificationClosed") == 0);
395 : :
396 : 1 : _notification_closed (adapter, parameters);
397 : 1 : }
398 : :
399 : : /*
400 : : * Setup
401 : : */
402 : : static void
403 : 1 : on_name_appeared (GDBusConnection *connection,
404 : : const char *name,
405 : : const char *name_owner,
406 : : gpointer user_data)
407 : : {
408 : 1 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
409 : :
410 [ - + ]: 1 : self->name_owner = g_strdup (name_owner);
411 : 1 : g_set_object (&self->session, connection);
412 : :
413 [ + - ]: 1 : if (self->closed_id == 0)
414 : : {
415 : 1 : self->closed_id =
416 : 1 : g_dbus_connection_signal_subscribe (self->session,
417 : : "org.freedesktop.Notifications",
418 : : "org.freedesktop.Notifications",
419 : : "NotificationClosed",
420 : : "/org/freedesktop/Notifications",
421 : : NULL,
422 : : G_DBUS_SIGNAL_FLAGS_NONE,
423 : : on_notification_closed,
424 : : self, NULL);
425 : : }
426 : :
427 [ + - ]: 1 : if (self->filter_id == 0)
428 : : {
429 : 1 : g_dbus_connection_add_filter (self->monitor,
430 : : valent_fdo_notifications_filter,
431 : : self,
432 : : NULL);
433 : : }
434 : :
435 : 1 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
436 : : VALENT_PLUGIN_STATE_ACTIVE,
437 : : NULL);
438 : 1 : }
439 : :
440 : : static void
441 : 0 : on_name_vanished (GDBusConnection *connection,
442 : : const char *name,
443 : : gpointer user_data)
444 : : {
445 : 0 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
446 : :
447 [ # # ]: 0 : g_clear_pointer (&self->name_owner, g_free);
448 : :
449 [ # # ]: 0 : if (self->closed_id > 0)
450 : : {
451 : 0 : g_dbus_connection_signal_unsubscribe (self->session, self->closed_id);
452 : 0 : self->closed_id = 0;
453 : : }
454 : :
455 [ # # ]: 0 : if (self->filter_id > 0)
456 : : {
457 : 0 : g_dbus_connection_remove_filter (self->session, self->filter_id);
458 : 0 : self->filter_id = 0;
459 : : }
460 : :
461 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
462 : : VALENT_PLUGIN_STATE_INACTIVE,
463 : : NULL);
464 : 0 : }
465 : :
466 : : static void
467 : 1 : become_monitor_cb (GDBusConnection *connection,
468 : : GAsyncResult *result,
469 : : gpointer user_data)
470 : : {
471 : 1 : g_autoptr (GTask) task = G_TASK (user_data);
472 : 1 : ValentFdoNotifications *self = g_task_get_source_object (task);
473 [ - - + - ]: 1 : g_autoptr (GVariant) reply = NULL;
474 [ - - ]: 1 : g_autoptr (GError) error = NULL;
475 : :
476 : 1 : reply = g_dbus_connection_call_finish (connection, result, &error);
477 : :
478 [ - + ]: 1 : if (reply == NULL)
479 : : {
480 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
481 : : VALENT_PLUGIN_STATE_ERROR,
482 : : error);
483 [ # # ]: 0 : g_clear_object (&self->monitor);
484 : 0 : g_dbus_error_strip_remote_error (error);
485 [ # # ]: 0 : return g_task_return_error (task, g_steal_pointer (&error));
486 : : }
487 : :
488 : : /* Watch the true name owner */
489 : 1 : self->name_owner_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
490 : : "org.freedesktop.Notifications",
491 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
492 : : on_name_appeared,
493 : : on_name_vanished,
494 : : self, NULL);
495 : :
496 : :
497 : : /* Report the adapter as active */
498 : 1 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
499 : : VALENT_PLUGIN_STATE_ACTIVE,
500 : : NULL);
501 [ - + ]: 1 : g_task_return_boolean (task, TRUE);
502 : : }
503 : :
504 : : static void
505 : 1 : new_for_address_cb (GObject *object,
506 : : GAsyncResult *result,
507 : : gpointer user_data)
508 : : {
509 : 1 : g_autoptr (GTask) task = G_TASK (user_data);
510 : 1 : ValentFdoNotifications *self = g_task_get_source_object (task);
511 : 1 : GCancellable *cancellable = g_task_get_cancellable (task);
512 [ - - ]: 1 : g_autoptr (GError) error = NULL;
513 : :
514 : 1 : self->monitor = g_dbus_connection_new_for_address_finish (result, &error);
515 : :
516 [ - + ]: 1 : if (self->monitor == NULL)
517 : : {
518 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
519 : : VALENT_PLUGIN_STATE_ERROR,
520 : : error);
521 : 0 : g_dbus_error_strip_remote_error (error);
522 : 0 : return g_task_return_error (task, g_steal_pointer (&error));
523 : : }
524 : :
525 : : /* Export the monitor interface */
526 : 2 : self->monitor_id =
527 : 1 : g_dbus_connection_register_object (self->monitor,
528 : : "/org/freedesktop/Notifications",
529 : : self->iface_info,
530 : 1 : &self->vtable,
531 : : self, NULL,
532 : : &error);
533 : :
534 [ - + ]: 1 : if (self->monitor_id == 0)
535 : : {
536 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
537 : : VALENT_PLUGIN_STATE_ERROR,
538 : : error);
539 [ # # ]: 0 : g_clear_object (&self->monitor);
540 : 0 : g_dbus_error_strip_remote_error (error);
541 : 0 : return g_task_return_error (task, g_steal_pointer (&error));
542 : : }
543 : :
544 : : /* Become a monitor for notifications */
545 [ - + ]: 1 : g_dbus_connection_call (self->monitor,
546 : : "org.freedesktop.DBus",
547 : : "/org/freedesktop/DBus",
548 : : "org.freedesktop.DBus.Monitoring",
549 : : "BecomeMonitor",
550 : : g_variant_new ("(^asu)", interface_matches, 0),
551 : : NULL,
552 : : G_DBUS_CALL_FLAGS_NONE,
553 : : -1,
554 : : cancellable,
555 : : (GAsyncReadyCallback)become_monitor_cb,
556 : : g_steal_pointer (&task));
557 : : }
558 : :
559 : :
560 : : /*
561 : : * GAsyncInitable
562 : : */
563 : : static void
564 : 1 : valent_fdo_notifications_init_async (GAsyncInitable *initable,
565 : : int io_priority,
566 : : GCancellable *cancellable,
567 : : GAsyncReadyCallback callback,
568 : : gpointer user_data)
569 : : {
570 : 1 : g_autoptr (GTask) task = NULL;
571 [ - - ]: 1 : g_autofree char *address = NULL;
572 : 1 : g_autoptr (GError) error = NULL;
573 : :
574 [ - + ]: 1 : g_assert (VALENT_IS_FDO_NOTIFICATIONS (initable));
575 : :
576 : 1 : task = g_task_new (initable, cancellable, callback, user_data);
577 : 1 : g_task_set_priority (task, io_priority);
578 [ + - ]: 1 : g_task_set_source_tag (task, valent_fdo_notifications_init_async);
579 : :
580 : : /* Get a bus address */
581 : 1 : address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION,
582 : : cancellable,
583 : : &error);
584 : :
585 [ - + ]: 1 : if (address == NULL)
586 : : {
587 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (initable),
588 : : VALENT_PLUGIN_STATE_ERROR,
589 : : error);
590 [ # # ]: 0 : return g_task_return_error (task, g_steal_pointer (&error));
591 : : }
592 : :
593 : : /* Get a dedicated connection for monitoring */
594 [ - + ]: 1 : g_dbus_connection_new_for_address (address,
595 : : G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
596 : : G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
597 : : NULL,
598 : : cancellable,
599 : : (GAsyncReadyCallback)new_for_address_cb,
600 : : g_steal_pointer (&task));
601 : : }
602 : :
603 : : static void
604 : 2 : g_async_initable_iface_init (GAsyncInitableIface *iface)
605 : : {
606 : 2 : iface->init_async = valent_fdo_notifications_init_async;
607 : 2 : }
608 : :
609 : : /*
610 : : * ValentObject
611 : : */
612 : : static void
613 : 2 : valent_fdo_notifications_destroy (ValentObject *object)
614 : : {
615 : 2 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (object);
616 : :
617 [ + + ]: 2 : if (self->closed_id > 0)
618 : : {
619 : 1 : g_dbus_connection_signal_unsubscribe (self->session, self->closed_id);
620 : 1 : self->closed_id = 0;
621 : : }
622 : :
623 [ - + ]: 2 : if (self->filter_id > 0)
624 : : {
625 : 0 : g_dbus_connection_remove_filter (self->session, self->filter_id);
626 : 0 : self->filter_id = 0;
627 : : }
628 : :
629 [ + + ]: 2 : if (self->name_owner_id > 0)
630 : : {
631 : 1 : g_clear_handle_id (&self->name_owner_id, g_bus_unwatch_name);
632 [ + - ]: 1 : g_clear_pointer (&self->name_owner, g_free);
633 : : }
634 : :
635 [ + + ]: 2 : if (self->monitor_id != 0)
636 : : {
637 : 1 : g_dbus_connection_unregister_object (self->monitor, self->monitor_id);
638 : 1 : self->monitor_id = 0;
639 : : }
640 : :
641 [ + + ]: 2 : g_clear_object (&self->monitor);
642 [ + + ]: 2 : g_clear_object (&self->session);
643 : :
644 : 2 : VALENT_OBJECT_CLASS (valent_fdo_notifications_parent_class)->destroy (object);
645 : 2 : }
646 : :
647 : : /*
648 : : * GObject
649 : : */
650 : : static void
651 : 1 : valent_fdo_notifications_finalize (GObject *object)
652 : : {
653 : 1 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (object);
654 : :
655 : 1 : valent_object_lock (VALENT_OBJECT (self));
656 [ + - ]: 1 : g_clear_pointer (&self->node_info, g_dbus_node_info_unref);
657 [ + - ]: 1 : g_clear_pointer (&self->pending, g_hash_table_unref);
658 : 1 : valent_object_unlock (VALENT_OBJECT (self));
659 : :
660 : 1 : G_OBJECT_CLASS (valent_fdo_notifications_parent_class)->finalize (object);
661 : 1 : }
662 : :
663 : : static void
664 : 2 : valent_fdo_notifications_class_init (ValentFdoNotificationsClass *klass)
665 : : {
666 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
667 : 2 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
668 : :
669 : 2 : object_class->finalize = valent_fdo_notifications_finalize;
670 : :
671 : 2 : vobject_class->destroy = valent_fdo_notifications_destroy;
672 : : }
673 : :
674 : : static void
675 : 1 : valent_fdo_notifications_init (ValentFdoNotifications *self)
676 : : {
677 : 1 : self->node_info = g_dbus_node_info_new_for_xml (interface_xml, NULL);
678 : 1 : self->iface_info = self->node_info->interfaces[0];
679 : :
680 : 1 : self->vtable.method_call = valent_fdo_notifications_method_call;
681 : 1 : self->vtable.get_property = NULL;
682 : 1 : self->vtable.set_property = NULL;
683 : :
684 : 1 : valent_object_lock (VALENT_OBJECT (self));
685 : 1 : self->pending = g_hash_table_new_full (NULL,
686 : : NULL,
687 : : NULL,
688 : : g_object_unref);
689 : 1 : valent_object_unlock (VALENT_OBJECT (self));
690 : 1 : }
691 : :
|