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 *active;
23 : : GHashTable *pending;
24 : : GDBusConnection *monitor;
25 : : unsigned int monitor_id;
26 : : char *name_owner;
27 : : unsigned int name_owner_id;
28 : : unsigned int filter_id;
29 : : };
30 : :
31 : : static void g_async_initable_iface_init (GAsyncInitableIface *iface);
32 : :
33 [ + + + - ]: 16 : G_DEFINE_FINAL_TYPE_WITH_CODE (ValentFdoNotifications, valent_fdo_notifications, VALENT_TYPE_NOTIFICATIONS_ADAPTER,
34 : : G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, g_async_initable_iface_init))
35 : :
36 : :
37 : : /*
38 : : * Map of notification-spec urgency to GNotificationPriority
39 : : *
40 : : * See: https://developer-old.gnome.org/notification-spec/#urgency-levels
41 : : */
42 : : static const unsigned int urgencies[] = {
43 : : G_NOTIFICATION_PRIORITY_LOW,
44 : : G_NOTIFICATION_PRIORITY_NORMAL,
45 : : G_NOTIFICATION_PRIORITY_URGENT
46 : : };
47 : :
48 : :
49 : : /*
50 : : * GDBusInterfaceSkeleton
51 : : */
52 : : static const char *interface_matches[] = {
53 : : "interface='org.freedesktop.Notifications',member='Notify',type='method_call'",
54 : : "interface='org.freedesktop.Notifications',member='NotificationClosed',type='signal'",
55 : : "type='method_return'",
56 : : NULL
57 : : };
58 : :
59 : :
60 : : static GIcon *
61 : 1 : _g_icon_new_for_variant (GVariant *image_data)
62 : : {
63 : : #ifdef HAVE_GLYCIN
64 : 1 : int32_t width, height, rowstride;
65 : 1 : gboolean has_alpha;
66 : 1 : int32_t bits_per_sample, n_channels;
67 : 2 : g_autoptr (GVariant) data_variant = NULL;
68 [ + - ]: 1 : g_autoptr (GlyCreator) creator = NULL;
69 [ + - ]: 1 : g_autoptr (GlyNewFrame) frame = NULL;
70 [ + - ]: 1 : g_autoptr (GlyEncodedImage) image = NULL;
71 [ + - ]: 1 : g_autoptr (GBytes) texture = NULL;
72 [ + - ]: 1 : g_autoptr (GBytes) encoded = NULL;
73 [ + - ]: 1 : g_autoptr (GError) error = NULL;
74 : :
75 : 1 : g_variant_get (image_data, "(iiibii@ay)",
76 : : &width,
77 : : &height,
78 : : &rowstride,
79 : : &has_alpha,
80 : : &bits_per_sample,
81 : : &n_channels,
82 : : &data_variant);
83 : 1 : texture = g_bytes_new (g_variant_get_data (data_variant),
84 : : g_variant_get_size (data_variant));
85 : :
86 : 1 : creator = gly_creator_new ("image/png", &error);
87 [ - + ]: 1 : if (creator == NULL)
88 : : {
89 : 0 : g_warning ("%s(): Creating image: %s", G_STRFUNC, error->message);
90 : 0 : return NULL;
91 : : }
92 : :
93 : 1 : frame = gly_creator_add_frame_with_stride (creator,
94 : : width,
95 : : height,
96 : : rowstride,
97 : : has_alpha
98 [ + - ]: 1 : ? GLY_MEMORY_R8G8B8A8
99 : : : GLY_MEMORY_R8G8B8,
100 : : texture,
101 : : &error);
102 [ - + ]: 1 : if (frame == NULL)
103 : : {
104 : 0 : g_warning ("%s(): Adding frame: %s", G_STRFUNC, error->message);
105 : 0 : return NULL;
106 : : }
107 : :
108 : 1 : image = gly_creator_create (creator, &error);
109 [ - + ]: 1 : if (image == NULL)
110 : : {
111 : 0 : g_warning ("%s(): Encoding image: %s", G_STRFUNC, error->message);
112 : 0 : return NULL;
113 : : }
114 : :
115 : 1 : encoded = gly_encoded_image_get_data (image);
116 : :
117 : 1 : return g_bytes_icon_new (encoded);
118 : : #else
119 : : return NULL;
120 : : #endif /* HAVE_GLYCIN */
121 : : }
122 : :
123 : : static gboolean
124 : 2 : valent_fdo_notifications_notify_main (gpointer data)
125 : : {
126 : 2 : GTask *task = G_TASK (data);
127 : 2 : ValentFdoNotifications *self = g_task_get_source_object (task);
128 : 2 : GDBusMessage *message = g_task_get_task_data (task);
129 : 4 : g_autoptr (ValentNotification) notification = NULL;
130 : 2 : GVariant *parameters;
131 : 2 : const char *app_name;
132 : 2 : uint32_t replaces_id;
133 : 2 : const char *app_icon;
134 : 2 : const char *summary;
135 : 2 : const char *body;
136 [ + - ]: 2 : g_autoptr (GVariant) actions = NULL;
137 [ + - ]: 2 : g_autoptr (GVariant) hints = NULL;
138 : 2 : int32_t expire_timeout;
139 [ + - ]: 2 : g_autoptr (GVariant) image_data = NULL;
140 : 2 : const char *image_path;
141 [ + + ]: 2 : g_autoptr (GIcon) icon = NULL;
142 : 2 : unsigned char urgency;
143 [ + - ]: 2 : g_autofree char *id_str = NULL;
144 : 2 : uint32_t serial;
145 : :
146 [ - + ]: 2 : g_assert (VALENT_IS_MAIN_THREAD ());
147 : :
148 : 2 : parameters = g_dbus_message_get_body (message);
149 : 2 : g_variant_get (parameters, "(&su&s&s&s@as@a{sv}i)",
150 : : &app_name,
151 : : &replaces_id,
152 : : &app_icon,
153 : : &summary,
154 : : &body,
155 : : &actions,
156 : : &hints,
157 : : &expire_timeout);
158 : :
159 : : /* The notification ID hasn't been received yet,
160 : : * so use `replaces_id` for the new notification
161 : : */
162 : 2 : id_str = g_strdup_printf ("%u", replaces_id);
163 : :
164 : 2 : notification = valent_notification_new (NULL);
165 : 2 : valent_notification_set_id (notification, id_str);
166 : 2 : valent_notification_set_application (notification, app_name);
167 : 2 : valent_notification_set_title (notification, summary);
168 : 2 : valent_notification_set_body (notification, body);
169 : :
170 : : /* This ordering is required by the specification.
171 : : * See: https://specifications.freedesktop.org/notification-spec/latest/icons-and-images.html
172 : : */
173 [ + + - + ]: 3 : if (g_variant_lookup (hints, "image-data", "@(iiibiiay)", &image_data) ||
174 : 1 : g_variant_lookup (hints, "image_data", "@(iiibiiay)", &image_data))
175 : : {
176 : 1 : icon = _g_icon_new_for_variant (image_data);
177 : 1 : valent_notification_set_icon (notification, icon);
178 : : }
179 [ + - - + ]: 2 : else if (g_variant_lookup (hints, "image-path", "&s", &image_path) ||
180 : 1 : g_variant_lookup (hints, "image_path", "&s", &image_path))
181 : : {
182 : 0 : icon = g_icon_new_for_string (image_path, NULL);
183 : 0 : valent_notification_set_icon (notification, icon);
184 : : }
185 [ + - ]: 1 : else if (*app_icon != '\0')
186 : : {
187 : 1 : icon = g_icon_new_for_string (app_icon, NULL);
188 : 1 : valent_notification_set_icon (notification, icon);
189 : : }
190 [ # # ]: 0 : else if (g_variant_lookup (hints, "icon_data", "@(iiibiiay)", &image_data))
191 : : {
192 : 0 : icon = _g_icon_new_for_variant (image_data);
193 : 0 : valent_notification_set_icon (notification, icon);
194 : : }
195 : :
196 : : /* Map libnotify urgency to GNotification priority
197 : : */
198 [ + - + - ]: 2 : if (g_variant_lookup (hints, "urgency", "y", &urgency) && urgency < G_N_ELEMENTS (urgencies))
199 : 2 : valent_notification_set_priority (notification, urgencies[urgency]);
200 : : else
201 : 0 : valent_notification_set_priority (notification, G_NOTIFICATION_PRIORITY_NORMAL);
202 : :
203 : 2 : valent_notification_set_time (notification, valent_timestamp_ms ());
204 : :
205 : : /* Wait for the reply to get the correct notification ID
206 : : */
207 : 2 : serial = g_dbus_message_get_serial (message);
208 : 2 : g_hash_table_replace (self->pending,
209 : 2 : GUINT_TO_POINTER (serial),
210 : : g_object_ref (notification));
211 : 2 : g_task_return_boolean (task, TRUE);
212 : :
213 : 2 : return G_SOURCE_REMOVE;
214 : : }
215 : :
216 : : static gboolean
217 : 2 : valent_fdo_notifications_notify_return_main (gpointer data)
218 : : {
219 : 2 : GTask *task = G_TASK (data);
220 : 2 : ValentFdoNotifications *self = g_task_get_source_object (task);
221 : 2 : ValentNotificationsAdapter *adapter = g_task_get_source_object (task);
222 : 2 : GDBusMessage *message = g_task_get_task_data (task);
223 : 4 : g_autoptr (ValentNotification) notification = NULL;
224 : 2 : uint32_t reply_serial;
225 : 2 : GVariant *body = NULL;
226 : 2 : uint32_t id;
227 [ + - ]: 2 : g_autofree char *id_str = NULL;
228 : :
229 [ - + ]: 2 : g_assert (VALENT_IS_MAIN_THREAD ());
230 : :
231 : 2 : reply_serial = g_dbus_message_get_reply_serial (message);
232 [ - + ]: 2 : if (!g_hash_table_steal_extended (self->pending,
233 : 2 : GUINT_TO_POINTER (reply_serial),
234 : : NULL,
235 : : (void **)¬ification))
236 : : {
237 : 0 : g_task_return_boolean (task, TRUE);
238 : 0 : return G_SOURCE_REMOVE;
239 : : }
240 : :
241 : 2 : body = g_dbus_message_get_body (message);
242 : 2 : g_variant_get (body, "(u)", &id);
243 : 2 : id_str = g_strdup_printf ("%u", id);
244 : 2 : valent_notification_set_id (notification, id_str);
245 : :
246 : 4 : g_hash_table_replace (self->active,
247 : 2 : (char *)valent_notification_get_id (notification),
248 : : g_object_ref (notification));
249 : 2 : valent_notifications_adapter_notification_added (adapter, notification);
250 : :
251 : 2 : g_task_return_boolean (task, TRUE);
252 : :
253 : 2 : return G_SOURCE_REMOVE;
254 : : }
255 : :
256 : : static gboolean
257 : 2 : valent_fdo_notifications_notification_closed_main (gpointer data)
258 : : {
259 : 2 : GTask *task = G_TASK (data);
260 : 2 : ValentFdoNotifications *self = g_task_get_source_object (task);
261 : 2 : ValentNotificationsAdapter *adapter = g_task_get_source_object (task);
262 : 2 : GDBusMessage *message = g_task_get_task_data (task);
263 : 4 : g_autoptr (ValentNotification) notification = NULL;
264 : 2 : uint32_t id, reason;
265 : 2 : GVariant *body = NULL;
266 [ + - ]: 2 : g_autofree char *id_str = NULL;
267 : :
268 [ - + ]: 2 : g_assert (VALENT_IS_MAIN_THREAD ());
269 : :
270 : 2 : body = g_dbus_message_get_body (message);
271 : 2 : g_variant_get (body, "(uu)", &id, &reason);
272 : 2 : id_str = g_strdup_printf ("%u", id);
273 : :
274 [ + - ]: 2 : if (g_hash_table_steal_extended (self->active,
275 : : id_str,
276 : : NULL,
277 : : (void **)¬ification))
278 : : {
279 : 2 : valent_notifications_adapter_notification_removed (adapter, notification);
280 : : }
281 : :
282 : 2 : g_task_return_boolean (task, TRUE);
283 : :
284 : 2 : return G_SOURCE_REMOVE;
285 : : }
286 : :
287 : : static GDBusMessage *
288 : 9 : valent_fdo_notifications_filter (GDBusConnection *connection,
289 : : GDBusMessage *message,
290 : : gboolean incoming,
291 : : gpointer user_data)
292 : : {
293 : 9 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
294 : 9 : GDBusMessageType message_type = G_DBUS_MESSAGE_TYPE_INVALID;
295 : 9 : GSourceFunc dispatch_func = NULL;
296 : :
297 [ - + ]: 9 : g_assert (VALENT_IS_FDO_NOTIFICATIONS (self));
298 : :
299 : 9 : message_type = g_dbus_message_get_message_type (message);
300 [ + + ]: 9 : if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
301 : : {
302 : 2 : const char *member;
303 : :
304 : 2 : member = g_dbus_message_get_member (message);
305 [ + - ]: 2 : if (g_strcmp0 (member, "Notify") == 0)
306 : : {
307 : 2 : const char *destination;
308 : :
309 : 2 : valent_object_lock (VALENT_OBJECT (self));
310 : 2 : destination = g_dbus_message_get_destination (message);
311 [ - + - - ]: 2 : if (g_strcmp0 (destination, "org.freedesktop.Notifications") == 0 ||
312 : 0 : g_strcmp0 (destination, self->name_owner) == 0)
313 : : {
314 : : dispatch_func = valent_fdo_notifications_notify_main;
315 : : }
316 : 2 : valent_object_unlock (VALENT_OBJECT (self));
317 : : }
318 : : }
319 [ + + ]: 7 : else if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN)
320 : : {
321 : 5 : const char *signature;
322 : :
323 : : /* NOTE: The method return will have no member name, but checking
324 : : * the signature avoids unnecessary locking
325 : : */
326 : 5 : signature = g_dbus_message_get_signature (message);
327 [ + + ]: 5 : if (g_str_equal (signature, "u"))
328 : : {
329 : 2 : const char *sender = NULL;
330 : :
331 : 2 : valent_object_lock (VALENT_OBJECT (self));
332 : 2 : sender = g_dbus_message_get_sender (message);
333 [ + - + - ]: 4 : if (g_strcmp0 (sender, "org.freedesktop.Notifications") == 0 ||
334 : 2 : g_strcmp0 (sender, self->name_owner) == 0)
335 : : {
336 : : dispatch_func = valent_fdo_notifications_notify_return_main;
337 : : }
338 : 2 : valent_object_unlock (VALENT_OBJECT (self));
339 : : }
340 : : }
341 [ + - ]: 2 : else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
342 : : {
343 : 2 : const char *member;
344 : :
345 : : /* NOTE: If a proxy daemon is running (i.e. GNOME Shell),
346 : : * NotificationClosed is not re-emitted by the name owner
347 : : */
348 : 2 : member = g_dbus_message_get_member (message);
349 [ + - ]: 2 : if (g_strcmp0 (member, "NotificationClosed") == 0)
350 : : {
351 : 11 : g_autoptr (GTask) task = NULL;
352 : :
353 : 2 : task = g_task_new (self, NULL, NULL, NULL);
354 [ + - ]: 2 : g_task_set_source_tag (task, valent_fdo_notifications_notification_closed_main);
355 : 2 : g_task_set_task_data (task, g_object_ref (message), g_object_unref);
356 : :
357 [ + - ]: 2 : g_idle_add_full (g_task_get_priority (task),
358 : : valent_fdo_notifications_notification_closed_main,
359 : : g_object_ref (task),
360 : : g_object_unref);
361 : : }
362 : : }
363 : :
364 [ + - ]: 4 : if (dispatch_func != NULL)
365 : : {
366 : 13 : g_autoptr (GTask) task = NULL;
367 : :
368 : 4 : task = g_task_new (self, NULL, NULL, NULL);
369 [ + - ]: 4 : g_task_set_source_tag (task, dispatch_func);
370 : 4 : g_task_set_task_data (task, g_object_ref (message), g_object_unref);
371 : :
372 [ + - ]: 4 : g_idle_add_full (g_task_get_priority (task),
373 : : dispatch_func,
374 : : g_object_ref (task),
375 : : g_object_unref);
376 : : }
377 : :
378 : 9 : g_object_unref (message);
379 : 9 : return NULL;
380 : : }
381 : :
382 : : /*
383 : : * Setup
384 : : */
385 : : static void
386 : 1 : on_name_appeared (GDBusConnection *connection,
387 : : const char *name,
388 : : const char *name_owner,
389 : : gpointer user_data)
390 : : {
391 : 1 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
392 : :
393 : 1 : valent_object_lock (VALENT_OBJECT (self));
394 : 1 : g_set_str (&self->name_owner, name_owner);
395 : 1 : valent_object_unlock (VALENT_OBJECT (self));
396 : :
397 [ + - ]: 1 : if (self->filter_id == 0)
398 : : {
399 : 1 : self->filter_id =
400 : 1 : g_dbus_connection_add_filter (self->monitor,
401 : : valent_fdo_notifications_filter,
402 : : g_object_ref (self),
403 : : g_object_unref);
404 : : }
405 : :
406 : 1 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
407 : : VALENT_PLUGIN_STATE_ACTIVE,
408 : : NULL);
409 : 1 : }
410 : :
411 : : static void
412 : 0 : on_name_vanished (GDBusConnection *connection,
413 : : const char *name,
414 : : gpointer user_data)
415 : : {
416 : 0 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (user_data);
417 : :
418 : 0 : valent_object_lock (VALENT_OBJECT (self));
419 [ # # ]: 0 : g_clear_pointer (&self->name_owner, g_free);
420 : 0 : valent_object_unlock (VALENT_OBJECT (self));
421 : :
422 [ # # ]: 0 : if (self->filter_id > 0)
423 : : {
424 : 0 : g_dbus_connection_remove_filter (self->monitor, self->filter_id);
425 : 0 : self->filter_id = 0;
426 : : }
427 : :
428 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
429 : : VALENT_PLUGIN_STATE_INACTIVE,
430 : : NULL);
431 : 0 : }
432 : :
433 : : static void
434 : 1 : become_monitor_cb (GDBusConnection *connection,
435 : : GAsyncResult *result,
436 : : gpointer user_data)
437 : : {
438 : 1 : g_autoptr (GTask) task = G_TASK (user_data);
439 : 1 : ValentFdoNotifications *self = g_task_get_source_object (task);
440 [ - - + - ]: 1 : g_autoptr (GVariant) reply = NULL;
441 [ - - ]: 1 : g_autoptr (GError) error = NULL;
442 : :
443 : 1 : reply = g_dbus_connection_call_finish (connection, result, &error);
444 [ - + ]: 1 : if (reply == NULL)
445 : : {
446 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
447 : : VALENT_PLUGIN_STATE_ERROR,
448 : : error);
449 [ # # ]: 0 : g_clear_object (&self->monitor);
450 : 0 : g_dbus_error_strip_remote_error (error);
451 : 0 : g_task_return_error (task, g_steal_pointer (&error));
452 [ # # ]: 0 : return;
453 : : }
454 : :
455 : 1 : self->name_owner_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
456 : : "org.freedesktop.Notifications",
457 : : G_BUS_NAME_WATCHER_FLAGS_NONE,
458 : : on_name_appeared,
459 : : on_name_vanished,
460 : : self, NULL);
461 : :
462 [ - + ]: 1 : g_task_return_boolean (task, TRUE);
463 : : }
464 : :
465 : : static void
466 : 1 : new_for_address_cb (GObject *object,
467 : : GAsyncResult *result,
468 : : gpointer user_data)
469 : : {
470 : 1 : g_autoptr (GTask) task = G_TASK (user_data);
471 : 1 : ValentFdoNotifications *self = g_task_get_source_object (task);
472 : 1 : GCancellable *cancellable = g_task_get_cancellable (task);
473 [ - - ]: 1 : g_autoptr (GError) error = NULL;
474 : :
475 : 1 : self->monitor = g_dbus_connection_new_for_address_finish (result, &error);
476 [ - + ]: 1 : if (self->monitor == NULL)
477 : : {
478 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (self),
479 : : VALENT_PLUGIN_STATE_ERROR,
480 : : error);
481 : 0 : g_dbus_error_strip_remote_error (error);
482 : 0 : g_task_return_error (task, g_steal_pointer (&error));
483 [ # # ]: 0 : return;
484 : : }
485 : :
486 : : /* Register as a monitor
487 : : */
488 [ - + ]: 1 : g_dbus_connection_call (self->monitor,
489 : : "org.freedesktop.DBus",
490 : : "/org/freedesktop/DBus",
491 : : "org.freedesktop.DBus.Monitoring",
492 : : "BecomeMonitor",
493 : : g_variant_new ("(^asu)", interface_matches, 0),
494 : : NULL,
495 : : G_DBUS_CALL_FLAGS_NONE,
496 : : -1,
497 : : cancellable,
498 : : (GAsyncReadyCallback)become_monitor_cb,
499 : : g_steal_pointer (&task));
500 : : }
501 : :
502 : :
503 : : /*
504 : : * GAsyncInitable
505 : : */
506 : : static void
507 : 1 : valent_fdo_notifications_init_async (GAsyncInitable *initable,
508 : : int io_priority,
509 : : GCancellable *cancellable,
510 : : GAsyncReadyCallback callback,
511 : : gpointer user_data)
512 : : {
513 : 1 : g_autoptr (GTask) task = NULL;
514 [ - - ]: 1 : g_autofree char *address = NULL;
515 : 1 : g_autoptr (GError) error = NULL;
516 : :
517 [ - + ]: 1 : g_assert (VALENT_IS_FDO_NOTIFICATIONS (initable));
518 : :
519 : 1 : task = g_task_new (initable, cancellable, callback, user_data);
520 : 1 : g_task_set_priority (task, io_priority);
521 [ + - ]: 1 : g_task_set_source_tag (task, valent_fdo_notifications_init_async);
522 : :
523 : : /* Get a bus address and dedicated monitoring connection
524 : : */
525 : 1 : address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SESSION,
526 : : cancellable,
527 : : &error);
528 [ - + ]: 1 : if (address == NULL)
529 : : {
530 : 0 : valent_extension_plugin_state_changed (VALENT_EXTENSION (initable),
531 : : VALENT_PLUGIN_STATE_ERROR,
532 : : error);
533 : 0 : g_dbus_error_strip_remote_error (error);
534 : 0 : g_task_return_error (task, g_steal_pointer (&error));
535 [ # # ]: 0 : return;
536 : : }
537 : :
538 [ - + ]: 1 : g_dbus_connection_new_for_address (address,
539 : : G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
540 : : G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
541 : : NULL,
542 : : cancellable,
543 : : (GAsyncReadyCallback)new_for_address_cb,
544 : : g_steal_pointer (&task));
545 : : }
546 : :
547 : : static void
548 : 2 : g_async_initable_iface_init (GAsyncInitableIface *iface)
549 : : {
550 : 2 : iface->init_async = valent_fdo_notifications_init_async;
551 : 2 : }
552 : :
553 : : /*
554 : : * ValentObject
555 : : */
556 : : static void
557 : 0 : valent_fdo_notifications_destroy (ValentObject *object)
558 : : {
559 : 0 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (object);
560 : :
561 [ # # ]: 0 : if (self->filter_id > 0)
562 : : {
563 : 0 : g_dbus_connection_remove_filter (self->monitor, self->filter_id);
564 : 0 : self->filter_id = 0;
565 : : }
566 : :
567 [ # # ]: 0 : if (self->name_owner_id > 0)
568 : : {
569 : 0 : g_clear_handle_id (&self->name_owner_id, g_bus_unwatch_name);
570 : 0 : valent_object_lock (VALENT_OBJECT (self));
571 [ # # ]: 0 : g_clear_pointer (&self->name_owner, g_free);
572 : 0 : valent_object_unlock (VALENT_OBJECT (self));
573 : : }
574 : :
575 [ # # ]: 0 : if (self->monitor_id != 0)
576 : : {
577 : 0 : g_dbus_connection_unregister_object (self->monitor, self->monitor_id);
578 : 0 : self->monitor_id = 0;
579 : : }
580 : :
581 [ # # ]: 0 : g_clear_object (&self->monitor);
582 : :
583 : 0 : VALENT_OBJECT_CLASS (valent_fdo_notifications_parent_class)->destroy (object);
584 : 0 : }
585 : :
586 : : /*
587 : : * GObject
588 : : */
589 : : static void
590 : 0 : valent_fdo_notifications_finalize (GObject *object)
591 : : {
592 : 0 : ValentFdoNotifications *self = VALENT_FDO_NOTIFICATIONS (object);
593 : :
594 [ # # ]: 0 : g_clear_pointer (&self->active, g_hash_table_unref);
595 [ # # ]: 0 : g_clear_pointer (&self->pending, g_hash_table_unref);
596 : :
597 : 0 : G_OBJECT_CLASS (valent_fdo_notifications_parent_class)->finalize (object);
598 : 0 : }
599 : :
600 : : static void
601 : 2 : valent_fdo_notifications_class_init (ValentFdoNotificationsClass *klass)
602 : : {
603 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
604 : 2 : ValentObjectClass *vobject_class = VALENT_OBJECT_CLASS (klass);
605 : :
606 : 2 : object_class->finalize = valent_fdo_notifications_finalize;
607 : :
608 : 2 : vobject_class->destroy = valent_fdo_notifications_destroy;
609 : : }
610 : :
611 : : static void
612 : 1 : valent_fdo_notifications_init (ValentFdoNotifications *self)
613 : : {
614 : 1 : self->active = g_hash_table_new_full (g_str_hash,
615 : : g_str_equal,
616 : : NULL,
617 : : g_object_unref);
618 : 1 : self->pending = g_hash_table_new_full (NULL,
619 : : NULL,
620 : : NULL,
621 : : g_object_unref);
622 : 1 : }
623 : :
|