Skip to content
Snippets Groups Projects
object.c 6.02 KiB
Newer Older
/* WirePlumber
 *
 * Copyright © 2019 Collabora Ltd.
 *    @author George Kiagiadakis <george.kiagiadakis@collabora.com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */
#include "interface-impl.h"
#include "error.h"

typedef struct {
  GArray *iface_objects;
  GArray *iface_types;
} WpObjectPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (WpObject, wp_object, G_TYPE_OBJECT);

static void
wp_object_init (WpObject * self)
{
  WpObjectPrivate *priv = wp_object_get_instance_private (self);

  priv->iface_objects = g_array_new (FALSE, FALSE, sizeof (gpointer));
  priv->iface_types = g_array_new (FALSE, FALSE, sizeof (GType));
}

static void
wp_object_finalize (GObject * obj)
{
  WpObject *self = WP_OBJECT (obj);
  WpObjectPrivate *priv = wp_object_get_instance_private (self);
  guint i;

  for (i = 0; i < priv->iface_objects->len; i++) {
    GObject *obj = g_array_index (priv->iface_objects, GObject*, i);
    wp_interface_impl_set_object (WP_INTERFACE_IMPL (obj), NULL);
    g_object_unref (obj);
  }

  g_array_free (priv->iface_objects, TRUE);
  g_array_free (priv->iface_types, TRUE);

  G_OBJECT_CLASS (wp_object_parent_class)->finalize (obj);
}

static void
wp_object_class_init (WpObjectClass * klass)
{
  GObjectClass *object_class = (GObjectClass *) klass;
  object_class->finalize = wp_object_finalize;
}

/**
 * wp_object_implements_interface: (method)
 * @self: the object
 * @interface: an interface type
 *
 * Returns: whether the interface is implemented in this object or not
 */
gboolean
wp_object_implements_interface (WpObject * self, GType interface)
{
  WpObjectPrivate *priv = wp_object_get_instance_private (self);
  guint i;

  g_return_val_if_fail (WP_IS_OBJECT (self), FALSE);

  for (i = 0; i < priv->iface_types->len; i++) {
    GType t = g_array_index (priv->iface_types, GType, i);
    if (t == interface)
      return TRUE;
  }

  return FALSE;
}

/**
 * wp_object_get_interface: (method)
 * @self: the object
 * @interface: an interface type
 *
 * Returns: (type GObject*) (nullable) (transfer none): the object
 *    implementing @interface
wp_object_get_interface (WpObject * self, GType interface)
{
  WpObjectPrivate *priv = wp_object_get_instance_private (self);
  guint i;

  g_return_val_if_fail (WP_IS_OBJECT (self), FALSE);

  for (i = 0; i < priv->iface_objects->len; i++) {
    GObject *obj = g_array_index (priv->iface_objects, GObject*, i);
    if (g_type_is_a (G_TYPE_FROM_INSTANCE (obj), interface))
  }

  return NULL;
}

/**
 * wp_object_list_interfaces: (method)
 * @self: the object
 * @n_interfaces: (out): the number of elements in the returned array
 *
 * Returns: (array length=n_interfaces) (transfer none): the interface types
 *   that are implemented in this object
 */
GType *
wp_object_list_interfaces (WpObject * self, guint * n_interfaces)
{
  WpObjectPrivate *priv = wp_object_get_instance_private (self);

  g_return_val_if_fail (WP_IS_OBJECT (self), NULL);

  *n_interfaces = priv->iface_types->len;
  return (GType *) priv->iface_types->data;
}

/**
 * wp_object_attach_interface_impl: (method)
 * @self: the object
 * @impl: (type WpInterfaceImpl*) (transfer none): the interface implementation
 * @error: (out): a GError to return on failure
 *
 * Returns: TRUE one success, FALSE on error
 */
gboolean
wp_object_attach_interface_impl (WpObject * self, gpointer impl,
    GError ** error)
{
  WpObjectPrivate *priv = wp_object_get_instance_private (self);
  GType *new_ifaces;
  GType *prerequisites;
  guint n_new_ifaces;
  guint n_prerequisites, n_satisfied = 0;
  guint i, j;

  g_return_val_if_fail (WP_IS_OBJECT (self), FALSE);
  g_return_val_if_fail (WP_IS_INTERFACE_IMPL (impl), FALSE);

  new_ifaces = g_type_interfaces (G_TYPE_FROM_INSTANCE (impl),
      &n_new_ifaces);
  prerequisites = wp_interface_impl_get_prerequisites (impl, &n_prerequisites);

  for (i = 0; i < priv->iface_types->len; i++) {
    GType t = g_array_index (priv->iface_types, GType, i);

    for (j = 0; j < n_prerequisites; j++) {
      if (prerequisites[j] == t)
        n_satisfied++;
    }

    for (j = 0; j < n_new_ifaces; j++) {
      if (new_ifaces[j] == t) {
        g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
            "Interface %s is already provided on object %p",
            g_type_name (t), self);
        return FALSE;
      }
    }
  }

  if (n_satisfied != n_prerequisites) {
    g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_INVARIANT,
        "Interface implementation %p has unsatisfied requirements", impl);
    return FALSE;
  }

  g_object_ref (impl);
  g_array_append_val (priv->iface_objects, impl);
  g_array_append_vals (priv->iface_types, new_ifaces, n_new_ifaces);
  wp_interface_impl_set_object (WP_INTERFACE_IMPL (impl), self);

/* WpPipewireProperties */

G_DEFINE_INTERFACE (WpPipewireProperties, wp_pipewire_properties, G_TYPE_OBJECT)

static void
wp_pipewire_properties_default_init (WpPipewirePropertiesInterface * iface)
{
}

/**
 * wp_pipewire_properties_get: (virtual get)
 * @self: the interface
 * @key: the name of the property to lookup
 *
 * Return: (transfer none): The value of the underlying PipeWire object's
 *    property with this @key, or %NULL.
 */
const gchar *
wp_pipewire_properties_get (WpPipewireProperties * self, const gchar * key)
{
  WpPipewirePropertiesInterface *iface = WP_PIPEWIRE_PROPERTIES_GET_IFACE (self);

  g_return_val_if_fail (WP_IS_PIPEWIRE_PROPERTIES (self), NULL);
  g_return_val_if_fail (key != NULL, NULL);
  g_return_val_if_fail (iface->get, NULL);

  return iface->get (self, key);
}

/**
 * wp_pipewire_properties_get_as_spa_dict: (virtual get_as_spa_dict)
 * @self: the interface
 *
 * Return: (transfer none): The underlying `struct spa_dict` that holds
 *    the properties
 */
const struct spa_dict *
wp_pipewire_properties_get_as_spa_dict (WpPipewireProperties * self)
{
  WpPipewirePropertiesInterface *iface = WP_PIPEWIRE_PROPERTIES_GET_IFACE (self);

  g_return_val_if_fail (WP_IS_PIPEWIRE_PROPERTIES (self), NULL);
  g_return_val_if_fail (iface->get_as_spa_dict, NULL);

  return iface->get_as_spa_dict (self);
}