]> git.sesse.net Git - vlc/blob - src/control/flat_media_list.c
fe2d0475ca4afa2ade6f3ed487d74d0c9245fa0e
[vlc] / src / control / flat_media_list.c
1 /*****************************************************************************
2  * flat_media_list.c: libvlc flat media list functions. (extension to
3  * media_list.c).
4  *****************************************************************************
5  * Copyright (C) 2007 the VideoLAN team
6  * $Id: flat_media_list.c 21287 2007-08-20 01:28:12Z pdherbemont $
7  *
8  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include "libvlc_internal.h"
26 #include <vlc/libvlc.h>
27 #include <assert.h>
28 #include "vlc_arrays.h"
29
30 //#define DEBUG_FLAT_LIST
31
32 #ifdef DEBUG_FLAT_LIST
33 # define trace( fmt, ... ) printf( "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
34 #else
35 # define trace( ... )
36 #endif
37
38 /*
39  * Private functions
40  */
41 static void add_media_list( libvlc_media_list_t * p_mlist, libvlc_media_list_t * p_submlist );
42 static void remove_media_list( libvlc_media_list_t * p_fmlist, libvlc_media_list_t * p_mlist );
43 static void add_item( libvlc_media_list_t * p_mlist, libvlc_media_descriptor_t * p_md );
44 static void remove_item( libvlc_media_list_t * p_mlist, libvlc_media_descriptor_t * p_md );
45 static void subitems_created( const libvlc_event_t * p_event , void * p_user_data);
46 static void sublist_item_added( const libvlc_event_t * p_event, void * p_user_data );
47 static void sublist_item_removed( const libvlc_event_t * p_event, void * p_user_data );
48 static void install_flat_mlist_observer( libvlc_media_list_t * p_mlist );
49 static void uninstall_flat_mlist_observer( libvlc_media_list_t * p_mlist );
50
51 /**************************************************************************
52  *       uninstall_media_list_observer (Private)
53  **************************************************************************/
54 static void
55 uninstall_media_list_observer( libvlc_media_list_t * p_mlist,
56                              libvlc_media_list_t * p_submlist )
57 {
58     trace("\n");
59     libvlc_event_detach( p_submlist->p_event_manager,
60                          libvlc_MediaListItemAdded,
61                          sublist_item_added, p_mlist, NULL );
62     libvlc_event_detach( p_submlist->p_event_manager,
63                          libvlc_MediaListItemDeleted,
64                          sublist_item_removed, p_mlist, NULL );
65 }
66
67 /**************************************************************************
68  *       install_media_list_observer (Private)
69  **************************************************************************/
70 static void
71 install_media_list_observer( libvlc_media_list_t * p_mlist,
72                              libvlc_media_list_t * p_submlist )
73 {
74     trace("\n");
75     libvlc_event_attach( p_submlist->p_event_manager,
76                          libvlc_MediaListItemAdded,
77                          sublist_item_added, p_mlist, NULL );
78     libvlc_event_attach( p_submlist->p_event_manager,
79                          libvlc_MediaListItemDeleted,
80                          sublist_item_removed, p_mlist, NULL );
81 }
82
83 /**************************************************************************
84  *       add_media_list (Private)
85  **************************************************************************/
86 static void
87 add_media_list( libvlc_media_list_t * p_mlist,
88                 libvlc_media_list_t * p_submlist )
89 {
90     int count = libvlc_media_list_count( p_submlist, NULL );
91     int i;
92     trace("\n");
93
94     for( i = 0; i < count; i++ )
95     {
96         libvlc_media_descriptor_t * p_md;
97         p_md = libvlc_media_list_item_at_index( p_submlist, i, NULL );
98         add_item( p_mlist, p_md );
99     }
100     install_media_list_observer( p_mlist, p_submlist );
101 }
102
103 /**************************************************************************
104  *       remove_media_list (Private)
105  **************************************************************************/
106 static void
107 remove_media_list( libvlc_media_list_t * p_mlist,
108                    libvlc_media_list_t * p_submlist )
109 {
110     trace("\n");
111     int count = libvlc_media_list_count( p_submlist, NULL );    
112     int i;
113     uninstall_media_list_observer( p_mlist, p_submlist );
114
115     for( i = 0; i < count; i++ )
116     {
117         libvlc_media_descriptor_t * p_md;
118         p_md = libvlc_media_list_item_at_index( p_submlist, i, NULL );
119         remove_item( p_mlist, p_md );
120     }
121 }
122
123
124 /**************************************************************************
125  *       add_item (private) 
126  **************************************************************************/
127 static void
128 add_item( libvlc_media_list_t * p_mlist, libvlc_media_descriptor_t * p_md )
129 {
130     trace( "p_md '%s'\n", p_md->p_input_item->psz_name );
131
132     /* Only add the media descriptor once to our flat list */
133     if( libvlc_media_list_index_of_item( p_mlist->p_flat_mlist, p_md, NULL ) < 0 )
134     {
135         if( p_md->p_subitems )
136         {
137             add_media_list( p_mlist, p_md->p_subitems );
138         }
139         else
140         {
141             libvlc_media_list_lock( p_mlist->p_flat_mlist );
142             libvlc_event_attach( p_md->p_event_manager,
143                                  libvlc_MediaDescriptorSubItemAdded,
144                                  subitems_created, p_mlist, NULL );
145             uninstall_flat_mlist_observer( p_mlist );
146             libvlc_media_list_add_media_descriptor( p_mlist->p_flat_mlist,
147                                                     p_md, NULL );
148             install_flat_mlist_observer( p_mlist );
149             libvlc_media_list_unlock( p_mlist->p_flat_mlist );
150        
151         }
152     }
153 }
154
155 /**************************************************************************
156  *       remove_item (private) 
157  **************************************************************************/
158 static void
159 remove_item( libvlc_media_list_t * p_mlist, libvlc_media_descriptor_t * p_md )
160 {
161     trace( "p_md '%s'\n", p_md->p_input_item->psz_name );
162
163     if( p_md->p_subitems ) /* XXX: Don't access that directly */
164         remove_media_list( p_mlist, p_md->p_subitems );
165     libvlc_event_detach( p_md->p_event_manager,
166                          libvlc_MediaDescriptorSubItemAdded,
167                          subitems_created, p_mlist, NULL );
168
169     libvlc_media_list_lock( p_mlist->p_flat_mlist );
170     int i = libvlc_media_list_index_of_item( p_mlist->p_flat_mlist, p_md, NULL );
171     if( i >= 0 )
172     {
173         uninstall_flat_mlist_observer( p_mlist );
174         libvlc_media_list_remove_index( p_mlist->p_flat_mlist, i, NULL );
175         install_flat_mlist_observer( p_mlist );
176     }
177     libvlc_media_list_unlock( p_mlist->p_flat_mlist );
178 }
179
180 /**************************************************************************
181  *       subitems_created (private) (Event Callback)
182  **************************************************************************/
183 static void
184 subitems_created( const libvlc_event_t * p_event , void * p_user_data)
185 {
186     libvlc_media_list_t * p_mlist = p_user_data;
187     libvlc_media_descriptor_t * p_md = p_event->p_obj;
188
189     trace( "parent p_md '%s'\n", p_md->p_input_item->psz_name );
190
191     /* Remove the item and add the playlist */
192     libvlc_media_list_lock( p_mlist->p_flat_mlist );
193     int i = libvlc_media_list_index_of_item( p_mlist->p_flat_mlist, p_md, NULL );
194     if( i >=  0 )
195     {
196         libvlc_event_detach_lock_state( p_md->p_event_manager,
197                          libvlc_MediaDescriptorSubItemAdded,
198                          subitems_created, p_mlist, libvlc_Locked, NULL );
199         uninstall_flat_mlist_observer( p_mlist );
200         libvlc_media_list_remove_index( p_mlist->p_flat_mlist, i, NULL );
201         install_flat_mlist_observer( p_mlist );
202     }
203     libvlc_media_list_unlock( p_mlist->p_flat_mlist );
204
205     trace( "Adding p_md '%s''s media list\n", p_md->p_input_item->psz_name );
206
207     add_media_list( p_mlist, p_md->p_subitems );
208
209     trace( "done\n" );
210
211 }
212
213 /**************************************************************************
214  *       sublist_item_added (private) (Event Callback)
215  *
216  * This is called if the dynamic sublist's data provider adds a new item.
217  **************************************************************************/
218 static void
219 sublist_item_added( const libvlc_event_t * p_event, void * p_user_data )
220 {
221     libvlc_media_list_t * p_mlist = p_user_data;
222     libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_added.item;
223     trace( "p_md '%s'\n", p_md->p_input_item->psz_name );
224
225     add_item( p_mlist, p_md );
226 }
227
228 /**************************************************************************
229  *       sublist_remove_item (private) (Event Callback)
230  **************************************************************************/
231 static void
232 sublist_item_removed( const libvlc_event_t * p_event, void * p_user_data )
233 {
234     libvlc_media_list_t * p_mlist = p_user_data;
235     libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_deleted.item;
236     trace( "p_md '%s'\n", p_md->p_input_item->psz_name );
237
238     remove_item( p_mlist, p_md );
239 }
240
241 /**************************************************************************
242  *       remove_item_in_submlist_rec (private)
243  **************************************************************************/
244 static void
245 remove_item_in_submlist_rec( libvlc_media_list_t * p_mlist,
246                              libvlc_media_list_t * p_submlist,
247                              libvlc_media_descriptor_t * p_md )
248 {
249     libvlc_media_descriptor_t * p_md_insub;    
250     int count = libvlc_media_list_count( p_submlist, NULL );    
251     int i;
252     trace("p_md '%s'\n", p_md->p_input_item->psz_name);
253
254     for( i = 0; i < count; i++ )
255     {
256         p_md_insub = libvlc_media_list_item_at_index( p_submlist,
257                                                       i, NULL );
258         if( p_md == p_md_insub )
259         {
260             libvlc_media_list_lock( p_submlist );
261             uninstall_media_list_observer( p_mlist, p_submlist );
262             libvlc_media_list_remove_index( p_submlist, i, NULL );
263             install_media_list_observer( p_mlist, p_submlist );
264             libvlc_media_list_unlock( p_submlist );
265         } else if( p_md_insub->p_subitems )
266             remove_item_in_submlist_rec( p_mlist, p_md_insub->p_subitems, p_md );
267     }
268 }
269
270 /**************************************************************************
271  *       flat_mlist_item_removed (private) (Event Callback)
272  **************************************************************************/
273 static void
274 flat_mlist_item_removed( const libvlc_event_t * p_event, void * p_user_data )
275 {
276     trace("\n");
277     /* Remove all occurences of that one in sublist */
278     libvlc_media_list_t * p_mlist = p_user_data;
279     libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_deleted.item;
280     remove_item( p_mlist, p_md ); /* Just to detach the event */
281     remove_item_in_submlist_rec( p_mlist, p_mlist, p_md );
282 }
283
284 /**************************************************************************
285  *       flat_mlist_item_added (private) (Event Callback)
286  **************************************************************************/
287 static void
288 flat_mlist_item_added( const libvlc_event_t * p_event, void * p_user_data )
289 {
290     trace("\n");
291     libvlc_media_list_t * p_mlist = p_user_data;
292     libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_added.item;
293
294     libvlc_event_attach( p_md->p_event_manager,
295                         libvlc_MediaDescriptorSubItemAdded,
296                         subitems_created, p_mlist, NULL );
297
298     /* Add in our root */
299     uninstall_media_list_observer( p_mlist, p_mlist );    
300     libvlc_media_list_add_media_descriptor( p_mlist, p_md, NULL );
301     install_media_list_observer( p_mlist, p_mlist );
302 }
303
304 /**************************************************************************
305  *       install_flat_mlist_observer (Private)
306  **************************************************************************/
307 static void
308 install_flat_mlist_observer( libvlc_media_list_t * p_mlist )
309 {
310     trace("\n");
311     libvlc_event_attach( p_mlist->p_flat_mlist->p_event_manager,
312                          libvlc_MediaListItemAdded,
313                          flat_mlist_item_added, p_mlist, NULL );
314     libvlc_event_attach( p_mlist->p_flat_mlist->p_event_manager,
315                          libvlc_MediaListItemDeleted,
316                          flat_mlist_item_removed, p_mlist, NULL );
317
318 }
319
320 /**************************************************************************
321  *       uninstall_flat_mlist_observer (Private)
322  **************************************************************************/
323 static void
324 uninstall_flat_mlist_observer( libvlc_media_list_t * p_mlist )
325 {
326     trace("\n");
327     libvlc_event_detach( p_mlist->p_flat_mlist->p_event_manager,
328                          libvlc_MediaListItemAdded,
329                          flat_mlist_item_added, p_mlist, NULL );
330     libvlc_event_detach( p_mlist->p_flat_mlist->p_event_manager,
331                          libvlc_MediaListItemDeleted,
332                          flat_mlist_item_removed, p_mlist, NULL );
333
334 }
335
336 /*
337  * libvlc Internal functions
338  */
339 /**************************************************************************
340  *       flat_media_list_release (Internal)
341  **************************************************************************/
342 void
343 libvlc_media_list_flat_media_list_release( libvlc_media_list_t * p_mlist )
344 {
345     if( !p_mlist->p_flat_mlist )
346         return;
347     uninstall_flat_mlist_observer( p_mlist );
348     libvlc_media_list_release( p_mlist->p_flat_mlist );
349 }
350
351 /*
352  * Public libvlc functions
353  */
354
355 /**************************************************************************
356  *       media_list (Public)
357  **************************************************************************/
358 libvlc_media_list_t *
359 libvlc_media_list_flat_media_list( libvlc_media_list_t * p_mlist,
360                                    libvlc_exception_t * p_e )
361 {
362     trace("\n");
363     libvlc_media_list_lock( p_mlist );
364     if( !p_mlist->p_flat_mlist )
365     {
366         p_mlist->p_flat_mlist = libvlc_media_list_new(
367                                             p_mlist->p_libvlc_instance,
368                                             p_e );
369         add_media_list( p_mlist, p_mlist );
370     }
371     libvlc_media_list_unlock( p_mlist );
372     libvlc_media_list_retain( p_mlist->p_flat_mlist );
373     return p_mlist->p_flat_mlist;
374 }