2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstobject.c: Fundamental class used for all of GStreamer
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 #include "gst_private.h"
25 #include "gstobject.h"
28 /* Object signals and args */
32 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
49 GType _gst_object_type = 0;
50 static GHashTable *object_name_counts = NULL;
51 G_LOCK_DEFINE_STATIC (object_name_mutex);
53 typedef struct _GstSignalObject GstSignalObject;
54 typedef struct _GstSignalObjectClass GstSignalObjectClass;
56 static GType gst_signal_object_get_type (void);
57 static void gst_signal_object_class_init (GstSignalObjectClass *klass);
58 static void gst_signal_object_init (GstSignalObject *object);
60 static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
62 static void gst_object_class_init (GstObjectClass *klass);
63 static void gst_object_init (GstObject *object);
65 static void gst_object_set_property (GObject * object, guint prop_id, const GValue * value,
67 static void gst_object_get_property (GObject * object, guint prop_id, GValue * value,
70 static void gst_object_dispose (GObject *object);
71 static void gst_object_finalize (GObject *object);
73 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
74 static void gst_object_real_restore_thyself (GstObject *object, xmlNodePtr self);
77 static GObjectClass *parent_class = NULL;
78 static guint gst_object_signals[LAST_SIGNAL] = { 0 };
81 gst_object_get_type (void)
83 if (!_gst_object_type) {
84 static const GTypeInfo object_info = {
85 sizeof (GstObjectClass),
88 (GClassInitFunc) gst_object_class_init,
93 (GInstanceInitFunc) gst_object_init,
96 _gst_object_type = g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info, G_TYPE_FLAG_ABSTRACT);
98 return _gst_object_type;
102 gst_object_class_init (GstObjectClass *klass)
104 GObjectClass *gobject_class;
106 gobject_class = (GObjectClass*) klass;
108 parent_class = g_type_class_ref (G_TYPE_OBJECT);
110 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_object_set_property);
111 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_object_get_property);
113 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NAME,
114 g_param_spec_string ("name", "Name", "The name of the object",
115 NULL, G_PARAM_READWRITE));
117 gst_object_signals[PARENT_SET] =
118 g_signal_new ("parent_set", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
119 G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
120 g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
122 gst_object_signals[PARENT_UNSET] =
123 g_signal_new ("parent_unset", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
124 G_STRUCT_OFFSET (GstObjectClass, parent_unset), NULL, NULL,
125 g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
127 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
128 gst_object_signals[OBJECT_SAVED] =
129 g_signal_new ("object_saved", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
130 G_STRUCT_OFFSET (GstObjectClass, object_saved), NULL, NULL,
131 g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
134 klass->restore_thyself = gst_object_real_restore_thyself;
137 klass->path_string_separator = "/";
139 klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
141 gobject_class->dispose = gst_object_dispose;
142 gobject_class->finalize = gst_object_finalize;
146 gst_object_init (GstObject *object)
148 object->lock = g_mutex_new();
149 object->parent = NULL;
153 GST_FLAG_SET (object, GST_FLOATING);
158 * @object: GstObject to reference
160 * Increments the refence count on the object.
162 * Returns: A pointer to the object
165 gst_object_ref (GstObject *object)
167 g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
169 GST_DEBUG (GST_CAT_REFCOUNTING, "ref '%s' %d->%d",GST_OBJECT_NAME(object),
170 G_OBJECT(object)->ref_count,G_OBJECT(object)->ref_count+1);
172 g_object_ref (G_OBJECT (object));
178 * @object: GstObject to unreference
180 * Decrements the refence count on the object. If reference count hits
181 * zero, destroy the object.
184 gst_object_unref (GstObject *object)
186 g_return_if_fail (GST_IS_OBJECT (object));
188 GST_DEBUG (GST_CAT_REFCOUNTING, "unref '%s' %d->%d",GST_OBJECT_NAME(object),
189 G_OBJECT(object)->ref_count,G_OBJECT(object)->ref_count-1);
191 g_object_unref (G_OBJECT (object));
196 * @object: GstObject to sink
198 * Removes floating reference on an object. Any newly created object has
199 * a refcount of 1 and is FLOATING. This function should be used when
200 * creating a new object to symbolically 'take ownership of' the object.
201 * Use #gst_object_set_parent to have this done for you.
204 gst_object_sink (GstObject *object)
206 g_return_if_fail (object != NULL);
207 g_return_if_fail (GST_IS_OBJECT (object));
209 GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'",GST_OBJECT_NAME(object));
210 if (GST_OBJECT_FLOATING (object))
212 GST_FLAG_UNSET (object, GST_FLOATING);
213 gst_object_unref (object);
218 * gst_object_destroy:
219 * @object: GstObject to destroy
221 * Destroy the object.
225 gst_object_destroy (GstObject *object)
227 g_return_if_fail (object != NULL);
228 g_return_if_fail (GST_IS_OBJECT (object));
230 GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'",GST_OBJECT_NAME(object));
231 if (!GST_OBJECT_DESTROYED (object))
233 /* need to hold a reference count around all class method
236 g_object_run_dispose (G_OBJECT (object));
241 gst_object_dispose (GObject *object)
243 GST_DEBUG (GST_CAT_REFCOUNTING, "dispose '%s'",GST_OBJECT_NAME(object));
244 GST_FLAG_SET (GST_OBJECT (object), GST_DESTROYED);
245 GST_OBJECT_PARENT (object) = NULL;
247 parent_class->dispose (object);
250 /* finilize is called when the object has to free its resources */
252 gst_object_finalize (GObject *object)
254 GstObject *gstobject = GST_OBJECT (object);
256 GST_DEBUG (GST_CAT_REFCOUNTING, "finalize '%s'",GST_OBJECT_NAME(object));
258 g_signal_handlers_destroy (object);
260 if (gstobject->name != NULL)
261 g_free (gstobject->name);
263 g_mutex_free (gstobject->lock);
265 parent_class->finalize (object);
269 gst_object_set_name_default (GstObject *object)
273 const gchar *type_name;
275 type_name = G_OBJECT_TYPE_NAME (object);
277 G_LOCK (object_name_mutex);
279 if (!object_name_counts)
280 object_name_counts = g_hash_table_new (g_str_hash, g_str_equal);
282 count = GPOINTER_TO_INT (g_hash_table_lookup (object_name_counts, type_name));
283 g_hash_table_insert (object_name_counts, g_strdup (type_name), GINT_TO_POINTER (count+1));
285 G_UNLOCK (object_name_mutex);
287 /* GstFooSink -> foosinkN */
288 if (strncmp (type_name, "Gst", 3) == 0)
290 tmp = g_strdup_printf ("%s%d", type_name, count);
291 name = g_ascii_strdown (tmp, strlen (tmp));
294 gst_object_set_name (object, name);
299 * gst_object_set_name:
300 * @object: GstObject to set the name of
301 * @name: new name of object
303 * Set the name of the object.
306 gst_object_set_name (GstObject *object, const gchar *name)
308 g_return_if_fail (object != NULL);
309 g_return_if_fail (GST_IS_OBJECT (object));
311 if (object->name != NULL)
312 g_free (object->name);
315 object->name = g_strdup (name);
317 gst_object_set_name_default (object);
321 * gst_object_get_name:
322 * @object: GstObject to get the name of
324 * Get the name of the object.
326 * Returns: name of the object
329 gst_object_get_name (GstObject *object)
331 g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
337 * gst_object_set_parent:
338 * @object: GstObject to set parent of
339 * @parent: new parent of object
341 * Set the parent of the object. The object's reference count is
343 * signals the parent-set signal
346 gst_object_set_parent (GstObject *object, GstObject *parent)
348 g_return_if_fail (object != NULL);
349 g_return_if_fail (GST_IS_OBJECT (object));
350 g_return_if_fail (parent != NULL);
351 g_return_if_fail (GST_IS_OBJECT (parent));
352 g_return_if_fail (object != parent);
354 if (object->parent != NULL) {
355 GST_ERROR_OBJECT (object,object->parent, "object's parent is already set, must unparent first");
359 gst_object_ref (object);
360 gst_object_sink (object);
361 object->parent = parent;
363 g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
367 * gst_object_get_parent:
368 * @object: GstObject to get parent of
370 * Return the parent of the object.
372 * Returns: parent of the object
375 gst_object_get_parent (GstObject *object)
377 g_return_val_if_fail (object != NULL, NULL);
378 g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
380 return object->parent;
384 * gst_object_unparent:
385 * @object: GstObject to unparent
387 * Clear the parent of the object, removing the associated reference.
390 gst_object_unparent (GstObject *object)
392 g_return_if_fail (object != NULL);
393 g_return_if_fail (GST_IS_OBJECT(object));
394 if (object->parent == NULL)
397 GST_DEBUG (GST_CAT_REFCOUNTING, "unparent '%s'",GST_OBJECT_NAME(object));
399 g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0, object->parent);
401 object->parent = NULL;
402 gst_object_unref (object);
406 * gst_object_check_uniqueness:
407 * @list: a list of #GstObject to check through
408 * @name: the name to search for
410 * This function checks through the list of objects to see if the name
411 * given appears in the list as the name of an object. It returns TRUE if
412 * the name does not exist in the list.
414 * Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
417 gst_object_check_uniqueness (GList *list, const gchar *name)
419 g_return_val_if_fail (name != NULL, FALSE);
422 GstObject *child = GST_OBJECT (list->data);
424 list = g_list_next (list);
426 if (strcmp (GST_OBJECT_NAME (child), name) == 0)
434 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
436 * gst_object_save_thyself:
437 * @object: GstObject to save
438 * @parent: The parent XML node to save the object into
440 * Saves the given object into the parent XML node.
442 * Returns: the new xmlNodePtr with the saved object
445 gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
447 GstObjectClass *oclass;
449 g_return_val_if_fail (object != NULL, parent);
450 g_return_val_if_fail (GST_IS_OBJECT (object), parent);
451 g_return_val_if_fail (parent != NULL, parent);
453 oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(object);
454 if (oclass->save_thyself)
455 oclass->save_thyself (object, parent);
457 g_signal_emit (G_OBJECT (object), gst_object_signals[OBJECT_SAVED], 0, parent);
463 * gst_object_restore_thyself:
464 * @object: GstObject to load into
465 * @self: The XML node to load the object from
467 * Restores the given object with the data from the parent XML node.
470 gst_object_restore_thyself (GstObject *object, xmlNodePtr self)
472 GstObjectClass *oclass;
474 g_return_if_fail (object != NULL);
475 g_return_if_fail (GST_IS_OBJECT (object));
476 g_return_if_fail (self != NULL);
478 oclass = (GstObjectClass *) G_OBJECT_GET_CLASS(object);
479 if (oclass->restore_thyself)
480 oclass->restore_thyself (object, self);
484 gst_object_real_restore_thyself (GstObject *object, xmlNodePtr self)
486 g_return_if_fail (object != NULL);
487 g_return_if_fail (GST_IS_OBJECT (object));
488 g_return_if_fail (self != NULL);
490 /* FIXME: the signalobject stuff doesn't work
491 * gst_class_signal_emit_by_name (object, "object_loaded", self); */
493 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
496 gst_object_set_property (GObject* object, guint prop_id,
497 const GValue* value, GParamSpec* pspec)
499 GstObject *gstobject;
501 /* it's not null if we got it, but it might not be ours */
502 g_return_if_fail (GST_IS_OBJECT (object));
504 gstobject = GST_OBJECT (object);
508 gst_object_set_name (gstobject, g_value_get_string (value));
511 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
517 gst_object_get_property (GObject* object, guint prop_id,
518 GValue* value, GParamSpec* pspec)
520 GstObject *gstobject;
522 /* it's not null if we got it, but it might not be ours */
523 g_return_if_fail (GST_IS_OBJECT (object));
525 gstobject = GST_OBJECT (object);
529 g_value_set_string (value, (gchar*)GST_OBJECT_NAME (gstobject));
532 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
538 * gst_object_get_path_string:
539 * @object: GstObject to get the path from
541 * Generates a string describing the path of the object in
542 * the object hierarchy. Only useful (or used) for debugging
544 * Returns: a string describing the path of the object
547 gst_object_get_path_string (GstObject *object)
549 GSList *parentage = NULL;
552 gchar *prevpath, *path;
553 const char *component;
554 gchar *separator = "";
555 gboolean free_component;
557 parentage = g_slist_prepend (NULL, object);
559 path = g_strdup ("");
561 /* first walk the object hierarchy to build a list of the parents */
563 if (GST_IS_OBJECT (object)) {
564 parent = gst_object_get_parent (object);
566 parentage = g_slist_prepend (parentage, NULL);
570 if (parent != NULL) {
571 parentage = g_slist_prepend (parentage, parent);
575 } while (object != NULL);
577 /* then walk the parent list and print them out */
580 if (GST_IS_OBJECT (parents->data)) {
581 GstObjectClass *oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(parents->data);
583 component = gst_object_get_name (parents->data);
584 separator = oclass->path_string_separator;
585 free_component = FALSE;
587 component = g_strdup_printf("%p",parents->data);
589 free_component = TRUE;
593 path = g_strjoin (separator, prevpath, component, NULL);
596 g_free((gchar *)component);
598 parents = g_slist_next(parents);
601 g_slist_free (parentage);
608 struct _GstSignalObject {
612 struct _GstSignalObjectClass {
613 GObjectClass parent_class;
616 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
617 void (*object_loaded) (GstSignalObject *object, GstObject *new, xmlNodePtr self);
618 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
622 gst_signal_object_get_type (void)
624 static GType signal_object_type = 0;
626 if (!signal_object_type) {
627 static const GTypeInfo signal_object_info = {
628 sizeof(GstSignalObjectClass),
631 (GClassInitFunc)gst_signal_object_class_init,
634 sizeof(GstSignalObject),
636 (GInstanceInitFunc)gst_signal_object_init,
639 signal_object_type = g_type_register_static(G_TYPE_OBJECT, "GstSignalObject", &signal_object_info, 0);
641 return signal_object_type;
645 gst_signal_object_class_init (GstSignalObjectClass *klass)
647 GObjectClass *gobject_class;
649 gobject_class = (GObjectClass*) klass;
651 parent_class = g_type_class_ref (G_TYPE_OBJECT);
653 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
654 gst_signal_object_signals[SO_OBJECT_LOADED] =
655 g_signal_new("object_loaded", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
656 G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
657 gst_marshal_VOID__OBJECT_POINTER,G_TYPE_NONE,2,
658 G_TYPE_OBJECT,G_TYPE_POINTER);
663 gst_signal_object_init (GstSignalObject *object)
668 * gst_class_signal_connect
669 * @klass: the GstObjectClass to attach the signal to
670 * @name: the name of the signal to attach to
671 * @func: the signal function
672 * @func_data: a pointer to user data
674 * Connect to a class signal.
676 * Returns: the signal id.
679 gst_class_signal_connect (GstObjectClass *klass,
684 return g_signal_connect (klass->signal_object, name, func, func_data);
687 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
689 * gst_class_signal_emit_by_name:
690 * @object: the object that sends the signal
691 * @name: the name of the signal to emit
692 * @self: data for the signal
694 * emits the named class signal.
697 gst_class_signal_emit_by_name (GstObject *object,
701 GstObjectClass *oclass;
703 oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(object);
705 g_signal_emit_by_name (oclass->signal_object, name, object, self);
708 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */