diff --git a/lib/wp/core-interfaces.c b/lib/wp/core-interfaces.c new file mode 100644 index 00000000..94f9d87d --- /dev/null +++ b/lib/wp/core-interfaces.c @@ -0,0 +1,149 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "core-interfaces.h" +#include "plugin.h" + +/* WpPluginRegistry */ + +G_DEFINE_INTERFACE (WpPluginRegistry, wp_plugin_registry, WP_TYPE_INTERFACE_IMPL) + +static void +wp_plugin_registry_default_init (WpPluginRegistryInterface * iface) +{ +} + +/** + * wp_plugin_registry_register_static: (skip) + * @plugin_type: the #GType of the #WpPlugin subclass + * @metadata: the metadata + * @metadata_size: the sizeof (@metadata), to allow ABI-compatible future + * expansion of the structure + * + * Registers a plugin in the registry. + * This method is used internally by WP_PLUGIN_REGISTER(). + * Avoid using it directly. + */ +void +wp_plugin_registry_register_static (WpPluginRegistry * self, + GType plugin_type, + const WpPluginMetadata * metadata, + gsize metadata_size) +{ + WpPluginRegistryInterface *iface = WP_PLUGIN_REGISTRY_GET_IFACE (self); + + g_return_if_fail (WP_IS_PLUGIN_REGISTRY (self)); + g_return_if_fail (iface->register_plugin != NULL); + g_return_if_fail (g_type_is_a (plugin_type, WP_TYPE_PLUGIN)); + g_return_if_fail (metadata->name != NULL); + g_return_if_fail (metadata->description != NULL); + g_return_if_fail (metadata->author != NULL); + g_return_if_fail (metadata->license != NULL); + g_return_if_fail (metadata->version != NULL); + g_return_if_fail (metadata->origin != NULL); + + WP_PLUGIN_REGISTRY_GET_IFACE (self)->register_plugin (self, plugin_type, + metadata, metadata_size, TRUE); +} + +/** + * wp_plugin_registry_register: (method) + * @plugin_type: the #GType of the #WpPlugin subclass + * @rank: the rank of the plugin + * @name: the name of the plugin + * @description: plugin description + * @author: author , author2 + * @license: a SPDX license ID or "Proprietary" + * @version: the version of the plugin + * @origin: URL or short reference of where this plugin came from + * + * Registers a plugin in the registry. + * This method creates a dynamically allocated #WpPluginMetadata and is meant + * to be used by bindings that have no way of representing #WpPluginMetadata. + * In C/C++, you should use WP_PLUGIN_REGISTER() + */ +void +wp_plugin_registry_register (WpPluginRegistry * self, + GType plugin_type, + guint16 rank, + const gchar *name, + const gchar *description, + const gchar *author, + const gchar *license, + const gchar *version, + const gchar *origin) +{ + WpPluginRegistryInterface *iface = WP_PLUGIN_REGISTRY_GET_IFACE (self); + WpPluginMetadata metadata = {0}; + + g_return_if_fail (WP_IS_PLUGIN_REGISTRY (self)); + g_return_if_fail (iface->register_plugin != NULL); + g_return_if_fail (g_type_is_a (plugin_type, WP_TYPE_PLUGIN)); + g_return_if_fail (name != NULL); + g_return_if_fail (description != NULL); + g_return_if_fail (author != NULL); + g_return_if_fail (license != NULL); + g_return_if_fail (version != NULL); + g_return_if_fail (origin != NULL); + + metadata.rank = rank; + metadata.name = name; + metadata.description = description; + metadata.author = author; + metadata.license = license; + metadata.version = version; + metadata.origin = origin; + + WP_PLUGIN_REGISTRY_GET_IFACE (self)->register_plugin (self, plugin_type, + &metadata, sizeof (metadata), FALSE); +} + +/* WpProxyRegistry */ + +G_DEFINE_INTERFACE (WpProxyRegistry, wp_proxy_registry, WP_TYPE_INTERFACE_IMPL) + +static void +wp_proxy_registry_default_init (WpProxyRegistryInterface * iface) +{ +} + +/** + * wp_proxy_registry_get_proxy: (method) + * @self: the registry + * @global_id: the ID of the pw_global that is represented by the proxy + * + * Returns: (transfer full): the #WpProxy that represents the global with + * @global_id + */ +WpProxy * +wp_proxy_registry_get_proxy (WpProxyRegistry * self, guint32 global_id) +{ + WpProxyRegistryInterface * iface = WP_PROXY_REGISTRY_GET_IFACE (self); + + g_return_val_if_fail (WP_IS_PROXY_REGISTRY (self), NULL); + g_return_val_if_fail (iface->get_proxy != NULL, NULL); + + return iface->get_proxy (self, global_id); +} + +/** + * wp_proxy_registry_get_pw_registry_proxy: (skip) + * @self: the registry + * + * Returns: the underlying `pw_registry_proxy` + */ +struct pw_registry_proxy * +wp_proxy_registry_get_pw_registry_proxy (WpProxyRegistry * self) +{ + WpProxyRegistryInterface * iface = WP_PROXY_REGISTRY_GET_IFACE (self); + + g_return_val_if_fail (WP_IS_PROXY_REGISTRY (self), NULL); + g_return_val_if_fail (iface->get_pw_registry_proxy != NULL, NULL); + + return iface->get_pw_registry_proxy (self); +} diff --git a/lib/wp/core-interfaces.h b/lib/wp/core-interfaces.h new file mode 100644 index 00000000..f012c348 --- /dev/null +++ b/lib/wp/core-interfaces.h @@ -0,0 +1,73 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __WP_CORE_INTERFACES_H__ +#define __WP_CORE_INTERFACES_H__ + +#include "interface-impl.h" + +G_BEGIN_DECLS + +/* WpPluginRegistry */ + +#define WP_TYPE_PLUGIN_REGISTRY (wp_plugin_registry_get_type ()) +G_DECLARE_INTERFACE (WpPluginRegistry, wp_plugin_registry, WP, PLUGIN_REGISTRY, WpInterfaceImpl) + +typedef struct _WpPluginMetadata WpPluginMetadata; + +struct _WpPluginRegistryInterface +{ + GTypeInterface parent; + + void (*register_plugin) (WpPluginRegistry * self, + GType plugin_type, + const WpPluginMetadata * metadata, + gsize metadata_size, + gboolean static_data); +}; + +void wp_plugin_registry_register_static (WpPluginRegistry * self, + GType plugin_type, + const WpPluginMetadata * metadata, + gsize metadata_size); + +void wp_plugin_registry_register (WpPluginRegistry * self, + GType plugin_type, + guint16 rank, + const gchar *name, + const gchar *description, + const gchar *author, + const gchar *license, + const gchar *version, + const gchar *origin); + +/* WpProxyRegistry */ + +struct pw_registry_proxy; +typedef struct _WpProxy WpProxy; + +#define WP_TYPE_PROXY_REGISTRY (wp_proxy_registry_get_type ()) +G_DECLARE_INTERFACE (WpProxyRegistry, wp_proxy_registry, WP, PROXY_REGISTRY, WpInterfaceImpl) + +struct _WpProxyRegistryInterface +{ + GTypeInterface parent; + + WpProxy * (*get_proxy) (WpProxyRegistry * self, guint32 global_id); + struct pw_registry_proxy * (*get_pw_registry_proxy) (WpProxyRegistry * self); +}; + +WpProxy * wp_proxy_registry_get_proxy (WpProxyRegistry * self, + guint32 global_id); + +struct pw_registry_proxy * wp_proxy_registry_get_pw_registry_proxy ( + WpProxyRegistry * self); + +G_END_DECLS + +#endif diff --git a/lib/wp/interface-impl.c b/lib/wp/interface-impl.c index 80ec4f30..25de7840 100644 --- a/lib/wp/interface-impl.c +++ b/lib/wp/interface-impl.c @@ -10,7 +10,7 @@ #include "object.h" typedef struct { - GObject *object; + WpObject *object; } WpInterfaceImplPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpInterfaceImpl, wp_interface_impl, G_TYPE_OBJECT); @@ -44,7 +44,7 @@ wp_interface_impl_class_init (WpInterfaceImplClass * klass) * @object: (nullable) (transfer none): the implementor */ void -wp_interface_impl_set_object (WpInterfaceImpl * self, GObject * object) +wp_interface_impl_set_object (WpInterfaceImpl * self, WpObject * object) { WpInterfaceImplPrivate *priv = wp_interface_impl_get_instance_private (self); @@ -60,7 +60,7 @@ wp_interface_impl_set_object (WpInterfaceImpl * self, GObject * object) * * Returns: (nullable) (transfer none): the object implementing this interface */ -GObject * +WpObject * wp_interface_impl_get_object (WpInterfaceImpl * self) { WpInterfaceImplPrivate *priv = wp_interface_impl_get_instance_private (self); @@ -75,9 +75,10 @@ wp_interface_impl_get_object (WpInterfaceImpl * self) * @self: the interface implementation instance * @interface: an interface type * - * Returns: (nullable) (transfer full): the object implementing @interface + * Returns: (type GObject*) (nullable) (transfer full): the object + * implementing @interface */ -GObject * +gpointer wp_interface_impl_get_sibling (WpInterfaceImpl * self, GType interface) { WpInterfaceImplPrivate *priv = wp_interface_impl_get_instance_private (self); @@ -89,7 +90,7 @@ wp_interface_impl_get_sibling (WpInterfaceImpl * self, GType interface) if (g_type_is_a (G_TYPE_FROM_INSTANCE (self), interface)) { iface = G_OBJECT (g_object_ref (self)); } else if (priv->object) { - iface = wp_object_get_interface (WP_OBJECT (priv->object), interface); + iface = wp_object_get_interface (priv->object, interface); } return iface; diff --git a/lib/wp/interface-impl.h b/lib/wp/interface-impl.h index 7e71254e..068b9fe3 100644 --- a/lib/wp/interface-impl.h +++ b/lib/wp/interface-impl.h @@ -13,6 +13,9 @@ G_BEGIN_DECLS +typedef struct _WpObject WpObject; + +#define WP_TYPE_INTERFACE_IMPL (wp_interface_impl_get_type ()) G_DECLARE_DERIVABLE_TYPE (WpInterfaceImpl, wp_interface_impl, WP, INTERFACE_IMPL, GObject) struct _WpInterfaceImplClass @@ -30,9 +33,9 @@ struct _WpInterfaceImplClass GType *(*get_prerequisites) (WpInterfaceImpl * self, guint * n_prerequisites); }; -void wp_interface_impl_set_object (WpInterfaceImpl * self, GObject * object); -GObject * wp_interface_impl_get_object (WpInterfaceImpl * self); -GObject * wp_interface_impl_get_sibling (WpInterfaceImpl * self, +void wp_interface_impl_set_object (WpInterfaceImpl * self, WpObject * object); +WpObject * wp_interface_impl_get_object (WpInterfaceImpl * self); +gpointer wp_interface_impl_get_sibling (WpInterfaceImpl * self, GType interface); GType * wp_interface_impl_get_prerequisites (WpInterfaceImpl * self, guint * n_prerequisites); diff --git a/lib/wp/meson.build b/lib/wp/meson.build index 7525033d..ffa45ee2 100644 --- a/lib/wp/meson.build +++ b/lib/wp/meson.build @@ -1,20 +1,18 @@ wp_lib_sources = [ + 'core-interfaces.c', 'error.c', 'interface-impl.c', 'object.c', - 'plugin-registry.c', 'plugin.c', - 'proxy-registry.c', 'proxy.c', ] wp_lib_headers = [ + 'core-interfaces.h', 'error.h', 'interface-impl.h', 'object.h', - 'plugin-registry.h', 'plugin.h', - 'proxy-registry.h', 'proxy.h', ] diff --git a/lib/wp/object.c b/lib/wp/object.c index 70d9b171..3bbf8ca7 100644 --- a/lib/wp/object.c +++ b/lib/wp/object.c @@ -7,6 +7,7 @@ */ #include "object.h" +#include "interface-impl.h" #include "error.h" typedef struct { @@ -80,9 +81,10 @@ wp_object_implements_interface (WpObject * self, GType interface) * @self: the object * @interface: an interface type * - * Returns: (nullable) (transfer full): the object implementing @interface + * Returns: (type GObject*) (nullable) (transfer full): the object + * implementing @interface */ -GObject * +gpointer wp_object_get_interface (WpObject * self, GType interface) { WpObjectPrivate *priv = wp_object_get_instance_private (self); @@ -121,13 +123,13 @@ wp_object_list_interfaces (WpObject * self, guint * n_interfaces) /** * wp_object_attach_interface_impl: (method) * @self: the object - * @impl: (transfer none): the interface implementation + * @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, WpInterfaceImpl * impl, +wp_object_attach_interface_impl (WpObject * self, gpointer impl, GError ** error) { WpObjectPrivate *priv = wp_object_get_instance_private (self); @@ -171,6 +173,6 @@ wp_object_attach_interface_impl (WpObject * self, WpInterfaceImpl * impl, 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 (impl, G_OBJECT (self)); + wp_interface_impl_set_object (WP_INTERFACE_IMPL (impl), self); return TRUE; } diff --git a/lib/wp/object.h b/lib/wp/object.h index 0f2332fd..138c4bb7 100644 --- a/lib/wp/object.h +++ b/lib/wp/object.h @@ -9,10 +9,11 @@ #ifndef __WP_OBJECT_H__ #define __WP_OBJECT_H__ -#include "interface-impl.h" +#include G_BEGIN_DECLS +#define WP_TYPE_OBJECT (wp_object_get_type ()) G_DECLARE_DERIVABLE_TYPE (WpObject, wp_object, WP, OBJECT, GObject) struct _WpObjectClass @@ -21,11 +22,11 @@ struct _WpObjectClass }; gboolean wp_object_implements_interface (WpObject * self, GType interface); -GObject * wp_object_get_interface (WpObject * self, GType interface); +gpointer wp_object_get_interface (WpObject * self, GType interface); GType * wp_object_list_interfaces (WpObject * self, guint * n_interfaces); -gboolean wp_object_attach_interface_impl (WpObject * self, - WpInterfaceImpl * impl, GError ** error); +gboolean wp_object_attach_interface_impl (WpObject * self, gpointer impl, + GError ** error); G_END_DECLS diff --git a/lib/wp/plugin-registry.c b/lib/wp/plugin-registry.c deleted file mode 100644 index d868c0b3..00000000 --- a/lib/wp/plugin-registry.c +++ /dev/null @@ -1,227 +0,0 @@ -/* WirePlumber - * - * Copyright © 2019 Collabora Ltd. - * @author George Kiagiadakis - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include "plugin-registry.h" -#include "plugin.h" - -typedef struct { - gsize block_size; - GType gtype; - const WpPluginMetadata *metadata; - WpPlugin *instance; -} PluginData; - -struct _WpPluginRegistry -{ - GObject parent; - - GList *plugins; - GStringChunk *metadata_strings; -}; - -G_DEFINE_TYPE (WpPluginRegistry, wp_plugin_registry, G_TYPE_OBJECT); - -static void -wp_plugin_registry_init (WpPluginRegistry * self) -{ - self->metadata_strings = g_string_chunk_new (200); -} - -static void -wp_plugin_registry_dispose (GObject * object) -{ - WpPluginRegistry *self = WP_PLUGIN_REGISTRY (object); - GList *list; - PluginData *plugin_data; - - for (list = self->plugins; list != NULL; list = g_list_next (list)) { - plugin_data = list->data; - g_clear_object (&plugin_data->instance); - } - - G_OBJECT_CLASS (wp_plugin_registry_parent_class)->dispose (object); -} - -static void -plugin_data_free (PluginData *data) -{ - g_slice_free1 (data->block_size, data); -} - -static void -wp_plugin_registry_finalize (GObject * object) -{ - WpPluginRegistry *self = WP_PLUGIN_REGISTRY (object); - - g_list_free_full (self->plugins, (GDestroyNotify) plugin_data_free); - g_string_chunk_free (self->metadata_strings); - - G_OBJECT_CLASS (wp_plugin_registry_parent_class)->finalize (object); -} - -static void -wp_plugin_registry_class_init (WpPluginRegistryClass * klass) -{ - GObjectClass *object_class = (GObjectClass *) klass; - object_class->dispose = wp_plugin_registry_dispose; - object_class->finalize = wp_plugin_registry_finalize; -} - -/** - * wp_plugin_registry_new: (constructor) - * - * Create a new registry. - */ -WpPluginRegistry * -wp_plugin_registry_new (void) -{ - return g_object_new (wp_plugin_registry_get_type (), NULL); -} - -static gint -compare_ranks (const WpPluginMetadata * a, const WpPluginMetadata * b) -{ - return (gint) b->rank - (gint) a->rank; -} - -/** - * wp_plugin_registry_register_with_metadata: (skip) - * @plugin_type: the #GType of the #WpPlugin subclass - * @metadata: the metadata - * @metadata_size: the sizeof (@metadata), to allow ABI-compatible future - * expansion of the structure - * - * Registers a plugin in the registry. - * This method is used internally by WP_PLUGIN_REGISTER(). - * Avoid using it directly. - */ -void -wp_plugin_registry_register_with_metadata (WpPluginRegistry * self, - GType plugin_type, - const WpPluginMetadata * metadata, - gsize metadata_size) -{ - PluginData *data; - - g_return_if_fail (WP_IS_PLUGIN_REGISTRY (self)); - g_return_if_fail (metadata_size == sizeof (WpPluginMetadata)); - g_return_if_fail (g_type_is_a (plugin_type, wp_plugin_get_type ())); - g_return_if_fail (metadata->name != NULL); - g_return_if_fail (metadata->description != NULL); - g_return_if_fail (metadata->author != NULL); - g_return_if_fail (metadata->license != NULL); - g_return_if_fail (metadata->version != NULL); - g_return_if_fail (metadata->origin != NULL); - - data = g_slice_alloc (sizeof (PluginData)); - data->block_size = sizeof (PluginData); - data->gtype = plugin_type; - data->metadata = metadata; - data->instance = NULL; - - self->plugins = g_list_insert_sorted (self->plugins, data, - (GCompareFunc) compare_ranks); -} - -/** - * wp_plugin_registry_register: (method) - * @plugin_type: the #GType of the #WpPlugin subclass - * @rank: the rank of the plugin - * @name: the name of the plugin - * @description: plugin description - * @author: author , author2 - * @license: a SPDX license ID or "Proprietary" - * @version: the version of the plugin - * @origin: URL or short reference of where this plugin came from - * - * Registers a plugin in the registry. - * This method creates a dynamically allocated #WpPluginMetadata and is meant - * to be used by bindings that have no way of representing #WpPluginMetadata. - * In C/C++, you should use WP_PLUGIN_REGISTER() - */ -void -wp_plugin_registry_register (WpPluginRegistry * self, - GType plugin_type, - guint16 rank, - const gchar *name, - const gchar *description, - const gchar *author, - const gchar *license, - const gchar *version, - const gchar *origin) -{ - PluginData *data; - WpPluginMetadata *metadata; - - g_return_if_fail (WP_IS_PLUGIN_REGISTRY (self)); - g_return_if_fail (g_type_is_a (plugin_type, wp_plugin_get_type ())); - g_return_if_fail (name != NULL); - g_return_if_fail (description != NULL); - g_return_if_fail (author != NULL); - g_return_if_fail (license != NULL); - g_return_if_fail (version != NULL); - g_return_if_fail (origin != NULL); - - data = g_slice_alloc (sizeof (PluginData) + sizeof (WpPluginMetadata)); - data->block_size = sizeof (PluginData) + sizeof (WpPluginMetadata); - data->gtype = plugin_type; - - metadata = (WpPluginMetadata *) ((guint8 *) data) + sizeof (PluginData); - metadata->rank = rank; - metadata->name = g_string_chunk_insert (self->metadata_strings, name); - metadata->description = g_string_chunk_insert (self->metadata_strings, - description); - metadata->author = g_string_chunk_insert (self->metadata_strings, author); - metadata->license = g_string_chunk_insert (self->metadata_strings, license); - metadata->version = g_string_chunk_insert (self->metadata_strings, version); - metadata->origin = g_string_chunk_insert (self->metadata_strings, origin); - - data->metadata = metadata; - data->instance = NULL; - - self->plugins = g_list_insert_sorted (self->plugins, data, - (GCompareFunc) compare_ranks); -} - -static inline void -make_plugin (WpPluginRegistry * self, PluginData * plugin_data) -{ - plugin_data->instance = g_object_new (plugin_data->gtype, - "registry", self, "metadata", plugin_data->metadata, NULL); -} - -/** - * WpPluginFunc: (skip) - */ - -/** - * wp_plugin_registry_invoke_internal: (skip) - * @self: the registry - * @func: a vfunc invocation function of #WpPlugin - * @data: data to pass to @func - * - * Used internally only. - */ -gboolean -wp_plugin_registry_invoke_internal (WpPluginRegistry * self, WpPluginFunc func, - gpointer data) -{ - GList *list; - PluginData *plugin_data; - - for (list = self->plugins; list != NULL; list = g_list_next (list)) { - plugin_data = list->data; - if (!plugin_data->instance) - make_plugin (self, plugin_data); - - if (func (plugin_data->instance, data)) - return TRUE; - } - - return FALSE; -} diff --git a/lib/wp/plugin-registry.h b/lib/wp/plugin-registry.h deleted file mode 100644 index 21deef69..00000000 --- a/lib/wp/plugin-registry.h +++ /dev/null @@ -1,54 +0,0 @@ -/* WirePlumber - * - * Copyright © 2019 Collabora Ltd. - * @author George Kiagiadakis - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#ifndef __WP_PLUGIN_REGISTRY_H__ -#define __WP_PLUGIN_REGISTRY_H__ - -#include - -G_BEGIN_DECLS - -/* declared in plugin.h */ -typedef struct _WpPluginMetadata WpPluginMetadata; - -G_DECLARE_FINAL_TYPE (WpPluginRegistry, wp_plugin_registry, WP, PLUGIN_REGISTRY, GObject) - -WpPluginRegistry * wp_plugin_registry_new (void); - -void wp_plugin_registry_register_with_metadata (WpPluginRegistry * self, - GType plugin_type, - const WpPluginMetadata * metadata, - gsize metadata_size); - -void wp_plugin_registry_register (WpPluginRegistry * self, - GType plugin_type, - guint16 rank, - const gchar *name, - const gchar *description, - const gchar *author, - const gchar *license, - const gchar *version, - const gchar *origin); - - -typedef gboolean (*WpPluginFunc) (gpointer plugin, gpointer data); -gboolean wp_plugin_registry_invoke_internal (WpPluginRegistry * self, - WpPluginFunc func, gpointer data); - -#define wp_plugin_registry_invoke(r, func, data) \ - G_STMT_START \ - if (!(0 ? func ((WpPlugin *) NULL, data) : \ - wp_plugin_registry_invoke_internal (r, (WpPluginFunc) func, \ - (gpointer) data))) { \ - g_warning ("No plugin handled invocation to " ##func); \ - } \ - G_STMT_END - -G_END_DECLS - -#endif diff --git a/lib/wp/plugin.h b/lib/wp/plugin.h index 9a6a33f5..11089475 100644 --- a/lib/wp/plugin.h +++ b/lib/wp/plugin.h @@ -11,9 +11,7 @@ #include "object.h" #include "proxy.h" -#include "plugin-registry.h" - -#include +#include "core-interfaces.h" G_BEGIN_DECLS @@ -66,6 +64,7 @@ struct _WpPluginMetadata const gchar *origin; }; +#define WP_TYPE_PLUGIN (wp_plugin_get_type ()) G_DECLARE_DERIVABLE_TYPE (WpPlugin, wp_plugin, WP, PLUGIN, GObject) struct _WpPluginClass diff --git a/lib/wp/proxy-registry.h b/lib/wp/proxy-registry.h deleted file mode 100644 index 23fdb735..00000000 --- a/lib/wp/proxy-registry.h +++ /dev/null @@ -1,33 +0,0 @@ -/* WirePlumber - * - * Copyright © 2019 Collabora Ltd. - * @author George Kiagiadakis - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#ifndef __WP_PROXY_REGISTRY_H__ -#define __WP_PROXY_REGISTRY_H__ - -#include - -G_BEGIN_DECLS - -struct pw_remote; -struct pw_registry_proxy; -typedef struct _WpProxy WpProxy; - -G_DECLARE_FINAL_TYPE (WpProxyRegistry, wp_proxy_registry, WP, PROXY_REGISTRY, GObject) - -WpProxyRegistry * wp_proxy_registry_new (struct pw_remote * remote); - -WpProxy * wp_proxy_registry_get_proxy (WpProxyRegistry * self, - guint32 global_id); - -struct pw_remote * wp_proxy_registry_get_pw_remote (WpProxyRegistry * self); -struct pw_registry_proxy * wp_proxy_registry_get_pw_registry_proxy ( - WpProxyRegistry * self); - -G_END_DECLS - -#endif diff --git a/lib/wp/proxy.h b/lib/wp/proxy.h index ffa763b5..3a4d9b7c 100644 --- a/lib/wp/proxy.h +++ b/lib/wp/proxy.h @@ -10,12 +10,13 @@ #define __WP_PROXY_H__ #include "object.h" -#include "proxy-registry.h" +#include "core-interfaces.h" G_BEGIN_DECLS struct pw_proxy; +#define WP_TYPE_PROXY (wp_proxy_get_type ()) G_DECLARE_FINAL_TYPE (WpProxy, wp_proxy, WP, PROXY, WpObject) guint32 wp_proxy_get_id (WpProxy * self); diff --git a/src/core.c b/src/core.c index f75b8a93..f3fb720e 100644 --- a/src/core.c +++ b/src/core.c @@ -9,11 +9,10 @@ #include "core.h" #include "loop-source.h" #include "module-loader.h" +#include "plugin-registry-impl.h" +#include "proxy-registry-impl.h" #include "utils.h" -#include -#include - #include #include #include @@ -32,13 +31,11 @@ struct _WpCore struct spa_hook remote_listener; WpModuleLoader *module_loader; - WpPluginRegistry *plugin_registry; - WpProxyRegistry *proxy_registry; GError *exit_error; }; -G_DEFINE_TYPE (WpCore, wp_core, G_TYPE_OBJECT); +G_DEFINE_TYPE (WpCore, wp_core, WP_TYPE_OBJECT); static gboolean signal_handler (gpointer data) @@ -83,6 +80,7 @@ static gboolean wp_core_parse_commands_file (WpCore * self, GInputStream * stream, GError ** error) { + g_autoptr (WpPluginRegistry) plugin_registry = NULL; gchar buffer[4096]; gssize bytes_read; gchar *cur, *linestart, *saveptr; @@ -90,6 +88,9 @@ wp_core_parse_commands_file (WpCore * self, GInputStream * stream, gint lineno = 1; gboolean eof = FALSE; + plugin_registry = wp_object_get_interface (WP_OBJECT (self), + WP_TYPE_PLUGIN_REGISTRY); + linestart = cur = buffer; do { @@ -126,7 +127,7 @@ wp_core_parse_commands_file (WpCore * self, GInputStream * stream, "expected ABI and MODULE at line %i", lineno); return FALSE; } else if (!wp_module_loader_load (self->module_loader, - self->plugin_registry, abi, module, error)) { + plugin_registry, abi, module, error)) { return FALSE; } } else { @@ -195,6 +196,9 @@ wp_core_load_commands_file (WpCore * self) static void wp_core_init (WpCore * self) { + WpPluginRegistryImpl *plugin_registry; + WpProxyRegistryImpl *proxy_registry; + self->loop = g_main_loop_new (NULL, FALSE); self->source = wp_loop_source_new (); g_source_attach (self->source, NULL); @@ -206,8 +210,31 @@ wp_core_init (WpCore * self) self); self->module_loader = wp_module_loader_new (); - self->proxy_registry = wp_proxy_registry_new (self->remote); - self->plugin_registry = wp_plugin_registry_new (); + + proxy_registry = wp_proxy_registry_impl_new (self->remote); + wp_object_attach_interface_impl (WP_OBJECT (self), proxy_registry, NULL); + + plugin_registry = wp_plugin_registry_impl_new (); + wp_object_attach_interface_impl (WP_OBJECT (self), plugin_registry, NULL); +} + +static void +wp_core_dispose (GObject * obj) +{ + WpCore *self = WP_CORE (obj); + g_autoptr (WpPluginRegistry) plugin_registry = NULL; + g_autoptr (WpProxyRegistry) proxy_registry = NULL; + + /* ensure all proxies and plugins are unrefed, + * so that the registries can be disposed */ + + plugin_registry = wp_object_get_interface (WP_OBJECT (self), + WP_TYPE_PLUGIN_REGISTRY); + wp_plugin_registry_impl_unload (WP_PLUGIN_REGISTRY_IMPL (plugin_registry)); + + proxy_registry = wp_object_get_interface (WP_OBJECT (self), + WP_TYPE_PROXY_REGISTRY); + wp_proxy_registry_impl_unload (WP_PROXY_REGISTRY_IMPL (proxy_registry)); } static void @@ -215,13 +242,6 @@ wp_core_finalize (GObject * obj) { WpCore *self = WP_CORE (obj); - /* ensure all proxies and plugins are unrefed, - * so that the registries can be disposed */ - g_object_run_dispose (G_OBJECT (self->plugin_registry)); - g_object_run_dispose (G_OBJECT (self->proxy_registry)); - - g_clear_object (&self->plugin_registry); - g_clear_object (&self->proxy_registry); g_clear_object (&self->module_loader); spa_hook_remove (&self->remote_listener); @@ -242,6 +262,7 @@ wp_core_class_init (WpCoreClass * klass) { GObjectClass * object_class = (GObjectClass *) klass; + object_class->dispose = wp_core_dispose; object_class->finalize = wp_core_finalize; } diff --git a/src/core.h b/src/core.h index f2cfb9e1..f4cb3e45 100644 --- a/src/core.h +++ b/src/core.h @@ -9,11 +9,11 @@ #ifndef __WIREPLUMBER_CORE_H__ #define __WIREPLUMBER_CORE_H__ -#include +#include G_BEGIN_DECLS -G_DECLARE_FINAL_TYPE (WpCore, wp_core, WP, CORE, GObject); +G_DECLARE_FINAL_TYPE (WpCore, wp_core, WP, CORE, WpObject); WpCore * wp_core_get_instance (void); void wp_core_run (WpCore * self, GError ** error); diff --git a/src/meson.build b/src/meson.build index abc38af4..7498ca21 100644 --- a/src/meson.build +++ b/src/meson.build @@ -3,6 +3,8 @@ wp_sources = [ 'loop-source.c', 'main.c', 'module-loader.c', + 'plugin-registry-impl.c', + 'proxy-registry-impl.c', 'utils.c', ] diff --git a/src/module-loader.c b/src/module-loader.c index 8310e954..64434b16 100644 --- a/src/module-loader.c +++ b/src/module-loader.c @@ -10,6 +10,7 @@ #include "utils.h" #include +#include struct _WpModuleLoader { diff --git a/src/module-loader.h b/src/module-loader.h index e095cdc8..553b8e57 100644 --- a/src/module-loader.h +++ b/src/module-loader.h @@ -10,7 +10,7 @@ #define __WIREPLUMBER_MODULE_LOADER_H__ #include -#include +#include G_BEGIN_DECLS diff --git a/src/plugin-registry-impl.c b/src/plugin-registry-impl.c new file mode 100644 index 00000000..ffff8eab --- /dev/null +++ b/src/plugin-registry-impl.c @@ -0,0 +1,163 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "plugin-registry-impl.h" +#include + +typedef struct { + gsize block_size; + GType gtype; + const WpPluginMetadata *metadata; + WpPlugin *instance; +} PluginData; + +struct _WpPluginRegistryImpl +{ + WpInterfaceImpl parent; + + GList *plugins; + GStringChunk *metadata_strings; +}; + +static void wp_plugin_registry_impl_iface_init (WpPluginRegistryInterface * iface); + +G_DEFINE_TYPE_WITH_CODE (WpPluginRegistryImpl, wp_plugin_registry_impl, WP_TYPE_INTERFACE_IMPL, + G_IMPLEMENT_INTERFACE (WP_TYPE_PLUGIN_REGISTRY, wp_plugin_registry_impl_iface_init);) + +static void +wp_plugin_registry_impl_init (WpPluginRegistryImpl * self) +{ + self->metadata_strings = g_string_chunk_new (200); +} + +static void +plugin_data_free (PluginData *data) +{ + g_slice_free1 (data->block_size, data); +} + +static void +wp_plugin_registry_impl_finalize (GObject * object) +{ + WpPluginRegistryImpl *self = WP_PLUGIN_REGISTRY_IMPL (object); + + g_list_free_full (self->plugins, (GDestroyNotify) plugin_data_free); + g_string_chunk_free (self->metadata_strings); + + G_OBJECT_CLASS (wp_plugin_registry_impl_parent_class)->finalize (object); +} + +static void +wp_plugin_registry_impl_class_init (WpPluginRegistryImplClass * klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + object_class->finalize = wp_plugin_registry_impl_finalize; +} + +static gint +compare_ranks (const WpPluginMetadata * a, const WpPluginMetadata * b) +{ + return (gint) b->rank - (gint) a->rank; +} + +static void +wp_plugin_registry_impl_register_plugin (WpPluginRegistry * r, + GType plugin_type, + const WpPluginMetadata * metadata, + gsize metadata_size, + gboolean static_data) +{ + WpPluginRegistryImpl *self = WP_PLUGIN_REGISTRY_IMPL (r); + PluginData *data; + + g_return_if_fail (metadata_size == sizeof (WpPluginMetadata)); + + if (static_data) { + data = g_slice_alloc (sizeof (PluginData)); + data->block_size = sizeof (PluginData); + } else { + data = g_slice_alloc (sizeof (PluginData) + sizeof (WpPluginMetadata)); + data->block_size = sizeof (PluginData) + sizeof (WpPluginMetadata); + } + + data->gtype = plugin_type; + data->instance = NULL; + + if (!static_data) { + WpPluginMetadata *m; + m = (WpPluginMetadata *) ((guint8 *) data) + sizeof (PluginData); + m->rank = metadata->rank; + m->name = g_string_chunk_insert (self->metadata_strings, metadata->name); + m->description = g_string_chunk_insert (self->metadata_strings, + metadata->description); + m->author = g_string_chunk_insert (self->metadata_strings, + metadata->author); + m->license = g_string_chunk_insert (self->metadata_strings, + metadata->license); + m->version = g_string_chunk_insert (self->metadata_strings, + metadata->version); + m->origin = g_string_chunk_insert (self->metadata_strings, + metadata->origin); + data->metadata = m; + } else { + data->metadata = metadata; + } + + self->plugins = g_list_insert_sorted (self->plugins, data, + (GCompareFunc) compare_ranks); +} + +static void +wp_plugin_registry_impl_iface_init (WpPluginRegistryInterface * iface) +{ + iface->register_plugin = wp_plugin_registry_impl_register_plugin; +} + +WpPluginRegistryImpl * +wp_plugin_registry_impl_new (void) +{ + return g_object_new (wp_plugin_registry_impl_get_type (), NULL); +} + +void +wp_plugin_registry_impl_unload (WpPluginRegistryImpl * self) +{ + GList *list; + PluginData *plugin_data; + + for (list = self->plugins; list != NULL; list = g_list_next (list)) { + plugin_data = list->data; + g_clear_object (&plugin_data->instance); + } +} + +static inline void +make_plugin (WpPluginRegistryImpl * self, PluginData * plugin_data) +{ + plugin_data->instance = g_object_new (plugin_data->gtype, + "registry", self, "metadata", plugin_data->metadata, NULL); +} + +gboolean +wp_plugin_registry_impl_invoke_internal (WpPluginRegistryImpl * self, + WpPluginFunc func, gpointer data) +{ + GList *list; + PluginData *plugin_data; + + for (list = self->plugins; list != NULL; list = g_list_next (list)) { + plugin_data = list->data; + if (!plugin_data->instance) + make_plugin (self, plugin_data); + + if (func (plugin_data->instance, data)) + return TRUE; + } + + return FALSE; +} diff --git a/src/plugin-registry-impl.h b/src/plugin-registry-impl.h new file mode 100644 index 00000000..3cb9a4f2 --- /dev/null +++ b/src/plugin-registry-impl.h @@ -0,0 +1,39 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __WP_PLUGIN_REGISTRY_IMPL_H__ +#define __WP_PLUGIN_REGISTRY_IMPL_H__ + +#include + +G_BEGIN_DECLS + +G_DECLARE_FINAL_TYPE (WpPluginRegistryImpl, wp_plugin_registry_impl, + WP, PLUGIN_REGISTRY_IMPL, WpInterfaceImpl) + +WpPluginRegistryImpl * wp_plugin_registry_impl_new (void); + +void wp_plugin_registry_impl_unload (WpPluginRegistryImpl * self); + +typedef gboolean (*WpPluginFunc) (gpointer plugin, gpointer data); +gboolean wp_plugin_registry_impl_invoke_internal (WpPluginRegistryImpl * self, + WpPluginFunc func, gpointer data); + +#define wp_plugin_registry_impl_invoke(r, func, data) \ + G_STMT_START { \ + if (!(0 ? func ((WpPlugin *) NULL, data) : \ + wp_plugin_registry_impl_invoke_internal ( \ + WP_PLUGIN_REGISTRY_IMPL (r), (WpPluginFunc) func, \ + (gpointer) data))) { \ + g_warning ("No plugin handled invocation to " ##func); \ + } \ + } G_STMT_END + +G_END_DECLS + +#endif diff --git a/lib/wp/proxy-registry.c b/src/proxy-registry-impl.c similarity index 62% rename from lib/wp/proxy-registry.c rename to src/proxy-registry-impl.c index 0f7328df..68ae8eae 100644 --- a/lib/wp/proxy-registry.c +++ b/src/proxy-registry-impl.c @@ -6,14 +6,16 @@ * SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "proxy-registry.h" -#include "proxy.h" +#include "proxy-registry-impl.h" + +#include + #include #include -struct _WpProxyRegistry +struct _WpProxyRegistryImpl { - GObject parent; + WpInterfaceImpl parent; struct pw_remote *remote; struct spa_hook remote_listener; @@ -37,7 +39,10 @@ enum { static guint signals[N_SIGNALS]; -G_DEFINE_TYPE (WpProxyRegistry, wp_proxy_registry, G_TYPE_OBJECT); +static void wp_proxy_registry_impl_iface_init (WpProxyRegistryInterface * iface); + +G_DEFINE_TYPE_WITH_CODE (WpProxyRegistryImpl, wp_proxy_registry_impl, WP_TYPE_INTERFACE_IMPL, + G_IMPLEMENT_INTERFACE (WP_TYPE_PROXY_REGISTRY, wp_proxy_registry_impl_iface_init);) static gint guint32_compare (const guint32 *a, const guint32 *b) @@ -48,7 +53,7 @@ guint32_compare (const guint32 *a, const guint32 *b) static gboolean idle_notify_new_globals (gpointer data) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (data); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (data); guint i; guint32 id; @@ -58,7 +63,7 @@ idle_notify_new_globals (gpointer data) for (i = 0; i < self->new_globals->len; i++) { id = g_array_index (self->new_globals, guint32, i); g_signal_emit (self, signals[SIGNAL_NEW_PROXY_AVAILABLE], 0, - wp_proxy_registry_get_proxy (self, id)); + pw_map_lookup (&self->globals, id)); } g_array_remove_range (self->new_globals, 0, self->new_globals->len); @@ -79,8 +84,8 @@ registry_global (void * data, uint32_t id, uint32_t parent_id, uint32_t permissions, uint32_t type, uint32_t version, const struct spa_dict * props) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (data); - WpProxy *proxy = g_object_new (wp_proxy_get_type (), + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (data); + WpProxy *proxy = g_object_new (WP_TYPE_PROXY, "id", id, "parent-id", parent_id, "spa-type", type, @@ -101,7 +106,7 @@ registry_global (void * data, uint32_t id, uint32_t parent_id, static void registry_global_remove (void * data, uint32_t id) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (data); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (data); GObject *p = pw_map_lookup (&self->globals, id); g_object_unref (p); pw_map_insert_at (&self->globals, id, NULL); @@ -117,7 +122,7 @@ static void remote_state_changed (void * data, enum pw_remote_state old_state, enum pw_remote_state new_state, const char * error) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (data); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (data); switch (new_state) { case PW_REMOTE_STATE_CONNECTED: @@ -143,39 +148,39 @@ static const struct pw_remote_events remote_events = { }; static void -wp_proxy_registry_init (WpProxyRegistry * self) +wp_proxy_registry_impl_init (WpProxyRegistryImpl * self) { pw_map_init (&self->globals, 64, 64); self->new_globals = g_array_sized_new (FALSE, FALSE, sizeof (guint32), 64); } static void -wp_proxy_registry_constructed (GObject * obj) +wp_proxy_registry_impl_constructed (GObject * obj) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (obj); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (obj); pw_remote_add_listener (self->remote, &self->remote_listener, &remote_events, self); - G_OBJECT_CLASS (wp_proxy_registry_parent_class)->constructed (obj); + G_OBJECT_CLASS (wp_proxy_registry_impl_parent_class)->constructed (obj); } static void -wp_proxy_registry_finalize (GObject * obj) +wp_proxy_registry_impl_finalize (GObject * obj) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (obj); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (obj); pw_map_clear (&self->globals); g_array_unref (self->new_globals); - G_OBJECT_CLASS (wp_proxy_registry_parent_class)->finalize (obj); + G_OBJECT_CLASS (wp_proxy_registry_impl_parent_class)->finalize (obj); } static void -wp_proxy_registry_set_property (GObject * object, guint property_id, +wp_proxy_registry_impl_set_property (GObject * object, guint property_id, const GValue * value, GParamSpec * pspec) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (object); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (object); switch (property_id) { case PROP_REMOTE: @@ -188,10 +193,10 @@ wp_proxy_registry_set_property (GObject * object, guint property_id, } static void -wp_proxy_registry_get_property (GObject * object, guint property_id, +wp_proxy_registry_impl_get_property (GObject * object, guint property_id, GValue * value, GParamSpec * pspec) { - WpProxyRegistry *self = WP_PROXY_REGISTRY (object); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (object); switch (property_id) { case PROP_REMOTE: @@ -204,14 +209,14 @@ wp_proxy_registry_get_property (GObject * object, guint property_id, } static void -wp_proxy_registry_class_init (WpProxyRegistryClass * klass) +wp_proxy_registry_impl_class_init (WpProxyRegistryImplClass * klass) { GObjectClass * object_class = (GObjectClass *) klass; - object_class->constructed = wp_proxy_registry_constructed; - object_class->finalize = wp_proxy_registry_finalize; - object_class->get_property = wp_proxy_registry_get_property; - object_class->set_property = wp_proxy_registry_set_property; + object_class->constructed = wp_proxy_registry_impl_constructed; + object_class->finalize = wp_proxy_registry_impl_finalize; + object_class->get_property = wp_proxy_registry_impl_get_property; + object_class->set_property = wp_proxy_registry_impl_set_property; g_object_class_install_property (object_class, PROP_REMOTE, g_param_spec_pointer ("remote", "remote", @@ -220,64 +225,45 @@ wp_proxy_registry_class_init (WpProxyRegistryClass * klass) signals[SIGNAL_NEW_PROXY_AVAILABLE] = g_signal_new ("new-proxy-available", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, wp_proxy_get_type ()); + G_TYPE_NONE, 1, WP_TYPE_PROXY); } -/** - * wp_proxy_registry_new: (constructor) - * @remote: the `pw_remote` on which to bind - * - * Returns: (transfer full): the new #WpProxyRegistry - */ -WpProxyRegistry * -wp_proxy_registry_new (struct pw_remote * remote) +static WpProxy * +wp_proxy_registry_impl_get_proxy (WpProxyRegistry * r, guint32 global_id) { - return g_object_new (wp_proxy_registry_get_type (), "remote", remote, NULL); -} - -/** - * wp_proxy_registry_get_proxy: (method) - * @self: the registry - * @global_id: the ID of the pw_global that is represented by the proxy - * - * Returns: (transfer full): the #WpProxy that represents the global with - * @global_id - */ -WpProxy * -wp_proxy_registry_get_proxy (WpProxyRegistry * self, guint32 global_id) -{ - WpProxy *p; - - g_return_val_if_fail (WP_IS_PROXY_REGISTRY (self), NULL); - - p = pw_map_lookup (&self->globals, global_id); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (r); + WpProxy *p = pw_map_lookup (&self->globals, global_id); if (p) g_object_ref (p); return p; } -/** - * wp_proxy_registry_get_pw_remote: (skip) - * @self: the registry - * - * Returns: the underlying `pw_remote` - */ -struct pw_remote * -wp_proxy_registry_get_pw_remote (WpProxyRegistry * self) +static struct pw_registry_proxy * +wp_proxy_registry_impl_get_pw_registry_proxy (WpProxyRegistry * r) { - g_return_val_if_fail (WP_IS_PROXY_REGISTRY (self), NULL); - return self->remote; -} - -/** - * wp_proxy_registry_get_pw_registry_proxy: (skip) - * @self: the registry - * - * Returns: the underlying `pw_registry_proxy` - */ -struct pw_registry_proxy * -wp_proxy_registry_get_pw_registry_proxy (WpProxyRegistry * self) -{ - g_return_val_if_fail (WP_IS_PROXY_REGISTRY (self), NULL); + WpProxyRegistryImpl *self = WP_PROXY_REGISTRY_IMPL (r); return self->reg_proxy; } + +static void +wp_proxy_registry_impl_iface_init (WpProxyRegistryInterface * iface) +{ + iface->get_proxy = wp_proxy_registry_impl_get_proxy; + iface->get_pw_registry_proxy = wp_proxy_registry_impl_get_pw_registry_proxy; +} + +WpProxyRegistryImpl * +wp_proxy_registry_impl_new (struct pw_remote * remote) +{ + return g_object_new (wp_proxy_registry_impl_get_type (), "remote", remote, + NULL); +} + +void +wp_proxy_registry_impl_unload (WpProxyRegistryImpl * self) +{ + size_t i, size = pw_map_get_size (&self->globals); + for (i = 0; i < size; i++) { + g_clear_object (&pw_map_get_item (&self->globals, i)->data); + } +} diff --git a/src/proxy-registry-impl.h b/src/proxy-registry-impl.h new file mode 100644 index 00000000..a0e4944a --- /dev/null +++ b/src/proxy-registry-impl.h @@ -0,0 +1,27 @@ +/* WirePlumber + * + * Copyright © 2019 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef __WP_PROXY_REGISTRY_IMPL_H__ +#define __WP_PROXY_REGISTRY_IMPL_H__ + +#include + +G_BEGIN_DECLS + +struct pw_remote; + +G_DECLARE_FINAL_TYPE (WpProxyRegistryImpl, wp_proxy_registry_impl, + WP, PROXY_REGISTRY_IMPL, WpInterfaceImpl) + +WpProxyRegistryImpl * wp_proxy_registry_impl_new (struct pw_remote * remote); + +void wp_proxy_registry_impl_unload (WpProxyRegistryImpl * self); + +G_END_DECLS + +#endif