]> git.sesse.net Git - vlc/blob - src/misc/objects.c
* modules/gui/wxwindows/*: don't forget to delete the timer.
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: objects.c,v 1.42 2003/10/14 22:41:41 gbazin Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /**
25  * \file
26  * This file contains the functions to handle the vlc_object_t type
27  */
28
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <vlc/vlc.h>
34
35 #ifdef HAVE_STDLIB_H
36 #   include <stdlib.h>                                          /* realloc() */
37 #endif
38
39 #include "stream_control.h"
40 #include "input_ext-intf.h"
41 #include "input_ext-dec.h"
42
43 #include "vlc_video.h"
44 #include "video_output.h"
45
46 #include "audio_output.h"
47 #include "aout_internal.h"
48 #include "stream_output.h"
49
50 #include "vlc_playlist.h"
51 #include "vlc_interface.h"
52 #include "vlc_codec.h"
53
54 #include "httpd.h"
55 /*****************************************************************************
56  * Local prototypes
57  *****************************************************************************/
58 static int  DumpCommand( vlc_object_t *, char const *,
59                          vlc_value_t, vlc_value_t, void * );
60
61 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
62 static void           DetachObject  ( vlc_object_t * );
63 static void           PrintObject   ( vlc_object_t *, const char * );
64 static void           DumpStructure ( vlc_object_t *, int, char * );
65 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
66 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
67
68 static vlc_list_t   * NewList       ( int );
69 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
70 static void           ListAppend    ( vlc_list_t *, vlc_object_t * );
71 static int            CountChildren ( vlc_object_t *, int );
72 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
73
74 /*****************************************************************************
75  * Local structure lock
76  *****************************************************************************/
77 static vlc_mutex_t    structure_lock;
78
79 /*****************************************************************************
80  * vlc_object_create: initialize a vlc object
81  *****************************************************************************
82  * This function allocates memory for a vlc object and initializes it. If
83  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
84  * so on, vlc_object_create will use its value for the object size.
85  *****************************************************************************/
86
87 /** 
88  * Initialize a vlc object
89  *
90  * This function allocates memory for a vlc object and initializes it. If
91  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
92  * so on, vlc_object_create will use its value for the object size.
93  */
94 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
95 {
96     vlc_object_t * p_new;
97     char *         psz_type;
98     size_t         i_size;
99
100     switch( i_type )
101     {
102         case VLC_OBJECT_ROOT:
103             i_size = sizeof(libvlc_t);
104             psz_type = "root";
105             break;
106         case VLC_OBJECT_VLC:
107             i_size = sizeof(vlc_t);
108             psz_type = "vlc";
109             break;
110         case VLC_OBJECT_MODULE:
111             i_size = sizeof(module_t);
112             psz_type = "module";
113             break;
114         case VLC_OBJECT_INTF:
115             i_size = sizeof(intf_thread_t);
116             psz_type = "interface";
117             break;
118         case VLC_OBJECT_DIALOGS:
119             i_size = sizeof(intf_thread_t);
120             psz_type = "dialogs provider";
121             break;
122         case VLC_OBJECT_PLAYLIST:
123             i_size = sizeof(playlist_t);
124             psz_type = "playlist";
125             break;
126         case VLC_OBJECT_INPUT:
127             i_size = sizeof(input_thread_t);
128             psz_type = "input";
129             break;
130         case VLC_OBJECT_DECODER:
131             i_size = sizeof(decoder_t);
132             psz_type = "decoder";
133             break;
134         case VLC_OBJECT_DECODER_FIFO: /* tmp for backward compat */
135             i_size = sizeof(decoder_fifo_t);
136             psz_type = "decoder";
137             break;
138         case VLC_OBJECT_PACKETIZER:
139             i_size = sizeof(decoder_t);
140             psz_type = "packetizer";
141             break;
142         case VLC_OBJECT_ENCODER:
143             i_size = sizeof(encoder_t);
144             psz_type = "encoder";
145             break;
146         case VLC_OBJECT_VOUT:
147             i_size = sizeof(vout_thread_t);
148             psz_type = "video output";
149             break;
150         case VLC_OBJECT_AOUT:
151             i_size = sizeof(aout_instance_t);
152             psz_type = "audio output";
153             break;
154         case VLC_OBJECT_SOUT:
155             i_size = sizeof(sout_instance_t);
156             psz_type = "stream output";
157             break;
158         case VLC_OBJECT_HTTPD:
159             i_size = sizeof( httpd_t );
160             psz_type = "http daemon";
161             break;
162         default:
163             i_size = i_type > 0
164                       ? i_type > (int)sizeof(vlc_object_t)
165                          ? i_type : (int)sizeof(vlc_object_t)
166                       : (int)sizeof(vlc_object_t);
167             i_type = VLC_OBJECT_GENERIC;
168             psz_type = "generic";
169             break;
170     }
171
172     if( i_type == VLC_OBJECT_ROOT )
173     {
174         p_new = p_this;
175     }
176     else
177     {
178         p_new = malloc( i_size );
179
180         if( !p_new )
181         {
182             return NULL;
183         }
184
185         memset( p_new, 0, i_size );
186     }
187
188     p_new->i_object_type = i_type;
189     p_new->psz_object_type = psz_type;
190
191     p_new->psz_object_name = NULL;
192
193     p_new->b_die = VLC_FALSE;
194     p_new->b_error = VLC_FALSE;
195     p_new->b_dead = VLC_FALSE;
196     p_new->b_attached = VLC_FALSE;
197
198     p_new->i_vars = 0;
199     p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) );
200
201     if( !p_new->p_vars )
202     {
203         free( p_new );
204         return NULL;
205     }
206
207     if( i_type == VLC_OBJECT_ROOT )
208     {
209         /* If i_type is root, then p_new is actually p_libvlc */
210         p_new->p_libvlc = (libvlc_t*)p_new;
211         p_new->p_vlc = NULL;
212
213         p_new->p_libvlc->i_counter = 0;
214         p_new->i_object_id = 0;
215
216         p_new->p_libvlc->i_objects = 1;
217         p_new->p_libvlc->pp_objects = malloc( sizeof(vlc_object_t *) );
218         p_new->p_libvlc->pp_objects[0] = p_new;
219         p_new->b_attached = VLC_TRUE;
220     }
221     else
222     {
223         p_new->p_libvlc = p_this->p_libvlc;
224         p_new->p_vlc = ( i_type == VLC_OBJECT_VLC ) ? (vlc_t*)p_new
225                                                     : p_this->p_vlc;
226
227         vlc_mutex_lock( &structure_lock );
228
229         p_new->p_libvlc->i_counter++;
230         p_new->i_object_id = p_new->p_libvlc->i_counter;
231
232         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
233          * useless to try and recover anything if pp_objects gets smashed. */
234         INSERT_ELEM( p_new->p_libvlc->pp_objects,
235                      p_new->p_libvlc->i_objects,
236                      p_new->p_libvlc->i_objects,
237                      p_new );
238
239         vlc_mutex_unlock( &structure_lock );
240     }
241
242     p_new->i_refcount = 0;
243     p_new->p_parent = NULL;
244     p_new->pp_children = NULL;
245     p_new->i_children = 0;
246
247     p_new->p_private = NULL;
248
249     /* Initialize mutexes and condvars */
250     vlc_mutex_init( p_new, &p_new->object_lock );
251     vlc_cond_init( p_new, &p_new->object_wait );
252     vlc_mutex_init( p_new, &p_new->var_lock );
253
254     if( i_type == VLC_OBJECT_ROOT )
255     {
256         vlc_mutex_init( p_new, &structure_lock );
257
258         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
259         var_AddCallback( p_new, "list", DumpCommand, NULL );
260         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
261         var_AddCallback( p_new, "tree", DumpCommand, NULL );
262     }
263
264     return p_new;
265 }
266
267 /**
268  ****************************************************************************
269  * Destroy a vlc object
270  * 
271  * This function destroys an object that has been previously allocated with
272  * vlc_object_create. The object's refcount must be zero and it must not be
273  * attached to other objects in any way.
274  *****************************************************************************/
275 void __vlc_object_destroy( vlc_object_t *p_this )
276 {
277     int i_delay = 0;
278
279     if( p_this->i_children )
280     {
281         msg_Err( p_this, "cannot delete object (%i, %s) with children" ,
282                  p_this->i_object_id, p_this->psz_object_name );
283         return;
284     }
285
286     if( p_this->p_parent )
287     {
288         msg_Err( p_this, "cannot delete object (%i, %s) with a parent",
289                  p_this->i_object_id, p_this->psz_object_name );
290         return;
291     }
292
293     while( p_this->i_refcount )
294     {
295         i_delay++;
296
297         /* Don't warn immediately ... 100ms seems OK */
298         if( i_delay == 2 )
299         {
300             msg_Warn( p_this, "refcount is %i, delaying before deletion",
301                               p_this->i_refcount );
302         }
303         else if( i_delay == 12 )
304         {
305             msg_Err( p_this, "refcount is %i, I have a bad feeling about this",
306                              p_this->i_refcount );
307         }
308         else if( i_delay == 42 )
309         {
310             msg_Err( p_this, "we waited too long, cancelling destruction" );
311             return;
312         }
313
314         msleep( 100000 );
315     }
316
317     /* Destroy the associated variables, starting from the end so that
318      * no memmove calls have to be done. */
319     while( p_this->i_vars )
320     {
321         var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name );
322     }
323
324     free( p_this->p_vars );
325     vlc_mutex_destroy( &p_this->var_lock );
326
327     if( p_this->i_object_type == VLC_OBJECT_ROOT )
328     {
329         /* We are the root object ... no need to lock. */
330         free( p_this->p_libvlc->pp_objects );
331         p_this->p_libvlc->pp_objects = NULL;
332         p_this->p_libvlc->i_objects--;
333
334         vlc_mutex_destroy( &structure_lock );
335     }
336     else
337     {
338         int i_index;
339
340         vlc_mutex_lock( &structure_lock );
341
342         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
343          * useless to try and recover anything if pp_objects gets smashed. */
344         i_index = FindIndex( p_this, p_this->p_libvlc->pp_objects,
345                              p_this->p_libvlc->i_objects );
346         REMOVE_ELEM( p_this->p_libvlc->pp_objects,
347                      p_this->p_libvlc->i_objects, i_index );
348
349         vlc_mutex_unlock( &structure_lock );
350     }
351
352     vlc_mutex_destroy( &p_this->object_lock );
353     vlc_cond_destroy( &p_this->object_wait );
354
355     free( p_this );
356 }
357
358 /**
359  * find an object given its ID
360  *
361  * This function looks for the object whose i_object_id field is i_id. We
362  * use a dichotomy so that lookups are in log2(n).
363  *****************************************************************************/
364 void * __vlc_object_get( vlc_object_t *p_this, int i_id )
365 {
366     int i_max, i_middle;
367     vlc_object_t **pp_objects;
368
369     vlc_mutex_lock( &structure_lock );
370
371     pp_objects = p_this->p_libvlc->pp_objects;
372
373     /* Perform our dichotomy */
374     for( i_max = p_this->p_libvlc->i_objects - 1 ; ; )
375     {
376         i_middle = i_max / 2;
377
378         if( pp_objects[i_middle]->i_object_id > i_id )
379         {
380             i_max = i_middle;
381         }
382         else if( pp_objects[i_middle]->i_object_id < i_id )
383         {
384             if( i_middle )
385             {
386                 pp_objects += i_middle;
387                 i_max -= i_middle;
388             }
389             else
390             {
391                 /* This happens when there are only two remaining objects */
392                 if( pp_objects[i_middle+1]->i_object_id == i_id )
393                 {
394                     vlc_mutex_unlock( &structure_lock );
395                     pp_objects[i_middle+1]->i_refcount++;
396                     return pp_objects[i_middle+1];
397                 }
398                 break;
399             }
400         }
401         else
402         {
403             vlc_mutex_unlock( &structure_lock );
404             pp_objects[i_middle]->i_refcount++;
405             return pp_objects[i_middle];
406         }
407
408         if( i_max == 0 )
409         {
410             /* this means that i_max == i_middle, and since we have already
411              * tested pp_objects[i_middle]), p_found is properly set. */
412             break;
413         }
414     }
415
416     vlc_mutex_unlock( &structure_lock );
417     return NULL;
418 }
419
420 /**
421  ****************************************************************************
422  * find a typed object and increment its refcount
423  *****************************************************************************
424  * This function recursively looks for a given object type. i_mode can be one
425  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
426  *****************************************************************************/
427 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
428 {
429     vlc_object_t *p_found;
430
431     vlc_mutex_lock( &structure_lock );
432
433     /* If we are of the requested type ourselves, don't look further */
434     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
435     {
436         p_this->i_refcount++;
437         vlc_mutex_unlock( &structure_lock );
438         return p_this;
439     }
440
441     /* Otherwise, recursively look for the object */
442     if( (i_mode & 0x000f) == FIND_ANYWHERE )
443     {
444         vlc_object_t *p_root = p_this;
445
446         /* Find the root */
447         while( p_root->p_parent != NULL &&
448                p_root != VLC_OBJECT( p_this->p_vlc ) )
449         {
450             p_root = p_root->p_parent;
451         }
452
453         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
454         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_vlc ) )
455         {
456             p_found = FindObject( VLC_OBJECT( p_this->p_vlc ),
457                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
458         }
459     }
460     else
461     {
462         p_found = FindObject( p_this, i_type, i_mode );
463     }
464
465     vlc_mutex_unlock( &structure_lock );
466
467     return p_found;
468 }
469
470 /**
471  ****************************************************************************
472  * increment an object refcount
473  *****************************************************************************/
474 void __vlc_object_yield( vlc_object_t *p_this )
475 {
476     vlc_mutex_lock( &structure_lock );
477     p_this->i_refcount++;
478     vlc_mutex_unlock( &structure_lock );
479 }
480
481 /**
482  ****************************************************************************
483  * decrement an object refcount
484  *****************************************************************************/
485 void __vlc_object_release( vlc_object_t *p_this )
486 {
487     vlc_mutex_lock( &structure_lock );
488     p_this->i_refcount--;
489     vlc_mutex_unlock( &structure_lock );
490 }
491
492 /**
493  ****************************************************************************
494  * attach object to a parent object
495  *****************************************************************************
496  * This function sets p_this as a child of p_parent, and p_parent as a parent
497  * of p_this. This link can be undone using vlc_object_detach.
498  *****************************************************************************/
499 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
500 {
501     vlc_mutex_lock( &structure_lock );
502
503     /* Attach the parent to its child */
504     p_this->p_parent = p_parent;
505
506     /* Attach the child to its parent */
507     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
508                  p_parent->i_children, p_this );
509
510     /* Climb up the tree to see whether we are connected with the root */
511     if( p_parent->b_attached )
512     {
513         SetAttachment( p_this, VLC_TRUE );
514     }
515
516     vlc_mutex_unlock( &structure_lock );
517 }
518
519 /**
520  ****************************************************************************
521  * detach object from its parent
522  *****************************************************************************
523  * This function removes all links between an object and its parent.
524  *****************************************************************************/
525 void __vlc_object_detach( vlc_object_t *p_this )
526 {
527     vlc_mutex_lock( &structure_lock );
528     if( !p_this->p_parent )
529     {
530         msg_Err( p_this, "object is not attached" );
531         vlc_mutex_unlock( &structure_lock );
532         return;
533     }
534
535     /* Climb up the tree to see whether we are connected with the root */
536     if( p_this->p_parent->b_attached )
537     {
538         SetAttachment( p_this, VLC_FALSE );
539     }
540
541     DetachObject( p_this );
542     vlc_mutex_unlock( &structure_lock );
543 }
544
545 /**
546  ****************************************************************************
547  * find a list typed objects and increment their refcount
548  *****************************************************************************
549  * This function recursively looks for a given object type. i_mode can be one
550  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
551  *****************************************************************************/
552 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
553 {
554     vlc_list_t *p_list;
555     vlc_object_t **pp_current, **pp_end;
556     int i_count = 0, i_index = 0;
557
558     vlc_mutex_lock( &structure_lock );
559
560     /* Look for the objects */
561     switch( i_mode & 0x000f )
562     {
563     case FIND_ANYWHERE:
564         pp_current = p_this->p_libvlc->pp_objects;
565         pp_end = pp_current + p_this->p_libvlc->i_objects;
566
567         for( ; pp_current < pp_end ; pp_current++ )
568         {
569             if( (*pp_current)->b_attached
570                  && (*pp_current)->i_object_type == i_type )
571             {
572                 i_count++;
573             }
574         }
575
576         p_list = NewList( i_count );
577         pp_current = p_this->p_libvlc->pp_objects;
578
579         for( ; pp_current < pp_end ; pp_current++ )
580         {
581             if( (*pp_current)->b_attached
582                  && (*pp_current)->i_object_type == i_type )
583             {
584                 ListReplace( p_list, *pp_current, i_index );
585                 if( i_index < i_count ) i_index++;
586             }
587         }
588     break;
589
590     case FIND_CHILD:
591         i_count = CountChildren( p_this, i_type );
592         p_list = NewList( i_count );
593
594         /* Check allocation was successful */
595         if( p_list->i_count != i_count )
596         {
597             msg_Err( p_this, "list allocation failed!" );
598             p_list->i_count = 0;
599             break;
600         }
601
602         p_list->i_count = 0;
603         ListChildren( p_list, p_this, i_type );
604         break;
605
606     default:
607         msg_Err( p_this, "unimplemented!" );
608         p_list = NewList( 0 );
609         break;
610     }
611
612     vlc_mutex_unlock( &structure_lock );
613
614     return p_list;
615 }
616
617 /*****************************************************************************
618  * DumpCommand: print the current vlc structure
619  *****************************************************************************
620  * This function prints either an ASCII tree showing the connections between
621  * vlc objects, and additional information such as their refcount, thread ID,
622  * etc. (command "tree"), or the same data as a simple list (command "list").
623  *****************************************************************************/
624 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
625                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
626 {
627     if( *psz_cmd == 't' )
628     {
629         char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
630         vlc_object_t *p_object;
631
632         if( *newval.psz_string )
633         {
634             p_object = vlc_object_get( p_this, atoi(newval.psz_string) );
635
636             if( !p_object )
637             {
638                 return VLC_ENOOBJ;
639             }
640         }
641         else
642         {
643             p_object = p_this->p_vlc ? VLC_OBJECT(p_this->p_vlc) : p_this;
644         }
645
646         vlc_mutex_lock( &structure_lock );
647
648         psz_foo[0] = '|';
649         DumpStructure( p_object, 0, psz_foo );
650
651         vlc_mutex_unlock( &structure_lock );
652
653         if( *newval.psz_string )
654         {
655             vlc_object_release( p_this );
656         }
657     }
658     else if( *psz_cmd == 'l' )
659     {
660         vlc_object_t **pp_current, **pp_end;
661
662         vlc_mutex_lock( &structure_lock );
663
664         pp_current = p_this->p_libvlc->pp_objects;
665         pp_end = pp_current + p_this->p_libvlc->i_objects;
666
667         for( ; pp_current < pp_end ; pp_current++ )
668         {
669             if( (*pp_current)->b_attached )
670             {
671                 PrintObject( *pp_current, "" );
672             }
673             else
674             {
675                 printf( " o %.8i %s (not attached)\n",
676                         (*pp_current)->i_object_id,
677                         (*pp_current)->psz_object_type );
678             }
679         }
680
681         vlc_mutex_unlock( &structure_lock );
682     }
683
684     return VLC_SUCCESS;
685 }
686
687 /*****************************************************************************
688  * vlc_list_release: free a list previously allocated by vlc_list_find
689  *****************************************************************************
690  * This function decreases the refcount of all objects in the list and
691  * frees the list.
692  *****************************************************************************/
693 void vlc_list_release( vlc_list_t *p_list )
694 {
695     int i_index;
696
697     for( i_index = 0; i_index < p_list->i_count; i_index++ )
698     {
699         vlc_mutex_lock( &structure_lock );
700
701         p_list->p_values[i_index].p_object->i_refcount--;
702
703         vlc_mutex_unlock( &structure_lock );
704     }
705
706     free( p_list->p_values );
707     free( p_list );
708 }
709
710 /* Following functions are local */
711
712 /*****************************************************************************
713  * FindIndex: find the index of an object in an array of objects
714  *****************************************************************************
715  * This function assumes that p_this can be found in pp_objects. It will not
716  * crash if p_this cannot be found, but will return a wrong value. It is your
717  * duty to check the return value if you are not certain that the object could
718  * be found for sure.
719  *****************************************************************************/
720 static int FindIndex( vlc_object_t *p_this,
721                       vlc_object_t **pp_objects, int i_count )
722 {
723     int i_middle = i_count / 2;
724
725     if( i_count == 0 )
726     {
727         return 0;
728     }
729
730     if( pp_objects[i_middle] == p_this )
731     {
732         return i_middle;
733     }
734
735     if( i_count == 1 )
736     {
737         return 0;
738     }
739
740     /* We take advantage of the sorted array */
741     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
742     {
743         return i_middle + FindIndex( p_this, pp_objects + i_middle,
744                                              i_count - i_middle );
745     }
746     else
747     {
748         return FindIndex( p_this, pp_objects, i_middle );
749     }
750 }
751
752 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
753 {
754     int i;
755     vlc_object_t *p_tmp;
756
757     switch( i_mode & 0x000f )
758     {
759     case FIND_PARENT:
760         p_tmp = p_this->p_parent;
761         if( p_tmp )
762         {
763             if( p_tmp->i_object_type == i_type )
764             {
765                 p_tmp->i_refcount++;
766                 return p_tmp;
767             }
768             else
769             {
770                 return FindObject( p_tmp, i_type, i_mode );
771             }
772         }
773         break;
774
775     case FIND_CHILD:
776         for( i = p_this->i_children; i--; )
777         {
778             p_tmp = p_this->pp_children[i];
779             if( p_tmp->i_object_type == i_type )
780             {
781                 p_tmp->i_refcount++;
782                 return p_tmp;
783             }
784             else if( p_tmp->i_children )
785             {
786                 p_tmp = FindObject( p_tmp, i_type, i_mode );
787                 if( p_tmp )
788                 {
789                     return p_tmp;
790                 }
791             }
792         }
793         break;
794
795     case FIND_ANYWHERE:
796         /* Handled in vlc_object_find */
797         break;
798     }
799
800     return NULL;
801 }
802
803 static void DetachObject( vlc_object_t *p_this )
804 {
805     vlc_object_t *p_parent = p_this->p_parent;
806     int i_index, i;
807
808     /* Remove p_this's parent */
809     p_this->p_parent = NULL;
810
811     /* Remove all of p_parent's children which are p_this */
812     for( i_index = p_parent->i_children ; i_index-- ; )
813     {
814         if( p_parent->pp_children[i_index] == p_this )
815         {
816             p_parent->i_children--;
817             for( i = i_index ; i < p_parent->i_children ; i++ )
818             {
819                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
820             }
821         }
822     }
823
824     if( p_parent->i_children )
825     {
826         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
827                                p_parent->i_children * sizeof(vlc_object_t *) );
828     }
829     else
830     {
831         free( p_parent->pp_children );
832         p_parent->pp_children = NULL;
833     }
834 }
835
836 /*****************************************************************************
837  * SetAttachment: recursively set the b_attached flag of a subtree.
838  *****************************************************************************
839  * This function is used by the attach and detach functions to propagate
840  * the b_attached flag in a subtree.
841  *****************************************************************************/
842 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
843 {
844     int i_index;
845
846     for( i_index = p_this->i_children ; i_index-- ; )
847     {
848         SetAttachment( p_this->pp_children[i_index], b_attached );
849     }
850
851     p_this->b_attached = b_attached;
852 }
853
854 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
855 {
856     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
857
858     psz_name[0] = '\0';
859     if( p_this->psz_object_name )
860     {
861         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
862         psz_name[48] = '\"';
863         psz_name[49] = '\0';
864     }
865
866     psz_children[0] = '\0';
867     switch( p_this->i_children )
868     {
869         case 0:
870             break;
871         case 1:
872             strcpy( psz_children, ", 1 child" );
873             break;
874         default:
875             snprintf( psz_children, 20,
876                       ", %i children", p_this->i_children );
877             psz_children[19] = '\0';
878             break;
879     }
880
881     psz_refcount[0] = '\0';
882     if( p_this->i_refcount )
883     {
884         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
885         psz_refcount[19] = '\0';
886     }
887
888     psz_thread[0] = '\0';
889     if( p_this->b_thread )
890     {
891         snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
892         psz_thread[19] = '\0';
893     }
894
895     printf( " %so %.8i %s%s%s%s%s\n", psz_prefix,
896             p_this->i_object_id, p_this->psz_object_type,
897             psz_name, psz_thread, psz_refcount, psz_children );
898 }
899
900 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
901 {
902     int i;
903     char i_back = psz_foo[i_level];
904     psz_foo[i_level] = '\0';
905
906     PrintObject( p_this, psz_foo );
907
908     psz_foo[i_level] = i_back;
909
910     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
911     {
912         msg_Warn( p_this, "structure tree is too deep" );
913         return;
914     }
915
916     for( i = 0 ; i < p_this->i_children ; i++ )
917     {
918         if( i_level )
919         {
920             psz_foo[i_level-1] = ' ';
921
922             if( psz_foo[i_level-2] == '`' )
923             {
924                 psz_foo[i_level-2] = ' ';
925             }
926         }
927
928         if( i == p_this->i_children - 1 )
929         {
930             psz_foo[i_level] = '`';
931         }
932         else
933         {
934             psz_foo[i_level] = '|';
935         }
936
937         psz_foo[i_level+1] = '-';
938         psz_foo[i_level+2] = '\0';
939
940         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
941     }
942 }
943
944 static vlc_list_t * NewList( int i_count )
945 {
946     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
947     if( p_list == NULL )
948     {
949         return NULL;
950     }
951
952     p_list->i_count = i_count;
953
954     if( i_count == 0 )
955     {
956         p_list->p_values = NULL;
957         return p_list;
958     }
959
960     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
961     if( p_list->p_values == NULL )
962     {
963         p_list->i_count = 0;
964         return p_list;
965     }
966
967     return p_list;
968 }
969
970 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
971                          int i_index )
972 {
973     if( p_list == NULL || i_index >= p_list->i_count )
974     {
975         return;
976     }
977
978     p_object->i_refcount++;
979
980     p_list->p_values[i_index].p_object = p_object;
981
982     return;
983 }
984
985 static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
986 {
987     if( p_list == NULL )
988     {
989         return;
990     }
991
992     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
993                                 * sizeof( vlc_value_t ) );
994     if( p_list->p_values == NULL )
995     {
996         p_list->i_count = 0;
997         return;
998     }
999
1000     p_object->i_refcount++;
1001
1002     p_list->p_values[p_list->i_count].p_object = p_object;
1003     p_list->i_count++;
1004
1005     return;
1006 }
1007
1008 static int CountChildren( vlc_object_t *p_this, int i_type )
1009 {
1010     vlc_object_t *p_tmp;
1011     int i, i_count = 0;
1012
1013     for( i = 0; i < p_this->i_children; i++ )
1014     {
1015         p_tmp = p_this->pp_children[i];
1016
1017         if( p_tmp->i_object_type == i_type )
1018         {
1019             i_count++;
1020         }
1021
1022         if( p_tmp->i_children )
1023         {
1024             i_count += CountChildren( p_tmp, i_type );
1025         }
1026     }
1027
1028     return i_count;
1029 }
1030
1031 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1032 {
1033     vlc_object_t *p_tmp;
1034     int i;
1035
1036     for( i = 0; i < p_this->i_children; i++ )
1037     {
1038         p_tmp = p_this->pp_children[i];
1039
1040         if( p_tmp->i_object_type == i_type )
1041         {
1042             ListReplace( p_list, p_tmp, p_list->i_count++ );
1043         }
1044
1045         if( p_tmp->i_children )
1046         {
1047             ListChildren( p_list, p_tmp, i_type );
1048         }
1049     }
1050 }