summaryrefslogtreecommitdiffstats
path: root/src/nautilus-starred-directory.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nautilus-starred-directory.c')
-rw-r--r--src/nautilus-starred-directory.c573
1 files changed, 573 insertions, 0 deletions
diff --git a/src/nautilus-starred-directory.c b/src/nautilus-starred-directory.c
new file mode 100644
index 0000000..0fedbfb
--- /dev/null
+++ b/src/nautilus-starred-directory.c
@@ -0,0 +1,573 @@
+/* nautilus-starred-directory.c
+ *
+ * Copyright (C) 2017 Alexandru Pandelea <alexandru.pandelea@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nautilus-starred-directory.h"
+#include "nautilus-tag-manager.h"
+#include "nautilus-file-utilities.h"
+#include "nautilus-directory-private.h"
+#include <glib/gi18n.h>
+
+struct _NautilusFavoriteDirectory
+{
+ NautilusDirectory parent_slot;
+
+ GList *files;
+
+ GList *monitor_list;
+ GList *callback_list;
+ GList *pending_callback_list;
+};
+
+typedef struct
+{
+ gboolean monitor_hidden_files;
+ NautilusFileAttributes monitor_attributes;
+
+ gconstpointer client;
+} FavoriteMonitor;
+
+typedef struct
+{
+ NautilusFavoriteDirectory *starred_directory;
+
+ NautilusDirectoryCallback callback;
+ gpointer callback_data;
+
+ NautilusFileAttributes wait_for_attributes;
+ gboolean wait_for_file_list;
+ GList *file_list;
+} FavoriteCallback;
+
+G_DEFINE_TYPE_WITH_CODE (NautilusFavoriteDirectory, nautilus_starred_directory, NAUTILUS_TYPE_DIRECTORY,
+ nautilus_ensure_extension_points ();
+ /* It looks like you’re implementing an extension point.
+ * Did you modify nautilus_ensure_extension_builtins() accordingly?
+ *
+ * • Yes
+ * • Doing it right now
+ */
+ g_io_extension_point_implement (NAUTILUS_DIRECTORY_PROVIDER_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ NAUTILUS_STARRED_DIRECTORY_PROVIDER_NAME,
+ 0));
+
+static void
+file_changed (NautilusFile *file,
+ NautilusFavoriteDirectory *starred)
+{
+ GList list;
+
+ list.data = file;
+ list.next = NULL;
+
+ nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (starred), &list);
+}
+
+static void
+disconnect_and_unmonitor_file (NautilusFile *file,
+ NautilusFavoriteDirectory *self)
+{
+ /* Disconnect change handler */
+ g_signal_handlers_disconnect_by_func (file, file_changed, self);
+
+ /* Remove monitors */
+ for (GList *m = self->monitor_list; m != NULL; m = m->next)
+ {
+ nautilus_file_monitor_remove (file, m->data);
+ }
+}
+
+static void
+nautilus_starred_directory_update_files (NautilusFavoriteDirectory *self)
+{
+ NautilusTagManager *tag_manager = nautilus_tag_manager_get ();
+ GList *l;
+ GList *tmp_l;
+ GList *new_starred_files;
+ GList *monitor_list;
+ FavoriteMonitor *monitor;
+ NautilusFile *file;
+ GHashTable *uri_table;
+ GList *files_added;
+ GList *files_removed;
+ gchar *uri;
+
+ files_added = NULL;
+ files_removed = NULL;
+
+ uri_table = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ (GDestroyNotify) g_free,
+ NULL);
+
+ for (l = self->files; l != NULL; l = l->next)
+ {
+ g_hash_table_add (uri_table, nautilus_file_get_uri (NAUTILUS_FILE (l->data)));
+ }
+
+ new_starred_files = nautilus_tag_manager_get_starred_files (tag_manager);
+
+ for (l = new_starred_files; l != NULL; l = l->next)
+ {
+ if (!g_hash_table_contains (uri_table, l->data))
+ {
+ file = nautilus_file_get_by_uri ((gchar *) l->data);
+
+ for (monitor_list = self->monitor_list; monitor_list; monitor_list = monitor_list->next)
+ {
+ monitor = monitor_list->data;
+
+ /* Add monitors */
+ nautilus_file_monitor_add (file, monitor, monitor->monitor_attributes);
+ }
+
+ g_signal_connect (file, "changed", G_CALLBACK (file_changed), self);
+
+ files_added = g_list_prepend (files_added, file);
+ }
+ }
+
+ l = self->files;
+ while (l != NULL)
+ {
+ uri = nautilus_file_get_uri (NAUTILUS_FILE (l->data));
+
+ if (!nautilus_tag_manager_file_is_starred (tag_manager, uri))
+ {
+ files_removed = g_list_prepend (files_removed,
+ nautilus_file_ref (NAUTILUS_FILE (l->data)));
+
+ disconnect_and_unmonitor_file (NAUTILUS_FILE (l->data), self);
+
+ if (l == self->files)
+ {
+ self->files = g_list_delete_link (self->files, l);
+ l = self->files;
+ }
+ else
+ {
+ tmp_l = l->prev;
+ self->files = g_list_delete_link (self->files, l);
+ l = tmp_l->next;
+ }
+ }
+ else
+ {
+ l = l->next;
+ }
+
+ g_free (uri);
+ }
+
+ if (files_added)
+ {
+ nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (self), files_added);
+
+ for (l = files_added; l != NULL; l = l->next)
+ {
+ self->files = g_list_prepend (self->files, nautilus_file_ref (NAUTILUS_FILE (l->data)));
+ }
+ }
+
+ if (files_removed)
+ {
+ nautilus_directory_emit_files_changed (NAUTILUS_DIRECTORY (self), files_removed);
+ }
+
+ nautilus_file_list_free (files_added);
+ nautilus_file_list_free (files_removed);
+ g_hash_table_destroy (uri_table);
+}
+
+static void
+on_starred_files_changed (NautilusTagManager *tag_manager,
+ GList *changed_files,
+ gpointer user_data)
+{
+ NautilusFavoriteDirectory *self;
+
+ self = NAUTILUS_STARRED_DIRECTORY (user_data);
+
+ nautilus_starred_directory_update_files (self);
+}
+
+static gboolean
+real_contains_file (NautilusDirectory *directory,
+ NautilusFile *file)
+{
+ g_autofree gchar *uri = NULL;
+
+ uri = nautilus_file_get_uri (file);
+
+ return nautilus_tag_manager_file_is_starred (nautilus_tag_manager_get (), uri);
+}
+
+static gboolean
+real_is_editable (NautilusDirectory *directory)
+{
+ return FALSE;
+}
+
+static void
+real_call_when_ready (NautilusDirectory *directory,
+ NautilusFileAttributes file_attributes,
+ gboolean wait_for_file_list,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ GList *file_list;
+ NautilusFavoriteDirectory *starred;
+
+ starred = NAUTILUS_STARRED_DIRECTORY (directory);
+
+ file_list = nautilus_file_list_copy (starred->files);
+
+ callback (NAUTILUS_DIRECTORY (directory),
+ file_list,
+ callback_data);
+}
+
+static gboolean
+real_are_all_files_seen (NautilusDirectory *directory)
+{
+ return TRUE;
+}
+
+static void
+real_file_monitor_add (NautilusDirectory *directory,
+ gconstpointer client,
+ gboolean monitor_hidden_files,
+ NautilusFileAttributes file_attributes,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ GList *list;
+ FavoriteMonitor *monitor;
+ NautilusFavoriteDirectory *starred;
+ NautilusFile *file;
+
+ starred = NAUTILUS_STARRED_DIRECTORY (directory);
+
+ monitor = g_new0 (FavoriteMonitor, 1);
+ monitor->monitor_hidden_files = monitor_hidden_files;
+ monitor->monitor_attributes = file_attributes;
+ monitor->client = client;
+
+ starred->monitor_list = g_list_prepend (starred->monitor_list, monitor);
+
+ if (callback != NULL)
+ {
+ (*callback)(directory, starred->files, callback_data);
+ }
+
+ for (list = starred->files; list != NULL; list = list->next)
+ {
+ file = list->data;
+
+ /* Add monitors */
+ nautilus_file_monitor_add (file, monitor, file_attributes);
+ }
+}
+
+static void
+starred_monitor_destroy (FavoriteMonitor *monitor,
+ NautilusFavoriteDirectory *starred)
+{
+ GList *l;
+ NautilusFile *file;
+
+ for (l = starred->files; l != NULL; l = l->next)
+ {
+ file = l->data;
+
+ nautilus_file_monitor_remove (file, monitor);
+ }
+
+ g_free (monitor);
+}
+
+static void
+real_monitor_remove (NautilusDirectory *directory,
+ gconstpointer client)
+{
+ NautilusFavoriteDirectory *starred;
+ FavoriteMonitor *monitor;
+ GList *list;
+
+ starred = NAUTILUS_STARRED_DIRECTORY (directory);
+
+ for (list = starred->monitor_list; list != NULL; list = list->next)
+ {
+ monitor = list->data;
+
+ if (monitor->client != client)
+ {
+ continue;
+ }
+
+ starred->monitor_list = g_list_delete_link (starred->monitor_list, list);
+
+ starred_monitor_destroy (monitor, starred);
+
+ break;
+ }
+}
+
+static gboolean
+real_handles_location (GFile *location)
+{
+ g_autofree gchar *uri = NULL;
+
+ uri = g_file_get_uri (location);
+
+ if (eel_uri_is_starred (uri))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static FavoriteCallback *
+starred_callback_find_pending (NautilusFavoriteDirectory *starred,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ FavoriteCallback *starred_callback;
+ GList *list;
+
+ for (list = starred->pending_callback_list; list != NULL; list = list->next)
+ {
+ starred_callback = list->data;
+
+ if (starred_callback->callback == callback &&
+ starred_callback->callback_data == callback_data)
+ {
+ return starred_callback;
+ }
+ }
+
+ return NULL;
+}
+
+static FavoriteCallback *
+starred_callback_find (NautilusFavoriteDirectory *starred,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ FavoriteCallback *starred_callback;
+ GList *list;
+
+ for (list = starred->callback_list; list != NULL; list = list->next)
+ {
+ starred_callback = list->data;
+
+ if (starred_callback->callback == callback &&
+ starred_callback->callback_data == callback_data)
+ {
+ return starred_callback;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+starred_callback_destroy (FavoriteCallback *starred_callback)
+{
+ nautilus_file_list_free (starred_callback->file_list);
+
+ g_free (starred_callback);
+}
+
+static void
+real_cancel_callback (NautilusDirectory *directory,
+ NautilusDirectoryCallback callback,
+ gpointer callback_data)
+{
+ NautilusFavoriteDirectory *starred;
+ FavoriteCallback *starred_callback;
+
+ starred = NAUTILUS_STARRED_DIRECTORY (directory);
+ starred_callback = starred_callback_find (starred, callback, callback_data);
+
+ if (starred_callback)
+ {
+ starred->callback_list = g_list_remove (starred->callback_list, starred_callback);
+
+ starred_callback_destroy (starred_callback);
+
+ return;
+ }
+
+ /* Check for a pending callback */
+ starred_callback = starred_callback_find_pending (starred, callback, callback_data);
+
+ if (starred_callback)
+ {
+ starred->pending_callback_list = g_list_remove (starred->pending_callback_list, starred_callback);
+
+ starred_callback_destroy (starred_callback);
+ }
+}
+
+static GList *
+real_get_file_list (NautilusDirectory *directory)
+{
+ NautilusFavoriteDirectory *starred;
+
+ starred = NAUTILUS_STARRED_DIRECTORY (directory);
+
+ return nautilus_file_list_copy (starred->files);
+}
+
+static void
+nautilus_starred_directory_set_files (NautilusFavoriteDirectory *self)
+{
+ GList *starred_files;
+ NautilusFile *file;
+ GList *l;
+ GList *file_list;
+ FavoriteMonitor *monitor;
+ GList *monitor_list;
+
+ file_list = NULL;
+
+ starred_files = nautilus_tag_manager_get_starred_files (nautilus_tag_manager_get ());
+
+ for (l = starred_files; l != NULL; l = l->next)
+ {
+ file = nautilus_file_get_by_uri ((gchar *) l->data);
+
+ g_signal_connect (file, "changed", G_CALLBACK (file_changed), self);
+
+ for (monitor_list = self->monitor_list; monitor_list; monitor_list = monitor_list->next)
+ {
+ monitor = monitor_list->data;
+
+ /* Add monitors */
+ nautilus_file_monitor_add (file, monitor, monitor->monitor_attributes);
+ }
+
+ file_list = g_list_prepend (file_list, file);
+ }
+
+ nautilus_directory_emit_files_added (NAUTILUS_DIRECTORY (self), file_list);
+
+ self->files = file_list;
+}
+
+static void
+real_force_reload (NautilusDirectory *directory)
+{
+ NautilusFavoriteDirectory *self = NAUTILUS_STARRED_DIRECTORY (directory);
+
+ /* Unset current file list */
+ g_list_foreach (self->files, (GFunc) disconnect_and_unmonitor_file, self);
+ g_clear_list (&self->files, g_object_unref);
+
+ /* Set a fresh file list */
+ nautilus_starred_directory_set_files (self);
+}
+
+static void
+nautilus_starred_directory_finalize (GObject *object)
+{
+ NautilusFavoriteDirectory *self;
+
+ self = NAUTILUS_STARRED_DIRECTORY (object);
+
+ g_signal_handlers_disconnect_by_func (nautilus_tag_manager_get (),
+ on_starred_files_changed,
+ self);
+
+ nautilus_file_list_free (self->files);
+
+ G_OBJECT_CLASS (nautilus_starred_directory_parent_class)->finalize (object);
+}
+
+static void
+nautilus_starred_directory_dispose (GObject *object)
+{
+ NautilusFavoriteDirectory *starred;
+ GList *l;
+
+ starred = NAUTILUS_STARRED_DIRECTORY (object);
+
+ /* Remove file connections */
+ g_list_foreach (starred->files, (GFunc) disconnect_and_unmonitor_file, starred);
+
+ /* Remove search monitors */
+ if (starred->monitor_list)
+ {
+ for (l = starred->monitor_list; l != NULL; l = l->next)
+ {
+ starred_monitor_destroy ((FavoriteMonitor *) l->data, starred);
+ }
+
+ g_list_free (starred->monitor_list);
+ starred->monitor_list = NULL;
+ }
+
+ G_OBJECT_CLASS (nautilus_starred_directory_parent_class)->dispose (object);
+}
+
+static void
+nautilus_starred_directory_class_init (NautilusFavoriteDirectoryClass *klass)
+{
+ GObjectClass *oclass;
+ NautilusDirectoryClass *directory_class;
+
+ oclass = G_OBJECT_CLASS (klass);
+ directory_class = NAUTILUS_DIRECTORY_CLASS (klass);
+
+ oclass->finalize = nautilus_starred_directory_finalize;
+ oclass->dispose = nautilus_starred_directory_dispose;
+
+ directory_class->handles_location = real_handles_location;
+ directory_class->contains_file = real_contains_file;
+ directory_class->is_editable = real_is_editable;
+ directory_class->force_reload = real_force_reload;
+ directory_class->call_when_ready = real_call_when_ready;
+ directory_class->are_all_files_seen = real_are_all_files_seen;
+ directory_class->file_monitor_add = real_file_monitor_add;
+ directory_class->file_monitor_remove = real_monitor_remove;
+ directory_class->cancel_callback = real_cancel_callback;
+ directory_class->get_file_list = real_get_file_list;
+}
+
+NautilusFavoriteDirectory *
+nautilus_starred_directory_new (void)
+{
+ NautilusFavoriteDirectory *self;
+
+ self = g_object_new (NAUTILUS_TYPE_STARRED_DIRECTORY, NULL);
+
+ return self;
+}
+
+static void
+nautilus_starred_directory_init (NautilusFavoriteDirectory *self)
+{
+ g_signal_connect (nautilus_tag_manager_get (),
+ "starred-changed",
+ (GCallback) on_starred_files_changed,
+ self);
+
+ nautilus_starred_directory_set_files (self);
+}