summaryrefslogtreecommitdiffstats
path: root/src/gtk/nautilusgtkbookmarksmanager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gtk/nautilusgtkbookmarksmanager.c')
-rw-r--r--src/gtk/nautilusgtkbookmarksmanager.c643
1 files changed, 643 insertions, 0 deletions
diff --git a/src/gtk/nautilusgtkbookmarksmanager.c b/src/gtk/nautilusgtkbookmarksmanager.c
new file mode 100644
index 0000000..86f3bb4
--- /dev/null
+++ b/src/gtk/nautilusgtkbookmarksmanager.c
@@ -0,0 +1,643 @@
+/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
+/* GTK - The GIMP Toolkit
+ * nautilusgtkbookmarksmanager.c: Utilities to manage and monitor ~/.gtk-bookmarks
+ * Copyright (C) 2003, Red Hat, Inc.
+ * Copyright (C) 2007-2008 Carlos Garnacho
+ * Copyright (C) 2011 Suse
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Federico Mena Quintero <federico@gnome.org>
+ */
+
+#include "config.h"
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include "nautilus-enum-types.h"
+
+#include <string.h>
+
+#include "nautilusgtkbookmarksmanagerprivate.h"
+
+static void
+_gtk_bookmark_free (gpointer data)
+{
+ GtkBookmark *bookmark = data;
+
+ g_object_unref (bookmark->file);
+ g_free (bookmark->label);
+ g_slice_free (GtkBookmark, bookmark);
+}
+
+static void
+set_error_bookmark_doesnt_exist (GFile *file, GError **error)
+{
+ char *uri = g_file_get_uri (file);
+
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
+ _("%s does not exist in the bookmarks list"),
+ uri);
+
+ g_free (uri);
+}
+
+static GFile *
+get_legacy_bookmarks_file (void)
+{
+ GFile *file;
+ char *filename;
+
+ filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL);
+ file = g_file_new_for_path (filename);
+ g_free (filename);
+
+ return file;
+}
+
+static GFile *
+get_bookmarks_file (void)
+{
+ GFile *file;
+ char *filename;
+
+ /* Use gtk-3.0's bookmarks file as the format didn't change.
+ * Add the 3.0 file format to get_legacy_bookmarks_file() when
+ * the format does change.
+ */
+ filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0", "bookmarks", NULL);
+ file = g_file_new_for_path (filename);
+ g_free (filename);
+
+ return file;
+}
+
+static GSList *
+parse_bookmarks (const char *contents)
+{
+ char **lines, *space;
+ GSList *bookmarks = NULL;
+ int i;
+
+ lines = g_strsplit (contents, "\n", -1);
+
+ for (i = 0; lines[i]; i++)
+ {
+ GtkBookmark *bookmark;
+
+ if (!*lines[i])
+ continue;
+
+ if (!g_utf8_validate (lines[i], -1, NULL))
+ continue;
+
+ bookmark = g_slice_new0 (GtkBookmark);
+
+ if ((space = strchr (lines[i], ' ')) != NULL)
+ {
+ space[0] = '\0';
+ bookmark->label = g_strdup (space + 1);
+ }
+
+ bookmark->file = g_file_new_for_uri (lines[i]);
+ bookmarks = g_slist_prepend (bookmarks, bookmark);
+ }
+
+ bookmarks = g_slist_reverse (bookmarks);
+ g_strfreev (lines);
+
+ return bookmarks;
+}
+
+static GSList *
+read_bookmarks (GFile *file)
+{
+ char *contents;
+ GSList *bookmarks = NULL;
+
+ if (!g_file_load_contents (file, NULL, &contents,
+ NULL, NULL, NULL))
+ return NULL;
+
+ bookmarks = parse_bookmarks (contents);
+
+ g_free (contents);
+
+ return bookmarks;
+}
+
+static void
+notify_changed (NautilusGtkBookmarksManager *manager)
+{
+ if (manager->changed_func)
+ manager->changed_func (manager->changed_func_data);
+}
+
+static void
+read_bookmarks_finish (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ GFile *file = G_FILE (source);
+ NautilusGtkBookmarksManager *manager = data;
+ char *contents = NULL;
+ GError *error = NULL;
+
+ if (!g_file_load_contents_finish (file, result, &contents, NULL, NULL, &error))
+ {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ g_warning ("Failed to load '%s': %s", g_file_peek_path (file), error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_slist_free_full (manager->bookmarks, _gtk_bookmark_free);
+ manager->bookmarks = parse_bookmarks (contents);
+
+ g_free (contents);
+
+ notify_changed (manager);
+}
+
+static void
+save_bookmarks (GFile *bookmarks_file,
+ GSList *bookmarks)
+{
+ GError *error = NULL;
+ GString *contents;
+ GSList *l;
+ GFile *parent = NULL;
+
+ contents = g_string_new ("");
+
+ for (l = bookmarks; l; l = l->next)
+ {
+ GtkBookmark *bookmark = l->data;
+ char *uri;
+
+ uri = g_file_get_uri (bookmark->file);
+ if (!uri)
+ continue;
+
+ g_string_append (contents, uri);
+
+ if (bookmark->label && g_utf8_validate (bookmark->label, -1, NULL))
+ g_string_append_printf (contents, " %s", bookmark->label);
+
+ g_string_append_c (contents, '\n');
+ g_free (uri);
+ }
+
+ parent = g_file_get_parent (bookmarks_file);
+ if (!g_file_make_directory_with_parents (parent, NULL, &error))
+ {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
+ g_clear_error (&error);
+ else
+ goto out;
+ }
+ if (!g_file_replace_contents (bookmarks_file,
+ contents->str,
+ contents->len,
+ NULL, FALSE, 0, NULL,
+ NULL, &error))
+ goto out;
+
+ out:
+ if (error)
+ {
+ g_critical ("%s", error->message);
+ g_error_free (error);
+ }
+ g_clear_object (&parent);
+ g_string_free (contents, TRUE);
+}
+
+static void
+bookmarks_file_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer data)
+{
+ NautilusGtkBookmarksManager *manager = data;
+
+ switch (event)
+ {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ case G_FILE_MONITOR_EVENT_CREATED:
+ g_file_load_contents_async (file, manager->cancellable, read_bookmarks_finish, manager);
+ break;
+
+ case G_FILE_MONITOR_EVENT_DELETED:
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+ case G_FILE_MONITOR_EVENT_UNMOUNTED:
+ case G_FILE_MONITOR_EVENT_MOVED:
+ case G_FILE_MONITOR_EVENT_RENAMED:
+ case G_FILE_MONITOR_EVENT_MOVED_IN:
+ case G_FILE_MONITOR_EVENT_MOVED_OUT:
+ default:
+ /* ignore at the moment */
+ break;
+ }
+}
+
+NautilusGtkBookmarksManager *
+_nautilus_gtk_bookmarks_manager_new (GtkBookmarksChangedFunc changed_func, gpointer changed_func_data)
+{
+ NautilusGtkBookmarksManager *manager;
+ GFile *bookmarks_file;
+ GError *error;
+
+ manager = g_new0 (NautilusGtkBookmarksManager, 1);
+
+ manager->changed_func = changed_func;
+ manager->changed_func_data = changed_func_data;
+
+ manager->cancellable = g_cancellable_new ();
+
+ bookmarks_file = get_bookmarks_file ();
+ if (!g_file_query_exists (bookmarks_file, NULL))
+ {
+ GFile *legacy_bookmarks_file;
+
+ /* Read the legacy one and write it to the new one */
+ legacy_bookmarks_file = get_legacy_bookmarks_file ();
+ manager->bookmarks = read_bookmarks (legacy_bookmarks_file);
+ if (manager->bookmarks)
+ save_bookmarks (bookmarks_file, manager->bookmarks);
+
+ g_object_unref (legacy_bookmarks_file);
+ }
+ else
+ g_file_load_contents_async (bookmarks_file, manager->cancellable, read_bookmarks_finish, manager);
+
+ error = NULL;
+ manager->bookmarks_monitor = g_file_monitor_file (bookmarks_file,
+ G_FILE_MONITOR_NONE,
+ NULL, &error);
+ if (error)
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+ else
+ manager->bookmarks_monitor_changed_id = g_signal_connect (manager->bookmarks_monitor, "changed",
+ G_CALLBACK (bookmarks_file_changed), manager);
+
+
+ g_object_unref (bookmarks_file);
+
+ return manager;
+}
+
+void
+_nautilus_gtk_bookmarks_manager_free (NautilusGtkBookmarksManager *manager)
+{
+ g_return_if_fail (manager != NULL);
+
+ g_cancellable_cancel (manager->cancellable);
+ g_object_unref (manager->cancellable);
+
+ if (manager->bookmarks_monitor)
+ {
+ g_file_monitor_cancel (manager->bookmarks_monitor);
+ g_signal_handler_disconnect (manager->bookmarks_monitor, manager->bookmarks_monitor_changed_id);
+ manager->bookmarks_monitor_changed_id = 0;
+ g_object_unref (manager->bookmarks_monitor);
+ }
+
+ g_slist_free_full (manager->bookmarks, _gtk_bookmark_free);
+
+ g_free (manager);
+}
+
+GSList *
+_nautilus_gtk_bookmarks_manager_list_bookmarks (NautilusGtkBookmarksManager *manager)
+{
+ GSList *bookmarks, *files = NULL;
+
+ g_return_val_if_fail (manager != NULL, NULL);
+
+ bookmarks = manager->bookmarks;
+
+ while (bookmarks)
+ {
+ GtkBookmark *bookmark;
+
+ bookmark = bookmarks->data;
+ bookmarks = bookmarks->next;
+
+ files = g_slist_prepend (files, g_object_ref (bookmark->file));
+ }
+
+ return g_slist_reverse (files);
+}
+
+static GSList *
+find_bookmark_link_for_file (GSList *bookmarks, GFile *file, int *position_ret)
+{
+ int pos;
+
+ pos = 0;
+ for (; bookmarks; bookmarks = bookmarks->next)
+ {
+ GtkBookmark *bookmark = bookmarks->data;
+
+ if (g_file_equal (file, bookmark->file))
+ {
+ if (position_ret)
+ *position_ret = pos;
+
+ return bookmarks;
+ }
+
+ pos++;
+ }
+
+ if (position_ret)
+ *position_ret = -1;
+
+ return NULL;
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_has_bookmark (NautilusGtkBookmarksManager *manager,
+ GFile *file)
+{
+ GSList *link;
+
+ link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
+ return (link != NULL);
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_insert_bookmark (NautilusGtkBookmarksManager *manager,
+ GFile *file,
+ int position,
+ GError **error)
+{
+ GSList *link;
+ GtkBookmark *bookmark;
+ GFile *bookmarks_file;
+
+ g_return_val_if_fail (manager != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
+
+ if (link)
+ {
+ char *uri;
+ bookmark = link->data;
+ uri = g_file_get_uri (bookmark->file);
+
+ g_set_error (error,
+ GTK_FILE_CHOOSER_ERROR,
+ GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
+ _("%s already exists in the bookmarks list"),
+ uri);
+
+ g_free (uri);
+
+ return FALSE;
+ }
+
+ bookmark = g_slice_new0 (GtkBookmark);
+ bookmark->file = g_object_ref (file);
+
+ manager->bookmarks = g_slist_insert (manager->bookmarks, bookmark, position);
+
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, manager->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ notify_changed (manager);
+
+ return TRUE;
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_remove_bookmark (NautilusGtkBookmarksManager *manager,
+ GFile *file,
+ GError **error)
+{
+ GSList *link;
+ GFile *bookmarks_file;
+
+ g_return_val_if_fail (manager != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ if (!manager->bookmarks)
+ return FALSE;
+
+ link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
+ if (link)
+ {
+ GtkBookmark *bookmark = link->data;
+
+ manager->bookmarks = g_slist_remove_link (manager->bookmarks, link);
+ _gtk_bookmark_free (bookmark);
+ g_slist_free_1 (link);
+ }
+ else
+ {
+ set_error_bookmark_doesnt_exist (file, error);
+ return FALSE;
+ }
+
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, manager->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ notify_changed (manager);
+
+ return TRUE;
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_reorder_bookmark (NautilusGtkBookmarksManager *manager,
+ GFile *file,
+ int new_position,
+ GError **error)
+{
+ GSList *link;
+ GFile *bookmarks_file;
+ int old_position;
+
+ g_return_val_if_fail (manager != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+ g_return_val_if_fail (new_position >= 0, FALSE);
+
+ if (!manager->bookmarks)
+ return FALSE;
+
+ link = find_bookmark_link_for_file (manager->bookmarks, file, &old_position);
+ if (new_position == old_position)
+ return TRUE;
+
+ if (link)
+ {
+ GtkBookmark *bookmark = link->data;
+
+ manager->bookmarks = g_slist_remove_link (manager->bookmarks, link);
+ g_slist_free_1 (link);
+
+ if (new_position > old_position)
+ new_position--;
+
+ manager->bookmarks = g_slist_insert (manager->bookmarks, bookmark, new_position);
+ }
+ else
+ {
+ set_error_bookmark_doesnt_exist (file, error);
+ return FALSE;
+ }
+
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, manager->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ notify_changed (manager);
+
+ return TRUE;
+}
+
+char *
+_nautilus_gtk_bookmarks_manager_get_bookmark_label (NautilusGtkBookmarksManager *manager,
+ GFile *file)
+{
+ GSList *bookmarks;
+ char *label = NULL;
+
+ g_return_val_if_fail (manager != NULL, NULL);
+ g_return_val_if_fail (file != NULL, NULL);
+
+ bookmarks = manager->bookmarks;
+
+ while (bookmarks)
+ {
+ GtkBookmark *bookmark;
+
+ bookmark = bookmarks->data;
+ bookmarks = bookmarks->next;
+
+ if (g_file_equal (file, bookmark->file))
+ {
+ label = g_strdup (bookmark->label);
+ break;
+ }
+ }
+
+ return label;
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_set_bookmark_label (NautilusGtkBookmarksManager *manager,
+ GFile *file,
+ const char *label,
+ GError **error)
+{
+ GFile *bookmarks_file;
+ GSList *link;
+
+ g_return_val_if_fail (manager != NULL, FALSE);
+ g_return_val_if_fail (file != NULL, FALSE);
+
+ link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
+ if (link)
+ {
+ GtkBookmark *bookmark = link->data;
+
+ g_free (bookmark->label);
+ bookmark->label = g_strdup (label);
+ }
+ else
+ {
+ set_error_bookmark_doesnt_exist (file, error);
+ return FALSE;
+ }
+
+ bookmarks_file = get_bookmarks_file ();
+ save_bookmarks (bookmarks_file, manager->bookmarks);
+ g_object_unref (bookmarks_file);
+
+ notify_changed (manager);
+
+ return TRUE;
+}
+
+static gboolean
+_nautilus_gtk_bookmarks_manager_get_xdg_type (NautilusGtkBookmarksManager *manager,
+ GFile *file,
+ GUserDirectory *directory)
+{
+ GSList *link;
+ gboolean match;
+ GFile *location;
+ const char *path;
+ GUserDirectory dir;
+ GtkBookmark *bookmark;
+
+ link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
+ if (!link)
+ return FALSE;
+
+ match = FALSE;
+ bookmark = link->data;
+
+ for (dir = 0; dir < G_USER_N_DIRECTORIES; dir++)
+ {
+ path = g_get_user_special_dir (dir);
+ if (!path)
+ continue;
+
+ location = g_file_new_for_path (path);
+ match = g_file_equal (location, bookmark->file);
+ g_object_unref (location);
+
+ if (match)
+ break;
+ }
+
+ if (match && directory != NULL)
+ *directory = dir;
+
+ return match;
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_get_is_builtin (NautilusGtkBookmarksManager *manager,
+ GFile *file)
+{
+ GUserDirectory xdg_type;
+
+ /* if this is not an XDG dir, it's never builtin */
+ if (!_nautilus_gtk_bookmarks_manager_get_xdg_type (manager, file, &xdg_type))
+ return FALSE;
+
+ /* exclude XDG locations we don't display by default */
+ return _nautilus_gtk_bookmarks_manager_get_is_xdg_dir_builtin (xdg_type);
+}
+
+gboolean
+_nautilus_gtk_bookmarks_manager_get_is_xdg_dir_builtin (GUserDirectory xdg_type)
+{
+ return (xdg_type != G_USER_DIRECTORY_DESKTOP) &&
+ (xdg_type != G_USER_DIRECTORY_TEMPLATES) &&
+ (xdg_type != G_USER_DIRECTORY_PUBLIC_SHARE);
+}