X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdesktopappinfo.c;h=7bfc904719c73e3af44f8a15d5423aa16336c77c;hb=13e15733f38a40c6ef6a1baede91cce81c86ebaa;hp=ddec6906005a3364056cf130078f5cfd3dc85cf7;hpb=08efbda7333cf1d349719e699bbcbb63b8ef09e4;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index ddec690..7bfc904 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -137,6 +137,7 @@ G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT, typedef struct { gchar *path; + gchar *alternatively_watching; gboolean is_config; gboolean is_setup; GLocalDirectoryMonitor *monitor; @@ -155,6 +156,52 @@ static GMutex desktop_file_dir_lock; /* Monitor 'changed' signal handler {{{2 */ static void desktop_file_dir_reset (DesktopFileDir *dir); +/*< internal > + * desktop_file_dir_get_alternative_dir: + * @dir: a #DesktopFileDir + * + * Gets the "alternative" directory to monitor in case the path + * doesn't exist. + * + * If the path exists this will return NULL, otherwise it will return a + * parent directory of the path. + * + * This is used to avoid inotify on a non-existent directory (which + * results in polling). + * + * See https://bugzilla.gnome.org/show_bug.cgi?id=522314 for more info. + */ +static gchar * +desktop_file_dir_get_alternative_dir (DesktopFileDir *dir) +{ + gchar *parent; + + /* If the directory itself exists then we need no alternative. */ + if (g_access (dir->path, R_OK | X_OK) == 0) + return NULL; + + /* Otherwise, try the parent directories until we find one. */ + parent = g_path_get_dirname (dir->path); + + while (g_access (parent, R_OK | X_OK) != 0) + { + gchar *tmp = parent; + + parent = g_path_get_dirname (tmp); + + /* If somehow we get to '/' or '.' then just stop... */ + if (g_str_equal (parent, tmp)) + { + g_free (tmp); + break; + } + + g_free (tmp); + } + + return parent; +} + static void desktop_file_dir_changed (GFileMonitor *monitor, GFile *file, @@ -163,6 +210,7 @@ desktop_file_dir_changed (GFileMonitor *monitor, gpointer user_data) { DesktopFileDir *dir = user_data; + gboolean do_nothing = FALSE; /* We are not interested in receiving notifications forever just * because someone asked about one desktop file once. @@ -170,15 +218,30 @@ desktop_file_dir_changed (GFileMonitor *monitor, * After we receive the first notification, reset the dir, destroying * the monitor. We will take this as a hint, next time that we are * asked, that we need to check if everything is up to date. + * + * If this is a notification for a parent directory (because the + * desktop directory didn't exist) then we shouldn't fire the signal + * unless something actually changed. */ g_mutex_lock (&desktop_file_dir_lock); - desktop_file_dir_reset (dir); + if (dir->alternatively_watching) + { + gchar *alternative_dir; + + alternative_dir = desktop_file_dir_get_alternative_dir (dir); + do_nothing = alternative_dir && g_str_equal (dir->alternatively_watching, alternative_dir); + g_free (alternative_dir); + } + + if (!do_nothing) + desktop_file_dir_reset (dir); g_mutex_unlock (&desktop_file_dir_lock); /* Notify anyone else who may be interested */ - g_app_info_monitor_fire (); + if (!do_nothing) + g_app_info_monitor_fire (); } /* Internal utility functions {{{2 */ @@ -331,13 +394,13 @@ desktop_key_get_name (guint key_id) case DESKTOP_KEY_Exec: return "Exec"; case DESKTOP_KEY_GenericName: - return "GenericName"; + return GENERIC_NAME_KEY; case DESKTOP_KEY_Keywords: - return "Keywords"; + return KEYWORDS_KEY; case DESKTOP_KEY_Name: return "Name"; case DESKTOP_KEY_X_GNOME_FullName: - return "X-GNOME-FullName"; + return FULL_NAME_KEY; default: g_assert_not_reached (); } @@ -707,8 +770,6 @@ desktop_file_dir_unindexed_read_mimeapps_list (DesktopFileDir *dir, const gchar *added_group, gboolean tweaks_permitted) { - const gchar default_group[] = "Default Applications"; - const gchar removed_group[] = "Removed Assocations"; UnindexedMimeTweaks *tweaks; char **desktop_file_ids; GKeyFile *key_file; @@ -748,12 +809,12 @@ desktop_file_dir_unindexed_read_mimeapps_list (DesktopFileDir *dir, g_strfreev (mime_types); } - mime_types = g_key_file_get_keys (key_file, removed_group, NULL, NULL); + mime_types = g_key_file_get_keys (key_file, REMOVED_ASSOCIATIONS_GROUP, NULL, NULL); if G_UNLIKELY (mime_types != NULL && !tweaks_permitted) { g_warning ("%s contains a [%s] group, but it is not permitted here. Only the non-desktop-specific " - "mimeapps.list file may add or remove associations.", filename, removed_group); + "mimeapps.list file may add or remove associations.", filename, REMOVED_ASSOCIATIONS_GROUP); g_strfreev (mime_types); mime_types = NULL; } @@ -762,7 +823,7 @@ desktop_file_dir_unindexed_read_mimeapps_list (DesktopFileDir *dir, { for (i = 0; mime_types[i] != NULL; i++) { - desktop_file_ids = g_key_file_get_string_list (key_file, removed_group, mime_types[i], NULL, NULL); + desktop_file_ids = g_key_file_get_string_list (key_file, REMOVED_ASSOCIATIONS_GROUP, mime_types[i], NULL, NULL); if (desktop_file_ids) { @@ -774,13 +835,13 @@ desktop_file_dir_unindexed_read_mimeapps_list (DesktopFileDir *dir, g_strfreev (mime_types); } - mime_types = g_key_file_get_keys (key_file, default_group, NULL, NULL); + mime_types = g_key_file_get_keys (key_file, DEFAULT_APPLICATIONS_GROUP, NULL, NULL); if (mime_types != NULL) { for (i = 0; mime_types[i] != NULL; i++) { - desktop_file_ids = g_key_file_get_string_list (key_file, default_group, mime_types[i], NULL, NULL); + desktop_file_ids = g_key_file_get_string_list (key_file, DEFAULT_APPLICATIONS_GROUP, mime_types[i], NULL, NULL); if (desktop_file_ids) { @@ -815,13 +876,13 @@ desktop_file_dir_unindexed_read_mimeapps_lists (DesktopFileDir *dir) for (i = 0; desktops[i]; i++) { filename = g_strdup_printf ("%s/%s-mimeapps.list", dir->path, desktops[i]); - desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, "Added Associations", FALSE); + desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, ADDED_ASSOCIATIONS_GROUP, FALSE); g_free (filename); } /* Next, the non-desktop-specific mimeapps.list */ filename = g_strdup_printf ("%s/mimeapps.list", dir->path); - desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, "Added Associations", TRUE); + desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, ADDED_ASSOCIATIONS_GROUP, TRUE); g_free (filename); /* The remaining files are only checked for in directories that might @@ -836,14 +897,14 @@ desktop_file_dir_unindexed_read_mimeapps_lists (DesktopFileDir *dir) * version. */ filename = g_strdup_printf ("%s/defaults.list", dir->path); - desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, "Added Associations", FALSE); + desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, ADDED_ASSOCIATIONS_GROUP, FALSE); g_free (filename); /* Finally, the mimeinfo.cache, which is just a cached copy of what we * would find in the MimeTypes= lines of all of the desktop files. */ filename = g_strdup_printf ("%s/mimeinfo.cache", dir->path); - desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, "MIME Cache", TRUE); + desktop_file_dir_unindexed_read_mimeapps_list (dir, filename, MIME_CACHE_GROUP, TRUE); g_free (filename); } @@ -1207,6 +1268,12 @@ desktop_file_dir_create_for_config (GArray *array, static void desktop_file_dir_reset (DesktopFileDir *dir) { + if (dir->alternatively_watching) + { + g_free (dir->alternatively_watching); + dir->alternatively_watching = NULL; + } + if (dir->monitor) { g_signal_handlers_disconnect_by_func (dir->monitor, desktop_file_dir_changed, dir); @@ -1252,10 +1319,23 @@ desktop_file_dir_reset (DesktopFileDir *dir) static void desktop_file_dir_init (DesktopFileDir *dir) { + const gchar *watch_dir; + g_assert (!dir->is_setup); + g_assert (!dir->alternatively_watching); g_assert (!dir->monitor); - dir->monitor = g_local_directory_monitor_new_in_worker (dir->path, G_FILE_MONITOR_NONE, NULL); + + dir->alternatively_watching = desktop_file_dir_get_alternative_dir (dir); + watch_dir = dir->alternatively_watching ? dir->alternatively_watching : dir->path; + + /* There is a very thin race here if the watch_dir has been _removed_ + * between when we checked for it and when we establish the watch. + * Removes probably don't happen in usual operation, and even if it + * does (and we catch the unlikely race), the only degradation is that + * we will fall back to polling. + */ + dir->monitor = g_local_directory_monitor_new_in_worker (watch_dir, G_FILE_MONITOR_NONE, NULL); if (dir->monitor) { @@ -4056,6 +4136,9 @@ g_app_info_get_default_for_uri_scheme (const char *uri_scheme) * An application implements an interface if that interface is listed in * the Implements= line of the desktop file of the application. * + * Returns: (element-type GDesktopAppInfo) (transfer full): a list of #GDesktopAppInfo + * objects. + * * Since: 2.42 **/ GList *