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-notifications"
5 : :
6 : : #include "config.h"
7 : :
8 : : #include <gio/gio.h>
9 : : #include <libvalent-core.h>
10 : :
11 : : #include "valent-notification.h"
12 : :
13 : : /**
14 : : * ValentNotification:
15 : : *
16 : : * A class representing a notification.
17 : : *
18 : : * `ValentNotification` is a derivable, generic class for a notification.
19 : : *
20 : : * Since: 1.0
21 : : */
22 : :
23 : : struct _ValentNotification
24 : : {
25 : : ValentObject parent_instance;
26 : :
27 : : char *application;
28 : : char *id;
29 : : char *body;
30 : : GIcon *icon;
31 : : int64_t time;
32 : : char *title;
33 : : char *default_action;
34 : : GVariant *default_action_target;
35 : : GPtrArray *buttons;
36 : : GNotificationPriority priority;
37 : : };
38 : :
39 : : typedef enum {
40 : : PROP_APPLICATION = 1,
41 : : PROP_BODY,
42 : : PROP_ICON,
43 : : PROP_ID,
44 : : PROP_PRIORITY,
45 : : PROP_TIME,
46 : : PROP_TITLE,
47 : : } ValentNotificationProperty;
48 : :
49 [ + + + - ]: 319 : G_DEFINE_FINAL_TYPE (ValentNotification, valent_notification, VALENT_TYPE_OBJECT)
50 : :
51 : : static GParamSpec *properties[PROP_TITLE + 1] = { NULL, };
52 : :
53 : :
54 : : /*
55 : : * Notification Buttons
56 : : */
57 : : typedef struct
58 : : {
59 : : char *label;
60 : : char *action;
61 : : GVariant *target;
62 : : } Button;
63 : :
64 : : static void
65 : 2 : notification_button_free (gpointer data)
66 : : {
67 : 2 : Button *button = data;
68 : :
69 [ + - ]: 2 : g_clear_pointer (&button->label, g_free);
70 [ + - ]: 2 : g_clear_pointer (&button->action, g_free);
71 [ + - ]: 2 : g_clear_pointer (&button->target, g_variant_unref);
72 : 2 : g_free (data);
73 : 2 : }
74 : :
75 : :
76 : : /*
77 : : * (De)serializing helpers
78 : : */
79 : : static GVariant *
80 : 1 : valent_notification_serialize_button (Button *button)
81 : : {
82 : 1 : GVariantBuilder builder;
83 : :
84 : 1 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
85 : :
86 : 1 : g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (button->label));
87 : 1 : g_variant_builder_add (&builder, "{sv}", "action", g_variant_new_string (button->action));
88 : :
89 [ + - ]: 1 : if (button->target)
90 : 1 : g_variant_builder_add (&builder, "{sv}", "target", button->target);
91 : :
92 : 1 : return g_variant_builder_end (&builder);
93 : : }
94 : :
95 : : static GVariant *
96 : 3 : valent_notification_get_priority_nick (ValentNotification *notification)
97 : : {
98 : 6 : g_autoptr (GEnumClass) enum_class = NULL;
99 : 3 : GEnumValue *enum_value;
100 : :
101 : 3 : enum_class = g_type_class_ref (G_TYPE_NOTIFICATION_PRIORITY);
102 : 3 : enum_value = g_enum_get_value (enum_class, notification->priority);
103 : :
104 [ - + ]: 3 : g_assert (enum_value != NULL);
105 : :
106 [ + - ]: 3 : return g_variant_new_string (enum_value->value_nick);
107 : : }
108 : :
109 : : static void
110 : 2 : valent_notification_set_priority_nick (ValentNotification *notification,
111 : : const char *nick)
112 : : {
113 : 4 : g_autoptr (GEnumClass) enum_class = NULL;
114 : 2 : GEnumValue *enum_value;
115 : :
116 : 2 : enum_class = g_type_class_ref (G_TYPE_NOTIFICATION_PRIORITY);
117 : 2 : enum_value = g_enum_get_value_by_nick (enum_class, nick);
118 : :
119 [ - + ]: 2 : g_assert (enum_value != NULL);
120 : :
121 [ + - ]: 2 : valent_notification_set_priority (notification, enum_value->value);
122 : 2 : }
123 : :
124 : :
125 : : /*
126 : : * GObject
127 : : */
128 : : static void
129 : 8 : valent_notification_finalize (GObject *object)
130 : : {
131 : 8 : ValentNotification *self = VALENT_NOTIFICATION (object);
132 : :
133 [ + + ]: 8 : g_clear_pointer (&self->application, g_free);
134 [ + - ]: 8 : g_clear_pointer (&self->id, g_free);
135 [ + + ]: 8 : g_clear_pointer (&self->body, g_free);
136 [ + - ]: 8 : g_clear_pointer (&self->title, g_free);
137 [ + + ]: 8 : g_clear_object (&self->icon);
138 : :
139 [ - + ]: 8 : g_clear_pointer (&self->default_action, g_free);
140 [ - + ]: 8 : g_clear_pointer (&self->default_action_target, g_variant_unref);
141 [ + - ]: 8 : g_clear_pointer (&self->buttons, g_ptr_array_unref);
142 : :
143 : 8 : G_OBJECT_CLASS (valent_notification_parent_class)->finalize (object);
144 : 8 : }
145 : :
146 : : static void
147 : 25 : valent_notification_get_property (GObject *object,
148 : : guint prop_id,
149 : : GValue *value,
150 : : GParamSpec *pspec)
151 : : {
152 : 25 : ValentNotification *self = VALENT_NOTIFICATION (object);
153 : :
154 [ + + + + : 25 : switch ((ValentNotificationProperty)prop_id)
+ + + - ]
155 : : {
156 : 4 : case PROP_APPLICATION:
157 : 4 : g_value_set_string (value, valent_notification_get_application (self));
158 : 4 : break;
159 : :
160 : 4 : case PROP_BODY:
161 : 4 : g_value_set_string (value, valent_notification_get_body (self));
162 : 4 : break;
163 : :
164 : 4 : case PROP_ID:
165 : 4 : g_value_set_string (value, valent_notification_get_id (self));
166 : 4 : break;
167 : :
168 : 4 : case PROP_ICON:
169 : 4 : g_value_set_object (value, valent_notification_get_icon (self));
170 : 4 : break;
171 : :
172 : 4 : case PROP_PRIORITY:
173 : 4 : g_value_set_enum (value, valent_notification_get_priority (self));
174 : 4 : break;
175 : :
176 : 1 : case PROP_TIME:
177 : 1 : g_value_set_int64 (value, valent_notification_get_time (self));
178 : 1 : break;
179 : :
180 : 4 : case PROP_TITLE:
181 : 4 : g_value_set_string (value, valent_notification_get_title (self));
182 : 4 : break;
183 : :
184 : 0 : default:
185 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
186 : : }
187 : 25 : }
188 : :
189 : : static void
190 : 22 : valent_notification_set_property (GObject *object,
191 : : guint prop_id,
192 : : const GValue *value,
193 : : GParamSpec *pspec)
194 : : {
195 : 22 : ValentNotification *self = VALENT_NOTIFICATION (object);
196 : :
197 [ + + + + : 22 : switch ((ValentNotificationProperty)prop_id)
+ + + - ]
198 : : {
199 : 3 : case PROP_APPLICATION:
200 : 3 : valent_notification_set_application (self, g_value_get_string (value));
201 : 3 : break;
202 : :
203 : 3 : case PROP_BODY:
204 : 3 : valent_notification_set_body (self, g_value_get_string(value));
205 : 3 : break;
206 : :
207 : 3 : case PROP_ICON:
208 : 3 : valent_notification_set_icon (self, g_value_get_object (value));
209 : 3 : break;
210 : :
211 : 5 : case PROP_ID:
212 : 5 : valent_notification_set_id (self, g_value_get_string (value));
213 : 5 : break;
214 : :
215 : 1 : case PROP_PRIORITY:
216 : 1 : valent_notification_set_priority (self, g_value_get_enum (value));
217 : 1 : break;
218 : :
219 : 2 : case PROP_TIME:
220 : 2 : valent_notification_set_time (self, g_value_get_int64 (value));
221 : 2 : break;
222 : :
223 : 5 : case PROP_TITLE:
224 : 5 : valent_notification_set_title (self, g_value_get_string (value));
225 : 5 : break;
226 : :
227 : 0 : default:
228 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
229 : : }
230 : 22 : }
231 : :
232 : : static void
233 : 9 : valent_notification_init (ValentNotification *notification)
234 : : {
235 : 9 : notification->id = g_uuid_string_random ();
236 : 9 : notification->buttons = g_ptr_array_new_full (3, notification_button_free);
237 : 9 : }
238 : :
239 : : static void
240 : 5 : valent_notification_class_init (ValentNotificationClass *klass)
241 : : {
242 : 5 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
243 : :
244 : 5 : object_class->finalize = valent_notification_finalize;
245 : 5 : object_class->get_property = valent_notification_get_property;
246 : 5 : object_class->set_property = valent_notification_set_property;
247 : :
248 : : /**
249 : : * ValentNotification:application: (getter get_application) (setter set_application)
250 : : *
251 : : * The notifying application.
252 : : *
253 : : * The semantics of this property are not well-defined. It may be the
254 : : * application name (i.e. the `appName` argument passed to
255 : : * `org.freedesktop.Notifications.Notify()`), the desktop application ID (i.e.
256 : : * from `org.gtk.Notifications.AddNotification()`) or some other identifying
257 : : * string.
258 : : *
259 : : * Since: 1.0
260 : : */
261 : 10 : properties [PROP_APPLICATION] =
262 : 5 : g_param_spec_string ("application", NULL, NULL,
263 : : NULL,
264 : : (G_PARAM_READWRITE |
265 : : G_PARAM_EXPLICIT_NOTIFY |
266 : : G_PARAM_STATIC_STRINGS));
267 : :
268 : : /**
269 : : * ValentNotification:body: (getter get_body) (setter set_body)
270 : : *
271 : : * The notification body.
272 : : *
273 : : * Since: 1.0
274 : : */
275 : 10 : properties [PROP_BODY] =
276 : 5 : g_param_spec_string ("body", NULL, NULL,
277 : : NULL,
278 : : (G_PARAM_READWRITE |
279 : : G_PARAM_EXPLICIT_NOTIFY |
280 : : G_PARAM_STATIC_STRINGS));
281 : :
282 : : /**
283 : : * ValentNotification:icon: (getter get_icon) (setter set_icon)
284 : : *
285 : : * The notification [iface@Gio.Icon].
286 : : *
287 : : * Since: 1.0
288 : : */
289 : 10 : properties [PROP_ICON] =
290 : 5 : g_param_spec_object ("icon", NULL, NULL,
291 : : G_TYPE_ICON,
292 : : (G_PARAM_READWRITE |
293 : : G_PARAM_EXPLICIT_NOTIFY |
294 : : G_PARAM_STATIC_STRINGS));
295 : :
296 : : /**
297 : : * ValentNotification:id: (getter get_id) (setter set_id)
298 : : *
299 : : * The unique ID of the notification.
300 : : *
301 : : * Since: 1.0
302 : : */
303 : 10 : properties [PROP_ID] =
304 : 5 : g_param_spec_string ("id", NULL, NULL,
305 : : NULL,
306 : : (G_PARAM_READWRITE |
307 : : G_PARAM_EXPLICIT_NOTIFY |
308 : : G_PARAM_STATIC_STRINGS));
309 : :
310 : : /**
311 : : * ValentNotification:priority: (getter get_priority) (setter set_priority)
312 : : *
313 : : * The notification priority.
314 : : *
315 : : * Since: 1.0
316 : : */
317 : 10 : properties [PROP_PRIORITY] =
318 : 5 : g_param_spec_enum ("priority", NULL, NULL,
319 : : G_TYPE_NOTIFICATION_PRIORITY,
320 : : G_NOTIFICATION_PRIORITY_NORMAL,
321 : : (G_PARAM_READWRITE |
322 : : G_PARAM_EXPLICIT_NOTIFY |
323 : : G_PARAM_STATIC_STRINGS));
324 : :
325 : : /**
326 : : * ValentNotification:time: (getter get_time) (setter set_time)
327 : : *
328 : : * The posting time of the notification in milliseconds.
329 : : *
330 : : * Since: 1.0
331 : : */
332 : 10 : properties [PROP_TIME] =
333 : 5 : g_param_spec_int64 ("time", NULL, NULL,
334 : : 0, G_MAXINT64,
335 : : 0,
336 : : (G_PARAM_READWRITE |
337 : : G_PARAM_EXPLICIT_NOTIFY |
338 : : G_PARAM_STATIC_STRINGS));
339 : :
340 : : /**
341 : : * ValentNotification:title: (getter get_title) (setter set_title)
342 : : *
343 : : * The title of the notification.
344 : : *
345 : : * Since: 1.0
346 : : */
347 : 10 : properties [PROP_TITLE] =
348 : 5 : g_param_spec_string ("title", NULL, NULL,
349 : : NULL,
350 : : (G_PARAM_READWRITE |
351 : : G_PARAM_EXPLICIT_NOTIFY |
352 : : G_PARAM_STATIC_STRINGS));
353 : :
354 : 5 : g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
355 : 5 : }
356 : :
357 : : /**
358 : : * valent_notification_new:
359 : : * @title: (nullable): a notification title
360 : : *
361 : : * Create a new `ValentNotification`.
362 : : *
363 : : * A notification without a title (or primary text) is not strictly possible,
364 : : * but this is allowed during construction for the case where it is more
365 : : * convenient to set it later.
366 : : *
367 : : * Returns: (transfer full): a `ValentNotification`
368 : : *
369 : : * Since: 1.0
370 : : */
371 : : ValentNotification *
372 : 5 : valent_notification_new (const char *title)
373 : : {
374 [ + - ]: 5 : if (title == NULL)
375 : 5 : return g_object_new (VALENT_TYPE_NOTIFICATION, NULL);
376 : : else
377 : 0 : return g_object_new (VALENT_TYPE_NOTIFICATION,
378 : : "title", title,
379 : : NULL);
380 : : }
381 : :
382 : : /**
383 : : * valent_notification_get_application: (get-property application)
384 : : * @notification: a `ValentNotification`
385 : : *
386 : : * Get the notifying application.
387 : : *
388 : : * Returns: (transfer none) (nullable): the notifying application name
389 : : *
390 : : * Since: 1.0
391 : : */
392 : : const char *
393 : 19 : valent_notification_get_application (ValentNotification *notification)
394 : : {
395 [ - + ]: 19 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), NULL);
396 : :
397 : 19 : return notification->application;
398 : : }
399 : :
400 : : /**
401 : : * valent_notification_set_application: (set-property application)
402 : : * @notification: a `ValentNotification`
403 : : * @application: (nullable): the notifying application
404 : : *
405 : : * Set the notifying application.
406 : : *
407 : : * Since: 1.0
408 : : */
409 : : void
410 : 7 : valent_notification_set_application (ValentNotification *notification,
411 : : const char *application)
412 : : {
413 [ - + ]: 7 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
414 : :
415 [ + - ]: 7 : if (g_set_str (¬ification->application, application))
416 : 7 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_APPLICATION]);
417 : : }
418 : :
419 : : /**
420 : : * valent_notification_get_body: (get-property body)
421 : : * @notification: a `ValentNotification`
422 : : *
423 : : * Get the notification body.
424 : : *
425 : : * Returns: (transfer none) (nullable): the notification body
426 : : *
427 : : * Since: 1.0
428 : : */
429 : : const char *
430 : 9 : valent_notification_get_body (ValentNotification *notification)
431 : : {
432 [ - + ]: 9 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), NULL);
433 : :
434 : 9 : return notification->body;
435 : : }
436 : :
437 : : /**
438 : : * valent_notification_set_body: (set-property body)
439 : : * @notification: a `ValentNotification`
440 : : * @body: (nullable): a notification body
441 : : *
442 : : * Set the notification body.
443 : : *
444 : : * Since: 1.0
445 : : */
446 : : void
447 : 8 : valent_notification_set_body (ValentNotification *notification,
448 : : const char *body)
449 : : {
450 [ - + ]: 8 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
451 : :
452 [ + - ]: 8 : if (g_set_str (¬ification->body, body))
453 : 8 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_BODY]);
454 : : }
455 : :
456 : : /**
457 : : * valent_notification_get_icon: (set-property icon)
458 : : * @notification: a `ValentNotification`
459 : : *
460 : : * Get the notification icon.
461 : : *
462 : : * Returns: (transfer none) (nullable): a `GIcon`
463 : : *
464 : : * Since: 1.0
465 : : */
466 : : GIcon *
467 : 14 : valent_notification_get_icon (ValentNotification *notification)
468 : : {
469 [ - + ]: 14 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), NULL);
470 : :
471 : 14 : return notification->icon;
472 : : }
473 : :
474 : : /**
475 : : * valent_notification_set_icon: (set-property icon)
476 : : * @notification: a `ValentNotification`
477 : : * @icon: (nullable): a `GIcon`
478 : : *
479 : : * Set the notification icon.
480 : : *
481 : : * Since: 1.0
482 : : */
483 : : void
484 : 10 : valent_notification_set_icon (ValentNotification *notification,
485 : : GIcon *icon)
486 : : {
487 [ - + ]: 10 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
488 [ + + + - : 10 : g_return_if_fail (icon == NULL || G_IS_ICON (icon));
+ - + - ]
489 : :
490 [ + + ]: 10 : if (g_icon_equal (notification->icon, icon))
491 : : return;
492 : :
493 : 9 : g_set_object (¬ification->icon, icon);
494 : 9 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_ICON]);
495 : : }
496 : :
497 : : /**
498 : : * valent_notification_get_id: (get-property id)
499 : : * @notification: a `ValentNotification`
500 : : *
501 : : * Get the notification ID.
502 : : *
503 : : * Returns: (transfer none) (not nullable): a unique ID
504 : : *
505 : : * Since: 1.0
506 : : */
507 : : const char *
508 : 17 : valent_notification_get_id (ValentNotification *notification)
509 : : {
510 [ - + ]: 17 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), NULL);
511 : :
512 : 17 : return notification->id;
513 : : }
514 : :
515 : : /**
516 : : * valent_notification_set_id: (set-property id)
517 : : * @notification: a `ValentNotification`
518 : : * @id: (not nullable): a unique ID
519 : : *
520 : : * Set the notification ID.
521 : : *
522 : : * Since: 1.0
523 : : */
524 : : void
525 : 12 : valent_notification_set_id (ValentNotification *notification,
526 : : const char *id)
527 : : {
528 [ - + ]: 12 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
529 [ + - + - ]: 12 : g_return_if_fail (id != NULL && *id != '\0');
530 : :
531 [ + + ]: 12 : if (g_set_str (¬ification->id, id))
532 : 11 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_ID]);
533 : : }
534 : :
535 : : /**
536 : : * valent_notification_get_priority:
537 : : * @notification: a `ValentNotification`
538 : : *
539 : : * Get the notification priority.
540 : : *
541 : : * Returns: a `GNotificationPriority`
542 : : *
543 : : * Since: 1.0
544 : : */
545 : : GNotificationPriority
546 : 4 : valent_notification_get_priority (ValentNotification *notification)
547 : : {
548 [ - + ]: 4 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), G_NOTIFICATION_PRIORITY_NORMAL);
549 : :
550 : 4 : return notification->priority;
551 : : }
552 : :
553 : : /**
554 : : * valent_notification_set_priority:
555 : : * @notification: a `ValentNotification`
556 : : * @priority: a `GNotificationPriority`
557 : : *
558 : : * Set the notification priority.
559 : : *
560 : : * Since: 1.0
561 : : */
562 : : void
563 : 5 : valent_notification_set_priority (ValentNotification *notification,
564 : : GNotificationPriority priority)
565 : : {
566 [ - + ]: 5 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
567 : :
568 [ + - ]: 5 : if (notification->priority == priority)
569 : : return;
570 : :
571 : 5 : notification->priority = priority;
572 : 5 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_PRIORITY]);
573 : : }
574 : :
575 : : /**
576 : : * valent_notification_get_time: (get-property time)
577 : : * @notification: a `ValentNotification`
578 : : *
579 : : * Get the notification time.
580 : : *
581 : : * Returns: a UNIX epoch timestamp (ms)
582 : : *
583 : : * Since: 1.0
584 : : */
585 : : int64_t
586 : 1 : valent_notification_get_time (ValentNotification *notification)
587 : : {
588 [ - + ]: 1 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), 0);
589 : :
590 : 1 : return notification->time;
591 : : }
592 : :
593 : : /**
594 : : * valent_notification_set_time: (set-property time)
595 : : * @notification: a `ValentNotification`
596 : : * @time: a UNIX epoch timestamp (ms)
597 : : *
598 : : * Set the notification time.
599 : : *
600 : : * Since: 1.0
601 : : */
602 : : void
603 : 5 : valent_notification_set_time (ValentNotification *notification,
604 : : int64_t time)
605 : : {
606 [ - + ]: 5 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
607 : :
608 [ + - ]: 5 : if (notification->time == time)
609 : : return;
610 : :
611 : 5 : notification->time = time;
612 : 5 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_TIME]);
613 : : }
614 : :
615 : : /**
616 : : * valent_notification_get_title: (get-property title)
617 : : * @notification: a `ValentNotification`
618 : : *
619 : : * Get the notification title.
620 : : *
621 : : * Returns: (transfer none) (nullable): the notification title
622 : : *
623 : : * Since: 1.0
624 : : */
625 : : const char *
626 : 9 : valent_notification_get_title (ValentNotification *notification)
627 : : {
628 [ - + ]: 9 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), NULL);
629 : :
630 : 9 : return notification->title;
631 : : }
632 : :
633 : : /**
634 : : * valent_notification_set_title: (set-property title)
635 : : * @notification: a `ValentNotification`
636 : : * @title: (nullable): a notification title
637 : : *
638 : : * Set the notification title.
639 : : *
640 : : * Since: 1.0
641 : : */
642 : : void
643 : 10 : valent_notification_set_title (ValentNotification *notification,
644 : : const char *title)
645 : : {
646 [ - + ]: 10 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
647 : :
648 [ + + ]: 10 : if (g_set_str (¬ification->title, title))
649 : 9 : g_object_notify_by_pspec (G_OBJECT (notification), properties [PROP_TITLE]);
650 : : }
651 : :
652 : : /**
653 : : * valent_notification_add_button:
654 : : * @notification: a `ValentNotification`
655 : : * @label: a button label
656 : : * @action: an action name
657 : : * @target: (nullable): an action target
658 : : *
659 : : * Add a notification button.
660 : : *
661 : : * If @target is %NULL, then @action may be a detailed action name.
662 : : *
663 : : * Since: 1.0
664 : : */
665 : : void
666 : 2 : valent_notification_add_button (ValentNotification *notification,
667 : : const char *label,
668 : : const char *action,
669 : : GVariant *target)
670 : : {
671 : 2 : Button *button;
672 : :
673 [ - + ]: 2 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
674 [ + - ]: 2 : g_return_if_fail (label != NULL);
675 [ + - ]: 2 : g_return_if_fail (action != NULL);
676 [ + + + - ]: 2 : g_return_if_fail (target == NULL || g_action_name_is_valid (action));
677 [ + - ]: 2 : g_return_if_fail (notification->buttons->len < 3);
678 : :
679 [ + + ]: 2 : if (target != NULL)
680 : : {
681 : 1 : button = g_new0 (Button, 1);
682 [ - + ]: 1 : button->label = g_strdup (label);
683 [ - + ]: 1 : button->action = g_strdup (action);
684 : :
685 : 1 : if (target)
686 : 1 : button->target = g_variant_ref_sink (target);
687 : : }
688 : : else
689 : : {
690 : 1 : g_autofree char *name = NULL;
691 : 1 : g_autoptr (GVariant) parameter = NULL;
692 [ - - + - ]: 1 : g_autoptr (GError) error = NULL;
693 : :
694 [ - + ]: 1 : if (!g_action_parse_detailed_name (action, &name, ¶meter, &error))
695 : : {
696 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
697 [ # # ]: 0 : return;
698 : : }
699 : :
700 : 1 : button = g_new0 (Button, 1);
701 [ - + ]: 1 : button->label = g_strdup (label);
702 [ - + ]: 1 : button->action = g_strdup (name);
703 : :
704 [ + - ]: 1 : if (parameter)
705 : 1 : button->target = g_variant_ref_sink (parameter);
706 : : }
707 : :
708 : 2 : g_ptr_array_add (notification->buttons, button);
709 : : }
710 : :
711 : : /**
712 : : * valent_notification_set_default_action:
713 : : * @notification: a `ValentNotification`
714 : : * @action: an action name
715 : : * @target: (nullable): a `GVariant` to use as @action's parameter
716 : : *
717 : : * Set the default notification action.
718 : : *
719 : : * If @target is %NULL, then @action may be a detailed action name.
720 : : *
721 : : * Since: 1.0
722 : : */
723 : : void
724 : 0 : valent_notification_set_default_action (ValentNotification *notification,
725 : : const char *action,
726 : : GVariant *target)
727 : : {
728 [ # # ]: 0 : g_return_if_fail (VALENT_IS_NOTIFICATION (notification));
729 [ # # ]: 0 : g_return_if_fail (action != NULL);
730 [ # # # # ]: 0 : g_return_if_fail (target == NULL || g_action_name_is_valid (action));
731 : :
732 [ # # ]: 0 : if (target != NULL)
733 : : {
734 : 0 : g_set_str (¬ification->default_action, action);
735 [ # # ]: 0 : g_clear_pointer (¬ification->default_action_target, g_variant_unref);
736 : :
737 : 0 : if (target)
738 : 0 : notification->default_action_target = g_variant_ref_sink (target);
739 : : }
740 : : else
741 : : {
742 : 0 : g_autofree char *name = NULL;
743 : 0 : g_autoptr (GVariant) parameter = NULL;
744 [ # # # # ]: 0 : g_autoptr (GError) error = NULL;
745 : :
746 [ # # ]: 0 : if (!g_action_parse_detailed_name (action, &name, ¶meter, &error))
747 : : {
748 : 0 : g_warning ("%s(): %s", G_STRFUNC, error->message);
749 [ # # ]: 0 : return;
750 : : }
751 : :
752 : 0 : g_set_str (¬ification->default_action, name);
753 [ # # ]: 0 : g_clear_pointer (¬ification->default_action_target, g_variant_unref);
754 : :
755 [ # # ]: 0 : if (parameter)
756 : 0 : notification->default_action_target = g_variant_ref_sink (target);
757 : : }
758 : : }
759 : :
760 : : /**
761 : : * valent_notification_serialize:
762 : : * @notification: a `ValentNotification`
763 : : *
764 : : * Serialize the notification into a variant of type `a{sv}`.
765 : : *
766 : : * Returns: (nullable): a floating `GVariant`
767 : : *
768 : : * Since: 1.0
769 : : */
770 : : GVariant *
771 : 3 : valent_notification_serialize (ValentNotification *notification)
772 : : {
773 : 3 : GVariantBuilder builder;
774 : :
775 [ - + ]: 3 : g_return_val_if_fail (VALENT_IS_NOTIFICATION (notification), NULL);
776 : :
777 : 3 : g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
778 : :
779 [ + - ]: 3 : if (notification->id)
780 : 3 : g_variant_builder_add (&builder, "{sv}", "id",
781 : : g_variant_new_string (notification->id));
782 : :
783 [ + - ]: 3 : if (notification->application)
784 : 3 : g_variant_builder_add (&builder, "{sv}", "application",
785 : : g_variant_new_string (notification->application));
786 : :
787 [ + - ]: 3 : if (notification->title)
788 : 3 : g_variant_builder_add (&builder, "{sv}", "title",
789 : : g_variant_new_string (notification->title));
790 : :
791 [ + - ]: 3 : if (notification->body)
792 : 3 : g_variant_builder_add (&builder, "{sv}", "body",
793 : : g_variant_new_string (notification->body));
794 : :
795 [ + + ]: 3 : if (notification->icon)
796 : : {
797 : 5 : g_autoptr (GVariant) serialized_icon = NULL;
798 : :
799 [ + - ]: 2 : if ((serialized_icon = g_icon_serialize (notification->icon)))
800 : 2 : g_variant_builder_add (&builder, "{sv}", "icon", serialized_icon);
801 : : }
802 : :
803 : 3 : g_variant_builder_add (&builder, "{sv}", "priority",
804 : : valent_notification_get_priority_nick (notification));
805 : :
806 [ - + ]: 3 : if (notification->default_action)
807 : : {
808 : 0 : g_variant_builder_add (&builder, "{sv}", "default-action",
809 : : g_variant_new_string (notification->default_action));
810 : :
811 [ # # ]: 0 : if (notification->default_action_target)
812 : 0 : g_variant_builder_add (&builder, "{sv}", "default-action-target",
813 : : notification->default_action_target);
814 : : }
815 : :
816 [ + + ]: 3 : if (notification->buttons->len > 0)
817 : : {
818 : 1 : GVariantBuilder actions_builder;
819 : :
820 : 1 : g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
821 : :
822 [ + + ]: 2 : for (unsigned int i = 0; i < notification->buttons->len; i++)
823 : : {
824 : 1 : Button *button;
825 : :
826 : 1 : button = g_ptr_array_index (notification->buttons, i);
827 : 1 : g_variant_builder_add (&actions_builder, "@a{sv}",
828 : : valent_notification_serialize_button (button));
829 : : }
830 : :
831 : 1 : g_variant_builder_add (&builder, "{sv}", "buttons",
832 : : g_variant_builder_end (&actions_builder));
833 : : }
834 : :
835 : 3 : return g_variant_builder_end (&builder);
836 : : }
837 : :
838 : : /**
839 : : * valent_notification_deserialize:
840 : : * @variant: a `GVariant`
841 : : *
842 : : * Deserializes @variant into a `ValentNotification`. Since `ValentNotification`
843 : : * is effectively a super-set of `GNotification`, @variant may be a serialized
844 : : * `GNotification` or `ValentNotification`.
845 : : *
846 : : * Returns: (transfer full) (nullable): a `ValentNotification`
847 : : *
848 : : * Since: 1.0
849 : : */
850 : : ValentNotification *
851 : 2 : valent_notification_deserialize (GVariant *variant)
852 : : {
853 : 2 : ValentNotification *notification;
854 : 4 : g_autoptr (GVariant) props = NULL;
855 [ + - ]: 2 : g_autoptr (GVariant) icon = NULL;
856 [ + - ]: 2 : g_autoptr (GVariant) buttons = NULL;
857 : 2 : const char *id, *title, *body, *priority, *application;
858 : 2 : const char *default_action;
859 : :
860 [ - + ]: 2 : g_return_val_if_fail (g_variant_check_format_string (variant, "a{sv}", FALSE), NULL);
861 : :
862 : 2 : notification = valent_notification_new (NULL);
863 : :
864 : 2 : g_variant_get (variant, "@a{sv}", &props);
865 : :
866 [ + + ]: 2 : if (g_variant_lookup (props, "id", "&s", &id))
867 : 1 : valent_notification_set_id (notification, id);
868 : :
869 [ + + ]: 2 : if (g_variant_lookup (props, "application", "&s", &application))
870 : 1 : valent_notification_set_application (notification, application);
871 : :
872 [ + - ]: 2 : if (g_variant_lookup (props, "title", "&s", &title))
873 : 2 : valent_notification_set_title (notification, title);
874 : :
875 [ + - ]: 2 : if (g_variant_lookup (props, "body", "&s", &body))
876 : 2 : valent_notification_set_body (notification, body);
877 : :
878 [ + - ]: 2 : if (g_variant_lookup (props, "icon", "@(sv)", &icon))
879 : : {
880 : 4 : g_autoptr (GIcon) gicon = NULL;
881 : :
882 : 2 : gicon = g_icon_deserialize (icon);
883 [ + - ]: 2 : valent_notification_set_icon (notification, gicon);
884 : : }
885 : :
886 [ + - ]: 2 : if (g_variant_lookup (props, "priority", "&s", &priority))
887 : 2 : valent_notification_set_priority_nick (notification, priority);
888 : :
889 [ - + ]: 2 : if (g_variant_lookup (props, "default-action", "&s", &default_action))
890 : : {
891 : 2 : g_autoptr (GVariant) default_action_target = NULL;
892 : :
893 : 0 : default_action_target = g_variant_lookup_value (props,
894 : : "default-action-target",
895 : : NULL);
896 [ # # ]: 0 : valent_notification_set_default_action (notification,
897 : : default_action,
898 : : default_action_target);
899 : : }
900 : :
901 [ + + ]: 2 : if (g_variant_lookup (props, "buttons", "@aa{sv}", &buttons))
902 : : {
903 : 1 : GVariantIter iter;
904 : 1 : size_t n_buttons;
905 : 1 : GVariant *button;
906 : :
907 : 1 : n_buttons = g_variant_iter_init (&iter, buttons);
908 [ - + ]: 1 : g_warn_if_fail (n_buttons <= 3);
909 : :
910 [ + + ]: 2 : while (g_variant_iter_loop (&iter, "@a{sv}", &button))
911 : : {
912 : 1 : const char *label, *action;
913 : 1 : g_autoptr (GVariant) target = NULL;
914 : :
915 : 1 : g_variant_lookup (button, "label", "&s", &label);
916 : 1 : g_variant_lookup (button, "action", "&s", &action);
917 : 1 : target = g_variant_lookup_value (button, "target", NULL);
918 [ + - ]: 1 : valent_notification_add_button (notification, label, action, target);
919 : : }
920 : : }
921 : :
922 : : return notification;
923 : : }
924 : :
925 : : /**
926 : : * valent_notification_hash:
927 : : * @notification: (type Valent.Notification): a `ValentNotification`
928 : : *
929 : : * Converts a notification to a hash value, using g_str_hash() on the ID.
930 : : *
931 : : * Returns: a hash value
932 : : *
933 : : * Since: 1.0
934 : : */
935 : : unsigned int
936 : 2 : valent_notification_hash (gconstpointer notification)
937 : : {
938 [ - + ]: 2 : g_return_val_if_fail (VALENT_IS_NOTIFICATION ((void *)notification), 0);
939 : :
940 : 2 : return g_str_hash (((ValentNotification *)notification)->id);
941 : : }
942 : :
943 : : /**
944 : : * valent_notification_equal:
945 : : * @notification1: (type Valent.Notification): a `ValentNotification`
946 : : * @notification2: (type Valent.Notification): a `ValentNotification`
947 : : *
948 : : * Compare two notifications for equality by ID.
949 : : *
950 : : * Returns: %TRUE if equal, or %FALSE if not
951 : : *
952 : : * Since: 1.0
953 : : */
954 : : gboolean
955 : 2 : valent_notification_equal (gconstpointer notification1,
956 : : gconstpointer notification2)
957 : : {
958 [ - + ]: 2 : g_return_val_if_fail (VALENT_IS_NOTIFICATION ((void *)notification1), FALSE);
959 [ + - ]: 2 : g_return_val_if_fail (VALENT_IS_NOTIFICATION ((void *)notification2), FALSE);
960 : :
961 : 2 : return g_strcmp0 (((ValentNotification *)notification1)->id,
962 : 2 : ((ValentNotification *)notification2)->id) == 0;
963 : : }
964 : :
|