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