[gnome-builder] device-provider: implement new IdeDeviceProvider API



commit 981436abfd23817843ae22ebe3ab775c7d68d4a5
Author: Christian Hergert <chergert redhat com>
Date:   Thu Feb 22 14:41:43 2018 -0800

    device-provider: implement new IdeDeviceProvider API
    
    This moves to using a base object like we now do elsewhere instead of an
    interface (which we did because of libpeas requirements early on which are
    no longer an issue).
    
    It also drops the "settled" design in favor of an easier to manage load
    async/finish pair.

 src/libide/devices/ide-device-provider.c | 278 +++++++++++++++++++++++++------
 src/libide/devices/ide-device-provider.h |  42 +++--
 2 files changed, 258 insertions(+), 62 deletions(-)
---
diff --git a/src/libide/devices/ide-device-provider.c b/src/libide/devices/ide-device-provider.c
index 33d076cce..0abe19c0e 100644
--- a/src/libide/devices/ide-device-provider.c
+++ b/src/libide/devices/ide-device-provider.c
@@ -16,88 +16,169 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <glib/gi18n.h>
+#define G_LOG_DOMAIN "ide-device-provider"
 
-#include "ide-context.h"
 #include "devices/ide-device-provider.h"
 
-G_DEFINE_INTERFACE (IdeDeviceProvider, ide_device_provider, IDE_TYPE_OBJECT)
+typedef struct
+{
+  GPtrArray *devices;
+} IdeDeviceProviderPrivate;
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (IdeDeviceProvider, ide_device_provider, IDE_TYPE_OBJECT)
 
 enum {
   DEVICE_ADDED,
   DEVICE_REMOVED,
-  LAST_SIGNAL
+  N_SIGNALS
 };
 
-static guint signals [LAST_SIGNAL];
+static guint signals [N_SIGNALS];
+
+static void
+ide_device_provider_real_load_async (IdeDeviceProvider   *self,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
+{
+  g_task_report_new_error (self, callback, user_data,
+                           ide_device_provider_real_load_async,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "%s does not implement load_async",
+                           G_OBJECT_TYPE_NAME (self));
+}
 
-static GPtrArray *
-default_get_devices (IdeDeviceProvider *self)
+static gboolean
+ide_device_provider_real_load_finish (IdeDeviceProvider  *self,
+                                      GAsyncResult       *result,
+                                      GError            **error)
+{
+  return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+ide_device_provider_real_device_added (IdeDeviceProvider *self,
+                                       IdeDevice         *device)
 {
-  return g_ptr_array_new_with_free_func (g_object_unref);
+  IdeDeviceProviderPrivate *priv = ide_device_provider_get_instance_private (self);
+
+  g_assert (IDE_IS_DEVICE_PROVIDER (self));
+  g_assert (IDE_IS_DEVICE (device));
+
+  if (priv->devices == NULL)
+    priv->devices = g_ptr_array_new_with_free_func (g_object_unref);
+  g_ptr_array_add (priv->devices, g_object_ref (device));
+}
+
+static void
+ide_device_provider_real_device_removed (IdeDeviceProvider *self,
+                                         IdeDevice         *device)
+{
+  IdeDeviceProviderPrivate *priv = ide_device_provider_get_instance_private (self);
+
+  g_assert (IDE_IS_DEVICE_PROVIDER (self));
+  g_assert (IDE_IS_DEVICE (device));
+
+  /* Maybe we just disposed */
+  if (priv->devices == NULL)
+    return;
+
+  if (!g_ptr_array_remove (priv->devices, device))
+    g_warning ("No such device \"%s\" found in \"%s\"",
+               G_OBJECT_TYPE_NAME (device),
+               G_OBJECT_TYPE_NAME (self));
 }
 
 static void
-ide_device_provider_default_init (IdeDeviceProviderInterface *iface)
+ide_device_provider_dispose (GObject *object)
 {
-  iface->get_devices = default_get_devices;
+  IdeDeviceProvider *self = (IdeDeviceProvider *)object;
+  IdeDeviceProviderPrivate *priv = ide_device_provider_get_instance_private (self);
 
-  g_object_interface_install_property (iface,
-                                       g_param_spec_boolean ("settled",
-                                                             "Settled",
-                                                             "If the device provider has settled",
-                                                             FALSE,
-                                                             (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)));
+  g_clear_pointer (&priv->devices, g_ptr_array_unref);
 
+  G_OBJECT_CLASS (ide_device_provider_parent_class)->dispose (object);
+}
+
+static void
+ide_device_provider_class_init (IdeDeviceProviderClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_device_provider_dispose;
+
+  klass->device_added = ide_device_provider_real_device_added;
+  klass->device_removed = ide_device_provider_real_device_removed;
+  klass->load_async = ide_device_provider_real_load_async;
+  klass->load_finish = ide_device_provider_real_load_finish;
+
+  /**
+   * IdeDeviceProvider::device-added:
+   * @self: an #IdeDeviceProvider
+   * @device: an #IdeDevice
+   *
+   * The "device-added" signal is emitted when a provider has discovered
+   * a device has become available.
+   *
+   * Subclasses of #IdeDeviceManager must chain-up if they override the
+   * #IdeDeviceProviderClass.device_added vfunc.
+   *
+   * Since: 3.28
+   */
   signals [DEVICE_ADDED] =
     g_signal_new ("device-added",
-                  IDE_TYPE_DEVICE_PROVIDER,
+                  G_TYPE_FROM_CLASS (klass),
                   G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL, NULL,
-                  G_TYPE_NONE,
-                  1,
-                  IDE_TYPE_DEVICE);
+                  G_STRUCT_OFFSET (IdeDeviceProviderClass, device_added),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, IDE_TYPE_DEVICE);
+  g_signal_set_va_marshaller (signals [DEVICE_ADDED],
+                              G_TYPE_FROM_CLASS (klass),
+                              g_cclosure_marshal_VOID__OBJECTv);
 
+  /**
+   * IdeDeviceProvider::device-removed:
+   * @self: an #IdeDeviceProvider
+   * @device: an #IdeDevice
+   *
+   * The "device-removed" signal is emitted when a provider has discovered
+   * a device is no longer available.
+   *
+   * Subclasses of #IdeDeviceManager must chain-up if they override the
+   * #IdeDeviceProviderClass.device_removed vfunc.
+   *
+   * Since: 3.28
+   */
   signals [DEVICE_REMOVED] =
     g_signal_new ("device-removed",
-                  IDE_TYPE_DEVICE_PROVIDER,
+                  G_TYPE_FROM_CLASS (klass),
                   G_SIGNAL_RUN_LAST,
-                  0,
-                  NULL, NULL, NULL,
-                  G_TYPE_NONE,
-                  1,
-                  IDE_TYPE_DEVICE);
+                  G_STRUCT_OFFSET (IdeDeviceProviderClass, device_removed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, IDE_TYPE_DEVICE);
+  g_signal_set_va_marshaller (signals [DEVICE_REMOVED],
+                              G_TYPE_FROM_CLASS (klass),
+                              g_cclosure_marshal_VOID__OBJECTv);
 }
 
-gboolean
-ide_device_provider_get_settled (IdeDeviceProvider *provider)
+static void
+ide_device_provider_init (IdeDeviceProvider *self)
 {
-  gboolean settled = FALSE;
-
-  g_return_val_if_fail (IDE_IS_DEVICE_PROVIDER (provider), FALSE);
-
-  g_object_get (provider, "settled", &settled, NULL);
-
-  return settled;
 }
 
 /**
- * ide_device_provider_get_devices:
+ * ide_device_provider_emit_device_added:
  *
- * Retrieves a list of devices currently managed by @provider.
+ * Emits the #IdeDeviceProvider::device-added signal.
  *
- * Returns: (transfer container) (element-type Ide.Device): a #GPtrArray of
- *  #IdeDevice instances.
+ * This should only be called by subclasses of #IdeDeviceProvider when
+ * a new device has been discovered.
+ *
+ * Since: 3.28
  */
-GPtrArray *
-ide_device_provider_get_devices (IdeDeviceProvider *provider)
-{
-  g_return_val_if_fail (IDE_IS_DEVICE_PROVIDER (provider), NULL);
-
-  return IDE_DEVICE_PROVIDER_GET_IFACE (provider)->get_devices (provider);
-}
-
 void
 ide_device_provider_emit_device_added (IdeDeviceProvider *provider,
                                        IdeDevice         *device)
@@ -108,6 +189,16 @@ ide_device_provider_emit_device_added (IdeDeviceProvider *provider,
   g_signal_emit (provider, signals [DEVICE_ADDED], 0, device);
 }
 
+/**
+ * ide_device_provider_emit_device_removed:
+ *
+ * Emits the #IdeDeviceProvider::device-removed signal.
+ *
+ * This should only be called by subclasses of #IdeDeviceProvider when
+ * a previously added device has been removed.
+ *
+ * Since: 3.28
+ */
 void
 ide_device_provider_emit_device_removed (IdeDeviceProvider *provider,
                                          IdeDevice         *device)
@@ -117,3 +208,92 @@ ide_device_provider_emit_device_removed (IdeDeviceProvider *provider,
 
   g_signal_emit (provider, signals [DEVICE_REMOVED], 0, device);
 }
+
+/**
+ * ide_device_provider_load_async:
+ * @self: an #IdeDeviceProvider
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (nullable): a #GAsyncReadyCallback to execute upon completion
+ * @user_data: closure data for @callback
+ *
+ * Requests that the #IdeDeviceProvider asynchronously load any known devices.
+ *
+ * This should only be called once on an #IdeDeviceProvider. It is an error
+ * to call this function more than once for a single #IdeDeviceProvider.
+ *
+ * #IdeDeviceProvider implementations are expected to emit the
+ * #IdeDeviceProvider::device-added signal for each device they've discovered.
+ * That should be done for known devices before returning from the asynchronous
+ * operation so that the device manager does not need to wait for additional
+ * devices to enter the "settled" state.
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ *
+ * Since: 3.28
+ */
+void
+ide_device_provider_load_async (IdeDeviceProvider   *self,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+  g_return_if_fail (IDE_IS_DEVICE_PROVIDER (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  IDE_DEVICE_PROVIDER_GET_CLASS (self)->load_async (self, cancellable, callback, user_data);
+}
+
+/**
+ * ide_device_provider_load_finish:
+ * @self: an #IdeDeviceProvider
+ * @result: a #GAsyncResult provided to callback
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to load known devices via
+ * ide_device_provider_load_async().
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ *
+ * Since: 3.28
+ */
+gboolean
+ide_device_provider_load_finish (IdeDeviceProvider  *self,
+                                 GAsyncResult       *result,
+                                 GError            **error)
+{
+  g_return_val_if_fail (IDE_IS_DEVICE_PROVIDER (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  return IDE_DEVICE_PROVIDER_GET_CLASS (self)->load_finish (self, result, error);
+}
+
+/**
+ * ide_device_provider_get_devices:
+ * @self: an #IdeDeviceProvider
+ *
+ * Gets a new #GPtrArray containing a list of #IdeDevice instances that were
+ * registered by the #IdeDeviceProvider
+ *
+ * Returns: (transfer container) (element-type Ide.Device) (not nullable):
+ *   a #GPtrArray of #IdeDevice.
+ *
+ * Since: 3.28
+ */
+GPtrArray *
+ide_device_provider_get_devices (IdeDeviceProvider *self)
+{
+  IdeDeviceProviderPrivate *priv = ide_device_provider_get_instance_private (self);
+  g_autoptr(GPtrArray) devices = NULL;
+
+  g_return_val_if_fail (IDE_IS_DEVICE_PROVIDER (self), NULL);
+
+  devices = g_ptr_array_new_with_free_func (g_object_unref);
+
+  if (priv->devices != NULL)
+    {
+      for (guint i = 0; i < priv->devices->len; i++)
+        g_ptr_array_add (devices, g_object_ref (g_ptr_array_index (priv->devices, i)));
+    }
+
+  return g_steal_pointer (&devices);
+}
diff --git a/src/libide/devices/ide-device-provider.h b/src/libide/devices/ide-device-provider.h
index 8c08fb4f8..3b7c4a83d 100644
--- a/src/libide/devices/ide-device-provider.h
+++ b/src/libide/devices/ide-device-provider.h
@@ -18,34 +18,50 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
+#include "ide-object.h"
 
 #include "devices/ide-device.h"
-#include "ide-object.h"
+#include "ide-version-macros.h"
 
 G_BEGIN_DECLS
 
 #define IDE_TYPE_DEVICE_PROVIDER (ide_device_provider_get_type())
 
-G_DECLARE_INTERFACE (IdeDeviceProvider, ide_device_provider, IDE, DEVICE_PROVIDER, IdeObject)
+G_DECLARE_DERIVABLE_TYPE (IdeDeviceProvider, ide_device_provider, IDE, DEVICE_PROVIDER, IdeObject)
 
-struct _IdeDeviceProviderInterface
+struct _IdeDeviceProviderClass
 {
-  GTypeInterface parent_interface;
+  IdeObjectClass parent_class;
 
-  gboolean   (*get_settled) (IdeDeviceProvider *provider);
-  GPtrArray *(*get_devices) (IdeDeviceProvider *provider);
+  void     (*device_added)   (IdeDeviceProvider    *self,
+                              IdeDevice            *device);
+  void     (*device_removed) (IdeDeviceProvider    *self,
+                              IdeDevice            *device);
+  void     (*load_async)     (IdeDeviceProvider    *self,
+                              GCancellable         *cancellable,
+                              GAsyncReadyCallback   callback,
+                              gpointer              user_data);
+  gboolean (*load_finish)    (IdeDeviceProvider    *self,
+                              GAsyncResult         *result,
+                              GError              **error);
 };
 
 IDE_AVAILABLE_IN_ALL
-void       ide_device_provider_emit_device_added   (IdeDeviceProvider *provider,
-                                                    IdeDevice         *device);
+void       ide_device_provider_emit_device_added   (IdeDeviceProvider    *self,
+                                                    IdeDevice            *device);
+IDE_AVAILABLE_IN_ALL
+void       ide_device_provider_emit_device_removed (IdeDeviceProvider    *self,
+                                                    IdeDevice            *device);
 IDE_AVAILABLE_IN_ALL
-void       ide_device_provider_emit_device_removed (IdeDeviceProvider *provider,
-                                                    IdeDevice         *device);
+void       ide_device_provider_load_async          (IdeDeviceProvider    *self,
+                                                    GCancellable         *cancellable,
+                                                    GAsyncReadyCallback   callback,
+                                                    gpointer              user_data);
 IDE_AVAILABLE_IN_ALL
-GPtrArray *ide_device_provider_get_devices         (IdeDeviceProvider *provider);
+gboolean   ide_device_provider_load_finish         (IdeDeviceProvider    *self,
+                                                    GAsyncResult         *result,
+                                                    GError              **error);
 IDE_AVAILABLE_IN_ALL
-gboolean   ide_device_provider_get_settled         (IdeDeviceProvider *provider);
+GPtrArray *ide_device_provider_get_devices         (IdeDeviceProvider    *self);
 
 G_END_DECLS


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