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