Added parent_unset signal to gstobject for completeness
[platform/upstream/gstreamer.git] / gst / gstobject.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstobject.c: Fundamental class used for all of GStreamer
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include "gst_private.h"
24
25 #include "gstobject.h"
26 #include "gstlog.h"
27
28 /* Object signals and args */
29 enum {
30   PARENT_SET,
31   PARENT_UNSET,
32 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
33   OBJECT_SAVED,
34 #endif
35   LAST_SIGNAL
36 };
37
38 enum {
39   ARG_0,
40   ARG_NAME,
41   /* FILL ME */
42 };
43
44 enum {
45   SO_OBJECT_LOADED,
46   SO_LAST_SIGNAL
47 };
48
49 GType _gst_object_type = 0;
50 static GHashTable *object_name_counts = NULL;
51 G_LOCK_DEFINE_STATIC (object_name_mutex);
52
53 typedef struct _GstSignalObject GstSignalObject;
54 typedef struct _GstSignalObjectClass GstSignalObjectClass;
55
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);
59
60 static guint gst_signal_object_signals[SO_LAST_SIGNAL] = { 0 };
61
62 static void             gst_object_class_init           (GstObjectClass *klass);
63 static void             gst_object_init                 (GstObject *object);
64
65 static void             gst_object_set_property         (GObject * object, guint prop_id, const GValue * value,
66                                                          GParamSpec * pspec);
67 static void             gst_object_get_property         (GObject * object, guint prop_id, GValue * value,
68                                                          GParamSpec * pspec);
69
70 static void             gst_object_dispose              (GObject *object);
71 static void             gst_object_finalize             (GObject *object);
72
73 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
74 static void             gst_object_real_restore_thyself (GstObject *object, xmlNodePtr self);
75 #endif
76
77 static GObjectClass *parent_class = NULL;
78 static guint gst_object_signals[LAST_SIGNAL] = { 0 };
79
80 GType
81 gst_object_get_type (void)
82 {
83   if (!_gst_object_type) {
84     static const GTypeInfo object_info = {
85       sizeof (GstObjectClass),
86       NULL,
87       NULL,
88       (GClassInitFunc) gst_object_class_init,
89       NULL,
90       NULL,
91       sizeof (GstObject),
92       32,
93       (GInstanceInitFunc) gst_object_init,
94       NULL
95     };
96     _gst_object_type = g_type_register_static (G_TYPE_OBJECT, "GstObject", &object_info, G_TYPE_FLAG_ABSTRACT);
97   }
98   return _gst_object_type;
99 }
100
101 static void
102 gst_object_class_init (GstObjectClass *klass)
103 {
104   GObjectClass *gobject_class;
105
106   gobject_class = (GObjectClass*) klass;
107
108   parent_class = g_type_class_ref (G_TYPE_OBJECT);
109
110   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_object_set_property);
111   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_object_get_property);
112
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));
116
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,
121                   G_TYPE_OBJECT);
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,
126                   G_TYPE_OBJECT);
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,
132                   G_TYPE_POINTER);
133   
134   klass->restore_thyself = gst_object_real_restore_thyself;
135 #endif
136
137   klass->path_string_separator = "/";
138
139   klass->signal_object = g_object_new (gst_signal_object_get_type (), NULL);
140
141   gobject_class->dispose = gst_object_dispose;
142   gobject_class->finalize = gst_object_finalize;
143 }
144
145 static void
146 gst_object_init (GstObject *object)
147 {
148   object->lock = g_mutex_new();
149   object->parent = NULL;
150   object->name = NULL;
151
152   object->flags = 0;
153   GST_FLAG_SET (object, GST_FLOATING);
154 }
155
156 /**
157  * gst_object_ref:
158  * @object: GstObject to reference
159  *
160  * Increments the refence count on the object.
161  *
162  * Returns: A pointer to the object
163  */
164 GstObject*
165 gst_object_ref (GstObject *object)
166 {
167   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
168
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);
171
172   g_object_ref (G_OBJECT (object));
173   return object;
174 }
175
176 /**
177  * gst_object_unref:
178  * @object: GstObject to unreference
179  *
180  * Decrements the refence count on the object.  If reference count hits
181  * zero, destroy the object.
182  */
183 void
184 gst_object_unref (GstObject *object)
185 {
186   g_return_if_fail (GST_IS_OBJECT (object));
187
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);
190
191   g_object_unref (G_OBJECT (object));
192 }
193
194 /**
195  * gst_object_sink:
196  * @object: GstObject to sink
197  *
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.
202  */
203 void
204 gst_object_sink (GstObject *object)
205 {
206   g_return_if_fail (object != NULL);
207   g_return_if_fail (GST_IS_OBJECT (object));
208
209   GST_DEBUG (GST_CAT_REFCOUNTING, "sink '%s'",GST_OBJECT_NAME(object));
210   if (GST_OBJECT_FLOATING (object))
211   {
212     GST_FLAG_UNSET (object, GST_FLOATING);
213     gst_object_unref (object);
214   }
215 }
216
217 /**
218  * gst_object_destroy:
219  * @object: GstObject to destroy
220  *
221  * Destroy the object.
222  * 
223  */
224 void
225 gst_object_destroy (GstObject *object)
226 {
227   g_return_if_fail (object != NULL);
228   g_return_if_fail (GST_IS_OBJECT (object));
229
230   GST_DEBUG (GST_CAT_REFCOUNTING, "destroy '%s'",GST_OBJECT_NAME(object));
231   if (!GST_OBJECT_DESTROYED (object))
232   {
233     /* need to hold a reference count around all class method
234      * invocations.
235      */
236     g_object_run_dispose (G_OBJECT (object));
237   }
238 }
239
240 static void
241 gst_object_dispose (GObject *object)
242 {
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;
246
247   parent_class->dispose (object);
248 }
249
250 /* finilize is called when the object has to free its resources */
251 static void
252 gst_object_finalize (GObject *object)
253 {
254   GstObject *gstobject = GST_OBJECT (object);
255
256   GST_DEBUG (GST_CAT_REFCOUNTING, "finalize '%s'",GST_OBJECT_NAME(object));
257
258   g_signal_handlers_destroy (object);
259
260   if (gstobject->name != NULL)
261     g_free (gstobject->name);
262
263   g_mutex_free (gstobject->lock);
264
265   parent_class->finalize (object);
266 }
267
268 static void
269 gst_object_set_name_default (GstObject *object)
270 {
271   gint count;
272   gchar *name, *tmp;
273   const gchar *type_name;
274   
275   type_name = G_OBJECT_TYPE_NAME (object);
276
277   G_LOCK (object_name_mutex);
278
279   if (!object_name_counts)
280     object_name_counts = g_hash_table_new (g_str_hash, g_str_equal);
281
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));
284   
285   G_UNLOCK (object_name_mutex);
286
287   /* GstFooSink -> foosinkN */
288   if (strncmp (type_name, "Gst", 3) == 0)
289     type_name += 3;
290   tmp = g_strdup_printf ("%s%d", type_name, count);
291   name = g_ascii_strdown (tmp, strlen (tmp));
292   g_free (tmp);
293   
294   gst_object_set_name (object, name);
295   g_free (name);
296 }
297
298 /**
299  * gst_object_set_name:
300  * @object: GstObject to set the name of
301  * @name: new name of object
302  *
303  * Set the name of the object.
304  */
305 void
306 gst_object_set_name (GstObject *object, const gchar *name)
307 {
308   g_return_if_fail (object != NULL);
309   g_return_if_fail (GST_IS_OBJECT (object));
310
311   if (object->name != NULL)
312     g_free (object->name);
313
314   if (name != NULL)
315     object->name = g_strdup (name);
316   else
317     gst_object_set_name_default (object);
318 }
319
320 /**
321  * gst_object_get_name:
322  * @object: GstObject to get the name of
323  *
324  * Get the name of the object.
325  *
326  * Returns: name of the object
327  */
328 const gchar*
329 gst_object_get_name (GstObject *object)
330 {
331   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
332
333   return object->name;
334 }
335
336 /**
337  * gst_object_set_parent:
338  * @object: GstObject to set parent of
339  * @parent: new parent of object
340  *
341  * Set the parent of the object.  The object's reference count is
342  * incremented.
343  * signals the parent-set signal
344  */
345 void
346 gst_object_set_parent (GstObject *object, GstObject *parent)
347 {
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);
353
354   if (object->parent != NULL) {
355     GST_ERROR_OBJECT (object,object->parent, "object's parent is already set, must unparent first");
356     return;
357   }
358
359   gst_object_ref (object);
360   gst_object_sink (object);
361   object->parent = parent;
362
363   g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_SET], 0, parent);
364 }
365
366 /**
367  * gst_object_get_parent:
368  * @object: GstObject to get parent of
369  *
370  * Return the parent of the object.
371  *
372  * Returns: parent of the object
373  */
374 GstObject*
375 gst_object_get_parent (GstObject *object)
376 {
377   g_return_val_if_fail (object != NULL, NULL);
378   g_return_val_if_fail (GST_IS_OBJECT (object), NULL);
379
380   return object->parent;
381 }
382
383 /**
384  * gst_object_unparent:
385  * @object: GstObject to unparent
386  *
387  * Clear the parent of the object, removing the associated reference.
388  */
389 void
390 gst_object_unparent (GstObject *object)
391 {
392   g_return_if_fail (object != NULL);
393   g_return_if_fail (GST_IS_OBJECT(object));
394   if (object->parent == NULL)
395     return;
396
397   GST_DEBUG (GST_CAT_REFCOUNTING, "unparent '%s'",GST_OBJECT_NAME(object));
398   
399   g_signal_emit (G_OBJECT (object), gst_object_signals[PARENT_UNSET], 0, object->parent);
400
401   object->parent = NULL;
402   gst_object_unref (object);
403 }
404
405 /**
406  * gst_object_check_uniqueness:
407  * @list: a list of #GstObject to check through
408  * @name: the name to search for
409  *
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.
413  *
414  * Returns: TRUE if the name doesn't appear in the list, FALSE if it does.
415  */
416 gboolean
417 gst_object_check_uniqueness (GList *list, const gchar *name)
418 {
419   g_return_val_if_fail (name != NULL, FALSE);
420
421   while (list) {
422     GstObject *child = GST_OBJECT (list->data);
423
424     list = g_list_next (list);
425       
426     if (strcmp (GST_OBJECT_NAME (child), name) == 0) 
427       return FALSE;
428   }
429
430   return TRUE;
431 }
432
433
434 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
435 /**
436  * gst_object_save_thyself:
437  * @object: GstObject to save
438  * @parent: The parent XML node to save the object into
439  *
440  * Saves the given object into the parent XML node.
441  *
442  * Returns: the new xmlNodePtr with the saved object
443  */
444 xmlNodePtr
445 gst_object_save_thyself (GstObject *object, xmlNodePtr parent)
446 {
447   GstObjectClass *oclass;
448
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);
452
453   oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(object);
454   if (oclass->save_thyself)
455     oclass->save_thyself (object, parent);
456
457   g_signal_emit (G_OBJECT (object), gst_object_signals[OBJECT_SAVED], 0, parent);
458
459   return parent;
460 }
461
462 /**
463  * gst_object_restore_thyself:
464  * @object: GstObject to load into
465  * @self: The XML node to load the object from
466  *
467  * Restores the given object with the data from the parent XML node.
468  */
469 void
470 gst_object_restore_thyself (GstObject *object, xmlNodePtr self)
471 {
472   GstObjectClass *oclass;
473
474   g_return_if_fail (object != NULL);
475   g_return_if_fail (GST_IS_OBJECT (object));
476   g_return_if_fail (self != NULL);
477
478   oclass = (GstObjectClass *) G_OBJECT_GET_CLASS(object);
479   if (oclass->restore_thyself)
480     oclass->restore_thyself (object, self);
481 }
482
483 static void
484 gst_object_real_restore_thyself (GstObject *object, xmlNodePtr self)
485 {
486   g_return_if_fail (object != NULL);
487   g_return_if_fail (GST_IS_OBJECT (object));
488   g_return_if_fail (self != NULL);
489   
490 /* FIXME: the signalobject stuff doesn't work
491  *  gst_class_signal_emit_by_name (object, "object_loaded", self); */
492 }
493 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
494
495 static void
496 gst_object_set_property (GObject* object, guint prop_id, 
497                          const GValue* value, GParamSpec* pspec)
498 {
499   GstObject *gstobject;
500             
501   /* it's not null if we got it, but it might not be ours */
502   g_return_if_fail (GST_IS_OBJECT (object));
503               
504   gstobject = GST_OBJECT (object);
505
506   switch (prop_id) {
507     case ARG_NAME:
508       gst_object_set_name (gstobject, g_value_get_string (value));
509       break;
510     default:
511       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
512       break;
513   }
514 }
515
516 static void
517 gst_object_get_property (GObject* object, guint prop_id, 
518                          GValue* value, GParamSpec* pspec)
519 {
520   GstObject *gstobject;
521             
522   /* it's not null if we got it, but it might not be ours */
523   g_return_if_fail (GST_IS_OBJECT (object));
524               
525   gstobject = GST_OBJECT (object);
526
527   switch (prop_id) {
528     case ARG_NAME:
529       g_value_set_string (value, (gchar*)GST_OBJECT_NAME (gstobject));
530       break;
531     default:
532       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
533       break;
534   }
535 }
536
537 /**
538  * gst_object_get_path_string:
539  * @object: GstObject to get the path from
540  *
541  * Generates a string describing the path of the object in
542  * the object hierarchy. Only useful (or used) for debugging
543  *
544  * Returns: a string describing the path of the object
545  */
546 gchar*
547 gst_object_get_path_string (GstObject *object)
548 {
549   GSList *parentage = NULL;
550   GSList *parents;
551   void *parent;
552   gchar *prevpath, *path;
553   const char *component;
554   gchar *separator = "";
555   gboolean free_component;
556
557   parentage = g_slist_prepend (NULL, object);
558
559   path = g_strdup ("");
560
561   /* first walk the object hierarchy to build a list of the parents */
562   do {
563     if (GST_IS_OBJECT (object)) {
564       parent = gst_object_get_parent (object);
565     } else {
566       parentage = g_slist_prepend (parentage, NULL);
567       parent = NULL;
568     }
569
570     if (parent != NULL) {
571       parentage = g_slist_prepend (parentage, parent);
572     }
573
574     object = parent;
575   } while (object != NULL);
576
577   /* then walk the parent list and print them out */
578   parents = parentage;
579   while (parents) {
580     if (GST_IS_OBJECT (parents->data)) {
581       GstObjectClass *oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(parents->data);
582
583       component = gst_object_get_name (parents->data);
584       separator = oclass->path_string_separator;
585       free_component = FALSE;
586     } else {
587       component = g_strdup_printf("%p",parents->data);
588       separator = "/";
589       free_component = TRUE;
590     }
591
592     prevpath = path;
593     path = g_strjoin (separator, prevpath, component, NULL);
594     g_free(prevpath);
595     if (free_component)
596       g_free((gchar *)component);
597
598     parents = g_slist_next(parents);
599   }
600
601   g_slist_free (parentage);
602
603   return path;
604 }
605
606
607
608 struct _GstSignalObject {
609   GObject object;
610 };
611
612 struct _GstSignalObjectClass {
613   GObjectClass        parent_class;
614
615   /* signals */
616 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
617   void          (*object_loaded)           (GstSignalObject *object, GstObject *new, xmlNodePtr self);
618 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */
619 };
620
621 static GType
622 gst_signal_object_get_type (void)
623 {
624   static GType signal_object_type = 0;
625
626   if (!signal_object_type) {
627     static const GTypeInfo signal_object_info = {
628       sizeof(GstSignalObjectClass),
629       NULL,
630       NULL,
631       (GClassInitFunc)gst_signal_object_class_init,
632       NULL,
633       NULL,
634       sizeof(GstSignalObject),
635       16,
636       (GInstanceInitFunc)gst_signal_object_init,
637       NULL
638     };
639     signal_object_type = g_type_register_static(G_TYPE_OBJECT, "GstSignalObject", &signal_object_info, 0);
640   }
641   return signal_object_type;
642 }
643
644 static void
645 gst_signal_object_class_init (GstSignalObjectClass *klass)
646 {
647   GObjectClass *gobject_class;
648
649   gobject_class = (GObjectClass*) klass;
650
651   parent_class = g_type_class_ref (G_TYPE_OBJECT);
652
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);
659 #endif
660 }
661
662 static void
663 gst_signal_object_init (GstSignalObject *object)
664 {
665 }
666
667 /**
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
673  *
674  * Connect to a class signal.
675  *
676  * Returns: the signal id.
677  */
678 guint
679 gst_class_signal_connect (GstObjectClass *klass,
680                           const gchar    *name,
681                           gpointer  func,
682                           gpointer       func_data)
683 {
684   return g_signal_connect (klass->signal_object, name, func, func_data);
685 }
686
687 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
688 /**
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
693  *
694  * emits the named class signal.
695  */
696 void
697 gst_class_signal_emit_by_name (GstObject *object,
698                                const gchar *name,
699                                xmlNodePtr self)
700 {
701   GstObjectClass *oclass;
702
703   oclass = (GstObjectClass *)G_OBJECT_GET_CLASS(object);
704
705   g_signal_emit_by_name (oclass->signal_object, name, object, self);
706 }
707
708 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */