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