eff18da83181ae53787ace3a50eeb8ee1fdea6d3
[platform/upstream/glib.git] / gio / gappinfo.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: Alexander Larsson <alexl@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include "gappinfo.h"
24 #include "gappinfoprivate.h"
25 #include "gcontextspecificgroup.h"
26 #include "gtask.h"
27 #include "gcancellable.h"
28
29 #include "glibintl.h"
30 #include "gmarshal-internal.h"
31 #include <gioerror.h>
32 #include <gfile.h>
33
34 #ifdef G_OS_UNIX
35 #include "gdbusconnection.h"
36 #include "gdbusmessage.h"
37 #include "gportalsupport.h"
38 #include "gunixfdlist.h"
39 #include "gopenuriportal.h"
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #endif
44
45 /**
46  * SECTION:gappinfo
47  * @short_description: Application information and launch contexts
48  * @include: gio/gio.h
49  * @see_also: #GAppInfoMonitor
50  * 
51  * #GAppInfo and #GAppLaunchContext are used for describing and launching
52  * applications installed on the system.
53  *
54  * As of GLib 2.20, URIs will always be converted to POSIX paths
55  * (using g_file_get_path()) when using g_app_info_launch() even if
56  * the application requested an URI and not a POSIX path. For example
57  * for a desktop-file based application with Exec key `totem
58  * %U` and a single URI, `sftp://foo/file.avi`, then
59  * `/home/user/.gvfs/sftp on foo/file.avi` will be passed. This will
60  * only work if a set of suitable GIO extensions (such as gvfs 2.26
61  * compiled with FUSE support), is available and operational; if this
62  * is not the case, the URI will be passed unmodified to the application.
63  * Some URIs, such as `mailto:`, of course cannot be mapped to a POSIX
64  * path (in gvfs there's no FUSE mount for it); such URIs will be
65  * passed unmodified to the application.
66  *
67  * Specifically for gvfs 2.26 and later, the POSIX URI will be mapped
68  * back to the GIO URI in the #GFile constructors (since gvfs
69  * implements the #GVfs extension point). As such, if the application
70  * needs to examine the URI, it needs to use g_file_get_uri() or
71  * similar on #GFile. In other words, an application cannot assume
72  * that the URI passed to e.g. g_file_new_for_commandline_arg() is
73  * equal to the result of g_file_get_uri(). The following snippet
74  * illustrates this:
75  *
76  * |[ 
77  * GFile *f;
78  * char *uri;
79  *
80  * file = g_file_new_for_commandline_arg (uri_from_commandline);
81  *
82  * uri = g_file_get_uri (file);
83  * strcmp (uri, uri_from_commandline) == 0;
84  * g_free (uri);
85  *
86  * if (g_file_has_uri_scheme (file, "cdda"))
87  *   {
88  *     // do something special with uri
89  *   }
90  * g_object_unref (file);
91  * ]|
92  *
93  * This code will work when both `cdda://sr0/Track 1.wav` and
94  * `/home/user/.gvfs/cdda on sr0/Track 1.wav` is passed to the
95  * application. It should be noted that it's generally not safe
96  * for applications to rely on the format of a particular URIs.
97  * Different launcher applications (e.g. file managers) may have
98  * different ideas of what a given URI means.
99  */
100
101 struct _GAppLaunchContextPrivate {
102   char **envp;
103 };
104
105 typedef GAppInfoIface GAppInfoInterface;
106 G_DEFINE_INTERFACE (GAppInfo, g_app_info, G_TYPE_OBJECT)
107
108 static void
109 g_app_info_default_init (GAppInfoInterface *iface)
110 {
111 }
112
113
114 /**
115  * g_app_info_dup:
116  * @appinfo: a #GAppInfo.
117  * 
118  * Creates a duplicate of a #GAppInfo.
119  *
120  * Returns: (transfer full): a duplicate of @appinfo.
121  **/
122 GAppInfo *
123 g_app_info_dup (GAppInfo *appinfo)
124 {
125   GAppInfoIface *iface;
126
127   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
128
129   iface = G_APP_INFO_GET_IFACE (appinfo);
130
131   return (* iface->dup) (appinfo);
132 }
133
134 /**
135  * g_app_info_equal:
136  * @appinfo1: the first #GAppInfo.
137  * @appinfo2: the second #GAppInfo.
138  *
139  * Checks if two #GAppInfos are equal.
140  *
141  * Note that the check *may not* compare each individual
142  * field, and only does an identity check. In case detecting changes in the 
143  * contents is needed, program code must additionally compare relevant fields.
144  *
145  * Returns: %TRUE if @appinfo1 is equal to @appinfo2. %FALSE otherwise.
146  **/
147 gboolean
148 g_app_info_equal (GAppInfo *appinfo1,
149                   GAppInfo *appinfo2)
150 {
151   GAppInfoIface *iface;
152
153   g_return_val_if_fail (G_IS_APP_INFO (appinfo1), FALSE);
154   g_return_val_if_fail (G_IS_APP_INFO (appinfo2), FALSE);
155
156   if (G_TYPE_FROM_INSTANCE (appinfo1) != G_TYPE_FROM_INSTANCE (appinfo2))
157     return FALSE;
158   
159   iface = G_APP_INFO_GET_IFACE (appinfo1);
160
161   return (* iface->equal) (appinfo1, appinfo2);
162 }
163
164 /**
165  * g_app_info_get_id:
166  * @appinfo: a #GAppInfo.
167  * 
168  * Gets the ID of an application. An id is a string that
169  * identifies the application. The exact format of the id is
170  * platform dependent. For instance, on Unix this is the
171  * desktop file id from the xdg menu specification.
172  *
173  * Note that the returned ID may be %NULL, depending on how
174  * the @appinfo has been constructed.
175  *
176  * Returns: (nullable): a string containing the application's ID.
177  **/
178 const char *
179 g_app_info_get_id (GAppInfo *appinfo)
180 {
181   GAppInfoIface *iface;
182   
183   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
184
185   iface = G_APP_INFO_GET_IFACE (appinfo);
186
187   return (* iface->get_id) (appinfo);
188 }
189
190 /**
191  * g_app_info_get_name:
192  * @appinfo: a #GAppInfo.
193  * 
194  * Gets the installed name of the application. 
195  *
196  * Returns: the name of the application for @appinfo.
197  **/
198 const char *
199 g_app_info_get_name (GAppInfo *appinfo)
200 {
201   GAppInfoIface *iface;
202   
203   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
204
205   iface = G_APP_INFO_GET_IFACE (appinfo);
206
207   return (* iface->get_name) (appinfo);
208 }
209
210 /**
211  * g_app_info_get_display_name:
212  * @appinfo: a #GAppInfo.
213  *
214  * Gets the display name of the application. The display name is often more
215  * descriptive to the user than the name itself.
216  *
217  * Returns: the display name of the application for @appinfo, or the name if
218  * no display name is available.
219  *
220  * Since: 2.24
221  **/
222 const char *
223 g_app_info_get_display_name (GAppInfo *appinfo)
224 {
225   GAppInfoIface *iface;
226
227   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
228
229   iface = G_APP_INFO_GET_IFACE (appinfo);
230
231   if (iface->get_display_name == NULL)
232     return (* iface->get_name) (appinfo);
233
234   return (* iface->get_display_name) (appinfo);
235 }
236
237 /**
238  * g_app_info_get_description:
239  * @appinfo: a #GAppInfo.
240  * 
241  * Gets a human-readable description of an installed application.
242  *
243  * Returns: (nullable): a string containing a description of the 
244  * application @appinfo, or %NULL if none. 
245  **/
246 const char *
247 g_app_info_get_description (GAppInfo *appinfo)
248 {
249   GAppInfoIface *iface;
250   
251   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
252
253   iface = G_APP_INFO_GET_IFACE (appinfo);
254
255   return (* iface->get_description) (appinfo);
256 }
257
258 /**
259  * g_app_info_get_executable: (virtual get_executable)
260  * @appinfo: a #GAppInfo
261  * 
262  * Gets the executable's name for the installed application.
263  *
264  * Returns: (type filename): a string containing the @appinfo's application
265  * binaries name
266  **/
267 const char *
268 g_app_info_get_executable (GAppInfo *appinfo)
269 {
270   GAppInfoIface *iface;
271   
272   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
273
274   iface = G_APP_INFO_GET_IFACE (appinfo);
275
276   return (* iface->get_executable) (appinfo);
277 }
278
279
280 /**
281  * g_app_info_get_commandline: (virtual get_commandline)
282  * @appinfo: a #GAppInfo
283  * 
284  * Gets the commandline with which the application will be
285  * started.  
286  *
287  * Returns: (nullable) (type filename): a string containing the @appinfo's commandline,
288  *     or %NULL if this information is not available
289  *
290  * Since: 2.20
291  **/
292 const char *
293 g_app_info_get_commandline (GAppInfo *appinfo)
294 {
295   GAppInfoIface *iface;
296   
297   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
298
299   iface = G_APP_INFO_GET_IFACE (appinfo);
300
301   if (iface->get_commandline)
302     return (* iface->get_commandline) (appinfo);
303  
304   return NULL;
305 }
306
307 /**
308  * g_app_info_set_as_default_for_type:
309  * @appinfo: a #GAppInfo.
310  * @content_type: the content type.
311  * @error: a #GError.
312  * 
313  * Sets the application as the default handler for a given type.
314  *
315  * Returns: %TRUE on success, %FALSE on error.
316  **/
317 gboolean
318 g_app_info_set_as_default_for_type (GAppInfo    *appinfo,
319                                     const char  *content_type,
320                                     GError     **error)
321 {
322   GAppInfoIface *iface;
323   
324   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
325   g_return_val_if_fail (content_type != NULL, FALSE);
326
327   iface = G_APP_INFO_GET_IFACE (appinfo);
328
329   return (* iface->set_as_default_for_type) (appinfo, content_type, error);
330 }
331
332 /**
333  * g_app_info_set_as_last_used_for_type:
334  * @appinfo: a #GAppInfo.
335  * @content_type: the content type.
336  * @error: a #GError.
337  *
338  * Sets the application as the last used application for a given type.
339  * This will make the application appear as first in the list returned
340  * by g_app_info_get_recommended_for_type(), regardless of the default
341  * application for that content type.
342  *
343  * Returns: %TRUE on success, %FALSE on error.
344  **/
345 gboolean
346 g_app_info_set_as_last_used_for_type (GAppInfo    *appinfo,
347                                       const char  *content_type,
348                                       GError     **error)
349 {
350   GAppInfoIface *iface;
351   
352   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
353   g_return_val_if_fail (content_type != NULL, FALSE);
354
355   iface = G_APP_INFO_GET_IFACE (appinfo);
356
357   return (* iface->set_as_last_used_for_type) (appinfo, content_type, error);
358 }
359
360 /**
361  * g_app_info_set_as_default_for_extension:
362  * @appinfo: a #GAppInfo.
363  * @extension: (type filename): a string containing the file extension
364  *     (without the dot).
365  * @error: a #GError.
366  * 
367  * Sets the application as the default handler for the given file extension.
368  *
369  * Returns: %TRUE on success, %FALSE on error.
370  **/
371 gboolean
372 g_app_info_set_as_default_for_extension (GAppInfo    *appinfo,
373                                          const char  *extension,
374                                          GError     **error)
375 {
376   GAppInfoIface *iface;
377   
378   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
379   g_return_val_if_fail (extension != NULL, FALSE);
380
381   iface = G_APP_INFO_GET_IFACE (appinfo);
382
383   if (iface->set_as_default_for_extension)
384     return (* iface->set_as_default_for_extension) (appinfo, extension, error);
385
386   g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
387                        "g_app_info_set_as_default_for_extension not supported yet");
388   return FALSE;
389 }
390
391
392 /**
393  * g_app_info_add_supports_type:
394  * @appinfo: a #GAppInfo.
395  * @content_type: a string.
396  * @error: a #GError.
397  * 
398  * Adds a content type to the application information to indicate the 
399  * application is capable of opening files with the given content type.
400  *
401  * Returns: %TRUE on success, %FALSE on error.
402  **/
403 gboolean
404 g_app_info_add_supports_type (GAppInfo    *appinfo,
405                               const char  *content_type,
406                               GError     **error)
407 {
408   GAppInfoIface *iface;
409   
410   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
411   g_return_val_if_fail (content_type != NULL, FALSE);
412
413   iface = G_APP_INFO_GET_IFACE (appinfo);
414
415   if (iface->add_supports_type)
416     return (* iface->add_supports_type) (appinfo, content_type, error);
417
418   g_set_error_literal (error, G_IO_ERROR, 
419                        G_IO_ERROR_NOT_SUPPORTED, 
420                        "g_app_info_add_supports_type not supported yet");
421
422   return FALSE;
423 }
424
425
426 /**
427  * g_app_info_can_remove_supports_type:
428  * @appinfo: a #GAppInfo.
429  * 
430  * Checks if a supported content type can be removed from an application.
431  *
432  * Returns: %TRUE if it is possible to remove supported 
433  *     content types from a given @appinfo, %FALSE if not.
434  **/
435 gboolean
436 g_app_info_can_remove_supports_type (GAppInfo *appinfo)
437 {
438   GAppInfoIface *iface;
439   
440   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
441
442   iface = G_APP_INFO_GET_IFACE (appinfo);
443
444   if (iface->can_remove_supports_type)
445     return (* iface->can_remove_supports_type) (appinfo);
446
447   return FALSE;
448 }
449
450
451 /**
452  * g_app_info_remove_supports_type:
453  * @appinfo: a #GAppInfo.
454  * @content_type: a string.
455  * @error: a #GError.
456  *
457  * Removes a supported type from an application, if possible.
458  * 
459  * Returns: %TRUE on success, %FALSE on error.
460  **/
461 gboolean
462 g_app_info_remove_supports_type (GAppInfo    *appinfo,
463                                  const char  *content_type,
464                                  GError     **error)
465 {
466   GAppInfoIface *iface;
467   
468   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
469   g_return_val_if_fail (content_type != NULL, FALSE);
470
471   iface = G_APP_INFO_GET_IFACE (appinfo);
472
473   if (iface->remove_supports_type)
474     return (* iface->remove_supports_type) (appinfo, content_type, error);
475
476   g_set_error_literal (error, G_IO_ERROR, 
477                        G_IO_ERROR_NOT_SUPPORTED, 
478                        "g_app_info_remove_supports_type not supported yet");
479
480   return FALSE;
481 }
482
483 /**
484  * g_app_info_get_supported_types:
485  * @appinfo: a #GAppInfo that can handle files
486  *
487  * Retrieves the list of content types that @app_info claims to support.
488  * If this information is not provided by the environment, this function
489  * will return %NULL.
490  * This function does not take in consideration associations added with
491  * g_app_info_add_supports_type(), but only those exported directly by
492  * the application.
493  *
494  * Returns: (transfer none) (array zero-terminated=1) (element-type utf8):
495  *    a list of content types.
496  *
497  * Since: 2.34
498  */
499 const char **
500 g_app_info_get_supported_types (GAppInfo *appinfo)
501 {
502   GAppInfoIface *iface;
503
504   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
505
506   iface = G_APP_INFO_GET_IFACE (appinfo);
507
508   if (iface->get_supported_types)
509     return iface->get_supported_types (appinfo);
510   else
511     return NULL;
512 }
513
514
515 /**
516  * g_app_info_get_icon:
517  * @appinfo: a #GAppInfo.
518  * 
519  * Gets the icon for the application.
520  *
521  * Returns: (nullable) (transfer none): the default #GIcon for @appinfo or %NULL
522  * if there is no default icon.
523  **/
524 GIcon *
525 g_app_info_get_icon (GAppInfo *appinfo)
526 {
527   GAppInfoIface *iface;
528   
529   g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
530
531   iface = G_APP_INFO_GET_IFACE (appinfo);
532
533   return (* iface->get_icon) (appinfo);
534 }
535
536
537 /**
538  * g_app_info_launch:
539  * @appinfo: a #GAppInfo
540  * @files: (nullable) (element-type GFile): a #GList of #GFile objects
541  * @context: (nullable): a #GAppLaunchContext or %NULL
542  * @error: a #GError
543  * 
544  * Launches the application. Passes @files to the launched application
545  * as arguments, using the optional @context to get information
546  * about the details of the launcher (like what screen it is on).
547  * On error, @error will be set accordingly.
548  *
549  * To launch the application without arguments pass a %NULL @files list.
550  *
551  * Note that even if the launch is successful the application launched
552  * can fail to start if it runs into problems during startup. There is
553  * no way to detect this.
554  *
555  * Some URIs can be changed when passed through a GFile (for instance
556  * unsupported URIs with strange formats like mailto:), so if you have
557  * a textual URI you want to pass in as argument, consider using
558  * g_app_info_launch_uris() instead.
559  *
560  * The launched application inherits the environment of the launching
561  * process, but it can be modified with g_app_launch_context_setenv()
562  * and g_app_launch_context_unsetenv().
563  *
564  * On UNIX, this function sets the `GIO_LAUNCHED_DESKTOP_FILE`
565  * environment variable with the path of the launched desktop file and
566  * `GIO_LAUNCHED_DESKTOP_FILE_PID` to the process id of the launched
567  * process. This can be used to ignore `GIO_LAUNCHED_DESKTOP_FILE`,
568  * should it be inherited by further processes. The `DISPLAY` and
569  * `DESKTOP_STARTUP_ID` environment variables are also set, based
570  * on information provided in @context.
571  *
572  * Returns: %TRUE on successful launch, %FALSE otherwise.
573  **/
574 gboolean
575 g_app_info_launch (GAppInfo           *appinfo,
576                    GList              *files,
577                    GAppLaunchContext  *launch_context,
578                    GError            **error)
579 {
580   GAppInfoIface *iface;
581   
582   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
583
584   iface = G_APP_INFO_GET_IFACE (appinfo);
585
586   return (* iface->launch) (appinfo, files, launch_context, error);
587 }
588
589
590 /**
591  * g_app_info_supports_uris:
592  * @appinfo: a #GAppInfo.
593  * 
594  * Checks if the application supports reading files and directories from URIs.
595  *
596  * Returns: %TRUE if the @appinfo supports URIs.
597  **/
598 gboolean
599 g_app_info_supports_uris (GAppInfo *appinfo)
600 {
601   GAppInfoIface *iface;
602   
603   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
604
605   iface = G_APP_INFO_GET_IFACE (appinfo);
606
607   return (* iface->supports_uris) (appinfo);
608 }
609
610
611 /**
612  * g_app_info_supports_files:
613  * @appinfo: a #GAppInfo.
614  * 
615  * Checks if the application accepts files as arguments.
616  *
617  * Returns: %TRUE if the @appinfo supports files.
618  **/
619 gboolean
620 g_app_info_supports_files (GAppInfo *appinfo)
621 {
622   GAppInfoIface *iface;
623   
624   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
625
626   iface = G_APP_INFO_GET_IFACE (appinfo);
627
628   return (* iface->supports_files) (appinfo);
629 }
630
631
632 /**
633  * g_app_info_launch_uris:
634  * @appinfo: a #GAppInfo
635  * @uris: (nullable) (element-type utf8): a #GList containing URIs to launch.
636  * @context: (nullable): a #GAppLaunchContext or %NULL
637  * @error: a #GError
638  * 
639  * Launches the application. This passes the @uris to the launched application
640  * as arguments, using the optional @context to get information
641  * about the details of the launcher (like what screen it is on).
642  * On error, @error will be set accordingly.
643  *
644  * To launch the application without arguments pass a %NULL @uris list.
645  *
646  * Note that even if the launch is successful the application launched
647  * can fail to start if it runs into problems during startup. There is
648  * no way to detect this.
649  *
650  * Returns: %TRUE on successful launch, %FALSE otherwise.
651  **/
652 gboolean
653 g_app_info_launch_uris (GAppInfo           *appinfo,
654                         GList              *uris,
655                         GAppLaunchContext  *launch_context,
656                         GError            **error)
657 {
658   GAppInfoIface *iface;
659   
660   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
661
662   iface = G_APP_INFO_GET_IFACE (appinfo);
663
664   return (* iface->launch_uris) (appinfo, uris, launch_context, error);
665 }
666
667 /**
668  * g_app_info_launch_uris_async:
669  * @appinfo: a #GAppInfo
670  * @uris: (nullable) (element-type utf8): a #GList containing URIs to launch.
671  * @context: (nullable): a #GAppLaunchContext or %NULL
672  * @cancellable: (nullable): a #GCancellable
673  * @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
674  * @user_data: (nullable): data to pass to @callback
675  *
676  * Async version of g_app_info_launch_uris().
677  *
678  * The @callback is invoked immediately after the application launch, but it
679  * waits for activation in case of D-Bus–activated applications and also provides
680  * extended error information for sandboxed applications, see notes for
681  * g_app_info_launch_default_for_uri_async().
682  *
683  * Since: 2.60
684  **/
685 void
686 g_app_info_launch_uris_async (GAppInfo           *appinfo,
687                               GList              *uris,
688                               GAppLaunchContext  *context,
689                               GCancellable       *cancellable,
690                               GAsyncReadyCallback callback,
691                               gpointer            user_data)
692 {
693   GAppInfoIface *iface;
694
695   g_return_if_fail (G_IS_APP_INFO (appinfo));
696   g_return_if_fail (context == NULL || G_IS_APP_LAUNCH_CONTEXT (context));
697   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
698
699   iface = G_APP_INFO_GET_IFACE (appinfo);
700   if (iface->launch_uris_async == NULL)
701     {
702       GTask *task;
703
704       task = g_task_new (appinfo, cancellable, callback, user_data);
705       g_task_set_source_tag (task, g_app_info_launch_uris_async);
706       g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
707                                "Operation not supported for the current backend.");
708       g_object_unref (task);
709
710       return;
711     }
712
713   (* iface->launch_uris_async) (appinfo, uris, context, cancellable, callback, user_data);
714 }
715
716 /**
717  * g_app_info_launch_uris_finish:
718  * @appinfo: a #GAppInfo
719  * @result: a #GAsyncResult
720  * @error: (nullable): a #GError
721  *
722  * Finishes a g_app_info_launch_uris_async() operation.
723  *
724  * Returns: %TRUE on successful launch, %FALSE otherwise.
725  *
726  * Since: 2.60
727  */
728 gboolean
729 g_app_info_launch_uris_finish (GAppInfo     *appinfo,
730                                GAsyncResult *result,
731                                GError      **error)
732 {
733   GAppInfoIface *iface;
734
735   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
736
737   iface = G_APP_INFO_GET_IFACE (appinfo);
738   if (iface->launch_uris_finish == NULL)
739     {
740       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
741                            "Operation not supported for the current backend.");
742       return FALSE;
743     }
744
745   return (* iface->launch_uris_finish) (appinfo, result, error);
746 }
747
748 /**
749  * g_app_info_should_show:
750  * @appinfo: a #GAppInfo.
751  *
752  * Checks if the application info should be shown in menus that 
753  * list available applications.
754  * 
755  * Returns: %TRUE if the @appinfo should be shown, %FALSE otherwise.
756  **/
757 gboolean
758 g_app_info_should_show (GAppInfo *appinfo)
759 {
760   GAppInfoIface *iface;
761   
762   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
763
764   iface = G_APP_INFO_GET_IFACE (appinfo);
765
766   return (* iface->should_show) (appinfo);
767 }
768
769 /**
770  * g_app_info_launch_default_for_uri:
771  * @uri: the uri to show
772  * @context: (nullable): an optional #GAppLaunchContext
773  * @error: (nullable): return location for an error, or %NULL
774  *
775  * Utility function that launches the default application
776  * registered to handle the specified uri. Synchronous I/O
777  * is done on the uri to detect the type of the file if
778  * required.
779  *
780  * The D-Bus–activated applications don't have to be started if your application
781  * terminates too soon after this function. To prevent this, use
782  * g_app_info_launch_default_for_uri_async() instead.
783  *
784  * Returns: %TRUE on success, %FALSE on error.
785  **/
786 gboolean
787 g_app_info_launch_default_for_uri (const char         *uri,
788                                    GAppLaunchContext  *launch_context,
789                                    GError            **error)
790 {
791   char *uri_scheme;
792   GAppInfo *app_info = NULL;
793   gboolean res = FALSE;
794
795   /* g_file_query_default_handler() calls
796    * g_app_info_get_default_for_uri_scheme() too, but we have to do it
797    * here anyway in case GFile can't parse @uri correctly.
798    */
799   uri_scheme = g_uri_parse_scheme (uri);
800   if (uri_scheme && uri_scheme[0] != '\0')
801     app_info = g_app_info_get_default_for_uri_scheme (uri_scheme);
802   g_free (uri_scheme);
803
804   if (!app_info)
805     {
806       GFile *file;
807
808       file = g_file_new_for_uri (uri);
809       app_info = g_file_query_default_handler (file, NULL, error);
810       g_object_unref (file);
811     }
812
813   if (app_info)
814     {
815       GList l;
816
817       l.data = (char *)uri;
818       l.next = l.prev = NULL;
819       res = g_app_info_launch_uris (app_info, &l, launch_context, error);
820       g_object_unref (app_info);
821     }
822
823 #ifdef G_OS_UNIX
824   if (!res && glib_should_use_portal ())
825     {
826       const char *parent_window = NULL;
827
828       /* Reset any error previously set by launch_default_for_uri */
829       g_clear_error (error);
830
831       if (launch_context && launch_context->priv->envp)
832         parent_window = g_environ_getenv (launch_context->priv->envp, "PARENT_WINDOW_ID");
833
834       return g_openuri_portal_open_uri (uri, parent_window, error);
835     }
836 #endif
837
838   return res;
839 }
840
841 typedef struct
842 {
843   gchar *uri;
844   GAppLaunchContext *context;
845 } LaunchDefaultForUriData;
846
847 static void
848 launch_default_for_uri_data_free (LaunchDefaultForUriData *data)
849 {
850   g_free (data->uri);
851   g_clear_object (&data->context);
852   g_free (data);
853 }
854
855 #ifdef G_OS_UNIX
856 static void
857 launch_default_for_uri_portal_open_uri_cb (GObject      *object,
858                                            GAsyncResult *result,
859                                            gpointer      user_data)
860 {
861   GTask *task = G_TASK (user_data);
862   GError *error = NULL;
863
864   if (g_openuri_portal_open_uri_finish (result, &error))
865     g_task_return_boolean (task, TRUE);
866   else
867     g_task_return_error (task, g_steal_pointer (&error));
868   g_object_unref (task);
869 }
870 #endif
871
872 static void
873 launch_default_for_uri_portal_open_uri (GTask *task, GError *error)
874 {
875 #ifdef G_OS_UNIX
876   LaunchDefaultForUriData *data = g_task_get_task_data (task);
877   GCancellable *cancellable = g_task_get_cancellable (task);
878
879   if (glib_should_use_portal ())
880     {
881       const char *parent_window = NULL;
882
883       /* Reset any error previously set by launch_default_for_uri */
884       g_error_free (error);
885
886       if (data->context && data->context->priv->envp)
887         parent_window = g_environ_getenv (data->context->priv->envp,
888                                           "PARENT_WINDOW_ID");
889
890       g_openuri_portal_open_uri_async (data->uri,
891                                        parent_window,
892                                        cancellable,
893                                        launch_default_for_uri_portal_open_uri_cb,
894                                        g_steal_pointer (&task));
895       return;
896     }
897 #endif
898
899   g_task_return_error (task, g_steal_pointer (&error));
900   g_object_unref (task);
901 }
902
903 static void
904 launch_default_for_uri_launch_uris_cb (GObject      *object,
905                                        GAsyncResult *result,
906                                        gpointer      user_data)
907 {
908   GAppInfo *app_info = G_APP_INFO (object);
909   GTask *task = G_TASK (user_data);
910   GError *error = NULL;
911
912   if (g_app_info_launch_uris_finish (app_info, result, &error))
913     {
914       g_task_return_boolean (task, TRUE);
915       g_object_unref (task);
916     }
917   else
918     launch_default_for_uri_portal_open_uri (g_steal_pointer (&task), g_steal_pointer (&error));
919 }
920
921 static void
922 launch_default_for_uri_launch_uris (GTask *task,
923                                     GAppInfo *app_info)
924 {
925   GCancellable *cancellable = g_task_get_cancellable (task);
926   GList l;
927   LaunchDefaultForUriData *data = g_task_get_task_data (task);
928
929   l.data = (char *)data->uri;
930   l.next = l.prev = NULL;
931   g_app_info_launch_uris_async (app_info,
932                                 &l,
933                                 data->context,
934                                 cancellable,
935                                 launch_default_for_uri_launch_uris_cb,
936                                 g_steal_pointer (&task));
937   g_object_unref (app_info);
938 }
939
940 static void
941 launch_default_for_uri_default_handler_cb (GObject      *object,
942                                            GAsyncResult *result,
943                                            gpointer      user_data)
944 {
945   GFile *file = G_FILE (object);
946   GTask *task = G_TASK (user_data);
947   GAppInfo *app_info = NULL;
948   GError *error = NULL;
949
950   app_info = g_file_query_default_handler_finish (file, result, &error);
951   if (app_info)
952     launch_default_for_uri_launch_uris (g_steal_pointer (&task), g_steal_pointer (&app_info));
953   else
954     launch_default_for_uri_portal_open_uri (g_steal_pointer (&task), g_steal_pointer (&error));
955 }
956
957 /**
958  * g_app_info_launch_default_for_uri_async:
959  * @uri: the uri to show
960  * @context: (nullable): an optional #GAppLaunchContext
961  * @cancellable: (nullable): a #GCancellable
962  * @callback: (nullable): a #GAsyncReadyCallback to call when the request is done
963  * @user_data: (nullable): data to pass to @callback
964  *
965  * Async version of g_app_info_launch_default_for_uri().
966  *
967  * This version is useful if you are interested in receiving
968  * error information in the case where the application is
969  * sandboxed and the portal may present an application chooser
970  * dialog to the user.
971  *
972  * This is also useful if you want to be sure that the D-Bus–activated
973  * applications are really started before termination and if you are interested
974  * in receiving error information from their activation.
975  *
976  * Since: 2.50
977  */
978 void
979 g_app_info_launch_default_for_uri_async (const char          *uri,
980                                          GAppLaunchContext   *context,
981                                          GCancellable        *cancellable,
982                                          GAsyncReadyCallback  callback,
983                                          gpointer             user_data)
984 {
985   GTask *task;
986   char *uri_scheme;
987   GAppInfo *app_info = NULL;
988   LaunchDefaultForUriData *data;
989
990   g_return_if_fail (uri != NULL);
991
992   task = g_task_new (NULL, cancellable, callback, user_data);
993   g_task_set_source_tag (task, g_app_info_launch_default_for_uri_async);
994
995   data = g_new (LaunchDefaultForUriData, 1);
996   data->uri = g_strdup (uri);
997   data->context = (context != NULL) ? g_object_ref (context) : NULL;
998   g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) launch_default_for_uri_data_free);
999
1000   /* g_file_query_default_handler_async() calls
1001    * g_app_info_get_default_for_uri_scheme() too, but we have to do it
1002    * here anyway in case GFile can't parse @uri correctly.
1003    */
1004   uri_scheme = g_uri_parse_scheme (uri);
1005   if (uri_scheme && uri_scheme[0] != '\0')
1006     /* FIXME: The following still uses blocking calls. */
1007     app_info = g_app_info_get_default_for_uri_scheme (uri_scheme);
1008   g_free (uri_scheme);
1009
1010   if (!app_info)
1011     {
1012       GFile *file;
1013
1014       file = g_file_new_for_uri (uri);
1015       g_file_query_default_handler_async (file,
1016                                           G_PRIORITY_DEFAULT,
1017                                           cancellable,
1018                                           launch_default_for_uri_default_handler_cb,
1019                                           g_steal_pointer (&task));
1020       g_object_unref (file);
1021     }
1022   else
1023     launch_default_for_uri_launch_uris (g_steal_pointer (&task), g_steal_pointer (&app_info));
1024 }
1025
1026 /**
1027  * g_app_info_launch_default_for_uri_finish:
1028  * @result: a #GAsyncResult
1029  * @error: (nullable): return location for an error, or %NULL
1030  *
1031  * Finishes an asynchronous launch-default-for-uri operation.
1032  *
1033  * Returns: %TRUE if the launch was successful, %FALSE if @error is set
1034  *
1035  * Since: 2.50
1036  */
1037 gboolean
1038 g_app_info_launch_default_for_uri_finish (GAsyncResult  *result,
1039                                           GError       **error)
1040 {
1041   g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
1042
1043   return g_task_propagate_boolean (G_TASK (result), error);
1044 }
1045
1046 /**
1047  * g_app_info_can_delete:
1048  * @appinfo: a #GAppInfo
1049  *
1050  * Obtains the information whether the #GAppInfo can be deleted.
1051  * See g_app_info_delete().
1052  *
1053  * Returns: %TRUE if @appinfo can be deleted
1054  *
1055  * Since: 2.20
1056  */
1057 gboolean
1058 g_app_info_can_delete (GAppInfo *appinfo)
1059 {
1060   GAppInfoIface *iface;
1061   
1062   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
1063
1064   iface = G_APP_INFO_GET_IFACE (appinfo);
1065
1066   if (iface->can_delete)
1067     return (* iface->can_delete) (appinfo);
1068  
1069   return FALSE; 
1070 }
1071
1072
1073 /**
1074  * g_app_info_delete:
1075  * @appinfo: a #GAppInfo
1076  *
1077  * Tries to delete a #GAppInfo.
1078  *
1079  * On some platforms, there may be a difference between user-defined
1080  * #GAppInfos which can be deleted, and system-wide ones which cannot.
1081  * See g_app_info_can_delete().
1082  *
1083  * Virtual: do_delete
1084  * Returns: %TRUE if @appinfo has been deleted
1085  *
1086  * Since: 2.20
1087  */
1088 gboolean
1089 g_app_info_delete (GAppInfo *appinfo)
1090 {
1091   GAppInfoIface *iface;
1092   
1093   g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
1094
1095   iface = G_APP_INFO_GET_IFACE (appinfo);
1096
1097   if (iface->do_delete)
1098     return (* iface->do_delete) (appinfo);
1099  
1100   return FALSE; 
1101 }
1102
1103
1104 enum {
1105   LAUNCH_FAILED,
1106   LAUNCHED,
1107   LAST_SIGNAL
1108 };
1109
1110 static guint signals[LAST_SIGNAL] = { 0 };
1111
1112 G_DEFINE_TYPE_WITH_PRIVATE (GAppLaunchContext, g_app_launch_context, G_TYPE_OBJECT)
1113
1114 /**
1115  * g_app_launch_context_new:
1116  * 
1117  * Creates a new application launch context. This is not normally used,
1118  * instead you instantiate a subclass of this, such as #GdkAppLaunchContext.
1119  *
1120  * Returns: a #GAppLaunchContext.
1121  **/
1122 GAppLaunchContext *
1123 g_app_launch_context_new (void)
1124 {
1125   return g_object_new (G_TYPE_APP_LAUNCH_CONTEXT, NULL);
1126 }
1127
1128 static void
1129 g_app_launch_context_finalize (GObject *object)
1130 {
1131   GAppLaunchContext *context = G_APP_LAUNCH_CONTEXT (object);
1132
1133   g_strfreev (context->priv->envp);
1134
1135   G_OBJECT_CLASS (g_app_launch_context_parent_class)->finalize (object);
1136 }
1137
1138 static void
1139 g_app_launch_context_class_init (GAppLaunchContextClass *klass)
1140 {
1141   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1142
1143   object_class->finalize = g_app_launch_context_finalize;
1144
1145   /**
1146    * GAppLaunchContext::launch-failed:
1147    * @context: the object emitting the signal
1148    * @startup_notify_id: the startup notification id for the failed launch
1149    *
1150    * The ::launch-failed signal is emitted when a #GAppInfo launch
1151    * fails. The startup notification id is provided, so that the launcher
1152    * can cancel the startup notification.
1153    *
1154    * Since: 2.36
1155    */
1156   signals[LAUNCH_FAILED] = g_signal_new (I_("launch-failed"),
1157                                          G_OBJECT_CLASS_TYPE (object_class),
1158                                          G_SIGNAL_RUN_LAST,
1159                                          G_STRUCT_OFFSET (GAppLaunchContextClass, launch_failed),
1160                                          NULL, NULL, NULL,
1161                                          G_TYPE_NONE, 1, G_TYPE_STRING);
1162
1163   /**
1164    * GAppLaunchContext::launched:
1165    * @context: the object emitting the signal
1166    * @info: the #GAppInfo that was just launched
1167    * @platform_data: additional platform-specific data for this launch
1168    *
1169    * The ::launched signal is emitted when a #GAppInfo is successfully
1170    * launched. The @platform_data is an GVariant dictionary mapping
1171    * strings to variants (ie a{sv}), which contains additional,
1172    * platform-specific data about this launch. On UNIX, at least the
1173    * "pid" and "startup-notification-id" keys will be present.
1174    *
1175    * Since: 2.36
1176    */
1177   signals[LAUNCHED] = g_signal_new (I_("launched"),
1178                                     G_OBJECT_CLASS_TYPE (object_class),
1179                                     G_SIGNAL_RUN_LAST,
1180                                     G_STRUCT_OFFSET (GAppLaunchContextClass, launched),
1181                                     NULL, NULL,
1182                                     _g_cclosure_marshal_VOID__OBJECT_VARIANT,
1183                                     G_TYPE_NONE, 2,
1184                                     G_TYPE_APP_INFO, G_TYPE_VARIANT);
1185   g_signal_set_va_marshaller (signals[LAUNCHED],
1186                               G_TYPE_FROM_CLASS (klass),
1187                               _g_cclosure_marshal_VOID__OBJECT_VARIANTv);
1188 }
1189
1190 static void
1191 g_app_launch_context_init (GAppLaunchContext *context)
1192 {
1193   context->priv = g_app_launch_context_get_instance_private (context);
1194 }
1195
1196 /**
1197  * g_app_launch_context_setenv:
1198  * @context: a #GAppLaunchContext
1199  * @variable: (type filename): the environment variable to set
1200  * @value: (type filename): the value for to set the variable to.
1201  *
1202  * Arranges for @variable to be set to @value in the child's
1203  * environment when @context is used to launch an application.
1204  *
1205  * Since: 2.32
1206  */
1207 void
1208 g_app_launch_context_setenv (GAppLaunchContext *context,
1209                              const char        *variable,
1210                              const char        *value)
1211 {
1212   g_return_if_fail (G_IS_APP_LAUNCH_CONTEXT (context));
1213   g_return_if_fail (variable != NULL);
1214   g_return_if_fail (value != NULL);
1215
1216   if (!context->priv->envp)
1217     context->priv->envp = g_get_environ ();
1218
1219   context->priv->envp =
1220     g_environ_setenv (context->priv->envp, variable, value, TRUE);
1221 }
1222
1223 /**
1224  * g_app_launch_context_unsetenv:
1225  * @context: a #GAppLaunchContext
1226  * @variable: (type filename): the environment variable to remove
1227  *
1228  * Arranges for @variable to be unset in the child's environment
1229  * when @context is used to launch an application.
1230  *
1231  * Since: 2.32
1232  */
1233 void
1234 g_app_launch_context_unsetenv (GAppLaunchContext *context,
1235                                const char        *variable)
1236 {
1237   g_return_if_fail (G_IS_APP_LAUNCH_CONTEXT (context));
1238   g_return_if_fail (variable != NULL);
1239
1240   if (!context->priv->envp)
1241     context->priv->envp = g_get_environ ();
1242
1243   context->priv->envp =
1244     g_environ_unsetenv (context->priv->envp, variable);
1245 }
1246
1247 /**
1248  * g_app_launch_context_get_environment:
1249  * @context: a #GAppLaunchContext
1250  *
1251  * Gets the complete environment variable list to be passed to
1252  * the child process when @context is used to launch an application.
1253  * This is a %NULL-terminated array of strings, where each string has
1254  * the form `KEY=VALUE`.
1255  *
1256  * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
1257  *     the child's environment
1258  *
1259  * Since: 2.32
1260  */
1261 char **
1262 g_app_launch_context_get_environment (GAppLaunchContext *context)
1263 {
1264   g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL);
1265
1266   if (!context->priv->envp)
1267     context->priv->envp = g_get_environ ();
1268
1269   return g_strdupv (context->priv->envp);
1270 }
1271
1272 /**
1273  * g_app_launch_context_get_display:
1274  * @context: a #GAppLaunchContext
1275  * @info: a #GAppInfo
1276  * @files: (element-type GFile): a #GList of #GFile objects
1277  *
1278  * Gets the display string for the @context. This is used to ensure new
1279  * applications are started on the same display as the launching
1280  * application, by setting the `DISPLAY` environment variable.
1281  *
1282  * Returns: (nullable): a display string for the display.
1283  */
1284 char *
1285 g_app_launch_context_get_display (GAppLaunchContext *context,
1286                                   GAppInfo          *info,
1287                                   GList             *files)
1288 {
1289   GAppLaunchContextClass *class;
1290
1291   g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL);
1292   g_return_val_if_fail (G_IS_APP_INFO (info), NULL);
1293
1294   class = G_APP_LAUNCH_CONTEXT_GET_CLASS (context);
1295
1296   if (class->get_display == NULL)
1297     return NULL;
1298
1299   return class->get_display (context, info, files);
1300 }
1301
1302 /**
1303  * g_app_launch_context_get_startup_notify_id:
1304  * @context: a #GAppLaunchContext
1305  * @info: a #GAppInfo
1306  * @files: (element-type GFile): a #GList of of #GFile objects
1307  * 
1308  * Initiates startup notification for the application and returns the
1309  * `DESKTOP_STARTUP_ID` for the launched operation, if supported.
1310  *
1311  * Startup notification IDs are defined in the 
1312  * [FreeDesktop.Org Startup Notifications standard](http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt).
1313  *
1314  * Returns: (nullable): a startup notification ID for the application, or %NULL if
1315  *     not supported.
1316  **/
1317 char *
1318 g_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
1319                                             GAppInfo          *info,
1320                                             GList             *files)
1321 {
1322   GAppLaunchContextClass *class;
1323
1324   g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL);
1325   g_return_val_if_fail (G_IS_APP_INFO (info), NULL);
1326
1327   class = G_APP_LAUNCH_CONTEXT_GET_CLASS (context);
1328
1329   if (class->get_startup_notify_id == NULL)
1330     return NULL;
1331
1332   return class->get_startup_notify_id (context, info, files);
1333 }
1334
1335
1336 /**
1337  * g_app_launch_context_launch_failed:
1338  * @context: a #GAppLaunchContext.
1339  * @startup_notify_id: the startup notification id that was returned by g_app_launch_context_get_startup_notify_id().
1340  *
1341  * Called when an application has failed to launch, so that it can cancel
1342  * the application startup notification started in g_app_launch_context_get_startup_notify_id().
1343  * 
1344  **/
1345 void
1346 g_app_launch_context_launch_failed (GAppLaunchContext *context,
1347                                     const char        *startup_notify_id)
1348 {
1349   g_return_if_fail (G_IS_APP_LAUNCH_CONTEXT (context));
1350   g_return_if_fail (startup_notify_id != NULL);
1351
1352   g_signal_emit (context, signals[LAUNCH_FAILED], 0, startup_notify_id);
1353 }
1354
1355
1356 /**
1357  * SECTION:gappinfomonitor
1358  * @short_description: Monitor application information for changes
1359  *
1360  * #GAppInfoMonitor is a very simple object used for monitoring the app
1361  * info database for changes (ie: newly installed or removed
1362  * applications).
1363  *
1364  * Call g_app_info_monitor_get() to get a #GAppInfoMonitor and connect
1365  * to the "changed" signal.
1366  *
1367  * In the usual case, applications should try to make note of the change
1368  * (doing things like invalidating caches) but not act on it.  In
1369  * particular, applications should avoid making calls to #GAppInfo APIs
1370  * in response to the change signal, deferring these until the time that
1371  * the data is actually required.  The exception to this case is when
1372  * application information is actually being displayed on the screen
1373  * (eg: during a search or when the list of all applications is shown).
1374  * The reason for this is that changes to the list of installed
1375  * applications often come in groups (like during system updates) and
1376  * rescanning the list on every change is pointless and expensive.
1377  *
1378  * Since: 2.40
1379  **/
1380
1381 /**
1382  * GAppInfoMonitor:
1383  *
1384  * The only thing you can do with this is to get it via
1385  * g_app_info_monitor_get() and connect to the "changed" signal.
1386  *
1387  * Since: 2.40
1388  **/
1389
1390 typedef struct _GAppInfoMonitorClass GAppInfoMonitorClass;
1391
1392 struct _GAppInfoMonitor
1393 {
1394   GObject parent_instance;
1395   GMainContext *context;
1396 };
1397
1398 struct _GAppInfoMonitorClass
1399 {
1400   GObjectClass parent_class;
1401 };
1402
1403 static GContextSpecificGroup g_app_info_monitor_group;
1404 static guint                 g_app_info_monitor_changed_signal;
1405
1406 G_DEFINE_TYPE (GAppInfoMonitor, g_app_info_monitor, G_TYPE_OBJECT)
1407
1408 static void
1409 g_app_info_monitor_finalize (GObject *object)
1410 {
1411   GAppInfoMonitor *monitor = G_APP_INFO_MONITOR (object);
1412
1413   g_context_specific_group_remove (&g_app_info_monitor_group, monitor->context, monitor, NULL);
1414
1415   G_OBJECT_CLASS (g_app_info_monitor_parent_class)->finalize (object);
1416 }
1417
1418 static void
1419 g_app_info_monitor_init (GAppInfoMonitor *monitor)
1420 {
1421 }
1422
1423 static void
1424 g_app_info_monitor_class_init (GAppInfoMonitorClass *class)
1425 {
1426   GObjectClass *object_class = G_OBJECT_CLASS (class);
1427
1428   /**
1429    * GAppInfoMonitor::changed:
1430    *
1431    * Signal emitted when the app info database for changes (ie: newly installed
1432    * or removed applications).
1433    **/
1434   g_app_info_monitor_changed_signal = g_signal_new (I_("changed"), G_TYPE_APP_INFO_MONITOR, G_SIGNAL_RUN_FIRST,
1435                                                     0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1436
1437   object_class->finalize = g_app_info_monitor_finalize;
1438 }
1439
1440 /**
1441  * g_app_info_monitor_get:
1442  *
1443  * Gets the #GAppInfoMonitor for the current thread-default main
1444  * context.
1445  *
1446  * The #GAppInfoMonitor will emit a "changed" signal in the
1447  * thread-default main context whenever the list of installed
1448  * applications (as reported by g_app_info_get_all()) may have changed.
1449  *
1450  * You must only call g_object_unref() on the return value from under
1451  * the same main context as you created it.
1452  *
1453  * Returns: (transfer full): a reference to a #GAppInfoMonitor
1454  *
1455  * Since: 2.40
1456  **/
1457 GAppInfoMonitor *
1458 g_app_info_monitor_get (void)
1459 {
1460   return g_context_specific_group_get (&g_app_info_monitor_group,
1461                                        G_TYPE_APP_INFO_MONITOR,
1462                                        G_STRUCT_OFFSET (GAppInfoMonitor, context),
1463                                        NULL);
1464 }
1465
1466 void
1467 g_app_info_monitor_fire (void)
1468 {
1469   g_context_specific_group_emit (&g_app_info_monitor_group, g_app_info_monitor_changed_signal);
1470 }