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