Files
wireplumber/lib/wp/core.c
George Kiagiadakis b770cf6a3e core: remove_global: remove object from the list before triggering the notification
This avoids being able to find the same object on the globals list
from code that is connected to the signal.
2019-06-18 19:39:52 +03:00

227 lines
5.2 KiB
C

/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#include "core.h"
enum {
SIGNAL_GLOBAL_ADDED,
SIGNAL_GLOBAL_REMOVED,
NUM_SIGNALS
};
static guint32 signals[NUM_SIGNALS];
struct global_object
{
GQuark key;
gpointer object;
GDestroyNotify destroy;
};
struct _WpCore
{
GObject parent;
GPtrArray *global_objects;
};
G_DEFINE_TYPE (WpCore, wp_core, G_TYPE_OBJECT)
static void
free_global_object (gpointer g)
{
g_slice_free (struct global_object, g);
}
static void
wp_core_init (WpCore * self)
{
self->global_objects = g_ptr_array_new_with_free_func (free_global_object);
}
static void
wp_core_finalize (GObject * obj)
{
WpCore *self = WP_CORE (obj);
GPtrArray *global_objects;
struct global_object *global;
gint i;
global_objects = self->global_objects;
self->global_objects = NULL;
for (i = 0; i < global_objects->len; i++) {
global = g_ptr_array_index (global_objects, i);
g_signal_emit (self, signals[SIGNAL_GLOBAL_REMOVED], global->key,
global->key, global->object);
if (global->destroy)
global->destroy (global->object);
}
g_ptr_array_unref (global_objects);
g_debug ("WpCore destroyed");
G_OBJECT_CLASS (wp_core_parent_class)->finalize (obj);
}
static void
wp_core_class_init (WpCoreClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
object_class->finalize = wp_core_finalize;
signals[SIGNAL_GLOBAL_ADDED] = g_signal_new ("global-added",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST, 0, NULL,
NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
signals[SIGNAL_GLOBAL_REMOVED] = g_signal_new ("global-removed",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_DETAILED | G_SIGNAL_RUN_LAST, 0, NULL,
NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
}
WpCore *
wp_core_new (void)
{
return g_object_new (WP_TYPE_CORE, NULL);
}
/**
* wp_core_get_global: (method)
* @self: the core
* @key: the key of the global
*
* Returns: (type GObject*) (nullable) (transfer none): the global object
* associated with @key; if multiple globals with the same key exist, the
* first one found is returned
*/
gpointer
wp_core_get_global (WpCore * self, GQuark key)
{
gint i;
struct global_object *global;
g_return_val_if_fail (WP_IS_CORE (self), NULL);
if (G_UNLIKELY (!self->global_objects))
return NULL;
for (i = 0; i < self->global_objects->len; i++) {
global = g_ptr_array_index (self->global_objects, i);
if (global->key == key)
return global->object;
}
return NULL;
}
/**
* wp_core_foreach_global: (method)
* @self: the core
* @callback: the function to call for each global object
* @user_data: data to passs to @callback
*
* Calls @callback for every global object registered
*/
void
wp_core_foreach_global (WpCore * self, WpCoreForeachGlobalFunc callback,
gpointer user_data)
{
gint i;
struct global_object *global;
g_return_if_fail (WP_IS_CORE (self));
if (G_UNLIKELY (!self->global_objects))
return;
for (i = 0; i < self->global_objects->len; i++) {
global = g_ptr_array_index (self->global_objects, i);
if (!callback (global->key, global->object, user_data))
break;
}
}
/**
* wp_core_register_global: (method)
* @self: the core
* @key: the key for this global
* @obj: (transfer full): the global object to attach
* @destroy_obj: the destroy function for @obj
*
* Registers @obj as a global object associated with @key
*/
void
wp_core_register_global (WpCore * self, GQuark key, gpointer obj,
GDestroyNotify destroy_obj)
{
struct global_object *global;
g_return_if_fail (WP_IS_CORE(self));
if (G_UNLIKELY (!self->global_objects)) {
if (destroy_obj)
destroy_obj (obj);
return;
}
global = g_slice_new0 (struct global_object);
global->key = key;
global->object = obj;
global->destroy = destroy_obj;
g_ptr_array_add (self->global_objects, global);
g_signal_emit (self, signals[SIGNAL_GLOBAL_ADDED], key, key, obj);
}
/**
* wp_core_remove_global: (method)
* @self: the core
* @key: the key for this global
* @obj: (nullable): a pointer to the global object to match, if there are
* multiple ones with the same key
*
* Detaches and unrefs the specified global from this core
*/
void
wp_core_remove_global (WpCore * self, GQuark key, gpointer obj)
{
gint i;
struct global_object *global;
struct global_object tmp;
g_return_if_fail (WP_IS_CORE (self));
if (G_UNLIKELY (!self->global_objects))
return;
for (i = 0; i < self->global_objects->len; i++) {
global = g_ptr_array_index (self->global_objects, i);
if (global->key == key && (!obj || global->object == obj))
break;
}
if (i < self->global_objects->len) {
tmp = *global;
g_ptr_array_remove_index_fast (self->global_objects, i);
g_signal_emit (self, signals[SIGNAL_GLOBAL_REMOVED], key,
key, tmp.object);
if (tmp.destroy)
tmp.destroy (tmp.object);
}
}
G_DEFINE_QUARK (endpoint, wp_global_endpoint)
G_DEFINE_QUARK (factory, wp_global_factory)
G_DEFINE_QUARK (module, wp_global_module)
G_DEFINE_QUARK (policy-manager, wp_global_policy_manager)
G_DEFINE_QUARK (remote-pipewire, wp_global_remote_pipewire)