Newer
Older
/* set the registry, so that wp_global_rm_flag() can work full-scale */
g->registry = self;
/* store it in the globals list */
if (self->globals->len <= g->id)
g_ptr_array_set_size (self->globals, g->id + 1);
g_ptr_array_index (self->globals, g->id) = wp_global_ref (g);

George Kiagiadakis
committed
}

George Kiagiadakis
committed
/* notify object managers */
for (guint i = 0; i < self->object_managers->len; i++) {
WpObjectManager *om = g_ptr_array_index (self->object_managers, i);
for (guint i = 0; i < tmp_globals->len; i++) {
WpGlobal *g = g_ptr_array_index (tmp_globals, i);
/* if global was already removed, drop it */
if (g->flags == 0)
continue;
wp_object_manager_add_global (om, g);
}

George Kiagiadakis
committed
wp_object_manager_maybe_objects_changed (om);
/*
* wp_registry_prepare_new_global:

George Kiagiadakis
committed
* @new_global: (out) (transfer full) (optional): the new global
*
* This is normally called up to 2 times in the same sync cycle:
* one from registry_global(), another from the proxy bound event
* Unfortunately the order in which those 2 events happen is specific
* to the implementation of the object, which is why this is implemented
* with a temporary globals list that get exposed later to the object managers
*/

George Kiagiadakis
committed
void
wp_registry_prepare_new_global (WpRegistry * self, guint32 id,
guint32 permissions, guint32 flag, GType type,

George Kiagiadakis
committed
WpProxy *proxy, const struct spa_dict *props,
WpGlobal ** new_global)
{
g_autoptr (WpGlobal) global = NULL;

George Kiagiadakis
committed
WpCore *core = wp_registry_get_core (self);

George Kiagiadakis
committed
g_return_if_fail (flag != 0);
g_return_if_fail (self->globals->len <= id ||
g_ptr_array_index (self->globals, id) == NULL);
for (guint i = 0; i < self->tmp_globals->len; i++) {
WpGlobal *g = g_ptr_array_index (self->tmp_globals, i);
if (g->id == id) {
global = wp_global_ref (g);
break;
}
wp_debug_object (core, "%s WpGlobal:%u type:%s proxy:%p",
global ? "reuse" : "new", id, g_type_name (type),
(global && global->proxy) ? global->proxy : proxy);
if (!global) {
global = g_rc_box_new0 (WpGlobal);
global->flags = flag;
global->id = id;
global->type = type;
global->permissions = permissions;
global->properties = props ?
wp_properties_new_copy_dict (props) : wp_properties_new_empty ();
global->proxy = proxy;
g_ptr_array_add (self->tmp_globals, wp_global_ref (global));
/* ensure we have 'object.id' so that we can filter by id on object managers */
wp_properties_setf (global->properties, PW_KEY_OBJECT_ID, "%u", global->id);
/* schedule exposing when adding the first global */
if (self->tmp_globals->len == 1) {
wp_core_sync (core, NULL, (GAsyncReadyCallback) expose_tmp_globals, self);
} else {
/* store the most permissive permissions */
if (permissions > global->permissions)
global->permissions = permissions;
global->flags |= flag;
/* store the most deep type (i.e. WpImplNode instead of WpNode),
so that object-manager interests can work more accurately
if the interest is on a specific subclass */
if (g_type_depth (type) > g_type_depth (global->type))
global->type = type;
if (proxy) {

George Kiagiadakis
committed
g_return_if_fail (global->proxy == NULL);
global->proxy = proxy;
if (props)
wp_properties_update_from_dict (global->properties, props);
}

George Kiagiadakis
committed
if (new_global)
*new_global = g_steal_pointer (&global);
}

George Kiagiadakis
committed
* wp_registry_find_object:
* @reg: the registry
* @func: (scope call): a function that takes the object being searched
* as the first argument and @data as the second. it should return TRUE if
* the object is found or FALSE otherwise
* @data: the second argument to @func
*
* Finds a registered object
*
* Returns: (transfer full) (type GObject *) (nullable): the registered object
* or NULL if not found
*/
gpointer

George Kiagiadakis
committed
wp_registry_find_object (WpRegistry *reg, GEqualFunc func, gconstpointer data)
GObject *object;
guint i;
/* prevent bad things when called from within wp_registry_clear() */
if (G_UNLIKELY (!reg->objects))
return NULL;
for (i = 0; i < reg->objects->len; i++) {
object = g_ptr_array_index (reg->objects, i);
if (func (object, data))
return g_object_ref (object);
}
}

George Kiagiadakis
committed
* wp_registry_register_object:
* @reg: the registry
* @obj: (transfer full) (type GObject*): the object to register
*
* Registers @obj with the core, making it appear on #WpObjectManager
* instances as well. The core will also maintain a ref to that object
* until it is removed.
*/
void

George Kiagiadakis
committed
wp_registry_register_object (WpRegistry *reg, gpointer obj)
g_return_if_fail (G_IS_OBJECT (obj));
/* prevent bad things when called from within wp_registry_clear() */
if (G_UNLIKELY (!reg->objects)) {
g_object_unref (obj);
return;
}
g_ptr_array_add (reg->objects, obj);
/* notify object managers */
wp_registry_notify_add_object (reg, obj);
}

George Kiagiadakis
committed
* wp_registry_remove_object:
* @reg: the registry
* @obj: (transfer none) (type GObject*): a pointer to the object to remove
*
* Detaches and unrefs the specified object from this core
*/
void

George Kiagiadakis
committed
wp_registry_remove_object (WpRegistry *reg, gpointer obj)
g_return_if_fail (G_IS_OBJECT (obj));
/* prevent bad things when called from within wp_registry_clear() */
if (G_UNLIKELY (!reg->objects))
/* notify object managers */
wp_registry_notify_rm_object (reg, obj);
g_ptr_array_remove_fast (reg->objects, obj);
}
* wp_core_install_object_manager:
* @self: the core
* @om: (transfer none): a #WpObjectManager
*
* Installs the object manager on this core, activating its internal management
* engine. This will immediately emit signals about objects added on @om
* if objects that the @om is interested in were in existence already.
*/
void
wp_core_install_object_manager (WpCore * self, WpObjectManager * om)
WpRegistry *reg;
guint i;
g_return_if_fail (WP_IS_CORE (self));
g_return_if_fail (WP_IS_OBJECT_MANAGER (om));
reg = wp_core_get_registry (self);
g_object_weak_ref (G_OBJECT (om), object_manager_destroyed, reg);
g_ptr_array_add (reg->object_managers, om);

George Kiagiadakis
committed
g_weak_ref_set (&om->core, self);
/* add pre-existing objects to the object manager,
in case it's interested in them */
for (i = 0; i < reg->globals->len; i++) {
WpGlobal *g = g_ptr_array_index (reg->globals, i);
/* check if null because the globals array can have gaps */
if (g)
wp_object_manager_add_global (om, g);
}
for (i = 0; i < reg->objects->len; i++) {
GObject *o = g_ptr_array_index (reg->objects, i);
wp_object_manager_add_object (om, o);

George Kiagiadakis
committed
}

George Kiagiadakis
committed
wp_object_manager_maybe_objects_changed (om);
}
/* WpGlobal */
G_DEFINE_BOXED_TYPE (WpGlobal, wp_global, wp_global_ref, wp_global_unref)
void
wp_global_rm_flag (WpGlobal *global, guint rm_flag)
WpRegistry *reg = global->registry;
/* no flag to remove */
if (!(global->flags & rm_flag))
return;
/* global was owned by the proxy; by removing the flag, we clear out
also the proxy pointer, which is presumably no longer valid and we
notify all listeners that the proxy is gone */
if (rm_flag == WP_GLOBAL_FLAG_OWNED_BY_PROXY) {
global->flags &= ~WP_GLOBAL_FLAG_OWNED_BY_PROXY;
if (reg && global->proxy) {
wp_registry_notify_rm_object (reg, global->proxy);
}
global->proxy = NULL;
}
/* registry removed the global */
else if (rm_flag == WP_GLOBAL_FLAG_APPEARS_ON_REGISTRY) {
global->flags &= ~WP_GLOBAL_FLAG_APPEARS_ON_REGISTRY;
/* destroy the proxy if it exists */
if (global->proxy) {
if (reg)
wp_registry_notify_rm_object (reg, global->proxy);
wp_proxy_destroy (global->proxy);
/* if the proxy is not owning the global, unref it */
if (global->flags == 0)
g_object_unref (global->proxy);
global->proxy = NULL;
}
/* drop the registry's ref on global when it has no flags anymore */
if (global->flags == 0 && reg) {
g_clear_pointer (&g_ptr_array_index (reg->globals, global->id), wp_global_unref);
}
}
struct pw_proxy *
wp_global_bind (WpGlobal * global)
g_return_val_if_fail (global->proxy, NULL);
g_return_val_if_fail (global->registry, NULL);
WpProxyClass *klass = WP_PROXY_GET_CLASS (global->proxy);
return pw_registry_bind (global->registry->pw_registry, global->id,
klass->pw_iface_type, klass->pw_iface_version, 0);