1
/* eggdesktopfile.c - Freedesktop.Org Desktop Files
2
* Copyright (C) 2007 Novell, Inc.
4
* Based on gnome-desktop-item.c
5
* Copyright (C) 1999, 2000 Red Hat Inc.
6
* Copyright (C) 2001 George Lebl
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public License
10
* as published by the Free Software Foundation; either version 2 of
11
* the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful, but
14
* WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; see the file COPYING.LIB. If not,
20
* write to the Free Software Foundation, Inc., 59 Temple Place -
21
* Suite 330, Boston, MA 02111-1307, USA.
28
#include "eggdesktopfile.h"
33
#include <glib/gi18n.h>
37
struct EggDesktopFile {
42
EggDesktopFileType type;
47
* egg_desktop_file_new:
48
* @desktop_file_path: path to a Freedesktop-style Desktop file
49
* @error: error pointer
51
* Creates a new #EggDesktopFile for @desktop_file.
53
* Return value: the new #EggDesktopFile, or %NULL on error.
56
egg_desktop_file_new (const char *desktop_file_path, GError **error)
60
key_file = g_key_file_new ();
61
if (!g_key_file_load_from_file (key_file, desktop_file_path, 0, error))
63
g_key_file_free (key_file);
67
return egg_desktop_file_new_from_key_file (key_file, desktop_file_path,
72
* egg_desktop_file_new_from_data_dirs:
73
* @desktop_file_path: relative path to a Freedesktop-style Desktop file
74
* @error: error pointer
76
* Looks for @desktop_file_path in the paths returned from
77
* g_get_user_data_dir() and g_get_system_data_dirs(), and creates
78
* a new #EggDesktopFile from it.
80
* Return value: the new #EggDesktopFile, or %NULL on error.
83
egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
86
EggDesktopFile *desktop_file;
90
key_file = g_key_file_new ();
91
if (!g_key_file_load_from_data_dirs (key_file, desktop_file_path,
92
&full_path, 0, error))
94
g_key_file_free (key_file);
98
desktop_file = egg_desktop_file_new_from_key_file (key_file,
106
* egg_desktop_file_new_from_dirs:
107
* @desktop_file_path: relative path to a Freedesktop-style Desktop file
108
* @search_dirs: NULL-terminated array of directories to search
109
* @error: error pointer
111
* Looks for @desktop_file_path in the paths returned from
112
* g_get_user_data_dir() and g_get_system_data_dirs(), and creates
113
* a new #EggDesktopFile from it.
115
* Return value: the new #EggDesktopFile, or %NULL on error.
118
egg_desktop_file_new_from_dirs (const char *desktop_file_path,
119
const char **search_dirs,
122
EggDesktopFile *desktop_file;
126
key_file = g_key_file_new ();
127
if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs,
128
&full_path, 0, error))
130
g_key_file_free (key_file);
134
desktop_file = egg_desktop_file_new_from_key_file (key_file,
142
* egg_desktop_file_new_from_key_file:
143
* @key_file: a #GKeyFile representing a desktop file
144
* @source: the path or URI that @key_file was loaded from, or %NULL
145
* @error: error pointer
147
* Creates a new #EggDesktopFile for @key_file. Assumes ownership of
148
* @key_file (on success or failure); you should consider @key_file to
149
* be freed after calling this function.
151
* Return value: the new #EggDesktopFile, or %NULL on error.
154
egg_desktop_file_new_from_key_file (GKeyFile *key_file,
158
EggDesktopFile *desktop_file;
159
char *version, *type;
161
if (!g_key_file_has_group (key_file, EGG_DESKTOP_FILE_GROUP))
163
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
164
EGG_DESKTOP_FILE_ERROR_INVALID,
165
_("File is not a valid .desktop file"));
166
g_key_file_free (key_file);
170
version = g_key_file_get_value (key_file, EGG_DESKTOP_FILE_GROUP,
171
EGG_DESKTOP_FILE_KEY_VERSION,
178
version_num = g_ascii_strtod (version, &end);
181
g_warning ("Invalid Version string '%s' in %s",
182
version, source ? source : "(unknown)");
184
else if (version_num > 1.0)
186
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
187
EGG_DESKTOP_FILE_ERROR_INVALID,
188
_("Unrecognized desktop file Version '%s'"), version);
190
g_key_file_free (key_file);
196
desktop_file = g_new0 (EggDesktopFile, 1);
197
desktop_file->key_file = key_file;
199
if (g_path_is_absolute (source))
200
desktop_file->source = g_filename_to_uri (source, NULL, NULL);
202
desktop_file->source = g_strdup (source);
204
desktop_file->name = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP,
205
EGG_DESKTOP_FILE_KEY_NAME, error);
206
if (!desktop_file->name)
208
egg_desktop_file_free (desktop_file);
212
type = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP,
213
EGG_DESKTOP_FILE_KEY_TYPE, error);
216
egg_desktop_file_free (desktop_file);
220
if (!strcmp (type, "Application"))
224
desktop_file->type = EGG_DESKTOP_FILE_TYPE_APPLICATION;
226
exec = g_key_file_get_string (key_file,
227
EGG_DESKTOP_FILE_GROUP,
228
EGG_DESKTOP_FILE_KEY_EXEC,
232
egg_desktop_file_free (desktop_file);
237
/* See if it takes paths or URIs or neither */
238
for (p = exec; *p; p++)
242
if (p[1] == '\0' || strchr ("FfUu", p[1]))
244
desktop_file->document_code = p[1];
253
else if (!strcmp (type, "Link"))
257
desktop_file->type = EGG_DESKTOP_FILE_TYPE_LINK;
259
url = g_key_file_get_string (key_file,
260
EGG_DESKTOP_FILE_GROUP,
261
EGG_DESKTOP_FILE_KEY_URL,
265
egg_desktop_file_free (desktop_file);
271
else if (!strcmp (type, "Directory"))
272
desktop_file->type = EGG_DESKTOP_FILE_TYPE_DIRECTORY;
274
desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED;
278
/* Check the Icon key */
279
desktop_file->icon = g_key_file_get_string (key_file,
280
EGG_DESKTOP_FILE_GROUP,
281
EGG_DESKTOP_FILE_KEY_ICON,
283
if (desktop_file->icon && !g_path_is_absolute (desktop_file->icon))
287
/* Lots of .desktop files still get this wrong */
288
ext = strrchr (desktop_file->icon, '.');
289
if (ext && (!strcmp (ext, ".png") ||
290
!strcmp (ext, ".xpm") ||
291
!strcmp (ext, ".svg")))
293
g_warning ("Desktop file '%s' has malformed Icon key '%s'"
294
"(should not include extension)",
295
source ? source : "(unknown)",
305
* egg_desktop_file_free:
306
* @desktop_file: an #EggDesktopFile
308
* Frees @desktop_file.
311
egg_desktop_file_free (EggDesktopFile *desktop_file)
313
g_key_file_free (desktop_file->key_file);
314
g_free (desktop_file->source);
315
g_free (desktop_file->name);
316
g_free (desktop_file->icon);
317
g_free (desktop_file);
321
* egg_desktop_file_get_source:
322
* @desktop_file: an #EggDesktopFile
324
* Gets the URI that @desktop_file was loaded from.
326
* Return value: @desktop_file's source URI
329
egg_desktop_file_get_source (EggDesktopFile *desktop_file)
331
return desktop_file->source;
335
* egg_desktop_file_get_desktop_file_type:
336
* @desktop_file: an #EggDesktopFile
338
* Gets the desktop file type of @desktop_file.
340
* Return value: @desktop_file's type
343
egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file)
345
return desktop_file->type;
349
* egg_desktop_file_get_name:
350
* @desktop_file: an #EggDesktopFile
352
* Gets the (localized) value of @desktop_file's "Name" key.
354
* Return value: the application/link name
357
egg_desktop_file_get_name (EggDesktopFile *desktop_file)
359
return desktop_file->name;
363
* egg_desktop_file_get_icon:
364
* @desktop_file: an #EggDesktopFile
366
* Gets the value of @desktop_file's "Icon" key.
368
* If the icon string is a full path (that is, if g_path_is_absolute()
369
* returns %TRUE when called on it), it points to a file containing an
370
* unthemed icon. If the icon string is not a full path, it is the
371
* name of a themed icon, which can be looked up with %GtkIconTheme,
372
* or passed directly to a theme-aware widget like %GtkImage or
373
* %GtkCellRendererPixbuf.
375
* Return value: the icon path or name
378
egg_desktop_file_get_icon (EggDesktopFile *desktop_file)
380
return desktop_file->icon;
384
egg_desktop_file_has_key (EggDesktopFile *desktop_file,
388
return g_key_file_has_key (desktop_file->key_file,
389
EGG_DESKTOP_FILE_GROUP, key,
394
egg_desktop_file_get_string (EggDesktopFile *desktop_file,
398
return g_key_file_get_string (desktop_file->key_file,
399
EGG_DESKTOP_FILE_GROUP, key,
404
egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
409
return g_key_file_get_locale_string (desktop_file->key_file,
410
EGG_DESKTOP_FILE_GROUP, key, locale,
415
egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
419
return g_key_file_get_boolean (desktop_file->key_file,
420
EGG_DESKTOP_FILE_GROUP, key,
425
egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
429
return g_key_file_get_double (desktop_file->key_file,
430
EGG_DESKTOP_FILE_GROUP, key,
435
egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
440
return g_key_file_get_string_list (desktop_file->key_file,
441
EGG_DESKTOP_FILE_GROUP, key, length,
446
egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
452
return g_key_file_get_locale_string_list (desktop_file->key_file,
453
EGG_DESKTOP_FILE_GROUP, key,
459
* egg_desktop_file_can_launch:
460
* @desktop_file: an #EggDesktopFile
461
* @desktop_environment: the name of the running desktop environment,
464
* Tests if @desktop_file can/should be launched in the current
465
* environment. If @desktop_environment is non-%NULL, @desktop_file's
466
* "OnlyShowIn" and "NotShowIn" keys are checked to make sure that
467
* this desktop_file is appropriate for the named environment.
469
* Furthermore, if @desktop_file has type
470
* %EGG_DESKTOP_FILE_TYPE_APPLICATION, its "TryExec" key (if any) is
471
* also checked, to make sure the binary it points to exists.
473
* egg_desktop_file_can_launch() does NOT check the value of the
476
* Return value: %TRUE if @desktop_file can be launched
479
egg_desktop_file_can_launch (EggDesktopFile *desktop_file,
480
const char *desktop_environment)
482
char *try_exec, *found_program;
483
char **only_show_in, **not_show_in;
487
if (desktop_file->type != EGG_DESKTOP_FILE_TYPE_APPLICATION &&
488
desktop_file->type != EGG_DESKTOP_FILE_TYPE_LINK)
491
if (desktop_environment)
493
only_show_in = g_key_file_get_string_list (desktop_file->key_file,
494
EGG_DESKTOP_FILE_GROUP,
495
EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN,
499
for (i = 0, found = FALSE; only_show_in[i] && !found; i++)
501
if (!strcmp (only_show_in[i], desktop_environment))
505
g_strfreev (only_show_in);
511
not_show_in = g_key_file_get_string_list (desktop_file->key_file,
512
EGG_DESKTOP_FILE_GROUP,
513
EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN,
517
for (i = 0, found = FALSE; not_show_in[i] && !found; i++)
519
if (!strcmp (not_show_in[i], desktop_environment))
523
g_strfreev (not_show_in);
530
if (desktop_file->type == EGG_DESKTOP_FILE_TYPE_APPLICATION)
532
try_exec = g_key_file_get_string (desktop_file->key_file,
533
EGG_DESKTOP_FILE_GROUP,
534
EGG_DESKTOP_FILE_KEY_TRY_EXEC,
538
found_program = g_find_program_in_path (try_exec);
543
g_free (found_program);
551
* egg_desktop_file_accepts_documents:
552
* @desktop_file: an #EggDesktopFile
554
* Tests if @desktop_file represents an application that can accept
555
* documents on the command line.
557
* Return value: %TRUE or %FALSE
560
egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file)
562
return desktop_file->document_code != 0;
566
* egg_desktop_file_accepts_multiple:
567
* @desktop_file: an #EggDesktopFile
569
* Tests if @desktop_file can accept multiple documents at once.
571
* If this returns %FALSE, you can still pass multiple documents to
572
* egg_desktop_file_launch(), but that will result in multiple copies
573
* of the application being launched. See egg_desktop_file_launch()
576
* Return value: %TRUE or %FALSE
579
egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file)
581
return (desktop_file->document_code == 'F' ||
582
desktop_file->document_code == 'U');
586
* egg_desktop_file_accepts_uris:
587
* @desktop_file: an #EggDesktopFile
589
* Tests if @desktop_file can accept (non-"file:") URIs as documents to
592
* Return value: %TRUE or %FALSE
595
egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file)
597
return (desktop_file->document_code == 'U' ||
598
desktop_file->document_code == 'u');
602
append_quoted_word (GString *str,
604
gboolean in_single_quotes,
605
gboolean in_double_quotes)
609
if (!in_single_quotes && !in_double_quotes)
610
g_string_append_c (str, '\'');
611
else if (!in_single_quotes && in_double_quotes)
612
g_string_append (str, "\"'");
614
if (!strchr (s, '\''))
615
g_string_append (str, s);
618
for (p = s; *p != '\0'; p++)
621
g_string_append (str, "'\\''");
623
g_string_append_c (str, *p);
627
if (!in_single_quotes && !in_double_quotes)
628
g_string_append_c (str, '\'');
629
else if (!in_single_quotes && in_double_quotes)
630
g_string_append (str, "'\"");
634
do_percent_subst (EggDesktopFile *desktop_file,
638
gboolean in_single_quotes,
639
gboolean in_double_quotes)
647
g_string_append_c (str, '%');
652
for (d = *documents; d; d = d->next)
655
g_string_append (str, " ");
656
append_quoted_word (str, doc, in_single_quotes, in_double_quotes);
665
doc = (*documents)->data;
666
g_string_append (str, " ");
667
append_quoted_word (str, doc, in_single_quotes, in_double_quotes);
668
*documents = (*documents)->next;
673
if (desktop_file->icon)
675
g_string_append (str, "--icon ");
676
append_quoted_word (str, desktop_file->icon,
677
in_single_quotes, in_double_quotes);
682
if (desktop_file->name)
684
append_quoted_word (str, desktop_file->name,
685
in_single_quotes, in_double_quotes);
690
if (desktop_file->source)
692
append_quoted_word (str, desktop_file->source,
693
in_single_quotes, in_double_quotes);
703
/* Deprecated; skip */
707
g_warning ("Unrecognized %%-code '%%%c' in Exec", code);
713
parse_exec (EggDesktopFile *desktop_file,
717
char *exec, *p, *command;
718
gboolean escape, single_quot, double_quot;
721
exec = g_key_file_get_string (desktop_file->key_file,
722
EGG_DESKTOP_FILE_GROUP,
723
EGG_DESKTOP_FILE_KEY_EXEC,
728
/* Build the command */
729
gs = g_string_new (NULL);
730
escape = single_quot = double_quot = FALSE;
732
for (p = exec; *p != '\0'; p++)
737
g_string_append_c (gs, *p);
743
g_string_append_c (gs, *p);
747
g_string_append_c (gs, *p);
748
if (!single_quot && !double_quot)
750
else if (single_quot)
755
g_string_append_c (gs, *p);
756
if (!single_quot && !double_quot)
758
else if (double_quot)
761
else if (*p == '%' && p[1])
763
do_percent_subst (desktop_file, p[1], gs, documents,
764
single_quot, double_quot);
768
g_string_append_c (gs, *p);
772
command = g_string_free (gs, FALSE);
774
/* Prepend "xdg-terminal " if needed (FIXME: use gvfs) */
775
if (g_key_file_has_key (desktop_file->key_file,
776
EGG_DESKTOP_FILE_GROUP,
777
EGG_DESKTOP_FILE_KEY_TERMINAL,
780
GError *terminal_error = NULL;
781
gboolean use_terminal =
782
g_key_file_get_boolean (desktop_file->key_file,
783
EGG_DESKTOP_FILE_GROUP,
784
EGG_DESKTOP_FILE_KEY_TERMINAL,
789
g_propagate_error (error, terminal_error);
795
gs = g_string_new ("xdg-terminal ");
796
append_quoted_word (gs, command, FALSE, FALSE);
798
command = g_string_free (gs, FALSE);
806
translate_document_list (EggDesktopFile *desktop_file, GSList *documents)
808
gboolean accepts_uris = egg_desktop_file_accepts_uris (desktop_file);
811
for (d = documents, ret = NULL; d; d = d->next)
813
const char *document = d->data;
814
gboolean is_uri = !g_path_is_absolute (document);
820
translated = g_strdup (document);
822
translated = g_filename_to_uri (document, NULL, NULL);
827
translated = g_filename_from_uri (document, NULL, NULL);
829
translated = g_strdup (document);
833
ret = g_slist_prepend (ret, translated);
836
return g_slist_reverse (ret);
840
free_document_list (GSList *documents)
844
for (d = documents; d; d = d->next)
846
g_slist_free (documents);
850
* egg_desktop_file_parse_exec:
851
* @desktop_file: a #EggDesktopFile
852
* @documents: a list of document paths or URIs
853
* @error: error pointer
855
* Parses @desktop_file's Exec key, inserting @documents into it, and
856
* returns the result.
858
* If @documents contains non-file: URIs and @desktop_file does not
859
* accept URIs, those URIs will be ignored. Likewise, if @documents
860
* contains more elements than @desktop_file accepts, the extra
861
* documents will be ignored.
863
* Return value: the parsed Exec string
866
egg_desktop_file_parse_exec (EggDesktopFile *desktop_file,
870
GSList *translated, *docs;
873
docs = translated = translate_document_list (desktop_file, documents);
874
command = parse_exec (desktop_file, &docs, error);
875
free_document_list (translated);
881
parse_link (EggDesktopFile *desktop_file,
882
EggDesktopFile **app_desktop_file,
889
url = g_key_file_get_string (desktop_file->key_file,
890
EGG_DESKTOP_FILE_GROUP,
891
EGG_DESKTOP_FILE_KEY_URL,
895
*documents = g_slist_prepend (NULL, url);
897
/* FIXME: use gvfs */
898
key_file = g_key_file_new ();
899
g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP,
900
EGG_DESKTOP_FILE_KEY_NAME,
902
g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP,
903
EGG_DESKTOP_FILE_KEY_TYPE,
905
g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP,
906
EGG_DESKTOP_FILE_KEY_EXEC,
908
*app_desktop_file = egg_desktop_file_new_from_key_file (key_file, NULL, NULL);
912
#if GTK_CHECK_VERSION (2, 12, 0)
914
start_startup_notification (GdkDisplay *display,
915
EggDesktopFile *desktop_file,
921
static int sequence = 0;
923
char *description, *wmclass;
924
char *screen_str, *workspace_str;
926
if (g_key_file_has_key (desktop_file->key_file,
927
EGG_DESKTOP_FILE_GROUP,
928
EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY,
931
if (!g_key_file_get_boolean (desktop_file->key_file,
932
EGG_DESKTOP_FILE_GROUP,
933
EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY,
940
wmclass = g_key_file_get_string (desktop_file->key_file,
941
EGG_DESKTOP_FILE_GROUP,
942
EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS,
948
if (launch_time == (guint32)-1)
949
launch_time = gdk_x11_display_get_user_time (display);
950
startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
952
(unsigned long)getpid (),
956
(unsigned long)launch_time);
958
description = g_strdup_printf (_("Starting %s"), desktop_file->name);
959
screen_str = g_strdup_printf ("%d", screen);
960
workspace_str = workspace == -1 ? NULL : g_strdup_printf ("%d", workspace);
962
gdk_x11_display_broadcast_startup_message (display, "new",
964
"NAME", desktop_file->name,
965
"SCREEN", screen_str,
967
"ICON", desktop_file->icon,
968
"DESKTOP", workspace_str,
969
"DESCRIPTION", description,
973
g_free (description);
976
g_free (workspace_str);
982
end_startup_notification (GdkDisplay *display,
983
const char *startup_id)
985
gdk_x11_display_broadcast_startup_message (display, "remove",
990
#define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */ * 1000)
995
} StartupNotificationData;
998
startup_notification_timeout (gpointer data)
1000
StartupNotificationData *sn_data = data;
1002
end_startup_notification (sn_data->display, sn_data->startup_id);
1003
g_object_unref (sn_data->display);
1004
g_free (sn_data->startup_id);
1011
set_startup_notification_timeout (GdkDisplay *display,
1012
const char *startup_id)
1014
StartupNotificationData *sn_data;
1016
sn_data = g_new (StartupNotificationData, 1);
1017
sn_data->display = g_object_ref (display);
1018
sn_data->startup_id = g_strdup (startup_id);
1020
g_timeout_add (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH,
1021
startup_notification_timeout, sn_data);
1023
#endif /* GTK 2.12 */
1026
array_putenv (GPtrArray *env, char *variable)
1034
env = g_ptr_array_new ();
1036
envp = g_listenv ();
1037
for (i = 0; envp[i]; i++)
1041
value = g_getenv (envp[i]);
1042
g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i],
1043
value ? value : ""));
1048
keylen = strcspn (variable, "=");
1050
/* Remove old value of key */
1051
for (i = 0; i < env->len; i++)
1053
char *envvar = env->pdata[i];
1055
if (!strncmp (envvar, variable, keylen) && envvar[keylen] == '=')
1058
g_ptr_array_remove_index_fast (env, i);
1064
g_ptr_array_add (env, g_strdup (variable));
1070
egg_desktop_file_launchv (EggDesktopFile *desktop_file,
1071
GSList *documents, va_list args,
1074
EggDesktopFileLaunchOption option;
1075
GSList *translated_documents, *docs;
1076
char *command, **argv;
1077
int argc, i, screen_num;
1078
gboolean success, current_success;
1079
GdkDisplay *display;
1082
GPtrArray *env = NULL;
1083
char **variables = NULL;
1084
GdkScreen *screen = NULL;
1086
const char *directory = NULL;
1087
guint32 launch_time = (guint32)-1;
1088
GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
1089
GSpawnChildSetupFunc setup_func = NULL;
1090
gpointer setup_data = NULL;
1092
GPid *ret_pid = NULL;
1093
int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL;
1094
char **ret_startup_id = NULL;
1096
if (documents && desktop_file->document_code == 0)
1098
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
1099
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
1100
_("Application does not accept documents on command line"));
1104
/* Read the options: technically it's incorrect for the caller to
1105
* NULL-terminate the list of options (rather than 0-terminating
1106
* it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED,
1107
* it's more consistent with other glib/gtk methods, and it will
1108
* work as long as sizeof (int) <= sizeof (NULL), and NULL is
1109
* represented as 0. (Which is true everywhere we care about.)
1111
while ((option = va_arg (args, EggDesktopFileLaunchOption)))
1115
case EGG_DESKTOP_FILE_LAUNCH_CLEARENV:
1117
g_ptr_array_free (env, TRUE);
1118
env = g_ptr_array_new ();
1120
case EGG_DESKTOP_FILE_LAUNCH_PUTENV:
1121
variables = va_arg (args, char **);
1122
for (i = 0; variables[i]; i++)
1123
env = array_putenv (env, variables[i]);
1126
case EGG_DESKTOP_FILE_LAUNCH_SCREEN:
1127
screen = va_arg (args, GdkScreen *);
1129
case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE:
1130
workspace = va_arg (args, int);
1133
case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY:
1134
directory = va_arg (args, const char *);
1136
case EGG_DESKTOP_FILE_LAUNCH_TIME:
1137
launch_time = va_arg (args, guint32);
1139
case EGG_DESKTOP_FILE_LAUNCH_FLAGS:
1140
flags |= va_arg (args, GSpawnFlags);
1141
/* Make sure they didn't set any flags that don't make sense. */
1142
flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO;
1144
case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC:
1145
setup_func = va_arg (args, GSpawnChildSetupFunc);
1146
setup_data = va_arg (args, gpointer);
1149
case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID:
1150
ret_pid = va_arg (args, GPid *);
1152
case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE:
1153
ret_stdin = va_arg (args, int *);
1155
case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE:
1156
ret_stdout = va_arg (args, int *);
1158
case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE:
1159
ret_stderr = va_arg (args, int *);
1161
case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID:
1162
ret_startup_id = va_arg (args, char **);
1166
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
1167
EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION,
1168
_("Unrecognized launch option: %d"),
1169
GPOINTER_TO_INT (option));
1177
char *display_name = gdk_screen_make_display_name (screen);
1178
char *display_env = g_strdup_printf ("DISPLAY=%s", display_name);
1179
env = array_putenv (env, display_env);
1180
g_free (display_name);
1181
g_free (display_env);
1183
display = gdk_screen_get_display (screen);
1187
display = gdk_display_get_default ();
1188
screen = gdk_display_get_default_screen (display);
1190
screen_num = gdk_screen_get_number (screen);
1192
translated_documents = translate_document_list (desktop_file, documents);
1193
docs = translated_documents;
1199
command = parse_exec (desktop_file, &docs, error);
1203
if (!g_shell_parse_argv (command, &argc, &argv, error))
1210
#if GTK_CHECK_VERSION (2, 12, 0)
1211
startup_id = start_startup_notification (display, desktop_file,
1212
argv[0], screen_num,
1213
workspace, launch_time);
1216
char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
1218
env = array_putenv (env, startup_id_env);
1219
g_free (startup_id_env);
1223
#endif /* GTK 2.12 */
1226
g_ptr_array_add (env, NULL);
1229
g_spawn_async_with_pipes (directory,
1231
env ? (char **)(env->pdata) : NULL,
1233
setup_func, setup_data,
1235
ret_stdin, ret_stdout, ret_stderr,
1241
#if GTK_CHECK_VERSION (2, 12, 0)
1242
if (current_success)
1244
set_startup_notification_timeout (display, startup_id);
1247
*ret_startup_id = startup_id;
1249
g_free (startup_id);
1252
#endif /* GTK 2.12 */
1253
g_free (startup_id);
1255
else if (ret_startup_id)
1256
*ret_startup_id = NULL;
1258
if (current_success)
1260
/* If we successfully launch any instances of the app, make
1261
* sure we return TRUE and don't set @error.
1266
/* Also, only set the output params on the first one */
1268
ret_stdin = ret_stdout = ret_stderr = NULL;
1269
ret_startup_id = NULL;
1272
while (docs && current_success);
1277
g_strfreev ((char **)env->pdata);
1278
g_ptr_array_free (env, FALSE);
1280
free_document_list (translated_documents);
1286
* egg_desktop_file_launch:
1287
* @desktop_file: an #EggDesktopFile
1288
* @documents: a list of URIs or paths to documents to open
1289
* @error: error pointer
1290
* @...: additional options
1292
* Launches @desktop_file with the given arguments. Additional options
1293
* can be specified as follows:
1295
* %EGG_DESKTOP_FILE_LAUNCH_CLEARENV: (no arguments)
1296
* clears the environment in the child process
1297
* %EGG_DESKTOP_FILE_LAUNCH_PUTENV: (char **variables)
1298
* adds the NAME=VALUE strings in the given %NULL-terminated
1299
* array to the child process's environment
1300
* %EGG_DESKTOP_FILE_LAUNCH_SCREEN: (GdkScreen *screen)
1301
* causes the application to be launched on the given screen
1302
* %EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: (int workspace)
1303
* causes the application to be launched on the given workspace
1304
* %EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: (char *dir)
1305
* causes the application to be launched in the given directory
1306
* %EGG_DESKTOP_FILE_LAUNCH_TIME: (guint32 launch_time)
1307
* sets the "launch time" for the application. If the user
1308
* interacts with another window after @launch_time but before
1309
* the launched application creates its first window, the window
1310
* manager may choose to not give focus to the new application.
1311
* Passing 0 for @launch_time will explicitly request that the
1312
* application not receive focus.
1313
* %EGG_DESKTOP_FILE_LAUNCH_FLAGS (GSpawnFlags flags)
1314
* Sets additional #GSpawnFlags to use. See g_spawn_async() for
1316
* %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC (GSpawnChildSetupFunc, gpointer)
1317
* Sets the child setup callback and the data to pass to it.
1318
* (See g_spawn_async() for more details.)
1320
* %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID (GPid **pid)
1321
* On a successful launch, sets *@pid to the PID of the launched
1323
* %EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID (char **startup_id)
1324
* On a successful launch, sets *@startup_id to the Startup
1325
* Notification "startup id" of the launched application.
1326
* %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE (int *fd)
1327
* On a successful launch, sets *@fd to the file descriptor of
1328
* a pipe connected to the application's stdin.
1329
* %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE (int *fd)
1330
* On a successful launch, sets *@fd to the file descriptor of
1331
* a pipe connected to the application's stdout.
1332
* %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE (int *fd)
1333
* On a successful launch, sets *@fd to the file descriptor of
1334
* a pipe connected to the application's stderr.
1336
* The options should be terminated with a single %NULL.
1338
* If @documents contains multiple documents, but
1339
* egg_desktop_file_accepts_multiple() returns %FALSE for
1340
* @desktop_file, then egg_desktop_file_launch() will actually launch
1341
* multiple instances of the application. In that case, the return
1342
* value (as well as any values passed via
1343
* %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, etc) will only reflect the
1344
* first instance of the application that was launched (but the
1345
* %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC will be called for each
1348
* Return value: %TRUE if the application was successfully launched.
1351
egg_desktop_file_launch (EggDesktopFile *desktop_file,
1352
GSList *documents, GError **error,
1357
EggDesktopFile *app_desktop_file;
1359
switch (desktop_file->type)
1361
case EGG_DESKTOP_FILE_TYPE_APPLICATION:
1362
va_start (args, error);
1363
success = egg_desktop_file_launchv (desktop_file, documents,
1368
case EGG_DESKTOP_FILE_TYPE_LINK:
1371
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
1372
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
1373
_("Can't pass document URIs to a 'Type=Link' desktop entry"));
1377
if (!parse_link (desktop_file, &app_desktop_file, &documents, error))
1380
va_start (args, error);
1381
success = egg_desktop_file_launchv (app_desktop_file, documents,
1385
egg_desktop_file_free (app_desktop_file);
1386
free_document_list (documents);
1390
g_set_error (error, EGG_DESKTOP_FILE_ERROR,
1391
EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
1392
_("Not a launchable item"));
1402
egg_desktop_file_error_quark (void)
1404
return g_quark_from_static_string ("egg-desktop_file-error-quark");
1408
G_LOCK_DEFINE_STATIC (egg_desktop_file);
1409
static EggDesktopFile *egg_desktop_file;
1412
* egg_set_desktop_file:
1413
* @desktop_file_path: path to the application's desktop file
1415
* Creates an #EggDesktopFile for the application from the data at
1416
* @desktop_file_path. This will also call g_set_application_name()
1417
* with the localized application name from the desktop file, and
1418
* gtk_window_set_default_icon_name() or
1419
* gtk_window_set_default_icon_from_file() with the application's
1420
* icon. Other code may use additional information from the desktop
1423
* Note that for thread safety reasons, this function can only
1427
egg_set_desktop_file (const char *desktop_file_path)
1429
GError *error = NULL;
1431
G_LOCK (egg_desktop_file);
1432
if (egg_desktop_file)
1433
egg_desktop_file_free (egg_desktop_file);
1435
egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error);
1438
g_warning ("Could not load desktop file '%s': %s",
1439
desktop_file_path, error->message);
1440
g_error_free (error);
1443
/* Set localized application name and default window icon */
1444
if (egg_desktop_file->name)
1445
g_set_application_name (egg_desktop_file->name);
1446
if (egg_desktop_file->icon)
1448
if (g_path_is_absolute (egg_desktop_file->icon))
1449
gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL);
1451
gtk_window_set_default_icon_name (egg_desktop_file->icon);
1454
G_UNLOCK (egg_desktop_file);
1458
* egg_get_desktop_file:
1460
* Gets the application's #EggDesktopFile, as set by
1461
* egg_set_desktop_file().
1463
* Return value: the #EggDesktopFile, or %NULL if it hasn't been set.
1466
egg_get_desktop_file (void)
1468
EggDesktopFile *retval;
1470
G_LOCK (egg_desktop_file);
1471
retval = egg_desktop_file;
1472
G_UNLOCK (egg_desktop_file);