[gtk/matthiasc/for-master: 39/40] filechooser: Create volume monitor in a thread



commit 2c2d69ad2e1e7505ed5c98d846e3f5fdeb8d5d52
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Feb 4 13:18:46 2020 +0100

    filechooser: Create volume monitor in a thread
    
    The placessidebar, placesview and filesystem code
    all create a volume monitor. No need to block on this,
    we need to handle volumes appearing and disappearing anyway.

 gtk/gtkfilesystem.c    | 55 ++++++++++++++++++++++++++++-------
 gtk/gtkplacessidebar.c | 57 ++++++++++++++++++++++++++++++------
 gtk/gtkplacesview.c    | 79 ++++++++++++++++++++++++++++++++------------------
 gtk/gtkvolumemonitor.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkvolumemonitor.h | 33 +++++++++++++++++++++
 gtk/meson.build        |  1 +
 6 files changed, 251 insertions(+), 48 deletions(-)
---
diff --git a/gtk/gtkfilesystem.c b/gtk/gtkfilesystem.c
index 55cf55b1fc..d30996a87a 100644
--- a/gtk/gtkfilesystem.c
+++ b/gtk/gtkfilesystem.c
@@ -31,6 +31,7 @@
 #include "gtkintl.h"
 #include "gtkprivate.h"
 #include "gtkstylecontextprivate.h"
+#include "gtkvolumemonitor.h"
 
 /* #define DEBUG_MODE */
 #ifdef DEBUG_MODE
@@ -78,6 +79,8 @@ struct GtkFileSystemPrivate
 {
   GVolumeMonitor *volume_monitor;
 
+  GCancellable *init_cancellable;
+
   /* This list contains elements that can be
    * of type GDrive, GVolume and GMount
    */
@@ -129,6 +132,11 @@ gtk_file_system_dispose (GObject *object)
       priv->volume_monitor = NULL;
     }
 
+  if (priv->init_cancellable)
+    g_cancellable_cancel (priv->init_cancellable);
+
+  g_clear_object (&priv->init_cancellable);
+
   G_OBJECT_CLASS (_gtk_file_system_parent_class)->dispose (object);
 }
 
@@ -201,7 +209,10 @@ get_volumes_list (GtkFileSystem *file_system)
     }
 
   /* first go through all connected drives */
-  drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
+  if (priv->volume_monitor)
+    drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
+  else
+    drives = NULL;
 
   for (l = drives; l != NULL; l = l->next)
     {
@@ -259,7 +270,10 @@ get_volumes_list (GtkFileSystem *file_system)
   g_list_free (drives);
 
   /* add all volumes that is not associated with a drive */
-  volumes = g_volume_monitor_get_volumes (priv->volume_monitor);
+  if (priv->volume_monitor)
+    volumes = g_volume_monitor_get_volumes (priv->volume_monitor);
+  else
+    volumes = NULL;
 
   for (l = volumes; l != NULL; l = l->next)
     {
@@ -290,7 +304,10 @@ get_volumes_list (GtkFileSystem *file_system)
     }
 
   /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
-  mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
+  if (priv->volume_monitor)
+    mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
+  else
+    mounts = NULL;
 
   for (l = mounts; l != NULL; l = l->next)
     {
@@ -323,16 +340,19 @@ get_volumes_list (GtkFileSystem *file_system)
 }
 
 static void
-_gtk_file_system_init (GtkFileSystem *file_system)
+got_volume_monitor (GObject *source,
+                    GAsyncResult *result,
+                    gpointer data)
 {
-  GtkFileSystemPrivate *priv;
-
-  DEBUG ("init");
+  GtkFileSystem *file_system = GTK_FILE_SYSTEM (data);
+  GtkFileSystemPrivate *priv = file_system->priv;
+  GTask *task = G_TASK (result);
 
-  file_system->priv = priv = _gtk_file_system_get_instance_private (file_system);
+  priv->volume_monitor = g_task_propagate_pointer (task, NULL);
+  if (!priv->volume_monitor)
+    return;
 
-  /* Volumes */
-  priv->volume_monitor = g_volume_monitor_get ();
+  g_object_ref (priv->volume_monitor);
 
   g_signal_connect (priv->volume_monitor, "mount-added",
                    G_CALLBACK (volumes_changed), file_system);
@@ -354,6 +374,21 @@ _gtk_file_system_init (GtkFileSystem *file_system)
                    G_CALLBACK (volumes_changed), file_system);
 }
 
+static void
+_gtk_file_system_init (GtkFileSystem *file_system)
+{
+  GtkFileSystemPrivate *priv;
+
+  DEBUG ("init");
+
+  file_system->priv = priv = _gtk_file_system_get_instance_private (file_system);
+
+  /* Volumes */
+  priv->init_cancellable = g_cancellable_new ();
+
+  gtk_volume_monitor_get (got_volume_monitor, file_system, priv->init_cancellable);
+}
+
 /* GtkFileSystem public methods */
 GtkFileSystem *
 _gtk_file_system_new (void)
diff --git a/gtk/gtkplacessidebar.c b/gtk/gtkplacessidebar.c
index 4b9a94d375..0f2071b937 100644
--- a/gtk/gtkplacessidebar.c
+++ b/gtk/gtkplacessidebar.c
@@ -67,6 +67,7 @@
 #include "gtkwidgetpaintable.h"
 #include "gtkselectionprivate.h"
 #include "gtkstylecontext.h"
+#include "gtkvolumemonitor.h"
 
 /*< private >
  * SECTION:gtkplacessidebar
@@ -166,6 +167,7 @@ struct _GtkPlacesSidebar {
   /* volume mounting - delayed open process */
   GtkPlacesOpenFlags go_to_after_mount_open_flags;
   GCancellable *cancellable;
+  GCancellable *init_cancellable;
 
   GtkWidget *popover;
   GtkSidebarRow *context_row;
@@ -1162,7 +1164,10 @@ update_places (GtkPlacesSidebar *sidebar)
 #endif
 
   /* go through all connected drives */
-  drives = g_volume_monitor_get_connected_drives (sidebar->volume_monitor);
+  if (sidebar->volume_monitor)
+    drives = g_volume_monitor_get_connected_drives (sidebar->volume_monitor);
+  else
+    drives = NULL;
 
   for (l = drives; l != NULL; l = l->next)
     {
@@ -1270,7 +1275,11 @@ update_places (GtkPlacesSidebar *sidebar)
   /* add all network volumes that are not associated with a drive, and
    * loop devices
    */
-  volumes = g_volume_monitor_get_volumes (sidebar->volume_monitor);
+  if (sidebar->volume_monitor)
+    volumes = g_volume_monitor_get_volumes (sidebar->volume_monitor);
+  else
+    volumes = NULL;
+
   for (l = volumes; l != NULL; l = l->next)
     {
       gboolean is_loop = FALSE;
@@ -1353,7 +1362,10 @@ update_places (GtkPlacesSidebar *sidebar)
     }
 
   /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
-  mounts = g_volume_monitor_get_mounts (sidebar->volume_monitor);
+  if (sidebar->volume_monitor)
+    mounts = g_volume_monitor_get_mounts (sidebar->volume_monitor);
+  else
+    mounts = NULL;
 
   for (l = mounts; l != NULL; l = l->next)
     {
@@ -3968,11 +3980,18 @@ hostname_proxy_new_cb (GObject      *source_object,
 }
 
 static void
-create_volume_monitor (GtkPlacesSidebar *sidebar)
+got_volume_monitor (GObject *source,
+                    GAsyncResult *result,
+                    gpointer data)
 {
-  g_assert (sidebar->volume_monitor == NULL);
+  GtkPlacesSidebar *sidebar = GTK_PLACES_SIDEBAR (data);
+  GTask *task = G_TASK (result);
 
-  sidebar->volume_monitor = g_volume_monitor_get ();
+  sidebar->volume_monitor = g_task_propagate_pointer (task, NULL);
+  if (!sidebar->volume_monitor)
+    return;
+
+  g_object_ref (sidebar->volume_monitor);
 
   g_signal_connect_object (sidebar->volume_monitor, "volume_added",
                            G_CALLBACK (update_places), sidebar, G_CONNECT_SWAPPED);
@@ -3992,6 +4011,20 @@ create_volume_monitor (GtkPlacesSidebar *sidebar)
                            G_CALLBACK (update_places), sidebar, G_CONNECT_SWAPPED);
   g_signal_connect_object (sidebar->volume_monitor, "drive_changed",
                            G_CALLBACK (update_places), sidebar, G_CONNECT_SWAPPED);
+
+  update_places (sidebar);
+}
+
+static void
+create_volume_monitor (GtkPlacesSidebar *sidebar)
+{
+  GTask *task;
+
+  g_assert (sidebar->volume_monitor == NULL);
+
+  sidebar->init_cancellable = g_cancellable_new ();
+  
+  gtk_volume_monitor_get (got_volume_monitor, sidebar, sidebar->init_cancellable);
 }
 
 static void
@@ -4137,10 +4170,9 @@ gtk_places_sidebar_init (GtkPlacesSidebar *sidebar)
                             sidebar);
 #endif
 
-  /* populate the sidebar */
-  update_places (sidebar);
-
   add_actions (sidebar);
+
+  /* we'll populate the sidebar when gtk_volume_manager_get returns in an idle */
 }
 
 static void
@@ -4264,6 +4296,13 @@ gtk_places_sidebar_dispose (GObject *object)
       sidebar->cancellable = NULL;
     }
 
+  if (sidebar->init_cancellable)
+    {
+      g_cancellable_cancel (sidebar->init_cancellable);
+      g_object_unref (sidebar->init_cancellable);
+      sidebar->init_cancellable = NULL;
+    }
+
   free_drag_data (sidebar);
 
   if (sidebar->bookmarks_manager != NULL)
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index c6915d1d55..2d303c344f 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -30,6 +30,7 @@
 #include "gtktypebuiltins.h"
 #include "gtkeventcontrollerkey.h"
 #include "gtkpopovermenu.h"
+#include "gtkvolumemonitor.h"
 
 /*
  * SECTION:gtkplacesview
@@ -86,6 +87,7 @@ struct _GtkPlacesViewPrivate
   GtkListStore                  *completion_store;
 
   GCancellable                  *networks_fetching_cancellable;
+  GCancellable                  *init_cancellable;
 
   GtkPlacesViewRow              *row_for_action;
 
@@ -390,7 +392,8 @@ gtk_places_view_destroy (GtkWidget *widget)
 
   priv->destroyed = 1;
 
-  g_signal_handlers_disconnect_by_func (priv->volume_monitor, update_places, widget);
+  if (priv->volume_monitor)
+    g_signal_handlers_disconnect_by_func (priv->volume_monitor, update_places, widget);
 
   if (priv->network_monitor)
     g_signal_handlers_disconnect_by_func (priv->network_monitor, update_places, widget);
@@ -400,6 +403,7 @@ gtk_places_view_destroy (GtkWidget *widget)
 
   g_cancellable_cancel (priv->cancellable);
   g_cancellable_cancel (priv->networks_fetching_cancellable);
+  g_cancellable_cancel (priv->init_cancellable);
 
   g_clear_pointer (&priv->server_adresses_popover, gtk_widget_unparent);
 
@@ -424,6 +428,7 @@ gtk_places_view_finalize (GObject *object)
   g_clear_object (&priv->networks_fetching_cancellable);
   g_clear_object (&priv->path_size_group);
   g_clear_object (&priv->space_size_group);
+  g_clear_object (&priv->init_cancellable);
 
   G_OBJECT_CLASS (gtk_places_view_parent_class)->finalize (object);
 }
@@ -1127,7 +1132,10 @@ update_places (GtkPlacesView *view)
   g_clear_object (&icon);
 
   /* Add currently connected drives */
-  drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
+  if ( priv->volume_monitor)
+    drives = g_volume_monitor_get_connected_drives (priv->volume_monitor);
+  else
+    drives = NULL;
 
   for (l = drives; l != NULL; l = l->next)
     add_drive (view, l->data);
@@ -1139,7 +1147,10 @@ update_places (GtkPlacesView *view)
    * add_drive before, add all volumes that aren't associated with a
    * drive.
    */
-  volumes = g_volume_monitor_get_volumes (priv->volume_monitor);
+  if (priv->volume_monitor)
+    volumes = g_volume_monitor_get_volumes (priv->volume_monitor);
+  else
+    volumes = NULL;
 
   for (l = volumes; l != NULL; l = l->next)
     {
@@ -1164,7 +1175,10 @@ update_places (GtkPlacesView *view)
    * Now that all necessary drives and volumes were already added, add mounts
    * that have no volume, such as /etc/mtab mounts, ftp, sftp, etc.
    */
-  mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
+  if (priv->volume_monitor)
+    mounts = g_volume_monitor_get_mounts (priv->volume_monitor);
+  else
+    mounts = NULL;
 
   for (l = mounts; l != NULL; l = l->next)
     {
@@ -2199,30 +2213,6 @@ gtk_places_view_constructed (GObject *object)
   /* load drives */
   update_places (GTK_PLACES_VIEW (object));
 
-  g_signal_connect_swapped (priv->volume_monitor,
-                            "mount-added",
-                            G_CALLBACK (update_places),
-                            object);
-  g_signal_connect_swapped (priv->volume_monitor,
-                            "mount-changed",
-                            G_CALLBACK (update_places),
-                            object);
-  g_signal_connect_swapped (priv->volume_monitor,
-                            "mount-removed",
-                            G_CALLBACK (update_places),
-                            object);
-  g_signal_connect_swapped (priv->volume_monitor,
-                            "volume-added",
-                            G_CALLBACK (update_places),
-                            object);
-  g_signal_connect_swapped (priv->volume_monitor,
-                            "volume-changed",
-                            G_CALLBACK (update_places),
-                            object);
-  g_signal_connect_swapped (priv->volume_monitor,
-                            "volume-removed",
-                            G_CALLBACK (update_places),
-                            object);
 }
 
 static void
@@ -2364,6 +2354,35 @@ gtk_places_view_class_init (GtkPlacesViewClass *klass)
   gtk_widget_class_set_css_name (widget_class, I_("placesview"));
 }
 
+static void
+got_volume_monitor (GObject *source,
+                    GAsyncResult *result,
+                    gpointer data)
+{
+  GtkPlacesView *self = GTK_PLACES_VIEW (data);
+  GtkPlacesViewPrivate *priv = gtk_places_view_get_instance_private (self);
+  GTask *task = G_TASK (result);
+
+  priv->volume_monitor = g_task_propagate_pointer (task, NULL);
+  if (!priv->volume_monitor)
+    return;
+
+  g_object_ref (priv->volume_monitor);
+
+  g_signal_connect_swapped (priv->volume_monitor, "mount-added",
+                            G_CALLBACK (update_places), self);
+  g_signal_connect_swapped (priv->volume_monitor, "mount-changed",
+                            G_CALLBACK (update_places), self);
+  g_signal_connect_swapped (priv->volume_monitor, "mount-removed",
+                            G_CALLBACK (update_places), self);
+  g_signal_connect_swapped (priv->volume_monitor, "volume-added",
+                            G_CALLBACK (update_places), self);
+  g_signal_connect_swapped (priv->volume_monitor, "volume-changed",
+                            G_CALLBACK (update_places), self);
+  g_signal_connect_swapped (priv->volume_monitor, "volume-removed",
+                            G_CALLBACK (update_places), self);
+}
+
 static void
 gtk_places_view_init (GtkPlacesView *self)
 {
@@ -2372,7 +2391,9 @@ gtk_places_view_init (GtkPlacesView *self)
 
   priv = gtk_places_view_get_instance_private (self);
 
-  priv->volume_monitor = g_volume_monitor_get ();
+  priv->init_cancellable = g_cancellable_new ();
+  gtk_volume_monitor_get (got_volume_monitor, self, priv->init_cancellable);
+
   priv->open_flags = GTK_PLACES_OPEN_NORMAL;
   priv->path_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
   priv->space_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
diff --git a/gtk/gtkvolumemonitor.c b/gtk/gtkvolumemonitor.c
new file mode 100644
index 0000000000..b51b3f7f2d
--- /dev/null
+++ b/gtk/gtkvolumemonitor.c
@@ -0,0 +1,74 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2020 Red Hat, Inc
+ *
+ * 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: Matthias Clasen
+ */
+
+#include "config.h"
+
+#include "gtkvolumemonitor.h"
+
+static GVolumeMonitor *the_volume_monitor;
+static GList *pending_tasks;
+
+static void
+get_volume_monitor_thread (GTask        *running_task,
+                           gpointer      source_object,
+                           gpointer      task_data,
+                           GCancellable *cancellable)
+{
+  GList *l;
+
+  the_volume_monitor = g_volume_monitor_get ();
+
+  g_object_add_weak_pointer (G_OBJECT (the_volume_monitor), (gpointer *)&the_volume_monitor);
+
+  for (l = pending_tasks; l; l = l->next)
+    {
+      GTask *task = l->data;
+
+      if (!g_task_return_error_if_cancelled (task))
+        g_task_return_pointer (task, g_object_ref (the_volume_monitor), g_object_unref);
+    }
+
+  g_list_free_full (pending_tasks, g_object_unref);
+  pending_tasks = NULL;
+
+  g_object_unref (the_volume_monitor);
+}
+
+void
+gtk_volume_monitor_get (GAsyncReadyCallback  callback,
+                        gpointer             data,
+                        GCancellable        *cancellable)
+{
+  GTask *task;
+
+  task = g_task_new (NULL, cancellable, callback, data);
+  g_task_set_return_on_cancel (task, TRUE);
+
+  if (the_volume_monitor)
+    {
+      g_task_return_pointer (task, g_object_ref (the_volume_monitor), g_object_unref);
+      g_object_unref (task);
+    }
+  else
+    {
+      pending_tasks = g_list_prepend (pending_tasks, task);
+      if (pending_tasks->next == NULL)
+        g_task_run_in_thread (task, get_volume_monitor_thread);
+    }
+}
diff --git a/gtk/gtkvolumemonitor.h b/gtk/gtkvolumemonitor.h
new file mode 100644
index 0000000000..06ef3fd6ec
--- /dev/null
+++ b/gtk/gtkvolumemonitor.h
@@ -0,0 +1,33 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2020 Red Hat, Inc
+ *
+ * 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: Matthias Clasen
+ */
+
+#ifndef __GTK_VOLUME_MONITOR_H__
+#define __GTK_VOLUME_MONITOR_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+void gtk_volume_monitor_get (GAsyncReadyCallback  callback,
+                             gpointer             data,
+                             GCancellable        *cancellable);
+
+G_END_DECLS
+
+#endif /* __GTK_VOLUME_MONITOR_H__ */
diff --git a/gtk/meson.build b/gtk/meson.build
index 17156b001a..8bde15bd5d 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -392,6 +392,7 @@ gtk_public_sources = files([
   'gtkvideo.c',
   'gtkviewport.c',
   'gtkvolumebutton.c',
+  'gtkvolumemonitor.c',
   'gtkwidget.c',
   'gtkwidgetfocus.c',
   'gtkwidgetpaintable.c',


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