Coverage Report

Created: 2025-07-23 08:13

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