[9ae8f17cfc8ba7fd8fb34b2a194ef965a3b36a40839a46eeab1350e916692ac9/directorylist-monitor] directorylist: Add monitoring
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [9ae8f17cfc8ba7fd8fb34b2a194ef965a3b36a40839a46eeab1350e916692ac9/directorylist-monitor] directorylist: Add monitoring
- Date: Wed, 8 Jul 2020 01:17:56 +0000 (UTC)
commit 504ad848b42f185de54de50b6d551f80ca183b30
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Jul 7 18:44:41 2020 -0400
directorylist: Add monitoring
Add a GtkDirectoryList:monitored property, and
keep a file monitor if it is set to TRUE. To ensure
that the list reflects reality, we reload the directory
when monitoring is turned on after the fact. This means
that turning monitoring is expensive, while turning it
off is cheap, so we default to monitoring being on.
docs/reference/gtk/gtk4-sections.txt | 2 +
gtk/gtkdirectorylist.c | 231 ++++++++++++++++++++++++++++++++++-
gtk/gtkdirectorylist.h | 6 +
3 files changed, 235 insertions(+), 4 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 80809369b4..e5b667cf43 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -1444,6 +1444,8 @@ gtk_directory_list_get_file
gtk_directory_list_set_file
gtk_directory_list_get_io_priority
gtk_directory_list_set_io_priority
+gtk_directory_list_get_monitored
+gtk_directory_list_set_monitored
gtk_directory_list_is_loading
gtk_directory_list_get_error
<SUBSECTION Standard>
diff --git a/gtk/gtkdirectorylist.c b/gtk/gtkdirectorylist.c
index 053305b674..ecb20c94b9 100644
--- a/gtk/gtkdirectorylist.c
+++ b/gtk/gtkdirectorylist.c
@@ -62,6 +62,7 @@ enum {
PROP_IO_PRIORITY,
PROP_ITEM_TYPE,
PROP_LOADING,
+ PROP_MONITORED,
NUM_PROPERTIES
};
@@ -70,8 +71,10 @@ struct _GtkDirectoryList
GObject parent_instance;
char *attributes;
- int io_priority;
GFile *file;
+ GFileMonitor *monitor;
+ gboolean monitored;
+ int io_priority;
GCancellable *cancellable;
GError *error; /* Error while loading */
@@ -147,13 +150,17 @@ gtk_directory_list_set_property (GObject *object,
gtk_directory_list_set_io_priority (self, g_value_get_int (value));
break;
+ case PROP_MONITORED:
+ gtk_directory_list_set_monitored (self, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
-static void
+static void
gtk_directory_list_get_property (GObject *object,
guint prop_id,
GValue *value,
@@ -187,6 +194,10 @@ gtk_directory_list_get_property (GObject *object,
g_value_set_boolean (value, gtk_directory_list_is_loading (self));
break;
+ case PROP_MONITORED:
+ g_value_set_boolean (value, gtk_directory_list_get_monitored (self));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -204,12 +215,27 @@ gtk_directory_list_stop_loading (GtkDirectoryList *self)
return TRUE;
}
+static void directory_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer data);
+
+static void
+gtk_directory_list_stop_monitoring (GtkDirectoryList *self)
+{
+ if (self->monitor)
+ g_signal_handlers_disconnect_by_func (self->monitor, directory_changed, self);
+ g_clear_object (&self->monitor);
+}
+
static void
gtk_directory_list_dispose (GObject *object)
{
GtkDirectoryList *self = GTK_DIRECTORY_LIST (object);
gtk_directory_list_stop_loading (self);
+ gtk_directory_list_stop_monitoring (self);
g_clear_object (&self->file);
g_clear_pointer (&self->attributes, g_free);
@@ -301,6 +327,18 @@ gtk_directory_list_class_init (GtkDirectoryListClass *class)
FALSE,
GTK_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
+ /**
+ * GtkDirectoryList:monitored:
+ *
+ * %TRUE if the directory is monitored for changed
+ */
+ properties[PROP_MONITORED] =
+ g_param_spec_boolean ("monitored",
+ P_("monitored"),
+ P_("TRUE if the directory is monitored for changes"),
+ TRUE,
+ GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
}
@@ -309,6 +347,7 @@ gtk_directory_list_init (GtkDirectoryList *self)
{
self->items = g_sequence_new (g_object_unref);
self->io_priority = G_PRIORITY_DEFAULT;
+ self->monitored = TRUE;
}
/**
@@ -324,7 +363,6 @@ gtk_directory_list_init (GtkDirectoryList *self)
GtkDirectoryList *
gtk_directory_list_new (const char *attributes,
GFile *file)
-
{
g_return_val_if_fail (file == NULL || G_IS_FILE (file), NULL);
@@ -410,7 +448,7 @@ gtk_directory_list_got_files_cb (GObject *source,
{
GFileInfo *info;
GFile *file;
-
+
info = l->data;
file = g_file_enumerator_get_child (enumerator, info);
g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
@@ -496,6 +534,141 @@ gtk_directory_list_start_loading (GtkDirectoryList *self)
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_LOADING]);
}
+static void
+got_new_file_info_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GFile *file = G_FILE (source);
+ GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
+ GFileInfo *info;
+ guint position;
+
+ info = g_file_query_info_finish (file, res, NULL);
+ if (!info)
+ return;
+
+ g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
+ position = g_sequence_get_length (self->items);
+ g_sequence_append (self->items, info);
+ g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
+}
+
+static void
+got_existing_file_info_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer data)
+{
+ GFile *file = G_FILE (source);
+ GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
+ GFileInfo *info;
+ GSequenceIter *iter;
+
+ info = g_file_query_info_finish (file, res, NULL);
+ if (!info)
+ return;
+
+ g_file_info_set_attribute_object (info, "standard::file", G_OBJECT (file));
+
+ iter = g_sequence_get_begin_iter (self->items);
+ while (!g_sequence_iter_is_end (iter))
+ {
+ GFileInfo *item = g_sequence_get (iter);
+ GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
+ if (g_file_equal (f, file))
+ {
+ guint position = g_sequence_iter_get_position (iter);
+ g_sequence_set (iter, g_object_ref (info));
+ g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 1);
+ break;
+ }
+ }
+}
+
+static void
+gtk_directory_list_remove_file (GtkDirectoryList *self,
+ GFile *file)
+{
+ GSequenceIter *iter;
+
+ iter = g_sequence_get_begin_iter (self->items);
+ while (!g_sequence_iter_is_end (iter))
+ {
+ GFileInfo *item = g_sequence_get (iter);
+ GFile *f = G_FILE (g_file_info_get_attribute_object (item, "standard::file"));
+ if (g_file_equal (f, file))
+ {
+ guint position = g_sequence_iter_get_position (iter);
+ g_sequence_remove (iter);
+ g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0);
+ break;
+ }
+ }
+}
+
+static void
+directory_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer data)
+{
+ GtkDirectoryList *self = GTK_DIRECTORY_LIST (data);
+ switch (event)
+ {
+ case G_FILE_MONITOR_EVENT_CREATED:
+ g_file_query_info_async (file,
+ self->attributes,
+ G_FILE_QUERY_INFO_NONE,
+ self->io_priority,
+ self->cancellable,
+ got_new_file_info_cb,
+ self);
+ break;
+
+ case G_FILE_MONITOR_EVENT_DELETED:
+ gtk_directory_list_remove_file (self, file);
+ break;
+
+ case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+ g_file_query_info_async (file,
+ self->attributes,
+ G_FILE_QUERY_INFO_NONE,
+ self->io_priority,
+ self->cancellable,
+ got_existing_file_info_cb,
+ self);
+ break;
+
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ 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:
+ break;
+ }
+}
+
+static void
+gtk_directory_list_start_monitoring (GtkDirectoryList *self)
+{
+ g_assert (self->monitor == NULL);
+ self->monitor = g_file_monitor_directory (self->file, G_FILE_MONITOR_NONE, NULL, NULL);
+ g_signal_connect (self->monitor, "changed", G_CALLBACK (directory_changed), self);
+}
+
+static void
+gtk_directory_list_update_monitoring (GtkDirectoryList *self)
+{
+ gtk_directory_list_stop_monitoring (self);
+ if (self->file && self->monitored)
+ gtk_directory_list_start_monitoring (self);
+}
+
/**
* gtk_directory_list_set_file:
* @self: a #GtkDirectoryList
@@ -521,6 +694,7 @@ gtk_directory_list_set_file (GtkDirectoryList *self,
g_set_object (&self->file, file);
gtk_directory_list_start_loading (self);
+ gtk_directory_list_update_monitoring (self);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FILE]);
@@ -679,3 +853,52 @@ gtk_directory_list_get_error (GtkDirectoryList *self)
return self->error;
}
+/**
+ * gtk_directory_list_set_monitored:
+ * @self: a #GtkDirectoryList
+ * @monitor: %TRUE to monitor the directory for changes
+ *
+ * Sets whether the directory list will monitor the directory
+ * for changes.
+ *
+ * If %TRUE, the #GListModel::items-changed signal will be
+ * emitted when the directory contents change.
+ */
+void
+gtk_directory_list_set_monitored (GtkDirectoryList *self,
+ gboolean monitored)
+{
+ g_return_if_fail (GTK_IS_DIRECTORY_LIST (self));
+
+ if (self->monitored == monitored)
+ return;
+
+ self->monitored = monitored;
+
+ /* When turning monitoring on, start over so we don't
+ * miss any files that appeared between the initial
+ * loading and when monitoring was turned on.
+ */
+ if (monitored)
+ gtk_directory_list_start_loading (self);
+ gtk_directory_list_update_monitoring (self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MONITORED]);
+}
+
+/**
+ * gtk_directory_list_get_monitored:
+ * @self: a #GtkDirectoryList
+ *
+ * Returns whether the directory list is monitoring
+ * the directory for changes.
+ *
+ * Returns: %TRUE if the directory is monitored
+ */
+gboolean
+gtk_directory_list_get_monitored (GtkDirectoryList *self)
+{
+ g_return_val_if_fail (GTK_IS_DIRECTORY_LIST (self), TRUE);
+
+ return self->monitored;
+}
diff --git a/gtk/gtkdirectorylist.h b/gtk/gtkdirectorylist.h
index 0952224c40..a41b4928af 100644
--- a/gtk/gtkdirectorylist.h
+++ b/gtk/gtkdirectorylist.h
@@ -62,6 +62,12 @@ gboolean gtk_directory_list_is_loading (GtkDirectoryLis
GDK_AVAILABLE_IN_ALL
const GError * gtk_directory_list_get_error (GtkDirectoryList *self);
+GDK_AVAILABLE_IN_ALL
+void gtk_directory_list_set_monitored (GtkDirectoryList *self,
+ gboolean monitored);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_directory_list_get_monitored (GtkDirectoryList *self);
+
G_END_DECLS
#endif /* __GTK_DIRECTORY_LIST_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]