]> git.sesse.net Git - vlc/blob - src/control/media_list_view.c
4c3116c9607aa3f8c8046d29f68f7c8576174166
[vlc] / src / control / media_list_view.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
42 media_list_item_added( const libvlc_event_t * p_event, void * p_user_data );
43 static void
44 media_list_item_removed( const libvlc_event_t * p_event, void * p_user_data );
45 static void
46 media_list_subitem_added( const libvlc_event_t * p_event, void * p_user_data );
47
48 static void
49 install_md_listener( libvlc_media_list_view_t * p_mlv,
50                      libvlc_media_descriptor_t * p_md)
51 {
52     libvlc_media_list_t * p_mlist;
53     if((p_mlist = libvlc_media_descriptor_subitems( p_md, NULL )))
54     {
55         libvlc_media_list_lock( p_mlist );
56         int i, count = libvlc_media_list_count( p_mlist, NULL );
57         for( i = 0; i < count; i++)
58         {
59             libvlc_media_descriptor_t * p_submd;
60             p_submd = libvlc_media_list_item_at_index( p_mlist, i, NULL );
61             install_md_listener( p_mlv, p_submd );
62             libvlc_media_descriptor_release( p_submd );
63         }
64         libvlc_media_list_unlock( p_mlist );
65         libvlc_media_list_release( p_mlist );
66     }
67     libvlc_event_attach( p_md->p_event_manager,
68                          libvlc_MediaDescriptorSubItemAdded,
69                          media_list_subitem_added, p_mlv, NULL );
70 }
71
72 static void
73 uninstall_md_listener( libvlc_media_list_view_t * p_mlv,
74                        libvlc_media_descriptor_t * p_md)
75 {
76     libvlc_media_list_t * p_mlist;
77     libvlc_event_detach( p_md->p_event_manager,
78                          libvlc_MediaDescriptorSubItemAdded,
79                          media_list_subitem_added, p_mlv, NULL );
80     if((p_mlist = libvlc_media_descriptor_subitems( p_md, NULL )))
81     {
82         libvlc_media_list_lock( p_mlist );
83         int i, count = libvlc_media_list_count( p_mlist, NULL );
84         for( i = 0; i < count; i++)
85         {
86             libvlc_media_descriptor_t * p_submd;
87             p_submd = libvlc_media_list_item_at_index( p_mlist,i, NULL );
88             uninstall_md_listener( p_mlv, p_submd );
89             libvlc_media_descriptor_release( p_submd );
90         }
91         libvlc_media_list_unlock( p_mlist );
92         libvlc_media_list_release( p_mlist );
93     }
94 }
95
96 static void
97 media_list_item_added( const libvlc_event_t * p_event, void * p_user_data )
98 {
99     libvlc_media_list_view_t * p_mlv = p_user_data;
100     libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_added.item;
101     install_md_listener( p_mlv, p_md );
102     if( p_mlv->pf_ml_item_added ) p_mlv->pf_ml_item_added( p_event, p_mlv );
103 }
104
105 static void
106 media_list_item_removed( const libvlc_event_t * p_event, void * p_user_data )
107 {
108     libvlc_media_list_view_t * p_mlv = p_user_data;
109     libvlc_media_descriptor_t * p_md = p_event->u.media_list_item_added.item;
110     uninstall_md_listener( p_mlv, p_md );
111     if( p_mlv->pf_ml_item_removed ) p_mlv->pf_ml_item_removed( p_event, p_mlv );
112 }
113
114 static void
115 media_list_subitem_added( const libvlc_event_t * p_event, void * p_user_data )
116 {
117     libvlc_event_t added_event;
118     libvlc_media_list_view_t * p_mlv = p_user_data;
119     libvlc_media_descriptor_t * p_md = p_event->u.media_descriptor_subitem_added.new_child;
120     install_md_listener( p_mlv, p_md );
121
122     added_event.u.media_list_item_added.item = p_md;
123     added_event.u.media_list_item_added.index = 0;
124     if( p_mlv->pf_ml_item_added ) p_mlv->pf_ml_item_added( &added_event, p_mlv );
125 }
126
127 /*
128  * LibVLC Internal functions
129  */
130 /**************************************************************************
131  *       libvlc_media_list_view_set_ml_notification_callback (Internal)
132  * The mlist lock should be held when entered
133  **************************************************************************/
134 void
135 libvlc_media_list_view_set_ml_notification_callback(
136                 libvlc_media_list_view_t * p_mlv,
137                 void (*item_added)(const libvlc_event_t *, libvlc_media_list_view_t *),
138                 void (*item_removed)(const libvlc_event_t *, libvlc_media_list_view_t *) )
139 {
140     p_mlv->pf_ml_item_added = item_added;
141     p_mlv->pf_ml_item_removed = item_removed;
142     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
143                          libvlc_MediaListItemAdded,
144                          media_list_item_added, p_mlv, NULL );
145     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
146                          libvlc_MediaListItemDeleted,
147                          media_list_item_removed, p_mlv, NULL );
148     int i, count = libvlc_media_list_count( p_mlv->p_mlist, NULL );
149     for( i = 0; i < count; i++)
150     {
151         libvlc_media_descriptor_t * p_md;
152         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
153         install_md_listener( p_mlv, p_md );
154         libvlc_media_descriptor_release( p_md );
155     }
156 }
157
158 /**************************************************************************
159  *       libvlc_media_list_view_notify_deletion (Internal)
160  **************************************************************************/
161 void
162 libvlc_media_list_view_will_delete_item(
163                 libvlc_media_list_view_t * p_mlv,
164                 libvlc_media_descriptor_t * p_item,
165                 int index )
166 {
167     libvlc_event_t event;
168
169     /* Construct the event */
170     event.type = libvlc_MediaListViewWillDeleteItem;
171     event.u.media_list_view_will_delete_item.item = p_item;
172     event.u.media_list_view_will_delete_item.index = index;
173
174     /* Send the event */
175     libvlc_event_send( p_mlv->p_event_manager, &event );
176 }
177
178 /**************************************************************************
179  *       libvlc_media_list_view_item_deleted (Internal)
180  **************************************************************************/
181 void
182 libvlc_media_list_view_item_deleted(
183                 libvlc_media_list_view_t * p_mlv,
184                 libvlc_media_descriptor_t * p_item,
185                 int index )
186 {
187     libvlc_event_t event;
188
189     /* Construct the event */
190     event.type = libvlc_MediaListViewItemDeleted;
191     event.u.media_list_view_item_deleted.item = p_item;
192     event.u.media_list_view_item_deleted.index = index;
193
194     /* Send the event */
195     libvlc_event_send( p_mlv->p_event_manager, &event );
196 }
197
198 /**************************************************************************
199  *       libvlc_media_list_view_will_add_item (Internal)
200  **************************************************************************/
201 void
202 libvlc_media_list_view_will_add_item(
203                 libvlc_media_list_view_t * p_mlv,
204                 libvlc_media_descriptor_t * p_item,
205                 int index )
206 {
207     libvlc_event_t event;
208
209     /* Construct the event */
210     event.type = libvlc_MediaListViewWillAddItem;
211     event.u.media_list_view_will_add_item.item = p_item;
212     event.u.media_list_view_will_add_item.index = index;
213
214     /* Send the event */
215     libvlc_event_send( p_mlv->p_event_manager, &event );
216 }
217
218 /**************************************************************************
219  *       libvlc_media_list_view_item_added (Internal)
220  **************************************************************************/
221 void
222 libvlc_media_list_view_item_added(
223                 libvlc_media_list_view_t * p_mlv,
224                 libvlc_media_descriptor_t * p_item,
225                 int index )
226 {
227     libvlc_event_t event;
228
229     /* Construct the event */
230     event.type = libvlc_MediaListViewItemAdded;
231     event.u.media_list_view_item_added.item = p_item;
232     event.u.media_list_view_item_added.index = index;
233
234     /* Send the event */
235     libvlc_event_send( p_mlv->p_event_manager, &event );
236 }
237
238 /**************************************************************************
239  *       libvlc_media_list_view_new (Internal)
240  **************************************************************************/
241 libvlc_media_list_view_t *
242 libvlc_media_list_view_new( libvlc_media_list_t * p_mlist,
243                             libvlc_media_list_view_count_func_t pf_count,
244                             libvlc_media_list_view_item_at_index_func_t pf_item_at_index,
245                             libvlc_media_list_view_children_at_index_func_t pf_children_at_index,
246                             libvlc_media_list_view_release_func_t pf_release,
247                             void * this_view_data,
248                             libvlc_exception_t * p_e )
249 {
250     libvlc_media_list_view_t * p_mlv;
251     p_mlv = calloc( 1, sizeof(libvlc_media_list_view_t) );
252     if( !p_mlv )
253         return NULL;
254
255     p_mlv->p_libvlc_instance = p_mlist->p_libvlc_instance;
256     p_mlv->p_event_manager = libvlc_event_manager_new( p_mlist,
257                                     p_mlv->p_libvlc_instance, p_e );
258
259     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
260             libvlc_MediaListViewItemAdded, p_e );
261     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
262             libvlc_MediaListViewWillAddItem, p_e );
263     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
264             libvlc_MediaListViewItemDeleted, p_e );
265     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
266             libvlc_MediaListViewWillDeleteItem, p_e );
267
268     libvlc_media_list_retain( p_mlist );
269     p_mlv->p_mlist = p_mlist;
270
271     p_mlv->pf_count             = pf_count;
272     p_mlv->pf_item_at_index     = pf_item_at_index;
273     p_mlv->pf_children_at_index = pf_children_at_index;
274     p_mlv->pf_release           = pf_release;
275
276     p_mlv->p_this_view_data = this_view_data;
277
278     vlc_mutex_init( p_mlv->p_libvlc_instance->p_libvlc_int, &p_mlv->object_lock );
279     p_mlv->i_refcount = 1;
280
281     return p_mlv;
282 }
283
284
285 /*
286  * Public libvlc functions
287  */
288
289 /**************************************************************************
290  *       libvlc_media_list_view_retain (Public)
291  **************************************************************************/
292 void
293 libvlc_media_list_view_retain( libvlc_media_list_view_t * p_mlv )
294 {
295     vlc_mutex_lock( &p_mlv->object_lock );
296     p_mlv->i_refcount++;
297     vlc_mutex_unlock( &p_mlv->object_lock );
298 }
299
300 /**************************************************************************
301  *       libvlc_media_list_view_release (Public)
302  **************************************************************************/
303 void
304 libvlc_media_list_view_release( libvlc_media_list_view_t * p_mlv )
305 {
306     vlc_mutex_lock( &p_mlv->object_lock );
307     p_mlv->i_refcount--;
308     if( p_mlv->i_refcount > 0 )
309     {
310         vlc_mutex_unlock( &p_mlv->object_lock );
311         return;
312     }
313     vlc_mutex_unlock( &p_mlv->object_lock );
314
315     /* Refcount null, time to free */
316     libvlc_media_list_lock( p_mlv->p_mlist );
317
318     if( p_mlv->pf_ml_item_added )
319     {
320         libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
321                             libvlc_MediaListItemAdded,
322                             media_list_item_added, p_mlv, NULL );
323     }
324     if( p_mlv->pf_ml_item_removed )
325     {
326         libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
327                             libvlc_MediaListItemDeleted,
328                             media_list_item_removed, p_mlv, NULL );
329     }
330     int i, count = libvlc_media_list_count( p_mlv->p_mlist, NULL );
331     for( i = 0; i < count; i++)
332     {
333         libvlc_media_descriptor_t * p_md;
334         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
335         uninstall_md_listener( p_mlv, p_md );
336         libvlc_media_descriptor_release( p_md );
337     }
338     libvlc_media_list_unlock( p_mlv->p_mlist );
339
340     libvlc_event_manager_release( p_mlv->p_event_manager );
341
342     if( p_mlv->pf_release ) p_mlv->pf_release( p_mlv );
343     libvlc_media_list_release( p_mlv->p_mlist );
344     vlc_mutex_destroy( &p_mlv->object_lock );
345 }
346
347 /**************************************************************************
348  *       libvlc_media_list_view_event_manager (Public)
349  **************************************************************************/
350 libvlc_event_manager_t *
351 libvlc_media_list_view_event_manager( libvlc_media_list_view_t * p_mlv )
352 {
353     libvlc_event_manager_t * p_em;
354     vlc_mutex_lock( &p_mlv->object_lock );
355     p_em = p_mlv->p_event_manager;
356     vlc_mutex_unlock( &p_mlv->object_lock );
357     return p_em;
358 }
359
360 /* Limited to four args, because it should be enough */
361
362 #define AN_SELECT( collapser, dec1, dec2, dec3, dec4, p, ...) p
363 #define ARGS(...) AN_SELECT( collapser, ##__VA_ARGS__, \
364                                               (p_mlv, arg1, arg2, arg3, arg4, p_e), \
365                                               (p_mlv, arg1, arg2, arg3, p_e), \
366                                               (p_mlv, arg1, arg2, p_e), \
367                                               (p_mlv, arg1, p_e), (p_mlv, p_e) )
368
369 #define MEDIA_LIST_VIEW_FUNCTION( name, ret_type, default_ret_value, /* Params */ ... ) \
370     ret_type \
371     libvlc_media_list_view_##name( libvlc_media_list_view_t * p_mlv, \
372                                   ##__VA_ARGS__, \
373                                   libvlc_exception_t * p_e ) \
374     { \
375         if( p_mlv->pf_##name ) \
376             return p_mlv->pf_##name ARGS(__VA_ARGS__) ; \
377         libvlc_exception_raise( p_e, "No '" #name "' method in this media_list_view" ); \
378         return default_ret_value;\
379     }
380
381 #define MEDIA_LIST_VIEW_FUNCTION_VOID_RET( name, /* Params */ ... ) \
382     void \
383     libvlc_media_list_view_##name( libvlc_media_list_view_t * p_mlv, \
384                                   ##__VA_ARGS__, \
385                                   libvlc_exception_t * p_e ) \
386     { \
387         if( p_mlv->pf_##name ) \
388         { \
389             p_mlv->pf_##name ARGS(__VA_ARGS__) ; \
390             return; \
391         } \
392         libvlc_exception_raise( p_e, "No '" #name "' method in this media_list_view" ); \
393     }
394
395
396 MEDIA_LIST_VIEW_FUNCTION( count, int, 0 )
397 MEDIA_LIST_VIEW_FUNCTION( item_at_index, libvlc_media_descriptor_t *, NULL, int arg1 )
398 MEDIA_LIST_VIEW_FUNCTION( children_at_index, libvlc_media_list_view_t *, NULL, int arg1 )
399