GDesktopAppInfo: fix leaks
[platform/upstream/glib.git] / gio / gdesktopappinfo.c
index 955d007..1bac191 100644 (file)
@@ -26,7 +26,6 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
-#include <sys/wait.h>
 
 #ifdef HAVE_CRT_EXTERNS_H
 #include <crt_externs.h>
@@ -65,6 +64,7 @@
 #define GENERIC_NAME_KEY            "GenericName"
 #define FULL_NAME_KEY               "X-GNOME-FullName"
 #define KEYWORDS_KEY                "Keywords"
+#define STARTUP_WM_CLASS_KEY        "StartupWMClass"
 
 enum {
   PROP_0,
@@ -106,13 +106,14 @@ struct _GDesktopAppInfo
   char *binary;
   char *path;
   char *categories;
+  char *startup_wm_class;
+  char **mime_types;
 
   guint nodisplay       : 1;
   guint hidden          : 1;
   guint terminal        : 1;
   guint startup_notify  : 1;
   guint no_fuse         : 1;
-  /* FIXME: what about StartupWMClass ? */
 };
 
 typedef enum {
@@ -185,6 +186,8 @@ g_desktop_app_info_finalize (GObject *object)
   g_free (info->binary);
   g_free (info->path);
   g_free (info->categories);
+  g_free (info->startup_wm_class);
+  g_strfreev (info->mime_types);
   
   G_OBJECT_CLASS (g_desktop_app_info_parent_class)->finalize (object);
 }
@@ -238,7 +241,7 @@ g_desktop_app_info_class_init (GDesktopAppInfoClass *klass)
   gobject_class->finalize = g_desktop_app_info_finalize;
 
   /**
-   * GDesktopAppInfo:filename
+   * GDesktopAppInfo:filename:
    *
    * The origin filename of this #GDesktopAppInfo
    */
@@ -330,6 +333,8 @@ g_desktop_app_info_load_from_keyfile (GDesktopAppInfo *info,
   info->no_fuse = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GIO-NoFuse", NULL) != FALSE;
   info->hidden = g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL) != FALSE;
   info->categories = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_CATEGORIES, NULL);
+  info->startup_wm_class = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, STARTUP_WM_CLASS_KEY, NULL);
+  info->mime_types = g_key_file_get_string_list (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_MIME_TYPE, NULL, NULL);
   
   info->icon = NULL;
   if (info->icon_name)
@@ -1306,7 +1311,8 @@ _g_desktop_app_info_launch_uris_internal (GAppInfo                   *appinfo,
           display = g_app_launch_context_get_display (launch_context,
                                                       appinfo,
                                                       launched_files);
-          envp = g_environ_setenv (envp, "DISPLAY", display, TRUE);
+          if (display)
+            envp = g_environ_setenv (envp, "DISPLAY", display, TRUE);
 
           if (info->startup_notify)
             {
@@ -1367,12 +1373,12 @@ _g_desktop_app_info_launch_uris_internal (GAppInfo                   *appinfo,
        * the connection if we were the initial owner.
        */
       g_dbus_connection_flush (session_bus, NULL, NULL, NULL);
-      g_object_unref (session_bus);
     }
 
   completed = TRUE;
 
  out:
+  g_clear_object (&session_bus);
   g_strfreev (argv);
   g_strfreev (envp);
 
@@ -1843,8 +1849,7 @@ update_program_done (GPid     pid,
                     gpointer data)
 {
   /* Did the application exit correctly */
-  if (WIFEXITED (status) &&
-      WEXITSTATUS (status) == 0)
+  if (g_spawn_check_exit_status (status, NULL))
     {
       /* Here we could clean out any caches in use */
     }
@@ -1977,6 +1982,15 @@ g_desktop_app_info_remove_supports_type (GAppInfo    *appinfo,
                                error);
 }
 
+static const char **
+g_desktop_app_info_get_supported_types (GAppInfo *appinfo)
+{
+  GDesktopAppInfo *info = G_DESKTOP_APP_INFO (appinfo);
+
+  return (const char**) info->mime_types;
+}
+
+
 static gboolean
 g_desktop_app_info_ensure_saved (GDesktopAppInfo  *info,
                                 GError          **error)
@@ -2064,6 +2078,7 @@ g_desktop_app_info_ensure_saved (GDesktopAppInfo  *info,
   close (fd);
   
   res = g_file_set_contents (filename, data, data_size, error);
+  g_free (data);
   if (!res)
     {
       g_free (desktop_id);
@@ -2127,6 +2142,12 @@ g_desktop_app_info_delete (GAppInfo *appinfo)
  *
  * Creates a new #GAppInfo from the given information.
  *
+ * Note that for @commandline, the quoting rules of the Exec key of the
+ * <ulink url="http://freedesktop.org/Standards/desktop-entry-spec">freedesktop.org Desktop
+ * Entry Specification</ulink> are applied. For example, if the @commandline contains
+ * percent-encoded URIs, the percent-character must be doubled in order to prevent it from
+ * being swallowed by Exec key unquoting. See the specification for exact quoting rules.
+ *
  * Returns: (transfer full): new #GAppInfo for given command.
  **/
 GAppInfo *
@@ -2198,6 +2219,7 @@ g_desktop_app_info_iface_init (GAppInfoIface *iface)
   iface->get_commandline = g_desktop_app_info_get_commandline;
   iface->get_display_name = g_desktop_app_info_get_display_name;
   iface->set_as_last_used_for_type = g_desktop_app_info_set_as_last_used_for_type;
+  iface->get_supported_types = g_desktop_app_info_get_supported_types;
 }
 
 static gboolean
@@ -3216,6 +3238,7 @@ get_all_desktop_entries_for_mime_type (const char  *base_mime_type,
   char **mime_types;
   char **default_entries;
   char **removed_associations;
+  gboolean already_found_handler;
   int i, j, k;
   GPtrArray *array;
   char **anc;
@@ -3267,6 +3290,11 @@ get_all_desktop_entries_for_mime_type (const char  *base_mime_type,
     {
       mime_type = mime_types[i];
 
+      /* This is true if we already found a handler for a more specific
+         mimetype. If its set we ignore any defaults for the less specific
+         mimetypes. */
+      already_found_handler = (desktop_entries != NULL);
+
       /* Go through all apps listed in user and system dirs */
       for (dir_list = mime_info_cache->dirs;
           dir_list != NULL;
@@ -3277,7 +3305,7 @@ get_all_desktop_entries_for_mime_type (const char  *base_mime_type,
           /* Pick the explicit default application if we got no result earlier
            * (ie, for more specific mime types)
            */
-          if (desktop_entries == NULL)
+          if (!already_found_handler)
             {
               entry = g_hash_table_lookup (dir->mimeapps_list_defaults_map, mime_type);
 
@@ -3303,7 +3331,7 @@ get_all_desktop_entries_for_mime_type (const char  *base_mime_type,
          default_entries = g_hash_table_lookup (dir->defaults_list_map, mime_type);
          for (j = 0; default_entries != NULL && default_entries[j] != NULL; j++)
             {
-              if (default_entry == NULL && old_default_entry == NULL)
+              if (default_entry == NULL && old_default_entry == NULL && !already_found_handler)
                 old_default_entry = g_strdup (default_entries[j]);
 
               desktop_entries = append_desktop_entry (desktop_entries, default_entries[j], removed_entries);
@@ -3352,6 +3380,8 @@ get_all_desktop_entries_for_mime_type (const char  *base_mime_type,
 
 /* GDesktopAppInfoLookup interface: */
 
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
 typedef GDesktopAppInfoLookupIface GDesktopAppInfoLookupInterface;
 G_DEFINE_INTERFACE (GDesktopAppInfoLookup, g_desktop_app_info_lookup, G_TYPE_OBJECT)
 
@@ -3382,8 +3412,6 @@ GAppInfo *
 g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *lookup,
                                                      const char            *uri_scheme)
 {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
   GDesktopAppInfoLookupIface *iface;
 
   g_return_val_if_fail (G_IS_DESKTOP_APP_INFO_LOOKUP (lookup), NULL);
@@ -3391,5 +3419,27 @@ g_desktop_app_info_lookup_get_default_for_uri_scheme (GDesktopAppInfoLookup *loo
   iface = G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE (lookup);
 
   return (* iface->get_default_for_uri_scheme) (lookup, uri_scheme);
-#pragma GCC diagnostic pop
+}
+
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+/**
+ * g_desktop_app_info_get_startup_wm_class:
+ * @app_info: a #GDesktopAppInfo that supports startup notify
+ *
+ * Retrieves the StartupWMClass field from @app_info. This represents the
+ * WM_CLASS property of the main window of the application, if launched through
+ * @app_info.
+ *
+ * Returns: (transfer none): the startup WM class, or %NULL if none is set
+ * in the desktop file.
+ *
+ * Since: 2.34
+ */
+const char *
+g_desktop_app_info_get_startup_wm_class (GDesktopAppInfo *app_info)
+{
+  g_return_val_if_fail (G_IS_DESKTOP_APP_INFO (app_info), NULL);
+
+  return app_info->startup_wm_class;
 }