Skip to content
Snippets Groups Projects
si-factory.c 8.33 KiB
Newer Older
/* WirePlumber
 *
 * Copyright © 2020 Collabora Ltd.
 *    @author George Kiagiadakis <george.kiagiadakis@collabora.com>
 *
 * SPDX-License-Identifier: MIT
 */

/**
 * SECTION: WpSiFactory
 * @title: Session Items Factory
 */

#include "si-factory.h"
#include "private.h"

enum {
  PROP_0,
  PROP_NAME,
};

typedef struct _WpSiFactoryPrivate WpSiFactoryPrivate;
struct _WpSiFactoryPrivate
{
  GQuark name_quark;
};

/**
 * WpSiFactory:
 *
 * A factory for session items.
 *
 * The most simple way to register a new item implementation would be:
 * |[
 * GVariantBuilder b = G_VARIANT_BUILDER_INIT ("a(ssymv)");
 * g_variant_builder_add (&b, ...);
 * wp_si_factory_register (core, wp_si_factory_new_simple (
 *    "foobar", FOO_TYPE_BAR, g_variant_builder_end (&b)));
 * ]|
 *
 * And the most simple way to construct an item from a registered factory:
 * |[
 * item = wp_session_item_make (core, "foobar");
 * ]|
 */
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpSiFactory, wp_si_factory, G_TYPE_OBJECT)

static void
wp_si_factory_init (WpSiFactory * self)
{
}

static void
wp_si_factory_set_property (GObject * object, guint property_id,
    const GValue * value, GParamSpec * pspec)
{
  WpSiFactory *self = WP_SI_FACTORY (object);
  WpSiFactoryPrivate *priv = wp_si_factory_get_instance_private (self);

  switch (property_id) {
  case PROP_NAME:
    priv->name_quark = g_quark_from_string (g_value_get_string (value));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

static void
wp_si_factory_get_property (GObject * object, guint property_id, GValue * value,
    GParamSpec * pspec)
{
  WpSiFactory *self = WP_SI_FACTORY (object);
  WpSiFactoryPrivate *priv = wp_si_factory_get_instance_private (self);

  switch (property_id) {
  case PROP_NAME:
    g_value_set_string (value, g_quark_to_string (priv->name_quark));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

static void
wp_si_factory_class_init (WpSiFactoryClass * klass)
{
  GObjectClass * object_class = (GObjectClass *) klass;

  object_class->get_property = wp_si_factory_get_property;
  object_class->set_property = wp_si_factory_set_property;

  g_object_class_install_property (object_class, PROP_NAME,
      g_param_spec_string ("name", "name", "The factory's name", "",
          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}

/**
 * wp_si_factory_get_name:
 * @self: the factory
 *
 * Returns: the factory name
 */
const gchar *
wp_si_factory_get_name (WpSiFactory * self)
{
  g_return_val_if_fail (WP_IS_SI_FACTORY (self), NULL);

  WpSiFactoryPrivate *priv = wp_si_factory_get_instance_private (self);
  return g_quark_to_string (priv->name_quark);
}

/**
 * wp_si_factory_construct:
 * @self: the factory
 *
 * Creates a new instance of the session item that is constructed
 * by this factory
 *
 * Returns: (transfer full): a new session item instance
 */
WpSessionItem *
wp_si_factory_construct (WpSiFactory * self)
{
  g_return_val_if_fail (WP_IS_SI_FACTORY (self), NULL);
  g_return_val_if_fail (WP_SI_FACTORY_GET_CLASS (self)->construct, NULL);

  return WP_SI_FACTORY_GET_CLASS (self)->construct (self);
}

/**
 * wp_si_factory_get_config_spec:
 * @self: the factory
 *
 * Returns a description of all the configuration options that the constructed
 * items of this factory have. Configuration options are a way for items to
 * accept input from external sources that affects their behavior, or to
 * provide output for other items to consume as their configuration.
 *
 * The returned GVariant has the a(ssymv) type. This is an array of tuples,
 * where each tuple has the following values, in order:
 *  * s (string): the name of the option
 *  * s (string): a GVariant type string, describing the type of the data
 *  * y (byte): a combination of #WpSiConfigOptionFlags
 *  * mv (optional variant): optionally, an additional variant
 *    This is provided to allow extensions.
 *
 * Returns: (transfer full): the configuration description
 */
GVariant *
wp_si_factory_get_config_spec (WpSiFactory * self)
{
  g_return_val_if_fail (WP_IS_SI_FACTORY (self), NULL);
  g_return_val_if_fail (WP_SI_FACTORY_GET_CLASS (self)->get_config_spec, NULL);

  return WP_SI_FACTORY_GET_CLASS (self)->get_config_spec (self);
}

/**
 * wp_si_factory_register:
 * @core: the core
 * @factory: (transfer full): the factory to register
 *
 * Registers the @factory on the @core.
 */
void
wp_si_factory_register (WpCore * core, WpSiFactory * factory)
{
  g_return_if_fail (WP_IS_CORE (core));
  g_return_if_fail (WP_IS_SI_FACTORY (factory));

  wp_registry_register_object (wp_core_get_registry (core), factory);
}

static gboolean
find_factory_func (gpointer factory, gpointer name_quark)
{
  if (!WP_IS_SI_FACTORY (factory))
    return FALSE;

  WpSiFactoryPrivate *priv =
      wp_si_factory_get_instance_private ((WpSiFactory *) factory);
  return priv->name_quark == GPOINTER_TO_UINT (name_quark);
}

/**
 * wp_si_factory_find:
 * @core: the core
 * @factory_name: the lookup name
 *
 * Returns: (transfer full) (nullable): the factory matching the lookup name
 */
WpSiFactory *
wp_si_factory_find (WpCore * core, const gchar * factory_name)
{
  g_return_val_if_fail (WP_IS_CORE (core), NULL);

  GQuark q = g_quark_try_string (factory_name);
  if (q == 0)
    return NULL;
  GObject *f = wp_registry_find_object (wp_core_get_registry (core),
      (GEqualFunc) find_factory_func, GUINT_TO_POINTER (q));
  return f ? WP_SI_FACTORY (f) : NULL;
}

/**
 * wp_session_item_make:
 * @core: the #WpCore
 * @factory_name: the name of the factory to be used for constructing the object
 *
 * Finds the factory associated with the given @name from the @core and
 * uses it to construct a new #WpSessionItem.
 *
 * Returns: (transfer full) (nullable): the new session item
 */
WpSessionItem *
wp_session_item_make (WpCore * core, const gchar * factory_name)
{
  g_autoptr (WpSiFactory) f = wp_si_factory_find (core, factory_name);
  return f ? wp_si_factory_construct (f) : NULL;
}

struct _WpSimpleSiFactory
{
  WpSiFactory parent;
  GType si_type;
  GVariant *config_spec;
};

G_DECLARE_FINAL_TYPE (WpSimpleSiFactory, wp_simple_si_factory,
                      WP, SIMPLE_SI_FACTORY, WpSiFactory)
G_DEFINE_TYPE (WpSimpleSiFactory, wp_simple_si_factory, WP_TYPE_SI_FACTORY)

static void
wp_simple_si_factory_init (WpSimpleSiFactory * self)
{
}

static void
wp_simple_si_factory_finalize (GObject * object)
{
  WpSimpleSiFactory * self = WP_SIMPLE_SI_FACTORY (object);

  g_clear_pointer (&self->config_spec, g_variant_unref);

  G_OBJECT_CLASS (wp_simple_si_factory_parent_class)->finalize (object);
}

static WpSessionItem *
wp_simple_si_factory_construct (WpSiFactory * self)
{
  return g_object_new (WP_SIMPLE_SI_FACTORY (self)->si_type, NULL);
}

static GVariant *
wp_simple_si_factory_get_config_spec (WpSiFactory * self)
{
  return g_variant_ref (WP_SIMPLE_SI_FACTORY (self)->config_spec);
}

static void
wp_simple_si_factory_class_init (WpSimpleSiFactoryClass * klass)
{
  GObjectClass * object_class = (GObjectClass *) klass;
  WpSiFactoryClass * factory_class = (WpSiFactoryClass *) klass;

  object_class->finalize = wp_simple_si_factory_finalize;

  factory_class->construct = wp_simple_si_factory_construct;
  factory_class->get_config_spec = wp_simple_si_factory_get_config_spec;
}

/**
 * wp_si_factory_new_simple:
 * @factory_name: the factory name; must be a static string!
 * @si_type: the #WpSessionItem subclass type to instantiate for
 *    constructing items
 * @config_spec: (transfer floating): the config spec that will be returned
 *    by wp_si_factory_get_config_spec()
 *
 * Returns: (transfer full): the new factory
 */
WpSiFactory *
wp_si_factory_new_simple (const gchar * factory_name,
    GType si_type, GVariant * config_spec)
{
  g_return_val_if_fail (factory_name != NULL, NULL);
  g_return_val_if_fail (g_type_is_a (si_type, WP_TYPE_SESSION_ITEM), NULL);
  g_return_val_if_fail (
      g_variant_is_of_type (config_spec, G_VARIANT_TYPE ("a{sv}")), NULL);

  WpSimpleSiFactory *self = g_object_new (
      wp_simple_si_factory_get_type (), NULL);

  /* assign the quark directly to use g_quark_from_static_string */
  WpSiFactoryPrivate *priv =
      wp_si_factory_get_instance_private (WP_SI_FACTORY (self));
  priv->name_quark = g_quark_from_static_string (factory_name);

  self->si_type = si_type;
  self->config_spec = g_variant_ref_sink (config_spec);

  return WP_SI_FACTORY (self);
}