[gnome-photos/wip/rishi/collection: 7/8] source-manager: Track GMounts representing USB storage & PTP devices



commit ec7cd1bd0fd991df66650dd0ee8c37709de4613c
Author: Petr Štětka <stetka peta gmail com>
Date:   Wed Sep 6 09:29:08 2017 +0200

    source-manager: Track GMounts representing USB storage & PTP devices
    
    The GMounts are synchronously enumerated at start-up. However, since
    hot-plugging a USB device generates a flurry of events from
    GVolumeMonitor while the GDaemonMount gets created and then shadowed
    by a new GProxyShadowMount, SourceManager waits for a small period of
    time to let things settle down before updating itself.
    
    Only USB mass storage and PTP devices, represented by the "file" and
    "gphoto2" URI schemes are tracked at the moment.
    
    https://gitlab.gnome.org/GNOME/gnome-photos/issues/29

 src/photos-source-manager.c | 206 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 154 insertions(+), 52 deletions(-)
---
diff --git a/src/photos-source-manager.c b/src/photos-source-manager.c
index ec3428d7..452a0b55 100644
--- a/src/photos-source-manager.c
+++ b/src/photos-source-manager.c
@@ -40,7 +40,9 @@ struct _PhotosSourceManager
   PhotosBaseManager parent_instance;
   GCancellable *cancellable;
   GHashTable *sources_notified;
+  GVolumeMonitor *volume_monitor;
   GoaClient *client;
+  guint refresh_mounts_timeout_id;
 };
 
 enum
@@ -56,6 +58,12 @@ static guint signals[LAST_SIGNAL] = { 0 };
 G_DEFINE_TYPE (PhotosSourceManager, photos_source_manager, PHOTOS_TYPE_BASE_MANAGER);
 
 
+enum
+{
+  REFRESH_MOUNTS_TIMEOUT = 1 /* s */
+};
+
+
 static gchar *
 photos_source_manager_get_filter (PhotosBaseManager *mngr, gint flags)
 {
@@ -128,46 +136,123 @@ photos_source_manager_online_source_needs_notification (PhotosSource *source)
 
 
 static void
-photos_source_manager_refresh_accounts (PhotosSourceManager *self)
+photos_source_manager_notify_sources (PhotosSourceManager *self)
+{
+  guint i;
+  guint n_items;
+
+  n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
+  for (i = 0; i < n_items; i++)
+    {
+      GMount *mount;
+      GoaObject *object;
+      g_autoptr (PhotosSource) source = NULL;
+      gboolean needs_notification;
+      gboolean source_notified;
+      const gchar *id;
+
+      source = PHOTOS_SOURCE (g_list_model_get_object (G_LIST_MODEL (self), i));
+      mount = photos_source_get_mount (source);
+      object = photos_source_get_goa_object (source);
+
+      if (object != NULL)
+        needs_notification = photos_source_manager_online_source_needs_notification (source);
+      else if (mount != NULL)
+        needs_notification = TRUE;
+      else
+        needs_notification = FALSE;
+
+      id = photos_filterable_get_id (PHOTOS_FILTERABLE (source));
+      source_notified = g_hash_table_contains (self->sources_notified, id);
+
+      if (!needs_notification && source_notified)
+        {
+          gboolean removed;
+
+          g_signal_emit (self, signals[NOTIFICATION_HIDE], 0, source);
+          removed = g_hash_table_remove (self->sources_notified, id);
+          g_assert_true (removed);
+        }
+      else if (needs_notification && !source_notified)
+        {
+          gboolean inserted;
+
+          g_signal_emit (self, signals[NOTIFICATION_SHOW], 0, source);
+          inserted = g_hash_table_insert (self->sources_notified, g_strdup (id), g_object_ref (source));
+          g_assert_true (inserted);
+        }
+    }
+}
+
+
+static void
+photos_source_manager_refresh_sources (PhotosSourceManager *self)
 {
   GApplication *app;
   g_autoptr (GHashTable) new_sources = NULL;
-  GList *accounts = NULL;
   GList *l;
+  GList *mounts = NULL;
   PhotosSource *active_source;
   const gchar *active_id;
-  guint i;
-  guint n_items;
 
   app = g_application_get_default ();
   if (photos_application_get_empty_results (PHOTOS_APPLICATION (app)))
     goto out;
 
-  accounts = goa_client_get_accounts (self->client);
   new_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
 
-  for (l = accounts; l != NULL; l = l->next)
+  mounts = g_volume_monitor_get_mounts (self->volume_monitor);
+
+  for (l = mounts; l != NULL; l = l->next)
     {
-      GoaAccount *account;
-      GoaObject *object = GOA_OBJECT (l->data);
+      g_autoptr (GFile) root = NULL;
+      GMount *mount = G_MOUNT (l->data);
       g_autoptr (PhotosSource) source = NULL;
       const gchar *id;
 
-      account = goa_object_peek_account (object);
-      if (account == NULL)
+      if (g_mount_is_shadowed (mount))
         continue;
 
-      if (goa_account_get_photos_disabled (account))
+      root = g_mount_get_root (mount);
+      if (!g_file_has_uri_scheme (root, "file") && !g_file_has_uri_scheme (root, "gphoto2"))
         continue;
 
-      if (goa_object_peek_photos (object) == NULL)
-        continue;
-
-      source = photos_source_new_from_goa_object (GOA_OBJECT (l->data));
+      source = photos_source_new_from_mount (mount);
       id = photos_filterable_get_id (PHOTOS_FILTERABLE (source));
       g_hash_table_insert (new_sources, g_strdup (id), g_object_ref (source));
     }
 
+  if (self->client != NULL)
+    {
+      GList *accounts = NULL;
+
+      accounts = goa_client_get_accounts (self->client);
+
+      for (l = accounts; l != NULL; l = l->next)
+        {
+          GoaAccount *account;
+          GoaObject *object = GOA_OBJECT (l->data);
+          g_autoptr (PhotosSource) source = NULL;
+          const gchar *id;
+
+          account = goa_object_peek_account (object);
+          if (account == NULL)
+            continue;
+
+          if (goa_account_get_photos_disabled (account))
+            continue;
+
+          if (goa_object_peek_photos (object) == NULL)
+            continue;
+
+          source = photos_source_new_from_goa_object (GOA_OBJECT (l->data));
+          id = photos_filterable_get_id (PHOTOS_FILTERABLE (source));
+          g_hash_table_insert (new_sources, g_strdup (id), g_object_ref (source));
+        }
+
+      g_list_free_full (accounts, g_object_unref);
+    }
+
   active_source = PHOTOS_SOURCE (photos_base_manager_get_active_object (PHOTOS_BASE_MANAGER (self)));
   active_id = photos_filterable_get_id (PHOTOS_FILTERABLE (active_source));
   if (!photos_filterable_get_builtin (PHOTOS_FILTERABLE (active_source))
@@ -177,45 +262,41 @@ photos_source_manager_refresh_accounts (PhotosSourceManager *self)
     }
 
   photos_base_manager_process_new_objects (PHOTOS_BASE_MANAGER (self), new_sources);
+  photos_source_manager_notify_sources (self);
 
-  n_items = g_list_model_get_n_items (G_LIST_MODEL (self));
-  for (i = 0; i < n_items; i++)
-    {
-      GoaObject *object;
-      g_autoptr (PhotosSource) source = NULL;
-      gboolean needs_notification;
-      gboolean source_notified;
-      const gchar *id;
-
-      source = PHOTOS_SOURCE (g_list_model_get_object (G_LIST_MODEL (self), i));
-      object = photos_source_get_goa_object (source);
-      if (object == NULL)
-        continue;
+ out:
+  return;
+}
 
-      needs_notification = photos_source_manager_online_source_needs_notification (source);
-      id = photos_filterable_get_id (PHOTOS_FILTERABLE (source));
-      source_notified = g_hash_table_contains (self->sources_notified, id);
 
-      if (!needs_notification && source_notified)
-        {
-          gboolean removed;
+static gboolean
+photos_source_manager_refresh_mounts_timeout (gpointer user_data)
+{
+  PhotosSourceManager *self = PHOTOS_SOURCE_MANAGER (user_data);
 
-          g_signal_emit (self, signals[NOTIFICATION_HIDE], 0, source);
-          removed = g_hash_table_remove (self->sources_notified, id);
-          g_assert_true (removed);
-        }
-      else if (needs_notification && !source_notified)
-        {
-          gboolean inserted;
+  self->refresh_mounts_timeout_id = 0;
+  photos_source_manager_refresh_sources (self);
+  return G_SOURCE_REMOVE;
+}
 
-          g_signal_emit (self, signals[NOTIFICATION_SHOW], 0, source);
-          inserted = g_hash_table_insert (self->sources_notified, g_strdup (id), g_object_ref (source));
-          g_assert_true (inserted);
-        }
+static void
+photos_source_manager_remove_refresh_mounts_timeout (PhotosSourceManager *self)
+{
+  if (self->refresh_mounts_timeout_id != 0)
+    {
+      g_source_remove (self->refresh_mounts_timeout_id);
+      self->refresh_mounts_timeout_id = 0;
     }
+}
 
- out:
-  g_list_free_full (accounts, g_object_unref);
+
+static void
+photos_source_manager_queue_refresh_mounts (PhotosSourceManager *self)
+{
+  photos_source_manager_remove_refresh_mounts_timeout (self);
+  self->refresh_mounts_timeout_id = g_timeout_add_seconds (REFRESH_MOUNTS_TIMEOUT,
+                                                           photos_source_manager_refresh_mounts_timeout,
+                                                           self);
 }
 
 
@@ -245,20 +326,20 @@ photos_source_manager_goa_client (GObject *source_object, GAsyncResult *res, gpo
       self->client = g_object_ref (client);
       g_signal_connect_swapped (self->client,
                                 "account-added",
-                                G_CALLBACK (photos_source_manager_refresh_accounts),
+                                G_CALLBACK (photos_source_manager_refresh_sources),
                                 self);
       g_signal_connect_swapped (self->client,
                                 "account-changed",
-                                G_CALLBACK (photos_source_manager_refresh_accounts),
+                                G_CALLBACK (photos_source_manager_refresh_sources),
                                 self);
       g_signal_connect_swapped (self->client,
                                 "account-removed",
-                                G_CALLBACK (photos_source_manager_refresh_accounts),
+                                G_CALLBACK (photos_source_manager_refresh_sources),
                                 self);
-
-      photos_source_manager_refresh_accounts (self);
     }
 
+  photos_source_manager_refresh_sources (self);
+
  out:
   return;
 }
@@ -269,11 +350,14 @@ photos_source_manager_dispose (GObject *object)
 {
   PhotosSourceManager *self = PHOTOS_SOURCE_MANAGER (object);
 
+  photos_source_manager_remove_refresh_mounts_timeout (self);
+
   if (self->cancellable != NULL)
     g_cancellable_cancel (self->cancellable);
 
   g_clear_object (&self->cancellable);
   g_clear_object (&self->client);
+  g_clear_object (&self->volume_monitor);
   g_clear_pointer (&self->sources_notified, (GDestroyNotify) g_hash_table_unref);
 
   G_OBJECT_CLASS (photos_source_manager_parent_class)->dispose (object);
@@ -294,6 +378,24 @@ photos_source_manager_init (PhotosSourceManager *self)
 
   self->cancellable = g_cancellable_new ();
   self->sources_notified = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+  self->volume_monitor = g_volume_monitor_get ();
+  g_signal_connect_object (self->volume_monitor,
+                           "mount-added",
+                           G_CALLBACK (photos_source_manager_queue_refresh_mounts),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (self->volume_monitor,
+                           "mount-changed",
+                           G_CALLBACK (photos_source_manager_queue_refresh_mounts),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (self->volume_monitor,
+                           "mount-removed",
+                           G_CALLBACK (photos_source_manager_queue_refresh_mounts),
+                           self,
+                           G_CONNECT_SWAPPED);
+
   goa_client_new (self->cancellable, photos_source_manager_goa_client, self);
 
   photos_base_manager_set_active_object_by_id (PHOTOS_BASE_MANAGER (self), PHOTOS_SOURCE_STOCK_ALL);


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