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"
27 /* Object signals and args */
31 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
48 GType _gst_object_type = 0;
50 typedef struct _GstSignalObject GstSignalObject;
51 typedef struct _GstSignalObjectClass GstSignalObjectClass;
53 static GType gst_signal_object_get_type (void);
54 static void gst_signal_object_class_init (GstSignalObjectClass *klass);
55 static void gst_signal_object_init (GstSignalObject *object);
57 static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
59 static void gst_object_class_init (GstObjectClass *klass);
60 static void gst_object_init (GstObject *object);
62 static void gst_object_set_property (GObject * object, guint prop_id, const GValue * value,
64 static void gst_object_get_property (GObject * object, guint prop_id, GValue * value,
66 static void gst_object_dispatch_properties_changed (GObject * object, guint n_pspecs, GParamSpec **pspecs);
68 static void gst_object_dispose (GObject *object);
69 static void gst_object_finalize (GObject *object);
71 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
72 static void gst_object_real_restore_thyself (GstObject *object, xmlNodePtr self);
75 static GObjectClass *parent_class = NULL;
76 static guint gst_object_signals[LAST_SIGNAL] = { 0 };
79 gst_object_get_type (void)
81 if (!_gst_object_type) {
82 static const GTypeInfo object_info = {
83 sizeof (GstObjectClass),
86 (GClassInitFunc) gst_object_class_init,
91 (GInstanceInitFunc) gst_object_init,
94 _gst_object_type = g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info, G_TYPE_FLAG_ABSTRACT);
96 return _gst_object_type;
100 gst_object_class_init (GstObjectClass *klass)
102 GObjectClass *gobject_class;
104 gobject_class = (GObjectClass*) klass;
106 parent_class = g_type_class_ref (G_TYPE_OBJECT);
108 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_object_set_property);
109 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_object_get_property);
110 gobject_class->dispatch_properties_changed = GST_DEBUG_FUNCPTR (gst_object_dispatch_properties_changed);
112 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NAME,
113 g_param_spec_string ("name", "Name", "The name of the object",
114 NULL, G_PARAM_READWRITE));
116 gst_object_signals[PARENT_SET] =
117 g_signal_new ("parent_set", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
118 G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
119 g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
121 gst_object_signals[DEEP_NOTIFY] =
122 g_signal_new ("deep_notify", G_TYPE_FROM_CLASS (klass),
123 G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS,
124 G_STRUCT_OFFSET (GstObjectClass, deep_notify), NULL, NULL,
125 gst_marshal_VOID__OBJECT_PARAM, G_TYPE_NONE,
126 2, G_TYPE_OBJECT, G_TYPE_PARAM);
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\n",GST_OBJECT_NAME(object),
170 G_OBJECT(object)->ref_count,G_OBJECT(object)->ref_count+1);
172 g_object_ref (G_OBJECT (object));
175 #define gst_object_ref gst_object_ref
179 * @object: GstObject to unreference
181 * Decrements the refence count on the object. If reference count hits
182 * zero, destroy the object.
185 gst_object_unref (GstObject *object)
187 g_return_if_fail (GST_IS_OBJECT (object));
189 GST_DEBUG (GST_CAT_REFCOUNTING, "unref '%s' %d->%d\n",GST_OBJECT_NAME(object),
190 G_OBJECT(object)->ref_count,G_OBJECT(object)->ref_count-1);
192 g_object_unref (G_OBJECT (object));
194 #define gst_object_unref gst_object_unref
198 * @object: GstObject to sink
200 * Removes floating reference on an object. Any newly created object has
201 * a refcount of 1 and is FLOATING. This function should be used when
202 * creating a new object to symbolically 'take ownership of' the object.
205 gst_object_sink (GstObject *object)
207 g_return_if_fail (object != NULL);
208 g_return_if_fail (GST_IS_OBJECT (object));
210 GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'\n",GST_OBJECT_NAME(object));
211 if (GST_OBJECT_FLOATING (object))
213 GST_FLAG_UNSET (object, GST_FLOATING);
214 gst_object_unref (object);
219 * gst_object_destroy:
220 * @object: GstObject to destroy
222 * 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'\n",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'\n",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'\n",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:
270 * @object: GstObject to set the name of
271 * @name: new name of object
273 * Set the name of the object.
276 gst_object_set_name (GstObject *object, const gchar *name)
278 g_return_if_fail (object != NULL);
279 g_return_if_fail (GST_IS_OBJECT (object));
280 g_return_if_fail (name != NULL);
282 if (object->name != NULL)
283 g_free (object->name);
285 object->name = g_strdup (name);
289 * gst_object_get_name:
290 * @object: GstObject to get the name of
292 * Get the name of the object.
294 * Returns: name of the object
297 gst_object_get_name (GstObject *object)
299 g_return_val_if_fail (object != NULL, NULL);
300 g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
306 * gst_object_set_parent:
307 * @object: GstObject to set parent of
308 * @parent: new parent of object
310 * Set the parent of the object. The object's reference count is
312 * signals the parent-set signal
315 gst_object_set_parent (GstObject *object, GstObject *parent)
317 g_return_if_fail (object != NULL);
318 g_return_if_fail (GST_IS_OBJECT (object));
319 g_return_if_fail (parent != NULL);
320 g_return_if_fail (GST_IS_OBJECT (parent));
321 g_return_if_fail (object != parent);
323 if (object->parent != NULL) {
324 GST_ERROR_OBJECT (object,object->parent, "object's parent is already set, must unparent first");
328 gst_object_ref (object);
329 gst_object_sink (object);
330 object->parent = parent;
332 g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
336 * gst_object_get_parent:
337 * @object: GstObject to get parent of
339 * Return the parent of the object.
341 * Returns: parent of the object
344 gst_object_get_parent (GstObject *object)
346 g_return_val_if_fail (object != NULL, NULL);
347 g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
349 return object->parent;
353 * gst_object_unparent:
354 * @object: GstObject to unparent
356 * Clear the parent of the object, removing the associated reference.
359 gst_object_unparent (GstObject *object)
361 g_return_if_fail (object != NULL);
362 g_return_if_fail (GST_IS_OBJECT(object));
363 if (object->parent == NULL)
366 GST_DEBUG (GST_CAT_REFCOUNTING, "unparent '%s'\n",GST_OBJECT_NAME(object));
368 object->parent = NULL;
369 gst_object_unref (object);
374 * @object: GstObject to reference
376 * Increments the refence count on the object.
378 * Returns: Apointer to the Object
380 #ifndef gst_object_ref
382 gst_object_ref (GstObject *object)
384 g_return_if_fail (object != NULL, NULL);
385 g_return_if_fail (GST_IS_OBJECT (object), NULL);
387 /* #ifdef HAVE_ATOMIC_H */
388 /* g_return_if_fail (atomic_read (&(object->refcount)) > 0); */
389 /* atomic_inc (&(object->refcount)) */
391 g_return_if_fail (object->refcount > 0);
393 /* object->refcount++; */
394 g_object_ref((GObject *)object);
400 #endif /* gst_object_ref */
404 * @object: GstObject to unreference
406 * Decrements the refence count on the object. If reference count hits
407 * zero, destroy the object.
409 #ifndef gst_object_unref
411 gst_object_unref (GstObject *object)
415 g_return_if_fail (object != NULL);
416 g_return_if_fail (GST_IS_OBJECT (object));
419 g_return_if_fail (atomic_read (&(object->refcount)) > 0);
420 reftest = atomic_dec_and_test (&(object->refcount))
422 g_return_if_fail (object->refcount > 0);
425 reftest = (object->refcount == 0);
429 /* if we ended up with the refcount at zero */
431 /* get the count to 1 for gtk_object_destroy() */
433 atomic_set (&(object->refcount),1);
435 object->refcount = 1;
438 gtk_object_destroy (G_OBJECT (object));
439 /* drop the refcount back to zero */
441 atomic_set (&(object->refcount),0);
443 object->refcount = 0;
445 /* finalize the object */
446 /* FIXME this is an evil hack that should be killed */
447 /* FIXMEFIXMEFIXMEFIXME */
448 /* gtk_object_finalize(G_OBJECT(object)); */
451 #endif /* gst_object_unref */
454 * gst_object_check_uniqueness:
455 * @list: a list of #GstObject to check through
456 * @name: the name to search for
458 * This function checks through the list of objects to see if the name
459 * given appears in the list as the name of an object. It returns TRUE if
460 * the name does not exist in the list.
462 * Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
465 gst_object_check_uniqueness (GList *list, const gchar *name)
467 g_return_val_if_fail (name != NULL, FALSE);
470 GstObject *child = GST_OBJECT (list->data);
472 list = g_list_next(list);
474 if (strcmp(GST_OBJECT_NAME(child), name) == 0)
482 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
484 * gst_object_save_thyself:
485 * @object: GstObject to save
486 * @parent: The parent XML node to save the object into
488 * Saves the given object into the parent XML node.
490 * Returns: the new xmlNodePtr with the saved object
493 gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
495 GstObjectClass *oclass;
497 g_return_val_if_fail (object != NULL, parent);
498 g_return_val_if_fail (GST_IS_OBJECT (object), parent);
499 g_return_val_if_fail (parent != NULL, parent);
501 oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(object);
502 if (oclass->save_thyself)
503 oclass->save_thyself (object, parent);
505 g_signal_emit (G_OBJECT (object), gst_object_signals[OBJECT_SAVED], 0, parent);
511 * gst_object_restore_thyself:
512 * @object: GstObject to load into
513 * @self: The XML node to load the object from
515 * Restores the given object with the data from the parent XML node.
518 gst_object_restore_thyself (GstObject *object, xmlNodePtr self)
520 GstObjectClass *oclass;
522 g_return_if_fail (object != NULL);
523 g_return_if_fail (GST_IS_OBJECT (object));
524 g_return_if_fail (self != NULL);
526 oclass = (GstObjectClass *) G_OBJECT_GET_CLASS(object);
527 if (oclass->restore_thyself)
528 oclass->restore_thyself (object, self);
532 gst_object_real_restore_thyself (GstObject *object, xmlNodePtr self)
534 GstObjectClass *oclass;
536 g_return_if_fail (object != NULL);
537 g_return_if_fail (GST_IS_OBJECT (object));
538 g_return_if_fail (self != NULL);
540 /* FIXME: the signalobject stuff doesn't work
541 * gst_class_signal_emit_by_name (object, "object_loaded", self); */
543 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
546 gst_object_set_property (GObject* object, guint prop_id,
547 const GValue* value, GParamSpec* pspec)
549 GstObject *gstobject;
551 /* it's not null if we got it, but it might not be ours */
552 g_return_if_fail (GST_IS_OBJECT (object));
554 gstobject = GST_OBJECT (object);
558 gst_object_set_name (gstobject, g_value_get_string (value));
561 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
567 gst_object_get_property (GObject* object, guint prop_id,
568 GValue* value, GParamSpec* pspec)
570 GstObject *gstobject;
572 /* it's not null if we got it, but it might not be ours */
573 g_return_if_fail (GST_IS_OBJECT (object));
575 gstobject = GST_OBJECT (object);
579 g_value_set_string (value, (gchar*)GST_OBJECT_NAME (gstobject));
582 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
587 gst_object_dispatch_properties_changed (GObject *object,
591 GstObject *gst_object;
594 /* do the standard dispatching */
595 parent_class->dispatch_properties_changed (object, n_pspecs, pspecs);
597 /* now let the parent dispatch those, too */
598 gst_object = GST_OBJECT (object);
601 /* need own category? */
602 GST_DEBUG (GST_CAT_EVENT, "deep notification from %s to %s\n", GST_OBJECT_NAME (object), GST_OBJECT_NAME (gst_object));
603 for (i = 0; i < n_pspecs; i++)
604 g_signal_emit (gst_object, gst_object_signals[DEEP_NOTIFY], g_quark_from_string (pspecs[i]->name), (GstObject *) object, pspecs[i]);
606 gst_object = GST_OBJECT_PARENT (gst_object);
611 * gst_object_get_path_string:
612 * @object: GstObject to get the path from
614 * Generates a string describing the path of the object in
615 * the object hierarchy. Usefull for debugging
617 * Returns: a string describing the path of the object
620 gst_object_get_path_string (GstObject *object)
622 GSList *parentage = NULL;
625 gchar *prevpath, *path;
626 const char *component;
627 gchar *separator = "";
628 gboolean free_component;
630 parentage = g_slist_prepend (NULL, object);
632 path = g_strdup ("");
634 /* first walk the object hierarchy to build a list of the parents */
636 if (GST_IS_OBJECT (object)) {
637 parent = gst_object_get_parent (object);
639 parentage = g_slist_prepend (parentage, NULL);
643 if (parent != NULL) {
644 parentage = g_slist_prepend (parentage, parent);
648 } while (object != NULL);
650 /* then walk the parent list and print them out */
653 if (GST_IS_OBJECT (parents->data)) {
654 GstObjectClass *oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(parents->data);
656 component = gst_object_get_name (parents->data);
657 separator = oclass->path_string_separator;
658 free_component = FALSE;
660 component = g_strdup_printf("%p",parents->data);
662 free_component = TRUE;
666 path = g_strjoin (separator, prevpath, component, NULL);
669 g_free((gchar *)component);
671 parents = g_slist_next(parents);
674 g_slist_free (parentage);
681 struct _GstSignalObject {
685 struct _GstSignalObjectClass {
686 GObjectClass parent_class;
689 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
690 void (*object_loaded) (GstSignalObject *object, GstObject *new, xmlNodePtr self);
691 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
695 gst_signal_object_get_type (void)
697 static GType signal_object_type = 0;
699 if (!signal_object_type) {
700 static const GTypeInfo signal_object_info = {
701 sizeof(GstSignalObjectClass),
704 (GClassInitFunc)gst_signal_object_class_init,
707 sizeof(GstSignalObject),
709 (GInstanceInitFunc)gst_signal_object_init,
712 signal_object_type = g_type_register_static(G_TYPE_OBJECT, "GstSignalObject", &signal_object_info, 0);
714 return signal_object_type;
718 gst_signal_object_class_init (GstSignalObjectClass *klass)
720 GObjectClass *gobject_class;
722 gobject_class = (GObjectClass*) klass;
724 parent_class = g_type_class_ref (G_TYPE_OBJECT);
726 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
727 gst_signal_object_signals[SO_OBJECT_LOADED] =
728 g_signal_new("object_loaded", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
729 G_STRUCT_OFFSET (GstObjectClass, parent_set), NULL, NULL,
730 gst_marshal_VOID__OBJECT_POINTER,G_TYPE_NONE,2,
731 G_TYPE_OBJECT,G_TYPE_POINTER);
736 gst_signal_object_init (GstSignalObject *object)
741 * gst_class_signal_connect
742 * @klass: the GstObjectClass to attach the signal to
743 * @name: the name of the signal to attach to
744 * @func: the signal function
745 * @func_data: a pointer to user data
747 * Connect to a class signal.
749 * Returns: the signal id.
752 gst_class_signal_connect (GstObjectClass *klass,
757 return g_signal_connect (klass->signal_object, name, func, func_data);
760 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
762 * gst_class_signal_emit_by_name:
763 * @object: the object that sends the signal
764 * @name: the name of the signal to emit
765 * @self: data for the signal
767 * emits the named class signal.
770 gst_class_signal_emit_by_name (GstObject *object,
774 GstObjectClass *oclass;
776 oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(object);
778 g_signal_emit_by_name (oclass->signal_object, name, object, self);
781 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */