Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2006-2007 Red Hat, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : *
20 : : * Author: Alexander Larsson <alexl@redhat.com>
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include "gappinfo.h"
26 : : #include "gappinfoprivate.h"
27 : : #include "gcontextspecificgroup.h"
28 : : #include "gdesktopappinfo.h"
29 : : #include "gtask.h"
30 : : #include "gcancellable.h"
31 : :
32 : : #include "glibintl.h"
33 : : #include "gmarshal-internal.h"
34 : : #include <gioerror.h>
35 : : #include <gfile.h>
36 : :
37 : : #ifdef G_OS_UNIX
38 : : #include "gdbusconnection.h"
39 : : #include "gdbusmessage.h"
40 : : #include "gportalsupport.h"
41 : : #include "gunixfdlist.h"
42 : : #include "gopenuriportal.h"
43 : : #include <sys/types.h>
44 : : #include <sys/stat.h>
45 : : #include <fcntl.h>
46 : : #endif
47 : :
48 : : /**
49 : : * GAppInfo:
50 : : *
51 : : * Information about an installed application and methods to launch
52 : : * it (with file arguments).
53 : :
54 : : * `GAppInfo` and `GAppLaunchContext` are used for describing and launching
55 : : * applications installed on the system.
56 : : *
57 : : * As of GLib 2.20, URIs will always be converted to POSIX paths
58 : : * (using [method@Gio.File.get_path]) when using [method@Gio.AppInfo.launch]
59 : : * even if the application requested an URI and not a POSIX path. For example
60 : : * for a desktop-file based application with the following Exec key:
61 : : *
62 : : * ```
63 : : * Exec=totem %U
64 : : * ```
65 : : *
66 : : * and a single URI, `sftp://foo/file.avi`, then
67 : : * `/home/user/.gvfs/sftp on foo/file.avi` will be passed. This will only work
68 : : * if a set of suitable GIO extensions (such as GVfs 2.26 compiled with FUSE
69 : : * support), is available and operational; if this is not the case, the URI
70 : : * will be passed unmodified to the application. Some URIs, such as `mailto:`,
71 : : * of course cannot be mapped to a POSIX path (in GVfs there’s no FUSE mount
72 : : * for it); such URIs will be passed unmodified to the application.
73 : : *
74 : : * Specifically for GVfs 2.26 and later, the POSIX URI will be mapped
75 : : * back to the GIO URI in the [iface@Gio.File] constructors (since GVfs
76 : : * implements the GVfs extension point). As such, if the application
77 : : * needs to examine the URI, it needs to use [method@Gio.File.get_uri]
78 : : * or similar on [iface@Gio.File]. In other words, an application cannot
79 : : * assume that the URI passed to e.g. [func@Gio.File.new_for_commandline_arg]
80 : : * is equal to the result of [method@Gio.File.get_uri]. The following snippet
81 : : * illustrates this:
82 : : *
83 : : * ```c
84 : : * GFile *f;
85 : : * char *uri;
86 : : *
87 : : * file = g_file_new_for_commandline_arg (uri_from_commandline);
88 : : *
89 : : * uri = g_file_get_uri (file);
90 : : * strcmp (uri, uri_from_commandline) == 0;
91 : : * g_free (uri);
92 : : *
93 : : * if (g_file_has_uri_scheme (file, "cdda"))
94 : : * {
95 : : * // do something special with uri
96 : : * }
97 : : * g_object_unref (file);
98 : : * ```
99 : : *
100 : : * This code will work when both `cdda://sr0/Track 1.wav` and
101 : : * `/home/user/.gvfs/cdda on sr0/Track 1.wav` is passed to the
102 : : * application. It should be noted that it’s generally not safe
103 : : * for applications to rely on the format of a particular URIs.
104 : : * Different launcher applications (e.g. file managers) may have
105 : : * different ideas of what a given URI means.
106 : : */
107 : :
108 : : struct _GAppLaunchContextPrivate {
109 : : char **envp;
110 : : };
111 : :
112 : : typedef GAppInfoIface GAppInfoInterface;
113 : 925 : G_DEFINE_INTERFACE (GAppInfo, g_app_info, G_TYPE_OBJECT)
114 : :
115 : : static void
116 : 28 : g_app_info_default_init (GAppInfoInterface *iface)
117 : : {
118 : 28 : }
119 : :
120 : : /**
121 : : * g_app_info_create_from_commandline:
122 : : * @commandline: (type filename): the command line to use
123 : : * @application_name: (nullable): the application name, or `NULL` to use @commandline
124 : : * @flags: flags that can specify details of the created [iface@Gio.AppInfo]
125 : : * @error: a [type@GLib.Error] location to store the error occurring,
126 : : * `NULL` to ignore.
127 : : *
128 : : * Creates a new [iface@Gio.AppInfo] from the given information.
129 : : *
130 : : * Note that for @commandline, the quoting rules of the `Exec` key of the
131 : : * [freedesktop.org Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec)
132 : : * are applied. For example, if the @commandline contains
133 : : * percent-encoded URIs, the percent-character must be doubled in order to prevent it from
134 : : * being swallowed by `Exec` key unquoting. See
135 : : * [the specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s07.html)
136 : : * for exact quoting rules.
137 : : *
138 : : * Returns: (transfer full): new [iface@Gio.AppInfo] for given command.
139 : : **/
140 : : GAppInfo *
141 : 51 : g_app_info_create_from_commandline (const char *commandline,
142 : : const char *application_name,
143 : : GAppInfoCreateFlags flags,
144 : : GError **error)
145 : : {
146 : 51 : g_return_val_if_fail (commandline, NULL);
147 : 51 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
148 : :
149 : 51 : return g_app_info_create_from_commandline_impl (commandline, application_name,
150 : : flags, error);
151 : : }
152 : :
153 : : /**
154 : : * g_app_info_dup:
155 : : * @appinfo: the app info
156 : : *
157 : : * Creates a duplicate of a [iface@Gio.AppInfo].
158 : : *
159 : : * Returns: (transfer full): a duplicate of @appinfo.
160 : : **/
161 : : GAppInfo *
162 : 1 : g_app_info_dup (GAppInfo *appinfo)
163 : : {
164 : : GAppInfoIface *iface;
165 : :
166 : 1 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
167 : :
168 : 1 : iface = G_APP_INFO_GET_IFACE (appinfo);
169 : :
170 : 1 : return (* iface->dup) (appinfo);
171 : : }
172 : :
173 : : /**
174 : : * g_app_info_equal:
175 : : * @appinfo1: the first [iface@Gio.AppInfo].
176 : : * @appinfo2: the second [iface@Gio.AppInfo].
177 : : *
178 : : * Checks if two [iface@Gio.AppInfo]s are equal.
179 : : *
180 : : * Note that the check *may not* compare each individual field, and only does
181 : : * an identity check. In case detecting changes in the contents is needed,
182 : : * program code must additionally compare relevant fields.
183 : : *
184 : : * Returns: `TRUE` if @appinfo1 is equal to @appinfo2. `FALSE` otherwise.
185 : : **/
186 : : gboolean
187 : 62 : g_app_info_equal (GAppInfo *appinfo1,
188 : : GAppInfo *appinfo2)
189 : : {
190 : : GAppInfoIface *iface;
191 : :
192 : 62 : g_return_val_if_fail (G_IS_APP_INFO (appinfo1), FALSE);
193 : 62 : g_return_val_if_fail (G_IS_APP_INFO (appinfo2), FALSE);
194 : :
195 : 62 : if (G_TYPE_FROM_INSTANCE (appinfo1) != G_TYPE_FROM_INSTANCE (appinfo2))
196 : 0 : return FALSE;
197 : :
198 : 62 : iface = G_APP_INFO_GET_IFACE (appinfo1);
199 : :
200 : 62 : return (* iface->equal) (appinfo1, appinfo2);
201 : : }
202 : :
203 : : /**
204 : : * g_app_info_get_id:
205 : : * @appinfo: the app info
206 : : *
207 : : * Gets the ID of an application. An id is a string that identifies the
208 : : * application. The exact format of the id is platform dependent. For instance,
209 : : * on Unix this is the desktop file id from the xdg menu specification.
210 : : *
211 : : * Note that the returned ID may be `NULL`, depending on how the @appinfo has
212 : : * been constructed.
213 : : *
214 : : * Returns: (nullable): a string containing the application’s ID.
215 : : **/
216 : : const char *
217 : 92 : g_app_info_get_id (GAppInfo *appinfo)
218 : : {
219 : : GAppInfoIface *iface;
220 : :
221 : 92 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
222 : :
223 : 92 : iface = G_APP_INFO_GET_IFACE (appinfo);
224 : :
225 : 92 : return (* iface->get_id) (appinfo);
226 : : }
227 : :
228 : : /**
229 : : * g_app_info_get_name:
230 : : * @appinfo: the app info
231 : : *
232 : : * Gets the installed name of the application.
233 : : *
234 : : * Returns: the name of the application for @appinfo.
235 : : **/
236 : : const char *
237 : 9 : g_app_info_get_name (GAppInfo *appinfo)
238 : : {
239 : : GAppInfoIface *iface;
240 : :
241 : 9 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
242 : :
243 : 9 : iface = G_APP_INFO_GET_IFACE (appinfo);
244 : :
245 : 9 : return (* iface->get_name) (appinfo);
246 : : }
247 : :
248 : : /**
249 : : * g_app_info_get_display_name:
250 : : * @appinfo: the app info
251 : : *
252 : : * Gets the display name of the application. The display name is often more
253 : : * descriptive to the user than the name itself.
254 : : *
255 : : * Returns: the display name of the application for @appinfo, or the name if
256 : : * no display name is available.
257 : : *
258 : : * Since: 2.24
259 : : **/
260 : : const char *
261 : 10 : g_app_info_get_display_name (GAppInfo *appinfo)
262 : : {
263 : : GAppInfoIface *iface;
264 : :
265 : 10 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
266 : :
267 : 10 : iface = G_APP_INFO_GET_IFACE (appinfo);
268 : :
269 : 10 : if (iface->get_display_name == NULL)
270 : 0 : return (* iface->get_name) (appinfo);
271 : :
272 : 10 : return (* iface->get_display_name) (appinfo);
273 : : }
274 : :
275 : : /**
276 : : * g_app_info_get_description:
277 : : * @appinfo: the app info
278 : : *
279 : : * Gets a human-readable description of an installed application.
280 : : *
281 : : * Returns: (nullable): a string containing a description of the
282 : : * application @appinfo, or `NULL` if none.
283 : : **/
284 : : const char *
285 : 6 : g_app_info_get_description (GAppInfo *appinfo)
286 : : {
287 : : GAppInfoIface *iface;
288 : :
289 : 6 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
290 : :
291 : 6 : iface = G_APP_INFO_GET_IFACE (appinfo);
292 : :
293 : 6 : return (* iface->get_description) (appinfo);
294 : : }
295 : :
296 : : /**
297 : : * g_app_info_get_executable: (virtual get_executable)
298 : : * @appinfo: the app info
299 : : *
300 : : * Gets the executable’s name for the installed application.
301 : : *
302 : : * This is intended to be used for debugging or labelling what program is going
303 : : * to be run. To launch the executable, use [method@Gio.AppInfo.launch] and related
304 : : * functions, rather than spawning the return value from this function.
305 : : *
306 : : * Returns: (type filename): a string containing the @appinfo’s application
307 : : * binaries name
308 : : **/
309 : : const char *
310 : 1 : g_app_info_get_executable (GAppInfo *appinfo)
311 : : {
312 : : GAppInfoIface *iface;
313 : :
314 : 1 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
315 : :
316 : 1 : iface = G_APP_INFO_GET_IFACE (appinfo);
317 : :
318 : 1 : return (* iface->get_executable) (appinfo);
319 : : }
320 : :
321 : :
322 : : /**
323 : : * g_app_info_get_commandline: (virtual get_commandline)
324 : : * @appinfo: the app info
325 : : *
326 : : * Gets the commandline with which the application will be
327 : : * started.
328 : : *
329 : : * Returns: (nullable) (type filename): a string containing the @appinfo’s
330 : : * commandline, or `NULL` if this information is not available
331 : : *
332 : : * Since: 2.20
333 : : **/
334 : : const char *
335 : 10 : g_app_info_get_commandline (GAppInfo *appinfo)
336 : : {
337 : : GAppInfoIface *iface;
338 : :
339 : 10 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
340 : :
341 : 10 : iface = G_APP_INFO_GET_IFACE (appinfo);
342 : :
343 : 10 : if (iface->get_commandline)
344 : 10 : return (* iface->get_commandline) (appinfo);
345 : :
346 : 0 : return NULL;
347 : : }
348 : :
349 : : /**
350 : : * g_app_info_set_as_default_for_type:
351 : : * @appinfo: the app info
352 : : * @content_type: the content type.
353 : : *
354 : : * Sets the application as the default handler for a given type.
355 : : *
356 : : * Returns: `TRUE` on success, `FALSE` on error.
357 : : **/
358 : : gboolean
359 : 29 : g_app_info_set_as_default_for_type (GAppInfo *appinfo,
360 : : const char *content_type,
361 : : GError **error)
362 : : {
363 : : GAppInfoIface *iface;
364 : :
365 : 29 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
366 : 29 : g_return_val_if_fail (content_type != NULL, FALSE);
367 : :
368 : 29 : iface = G_APP_INFO_GET_IFACE (appinfo);
369 : :
370 : 29 : if (iface->set_as_default_for_type)
371 : 29 : return (* iface->set_as_default_for_type) (appinfo, content_type, error);
372 : :
373 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
374 : : _("Setting default applications not supported yet"));
375 : 0 : return FALSE;
376 : : }
377 : :
378 : : /**
379 : : * g_app_info_set_as_last_used_for_type:
380 : : * @appinfo: the app info
381 : : * @content_type: the content type.
382 : : *
383 : : * Sets the application as the last used application for a given type. This
384 : : * will make the application appear as first in the list returned by
385 : : * [func@Gio.AppInfo.get_recommended_for_type], regardless of the default
386 : : * application for that content type.
387 : : *
388 : : * Returns: `TRUE` on success, `FALSE` on error.
389 : : **/
390 : : gboolean
391 : 7 : g_app_info_set_as_last_used_for_type (GAppInfo *appinfo,
392 : : const char *content_type,
393 : : GError **error)
394 : : {
395 : : GAppInfoIface *iface;
396 : :
397 : 7 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
398 : 7 : g_return_val_if_fail (content_type != NULL, FALSE);
399 : :
400 : 7 : iface = G_APP_INFO_GET_IFACE (appinfo);
401 : :
402 : 7 : if (iface->set_as_last_used_for_type)
403 : 7 : return (* iface->set_as_last_used_for_type) (appinfo, content_type, error);
404 : :
405 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
406 : : _("Setting application as last used for type not supported yet"));
407 : 0 : return FALSE;
408 : : }
409 : :
410 : : /**
411 : : * g_app_info_get_all:
412 : : *
413 : : * Gets a list of all of the applications currently registered
414 : : * on this system.
415 : : *
416 : : * For desktop files, this includes applications that have
417 : : * [`NoDisplay=true`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-nodisplay)
418 : : * set or are excluded from display by means of
419 : : * [`OnlyShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-onlyshowin)
420 : : * or [`NotShowIn`](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-notshowin).
421 : : * See [method@Gio.AppInfo.should_show].
422 : : *
423 : : * The returned list does not include applications which have the
424 : : * [`Hidden` key](https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html#key-hidden)
425 : : * set.
426 : : *
427 : : * Returns: (element-type GAppInfo) (transfer full): a newly allocated
428 : : * list of references to [iface@Gio.AppInfo]s.
429 : : **/
430 : : GList *
431 : 6 : g_app_info_get_all (void)
432 : : {
433 : 6 : return g_app_info_get_all_impl ();
434 : : }
435 : :
436 : : /**
437 : : * g_app_info_get_recommended_for_type:
438 : : * @content_type: the content type to find a [iface@Gio.AppInfo] for
439 : : *
440 : : * Gets a list of recommended [iface@Gio.AppInfo]s for a given content type,
441 : : * i.e. those applications which claim to support the given content type
442 : : * exactly, and not by MIME type subclassing.
443 : : *
444 : : * Note that the first application of the list is the last used one, i.e.
445 : : * the last one for which [method@Gio.AppInfo.set_as_last_used_for_type] has
446 : : * been called.
447 : : *
448 : : * Returns: (element-type GAppInfo) (transfer full): list of
449 : : * [iface@Gio.AppInfo]s for given @content_type or `NULL` on error.
450 : : *
451 : : * Since: 2.28
452 : : **/
453 : : GList *
454 : 20 : g_app_info_get_recommended_for_type (const gchar *content_type)
455 : : {
456 : 20 : g_return_val_if_fail (content_type != NULL, NULL);
457 : :
458 : 20 : return g_app_info_get_recommended_for_type_impl (content_type);
459 : : }
460 : :
461 : : /**
462 : : * g_app_info_get_fallback_for_type:
463 : : * @content_type: the content type to find a [iface@Gio.AppInfo] for
464 : : *
465 : : * Gets a list of fallback [iface@Gio.AppInfo]s for a given content type, i.e.
466 : : * those applications which claim to support the given content type by MIME
467 : : * type subclassing and not directly.
468 : : *
469 : : * Returns: (element-type GAppInfo) (transfer full): list of [iface@Gio.AppInfo]s
470 : : * for given @content_type or `NULL` on error.
471 : : *
472 : : * Since: 2.28
473 : : **/
474 : : GList *
475 : 1 : g_app_info_get_fallback_for_type (const gchar *content_type)
476 : : {
477 : 1 : g_return_val_if_fail (content_type != NULL, NULL);
478 : :
479 : 1 : return g_app_info_get_fallback_for_type_impl (content_type);
480 : : }
481 : :
482 : : /**
483 : : * g_app_info_get_all_for_type:
484 : : * @content_type: the content type to find a [iface@Gio.AppInfo] for
485 : : *
486 : : * Gets a list of all [iface@Gio.AppInfo]s for a given content type,
487 : : * including the recommended and fallback [iface@Gio.AppInfo]s. See
488 : : * [func@Gio.AppInfo.get_recommended_for_type] and
489 : : * [func@Gio.AppInfo.get_fallback_for_type].
490 : : *
491 : : * Returns: (element-type GAppInfo) (transfer full): list of
492 : : * [iface@Gio.AppInfo]s for given @content_type.
493 : : **/
494 : : GList *
495 : 6 : g_app_info_get_all_for_type (const char *content_type)
496 : : {
497 : 6 : g_return_val_if_fail (content_type != NULL, NULL);
498 : :
499 : 6 : return g_app_info_get_all_for_type_impl (content_type);
500 : : }
501 : :
502 : : /**
503 : : * g_app_info_reset_type_associations:
504 : : * @content_type: a content type
505 : : *
506 : : * Removes all changes to the type associations done by
507 : : * [method@Gio.AppInfo.set_as_default_for_type],
508 : : * [method@Gio.AppInfo.set_as_default_for_extension],
509 : : * [method@Gio.AppInfo.add_supports_type] or
510 : : * [method@Gio.AppInfo.remove_supports_type].
511 : : *
512 : : * Since: 2.20
513 : : */
514 : : void
515 : 28 : g_app_info_reset_type_associations (const char *content_type)
516 : : {
517 : 28 : g_app_info_reset_type_associations_impl (content_type);
518 : 28 : }
519 : :
520 : : /**
521 : : * g_app_info_get_default_for_type:
522 : : * @content_type: the content type to find a [iface@Gio.AppInfo] for
523 : : * @must_support_uris: if `TRUE`, the [iface@Gio.AppInfo] is expected to
524 : : * support URIs
525 : : *
526 : : * Gets the default [iface@Gio.AppInfo] for a given content type.
527 : : *
528 : : * Returns: (transfer full) (nullable): [iface@Gio.AppInfo] for given
529 : : * @content_type or `NULL` on error.
530 : : */
531 : : GAppInfo *
532 : 66 : g_app_info_get_default_for_type (const char *content_type,
533 : : gboolean must_support_uris)
534 : : {
535 : 66 : g_return_val_if_fail (content_type != NULL, NULL);
536 : :
537 : 66 : return g_app_info_get_default_for_type_impl (content_type, must_support_uris);
538 : : }
539 : :
540 : : /**
541 : : * g_app_info_get_default_for_uri_scheme:
542 : : * @uri_scheme: a string containing a URI scheme.
543 : : *
544 : : * Gets the default application for handling URIs with the given URI scheme.
545 : : *
546 : : * A URI scheme is the initial part of the URI, up to but not including the `:`.
547 : : * For example, `http`, `ftp` or `sip`.
548 : : *
549 : : * Returns: (transfer full) (nullable): [iface@Gio.AppInfo] for given
550 : : * @uri_scheme or `NULL` on error.
551 : : */
552 : : GAppInfo *
553 : 36 : g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
554 : : {
555 : 36 : g_return_val_if_fail (uri_scheme != NULL && *uri_scheme != '\0', NULL);
556 : :
557 : 32 : return g_app_info_get_default_for_uri_scheme_impl (uri_scheme);
558 : : }
559 : :
560 : : /**
561 : : * g_app_info_set_as_default_for_extension:
562 : : * @appinfo: the app info
563 : : * @extension: (type filename): a string containing the file extension (without
564 : : * the dot).
565 : : *
566 : : * Sets the application as the default handler for the given file extension.
567 : : *
568 : : * Returns: `TRUE` on success, `FALSE` on error.
569 : : **/
570 : : gboolean
571 : 1 : g_app_info_set_as_default_for_extension (GAppInfo *appinfo,
572 : : const char *extension,
573 : : GError **error)
574 : : {
575 : : GAppInfoIface *iface;
576 : :
577 : 1 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
578 : 1 : g_return_val_if_fail (extension != NULL, FALSE);
579 : :
580 : 1 : iface = G_APP_INFO_GET_IFACE (appinfo);
581 : :
582 : 1 : if (iface->set_as_default_for_extension)
583 : 1 : return (* iface->set_as_default_for_extension) (appinfo, extension, error);
584 : :
585 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
586 : : "g_app_info_set_as_default_for_extension not supported yet");
587 : 0 : return FALSE;
588 : : }
589 : :
590 : :
591 : : /**
592 : : * g_app_info_add_supports_type:
593 : : * @appinfo: the app info
594 : : * @content_type: a string.
595 : : *
596 : : * Adds a content type to the application information to indicate the
597 : : * application is capable of opening files with the given content type.
598 : : *
599 : : * Returns: `TRUE` on success, `FALSE` on error.
600 : : **/
601 : : gboolean
602 : 12 : g_app_info_add_supports_type (GAppInfo *appinfo,
603 : : const char *content_type,
604 : : GError **error)
605 : : {
606 : : GAppInfoIface *iface;
607 : :
608 : 12 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
609 : 12 : g_return_val_if_fail (content_type != NULL, FALSE);
610 : :
611 : 12 : iface = G_APP_INFO_GET_IFACE (appinfo);
612 : :
613 : 12 : if (iface->add_supports_type)
614 : 12 : return (* iface->add_supports_type) (appinfo, content_type, error);
615 : :
616 : 0 : g_set_error_literal (error, G_IO_ERROR,
617 : : G_IO_ERROR_NOT_SUPPORTED,
618 : : "g_app_info_add_supports_type not supported yet");
619 : :
620 : 0 : return FALSE;
621 : : }
622 : :
623 : :
624 : : /**
625 : : * g_app_info_can_remove_supports_type:
626 : : * @appinfo: the app info
627 : : *
628 : : * Checks if a supported content type can be removed from an application.
629 : : *
630 : : * Returns: `TRUE` if it is possible to remove supported content types from a
631 : : * given @appinfo, `FALSE` if not.
632 : : **/
633 : : gboolean
634 : 1 : g_app_info_can_remove_supports_type (GAppInfo *appinfo)
635 : : {
636 : : GAppInfoIface *iface;
637 : :
638 : 1 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
639 : :
640 : 1 : iface = G_APP_INFO_GET_IFACE (appinfo);
641 : :
642 : 1 : if (iface->can_remove_supports_type)
643 : 1 : return (* iface->can_remove_supports_type) (appinfo);
644 : :
645 : 0 : return FALSE;
646 : : }
647 : :
648 : :
649 : : /**
650 : : * g_app_info_remove_supports_type:
651 : : * @appinfo: the app info
652 : : * @content_type: a string.
653 : : *
654 : : * Removes a supported type from an application, if possible.
655 : : *
656 : : * Returns: `TRUE` on success, `FALSE` on error.
657 : : **/
658 : : gboolean
659 : 18 : g_app_info_remove_supports_type (GAppInfo *appinfo,
660 : : const char *content_type,
661 : : GError **error)
662 : : {
663 : : GAppInfoIface *iface;
664 : :
665 : 18 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
666 : 18 : g_return_val_if_fail (content_type != NULL, FALSE);
667 : :
668 : 18 : iface = G_APP_INFO_GET_IFACE (appinfo);
669 : :
670 : 18 : if (iface->remove_supports_type)
671 : 18 : return (* iface->remove_supports_type) (appinfo, content_type, error);
672 : :
673 : 0 : g_set_error_literal (error, G_IO_ERROR,
674 : : G_IO_ERROR_NOT_SUPPORTED,
675 : : "g_app_info_remove_supports_type not supported yet");
676 : :
677 : 0 : return FALSE;
678 : : }
679 : :
680 : : /**
681 : : * g_app_info_get_supported_types:
682 : : * @appinfo: an app info that can handle files
683 : : *
684 : : * Retrieves the list of content types that @app_info claims to support.
685 : : * If this information is not provided by the environment, this function
686 : : * will return `NULL`.
687 : : *
688 : : * This function does not take in consideration associations added with
689 : : * [method@Gio.AppInfo.add_supports_type], but only those exported directly by
690 : : * the application.
691 : : *
692 : : * Returns: (transfer none) (array zero-terminated=1) (element-type utf8):
693 : : * a list of content types.
694 : : *
695 : : * Since: 2.34
696 : : */
697 : : const char **
698 : 1 : g_app_info_get_supported_types (GAppInfo *appinfo)
699 : : {
700 : : GAppInfoIface *iface;
701 : :
702 : 1 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
703 : :
704 : 1 : iface = G_APP_INFO_GET_IFACE (appinfo);
705 : :
706 : 1 : if (iface->get_supported_types)
707 : 1 : return iface->get_supported_types (appinfo);
708 : : else
709 : 0 : return NULL;
710 : : }
711 : :
712 : :
713 : : /**
714 : : * g_app_info_get_icon:
715 : : * @appinfo: the app info
716 : : *
717 : : * Gets the icon for the application.
718 : : *
719 : : * Returns: (nullable) (transfer none): the default [iface@Gio.Icon] for
720 : : * @appinfo or `NULL` if there is no default icon.
721 : : **/
722 : : GIcon *
723 : 1 : g_app_info_get_icon (GAppInfo *appinfo)
724 : : {
725 : : GAppInfoIface *iface;
726 : :
727 : 1 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), NULL);
728 : :
729 : 1 : iface = G_APP_INFO_GET_IFACE (appinfo);
730 : :
731 : 1 : return (* iface->get_icon) (appinfo);
732 : : }
733 : :
734 : :
735 : : /**
736 : : * g_app_info_launch:
737 : : * @appinfo: the app info
738 : : * @files: (nullable) (element-type GFile): a list of [iface@Gio.File] objects
739 : : * @context: (nullable): the launch context
740 : : *
741 : : * Launches the application. Passes @files to the launched application
742 : : * as arguments, using the optional @context to get information
743 : : * about the details of the launcher (like what screen it is on).
744 : : * On error, @error will be set accordingly.
745 : : *
746 : : * To launch the application without arguments pass a `NULL` @files list.
747 : : *
748 : : * Note that even if the launch is successful the application launched
749 : : * can fail to start if it runs into problems during startup. There is
750 : : * no way to detect this.
751 : : *
752 : : * Some URIs can be changed when passed through a GFile (for instance
753 : : * unsupported URIs with strange formats like mailto:), so if you have
754 : : * a textual URI you want to pass in as argument, consider using
755 : : * [method@Gio.AppInfo.launch_uris] instead.
756 : : *
757 : : * The launched application inherits the environment of the launching
758 : : * process, but it can be modified with [method@Gio.AppLaunchContext.setenv]
759 : : * and [method@Gio.AppLaunchContext.unsetenv].
760 : : *
761 : : * On UNIX, this function sets the `GIO_LAUNCHED_DESKTOP_FILE`
762 : : * environment variable with the path of the launched desktop file and
763 : : * `GIO_LAUNCHED_DESKTOP_FILE_PID` to the process id of the launched
764 : : * process. This can be used to ignore `GIO_LAUNCHED_DESKTOP_FILE`,
765 : : * should it be inherited by further processes. The `DISPLAY`,
766 : : * `XDG_ACTIVATION_TOKEN` and `DESKTOP_STARTUP_ID` environment
767 : : * variables are also set, based on information provided in @context.
768 : : *
769 : : * Returns: `TRUE` on successful launch, `FALSE` otherwise.
770 : : **/
771 : : gboolean
772 : 14 : g_app_info_launch (GAppInfo *appinfo,
773 : : GList *files,
774 : : GAppLaunchContext *launch_context,
775 : : GError **error)
776 : : {
777 : : GAppInfoIface *iface;
778 : :
779 : 14 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
780 : :
781 : 14 : iface = G_APP_INFO_GET_IFACE (appinfo);
782 : :
783 : 14 : return (* iface->launch) (appinfo, files, launch_context, error);
784 : : }
785 : :
786 : :
787 : : /**
788 : : * g_app_info_supports_uris:
789 : : * @appinfo: the app info
790 : : *
791 : : * Checks if the application supports reading files and directories from URIs.
792 : : *
793 : : * Returns: `TRUE` if the @appinfo supports URIs.
794 : : **/
795 : : gboolean
796 : 2 : g_app_info_supports_uris (GAppInfo *appinfo)
797 : : {
798 : : GAppInfoIface *iface;
799 : :
800 : 2 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
801 : :
802 : 2 : iface = G_APP_INFO_GET_IFACE (appinfo);
803 : :
804 : 2 : return (* iface->supports_uris) (appinfo);
805 : : }
806 : :
807 : :
808 : : /**
809 : : * g_app_info_supports_files:
810 : : * @appinfo: the app info
811 : : *
812 : : * Checks if the application accepts files as arguments.
813 : : *
814 : : * Returns: `TRUE` if the @appinfo supports files.
815 : : **/
816 : : gboolean
817 : 2 : g_app_info_supports_files (GAppInfo *appinfo)
818 : : {
819 : : GAppInfoIface *iface;
820 : :
821 : 2 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
822 : :
823 : 2 : iface = G_APP_INFO_GET_IFACE (appinfo);
824 : :
825 : 2 : return (* iface->supports_files) (appinfo);
826 : : }
827 : :
828 : :
829 : : /**
830 : : * g_app_info_launch_uris:
831 : : * @appinfo: the app info
832 : : * @uris: (nullable) (element-type utf8): a list of URIs to launch.
833 : : * @context: (nullable): the launch context
834 : : *
835 : : * Launches the application. This passes the @uris to the launched application
836 : : * as arguments, using the optional @context to get information
837 : : * about the details of the launcher (like what screen it is on).
838 : : * On error, @error will be set accordingly. If the application only supports
839 : : * one URI per invocation as part of their command-line, multiple instances
840 : : * of the application will be spawned.
841 : : *
842 : : * To launch the application without arguments pass a `NULL` @uris list.
843 : : *
844 : : * Note that even if the launch is successful the application launched
845 : : * can fail to start if it runs into problems during startup. There is
846 : : * no way to detect this.
847 : : *
848 : : * Returns: `TRUE` on successful launch, `FALSE` otherwise.
849 : : **/
850 : : gboolean
851 : 44 : g_app_info_launch_uris (GAppInfo *appinfo,
852 : : GList *uris,
853 : : GAppLaunchContext *launch_context,
854 : : GError **error)
855 : : {
856 : : GAppInfoIface *iface;
857 : :
858 : 44 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
859 : :
860 : 44 : iface = G_APP_INFO_GET_IFACE (appinfo);
861 : :
862 : 44 : return (* iface->launch_uris) (appinfo, uris, launch_context, error);
863 : : }
864 : :
865 : : /**
866 : : * g_app_info_launch_uris_async:
867 : : * @appinfo: the app info
868 : : * @uris: (nullable) (element-type utf8): a list of URIs to launch.
869 : : * @context: (nullable): the launch context
870 : : * @cancellable: (nullable): a [class@Gio.Cancellable]
871 : : * @callback: (scope async) (nullable): a [type@Gio.AsyncReadyCallback] to call
872 : : * when the request is done
873 : : * @user_data: (nullable): data to pass to @callback
874 : : *
875 : : * Async version of [method@Gio.AppInfo.launch_uris].
876 : : *
877 : : * The @callback is invoked immediately after the application launch, but it
878 : : * waits for activation in case of D-Bus–activated applications and also provides
879 : : * extended error information for sandboxed applications, see notes for
880 : : * [func@Gio.AppInfo.launch_default_for_uri_async].
881 : : *
882 : : * Since: 2.60
883 : : **/
884 : : void
885 : 4 : g_app_info_launch_uris_async (GAppInfo *appinfo,
886 : : GList *uris,
887 : : GAppLaunchContext *context,
888 : : GCancellable *cancellable,
889 : : GAsyncReadyCallback callback,
890 : : gpointer user_data)
891 : : {
892 : : GAppInfoIface *iface;
893 : :
894 : 4 : g_return_if_fail (G_IS_APP_INFO (appinfo));
895 : 4 : g_return_if_fail (context == NULL || G_IS_APP_LAUNCH_CONTEXT (context));
896 : 4 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
897 : :
898 : 4 : iface = G_APP_INFO_GET_IFACE (appinfo);
899 : 4 : if (iface->launch_uris_async == NULL)
900 : : {
901 : : GTask *task;
902 : :
903 : 0 : task = g_task_new (appinfo, cancellable, callback, user_data);
904 : 0 : g_task_set_source_tag (task, g_app_info_launch_uris_async);
905 : 0 : g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
906 : : "Operation not supported for the current backend.");
907 : 0 : g_object_unref (task);
908 : :
909 : 0 : return;
910 : : }
911 : :
912 : 4 : (* iface->launch_uris_async) (appinfo, uris, context, cancellable, callback, user_data);
913 : : }
914 : :
915 : : /**
916 : : * g_app_info_launch_uris_finish:
917 : : * @appinfo: the app info
918 : : * @result: the async result
919 : : *
920 : : * Finishes a [method@Gio.AppInfo.launch_uris_async] operation.
921 : : *
922 : : * Returns: `TRUE` on successful launch, `FALSE` otherwise.
923 : : *
924 : : * Since: 2.60
925 : : */
926 : : gboolean
927 : 4 : g_app_info_launch_uris_finish (GAppInfo *appinfo,
928 : : GAsyncResult *result,
929 : : GError **error)
930 : : {
931 : : GAppInfoIface *iface;
932 : :
933 : 4 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
934 : :
935 : 4 : iface = G_APP_INFO_GET_IFACE (appinfo);
936 : 4 : if (iface->launch_uris_finish == NULL)
937 : : {
938 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
939 : : "Operation not supported for the current backend.");
940 : 0 : return FALSE;
941 : : }
942 : :
943 : 4 : return (* iface->launch_uris_finish) (appinfo, result, error);
944 : : }
945 : :
946 : : /**
947 : : * g_app_info_should_show:
948 : : * @appinfo: the app info
949 : : *
950 : : * Checks if the application info should be shown in menus that
951 : : * list available applications.
952 : : *
953 : : * Returns: `TRUE` if the @appinfo should be shown, `FALSE` otherwise.
954 : : **/
955 : : gboolean
956 : 14 : g_app_info_should_show (GAppInfo *appinfo)
957 : : {
958 : : GAppInfoIface *iface;
959 : :
960 : 14 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
961 : :
962 : 14 : iface = G_APP_INFO_GET_IFACE (appinfo);
963 : :
964 : 14 : return (* iface->should_show) (appinfo);
965 : : }
966 : :
967 : : typedef struct {
968 : : char *content_type;
969 : : gboolean must_support_uris;
970 : : } DefaultForTypeData;
971 : :
972 : : static void
973 : 7 : default_for_type_data_free (DefaultForTypeData *data)
974 : : {
975 : 7 : g_free (data->content_type);
976 : 7 : g_free (data);
977 : 7 : }
978 : :
979 : : static void
980 : 7 : get_default_for_type_thread (GTask *task,
981 : : gpointer object,
982 : : gpointer task_data,
983 : : GCancellable *cancellable)
984 : : {
985 : 7 : DefaultForTypeData *data = task_data;
986 : : GAppInfo *info;
987 : :
988 : 7 : info = g_app_info_get_default_for_type (data->content_type,
989 : : data->must_support_uris);
990 : :
991 : 7 : if (!info)
992 : : {
993 : 3 : g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
994 : 3 : _("Failed to find default application for "
995 : : "content type ‘%s’"), data->content_type);
996 : 3 : return;
997 : : }
998 : :
999 : 4 : g_task_return_pointer (task, g_steal_pointer (&info), g_object_unref);
1000 : : }
1001 : :
1002 : : /**
1003 : : * g_app_info_get_default_for_type_async:
1004 : : * @content_type: the content type to find a [iface@Gio.AppInfo] for
1005 : : * @must_support_uris: if `TRUE`, the [iface@Gio.AppInfo] is expected to
1006 : : * support URIs
1007 : : * @cancellable: (nullable): a [class@Gio.Cancellable]
1008 : : * @callback: (scope async) (nullable): a [type@Gio.AsyncReadyCallback] to call
1009 : : * when the request is done
1010 : : * @user_data: (nullable): data to pass to @callback
1011 : : *
1012 : : * Asynchronously gets the default [iface@Gio.AppInfo] for a given content
1013 : : * type.
1014 : : *
1015 : : * Since: 2.74
1016 : : */
1017 : : void
1018 : 9 : g_app_info_get_default_for_type_async (const char *content_type,
1019 : : gboolean must_support_uris,
1020 : : GCancellable *cancellable,
1021 : : GAsyncReadyCallback callback,
1022 : : gpointer user_data)
1023 : : {
1024 : : GTask *task;
1025 : : DefaultForTypeData *data;
1026 : :
1027 : 9 : g_return_if_fail (content_type != NULL && *content_type != '\0');
1028 : 7 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1029 : :
1030 : 7 : data = g_new0 (DefaultForTypeData, 1);
1031 : 7 : data->content_type = g_strdup (content_type);
1032 : 7 : data->must_support_uris = must_support_uris;
1033 : :
1034 : 7 : task = g_task_new (NULL, cancellable, callback, user_data);
1035 : 7 : g_task_set_source_tag (task, g_app_info_get_default_for_type_async);
1036 : 7 : g_task_set_task_data (task, data, (GDestroyNotify) default_for_type_data_free);
1037 : 7 : g_task_set_check_cancellable (task, TRUE);
1038 : 7 : g_task_run_in_thread (task, get_default_for_type_thread);
1039 : 7 : g_object_unref (task);
1040 : : }
1041 : :
1042 : : static void
1043 : 18 : get_default_for_scheme_thread (GTask *task,
1044 : : gpointer object,
1045 : : gpointer task_data,
1046 : : GCancellable *cancellable)
1047 : : {
1048 : 18 : const char *uri_scheme = task_data;
1049 : : GAppInfo *info;
1050 : :
1051 : 18 : info = g_app_info_get_default_for_uri_scheme (uri_scheme);
1052 : :
1053 : 18 : if (!info)
1054 : : {
1055 : 12 : g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1056 : 12 : _("Failed to find default application for "
1057 : : "URI Scheme ‘%s’"), uri_scheme);
1058 : 12 : return;
1059 : : }
1060 : :
1061 : 6 : g_task_return_pointer (task, g_steal_pointer (&info), g_object_unref);
1062 : : }
1063 : :
1064 : : /**
1065 : : * g_app_info_get_default_for_uri_scheme_async:
1066 : : * @uri_scheme: a string containing a URI scheme.
1067 : : * @cancellable: (nullable): a [class@Gio.Cancellable]
1068 : : * @callback: (scope async) (nullable): a [type@Gio.AsyncReadyCallback] to call
1069 : : * when the request is done
1070 : : * @user_data: (nullable): data to pass to @callback
1071 : : *
1072 : : * Asynchronously gets the default application for handling URIs with
1073 : : * the given URI scheme. A URI scheme is the initial part
1074 : : * of the URI, up to but not including the `:`, e.g. `http`,
1075 : : * `ftp` or `sip`.
1076 : : *
1077 : : * Since: 2.74
1078 : : */
1079 : : void
1080 : 18 : g_app_info_get_default_for_uri_scheme_async (const char *uri_scheme,
1081 : : GCancellable *cancellable,
1082 : : GAsyncReadyCallback callback,
1083 : : gpointer user_data)
1084 : : {
1085 : : GTask *task;
1086 : :
1087 : 18 : g_return_if_fail (uri_scheme != NULL && *uri_scheme != '\0');
1088 : 18 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1089 : :
1090 : 18 : task = g_task_new (NULL, cancellable, callback, user_data);
1091 : 18 : g_task_set_source_tag (task, g_app_info_get_default_for_uri_scheme_async);
1092 : 18 : g_task_set_task_data (task, g_strdup (uri_scheme), g_free);
1093 : 18 : g_task_set_check_cancellable (task, TRUE);
1094 : 18 : g_task_run_in_thread (task, get_default_for_scheme_thread);
1095 : 18 : g_object_unref (task);
1096 : : }
1097 : :
1098 : : /**
1099 : : * g_app_info_get_default_for_uri_scheme_finish:
1100 : : * @result: the async result
1101 : : *
1102 : : * Finishes a default [iface@Gio.AppInfo] lookup started by
1103 : : * [func@Gio.AppInfo.get_default_for_uri_scheme_async].
1104 : : *
1105 : : * If no [iface@Gio.AppInfo] is found, then @error will be set to
1106 : : * [error@Gio.IOErrorEnum.NOT_FOUND].
1107 : : *
1108 : : * Returns: (transfer full): [iface@Gio.AppInfo] for given @uri_scheme or
1109 : : * `NULL` on error.
1110 : : *
1111 : : * Since: 2.74
1112 : : */
1113 : : GAppInfo *
1114 : 18 : g_app_info_get_default_for_uri_scheme_finish (GAsyncResult *result,
1115 : : GError **error)
1116 : : {
1117 : 18 : g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
1118 : 18 : g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
1119 : : g_app_info_get_default_for_uri_scheme_async, NULL);
1120 : 18 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1121 : :
1122 : 18 : return g_task_propagate_pointer (G_TASK (result), error);
1123 : : }
1124 : :
1125 : : /**
1126 : : * g_app_info_get_default_for_type_finish:
1127 : : * @result: the async result
1128 : : *
1129 : : * Finishes a default [iface@Gio.AppInfo] lookup started by
1130 : : * [func@Gio.AppInfo.get_default_for_type_async].
1131 : : *
1132 : : * If no #[iface@Gio.AppInfo] is found, then @error will be set to
1133 : : * [error@Gio.IOErrorEnum.NOT_FOUND].
1134 : : *
1135 : : * Returns: (transfer full): [iface@Gio.AppInfo] for given @content_type or
1136 : : * `NULL` on error.
1137 : : *
1138 : : * Since: 2.74
1139 : : */
1140 : : GAppInfo *
1141 : 7 : g_app_info_get_default_for_type_finish (GAsyncResult *result,
1142 : : GError **error)
1143 : : {
1144 : 7 : g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
1145 : 7 : g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) ==
1146 : : g_app_info_get_default_for_type_async, NULL);
1147 : 7 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1148 : :
1149 : 7 : return g_task_propagate_pointer (G_TASK (result), error);
1150 : : }
1151 : :
1152 : : /**
1153 : : * g_app_info_launch_default_for_uri:
1154 : : * @uri: the uri to show
1155 : : * @context: (nullable): optional launch context
1156 : : *
1157 : : * Utility function that launches the default application registered to handle
1158 : : * the specified uri. Synchronous I/O is done on the uri to detect the type of
1159 : : * the file if required.
1160 : : *
1161 : : * The D-Bus–activated applications don’t have to be started if your application
1162 : : * terminates too soon after this function. To prevent this, use
1163 : : * [func@Gio.AppInfo.launch_default_for_uri_async] instead.
1164 : : *
1165 : : * Returns: `TRUE` on success, `FALSE` on error.
1166 : : **/
1167 : : gboolean
1168 : 4 : g_app_info_launch_default_for_uri (const char *uri,
1169 : : GAppLaunchContext *launch_context,
1170 : : GError **error)
1171 : : {
1172 : : char *uri_scheme;
1173 : 4 : GAppInfo *app_info = NULL;
1174 : 4 : gboolean res = FALSE;
1175 : :
1176 : : /* g_file_query_default_handler() calls
1177 : : * g_app_info_get_default_for_uri_scheme() too, but we have to do it
1178 : : * here anyway in case GFile can't parse @uri correctly.
1179 : : */
1180 : 4 : uri_scheme = g_uri_parse_scheme (uri);
1181 : 4 : if (uri_scheme && uri_scheme[0] != '\0')
1182 : 4 : app_info = g_app_info_get_default_for_uri_scheme (uri_scheme);
1183 : 4 : g_free (uri_scheme);
1184 : :
1185 : 4 : if (!app_info)
1186 : : {
1187 : : GFile *file;
1188 : :
1189 : 3 : file = g_file_new_for_uri (uri);
1190 : 3 : app_info = g_file_query_default_handler (file, NULL, error);
1191 : 3 : g_object_unref (file);
1192 : : }
1193 : :
1194 : 4 : if (app_info)
1195 : : {
1196 : : GList l;
1197 : :
1198 : 1 : l.data = (char *)uri;
1199 : 1 : l.next = l.prev = NULL;
1200 : 1 : res = g_app_info_launch_uris (app_info, &l, launch_context, error);
1201 : 1 : g_object_unref (app_info);
1202 : : }
1203 : :
1204 : : #ifdef G_OS_UNIX
1205 : 4 : if (!res && glib_should_use_portal ())
1206 : : {
1207 : 2 : GFile *file = NULL;
1208 : 2 : const char *parent_window = NULL;
1209 : 2 : char *startup_id = NULL;
1210 : :
1211 : : /* Reset any error previously set by launch_default_for_uri */
1212 : 2 : g_clear_error (error);
1213 : :
1214 : 2 : file = g_file_new_for_uri (uri);
1215 : :
1216 : 2 : if (launch_context)
1217 : : {
1218 : : GList *file_list;
1219 : :
1220 : 2 : if (launch_context->priv->envp)
1221 : 0 : parent_window = g_environ_getenv (launch_context->priv->envp, "PARENT_WINDOW_ID");
1222 : :
1223 : 2 : file_list = g_list_prepend (NULL, file);
1224 : :
1225 : 2 : startup_id = g_app_launch_context_get_startup_notify_id (launch_context,
1226 : : NULL,
1227 : : file_list);
1228 : 2 : g_list_free (file_list);
1229 : : }
1230 : :
1231 : 2 : res = g_openuri_portal_open_file (file, parent_window, startup_id, error);
1232 : :
1233 : 2 : g_object_unref (file);
1234 : 2 : g_free (startup_id);
1235 : : }
1236 : : #endif
1237 : :
1238 : 4 : return res;
1239 : : }
1240 : :
1241 : : typedef struct
1242 : : {
1243 : : gchar *uri;
1244 : : GAppLaunchContext *context;
1245 : : } LaunchDefaultForUriData;
1246 : :
1247 : : static void
1248 : 5 : launch_default_for_uri_data_free (LaunchDefaultForUriData *data)
1249 : : {
1250 : 5 : g_free (data->uri);
1251 : 5 : g_clear_object (&data->context);
1252 : 5 : g_free (data);
1253 : 5 : }
1254 : :
1255 : : #ifdef G_OS_UNIX
1256 : : static void
1257 : 2 : launch_default_for_uri_portal_open_uri_cb (GObject *object,
1258 : : GAsyncResult *result,
1259 : : gpointer user_data)
1260 : : {
1261 : 2 : GTask *task = G_TASK (user_data);
1262 : 2 : GError *error = NULL;
1263 : :
1264 : 2 : if (g_openuri_portal_open_file_finish (result, &error))
1265 : 2 : g_task_return_boolean (task, TRUE);
1266 : : else
1267 : 0 : g_task_return_error (task, g_steal_pointer (&error));
1268 : 2 : g_object_unref (task);
1269 : 2 : }
1270 : : #endif
1271 : :
1272 : : static void
1273 : 4 : launch_default_for_uri_portal_open_uri (GTask *task, GError *error)
1274 : : {
1275 : : #ifdef G_OS_UNIX
1276 : 4 : LaunchDefaultForUriData *data = g_task_get_task_data (task);
1277 : 4 : GCancellable *cancellable = g_task_get_cancellable (task);
1278 : :
1279 : 4 : if (glib_should_use_portal ())
1280 : : {
1281 : : GFile *file;
1282 : 2 : const char *parent_window = NULL;
1283 : 2 : char *startup_id = NULL;
1284 : :
1285 : : /* Reset any error previously set by launch_default_for_uri */
1286 : 2 : g_error_free (error);
1287 : :
1288 : 2 : file = g_file_new_for_uri (data->uri);
1289 : :
1290 : 2 : if (data->context)
1291 : : {
1292 : : GList *file_list;
1293 : :
1294 : 2 : if (data->context->priv->envp)
1295 : 0 : parent_window = g_environ_getenv (data->context->priv->envp,
1296 : : "PARENT_WINDOW_ID");
1297 : :
1298 : 2 : file_list = g_list_prepend (NULL, file);
1299 : :
1300 : 2 : startup_id = g_app_launch_context_get_startup_notify_id (data->context,
1301 : : NULL,
1302 : : file_list);
1303 : 2 : g_list_free (file_list);
1304 : : }
1305 : :
1306 : 2 : g_openuri_portal_open_file_async (file,
1307 : : parent_window,
1308 : : startup_id,
1309 : : cancellable,
1310 : : launch_default_for_uri_portal_open_uri_cb,
1311 : : g_steal_pointer (&task));
1312 : 2 : g_object_unref (file);
1313 : 2 : g_free (startup_id);
1314 : :
1315 : 2 : return;
1316 : : }
1317 : : #endif
1318 : :
1319 : 2 : g_task_return_error (task, g_steal_pointer (&error));
1320 : 2 : g_object_unref (task);
1321 : : }
1322 : :
1323 : : static void
1324 : 1 : launch_default_for_uri_launch_uris_cb (GObject *object,
1325 : : GAsyncResult *result,
1326 : : gpointer user_data)
1327 : : {
1328 : 1 : GAppInfo *app_info = G_APP_INFO (object);
1329 : 1 : GTask *task = G_TASK (user_data);
1330 : 1 : GError *error = NULL;
1331 : :
1332 : 1 : if (g_app_info_launch_uris_finish (app_info, result, &error))
1333 : : {
1334 : 1 : g_task_return_boolean (task, TRUE);
1335 : 1 : g_object_unref (task);
1336 : : }
1337 : : else
1338 : 0 : launch_default_for_uri_portal_open_uri (g_steal_pointer (&task), g_steal_pointer (&error));
1339 : 1 : }
1340 : :
1341 : : static void
1342 : 1 : launch_default_for_uri_launch_uris (GTask *task,
1343 : : GAppInfo *app_info)
1344 : : {
1345 : 1 : GCancellable *cancellable = g_task_get_cancellable (task);
1346 : : GList l;
1347 : 1 : LaunchDefaultForUriData *data = g_task_get_task_data (task);
1348 : :
1349 : 1 : l.data = (char *)data->uri;
1350 : 1 : l.next = l.prev = NULL;
1351 : 1 : g_app_info_launch_uris_async (app_info,
1352 : : &l,
1353 : : data->context,
1354 : : cancellable,
1355 : : launch_default_for_uri_launch_uris_cb,
1356 : : g_steal_pointer (&task));
1357 : 1 : g_object_unref (app_info);
1358 : 1 : }
1359 : :
1360 : : static void
1361 : 4 : launch_default_for_uri_default_handler_cb (GObject *object,
1362 : : GAsyncResult *result,
1363 : : gpointer user_data)
1364 : : {
1365 : 4 : GFile *file = G_FILE (object);
1366 : 4 : GTask *task = G_TASK (user_data);
1367 : 4 : GAppInfo *app_info = NULL;
1368 : 4 : GError *error = NULL;
1369 : :
1370 : 4 : app_info = g_file_query_default_handler_finish (file, result, &error);
1371 : 4 : if (app_info)
1372 : 0 : launch_default_for_uri_launch_uris (g_steal_pointer (&task), g_steal_pointer (&app_info));
1373 : : else
1374 : 4 : launch_default_for_uri_portal_open_uri (g_steal_pointer (&task), g_steal_pointer (&error));
1375 : 4 : }
1376 : :
1377 : : static void
1378 : 4 : launch_default_app_for_default_handler (GTask *task)
1379 : : {
1380 : : GFile *file;
1381 : : GCancellable *cancellable;
1382 : : LaunchDefaultForUriData *data;
1383 : :
1384 : 4 : data = g_task_get_task_data (task);
1385 : 4 : cancellable = g_task_get_cancellable (task);
1386 : 4 : file = g_file_new_for_uri (data->uri);
1387 : :
1388 : 4 : g_file_query_default_handler_async (file,
1389 : : G_PRIORITY_DEFAULT,
1390 : : cancellable,
1391 : : launch_default_for_uri_default_handler_cb,
1392 : : g_steal_pointer (&task));
1393 : 4 : g_object_unref (file);
1394 : 4 : }
1395 : :
1396 : : static void
1397 : 5 : launch_default_app_for_uri_cb (GObject *object,
1398 : : GAsyncResult *result,
1399 : : gpointer user_data)
1400 : : {
1401 : 5 : GTask *task = G_TASK (user_data);
1402 : : GAppInfo *app_info;
1403 : :
1404 : 5 : app_info = g_app_info_get_default_for_uri_scheme_finish (result, NULL);
1405 : :
1406 : 5 : if (!app_info)
1407 : : {
1408 : 4 : launch_default_app_for_default_handler (g_steal_pointer (&task));
1409 : : }
1410 : : else
1411 : : {
1412 : 1 : launch_default_for_uri_launch_uris (g_steal_pointer (&task),
1413 : 1 : g_steal_pointer (&app_info));
1414 : : }
1415 : 5 : }
1416 : :
1417 : : /**
1418 : : * g_app_info_launch_default_for_uri_async:
1419 : : * @uri: the uri to show
1420 : : * @context: (nullable): optional launch context
1421 : : * @cancellable: (nullable): a [class@Gio.Cancellable]
1422 : : * @callback: (scope async) (nullable): a [type@Gio.AsyncReadyCallback] to call
1423 : : * when the request is done
1424 : : * @user_data: (nullable): data to pass to @callback
1425 : : *
1426 : : * Async version of [func@Gio.AppInfo.launch_default_for_uri].
1427 : : *
1428 : : * This version is useful if you are interested in receiving error information
1429 : : * in the case where the application is sandboxed and the portal may present an
1430 : : * application chooser dialog to the user.
1431 : : *
1432 : : * This is also useful if you want to be sure that the D-Bus–activated
1433 : : * applications are really started before termination and if you are interested
1434 : : * in receiving error information from their activation.
1435 : : *
1436 : : * Since: 2.50
1437 : : */
1438 : : void
1439 : 5 : g_app_info_launch_default_for_uri_async (const char *uri,
1440 : : GAppLaunchContext *context,
1441 : : GCancellable *cancellable,
1442 : : GAsyncReadyCallback callback,
1443 : : gpointer user_data)
1444 : : {
1445 : : GTask *task;
1446 : : char *uri_scheme;
1447 : : LaunchDefaultForUriData *data;
1448 : :
1449 : 5 : g_return_if_fail (uri != NULL);
1450 : :
1451 : 5 : task = g_task_new (NULL, cancellable, callback, user_data);
1452 : 5 : g_task_set_source_tag (task, g_app_info_launch_default_for_uri_async);
1453 : :
1454 : 5 : data = g_new (LaunchDefaultForUriData, 1);
1455 : 5 : data->uri = g_strdup (uri);
1456 : 5 : data->context = (context != NULL) ? g_object_ref (context) : NULL;
1457 : 5 : g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) launch_default_for_uri_data_free);
1458 : :
1459 : : /* g_file_query_default_handler_async() calls
1460 : : * g_app_info_get_default_for_uri_scheme() too, but we have to do it
1461 : : * here anyway in case GFile can't parse @uri correctly.
1462 : : */
1463 : 5 : uri_scheme = g_uri_parse_scheme (uri);
1464 : 5 : if (uri_scheme && uri_scheme[0] != '\0')
1465 : : {
1466 : 5 : g_app_info_get_default_for_uri_scheme_async (uri_scheme,
1467 : : cancellable,
1468 : : launch_default_app_for_uri_cb,
1469 : : g_steal_pointer (&task));
1470 : : }
1471 : : else
1472 : : {
1473 : 0 : launch_default_app_for_default_handler (g_steal_pointer (&task));
1474 : : }
1475 : :
1476 : 5 : g_free (uri_scheme);
1477 : : }
1478 : :
1479 : : /**
1480 : : * g_app_info_launch_default_for_uri_finish:
1481 : : * @result: the async result
1482 : : *
1483 : : * Finishes an asynchronous launch-default-for-uri operation.
1484 : : *
1485 : : * Returns: `TRUE` if the launch was successful, `FALSE` if @error is set
1486 : : *
1487 : : * Since: 2.50
1488 : : */
1489 : : gboolean
1490 : 5 : g_app_info_launch_default_for_uri_finish (GAsyncResult *result,
1491 : : GError **error)
1492 : : {
1493 : 5 : g_return_val_if_fail (g_task_is_valid (result, NULL), FALSE);
1494 : :
1495 : 5 : return g_task_propagate_boolean (G_TASK (result), error);
1496 : : }
1497 : :
1498 : : /**
1499 : : * g_app_info_can_delete:
1500 : : * @appinfo: the app info
1501 : : *
1502 : : * Obtains the information whether the [iface@Gio.AppInfo] can be deleted.
1503 : : * See [method@Gio.AppInfo.delete].
1504 : : *
1505 : : * Returns: `TRUE` if @appinfo can be deleted
1506 : : *
1507 : : * Since: 2.20
1508 : : */
1509 : : gboolean
1510 : 2 : g_app_info_can_delete (GAppInfo *appinfo)
1511 : : {
1512 : : GAppInfoIface *iface;
1513 : :
1514 : 2 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
1515 : :
1516 : 2 : iface = G_APP_INFO_GET_IFACE (appinfo);
1517 : :
1518 : 2 : if (iface->can_delete)
1519 : 2 : return (* iface->can_delete) (appinfo);
1520 : :
1521 : 0 : return FALSE;
1522 : : }
1523 : :
1524 : :
1525 : : /**
1526 : : * g_app_info_delete: (virtual do_delete)
1527 : : * @appinfo: the app info
1528 : : *
1529 : : * Tries to delete a [iface@Gio.AppInfo].
1530 : : *
1531 : : * On some platforms, there may be a difference between user-defined
1532 : : * [iface@Gio.AppInfo]s which can be deleted, and system-wide ones which cannot.
1533 : : * See [method@Gio.AppInfo.can_delete].
1534 : : *
1535 : : * Returns: `TRUE` if @appinfo has been deleted
1536 : : *
1537 : : * Since: 2.20
1538 : : */
1539 : : gboolean
1540 : 12 : g_app_info_delete (GAppInfo *appinfo)
1541 : : {
1542 : : GAppInfoIface *iface;
1543 : :
1544 : 12 : g_return_val_if_fail (G_IS_APP_INFO (appinfo), FALSE);
1545 : :
1546 : 12 : iface = G_APP_INFO_GET_IFACE (appinfo);
1547 : :
1548 : 12 : if (iface->do_delete)
1549 : 12 : return (* iface->do_delete) (appinfo);
1550 : :
1551 : 0 : return FALSE;
1552 : : }
1553 : :
1554 : :
1555 : : enum {
1556 : : LAUNCH_FAILED,
1557 : : LAUNCH_STARTED,
1558 : : LAUNCHED,
1559 : : LAST_SIGNAL
1560 : : };
1561 : :
1562 : : static guint signals[LAST_SIGNAL] = { 0 };
1563 : :
1564 : 227 : G_DEFINE_TYPE_WITH_PRIVATE (GAppLaunchContext, g_app_launch_context, G_TYPE_OBJECT)
1565 : :
1566 : : /**
1567 : : * g_app_launch_context_new:
1568 : : *
1569 : : * Creates a new application launch context. This is not normally used,
1570 : : * instead you instantiate a subclass of this, such as
1571 : : * [`GdkAppLaunchContext`](https://docs.gtk.org/gdk4/class.AppLaunchContext.html).
1572 : : *
1573 : : * Returns: a launch context.
1574 : : **/
1575 : : GAppLaunchContext *
1576 : 4 : g_app_launch_context_new (void)
1577 : : {
1578 : 4 : return g_object_new (G_TYPE_APP_LAUNCH_CONTEXT, NULL);
1579 : : }
1580 : :
1581 : : static void
1582 : 52 : g_app_launch_context_finalize (GObject *object)
1583 : : {
1584 : 52 : GAppLaunchContext *context = G_APP_LAUNCH_CONTEXT (object);
1585 : :
1586 : 52 : g_strfreev (context->priv->envp);
1587 : :
1588 : 52 : G_OBJECT_CLASS (g_app_launch_context_parent_class)->finalize (object);
1589 : 52 : }
1590 : :
1591 : : static void
1592 : 5 : g_app_launch_context_class_init (GAppLaunchContextClass *klass)
1593 : : {
1594 : 5 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
1595 : :
1596 : 5 : object_class->finalize = g_app_launch_context_finalize;
1597 : :
1598 : : /**
1599 : : * GAppLaunchContext::launch-failed:
1600 : : * @context: the object emitting the signal
1601 : : * @startup_notify_id: the startup notification id for the failed launch
1602 : : *
1603 : : * The [signal@Gio.AppLaunchContext::launch-failed] signal is emitted when a
1604 : : * [iface@Gio.AppInfo] launch fails. The startup notification id is provided,
1605 : : * so that the launcher can cancel the startup notification.
1606 : : *
1607 : : * Because a launch operation may involve spawning multiple instances of the
1608 : : * target application, you should expect this signal to be emitted multiple
1609 : : * times, one for each spawned instance.
1610 : : *
1611 : : * Since: 2.36
1612 : : */
1613 : 5 : signals[LAUNCH_FAILED] = g_signal_new (I_("launch-failed"),
1614 : : G_OBJECT_CLASS_TYPE (object_class),
1615 : : G_SIGNAL_RUN_LAST,
1616 : : G_STRUCT_OFFSET (GAppLaunchContextClass, launch_failed),
1617 : : NULL, NULL, NULL,
1618 : : G_TYPE_NONE, 1, G_TYPE_STRING);
1619 : :
1620 : : /**
1621 : : * GAppLaunchContext::launch-started:
1622 : : * @context: the object emitting the signal
1623 : : * @info: the [iface@Gio.AppInfo] that is about to be launched
1624 : : * @platform_data: (nullable): additional platform-specific data for this launch
1625 : : *
1626 : : * The [signal@Gio.AppLaunchContext::launch-started] signal is emitted when a
1627 : : * [iface@Gio.AppInfo] is about to be launched. If non-null the
1628 : : * @platform_data is an GVariant dictionary mapping strings to variants
1629 : : * (ie `a{sv}`), which contains additional, platform-specific data about this
1630 : : * launch. On UNIX, at least the `startup-notification-id` keys will be
1631 : : * present.
1632 : : *
1633 : : * The value of the `startup-notification-id` key (type `s`) is a startup
1634 : : * notification ID corresponding to the format from the [startup-notification
1635 : : * specification](https://specifications.freedesktop.org/startup-notification-spec/startup-notification-0.1.txt).
1636 : : * It allows tracking the progress of the launchee through startup.
1637 : : *
1638 : : * It is guaranteed that this signal is followed by either a
1639 : : * [signal@Gio.AppLaunchContext::launched] or
1640 : : * [signal@Gio.AppLaunchContext::launch-failed] signal.
1641 : : *
1642 : : * Because a launch operation may involve spawning multiple instances of the
1643 : : * target application, you should expect this signal to be emitted multiple
1644 : : * times, one for each spawned instance.
1645 : : *
1646 : : * Since: 2.72
1647 : : */
1648 : 5 : signals[LAUNCH_STARTED] = g_signal_new (I_("launch-started"),
1649 : : G_OBJECT_CLASS_TYPE (object_class),
1650 : : G_SIGNAL_RUN_LAST,
1651 : : G_STRUCT_OFFSET (GAppLaunchContextClass, launch_started),
1652 : : NULL, NULL,
1653 : : _g_cclosure_marshal_VOID__OBJECT_VARIANT,
1654 : : G_TYPE_NONE, 2,
1655 : : G_TYPE_APP_INFO, G_TYPE_VARIANT);
1656 : 5 : g_signal_set_va_marshaller (signals[LAUNCH_STARTED],
1657 : : G_TYPE_FROM_CLASS (klass),
1658 : : _g_cclosure_marshal_VOID__OBJECT_VARIANTv);
1659 : :
1660 : : /**
1661 : : * GAppLaunchContext::launched:
1662 : : * @context: the object emitting the signal
1663 : : * @info: the [iface@Gio.AppInfo] that was just launched
1664 : : * @platform_data: additional platform-specific data for this launch
1665 : : *
1666 : : * The [signal@Gio.AppLaunchContext::launched] signal is emitted when a
1667 : : * [iface@Gio.AppInfo] is successfully launched.
1668 : : *
1669 : : * Because a launch operation may involve spawning multiple instances of the
1670 : : * target application, you should expect this signal to be emitted multiple
1671 : : * times, one time for each spawned instance.
1672 : : *
1673 : : * The @platform_data is an GVariant dictionary mapping
1674 : : * strings to variants (ie `a{sv}`), which contains additional,
1675 : : * platform-specific data about this launch. On UNIX, at least the
1676 : : * `pid` and `startup-notification-id` keys will be present.
1677 : : *
1678 : : * Since 2.72 the `pid` may be 0 if the process id wasn’t known (for
1679 : : * example if the process was launched via D-Bus). The `pid` may not be
1680 : : * set at all in subsequent releases.
1681 : : *
1682 : : * On Windows, `pid` is guaranteed to be valid only for the duration of the
1683 : : * [signal@Gio.AppLaunchContext::launched] signal emission; after the signal
1684 : : * is emitted, GLib will call [func@GLib.spawn_close_pid]. If you need to
1685 : : * keep the [alias@GLib.Pid] after the signal has been emitted, then you can
1686 : : * duplicate `pid` using `DuplicateHandle()`.
1687 : : *
1688 : : * Since: 2.36
1689 : : */
1690 : 5 : signals[LAUNCHED] = g_signal_new (I_("launched"),
1691 : : G_OBJECT_CLASS_TYPE (object_class),
1692 : : G_SIGNAL_RUN_LAST,
1693 : : G_STRUCT_OFFSET (GAppLaunchContextClass, launched),
1694 : : NULL, NULL,
1695 : : _g_cclosure_marshal_VOID__OBJECT_VARIANT,
1696 : : G_TYPE_NONE, 2,
1697 : : G_TYPE_APP_INFO, G_TYPE_VARIANT);
1698 : 5 : g_signal_set_va_marshaller (signals[LAUNCHED],
1699 : : G_TYPE_FROM_CLASS (klass),
1700 : : _g_cclosure_marshal_VOID__OBJECT_VARIANTv);
1701 : 5 : }
1702 : :
1703 : : static void
1704 : 52 : g_app_launch_context_init (GAppLaunchContext *context)
1705 : : {
1706 : 52 : context->priv = g_app_launch_context_get_instance_private (context);
1707 : 52 : }
1708 : :
1709 : : /**
1710 : : * g_app_launch_context_setenv:
1711 : : * @context: the launch context
1712 : : * @variable: (type filename): the environment variable to set
1713 : : * @value: (type filename): the value for to set the variable to.
1714 : : *
1715 : : * Arranges for @variable to be set to @value in the child’s environment when
1716 : : * @context is used to launch an application.
1717 : : *
1718 : : * Since: 2.32
1719 : : */
1720 : : void
1721 : 27 : g_app_launch_context_setenv (GAppLaunchContext *context,
1722 : : const char *variable,
1723 : : const char *value)
1724 : : {
1725 : 27 : g_return_if_fail (G_IS_APP_LAUNCH_CONTEXT (context));
1726 : 27 : g_return_if_fail (variable != NULL);
1727 : 27 : g_return_if_fail (value != NULL);
1728 : :
1729 : 27 : if (!context->priv->envp)
1730 : 24 : context->priv->envp = g_get_environ ();
1731 : :
1732 : 27 : context->priv->envp =
1733 : 27 : g_environ_setenv (context->priv->envp, variable, value, TRUE);
1734 : : }
1735 : :
1736 : : /**
1737 : : * g_app_launch_context_unsetenv:
1738 : : * @context: the launch context
1739 : : * @variable: (type filename): the environment variable to remove
1740 : : *
1741 : : * Arranges for @variable to be unset in the child’s environment when @context
1742 : : * is used to launch an application.
1743 : : *
1744 : : * Since: 2.32
1745 : : */
1746 : : void
1747 : 1 : g_app_launch_context_unsetenv (GAppLaunchContext *context,
1748 : : const char *variable)
1749 : : {
1750 : 1 : g_return_if_fail (G_IS_APP_LAUNCH_CONTEXT (context));
1751 : 1 : g_return_if_fail (variable != NULL);
1752 : :
1753 : 1 : if (!context->priv->envp)
1754 : 0 : context->priv->envp = g_get_environ ();
1755 : :
1756 : 1 : context->priv->envp =
1757 : 1 : g_environ_unsetenv (context->priv->envp, variable);
1758 : : }
1759 : :
1760 : : /**
1761 : : * g_app_launch_context_get_environment:
1762 : : * @context: the launch context
1763 : : *
1764 : : * Gets the complete environment variable list to be passed to
1765 : : * the child process when @context is used to launch an application.
1766 : : * This is a `NULL`-terminated array of strings, where each string has
1767 : : * the form `KEY=VALUE`.
1768 : : *
1769 : : * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
1770 : : * the child’s environment
1771 : : *
1772 : : * Since: 2.32
1773 : : */
1774 : : char **
1775 : 44 : g_app_launch_context_get_environment (GAppLaunchContext *context)
1776 : : {
1777 : 44 : g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL);
1778 : :
1779 : 44 : if (!context->priv->envp)
1780 : 17 : context->priv->envp = g_get_environ ();
1781 : :
1782 : 44 : return g_strdupv (context->priv->envp);
1783 : : }
1784 : :
1785 : : /**
1786 : : * g_app_launch_context_get_display:
1787 : : * @context: the launch context
1788 : : * @info: the app info
1789 : : * @files: (element-type GFile): a list of [iface@Gio.File] objects
1790 : : *
1791 : : * Gets the display string for the @context. This is used to ensure new
1792 : : * applications are started on the same display as the launching
1793 : : * application, by setting the `DISPLAY` environment variable.
1794 : : *
1795 : : * Returns: (nullable): a display string for the display.
1796 : : */
1797 : : char *
1798 : 1 : g_app_launch_context_get_display (GAppLaunchContext *context,
1799 : : GAppInfo *info,
1800 : : GList *files)
1801 : : {
1802 : : GAppLaunchContextClass *class;
1803 : :
1804 : 1 : g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL);
1805 : 1 : g_return_val_if_fail (G_IS_APP_INFO (info), NULL);
1806 : :
1807 : 1 : class = G_APP_LAUNCH_CONTEXT_GET_CLASS (context);
1808 : :
1809 : 1 : if (class->get_display == NULL)
1810 : 1 : return NULL;
1811 : :
1812 : 0 : return class->get_display (context, info, files);
1813 : : }
1814 : :
1815 : : /**
1816 : : * g_app_launch_context_get_startup_notify_id:
1817 : : * @context: the launch context
1818 : : * @info: (nullable): the app info
1819 : : * @files: (nullable) (element-type GFile): a list of [iface@Gio.File] objects
1820 : : *
1821 : : * Initiates startup notification for the application and returns the
1822 : : * `XDG_ACTIVATION_TOKEN` or `DESKTOP_STARTUP_ID` for the launched operation,
1823 : : * if supported.
1824 : : *
1825 : : * The returned token may be referred to equivalently as an ‘activation token’
1826 : : * (using Wayland terminology) or a ‘startup sequence ID’ (using X11 terminology).
1827 : : * The two [are interoperable](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/xdg-activation/x11-interoperation.rst).
1828 : : *
1829 : : * Activation tokens are defined in the [XDG Activation Protocol](https://wayland.app/protocols/xdg-activation-v1),
1830 : : * and startup notification IDs are defined in the
1831 : : * [freedesktop.org Startup Notification Protocol](http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt).
1832 : : *
1833 : : * Support for the XDG Activation Protocol was added in GLib 2.76.
1834 : : * Since GLib 2.82 @info and @files can be `NULL`. If that’s not supported by the backend,
1835 : : * the returned token will be `NULL`.
1836 : : *
1837 : : * Returns: (nullable): a startup notification ID for the application, or `NULL` if
1838 : : * not supported.
1839 : : **/
1840 : : char *
1841 : 18 : g_app_launch_context_get_startup_notify_id (GAppLaunchContext *context,
1842 : : GAppInfo *info,
1843 : : GList *files)
1844 : : {
1845 : : GAppLaunchContextClass *class;
1846 : :
1847 : 18 : g_return_val_if_fail (G_IS_APP_LAUNCH_CONTEXT (context), NULL);
1848 : 18 : g_return_val_if_fail (info == NULL || G_IS_APP_INFO (info), NULL);
1849 : :
1850 : 18 : class = G_APP_LAUNCH_CONTEXT_GET_CLASS (context);
1851 : :
1852 : 18 : if (class->get_startup_notify_id == NULL)
1853 : 2 : return NULL;
1854 : :
1855 : 16 : return class->get_startup_notify_id (context, info, files);
1856 : : }
1857 : :
1858 : :
1859 : : /**
1860 : : * g_app_launch_context_launch_failed:
1861 : : * @context: the launch context
1862 : : * @startup_notify_id: the startup notification id that was returned by
1863 : : * [method@Gio.AppLaunchContext.get_startup_notify_id].
1864 : : *
1865 : : * Called when an application has failed to launch, so that it can cancel
1866 : : * the application startup notification started in
1867 : : * [method@Gio.AppLaunchContext.get_startup_notify_id].
1868 : : *
1869 : : **/
1870 : : void
1871 : 2 : g_app_launch_context_launch_failed (GAppLaunchContext *context,
1872 : : const char *startup_notify_id)
1873 : : {
1874 : 2 : g_return_if_fail (G_IS_APP_LAUNCH_CONTEXT (context));
1875 : 2 : g_return_if_fail (startup_notify_id != NULL);
1876 : :
1877 : 2 : g_signal_emit (context, signals[LAUNCH_FAILED], 0, startup_notify_id);
1878 : : }
1879 : :
1880 : :
1881 : : /**
1882 : : * GAppInfoMonitor:
1883 : : *
1884 : : * `GAppInfoMonitor` monitors application information for changes.
1885 : : *
1886 : : * `GAppInfoMonitor` is a very simple object used for monitoring the app
1887 : : * info database for changes (newly installed or removed applications).
1888 : : *
1889 : : * Call [func@Gio.AppInfoMonitor.get] to get a `GAppInfoMonitor` and connect
1890 : : * to the [signal@Gio.AppInfoMonitor::changed] signal. The signal will be emitted once when
1891 : : * the app info database changes, and will not be emitted again until after the
1892 : : * next call to [func@Gio.AppInfo.get_all] or another `g_app_info_*()` function.
1893 : : * This is because monitoring the app info database for changes is expensive.
1894 : : *
1895 : : * The following functions will re-arm the [signal@Gio.AppInfoMonitor::changed]
1896 : : * signal so it can be emitted again:
1897 : : *
1898 : : * - [func@Gio.AppInfo.get_all]
1899 : : * - [func@Gio.AppInfo.get_all_for_type]
1900 : : * - [func@Gio.AppInfo.get_default_for_type]
1901 : : * - [func@Gio.AppInfo.get_fallback_for_type]
1902 : : * - [func@Gio.AppInfo.get_recommended_for_type]
1903 : : * - [`g_desktop_app_info_get_implementations()`](../gio-unix/type_func.DesktopAppInfo.get_implementation.html)
1904 : : * - [`g_desktop_app_info_new()`](../gio-unix/ctor.DesktopAppInfo.new.html)
1905 : : * - [`g_desktop_app_info_new_from_filename()`](../gio-unix/ctor.DesktopAppInfo.new_from_filename.html)
1906 : : * - [`g_desktop_app_info_new_from_keyfile()`](../gio-unix/ctor.DesktopAppInfo.new_from_keyfile.html)
1907 : : * - [`g_desktop_app_info_search()`](../gio-unix/type_func.DesktopAppInfo.search.html)
1908 : : *
1909 : : * The latter functions are available if using
1910 : : * [`GDesktopAppInfo`](../gio-unix/class.DesktopAppInfo.html) from
1911 : : * `gio-unix-2.0.pc` (GIR namespace `GioUnix-2.0`).
1912 : : *
1913 : : * In the usual case, applications should try to make note of the change
1914 : : * (doing things like invalidating caches) but not act on it. In
1915 : : * particular, applications should avoid making calls to `GAppInfo` APIs
1916 : : * in response to the change signal, deferring these until the time that
1917 : : * the updated data is actually required. The exception to this case is when
1918 : : * application information is actually being displayed on the screen
1919 : : * (for example, during a search or when the list of all applications is shown).
1920 : : * The reason for this is that changes to the list of installed applications
1921 : : * often come in groups (like during system updates) and rescanning the list
1922 : : * on every change is pointless and expensive.
1923 : : *
1924 : : * Since: 2.40
1925 : : */
1926 : :
1927 : : typedef struct _GAppInfoMonitorClass GAppInfoMonitorClass;
1928 : :
1929 : : struct _GAppInfoMonitor
1930 : : {
1931 : : GObject parent_instance;
1932 : : GMainContext *context;
1933 : : };
1934 : :
1935 : : struct _GAppInfoMonitorClass
1936 : : {
1937 : : GObjectClass parent_class;
1938 : : };
1939 : :
1940 : : static GContextSpecificGroup g_app_info_monitor_group;
1941 : : static guint g_app_info_monitor_changed_signal;
1942 : :
1943 : 178 : G_DEFINE_TYPE (GAppInfoMonitor, g_app_info_monitor, G_TYPE_OBJECT)
1944 : :
1945 : : static void
1946 : 1 : g_app_info_monitor_finalize (GObject *object)
1947 : : {
1948 : 1 : GAppInfoMonitor *monitor = G_APP_INFO_MONITOR (object);
1949 : :
1950 : 1 : g_context_specific_group_remove (&g_app_info_monitor_group, monitor->context, monitor, NULL);
1951 : :
1952 : 1 : G_OBJECT_CLASS (g_app_info_monitor_parent_class)->finalize (object);
1953 : 1 : }
1954 : :
1955 : : static void
1956 : 1 : g_app_info_monitor_init (GAppInfoMonitor *monitor)
1957 : : {
1958 : 1 : }
1959 : :
1960 : : static void
1961 : 2 : g_app_info_monitor_class_init (GAppInfoMonitorClass *class)
1962 : : {
1963 : 2 : GObjectClass *object_class = G_OBJECT_CLASS (class);
1964 : :
1965 : : /**
1966 : : * GAppInfoMonitor::changed:
1967 : : *
1968 : : * Signal emitted when the app info database changes, when applications are
1969 : : * installed or removed.
1970 : : *
1971 : : * Since: 2.40
1972 : : **/
1973 : 2 : g_app_info_monitor_changed_signal = g_signal_new (I_("changed"), G_TYPE_APP_INFO_MONITOR, G_SIGNAL_RUN_FIRST,
1974 : : 0, NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1975 : :
1976 : 2 : object_class->finalize = g_app_info_monitor_finalize;
1977 : 2 : }
1978 : :
1979 : : /**
1980 : : * g_app_info_monitor_get:
1981 : : *
1982 : : * Gets the #GAppInfoMonitor for the current thread-default main
1983 : : * context.
1984 : : *
1985 : : * The #GAppInfoMonitor will emit a “changed” signal in the
1986 : : * thread-default main context whenever the list of installed
1987 : : * applications (as reported by g_app_info_get_all()) may have changed.
1988 : : *
1989 : : * The #GAppInfoMonitor::changed signal will only be emitted once until
1990 : : * g_app_info_get_all() (or another `g_app_info_*()` function) is called. Doing
1991 : : * so will re-arm the signal ready to notify about the next change.
1992 : : *
1993 : : * You must only call g_object_unref() on the return value from under
1994 : : * the same main context as you created it.
1995 : : *
1996 : : * Returns: (transfer full): a reference to a #GAppInfoMonitor
1997 : : *
1998 : : * Since: 2.40
1999 : : **/
2000 : : GAppInfoMonitor *
2001 : 1 : g_app_info_monitor_get (void)
2002 : : {
2003 : 1 : return g_context_specific_group_get (&g_app_info_monitor_group,
2004 : : G_TYPE_APP_INFO_MONITOR,
2005 : : G_STRUCT_OFFSET (GAppInfoMonitor, context),
2006 : : NULL);
2007 : : }
2008 : :
2009 : : void
2010 : 357 : g_app_info_monitor_fire (void)
2011 : : {
2012 : 357 : g_context_specific_group_emit (&g_app_info_monitor_group, g_app_info_monitor_changed_signal);
2013 : 357 : }
|