Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/gnotification.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2013 Lars Uebernickel
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1-or-later
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General
17
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * Authors: Lars Uebernickel <lars@uebernic.de>
20
 */
21
22
#include "config.h"
23
24
#include "gnotification-private.h"
25
#include "gdbusutils.h"
26
#include "gicon.h"
27
#include "gaction.h"
28
#include "gioenumtypes.h"
29
30
/**
31
 * SECTION:gnotification
32
 * @short_description: User Notifications (pop up messages)
33
 * @include: gio/gio.h
34
 *
35
 * #GNotification is a mechanism for creating a notification to be shown
36
 * to the user -- typically as a pop-up notification presented by the
37
 * desktop environment shell.
38
 *
39
 * The key difference between #GNotification and other similar APIs is
40
 * that, if supported by the desktop environment, notifications sent
41
 * with #GNotification will persist after the application has exited,
42
 * and even across system reboots.
43
 *
44
 * Since the user may click on a notification while the application is
45
 * not running, applications using #GNotification should be able to be
46
 * started as a D-Bus service, using #GApplication.
47
 *
48
 * In order for #GNotification to work, the application must have installed
49
 * a `.desktop` file. For example:
50
 * |[
51
 *  [Desktop Entry]
52
 *   Name=Test Application
53
 *   Comment=Description of what Test Application does
54
 *   Exec=gnome-test-application
55
 *   Icon=org.gnome.TestApplication
56
 *   Terminal=false
57
 *   Type=Application
58
 *   Categories=GNOME;GTK;TestApplication Category;
59
 *   StartupNotify=true
60
 *   DBusActivatable=true
61
 *   X-GNOME-UsesNotifications=true
62
 * ]|
63
 *
64
 * The `X-GNOME-UsesNotifications` key indicates to GNOME Control Center
65
 * that this application uses notifications, so it can be listed in the
66
 * Control Center’s ‘Notifications’ panel.
67
 *
68
 * The `.desktop` file must be named as `org.gnome.TestApplication.desktop`,
69
 * where `org.gnome.TestApplication` is the ID passed to g_application_new().
70
 *
71
 * User interaction with a notification (either the default action, or
72
 * buttons) must be associated with actions on the application (ie:
73
 * "app." actions).  It is not possible to route user interaction
74
 * through the notification itself, because the object will not exist if
75
 * the application is autostarted as a result of a notification being
76
 * clicked.
77
 *
78
 * A notification can be sent with g_application_send_notification().
79
 *
80
 * Since: 2.40
81
 **/
82
83
/**
84
 * GNotification:
85
 *
86
 * This structure type is private and should only be accessed using the
87
 * public APIs.
88
 *
89
 * Since: 2.40
90
 **/
91
92
typedef GObjectClass GNotificationClass;
93
94
struct _GNotification
95
{
96
  GObject parent;
97
98
  gchar *title;
99
  gchar *body;
100
  GIcon *icon;
101
  GNotificationPriority priority;
102
  gchar *category;
103
  GPtrArray *buttons;
104
  gchar *default_action;
105
  GVariant *default_action_target;  /* (nullable) (owned), not floating */
106
};
107
108
typedef struct
109
{
110
  gchar *label;
111
  gchar *action_name;
112
  GVariant *target;
113
} Button;
114
115
G_DEFINE_TYPE (GNotification, g_notification, G_TYPE_OBJECT)
116
117
static void
118
button_free (gpointer data)
119
0
{
120
0
  Button *button = data;
121
122
0
  g_free (button->label);
123
0
  g_free (button->action_name);
124
0
  if (button->target)
125
0
    g_variant_unref (button->target);
126
127
0
  g_slice_free (Button, button);
128
0
}
129
130
static void
131
g_notification_dispose (GObject *object)
132
0
{
133
0
  GNotification *notification = G_NOTIFICATION (object);
134
135
0
  g_clear_object (&notification->icon);
136
137
0
  G_OBJECT_CLASS (g_notification_parent_class)->dispose (object);
138
0
}
139
140
static void
141
g_notification_finalize (GObject *object)
142
0
{
143
0
  GNotification *notification = G_NOTIFICATION (object);
144
145
0
  g_free (notification->title);
146
0
  g_free (notification->body);
147
0
  g_free (notification->category);
148
0
  g_free (notification->default_action);
149
0
  if (notification->default_action_target)
150
0
    g_variant_unref (notification->default_action_target);
151
0
  g_ptr_array_free (notification->buttons, TRUE);
152
153
0
  G_OBJECT_CLASS (g_notification_parent_class)->finalize (object);
154
0
}
155
156
static void
157
g_notification_class_init (GNotificationClass *klass)
158
0
{
159
0
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
160
161
0
  object_class->dispose = g_notification_dispose;
162
0
  object_class->finalize = g_notification_finalize;
163
0
}
164
165
static void
166
g_notification_init (GNotification *notification)
167
0
{
168
0
  notification->buttons = g_ptr_array_new_full (2, button_free);
169
0
}
170
171
/**
172
 * g_notification_new:
173
 * @title: the title of the notification
174
 *
175
 * Creates a new #GNotification with @title as its title.
176
 *
177
 * After populating @notification with more details, it can be sent to
178
 * the desktop shell with g_application_send_notification(). Changing
179
 * any properties after this call will not have any effect until
180
 * resending @notification.
181
 *
182
 * Returns: a new #GNotification instance
183
 *
184
 * Since: 2.40
185
 */
186
GNotification *
187
g_notification_new (const gchar *title)
188
0
{
189
0
  GNotification *notification;
190
191
0
  g_return_val_if_fail (title != NULL, NULL);
192
193
0
  notification = g_object_new (G_TYPE_NOTIFICATION, NULL);
194
0
  notification->title = g_strdup (title);
195
196
0
  return notification;
197
0
}
198
199
/*< private >
200
 * g_notification_get_title:
201
 * @notification: a #GNotification
202
 *
203
 * Gets the title of @notification.
204
 *
205
 * Returns: the title of @notification
206
 *
207
 * Since: 2.40
208
 */
209
const gchar *
210
g_notification_get_title (GNotification *notification)
211
0
{
212
0
  g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
213
214
0
  return notification->title;
215
0
}
216
217
/**
218
 * g_notification_set_title:
219
 * @notification: a #GNotification
220
 * @title: the new title for @notification
221
 *
222
 * Sets the title of @notification to @title.
223
 *
224
 * Since: 2.40
225
 */
226
void
227
g_notification_set_title (GNotification *notification,
228
                          const gchar   *title)
229
0
{
230
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
231
0
  g_return_if_fail (title != NULL);
232
233
0
  g_free (notification->title);
234
235
0
  notification->title = g_strdup (title);
236
0
}
237
238
/*< private >
239
 * g_notification_get_body:
240
 * @notification: a #GNotification
241
 *
242
 * Gets the current body of @notification.
243
 *
244
 * Returns: (nullable): the body of @notification
245
 *
246
 * Since: 2.40
247
 */
248
const gchar *
249
g_notification_get_body (GNotification *notification)
250
0
{
251
0
  g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
252
253
0
  return notification->body;
254
0
}
255
256
/**
257
 * g_notification_set_body:
258
 * @notification: a #GNotification
259
 * @body: (nullable): the new body for @notification, or %NULL
260
 *
261
 * Sets the body of @notification to @body.
262
 *
263
 * Since: 2.40
264
 */
265
void
266
g_notification_set_body (GNotification *notification,
267
                         const gchar   *body)
268
0
{
269
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
270
0
  g_return_if_fail (body != NULL);
271
272
0
  g_free (notification->body);
273
274
0
  notification->body = g_strdup (body);
275
0
}
276
277
/*< private >
278
 * g_notification_get_icon:
279
 * @notification: a #GNotification
280
 *
281
 * Gets the icon currently set on @notification.
282
 *
283
 * Returns: (transfer none): the icon associated with @notification
284
 *
285
 * Since: 2.40
286
 */
287
GIcon *
288
g_notification_get_icon (GNotification *notification)
289
0
{
290
0
  g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
291
292
0
  return notification->icon;
293
0
}
294
295
/**
296
 * g_notification_set_icon:
297
 * @notification: a #GNotification
298
 * @icon: the icon to be shown in @notification, as a #GIcon
299
 *
300
 * Sets the icon of @notification to @icon.
301
 *
302
 * Since: 2.40
303
 */
304
void
305
g_notification_set_icon (GNotification *notification,
306
                         GIcon         *icon)
307
0
{
308
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
309
310
0
  if (notification->icon)
311
0
    g_object_unref (notification->icon);
312
313
0
  notification->icon = g_object_ref (icon);
314
0
}
315
316
/*< private >
317
 * g_notification_get_priority:
318
 * @notification: a #GNotification
319
 *
320
 * Returns the priority of @notification
321
 *
322
 * Since: 2.42
323
 */
324
GNotificationPriority
325
g_notification_get_priority (GNotification *notification)
326
0
{
327
0
  g_return_val_if_fail (G_IS_NOTIFICATION (notification), G_NOTIFICATION_PRIORITY_NORMAL);
328
329
0
  return notification->priority;
330
0
}
331
332
/**
333
 * g_notification_set_urgent:
334
 * @notification: a #GNotification
335
 * @urgent: %TRUE if @notification is urgent
336
 *
337
 * Deprecated in favor of g_notification_set_priority().
338
 *
339
 * Since: 2.40
340
 * Deprecated: 2.42: Since 2.42, this has been deprecated in favour of
341
 *    g_notification_set_priority().
342
 */
343
void
344
g_notification_set_urgent (GNotification *notification,
345
                           gboolean       urgent)
346
0
{
347
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
348
349
0
  notification->priority = urgent ?
350
0
      G_NOTIFICATION_PRIORITY_URGENT :
351
0
      G_NOTIFICATION_PRIORITY_NORMAL;
352
0
}
353
354
/*< private >
355
 * g_notification_get_category:
356
 * @notification: a #GNotification
357
 *
358
 * Gets the category of @notification.
359
 *
360
 * This will be %NULL if no category is set.
361
 *
362
 * Returns: (nullable): the category of @notification
363
 *
364
 * Since: 2.70
365
 */
366
const gchar *
367
g_notification_get_category (GNotification *notification)
368
0
{
369
0
  g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
370
371
0
  return notification->category;
372
0
}
373
374
/**
375
 * g_notification_set_category:
376
 * @notification: a #GNotification
377
 * @category: (nullable): the category for @notification, or %NULL for no category
378
 *
379
 * Sets the type of @notification to @category. Categories have a main
380
 * type like `email`, `im` or `device` and can have a detail separated
381
 * by a `.`, e.g. `im.received` or `email.arrived`. Setting the category
382
 * helps the notification server to select proper feedback to the user.
383
 *
384
 * Standard categories are [listed in the specification](https://specifications.freedesktop.org/notification-spec/latest/ar01s06.html).
385
 *
386
 * Since: 2.70
387
 */
388
void
389
g_notification_set_category (GNotification *notification,
390
                             const gchar   *category)
391
0
{
392
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
393
0
  g_return_if_fail (category == NULL || *category != '\0');
394
395
0
  g_free (notification->category);
396
397
0
  notification->category = g_strdup (category);
398
0
}
399
400
/**
401
 * g_notification_set_priority:
402
 * @notification: a #GNotification
403
 * @priority: a #GNotificationPriority
404
 *
405
 * Sets the priority of @notification to @priority. See
406
 * #GNotificationPriority for possible values.
407
 */
408
void
409
g_notification_set_priority (GNotification         *notification,
410
                             GNotificationPriority  priority)
411
0
{
412
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
413
414
0
  notification->priority = priority;
415
0
}
416
417
/**
418
 * g_notification_add_button:
419
 * @notification: a #GNotification
420
 * @label: label of the button
421
 * @detailed_action: a detailed action name
422
 *
423
 * Adds a button to @notification that activates the action in
424
 * @detailed_action when clicked. That action must be an
425
 * application-wide action (starting with "app."). If @detailed_action
426
 * contains a target, the action will be activated with that target as
427
 * its parameter.
428
 *
429
 * See g_action_parse_detailed_name() for a description of the format
430
 * for @detailed_action.
431
 *
432
 * Since: 2.40
433
 */
434
void
435
g_notification_add_button (GNotification *notification,
436
                           const gchar   *label,
437
                           const gchar   *detailed_action)
438
0
{
439
0
  gchar *action;
440
0
  GVariant *target;
441
0
  GError *error = NULL;
442
443
0
  g_return_if_fail (detailed_action != NULL);
444
445
0
  if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error))
446
0
    {
447
0
      g_warning ("%s: %s", G_STRFUNC, error->message);
448
0
      g_error_free (error);
449
0
      return;
450
0
    }
451
452
0
  g_notification_add_button_with_target_value (notification, label, action, target);
453
454
0
  g_free (action);
455
0
  if (target)
456
0
    g_variant_unref (target);
457
0
}
458
459
/**
460
 * g_notification_add_button_with_target: (skip)
461
 * @notification: a #GNotification
462
 * @label: label of the button
463
 * @action: an action name
464
 * @target_format: (nullable): a #GVariant format string, or %NULL
465
 * @...: positional parameters, as determined by @target_format
466
 *
467
 * Adds a button to @notification that activates @action when clicked.
468
 * @action must be an application-wide action (it must start with "app.").
469
 *
470
 * If @target_format is given, it is used to collect remaining
471
 * positional parameters into a #GVariant instance, similar to
472
 * g_variant_new(). @action will be activated with that #GVariant as its
473
 * parameter.
474
 *
475
 * Since: 2.40
476
 */
477
void
478
g_notification_add_button_with_target (GNotification *notification,
479
                                       const gchar   *label,
480
                                       const gchar   *action,
481
                                       const gchar   *target_format,
482
                                       ...)
483
0
{
484
0
  va_list args;
485
0
  GVariant *target = NULL;
486
487
0
  if (target_format)
488
0
    {
489
0
      va_start (args, target_format);
490
0
      target = g_variant_new_va (target_format, NULL, &args);
491
0
      va_end (args);
492
0
    }
493
494
0
  g_notification_add_button_with_target_value (notification, label, action, target);
495
0
}
496
497
/**
498
 * g_notification_add_button_with_target_value: (rename-to g_notification_add_button_with_target)
499
 * @notification: a #GNotification
500
 * @label: label of the button
501
 * @action: an action name
502
 * @target: (nullable): a #GVariant to use as @action's parameter, or %NULL
503
 *
504
 * Adds a button to @notification that activates @action when clicked.
505
 * @action must be an application-wide action (it must start with "app.").
506
 *
507
 * If @target is non-%NULL, @action will be activated with @target as
508
 * its parameter.
509
 *
510
 * Since: 2.40
511
 */
512
void
513
g_notification_add_button_with_target_value (GNotification *notification,
514
                                             const gchar   *label,
515
                                             const gchar   *action,
516
                                             GVariant      *target)
517
0
{
518
0
  Button *button;
519
520
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
521
0
  g_return_if_fail (label != NULL);
522
0
  g_return_if_fail (action != NULL && g_action_name_is_valid (action));
523
524
0
  if (!g_str_has_prefix (action, "app."))
525
0
    {
526
0
      g_warning ("%s: action '%s' does not start with 'app.'."
527
0
                 "This is unlikely to work properly.", G_STRFUNC, action);
528
0
    }
529
530
0
  button =  g_slice_new0 (Button);
531
0
  button->label = g_strdup (label);
532
0
  button->action_name = g_strdup (action);
533
534
0
  if (target)
535
0
    button->target = g_variant_ref_sink (target);
536
537
0
  g_ptr_array_add (notification->buttons, button);
538
0
}
539
540
/*< private >
541
 * g_notification_get_n_buttons:
542
 * @notification: a #GNotification
543
 *
544
 * Returns: the amount of buttons added to @notification.
545
 */
546
guint
547
g_notification_get_n_buttons (GNotification *notification)
548
0
{
549
0
  return notification->buttons->len;
550
0
}
551
552
/*< private >
553
 * g_notification_get_button:
554
 * @notification: a #GNotification
555
 * @index: index of the button
556
 * @label: (): return location for the button's label
557
 * @action: (): return location for the button's associated action
558
 * @target: (): return location for the target @action should be
559
 * activated with
560
 *
561
 * Returns a description of a button that was added to @notification
562
 * with g_notification_add_button().
563
 *
564
 * @index must be smaller than the value returned by
565
 * g_notification_get_n_buttons().
566
 */
567
void
568
g_notification_get_button (GNotification  *notification,
569
                           gint            index,
570
                           gchar         **label,
571
                           gchar         **action,
572
                           GVariant      **target)
573
0
{
574
0
  Button *button;
575
576
0
  button = g_ptr_array_index (notification->buttons, index);
577
578
0
  if (label)
579
0
    *label = g_strdup (button->label);
580
581
0
  if (action)
582
0
    *action = g_strdup (button->action_name);
583
584
0
  if (target)
585
0
    *target = button->target ? g_variant_ref (button->target) : NULL;
586
0
}
587
588
/*< private >
589
 * g_notification_get_button_with_action:
590
 * @notification: a #GNotification
591
 * @action: an action name
592
 *
593
 * Returns the index of the button in @notification that is associated
594
 * with @action, or -1 if no such button exists.
595
 */
596
gint
597
g_notification_get_button_with_action (GNotification *notification,
598
                                       const gchar   *action)
599
0
{
600
0
  guint i;
601
602
0
  for (i = 0; i < notification->buttons->len; i++)
603
0
    {
604
0
      Button *button;
605
606
0
      button = g_ptr_array_index (notification->buttons, i);
607
0
      if (g_str_equal (action, button->action_name))
608
0
        return i;
609
0
    }
610
611
0
  return -1;
612
0
}
613
614
615
/*< private >
616
 * g_notification_get_default_action:
617
 * @notification: a #GNotification
618
 * @action: (out) (optional) (nullable) (transfer full): return location for the
619
 *   default action, or %NULL if unset
620
 * @target: (out) (optional) (nullable) (transfer full): return location for the
621
 *   target of the default action, or %NULL if unset
622
 *
623
 * Gets the action and target for the default action of @notification.
624
 *
625
 * If this function returns %TRUE, @action is guaranteed to be set to a non-%NULL
626
 * value (if a pointer is passed to @action). @target may still return a %NULL
627
 * value, as the default action may have no target.
628
 *
629
 * Returns: %TRUE if @notification has a default action
630
 */
631
gboolean
632
g_notification_get_default_action (GNotification  *notification,
633
                                   gchar         **action,
634
                                   GVariant      **target)
635
0
{
636
0
  if (notification->default_action == NULL)
637
0
    return FALSE;
638
639
0
  if (action)
640
0
    *action = g_strdup (notification->default_action);
641
642
0
  if (target)
643
0
    {
644
0
      if (notification->default_action_target)
645
0
        *target = g_variant_ref (notification->default_action_target);
646
0
      else
647
0
        *target = NULL;
648
0
    }
649
650
0
  return TRUE;
651
0
}
652
653
/**
654
 * g_notification_set_default_action:
655
 * @notification: a #GNotification
656
 * @detailed_action: a detailed action name
657
 *
658
 * Sets the default action of @notification to @detailed_action. This
659
 * action is activated when the notification is clicked on.
660
 *
661
 * The action in @detailed_action must be an application-wide action (it
662
 * must start with "app."). If @detailed_action contains a target, the
663
 * given action will be activated with that target as its parameter.
664
 * See g_action_parse_detailed_name() for a description of the format
665
 * for @detailed_action.
666
 *
667
 * When no default action is set, the application that the notification
668
 * was sent on is activated.
669
 *
670
 * Since: 2.40
671
 */
672
void
673
g_notification_set_default_action (GNotification *notification,
674
                                   const gchar   *detailed_action)
675
0
{
676
0
  gchar *action;
677
0
  GVariant *target;
678
0
  GError *error = NULL;
679
680
0
  if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error))
681
0
    {
682
0
      g_warning ("%s: %s", G_STRFUNC, error->message);
683
0
      g_error_free (error);
684
0
      return;
685
0
    }
686
687
0
  g_notification_set_default_action_and_target_value (notification, action, target);
688
689
0
  g_free (action);
690
0
  if (target)
691
0
    g_variant_unref (target);
692
0
}
693
694
/**
695
 * g_notification_set_default_action_and_target: (skip)
696
 * @notification: a #GNotification
697
 * @action: an action name
698
 * @target_format: (nullable): a #GVariant format string, or %NULL
699
 * @...: positional parameters, as determined by @target_format
700
 *
701
 * Sets the default action of @notification to @action. This action is
702
 * activated when the notification is clicked on. It must be an
703
 * application-wide action (it must start with "app.").
704
 *
705
 * If @target_format is given, it is used to collect remaining
706
 * positional parameters into a #GVariant instance, similar to
707
 * g_variant_new(). @action will be activated with that #GVariant as its
708
 * parameter.
709
 *
710
 * When no default action is set, the application that the notification
711
 * was sent on is activated.
712
 *
713
 * Since: 2.40
714
 */
715
void
716
g_notification_set_default_action_and_target (GNotification *notification,
717
                                              const gchar   *action,
718
                                              const gchar   *target_format,
719
                                              ...)
720
0
{
721
0
  va_list args;
722
0
  GVariant *target = NULL;
723
724
0
  if (target_format)
725
0
    {
726
0
      va_start (args, target_format);
727
0
      target = g_variant_new_va (target_format, NULL, &args);
728
0
      va_end (args);
729
0
    }
730
731
0
  g_notification_set_default_action_and_target_value (notification, action, target);
732
0
}
733
734
/**
735
 * g_notification_set_default_action_and_target_value: (rename-to g_notification_set_default_action_and_target)
736
 * @notification: a #GNotification
737
 * @action: an action name
738
 * @target: (nullable): a #GVariant to use as @action's parameter, or %NULL
739
 *
740
 * Sets the default action of @notification to @action. This action is
741
 * activated when the notification is clicked on. It must be an
742
 * application-wide action (start with "app.").
743
 *
744
 * If @target is non-%NULL, @action will be activated with @target as
745
 * its parameter. If @target is floating, it will be consumed.
746
 *
747
 * When no default action is set, the application that the notification
748
 * was sent on is activated.
749
 *
750
 * Since: 2.40
751
 */
752
void
753
g_notification_set_default_action_and_target_value (GNotification *notification,
754
                                                    const gchar   *action,
755
                                                    GVariant      *target)
756
0
{
757
0
  g_return_if_fail (G_IS_NOTIFICATION (notification));
758
0
  g_return_if_fail (action != NULL && g_action_name_is_valid (action));
759
760
0
  if (!g_str_has_prefix (action, "app."))
761
0
    {
762
0
      g_warning ("%s: action '%s' does not start with 'app.'."
763
0
                 "This is unlikely to work properly.", G_STRFUNC, action);
764
0
    }
765
766
0
  g_free (notification->default_action);
767
0
  g_clear_pointer (&notification->default_action_target, g_variant_unref);
768
769
0
  notification->default_action = g_strdup (action);
770
771
0
  if (target)
772
0
    notification->default_action_target = g_variant_ref_sink (target);
773
0
}
774
775
static GVariant *
776
g_notification_serialize_button (Button *button)
777
0
{
778
0
  GVariantBuilder builder;
779
780
0
  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
781
782
0
  g_variant_builder_add (&builder, "{sv}", "label", g_variant_new_string (button->label));
783
0
  g_variant_builder_add (&builder, "{sv}", "action", g_variant_new_string (button->action_name));
784
785
0
  if (button->target)
786
0
    g_variant_builder_add (&builder, "{sv}", "target", button->target);
787
788
0
  return g_variant_builder_end (&builder);
789
0
}
790
791
static GVariant *
792
g_notification_get_priority_nick (GNotification *notification)
793
0
{
794
0
  GEnumClass *enum_class;
795
0
  GEnumValue *value;
796
0
  GVariant *nick;
797
798
0
  enum_class = g_type_class_ref (G_TYPE_NOTIFICATION_PRIORITY);
799
0
  value = g_enum_get_value (enum_class, g_notification_get_priority (notification));
800
0
  g_assert (value != NULL);
801
0
  nick = g_variant_new_string (value->value_nick);
802
0
  g_type_class_unref (enum_class);
803
804
0
  return nick;
805
0
}
806
807
/*< private >
808
 * g_notification_serialize:
809
 *
810
 * Serializes @notification into a floating variant of type a{sv}.
811
 *
812
 * Returns: the serialized @notification as a floating variant.
813
 */
814
GVariant *
815
g_notification_serialize (GNotification *notification)
816
0
{
817
0
  GVariantBuilder builder;
818
819
0
  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
820
821
0
  if (notification->title)
822
0
    g_variant_builder_add (&builder, "{sv}", "title", g_variant_new_string (notification->title));
823
824
0
  if (notification->body)
825
0
    g_variant_builder_add (&builder, "{sv}", "body", g_variant_new_string (notification->body));
826
827
0
  if (notification->icon)
828
0
    {
829
0
      GVariant *serialized_icon;
830
831
0
      if ((serialized_icon = g_icon_serialize (notification->icon)))
832
0
        {
833
0
          g_variant_builder_add (&builder, "{sv}", "icon", serialized_icon);
834
0
          g_variant_unref (serialized_icon);
835
0
        }
836
0
    }
837
838
0
  g_variant_builder_add (&builder, "{sv}", "priority", g_notification_get_priority_nick (notification));
839
840
0
  if (notification->default_action)
841
0
    {
842
0
      g_variant_builder_add (&builder, "{sv}", "default-action",
843
0
                                               g_variant_new_string (notification->default_action));
844
845
0
      if (notification->default_action_target)
846
0
        g_variant_builder_add (&builder, "{sv}", "default-action-target",
847
0
                                                  notification->default_action_target);
848
0
    }
849
850
0
  if (notification->buttons->len > 0)
851
0
    {
852
0
      GVariantBuilder actions_builder;
853
0
      guint i;
854
855
0
      g_variant_builder_init (&actions_builder, G_VARIANT_TYPE ("aa{sv}"));
856
857
0
      for (i = 0; i < notification->buttons->len; i++)
858
0
        {
859
0
          Button *button = g_ptr_array_index (notification->buttons, i);
860
0
          g_variant_builder_add (&actions_builder, "@a{sv}", g_notification_serialize_button (button));
861
0
        }
862
863
0
      g_variant_builder_add (&builder, "{sv}", "buttons", g_variant_builder_end (&actions_builder));
864
0
    }
865
866
0
  return g_variant_builder_end (&builder);
867
0
}