Add GNotification
[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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17  * Boston, MA 02111-1307, USA.
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
29 typedef GObjectClass GNotificationClass;
30
31 struct _GNotification
32 {
33   GObject parent;
34
35   gchar *title;
36   gchar *body;
37   GIcon *image;
38   gboolean urgent;
39   GPtrArray *buttons;
40   gchar *default_action;
41   GVariant *default_action_target;
42 };
43
44 typedef struct
45 {
46   gchar *label;
47   gchar *action_name;
48   GVariant *target;
49 } Button;
50
51 G_DEFINE_TYPE (GNotification, g_notification, G_TYPE_OBJECT);
52
53 static void
54 button_free (gpointer data)
55 {
56   Button *button = data;
57
58   g_free (button->label);
59   g_free (button->action_name);
60   if (button->target)
61     g_variant_unref (button->target);
62
63   g_slice_free (Button, button);
64 }
65
66 static void
67 g_notification_dispose (GObject *object)
68 {
69   GNotification *notification = G_NOTIFICATION (object);
70
71   g_clear_object (&notification->image);
72
73   G_OBJECT_CLASS (g_notification_parent_class)->dispose (object);
74 }
75
76 static void
77 g_notification_finalize (GObject *object)
78 {
79   GNotification *notification = G_NOTIFICATION (object);
80
81   g_free (notification->title);
82   g_free (notification->body);
83   g_free (notification->default_action);
84   if (notification->default_action_target)
85     g_variant_unref (notification->default_action_target);
86   g_ptr_array_free (notification->buttons, TRUE);
87
88   G_OBJECT_CLASS (g_notification_parent_class)->finalize (object);
89 }
90
91 static void
92 g_notification_class_init (GNotificationClass *klass)
93 {
94   GObjectClass *object_class = G_OBJECT_CLASS (klass);
95
96   object_class->dispose = g_notification_dispose;
97   object_class->finalize = g_notification_finalize;
98 }
99
100 static void
101 g_notification_init (GNotification *notification)
102 {
103   notification->buttons = g_ptr_array_new_full (2, button_free);
104 }
105
106 /**
107  * g_notification_new:
108  * @title: the title of the notification
109  *
110  * Creates a new #GNotification with @title as its title.
111  *
112  * After populating @notification with more details, it can be sent to
113  * the desktop shell with g_application_send_notification(). Changing
114  * any properties after this call will not have any effect until
115  * resending @notification.
116  *
117  * Returns: a new #GNotification instance
118  *
119  * Since: 2.40
120  */
121 GNotification *
122 g_notification_new (const gchar *title)
123 {
124   GNotification *notification;
125
126   g_return_val_if_fail (title != NULL, NULL);
127
128   notification = g_object_new (G_TYPE_NOTIFICATION, NULL);
129   notification->title = g_strdup (title);
130
131   return notification;
132 }
133
134 /**
135  * g_notification_get_title:
136  * @notification: a #GNotification
137  *
138  * Gets the title of @notification.
139  *
140  * Returns: the title of @notification
141  *
142  * Since: 2.40
143  */
144 const gchar *
145 g_notification_get_title (GNotification *notification)
146 {
147   g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
148
149   return notification->title;
150 }
151
152 /**
153  * g_notification_set_title:
154  * @notification: a #GNotification
155  * title: the new title for @notification
156  *
157  * Sets the title of @notification to @title.
158  *
159  * Since: 2.40
160  */
161 void
162 g_notification_set_title (GNotification *notification,
163                           const gchar   *title)
164 {
165   g_return_if_fail (G_IS_NOTIFICATION (notification));
166   g_return_if_fail (title != NULL);
167
168   g_free (notification->title);
169
170   notification->title = g_strdup (title);
171 }
172
173 /**
174  * g_notification_get_body:
175  * @notification: a #GNotification
176  *
177  * Gets the current body of @notification.
178  *
179  * Returns: (allow-none): the body of @notification
180  *
181  * Since: 2.40
182  */
183 const gchar *
184 g_notification_get_body (GNotification *notification)
185 {
186   g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
187
188   return notification->body;
189 }
190
191 /**
192  * g_notification_set_body:
193  * @notification: a #GNotification
194  * @body: (allow-none): the new body for @notification, or %NULL
195  *
196  * Sets the body of @notification to @body.
197  *
198  * Since: 2.40
199  */
200 void
201 g_notification_set_body (GNotification *notification,
202                          const gchar   *body)
203 {
204   g_return_if_fail (G_IS_NOTIFICATION (notification));
205   g_return_if_fail (body != NULL);
206
207   g_free (notification->body);
208
209   notification->body = g_strdup (body);
210 }
211
212 /**
213  * g_notification_get_image:
214  * @notification: a #GNotification
215  *
216  * Gets the image currently set on @notification.
217  *
218  * Returns: (transfer none): the image associated with @notification
219  *
220  * Since: 2.40
221  */
222 GIcon *
223 g_notification_get_image (GNotification *notification)
224 {
225   g_return_val_if_fail (G_IS_NOTIFICATION (notification), NULL);
226
227   return notification->image;
228 }
229
230 /**
231  * g_notification_set_image:
232  * @notification: a #GNotification
233  * @image: the image to be shown in @notification, as a #GIcon
234  *
235  * Sets the image of @notification to @image.
236  *
237  * Since: 2.40
238  */
239 void
240 g_notification_set_image (GNotification *notification,
241                           GIcon         *image)
242 {
243   g_return_if_fail (G_IS_NOTIFICATION (notification));
244
245   if (notification->image)
246     g_object_unref (notification->image);
247
248   notification->image = g_object_ref (image);
249 }
250
251 /**
252  * g_notification_get_urgent:
253  * @notification: a #GNotification
254  *
255  * Returns %TRUE if @notification is marked as urgent.
256  *
257  * Since: 2.40
258  */
259 gboolean
260 g_notification_get_urgent (GNotification *notification)
261 {
262   g_return_val_if_fail (G_IS_NOTIFICATION (notification), FALSE);
263
264   return notification->urgent;
265 }
266
267 /**
268  * g_notification_set_urgent:
269  * @notification: a #GNotification
270  * @urgent: %TRUE if @notification is urgent
271  *
272  * Sets or unsets whether @notification is marked as urgent.
273  *
274  * Since: 2.40
275  */
276 void
277 g_notification_set_urgent (GNotification *notification,
278                            gboolean       urgent)
279 {
280   g_return_if_fail (G_IS_NOTIFICATION (notification));
281
282   notification->urgent = urgent;
283 }
284
285 /**
286  * g_notification_add_button:
287  * @notification: a #GNotification
288  * @label: label of the button
289  * @detailed_action: a detailed action name
290  *
291  * Adds a button to @notification that activates the action in
292  * @detailed_action when clicked. That action must be an
293  * application-wide action (starting with "app."). If @detailed_action
294  * contains a target, the action will be activated with that target as
295  * its parameter.
296  *
297  * See g_action_parse_detailed_name() for a description of the format
298  * for @detailed_action.
299  *
300  * Since: 2.40
301  */
302 void
303 g_notification_add_button (GNotification *notification,
304                            const gchar   *label,
305                            const gchar   *detailed_action)
306 {
307   gchar *action;
308   GVariant *target;
309   GError *error = NULL;
310
311   g_return_if_fail (detailed_action != NULL);
312
313   if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error))
314     {
315       g_warning ("%s: %s", G_STRFUNC, error->message);
316       g_error_free (error);
317       return;
318     }
319
320   g_notification_add_button_with_target_value (notification, label, action, target);
321
322   g_free (action);
323   if (target)
324     g_variant_unref (target);
325 }
326
327 /**
328  * g_notification_add_button_with_target: (skip)
329  * @notification: a #GNotification
330  * @label: label of the button
331  * @action: an action name
332  * @target_format: (allow-none): a GVariant format string, or %NULL
333  * @...: positional parameters, as determined by @format_string
334  *
335  * Adds a button to @notification that activates @action when clicked.
336  * @action must be an application-wide action (it must start with "app.").
337  *
338  * If @target_format is given, it is used to collect remaining
339  * positional parameters into a GVariant instance, similar to
340  * g_variant_new(). @action will be activated with that GVariant as its
341  * parameter.
342  *
343  * Since: 2.40
344  */
345 void
346 g_notification_add_button_with_target (GNotification *notification,
347                                        const gchar   *label,
348                                        const gchar   *action,
349                                        const gchar   *target_format,
350                                        ...)
351 {
352   va_list args;
353   GVariant *target = NULL;
354
355   if (target_format)
356     {
357       va_start (args, target_format);
358       target = g_variant_new_va (target_format, NULL, &args);
359       va_end (args);
360     }
361
362   g_notification_add_button_with_target_value (notification, label, action, target);
363 }
364
365 /**
366  * g_notification_add_button_with_target_value: (rename-to g_notification_add_button_with_target)
367  * @notification: a #GNotification
368  * @label: label of the button
369  * @action: an action name
370  * @target: (allow-none): a GVariant to use as @action's parameter, or %NULL
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 is non-%NULL, @action will be activated with @target as
376  * its parameter.
377  *
378  * Since: 2.40
379  */
380 void
381 g_notification_add_button_with_target_value (GNotification *notification,
382                                              const gchar   *label,
383                                              const gchar   *action,
384                                              GVariant      *target)
385 {
386   Button *button;
387
388   g_return_if_fail (G_IS_NOTIFICATION (notification));
389   g_return_if_fail (label != NULL);
390   g_return_if_fail (action != NULL && g_action_name_is_valid (action));
391
392   if (!g_str_has_prefix (action, "app."))
393     {
394       g_warning ("%s: action '%s' does not start with 'app.'."
395                  "This is unlikely to work properly.", G_STRFUNC, action);
396     }
397
398   button =  g_slice_new0 (Button);
399   button->label = g_strdup (label);
400   button->action_name = g_strdup (action);
401
402   if (target)
403     button->target = g_variant_ref_sink (target);
404
405   g_ptr_array_add (notification->buttons, button);
406 }
407
408 /*< private >
409  * g_notification_get_n_buttons:
410  * @notification: a #GNotification
411  *
412  * Returns: the amount of buttons added to @notification.
413  */
414 guint
415 g_notification_get_n_buttons (GNotification *notification)
416 {
417   return notification->buttons->len;
418 }
419
420 /*< private >
421  * g_notification_get_button:
422  * @notification: a #GNotification
423  * @index: index of the button
424  * @label: (): return location for the button's label
425  * @action: (): return location for the button's associated action
426  * @target: (): return location for the target @action should be
427  * activated with
428  *
429  * Returns a description of a button that was added to @notification
430  * with g_notification_add_button().
431  *
432  * @index must be smaller than the value returned by
433  * g_notification_get_n_buttons().
434  */
435 void
436 g_notification_get_button (GNotification  *notification,
437                            gint            index,
438                            gchar         **label,
439                            gchar         **action,
440                            GVariant      **target)
441 {
442   Button *button;
443
444   button = g_ptr_array_index (notification->buttons, index);
445
446   if (label)
447     *label = g_strdup (button->label);
448
449   if (action)
450     *action = g_strdup (button->action_name);
451
452   if (target)
453     *target = button->target ? g_variant_ref (button->target) : NULL;
454 }
455
456 /*< private >
457  * g_notification_get_button_with_action:
458  * @notification: a #GNotification
459  * @action: an action name
460  *
461  * Returns the index of the button in @notification that is associated
462  * with @action, or -1 if no such button exists.
463  */
464 gint
465 g_notification_get_button_with_action (GNotification *notification,
466                                        const gchar   *action)
467 {
468   guint i;
469
470   for (i = 0; i < notification->buttons->len; i++)
471     {
472       Button *button;
473
474       button = g_ptr_array_index (notification->buttons, i);
475       if (g_str_equal (action, button->action_name))
476         return i;
477     }
478
479   return -1;
480 }
481
482
483 /*< private >
484  * g_notification_get_default_action:
485  * @notification: a #GNotification
486  * @action: (allow-none): return location for the default action
487  * @target: (allow-none): return location for the target of the default action
488  *
489  * Gets the action and target for the default action of @notification.
490  *
491  * Returns: %TRUE if @notification has a default action
492  */
493 gboolean
494 g_notification_get_default_action (GNotification  *notification,
495                                    gchar         **action,
496                                    GVariant      **target)
497 {
498   if (notification->default_action == NULL)
499     return FALSE;
500
501   if (action)
502     *action = g_strdup (notification->default_action);
503
504   if (target)
505     {
506       if (notification->default_action_target)
507         *target = g_variant_ref (notification->default_action_target);
508       else
509         *target = NULL;
510     }
511
512   return TRUE;
513 }
514
515 /**
516  * g_notification_set_default_action:
517  * @notification: a #GNotification
518  * @detailed_action: a detailed action name
519  *
520  * Sets the default action of @notification to @detailed_action. This
521  * action is activated when the notification is clicked on.
522  *
523  * The action in @detailed_action must be an application-wide action (it
524  * must start with "app."). If @detailed_action contains a target, the
525  * given action will be activated with that target as its parameter.
526  * See g_action_parse_detailed_name() for a description of the format
527  * for @detailed_action.
528  *
529  * When no default action is set, the application that the notification
530  * was sent on is activated.
531  *
532  * Since: 2.40
533  */
534 void
535 g_notification_set_default_action (GNotification *notification,
536                                    const gchar   *detailed_action)
537 {
538   gchar *action;
539   GVariant *target;
540   GError *error = NULL;
541
542   if (!g_action_parse_detailed_name (detailed_action, &action, &target, &error))
543     {
544       g_warning ("%s: %s", G_STRFUNC, error->message);
545       g_error_free (error);
546       return;
547     }
548
549   g_notification_set_default_action_and_target_value (notification, action, target);
550
551   g_free (action);
552   if (target)
553     g_variant_unref (target);
554 }
555
556 /**
557  * g_notification_set_default_action_and_target: (skip)
558  * @notification: a #GNotification
559  * @action: an action name
560  * @target_format: (allow-none): a GVariant format string, or %NULL
561  * @...: positional parameters, as determined by @format_string
562  *
563  * Sets the default action of @notification to @action. This action is
564  * activated when the notification is clicked on. It must be an
565  * application-wide action (it must start with "app.").
566  *
567  * If @target_format is given, it is used to collect remaining
568  * positional parameters into a GVariant instance, similar to
569  * g_variant_new(). @action will be activated with that GVariant as its
570  * parameter.
571  *
572  * When no default action is set, the application that the notification
573  * was sent on is activated.
574  *
575  * Since: 2.40
576  */
577 void
578 g_notification_set_default_action_and_target (GNotification *notification,
579                                               const gchar   *action,
580                                               const gchar   *target_format,
581                                               ...)
582 {
583   va_list args;
584   GVariant *target = NULL;
585
586   if (target_format)
587     {
588       va_start (args, target_format);
589       target = g_variant_new_va (target_format, NULL, &args);
590       va_end (args);
591     }
592
593   g_notification_set_default_action_and_target_value (notification, action, target);
594 }
595
596 /**
597  * g_notification_set_default_action_and_target_value: (rename-to g_notification_set_default_action_and_target)
598  * @notification: a #GNotification
599  * @action: an action name
600  * @target: (allow-none): a GVariant to use as @action's parameter, or %NULL
601  *
602  * Sets the default action of @notification to @action. This action is
603  * activated when the notification is clicked on. It must be an
604  * application-wide action (start with "app.").
605  *
606  * If @target_format is given, it is used to collect remaining
607  * positional parameters into a GVariant instance, similar to
608  * g_variant_new().
609  *
610  * If @target is non-%NULL, @action will be activated with @target as
611  * its parameter.
612  *
613  * When no default action is set, the application that the notification
614  * was sent on is activated.
615  *
616  * Since: 2.40
617  */
618 void
619 g_notification_set_default_action_and_target_value (GNotification *notification,
620                                                     const gchar   *action,
621                                                     GVariant      *target)
622 {
623   g_return_if_fail (G_IS_NOTIFICATION (notification));
624   g_return_if_fail (action != NULL && g_action_name_is_valid (action));
625
626   if (!g_str_has_prefix (action, "app."))
627     {
628       g_warning ("%s: action '%s' does not start with 'app.'."
629                  "This is unlikely to work properly.", G_STRFUNC, action);
630     }
631
632   g_free (notification->default_action);
633   g_clear_pointer (&notification->default_action_target, g_variant_unref);
634
635   notification->default_action = g_strdup (action);
636
637   if (target)
638     notification->default_action_target = g_variant_ref_sink (target);
639 }