[gvfs] Notify changes in metadata



commit aa9164dc33297b3d15d0408ed22c32d8016e925e
Author: Sergio Costas <raster rastersoft com>
Date:   Sat Mar 28 23:08:05 2020 +0100

    Notify changes in metadata
    
    When a program (like Nautilus) modifies the metadata in a file
    (like metadata::custom-icon) there is no way of detecting that
    change from other programs: neither inotify generates an event
    in the file or the directory holding it, nor is possible to use
    it in the files at, or the folder itself,
    ~/.local/share/gvfs-metadata, because writting in them is delayed
    for nearly a minute.
    
    Unfortunately, there are cases where it is needed to be able
    to detect that. An example (and the reason for this patch) is
    when Nautilus (or another file manager) modifies the custom
    icon in a file from the desktop, and the desktop is managed
    by a different program (in this case, Desktop Icons NG), because
    the later can't detect the change made by the former and, thus,
    the file will keep the old icon until the whole desktop is
    refreshed.
    
    To fix this, this patch proposes to add a signal to the
    org.gtk.vfs.Metadata DBus interface, which will be triggered
    whenever a key is modified. To avoid saturating the system in
    case of modifying a lot of keys, it is triggered up to once
    per second.

 metadata/dbus-interface.xml |  4 ++
 metadata/meta-daemon.c      | 89 +++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 90 insertions(+), 3 deletions(-)
---
diff --git a/metadata/dbus-interface.xml b/metadata/dbus-interface.xml
index 990a95cb..f91d724b 100644
--- a/metadata/dbus-interface.xml
+++ b/metadata/dbus-interface.xml
@@ -45,6 +45,10 @@
       <arg type='u' name='minor' direction='in'/>
       <arg type='s' name='tree' direction='out'/>
     </method>
+    <signal name="AttributeChanged">
+      <arg type='s' name='tree_path'/>
+      <arg type='s' name='file_path'/>
+    </signal>
 
   </interface>
 </node>
diff --git a/metadata/meta-daemon.c b/metadata/meta-daemon.c
index 26edfcb3..15782d20 100644
--- a/metadata/meta-daemon.c
+++ b/metadata/meta-daemon.c
@@ -43,6 +43,7 @@
 
 #define WRITEOUT_TIMEOUT_SECS 60
 #define WRITEOUT_TIMEOUT_SECS_NFS 15
+#define WRITEOUT_TIMEOUT_SECS_DBUS 1
 
 typedef struct {
   char *filename;
@@ -50,11 +51,19 @@ typedef struct {
   guint writeout_timeout;
 } TreeInfo;
 
+typedef struct {
+  gchar *treefile;
+  gchar *path;
+  GVfsMetadata *object;
+  guint timeout_id;
+} BusNotificationInfo;
+
 static GHashTable *tree_infos = NULL;
 static GVfsMetadata *skeleton = NULL;
 #ifdef HAVE_GUDEV
 static GUdevClient *gudev_client = NULL;
 #endif
+static GList *dbus_notification_list = NULL;
 
 static void
 tree_info_free (TreeInfo *info)
@@ -105,8 +114,78 @@ flush_single (const gchar *filename,
 }
 
 static void
-flush_all ()
+free_bus_notification_info (BusNotificationInfo *info)
+{
+  dbus_notification_list = g_list_remove (dbus_notification_list,
+                                          info);
+  g_object_unref (info->object);
+  g_source_remove (info->timeout_id);
+  g_free (info->path);
+  g_free (info->treefile);
+  g_free (info);
+}
+
+static gboolean
+notify_attribute_change (gpointer data)
+{
+  BusNotificationInfo *info;
+
+  info = (BusNotificationInfo *) data;
+  gvfs_metadata_emit_attribute_changed (info->object,
+                                        info->treefile,
+                                        info->path);
+  free_bus_notification_info (info);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+emit_attribute_change (GVfsMetadata *object,
+                       const gchar  *treefile,
+                       const gchar  *path)
+{
+  GList *iter;
+  BusNotificationInfo *info;
+
+  for (iter = dbus_notification_list; iter != NULL; iter = iter->next)
+    {
+      info = iter->data;
+      if (g_str_equal (info->treefile, treefile) &&
+          g_str_equal (info->path, path))
+        {
+          break;
+        }
+    }
+  if (iter == NULL)
+    {
+      info = g_new0 (BusNotificationInfo, 1);
+      info->treefile = g_strdup (treefile);
+      info->path = g_strdup (path);
+      info->object = g_object_ref (object);
+      dbus_notification_list = g_list_prepend (dbus_notification_list,
+                                               info);
+    }
+  else
+    {
+      g_source_remove (info->timeout_id);
+    }
+  info->timeout_id = g_timeout_add_seconds (WRITEOUT_TIMEOUT_SECS_DBUS,
+                                            notify_attribute_change,
+                                            info);
+}
+
+static void
+flush_all (gboolean send_pending_notifications)
 {
+  BusNotificationInfo *info;
+
+  while (dbus_notification_list != NULL)
+    {
+      info = (BusNotificationInfo *) dbus_notification_list->data;
+      if (send_pending_notifications)
+        notify_attribute_change (info);
+      else
+        free_bus_notification_info (info);
+    }
   g_hash_table_foreach (tree_infos, (GHFunc) flush_single, NULL);
 }
 
@@ -222,6 +301,7 @@ handle_set (GVfsMetadata *object,
     }
   else
     {
+      emit_attribute_change (object, arg_treefile, arg_path);
       gvfs_metadata_complete_set (object, invocation);
     }
   
@@ -257,6 +337,7 @@ handle_remove (GVfsMetadata *object,
       return TRUE;
     }
 
+  emit_attribute_change (object, arg_treefile, arg_path);
   tree_info_schedule_writeout (info);
   gvfs_metadata_complete_remove (object, invocation);
   
@@ -297,6 +378,8 @@ handle_move (GVfsMetadata *object,
   /* Remove source if copy succeeded (ignoring errors) */
   meta_tree_remove (info->tree, arg_path);
 
+  emit_attribute_change (object, arg_treefile, arg_path);
+  emit_attribute_change (object, arg_treefile, arg_dest_path);
   tree_info_schedule_writeout (info);
   gvfs_metadata_complete_move (object, invocation);
   
@@ -344,7 +427,7 @@ on_name_lost (GDBusConnection *connection,
   GMainLoop *loop = user_data;
 
   /* means that someone has claimed our name (we allow replacement) */
-  flush_all ();
+  flush_all (TRUE);
   g_main_loop_quit (loop);
 }
 
@@ -357,7 +440,7 @@ on_connection_closed (GDBusConnection *connection,
   GMainLoop *loop = user_data;
 
   /* session bus died */
-  flush_all ();
+  flush_all (FALSE);
   g_main_loop_quit (loop);
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]