[Xfce4-commits] <thunar:nick/on-demand-content-type> Idle load not required mime-types in the background.

Nick Schermer noreply at xfce.org
Sat Nov 17 22:02:01 CET 2012


Updating branch refs/heads/nick/on-demand-content-type
         to 97f0ffcd69771383e79c324176d17815e89b399d (commit)
       from 3ea42fd2e12e7b084ff1c6ae82b18843f10b276c (commit)

commit 97f0ffcd69771383e79c324176d17815e89b399d
Author: Nick Schermer <nick at xfce.org>
Date:   Sat Nov 17 21:55:58 2012 +0100

    Idle load not required mime-types in the background.
    
    This way the window still shows quickly, but the content type
    is still loaded reasonably quick (but pauses during scrolling).

 thunar/thunar-file.c   |   75 ++++++++++++++++++++++++-----------
 thunar/thunar-file.h   |    1 +
 thunar/thunar-folder.c |  102 +++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 144 insertions(+), 34 deletions(-)

diff --git a/thunar/thunar-file.c b/thunar/thunar-file.c
index a110262..3325b30 100644
--- a/thunar/thunar-file.c
+++ b/thunar/thunar-file.c
@@ -118,6 +118,7 @@ static gboolean           thunar_file_same_filesystem          (const ThunarFile
 
 
 G_LOCK_DEFINE_STATIC (file_cache_mutex);
+G_LOCK_DEFINE_STATIC (file_content_type_mutex);
 
 
 
@@ -2237,42 +2238,53 @@ thunar_file_get_content_type (ThunarFile *file)
 
   if (G_UNLIKELY (file->content_type == NULL))
     {
+      G_LOCK (file_content_type_mutex);
+
+      /* make sure we weren't waiting for a lock */
+      if (G_UNLIKELY (file->content_type != NULL))
+        goto bailout;
+
       /* make sure this is not loaded in the general info */
       _thunar_assert (file->info == NULL
           || !g_file_info_has_attribute (file->info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE));
 
-      if (file->kind == G_FILE_TYPE_DIRECTORY)
+      if (G_UNLIKELY (file->kind == G_FILE_TYPE_DIRECTORY))
         {
           /* this we known for sure */
           file->content_type = g_strdup ("inode/directory");
-          return file->content_type;
-        }
-
-      /* async load the content-type */
-      info = g_file_query_info (file->gfile,
-                                THUNARX_FILE_INFO_MIME_NAMESPACE,
-                                G_FILE_QUERY_INFO_NONE,
-                                NULL, &err);
-
-      if (G_LIKELY (info != NULL))
-        {
-          /* store the new content type */
-          content_type = g_file_info_get_content_type (info);
-          if (G_UNLIKELY (content_type != NULL))
-            file->content_type = g_strdup (content_type);
-          g_object_unref (G_OBJECT (info));
         }
       else
         {
-          g_warning ("Content type loading failed for %s: %s",
-                     thunar_file_get_display_name (file),
-                     err->message);
-          g_error_free (err);
+          /* async load the content-type */
+          info = g_file_query_info (file->gfile,
+                                    THUNARX_FILE_INFO_MIME_NAMESPACE,
+                                    G_FILE_QUERY_INFO_NONE,
+                                    NULL, &err);
+
+          if (G_LIKELY (info != NULL))
+            {
+              /* store the new content type */
+              content_type = g_file_info_get_content_type (info);
+              if (G_UNLIKELY (content_type != NULL))
+                file->content_type = g_strdup (content_type);
+              g_object_unref (G_OBJECT (info));
+            }
+          else
+            {
+              g_warning ("Content type loading failed for %s: %s",
+                         thunar_file_get_display_name (file),
+                         err->message);
+              g_error_free (err);
+            }
+
+          /* always provide a fallback */
+          if (file->content_type == NULL)
+            file->content_type = g_strdup ("unknown");
         }
 
-      /* always provide a fallback */
-      if (file->content_type == NULL)
-        file->content_type = g_strdup ("unknown");
+      bailout:
+
+      G_UNLOCK (file_content_type_mutex);
     }
 
   return file->content_type;
@@ -2280,6 +2292,21 @@ thunar_file_get_content_type (ThunarFile *file)
 
 
 
+gboolean
+thunar_file_load_content_type (ThunarFile *file)
+{
+  _thunar_return_val_if_fail (THUNAR_IS_FILE (file), TRUE);
+
+  if (file->content_type != NULL)
+    return FALSE;
+
+  thunar_file_get_content_type (file);
+
+  return TRUE;
+}
+
+
+
 /**
  * thunar_file_get_symlink_target:
  * @file : a #ThunarFile.
diff --git a/thunar/thunar-file.h b/thunar/thunar-file.h
index 05f7f1b..d0a2084 100644
--- a/thunar/thunar-file.h
+++ b/thunar/thunar-file.h
@@ -174,6 +174,7 @@ ThunarGroup      *thunar_file_get_group            (const ThunarFile       *file
 ThunarUser       *thunar_file_get_user             (const ThunarFile       *file);
 
 const gchar      *thunar_file_get_content_type     (ThunarFile             *file);
+gboolean          thunar_file_load_content_type    (ThunarFile             *file);
 const gchar      *thunar_file_get_symlink_target   (const ThunarFile       *file);
 const gchar      *thunar_file_get_basename         (const ThunarFile       *file) G_GNUC_CONST;
 gboolean          thunar_file_is_symlink           (const ThunarFile       *file);
diff --git a/thunar/thunar-folder.c b/thunar/thunar-folder.c
index 3be87ba..3a259bc 100644
--- a/thunar/thunar-folder.c
+++ b/thunar/thunar-folder.c
@@ -110,6 +110,9 @@ struct _ThunarFolder
   GList             *new_files;
   GList             *files;
 
+  GList             *content_type_ptr;
+  guint              content_type_idle_id;
+
   guint              in_destruction : 1;
 
   ThunarFileMonitor *file_monitor;
@@ -299,6 +302,10 @@ thunar_folder_finalize (GObject *object)
       g_object_unref (G_OBJECT (folder->corresponding_file));
     }
 
+  /* stop metadata collector */
+  if (folder->content_type_idle_id != 0)
+    g_source_remove (folder->content_type_idle_id);
+
   /* release references to the new files */
   thunar_g_file_list_free (folder->new_files);
 
@@ -402,6 +409,56 @@ thunar_folder_files_ready (ThunarJob    *job,
 
 
 
+static gboolean
+thunar_folder_content_type_loader_idle (gpointer data)
+{
+  ThunarFolder *folder = THUNAR_FOLDER (data);
+  GList        *lp;
+
+  /* load another files content type */
+  for (lp = folder->content_type_ptr; lp != NULL; lp = lp->next)
+    if (thunar_file_load_content_type (lp->data))
+      {
+        /* if this was the last file, abort */
+        if (G_UNLIKELY (lp->next == NULL))
+          break;
+
+        /* set pointer to next file for the next iteration */
+        folder->content_type_ptr = lp->next;
+
+        return TRUE;
+      }
+
+  /* all content types loaded */
+  return FALSE;
+}
+
+
+
+static void
+thunar_folder_content_type_loader_idle_destroyed (gpointer data)
+{
+  THUNAR_FOLDER (data)->content_type_idle_id = 0;
+}
+
+
+
+static void
+thunar_folder_content_type_loader (ThunarFolder *folder)
+{
+  _thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
+  _thunar_return_if_fail (folder->content_type_idle_id == 0);
+
+  /* set the pointer to the start of the list */
+  folder->content_type_ptr = folder->files;
+
+  /* schedule idle */
+  folder->content_type_idle_id = g_idle_add_full (G_PRIORITY_LOW, thunar_folder_content_type_loader_idle,
+                                                  folder, thunar_folder_content_type_loader_idle_destroyed);
+}
+
+
+
 static void
 thunar_folder_finished (ExoJob       *job,
                         ThunarFolder *folder)
@@ -414,6 +471,7 @@ thunar_folder_finished (ExoJob       *job,
   _thunar_return_if_fail (THUNAR_IS_JOB (job));
   _thunar_return_if_fail (THUNAR_IS_FILE (folder->corresponding_file));
   _thunar_return_if_fail (folder->monitor == NULL);
+  _thunar_return_if_fail (folder->content_type_idle_id == 0);
 
   /* check if we need to merge new files with existing files */
   if (G_UNLIKELY (folder->files != NULL))
@@ -492,6 +550,9 @@ thunar_folder_finished (ExoJob       *job,
   g_object_unref (folder->job);
   folder->job = NULL;
 
+  /* restart the content type idle loader */
+  thunar_folder_content_type_loader (folder);
+
   /* add us to the file alteration monitor */
   folder->monitor = g_file_monitor_directory (thunar_file_get_file (folder->corresponding_file),
                                               G_FILE_MONITOR_NONE, NULL, NULL);
@@ -528,8 +589,9 @@ thunar_folder_file_destroyed (ThunarFileMonitor *file_monitor,
                               ThunarFile        *file,
                               ThunarFolder      *folder)
 {
-  GList  files;
-  GList *lp;
+  GList     files;
+  GList    *lp;
+  gboolean  restart = FALSE;
 
   _thunar_return_if_fail (THUNAR_IS_FILE (file));
   _thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
@@ -548,6 +610,9 @@ thunar_folder_file_destroyed (ThunarFileMonitor *file_monitor,
       lp = g_list_find (folder->files, file);
       if (G_LIKELY (lp != NULL))
         {
+          if (folder->content_type_idle_id != 0)
+            restart = g_source_remove (folder->content_type_idle_id);
+
           /* remove the file from our list */
           folder->files = g_list_delete_link (folder->files, lp);
 
@@ -557,6 +622,10 @@ thunar_folder_file_destroyed (ThunarFileMonitor *file_monitor,
 
           /* drop our reference to the file */
           g_object_unref (G_OBJECT (file));
+
+          /* continue collecting the metadata */
+          if (restart)
+            thunar_folder_content_type_loader (folder);
         }
     }
 }
@@ -631,6 +700,7 @@ thunar_folder_monitor (GFileMonitor     *monitor,
   ThunarFile   *file;
   GList        *lp;
   GList         list;
+  gboolean      restart = FALSE;
 
   _thunar_return_if_fail (G_IS_FILE_MONITOR (monitor));
   _thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
@@ -647,20 +717,24 @@ thunar_folder_monitor (GFileMonitor     *monitor,
         if (g_file_equal (event_file, thunar_file_get_file (lp->data)))
           break;
 
+      /* stop the content type collector */
+      if (folder->content_type_idle_id != 0)
+        restart = g_source_remove (folder->content_type_idle_id);
+
       /* if we don't have it, add it if the event is not an "deleted" event */
       if (G_UNLIKELY (lp == NULL && event_type != G_FILE_MONITOR_EVENT_DELETED))
         {
           /* allocate a file for the path */
           file = thunar_file_get (event_file, NULL);
-          if (G_UNLIKELY (file == NULL))
-            return;
-
-          /* prepend it to our internal list */
-          folder->files = g_list_prepend (folder->files, file);
+          if (G_UNLIKELY (file != NULL))
+            {
+              /* prepend it to our internal list */
+              folder->files = g_list_prepend (folder->files, file);
 
-          /* tell others about the new file */
-          list.data = file; list.next = list.prev = NULL;
-          g_signal_emit (G_OBJECT (folder), folder_signals[FILES_ADDED], 0, &list);
+              /* tell others about the new file */
+              list.data = file; list.next = list.prev = NULL;
+              g_signal_emit (G_OBJECT (folder), folder_signals[FILES_ADDED], 0, &list);
+            }
         }
       else if (lp != NULL)
         {
@@ -675,6 +749,10 @@ thunar_folder_monitor (GFileMonitor     *monitor,
               thunar_file_reload (lp->data);
             }
         }
+
+      /* check if we need to restart the collector */
+      if (restart)
+        thunar_folder_content_type_loader (folder);
     }
   else
     {
@@ -815,6 +893,10 @@ thunar_folder_reload (ThunarFolder *folder)
 {
   _thunar_return_if_fail (THUNAR_IS_FOLDER (folder));
 
+  /* stop metadata collector */
+  if (folder->content_type_idle_id != 0)
+    g_source_remove (folder->content_type_idle_id);
+
   /* check if we are currently connect to a job */
   if (G_UNLIKELY (folder->job != NULL))
     {


More information about the Xfce4-commits mailing list