recent-manager: Add migration to the new storage file location

The recently-used.xbel file location has been moved from $HOME to
$XDG_DATA_DIR, to be compliant with the desktop bookmark specification
and with other desktop environments following it.

The effective change was done in gtk+-3, but we need a migration path
for gtk+-2.

The possible cases are:

  • the old file is not present, so we just switch to the new one;
  • the old file is present, but the new one is not; in this case
    we rename the old file to the new one.
  • both the old file and the new file are present; in this case,
    we try a simple merge of the contents and remove the old file.

The merge is the (obviously) more expensive option, but it should only
happen once.

https://bugzilla.gnome.org/show_bug.cgi?id=633242
This commit is contained in:
Emmanuele Bassi 2010-10-30 15:11:23 +01:00
parent 78bb09c5a1
commit 7825f01b2f

View File

@ -42,7 +42,7 @@
#include "gtkalias.h"
/* the file where we store the recently used items */
#define GTK_RECENTLY_USED_FILE ".recently-used.xbel"
#define GTK_RECENTLY_USED_FILE "recently-used.xbel"
/* return all items by default */
#define DEFAULT_LIMIT -1
@ -468,6 +468,139 @@ gtk_recent_manager_monitor_changed (GFileMonitor *monitor,
}
}
/*
* get_default_recent_file:
*
* Retrieves the default storage file
*
* The default file is under XDG_DATA_HOME/recently-used.xbel but we also
* check if the old $HOME/.recently-used.xbel is still there, and rename it
* if needed.
*
* Return value: a newly allocated string with the new file
*/
static char *
get_default_recent_file (void)
{
char *old_file = g_build_filename (g_get_home_dir (),
"." GTK_RECENTLY_USED_FILE,
NULL);
char *new_file = g_build_filename (g_get_user_data_dir (),
GTK_RECENTLY_USED_FILE,
NULL);
GBookmarkFile *bf_old = NULL, *bf_new = NULL;
char **uris;
gsize n_uris, i;
/* simple case: the old file does not exist, so we just use the new one */
if (!g_file_test (old_file, G_FILE_TEST_EXISTS))
{
g_free (old_file);
return new_file;
}
/* less simple case: the old file still exists but the new one doesn't,
* so we rename the old one to the new one
*/
if (!g_file_test (new_file, G_FILE_TEST_EXISTS))
{
if (g_rename (old_file, new_file) == -1)
filename_warning ("Unable to rename '%s': %s",
old_file,
g_strerror (errno));
g_free (old_file);
return new_file;
}
/* complex case: both the old file and the new file exist, so we do
* a preliminary parse pass and merge the contents, then remove the
* old file
*/
bf_old = g_bookmark_file_new ();
if (!g_bookmark_file_load_from_file (bf_old, old_file, NULL))
goto unlink_and_return;
bf_new = g_bookmark_file_new ();
if (!g_bookmark_file_load_from_file (bf_new, new_file, NULL))
goto unlink_and_return;
uris = g_bookmark_file_get_uris (bf_old, &n_uris);
for (i = 0; i < n_uris; i++)
{
char *mime, *title, *description;
gboolean is_private;
char **apps;
gsize n_apps, j;
/* the new file always wins */
if (g_bookmark_file_has_item (bf_new, uris[i]))
continue;
mime = g_bookmark_file_get_mime_type (bf_old, uris[i], NULL);
title = g_bookmark_file_get_title (bf_old, uris[i], NULL);
description = g_bookmark_file_get_description (bf_old, uris[i], NULL);
is_private = g_bookmark_file_get_is_private (bf_old, uris[i], NULL);
g_bookmark_file_set_mime_type (bf_new, uris[i], mime);
if (title != NULL)
g_bookmark_file_set_title (bf_new, uris[i], title);
if (description != NULL)
g_bookmark_file_set_description (bf_new, uris[i], description);
g_free (mime);
g_free (title);
g_free (description);
g_bookmark_file_set_is_private (bf_new, uris[i], is_private);
apps = g_bookmark_file_get_applications (bf_old, uris[i], &n_apps, NULL);
for (j = 0; j < n_apps; j++)
{
char *exec;
guint count;
time_t stamp;
g_bookmark_file_get_app_info (bf_old, uris[i], apps[j],
&exec,
&count,
&stamp,
NULL);
g_bookmark_file_set_app_info (bf_new, uris[i], apps[j],
exec,
count,
stamp,
NULL);
g_free (exec);
}
g_strfreev (apps);
}
g_strfreev (uris);
/* we don't particularly care about errors here; if it fails then
* we start with a blank slate anyhow
*/
g_bookmark_file_to_file (bf_new, new_file, NULL);
unlink_and_return:
if (bf_old != NULL)
g_bookmark_file_free (bf_old);
if (bf_new != NULL)
g_bookmark_file_free (bf_new);
g_unlink (old_file);
g_free (old_file);
return new_file;
}
static void
gtk_recent_manager_set_filename (GtkRecentManager *manager,
const gchar *filename)
@ -508,9 +641,7 @@ gtk_recent_manager_set_filename (GtkRecentManager *manager,
else
{
if (!filename || *filename == '\0')
priv->filename = g_build_filename (g_get_home_dir (),
GTK_RECENTLY_USED_FILE,
NULL);
priv->filename = get_default_recent_file ();
else
priv->filename = g_strdup (filename);
}