Coverage Report

Created: 2026-10-14 08:19

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