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