Don't make local copy of desktop file for mimetype changes if the file
[platform/upstream/glib.git] / gio / gdesktopappinfo.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  * Copyright © 2007 Ryan Lortie
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General
17  * Public License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Author: Alexander Larsson <alexl@redhat.com>
22  */
23
24 #include <config.h>
25
26 #include <errno.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/wait.h>
30
31 #ifdef HAVE_CRT_EXTERNS_H
32 #include <crt_externs.h>
33 #endif
34
35 #include "gcontenttypeprivate.h"
36 #include "gdesktopappinfo.h"
37 #include "gioerror.h"
38 #include "gthemedicon.h"
39 #include "gfileicon.h"
40 #include <glib/gstdio.h>
41 #include "glibintl.h"
42
43 #include "gioalias.h"
44
45 /**
46  * SECTION:gdesktopappinfo
47  * @short_description: Application information from desktop files
48  * @include: gio/gdesktopappinfo.h 
49  * 
50  * #GDesktopAppInfo is an implementation of #GAppInfo based on
51  * desktop files.
52  *
53  **/
54
55 #define DEFAULT_APPLICATIONS_GROUP  "Default Applications" 
56 #define MIME_CACHE_GROUP            "MIME Cache"
57
58 static void g_desktop_app_info_iface_init (GAppInfoIface *iface);
59
60 static GList *get_all_desktop_entries_for_mime_type (const char *base_mime_type);
61 static void mime_info_cache_reload (const char *dir);
62
63 /**
64  * GDesktopAppInfo:
65  * 
66  * Information about an installed application from a desktop file.
67  */
68 struct _GDesktopAppInfo
69 {
70   GObject parent_instance;
71
72   char *desktop_id;
73   char *filename;
74
75   char *name;
76   /* FIXME: what about GenericName ? */
77   char *comment;
78   char *icon_name;
79   GIcon *icon;
80   char **only_show_in;
81   char **not_show_in;
82   char **mimetypes;
83   char *try_exec;
84   char *exec;
85   char *binary;
86   char *path;
87
88   guint nodisplay       : 1;
89   guint hidden          : 1;
90   guint terminal        : 1;
91   guint startup_notify  : 1;
92   /* FIXME: what about StartupWMClass ? */
93 };
94
95 G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT,
96                          G_IMPLEMENT_INTERFACE (G_TYPE_APP_INFO,
97                                                 g_desktop_app_info_iface_init))
98
99 static gpointer
100 search_path_init (gpointer data)
101 {
102   char **args = NULL;
103   const char * const *data_dirs;
104   const char *user_data_dir;
105   int i, length, j;
106
107   data_dirs = g_get_system_data_dirs ();
108   length = g_strv_length ((char **) data_dirs);
109   
110   args = g_new (char *, length + 2);
111   
112   j = 0;
113   user_data_dir = g_get_user_data_dir ();
114   args[j++] = g_build_filename (user_data_dir, "applications", NULL);
115   for (i = 0; i < length; i++)
116     args[j++] = g_build_filename (data_dirs[i],
117                                   "applications", NULL);
118   args[j++] = NULL;
119   
120   return args;
121 }
122   
123 static const char * const *
124 get_applications_search_path (void)
125 {
126   static GOnce once_init = G_ONCE_INIT;
127   return g_once (&once_init, search_path_init, NULL);
128 }
129
130 static void
131 g_desktop_app_info_finalize (GObject *object)
132 {
133   GDesktopAppInfo *info;
134
135   info = G_DESKTOP_APP_INFO (object);
136
137   g_free (info->desktop_id);
138   g_free (info->filename);
139   g_free (info->name);
140   g_free (info->comment);
141   g_free (info->icon_name);
142   if (info->icon)
143     g_object_unref (info->icon);
144   g_strfreev (info->only_show_in);
145   g_strfreev (info->not_show_in);
146   g_strfreev (info->mimetypes);
147   g_free (info->try_exec);
148   g_free (info->exec);
149   g_free (info->binary);
150   g_free (info->path);
151   
152   G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
153 }
154
155 static void
156 g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
157 {
158   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
159   
160   gobject_class->finalize = g_desktop_app_info_finalize;
161 }
162
163 static void
164 g_desktop_app_info_init (GDesktopAppInfo *local)
165 {
166 }
167
168 /**
169  * g_desktop_app_info_new_from_filename:
170  * @filename: a string containing a file name.
171  * 
172  * Creates a new #GDesktopAppInfo.
173  *
174  * Returns: a new #GDesktopAppInfo or %NULL on error.
175  **/
176 GDesktopAppInfo *
177 g_desktop_app_info_new_from_filename (const char *filename)
178 {
179   GDesktopAppInfo *info;
180   GKeyFile *key_file;
181   char *start_group;
182   char *type;
183   char *try_exec;
184   
185   key_file = g_key_file_new ();
186   
187   if (!g_key_file_load_from_file (key_file,
188                                   filename,
189                                   G_KEY_FILE_NONE,
190                                   NULL))
191     {
192       g_key_file_free (key_file);
193       return NULL;
194     }
195
196   start_group = g_key_file_get_start_group (key_file);
197   if (start_group == NULL || strcmp (start_group, G_KEY_FILE_DESKTOP_GROUP) != 0)
198     {
199       g_free (start_group);
200       g_key_file_free (key_file);
201       return NULL;
202     }
203   g_free (start_group);
204
205   type = g_key_file_get_string (key_file,
206                                 G_KEY_FILE_DESKTOP_GROUP,
207                                 G_KEY_FILE_DESKTOP_KEY_TYPE,
208                                 NULL);
209   if (type == NULL || strcmp (type, G_KEY_FILE_DESKTOP_TYPE_APPLICATION) != 0)
210     {
211       g_free (type);
212       g_key_file_free (key_file);
213       return NULL;
214     }
215   g_free (type);
216
217   try_exec = g_key_file_get_string (key_file,
218                                     G_KEY_FILE_DESKTOP_GROUP,
219                                     G_KEY_FILE_DESKTOP_KEY_TRY_EXEC,
220                                     NULL);
221   if (try_exec)
222     {
223       char *t;
224       t = g_find_program_in_path (try_exec);
225       if (t == NULL)
226         {
227           g_free (try_exec);
228           g_key_file_free (key_file);
229           return NULL;
230         }
231       g_free (t);
232     }
233
234   info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
235   info->filename = g_strdup (filename);
236
237   info->name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, NULL, NULL);
238   info->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, NULL, NULL);
239   info->nodisplay = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) != FALSE;
240   info->icon_name =  g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, NULL, NULL);
241   info->only_show_in = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, NULL, NULL);
242   info->not_show_in = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, NULL, NULL);
243   info->mimetypes = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, NULL, NULL);
244   info->try_exec = try_exec;
245   info->exec = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL);
246   info->path = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_PATH, NULL);
247   info->terminal = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL) != FALSE;
248   info->startup_notify = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, NULL) != FALSE;
249   info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
250
251   g_key_file_free (key_file);
252   
253   info->icon = NULL;
254   if (info->icon_name)
255     {
256       if (g_path_is_absolute (info->icon_name))
257         {
258           GFile *file;
259           
260           file = g_file_new_for_path (info->icon_name);
261           info->icon = g_file_icon_new (file);
262           g_object_unref (file);
263         }
264       else
265         info->icon = g_themed_icon_new (info->icon_name);
266     }
267   
268   if (info->exec)
269     {
270       char *p, *start;
271
272       p = info->exec;
273       while (*p == ' ')
274         p++;
275       start = p;
276       while (*p != ' ' && *p != 0)
277         p++;
278       
279       info->binary = g_strndup (start, p - start);
280     }
281   
282   return info;
283 }
284
285 /**
286  * g_desktop_app_info_new:
287  * @desktop_id: the desktop file id
288  * 
289  * Creates a new #GDesktopAppInfo.
290  * 
291  * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id
292  **/
293 GDesktopAppInfo *
294 g_desktop_app_info_new (const char *desktop_id)
295 {
296   GDesktopAppInfo *appinfo;
297   const char * const *dirs;
298   char *basename;
299   int i;
300
301   dirs = get_applications_search_path ();
302
303   basename = g_strdup (desktop_id);
304   
305   for (i = 0; dirs[i] != NULL; i++)
306     {
307       char *filename;
308       char *p;
309
310       filename = g_build_filename (dirs[i], desktop_id, NULL);
311       appinfo = g_desktop_app_info_new_from_filename (filename);
312       g_free (filename);
313       if (appinfo != NULL)
314         goto found;
315
316       p = basename;
317       while ((p = strchr (p, '-')) != NULL)
318         {
319           *p = '/';
320           
321           filename = g_build_filename (dirs[i], basename, NULL);
322           appinfo = g_desktop_app_info_new_from_filename (filename);
323           g_free (filename);
324           if (appinfo != NULL)
325             goto found;
326           *p = '-';
327           p++;
328         }
329     }
330   
331   g_free (basename);
332   return NULL;
333
334  found:
335   g_free (basename);
336   
337   appinfo->desktop_id = g_strdup (desktop_id);
338
339   if (g_desktop_app_info_get_is_hidden (appinfo))
340     {
341       g_object_unref (appinfo);
342       appinfo = NULL;
343     }
344   
345   return appinfo;
346 }
347
348 static GAppInfo *
349 g_desktop_app_info_dup (GAppInfo *appinfo)
350 {
351   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
352   GDesktopAppInfo *new_info;
353   
354   new_info = g_object_new (G_TYPE_DESKTOP_APP_INFO, NULL);
355
356   new_info->filename = g_strdup (info->filename);
357   new_info->desktop_id = g_strdup (info->desktop_id);
358   
359   new_info->name = g_strdup (info->name);
360   new_info->comment = g_strdup (info->comment);
361   new_info->nodisplay = info->nodisplay;
362   new_info->icon_name = g_strdup (info->icon_name);
363   new_info->icon = g_object_ref (info->icon);
364   new_info->only_show_in = g_strdupv (info->only_show_in);
365   new_info->not_show_in = g_strdupv (info->not_show_in);
366   new_info->try_exec = g_strdup (info->try_exec);
367   new_info->exec = g_strdup (info->exec);
368   new_info->binary = g_strdup (info->binary);
369   new_info->path = g_strdup (info->path);
370   new_info->hidden = info->hidden;
371   new_info->terminal = info->terminal;
372   new_info->startup_notify = info->startup_notify;
373   
374   return G_APP_INFO (new_info);
375 }
376
377 static gboolean
378 g_desktop_app_info_equal (GAppInfo *appinfo1,
379                           GAppInfo *appinfo2)
380 {
381   GDesktopAppInfo *info1 = G_DESKTOP_APP_INFO (appinfo1);
382   GDesktopAppInfo *info2 = G_DESKTOP_APP_INFO (appinfo2);
383
384   if (info1->desktop_id == NULL ||
385       info2->desktop_id == NULL)
386     return FALSE;
387
388   return strcmp (info1->desktop_id, info2->desktop_id) == 0;
389 }
390
391 static const char *
392 g_desktop_app_info_get_id (GAppInfo *appinfo)
393 {
394   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
395
396   return info->desktop_id;
397 }
398
399 static const char *
400 g_desktop_app_info_get_name (GAppInfo *appinfo)
401 {
402   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
403
404   if (info->name == NULL)
405     return _("Unnamed");
406   return info->name;
407 }
408
409 /**
410  * g_desktop_app_info_get_is_hidden:
411  * @info: a #GDesktopAppInfo.
412  *
413  * A desktop file is hidden if the Hidden key in it is
414  * set to True.
415  *
416  * Returns: %TRUE if hidden, %FALSE otherwise. 
417  **/
418 gboolean
419 g_desktop_app_info_get_is_hidden (GDesktopAppInfo *info)
420 {
421   return info->hidden;
422 }
423
424 static const char *
425 g_desktop_app_info_get_description (GAppInfo *appinfo)
426 {
427   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
428   
429   return info->comment;
430 }
431
432 static const char *
433 g_desktop_app_info_get_executable (GAppInfo *appinfo)
434 {
435   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
436   
437   return info->binary;
438 }
439
440 static GIcon *
441 g_desktop_app_info_get_icon (GAppInfo *appinfo)
442 {
443   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
444
445   return info->icon;
446 }
447
448 static char *
449 expand_macro_single (char macro, GFile *file)
450 {
451   char *result = NULL;
452   char *uri, *path;
453
454   path = g_file_get_path (file);
455   uri = g_file_get_uri (file);
456   
457   switch (macro)
458     {
459     case 'u':
460     case 'U':   
461       result = g_shell_quote (uri);
462       break;
463     case 'f':
464     case 'F':
465       if (path)
466         result = g_shell_quote (path);
467       break;
468     case 'd':
469     case 'D':
470       if (path)
471         result = g_shell_quote (g_path_get_dirname (path));
472       break;
473     case 'n':
474     case 'N':
475       if (path)
476         result = g_shell_quote (g_path_get_basename (path));
477       break;
478     }
479
480   g_free (path);
481   g_free (uri);
482   
483   return result;
484 }
485
486 static void
487 expand_macro (char              macro, 
488               GString          *exec, 
489               GDesktopAppInfo  *info, 
490               GList           **file_list)
491 {
492   GList *files = *file_list;
493   char *expanded;
494   
495   g_return_if_fail (exec != NULL);
496   
497   switch (macro)
498     {
499     case 'u':
500     case 'f':
501     case 'd':
502     case 'n':
503       if (files)
504         {
505           expanded = expand_macro_single (macro, files->data);
506           if (expanded)
507             {
508               g_string_append (exec, expanded);
509               g_free (expanded);
510             }
511           files = files->next;
512         }
513
514       break;
515
516     case 'U':   
517     case 'F':
518     case 'D':
519     case 'N':
520       while (files)
521         {
522           expanded = expand_macro_single (macro, files->data);
523           if (expanded)
524             {
525               g_string_append (exec, expanded);
526               g_free (expanded);
527             }
528           
529           files = files->next;
530           
531           if (files != NULL && expanded)
532             g_string_append_c (exec, ' ');
533         }
534
535       break;
536
537     case 'i':
538       if (info->icon_name)
539         {
540           g_string_append (exec, "--icon ");
541           g_string_append (exec, info->icon_name);
542         }
543       break;
544
545     case 'c':
546       if (info->name) 
547         g_string_append (exec, info->name);
548       break;
549
550     case 'k':
551       if (info->filename) 
552         g_string_append (exec, info->filename);
553       break;
554
555     case 'm': /* deprecated */
556       break;
557
558     case '%':
559       g_string_append_c (exec, '%');
560       break;
561     }
562   
563   *file_list = files;
564 }
565
566 static gboolean
567 expand_application_parameters (GDesktopAppInfo   *info,
568                                GList            **files,
569                                int               *argc,
570                                char            ***argv,
571                                GError           **error)
572 {
573   GList *file_list = *files;
574   const char *p = info->exec;
575   GString *expanded_exec = g_string_new (NULL);
576   gboolean res;
577   
578   if (info->exec == NULL)
579     {
580       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
581                    _("Desktop file didn't specify Exec field"));
582       return FALSE;
583     }
584   
585   while (*p)
586     {
587       if (p[0] == '%' && p[1] != '\0')
588         {
589           expand_macro (p[1], expanded_exec, info, files);
590           p++;
591         }
592       else
593         g_string_append_c (expanded_exec, *p);
594       
595       p++;
596     }
597   
598   /* No file substitutions */
599   if (file_list == *files && file_list != NULL)
600     {
601       /* If there is no macro default to %f. This is also what KDE does */
602       g_string_append_c (expanded_exec, ' ');
603       expand_macro ('f', expanded_exec, info, files);
604     }
605   
606   res = g_shell_parse_argv (expanded_exec->str, argc, argv, error);
607   g_string_free (expanded_exec, TRUE);
608   return res;
609 }
610
611 static gboolean
612 prepend_terminal_to_vector (int    *argc,
613                             char ***argv)
614 {
615 #ifndef G_OS_WIN32
616   char **real_argv;
617   int real_argc;
618   int i, j;
619   char **term_argv = NULL;
620   int term_argc = 0;
621   char *check;
622   char **the_argv;
623   
624   g_return_val_if_fail (argc != NULL, FALSE);
625   g_return_val_if_fail (argv != NULL, FALSE);
626         
627   /* sanity */
628   if(*argv == NULL)
629     *argc = 0;
630   
631   the_argv = *argv;
632
633   /* compute size if not given */
634   if (*argc < 0)
635     {
636       for (i = 0; the_argv[i] != NULL; i++)
637         ;
638       *argc = i;
639     }
640   
641   term_argc = 2;
642   term_argv = g_new0 (char *, 3);
643
644   check = g_find_program_in_path ("gnome-terminal");
645   if (check != NULL)
646     {
647       term_argv[0] = check;
648       /* Note that gnome-terminal takes -x and
649        * as -e in gnome-terminal is broken we use that. */
650       term_argv[1] = g_strdup ("-x");
651     }
652   else
653     {
654       if (check == NULL)
655         check = g_find_program_in_path ("nxterm");
656       if (check == NULL)
657         check = g_find_program_in_path ("color-xterm");
658       if (check == NULL)
659         check = g_find_program_in_path ("rxvt");
660       if (check == NULL)
661         check = g_find_program_in_path ("xterm");
662       if (check == NULL)
663         check = g_find_program_in_path ("dtterm");
664       if (check == NULL)
665         {
666           check = g_strdup ("xterm");
667           g_warning ("couldn't find a terminal, falling back to xterm");
668         }
669       term_argv[0] = check;
670       term_argv[1] = g_strdup ("-e");
671     }
672
673   real_argc = term_argc + *argc;
674   real_argv = g_new (char *, real_argc + 1);
675   
676   for (i = 0; i < term_argc; i++)
677     real_argv[i] = term_argv[i];
678   
679   for (j = 0; j < *argc; j++, i++)
680     real_argv[i] = (char *)the_argv[j];
681   
682   real_argv[i] = NULL;
683   
684   g_free (*argv);
685   *argv = real_argv;
686   *argc = real_argc;
687   
688   /* we use g_free here as we sucked all the inner strings
689    * out from it into real_argv */
690   g_free (term_argv);
691   return TRUE;
692 #else
693   return FALSE;
694 #endif /* G_OS_WIN32 */
695 }
696
697 /* '=' is the new '\0'.
698  * DO NOT CALL unless at least one string ends with '='
699  */
700 static gboolean
701 is_env (const char *a,
702         const char *b)
703 {
704   while (*a == *b)
705   {
706     if (*a == 0 || *b == 0)
707       return FALSE;
708     
709     if (*a == '=')
710       return TRUE;
711
712     a++;
713     b++;
714   }
715
716   return FALSE;
717 }
718
719 /* free with g_strfreev */
720 static char **
721 replace_env_var (char       **old_environ,
722                  const char  *env_var,
723                  const char  *new_value)
724 {
725   int length, new_length;
726   int index, new_index;
727   char **new_environ;
728   int i, new_i;
729
730   /* do two things at once:
731    *  - discover the length of the environment ('length')
732    *  - find the location (if any) of the env var ('index')
733    */
734   index = -1;
735   for (length = 0; old_environ[length]; length++)
736     {
737       /* if we already have it in our environment, replace */
738       if (is_env (old_environ[length], env_var))
739         index = length;
740     }
741
742   
743   /* no current env var, no desired env value.
744    * this is easy :)
745    */
746   if (new_value == NULL && index == -1)
747     return old_environ;
748
749   /* in all cases now, we will be using a modified environment.
750    * determine its length and allocated it.
751    * 
752    * after this block:
753    *   new_index   = location to insert, if any
754    *   new_length  = length of the new array
755    *   new_environ = the pointer array for the new environment
756    */
757   
758   if (new_value == NULL && index >= 0)
759     {
760       /* in this case, we will be removing an entry */
761       new_length = length - 1;
762       new_index = -1;
763     }
764   else if (new_value != NULL && index < 0)
765     {
766       /* in this case, we will be adding an entry to the end */
767       new_length = length + 1;
768       new_index = length;
769     }
770   else
771     /* in this case, we will be replacing the existing entry */
772     {
773       new_length = length;
774       new_index = index;
775     }
776
777   new_environ = g_malloc (sizeof (char *) * (new_length + 1));
778   new_environ[new_length] = NULL;
779
780   /* now we do the copying.
781    * for each entry in the new environment, we decide what to do
782    */
783   
784   i = 0;
785   for (new_i = 0; new_i < new_length; new_i++)
786     {
787       if (new_i == new_index)
788         {
789           /* insert our new item */
790           new_environ[new_i] = g_strconcat (env_var,
791                                             "=",
792                                             new_value,
793                                             NULL);
794           
795           /* if we had an old entry, skip it now */
796           if (index >= 0)
797             i++;
798         }
799       else
800         {
801           /* if this is the old DESKTOP_STARTUP_ID, skip it */
802           if (i == index)
803             i++;
804           
805           /* copy an old item */
806           new_environ[new_i] = g_strdup (old_environ[i]);
807           i++;
808         }
809     }
810
811   g_strfreev (old_environ);
812   
813   return new_environ;
814 }
815
816 static GList *
817 dup_list_segment (GList *start,
818                   GList *end)
819 {
820   GList *res;
821
822   res = NULL;
823   while (start != NULL && start != end)
824     {
825       res = g_list_prepend (res, start->data);
826       start = start->next;
827     }
828
829   return g_list_reverse (res);
830 }
831
832 #ifdef HAVE__NSGETENVIRON
833 #define environ (*_NSGetEnviron())
834 #elif !defined(G_OS_WIN32)
835
836 /* According to the Single Unix Specification, environ is not in 
837  *  * any system header, although unistd.h often declares it.
838  *   */
839 extern char **environ;
840 #endif
841
842 static gboolean
843 g_desktop_app_info_launch (GAppInfo           *appinfo,
844                            GList              *files,
845                            GAppLaunchContext  *launch_context,
846                            GError            **error)
847 {
848   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
849   gboolean completed = FALSE;
850   GList *old_files;
851   GList *launched_files;
852   char **envp;
853   char **argv;
854   int argc;
855   char *display;
856   char *sn_id;
857
858   g_return_val_if_fail (appinfo != NULL, FALSE);
859
860   argv = NULL;
861   envp = NULL;
862       
863   do 
864     {
865       old_files = files;
866       if (!expand_application_parameters (info, &files,
867                                           &argc, &argv, error))
868         goto out;
869       
870       if (info->terminal && !prepend_terminal_to_vector (&argc, &argv))
871         {
872           g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
873                        _("Unable to find terminal required for application"));
874           goto out;
875         }
876
877       sn_id = NULL;
878       if (launch_context)
879         {
880           launched_files = dup_list_segment (old_files, files);
881           
882           display = g_app_launch_context_get_display (launch_context,
883                                                       appinfo,
884                                                       launched_files);
885
886           sn_id = NULL;
887           if (info->startup_notify)
888             sn_id = g_app_launch_context_get_startup_notify_id (launch_context,
889                                                                 appinfo,
890                                                                 launched_files);
891           
892           if (display || sn_id)
893             {
894 #ifdef G_OS_WIN32
895               /* FIXME */
896               envp = g_new0 (char *, 1);
897 #else
898               envp = g_strdupv (environ);
899 #endif
900               
901               if (display)
902                 envp = replace_env_var (envp,
903                                         "DISPLAY",
904                                         display);
905               
906               if (sn_id)
907                 envp = replace_env_var (envp,
908                                         "DESKTOP_STARTUP_ID",
909                                         sn_id);
910             }
911
912           g_free (display);
913           
914           g_list_free (launched_files);
915         }
916       
917       if (!g_spawn_async (info->path,  /* working directory */
918                           argv,
919                           envp,
920                           G_SPAWN_SEARCH_PATH /* flags */,
921                           NULL /* child_setup */,
922                           NULL /* data */,
923                           NULL /* child_pid */,
924                           error))
925         {
926           if (sn_id)
927             {
928               g_app_launch_context_launch_failed (launch_context, sn_id);
929               g_free (sn_id);
930             }
931           goto out;
932         }
933
934       
935       g_free (sn_id);
936       
937       g_strfreev (envp);
938       g_strfreev (argv);
939       envp = NULL;
940       argv = NULL;
941     }
942   while (files != NULL);
943
944   completed = TRUE;
945
946  out:
947   g_strfreev (argv);
948   g_strfreev (envp);
949
950   return completed;
951 }
952
953 static gboolean
954 g_desktop_app_info_supports_uris (GAppInfo *appinfo)
955 {
956   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
957  
958   return info->exec && 
959     ((strstr (info->exec, "%u") != NULL) ||
960      (strstr (info->exec, "%U") != NULL));
961 }
962
963 static gboolean
964 g_desktop_app_info_supports_files (GAppInfo *appinfo)
965 {
966   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
967  
968   return info->exec && 
969     ((strstr (info->exec, "%f") != NULL) ||
970      (strstr (info->exec, "%F") != NULL));
971 }
972
973 static gboolean
974 g_desktop_app_info_launch_uris (GAppInfo           *appinfo,
975                                 GList              *uris,
976                                 GAppLaunchContext  *launch_context,
977                                 GError            **error)
978 {
979   GList *files;
980   GFile *file;
981   gboolean res;
982
983   files = NULL;
984   while (uris)
985     {
986       file = g_file_new_for_uri (uris->data);
987       if (file == NULL)
988         g_warning ("Invalid uri passed to g_desktop_app_info_launch_uris");
989       
990       if (file)
991         files = g_list_prepend (files, file);
992     }
993   
994   files = g_list_reverse (files);
995   
996   res = g_desktop_app_info_launch (appinfo, files, launch_context, error);
997   
998   g_list_foreach  (files, (GFunc)g_object_unref, NULL);
999   g_list_free (files);
1000   
1001   return res;
1002 }
1003
1004 G_LOCK_DEFINE_STATIC (g_desktop_env);
1005 static gchar *g_desktop_env = NULL;
1006
1007 /**
1008  * g_desktop_app_info_set_desktop_env:
1009  * @desktop_env: a string specifying what desktop this is
1010  *
1011  * Sets the name of the desktop that the application is running in.
1012  * This is used by g_app_info_should_show() to evaluate the
1013  * <literal>OnlyShowIn</literal> and <literal>NotShowIn</literal>
1014  * desktop entry fields.
1015  *
1016  * The <ulink url="http://standards.freedesktop.org/menu-spec/latest/">Desktop 
1017  * Menu specification</ulink> recognizes the following:
1018  * <simplelist>
1019  *   <member>GNOME</member>
1020  *   <member>KDE</member>
1021  *   <member>ROX</member>
1022  *   <member>XFCE</member>
1023  *   <member>Old</member> 
1024  * </simplelist>
1025  *
1026  * Should be called only once; subsequent calls are ignored.
1027  */
1028 void
1029 g_desktop_app_info_set_desktop_env (const gchar *desktop_env)
1030 {
1031   G_LOCK (g_desktop_env);
1032   if (!g_desktop_env)
1033     g_desktop_env = g_strdup (desktop_env);
1034   G_UNLOCK (g_desktop_env);
1035 }
1036
1037 static gboolean
1038 g_desktop_app_info_should_show (GAppInfo *appinfo)
1039 {
1040   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1041   gboolean found;
1042   const gchar *desktop_env;
1043   int i;
1044
1045   if (info->nodisplay)
1046     return FALSE;
1047
1048   G_LOCK (g_desktop_env);
1049   desktop_env = g_desktop_env;
1050   G_UNLOCK (g_desktop_env);
1051
1052   if (info->only_show_in)
1053     {
1054       if (desktop_env == NULL)
1055         return FALSE;
1056       
1057       found = FALSE;
1058       for (i = 0; info->only_show_in[i] != NULL; i++)
1059         {
1060           if (strcmp (info->only_show_in[i], desktop_env) == 0)
1061             {
1062               found = TRUE;
1063               break;
1064             }
1065         }
1066       if (!found)
1067         return FALSE;
1068     }
1069
1070   if (info->not_show_in && desktop_env)
1071     {
1072       for (i = 0; info->not_show_in[i] != NULL; i++)
1073         {
1074           if (strcmp (info->not_show_in[i], desktop_env) == 0)
1075             return FALSE;
1076         }
1077     }
1078   
1079   return TRUE;
1080 }
1081
1082 typedef enum {
1083   APP_DIR,
1084   MIMETYPE_DIR
1085 } DirType;
1086
1087 static char *
1088 ensure_dir (DirType   type,
1089             GError  **error)
1090 {
1091   char *path, *display_name;
1092   int err;
1093
1094   if (type == APP_DIR)
1095     path = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1096   else
1097     path = g_build_filename (g_get_user_data_dir (), "mime", "packages", NULL);
1098
1099   errno = 0;
1100   if (g_mkdir_with_parents (path, 0700) == 0)
1101     return path;
1102
1103   err = errno;
1104   display_name = g_filename_display_name (path);
1105   if (type == APP_DIR)
1106     g_set_error (error, G_IO_ERROR, g_io_error_from_errno (err),
1107                  _("Can't create user application configuration folder %s: %s"),
1108                  display_name, g_strerror (err));
1109   else
1110     g_set_error (error, G_IO_ERROR, g_io_error_from_errno (err),
1111                  _("Can't create user MIME configuration folder %s: %s"),
1112                  display_name, g_strerror (err));
1113
1114   g_free (display_name);
1115   g_free (path);
1116
1117   return NULL;
1118 }
1119
1120 static gboolean
1121 update_default_list (const char  *desktop_id, 
1122                      const char  *content_type, 
1123                      gboolean     add, 
1124                      GError     **error)
1125 {
1126   char *dirname, *filename;
1127   GKeyFile *key_file;
1128   gboolean load_succeeded, res;
1129   char **old_list;
1130   char **list;
1131   gsize length, data_size;
1132   char *data;
1133   int i, j;
1134
1135   dirname = ensure_dir (APP_DIR, error);
1136   if (!dirname)
1137     return FALSE;
1138
1139   filename = g_build_filename (dirname, "defaults.list", NULL);
1140   g_free (dirname);
1141
1142   key_file = g_key_file_new ();
1143   load_succeeded = g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL);
1144   if (!load_succeeded || !g_key_file_has_group (key_file, DEFAULT_APPLICATIONS_GROUP))
1145     {
1146       g_key_file_free (key_file);
1147       key_file = g_key_file_new ();
1148     }
1149
1150   length = 0;
1151   old_list = g_key_file_get_string_list (key_file, DEFAULT_APPLICATIONS_GROUP,
1152                                          content_type, &length, NULL);
1153
1154   list = g_new (char *, 1 + length + 1);
1155
1156   i = 0;
1157   if (add)
1158     list[i++] = g_strdup (desktop_id);
1159   if (old_list)
1160     {
1161       for (j = 0; old_list[j] != NULL; j++)
1162         {
1163           if (strcmp (old_list[j], desktop_id) != 0)
1164             list[i++] = g_strdup (old_list[j]);
1165         }
1166     }
1167   list[i] = NULL;
1168   
1169   g_strfreev (old_list);
1170
1171   g_key_file_set_string_list (key_file,
1172                               DEFAULT_APPLICATIONS_GROUP,
1173                               content_type,
1174                               (const char * const *)list, i);
1175
1176   g_strfreev (list);
1177   
1178   data = g_key_file_to_data (key_file, &data_size, error);
1179   g_key_file_free (key_file);
1180   
1181   res = g_file_set_contents (filename, data, data_size, error);
1182
1183   mime_info_cache_reload (NULL);
1184                           
1185   g_free (filename);
1186   g_free (data);
1187   
1188   return res;
1189 }
1190
1191 static gboolean
1192 g_desktop_app_info_set_as_default_for_type (GAppInfo    *appinfo,
1193                                             const char  *content_type,
1194                                             GError     **error)
1195 {
1196   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1197
1198   if (!g_app_info_add_supports_type (appinfo, content_type, error))
1199     return FALSE;
1200   
1201   return update_default_list (info->desktop_id, content_type, TRUE, error);
1202 }
1203
1204 static void
1205 update_program_done (GPid     pid,
1206                      gint     status,
1207                      gpointer data)
1208 {
1209   /* Did the application exit correctly */
1210   if (WIFEXITED (status) &&
1211       WEXITSTATUS (status) == 0)
1212     {
1213       /* Here we could clean out any caches in use */
1214     }
1215 }
1216
1217 static void
1218 run_update_command (char *command,
1219                     char *subdir)
1220 {
1221         char *argv[3] = {
1222                 NULL,
1223                 NULL,
1224                 NULL,
1225         };
1226         GPid pid = 0;
1227         GError *error = NULL;
1228
1229         argv[0] = command;
1230         argv[1] = g_build_filename (g_get_user_data_dir (), subdir, NULL);
1231
1232         if (g_spawn_async ("/", argv,
1233                            NULL,       /* envp */
1234                            G_SPAWN_SEARCH_PATH |
1235                            G_SPAWN_STDOUT_TO_DEV_NULL |
1236                            G_SPAWN_STDERR_TO_DEV_NULL |
1237                            G_SPAWN_DO_NOT_REAP_CHILD,
1238                            NULL, NULL, /* No setup function */
1239                            &pid,
1240                            NULL)) 
1241           g_child_watch_add (pid, update_program_done, NULL);
1242         else
1243           {
1244             /* If we get an error at this point, it's quite likely the user doesn't
1245              * have an installed copy of either 'update-mime-database' or
1246              * 'update-desktop-database'.  I don't think we want to popup an error
1247              * dialog at this point, so we just do a g_warning to give the user a
1248              * chance of debugging it.
1249              */
1250             g_warning ("%s", error->message);
1251           }
1252         
1253         g_free (argv[1]);
1254 }
1255
1256 static gboolean
1257 g_desktop_app_info_set_as_default_for_extension (GAppInfo    *appinfo,
1258                                                  const char  *extension,
1259                                                  GError     **error)
1260 {
1261   char *filename, *basename, *mimetype;
1262   char *dirname;
1263   gboolean res;
1264
1265   dirname = ensure_dir (MIMETYPE_DIR, error);
1266   if (!dirname)
1267     return FALSE;
1268   
1269   basename = g_strdup_printf ("user-extension-%s.xml", extension);
1270   filename = g_build_filename (dirname, basename, NULL);
1271   g_free (basename);
1272   g_free (dirname);
1273
1274   mimetype = g_strdup_printf ("application/x-extension-%s", extension);
1275   
1276   if (!g_file_test (filename, G_FILE_TEST_EXISTS)) 
1277     {
1278       char *contents;
1279
1280       contents =
1281         g_strdup_printf ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
1282                          "<mime-info xmlns=\"http://www.freedesktop.org/standards/shared-mime-info\">\n"
1283                          " <mime-type type=\"%s\">\n"
1284                          "  <comment>%s document</comment>\n"
1285                          "  <glob pattern=\"*.%s\"/>\n"
1286                          " </mime-type>\n"
1287                          "</mime-info>\n", mimetype, extension, extension);
1288
1289       g_file_set_contents (filename, contents, -1, NULL);
1290       g_free (contents);
1291
1292       run_update_command ("update-mime-database", "mime");
1293     }
1294   g_free (filename);
1295   
1296   res = g_desktop_app_info_set_as_default_for_type (appinfo,
1297                                                     mimetype,
1298                                                     error);
1299
1300   g_free (mimetype);
1301   
1302   return res;
1303 }
1304
1305 static gboolean
1306 g_desktop_app_info_supports_mimetype (GDesktopAppInfo *appinfo,
1307                                       const char *mimetype)
1308 {
1309   int i;
1310
1311   if (appinfo->mimetypes == NULL)
1312     return FALSE;
1313
1314   for (i = 0; appinfo->mimetypes[i] != NULL; i++)
1315     {
1316       if (strcmp (appinfo->mimetypes[i], mimetype) == 0)
1317         return TRUE;
1318     }
1319   
1320   return FALSE;
1321 }
1322
1323 static gboolean
1324 g_desktop_app_info_add_supports_type (GAppInfo    *appinfo,
1325                                       const char  *content_type,
1326                                       GError     **error)
1327 {
1328   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1329   GKeyFile *keyfile;
1330   char *new_mimetypes, *old_mimetypes, *content;
1331   char *dirname;
1332   char *filename;
1333
1334   if (g_desktop_app_info_supports_mimetype (info, content_type))
1335     return TRUE; /* Already supported */
1336   
1337   keyfile = g_key_file_new ();
1338   if (!g_key_file_load_from_file (keyfile, info->filename,
1339                                   G_KEY_FILE_KEEP_COMMENTS |
1340                                   G_KEY_FILE_KEEP_TRANSLATIONS, error))
1341     {
1342       g_key_file_free (keyfile);
1343       return FALSE;
1344     }
1345
1346   old_mimetypes = g_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, NULL);
1347   new_mimetypes = g_strconcat (content_type, ";", old_mimetypes, NULL);
1348   g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, new_mimetypes);
1349   g_free (old_mimetypes);
1350   g_free (new_mimetypes);
1351
1352   content = g_key_file_to_data (keyfile, NULL, NULL);
1353   g_key_file_free (keyfile);
1354
1355   dirname = ensure_dir (APP_DIR, error);
1356   if (!dirname)
1357     {
1358       g_free (content);
1359       return FALSE;
1360     }
1361   
1362   filename = g_build_filename (dirname, info->desktop_id, NULL);
1363   g_free (dirname);
1364   
1365   if (!g_file_set_contents (filename, content, -1, error))
1366     {
1367       g_free (filename);
1368       g_free (content);
1369       return FALSE;
1370     }
1371   g_free (filename);
1372   g_free (content);
1373
1374   run_update_command ("update-desktop-database", "applications");
1375   return TRUE;
1376 }
1377
1378 static gboolean
1379 g_desktop_app_info_can_remove_supports_type (GAppInfo *appinfo)
1380 {
1381   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1382   char *user_dirname;
1383   
1384   user_dirname = g_build_filename (g_get_user_data_dir (), "applications", NULL);
1385   return g_str_has_prefix (info->filename, user_dirname);
1386 }
1387
1388 static gboolean
1389 g_desktop_app_info_remove_supports_type (GAppInfo    *appinfo,
1390                                          const char  *content_type,
1391                                          GError     **error)
1392 {
1393   GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
1394   GKeyFile *keyfile;
1395   char *new_mimetypes, *old_mimetypes, *content;
1396   char *found;
1397   char *filename;
1398   char *dirname;
1399
1400   if (!g_desktop_app_info_supports_mimetype (info, content_type))
1401     return TRUE; /* Already not supported */
1402   
1403   keyfile = g_key_file_new ();
1404   if (!g_key_file_load_from_file (keyfile, info->filename,
1405                                   G_KEY_FILE_KEEP_COMMENTS |
1406                                   G_KEY_FILE_KEEP_TRANSLATIONS, error))
1407     {
1408       g_key_file_free (keyfile);
1409       return FALSE;
1410     }
1411
1412   old_mimetypes = g_key_file_get_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, NULL);
1413   new_mimetypes = g_strdup (old_mimetypes);
1414   found = NULL;
1415   if (new_mimetypes)
1416     found = strstr (new_mimetypes, content_type);
1417   if (found && *(found + strlen (content_type)) == ';')
1418     {
1419       char *rest = found + strlen (content_type) + 1;
1420       memmove (found, rest, strlen (rest) + 1);
1421     }
1422   g_key_file_set_string (keyfile, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, new_mimetypes);
1423   g_free (old_mimetypes);
1424   g_free (new_mimetypes);
1425
1426   content = g_key_file_to_data (keyfile, NULL, NULL);
1427   g_key_file_free (keyfile);
1428
1429   dirname = ensure_dir (APP_DIR, error);
1430   if (!dirname)
1431     {
1432       g_free (content);
1433       return FALSE;
1434     }
1435   
1436   filename = g_build_filename (dirname, info->desktop_id, NULL);
1437   g_free (dirname);
1438   if (!g_file_set_contents (filename, content, -1, error))
1439     {
1440       g_free (filename);
1441       g_free (content);
1442       return FALSE;
1443     }
1444   g_free (filename);
1445   g_free (content);
1446
1447   run_update_command ("update-desktop-database", "applications");
1448
1449   return update_default_list (info->desktop_id, content_type, FALSE, error);
1450 }
1451
1452 /**
1453  * g_app_info_create_from_commandline:
1454  * @commandline: the commandline to use
1455  * @application_name: the application name, or %NULL to use @commandline
1456  * @flags: flags that can specify details of the created #GAppInfo
1457  * @error: a #GError location to store the error occuring, %NULL to ignore.
1458  *
1459  * Creates a new #GAppInfo from the given information.
1460  *
1461  * Returns: new #GAppInfo for given command.
1462  **/
1463 GAppInfo *
1464 g_app_info_create_from_commandline (const char           *commandline,
1465                                     const char           *application_name,
1466                                     GAppInfoCreateFlags   flags,
1467                                     GError              **error)
1468 {
1469   GKeyFile *key_file;
1470   char *dirname;
1471   char **split;
1472   char *basename, *exec, *filename, *comment;
1473   char *data, *desktop_id;
1474   gsize data_size;
1475   int fd;
1476   GDesktopAppInfo *info;
1477   gboolean res;
1478
1479   dirname = ensure_dir (APP_DIR, error);
1480   if (!dirname)
1481     return NULL;
1482   
1483   key_file = g_key_file_new ();
1484
1485   g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1486                          "Encoding", "UTF-8");
1487   g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1488                          G_KEY_FILE_DESKTOP_KEY_VERSION, "1.0");
1489   g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1490                          G_KEY_FILE_DESKTOP_KEY_TYPE,
1491                          G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
1492   if (flags & G_APP_INFO_CREATE_NEEDS_TERMINAL) 
1493     g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1494                             G_KEY_FILE_DESKTOP_KEY_TERMINAL, TRUE);
1495
1496   exec = g_strconcat (commandline, " %f", NULL);
1497   g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1498                          G_KEY_FILE_DESKTOP_KEY_EXEC, exec);
1499   g_free (exec);
1500
1501   /* FIXME: this should be more robust. Maybe g_shell_parse_argv and use argv[0] */
1502   split = g_strsplit (commandline, " ", 2);
1503   basename = g_path_get_basename (split[0]);
1504   g_strfreev (split);
1505   g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1506                          G_KEY_FILE_DESKTOP_KEY_NAME, application_name?application_name:basename);
1507
1508   comment = g_strdup_printf (_("Custom definition for %s"), basename);
1509   g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP,
1510                          G_KEY_FILE_DESKTOP_KEY_COMMENT, comment);
1511   g_free (comment);
1512   
1513   g_key_file_set_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP,
1514                           G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, TRUE);
1515
1516   data = g_key_file_to_data (key_file, &data_size, NULL);
1517   g_key_file_free (key_file);
1518
1519   desktop_id = g_strdup_printf ("userapp-%s-XXXXXX.desktop", basename);
1520   g_free (basename);
1521   filename = g_build_filename (dirname, desktop_id, NULL);
1522   g_free (desktop_id);
1523   g_free (dirname);
1524   
1525   fd = g_mkstemp (filename);
1526   if (fd == -1)
1527     {
1528       char *display_name;
1529
1530       display_name = g_filename_display_name (filename);
1531       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1532                    _("Can't create user desktop file %s"), display_name);
1533       g_free (display_name);
1534       g_free (filename);
1535       g_free (data);
1536       return NULL;
1537     }
1538
1539   desktop_id = g_path_get_basename (filename);
1540
1541   close (fd);
1542   
1543   res = g_file_set_contents (filename, data, data_size, error);
1544   if (!res)
1545     {
1546       g_free (desktop_id);
1547       g_free (filename);
1548       return NULL;
1549     }
1550
1551   run_update_command ("update-desktop-database", "applications");
1552   
1553   info = g_desktop_app_info_new_from_filename (filename);
1554   g_free (filename);
1555   if (info == NULL) 
1556     g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1557                  _("Can't load just created desktop file"));
1558   else
1559     info->desktop_id = g_strdup (desktop_id);
1560     
1561   g_free (desktop_id);
1562   
1563   return G_APP_INFO (info);
1564 }
1565
1566
1567 static void
1568 g_desktop_app_info_iface_init (GAppInfoIface *iface)
1569 {
1570   iface->dup = g_desktop_app_info_dup;
1571   iface->equal = g_desktop_app_info_equal;
1572   iface->get_id = g_desktop_app_info_get_id;
1573   iface->get_name = g_desktop_app_info_get_name;
1574   iface->get_description = g_desktop_app_info_get_description;
1575   iface->get_executable = g_desktop_app_info_get_executable;
1576   iface->get_icon = g_desktop_app_info_get_icon;
1577   iface->launch = g_desktop_app_info_launch;
1578   iface->supports_uris = g_desktop_app_info_supports_uris;
1579   iface->supports_files = g_desktop_app_info_supports_files;
1580   iface->launch_uris = g_desktop_app_info_launch_uris;
1581   iface->should_show = g_desktop_app_info_should_show;
1582   iface->set_as_default_for_type = g_desktop_app_info_set_as_default_for_type;
1583   iface->set_as_default_for_extension = g_desktop_app_info_set_as_default_for_extension;
1584   iface->add_supports_type = g_desktop_app_info_add_supports_type;
1585   iface->can_remove_supports_type = g_desktop_app_info_can_remove_supports_type;
1586   iface->remove_supports_type = g_desktop_app_info_remove_supports_type;
1587 }
1588
1589 static gboolean
1590 app_info_in_list (GAppInfo *info, 
1591                   GList    *list)
1592 {
1593   while (list != NULL)
1594     {
1595       if (g_app_info_equal (info, list->data))
1596         return TRUE;
1597       list = list->next;
1598     }
1599   return FALSE;
1600 }
1601
1602
1603 /**
1604  * g_app_info_get_all_for_type:
1605  * @content_type: the content type to find a #GAppInfo for
1606  * 
1607  * Gets a list of all #GAppInfo s for a given content type.
1608  *
1609  * Returns: #GList of #GAppInfo s for given @content_type
1610  *    or %NULL on error.
1611  **/
1612 GList *
1613 g_app_info_get_all_for_type (const char *content_type)
1614 {
1615   GList *desktop_entries, *l;
1616   GList *infos;
1617   GDesktopAppInfo *info;
1618
1619   g_return_val_if_fail (content_type != NULL, NULL);
1620   
1621   desktop_entries = get_all_desktop_entries_for_mime_type (content_type);
1622
1623   infos = NULL;
1624   for (l = desktop_entries; l != NULL; l = l->next)
1625     {
1626       char *desktop_entry = l->data;
1627
1628       info = g_desktop_app_info_new (desktop_entry);
1629       if (info)
1630         {
1631           if (app_info_in_list (G_APP_INFO (info), infos))
1632             g_object_unref (info);
1633           else
1634             infos = g_list_prepend (infos, info);
1635         }
1636       g_free (desktop_entry);
1637     }
1638
1639   g_list_free (desktop_entries);
1640   
1641   return g_list_reverse (infos);
1642 }
1643
1644
1645 /**
1646  * g_app_info_get_default_for_type:
1647  * @content_type: the content type to find a #GAppInfo for
1648  * @must_support_uris: if %TRUE, the #GAppInfo is expected to
1649  *     support URIs
1650  * 
1651  * Gets the #GAppInfo that correspond to a given content type.
1652  *
1653  * Returns: #GAppInfo for given @content_type or %NULL on error.
1654  **/
1655 GAppInfo *
1656 g_app_info_get_default_for_type (const char *content_type,
1657                                  gboolean    must_support_uris)
1658 {
1659   GList *desktop_entries, *l;
1660   GAppInfo *info;
1661
1662   g_return_val_if_fail (content_type != NULL, NULL);
1663   
1664   desktop_entries = get_all_desktop_entries_for_mime_type (content_type);
1665
1666   info = NULL;
1667   for (l = desktop_entries; l != NULL; l = l->next)
1668     {
1669       char *desktop_entry = l->data;
1670
1671       info = (GAppInfo *)g_desktop_app_info_new (desktop_entry);
1672       if (info)
1673         {
1674           if (must_support_uris && !g_app_info_supports_uris (info))
1675             {
1676               g_object_unref (info);
1677               info = NULL;
1678             }
1679           else
1680             break;
1681         }
1682     }
1683   
1684   g_list_foreach  (desktop_entries, (GFunc)g_free, NULL);
1685   g_list_free (desktop_entries);
1686   
1687   return info;
1688 }
1689
1690
1691 /**
1692  * g_app_info_get_default_for_uri_scheme:
1693  * @uri_scheme: a string containing a URI scheme.
1694  *
1695  * Gets the default application for launching applications 
1696  * using this URI scheme.
1697  *
1698  * TODO: This is currently unimplemented.
1699  * 
1700  * Returns: %NULL.
1701  **/
1702 GAppInfo *
1703 g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
1704 {
1705   /* TODO: Implement this using giomodules, reading the gconf settings
1706    * in /desktop/gnome/url-handlers
1707    */
1708   return NULL;
1709 }
1710
1711
1712 static void
1713 get_apps_from_dir (GHashTable *apps, 
1714                    const char *dirname, 
1715                    const char *prefix)
1716 {
1717   GDir *dir;
1718   const char *basename;
1719   char *filename, *subprefix, *desktop_id;
1720   gboolean hidden;
1721   GDesktopAppInfo *appinfo;
1722   
1723   dir = g_dir_open (dirname, 0, NULL);
1724   if (dir)
1725     {
1726       while ((basename = g_dir_read_name (dir)) != NULL)
1727         {
1728           filename = g_build_filename (dirname, basename, NULL);
1729           if (g_str_has_suffix (basename, ".desktop"))
1730             {
1731               desktop_id = g_strconcat (prefix, basename, NULL);
1732
1733               /* Use _extended so we catch NULLs too (hidden) */
1734               if (!g_hash_table_lookup_extended (apps, desktop_id, NULL, NULL))
1735                 {
1736                   appinfo = g_desktop_app_info_new_from_filename (filename);
1737
1738                   if (appinfo && g_desktop_app_info_get_is_hidden (appinfo))
1739                     {
1740                       g_object_unref (appinfo);
1741                       appinfo = NULL;
1742                       hidden = TRUE;
1743                     }
1744                                       
1745                   if (appinfo || hidden)
1746                     {
1747                       g_hash_table_insert (apps, g_strdup (desktop_id), appinfo);
1748
1749                       if (appinfo)
1750                         {
1751                           /* Reuse instead of strdup here */
1752                           appinfo->desktop_id = desktop_id;
1753                           desktop_id = NULL;
1754                         }
1755                     }
1756                 }
1757               g_free (desktop_id);
1758             }
1759           else
1760             {
1761               if (g_file_test (filename, G_FILE_TEST_IS_DIR))
1762                 {
1763                   subprefix = g_strconcat (prefix, basename, "-", NULL);
1764                   get_apps_from_dir (apps, filename, subprefix);
1765                   g_free (subprefix);
1766                 }
1767             }
1768           g_free (filename);
1769         }
1770       g_dir_close (dir);
1771     }
1772 }
1773
1774
1775 /**
1776  * g_app_info_get_all:
1777  *
1778  * Gets a list of all of the applications currently registered 
1779  * on this system.
1780  * 
1781  * For desktop files, this includes applications that have 
1782  * <literal>NoDisplay=true</literal> set or are excluded from 
1783  * display by means of <literal>OnlyShowIn</literal> or
1784  * <literal>NotShowIn</literal>. See g_app_info_should_show().
1785  * The returned list does not include applications which have
1786  * the <literal>Hidden</literal> key set. 
1787  * 
1788  * Returns: a newly allocated #GList of references to #GAppInfo<!---->s.
1789  **/
1790 GList *
1791 g_app_info_get_all (void)
1792 {
1793   const char * const *dirs;
1794   GHashTable *apps;
1795   GHashTableIter iter;
1796   gpointer value;
1797   int i;
1798   GList *infos;
1799
1800   dirs = get_applications_search_path ();
1801
1802   apps = g_hash_table_new_full (g_str_hash, g_str_equal,
1803                                 g_free, NULL);
1804
1805   
1806   for (i = 0; dirs[i] != NULL; i++)
1807     get_apps_from_dir (apps, dirs[i], "");
1808
1809
1810   infos = NULL;
1811   g_hash_table_iter_init (&iter, apps);
1812   while (g_hash_table_iter_next (&iter, NULL, &value))
1813     {
1814       if (value)
1815         infos = g_list_prepend (infos, value);
1816     }
1817
1818   g_hash_table_destroy (apps);
1819
1820   return g_list_reverse (infos);
1821 }
1822
1823 /* Cacheing of mimeinfo.cache and defaults.list files */
1824
1825 typedef struct {
1826   char *path;
1827   GHashTable *mime_info_cache_map;
1828   GHashTable *defaults_list_map;
1829   time_t mime_info_cache_timestamp;
1830   time_t defaults_list_timestamp;
1831 } MimeInfoCacheDir;
1832
1833 typedef struct {
1834   GList *dirs;                       /* mimeinfo.cache and defaults.list */
1835   GHashTable *global_defaults_cache; /* global results of defaults.list lookup and validation */
1836   time_t last_stat_time;
1837   guint should_ping_mime_monitor : 1;
1838 } MimeInfoCache;
1839
1840 static MimeInfoCache *mime_info_cache = NULL;
1841 G_LOCK_DEFINE_STATIC (mime_info_cache);
1842
1843 static void mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir  *dir,
1844                                                      const char        *mime_type,
1845                                                      char             **new_desktop_file_ids);
1846
1847 static MimeInfoCache * mime_info_cache_new (void);
1848
1849 static void
1850 destroy_info_cache_value (gpointer  key, 
1851                           GList    *value, 
1852                           gpointer  data)
1853 {
1854   g_list_foreach (value, (GFunc)g_free, NULL);
1855   g_list_free (value);
1856 }
1857
1858 static void
1859 destroy_info_cache_map (GHashTable *info_cache_map)
1860 {
1861   g_hash_table_foreach (info_cache_map, (GHFunc)destroy_info_cache_value, NULL);
1862   g_hash_table_destroy (info_cache_map);
1863 }
1864
1865 static gboolean
1866 mime_info_cache_dir_out_of_date (MimeInfoCacheDir *dir,
1867                                  const char       *cache_file,
1868                                  time_t           *timestamp)
1869 {
1870   struct stat buf;
1871   char *filename;
1872   
1873   filename = g_build_filename (dir->path, cache_file, NULL);
1874   
1875   if (g_stat (filename, &buf) < 0)
1876     {
1877       g_free (filename);
1878       return TRUE;
1879     }
1880   g_free (filename);
1881
1882   if (buf.st_mtime != *timestamp) 
1883     return TRUE;
1884   
1885   return FALSE;
1886 }
1887
1888 /* Call with lock held */
1889 static gboolean
1890 remove_all (gpointer  key,
1891             gpointer  value,
1892             gpointer  user_data)
1893 {
1894   return TRUE;
1895 }
1896
1897
1898 static void
1899 mime_info_cache_blow_global_cache (void)
1900 {
1901   g_hash_table_foreach_remove (mime_info_cache->global_defaults_cache,
1902                                remove_all, NULL);
1903 }
1904
1905 static void
1906 mime_info_cache_dir_init (MimeInfoCacheDir *dir)
1907 {
1908   GError *load_error;
1909   GKeyFile *key_file;
1910   gchar *filename, **mime_types;
1911   int i;
1912   struct stat buf;
1913   
1914   load_error = NULL;
1915   mime_types = NULL;
1916   
1917   if (dir->mime_info_cache_map != NULL &&
1918       !mime_info_cache_dir_out_of_date (dir, "mimeinfo.cache",
1919                                         &dir->mime_info_cache_timestamp))
1920     return;
1921   
1922   if (dir->mime_info_cache_map != NULL)
1923     destroy_info_cache_map (dir->mime_info_cache_map);
1924   
1925   dir->mime_info_cache_map = g_hash_table_new_full (g_str_hash, g_str_equal,
1926                                                     (GDestroyNotify) g_free,
1927                                                     NULL);
1928   
1929   key_file = g_key_file_new ();
1930   
1931   filename = g_build_filename (dir->path, "mimeinfo.cache", NULL);
1932   
1933   if (g_stat (filename, &buf) < 0)
1934     goto error;
1935   
1936   if (dir->mime_info_cache_timestamp > 0) 
1937     mime_info_cache->should_ping_mime_monitor = TRUE;
1938   
1939   dir->mime_info_cache_timestamp = buf.st_mtime;
1940   
1941   g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
1942   
1943   g_free (filename);
1944   filename = NULL;
1945   
1946   if (load_error != NULL)
1947     goto error;
1948   
1949   mime_types = g_key_file_get_keys (key_file, MIME_CACHE_GROUP,
1950                                     NULL, &load_error);
1951   
1952   if (load_error != NULL)
1953     goto error;
1954   
1955   for (i = 0; mime_types[i] != NULL; i++)
1956     {
1957       gchar **desktop_file_ids;
1958       char *unaliased_type;
1959       desktop_file_ids = g_key_file_get_string_list (key_file,
1960                                                      MIME_CACHE_GROUP,
1961                                                      mime_types[i],
1962                                                      NULL,
1963                                                      NULL);
1964       
1965       if (desktop_file_ids == NULL)
1966         continue;
1967
1968       unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
1969       mime_info_cache_dir_add_desktop_entries (dir,
1970                                                unaliased_type,
1971                                                desktop_file_ids);
1972       g_free (unaliased_type);
1973     
1974       g_strfreev (desktop_file_ids);
1975     }
1976   
1977   g_strfreev (mime_types);
1978   g_key_file_free (key_file);
1979   
1980   return;
1981  error:
1982   g_free (filename);
1983   g_key_file_free (key_file);
1984   
1985   if (mime_types != NULL)
1986     g_strfreev (mime_types);
1987   
1988   if (load_error)
1989     g_error_free (load_error);
1990 }
1991
1992 static void
1993 mime_info_cache_dir_init_defaults_list (MimeInfoCacheDir *dir)
1994 {
1995   GKeyFile *key_file;
1996   GError *load_error;
1997   gchar *filename, **mime_types;
1998   char *unaliased_type;
1999   char **desktop_file_ids;
2000   int i;
2001   struct stat buf;
2002
2003   load_error = NULL;
2004   mime_types = NULL;
2005
2006   if (dir->defaults_list_map != NULL &&
2007       !mime_info_cache_dir_out_of_date (dir, "defaults.list",
2008                                         &dir->defaults_list_timestamp))
2009     return;
2010   
2011   if (dir->defaults_list_map != NULL)
2012     g_hash_table_destroy (dir->defaults_list_map);
2013
2014   dir->defaults_list_map = g_hash_table_new_full (g_str_hash, g_str_equal,
2015                                                   g_free, (GDestroyNotify)g_strfreev);
2016
2017   key_file = g_key_file_new ();
2018   
2019   filename = g_build_filename (dir->path, "defaults.list", NULL);
2020   if (g_stat (filename, &buf) < 0)
2021     goto error;
2022
2023   if (dir->defaults_list_timestamp > 0) 
2024     mime_info_cache->should_ping_mime_monitor = TRUE;
2025
2026   dir->defaults_list_timestamp = buf.st_mtime;
2027
2028   g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &load_error);
2029   g_free (filename);
2030   filename = NULL;
2031
2032   if (load_error != NULL)
2033     goto error;
2034
2035   mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP,
2036                                     NULL, &load_error);
2037
2038   if (load_error != NULL)
2039     goto error;
2040
2041   for (i = 0; mime_types[i] != NULL; i++)
2042     {
2043       desktop_file_ids = g_key_file_get_string_list (key_file,
2044                                                      DEFAULT_APPLICATIONS_GROUP,
2045                                                      mime_types[i],
2046                                                      NULL,
2047                                                      NULL);
2048       if (desktop_file_ids == NULL)
2049         continue;
2050
2051       unaliased_type = _g_unix_content_type_unalias (mime_types[i]);
2052       g_hash_table_replace (dir->defaults_list_map,
2053                             unaliased_type,
2054                             desktop_file_ids);
2055     }
2056
2057   g_strfreev (mime_types);
2058   g_key_file_free (key_file);
2059   
2060   return;
2061  error:
2062   g_free (filename);
2063   g_key_file_free (key_file);
2064   
2065   if (mime_types != NULL)
2066     g_strfreev (mime_types);
2067   
2068   if (load_error)
2069     g_error_free (load_error);
2070 }
2071
2072 static MimeInfoCacheDir *
2073 mime_info_cache_dir_new (const char *path)
2074 {
2075   MimeInfoCacheDir *dir;
2076
2077   dir = g_new0 (MimeInfoCacheDir, 1);
2078   dir->path = g_strdup (path);
2079   
2080   return dir;
2081 }
2082
2083 static void
2084 mime_info_cache_dir_free (MimeInfoCacheDir *dir)
2085 {
2086   if (dir == NULL)
2087     return;
2088   
2089   if (dir->mime_info_cache_map != NULL)
2090     {
2091       destroy_info_cache_map (dir->mime_info_cache_map);
2092       dir->mime_info_cache_map = NULL;
2093       
2094   }
2095   
2096   if (dir->defaults_list_map != NULL)
2097     {
2098       g_hash_table_destroy (dir->defaults_list_map);
2099       dir->defaults_list_map = NULL;
2100     }
2101   
2102   g_free (dir);
2103 }
2104
2105 static void
2106 mime_info_cache_dir_add_desktop_entries (MimeInfoCacheDir  *dir,
2107                                          const char        *mime_type,
2108                                          char             **new_desktop_file_ids)
2109 {
2110   GList *desktop_file_ids;
2111   int i;
2112   
2113   desktop_file_ids = g_hash_table_lookup (dir->mime_info_cache_map,
2114                                           mime_type);
2115   
2116   for (i = 0; new_desktop_file_ids[i] != NULL; i++)
2117     {
2118       if (!g_list_find (desktop_file_ids, new_desktop_file_ids[i]))
2119         desktop_file_ids = g_list_append (desktop_file_ids,
2120                                           g_strdup (new_desktop_file_ids[i]));
2121     }
2122   
2123   g_hash_table_insert (dir->mime_info_cache_map, g_strdup (mime_type), desktop_file_ids);
2124 }
2125
2126 static void
2127 mime_info_cache_init_dir_lists (void)
2128 {
2129   const char * const *dirs;
2130   int i;
2131   
2132   mime_info_cache = mime_info_cache_new ();
2133   
2134   dirs = get_applications_search_path ();
2135   
2136   for (i = 0; dirs[i] != NULL; i++)
2137     {
2138       MimeInfoCacheDir *dir;
2139       
2140       dir = mime_info_cache_dir_new (dirs[i]);
2141       
2142       if (dir != NULL)
2143         {
2144           mime_info_cache_dir_init (dir);
2145           mime_info_cache_dir_init_defaults_list (dir);
2146           
2147           mime_info_cache->dirs = g_list_append (mime_info_cache->dirs, dir);
2148         }
2149     }
2150 }
2151
2152 static void
2153 mime_info_cache_update_dir_lists (void)
2154 {
2155   GList *tmp;
2156   
2157   tmp = mime_info_cache->dirs;
2158   
2159   while (tmp != NULL)
2160     {
2161       MimeInfoCacheDir *dir = (MimeInfoCacheDir *) tmp->data;
2162
2163       /* No need to do this if we had file monitors... */
2164       mime_info_cache_blow_global_cache ();
2165       mime_info_cache_dir_init (dir);
2166       mime_info_cache_dir_init_defaults_list (dir);
2167       
2168       tmp = tmp->next;
2169     }
2170 }
2171
2172 static void
2173 mime_info_cache_init (void)
2174 {
2175         G_LOCK (mime_info_cache);
2176         if (mime_info_cache == NULL)
2177           mime_info_cache_init_dir_lists ();
2178         else
2179           {
2180             time_t now;
2181             
2182             time (&now);
2183             if (now >= mime_info_cache->last_stat_time + 10)
2184               {
2185                 mime_info_cache_update_dir_lists ();
2186                 mime_info_cache->last_stat_time = now;
2187               }
2188           }
2189
2190         if (mime_info_cache->should_ping_mime_monitor)
2191           {
2192             /* g_idle_add (emit_mime_changed, NULL); */
2193             mime_info_cache->should_ping_mime_monitor = FALSE;
2194           }
2195         
2196         G_UNLOCK (mime_info_cache);
2197 }
2198
2199 static MimeInfoCache *
2200 mime_info_cache_new (void)
2201 {
2202   MimeInfoCache *cache;
2203   
2204   cache = g_new0 (MimeInfoCache, 1);
2205   
2206   cache->global_defaults_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
2207                                                         (GDestroyNotify) g_free,
2208                                                         (GDestroyNotify) g_free);
2209   return cache;
2210 }
2211
2212 static void
2213 mime_info_cache_free (MimeInfoCache *cache)
2214 {
2215   if (cache == NULL)
2216     return;
2217   
2218   g_list_foreach (cache->dirs,
2219                   (GFunc) mime_info_cache_dir_free,
2220                   NULL);
2221   g_list_free (cache->dirs);
2222   g_hash_table_destroy (cache->global_defaults_cache);
2223   g_free (cache);
2224 }
2225
2226 /**
2227  * mime_info_cache_reload:
2228  * @dir: directory path which needs reloading.
2229  * 
2230  * Reload the mime information for the @dir.
2231  */
2232 static void
2233 mime_info_cache_reload (const char *dir)
2234 {
2235   /* FIXME: just reload the dir that needs reloading,
2236    * don't blow the whole cache
2237    */
2238   if (mime_info_cache != NULL)
2239     {
2240       G_LOCK (mime_info_cache);
2241       mime_info_cache_free (mime_info_cache);
2242       mime_info_cache = NULL;
2243       G_UNLOCK (mime_info_cache);
2244     }
2245 }
2246
2247 static GList *
2248 append_desktop_entry (GList      *list, 
2249                       const char *desktop_entry)
2250 {
2251   /* Add if not already in list, and valid */
2252   if (!g_list_find_custom (list, desktop_entry, (GCompareFunc) strcmp))
2253     list = g_list_prepend (list, g_strdup (desktop_entry));
2254   
2255   return list;
2256 }
2257
2258 /**
2259  * get_all_desktop_entries_for_mime_type:
2260  * @mime_type: a mime type.
2261  *
2262  * Returns all the desktop ids for @mime_type. The desktop files
2263  * are listed in an order so that default applications are listed before
2264  * non-default ones, and handlers for inherited mimetypes are listed
2265  * after the base ones.
2266  *
2267  * Return value: a #GList containing the desktop ids which claim
2268  *    to handle @mime_type.
2269  */
2270 static GList *
2271 get_all_desktop_entries_for_mime_type (const char *base_mime_type)
2272 {
2273   GList *desktop_entries, *list, *dir_list, *tmp;
2274   MimeInfoCacheDir *dir;
2275   char *mime_type;
2276   char **mime_types;
2277   char **default_entries;
2278   int i,j;
2279   
2280   mime_info_cache_init ();
2281
2282   mime_types = _g_unix_content_type_get_parents (base_mime_type);
2283   G_LOCK (mime_info_cache);
2284   
2285   desktop_entries = NULL;
2286   for (i = 0; mime_types[i] != NULL; i++)
2287     {
2288       mime_type = mime_types[i];
2289
2290       /* Go through all apps listed as defaults */
2291       for (dir_list = mime_info_cache->dirs;
2292            dir_list != NULL;
2293            dir_list = dir_list->next)
2294         {
2295           dir = dir_list->data;
2296           default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
2297           for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
2298             desktop_entries = append_desktop_entry (desktop_entries, default_entries[j]);
2299         }
2300
2301       /* Go through all entries that support the mimetype */
2302       for (dir_list = mime_info_cache->dirs;
2303            dir_list != NULL;
2304            dir_list = dir_list->next) 
2305         {
2306           dir = dir_list->data;
2307         
2308           list = g_hash_table_lookup (dir->mime_info_cache_map, mime_type);
2309           for (tmp = list; tmp != NULL; tmp = tmp->next)
2310             desktop_entries = append_desktop_entry (desktop_entries, tmp->data);
2311         }
2312     }
2313   
2314   G_UNLOCK (mime_info_cache);
2315
2316   g_strfreev (mime_types);
2317   
2318   desktop_entries = g_list_reverse (desktop_entries);
2319   
2320   return desktop_entries;
2321 }
2322
2323 #define __G_DESKTOP_APP_INFO_C__
2324 #include "gioaliasdef.c"