]> git.sesse.net Git - vlc/blob - src/control/media_list_view.c
libvlc_event_detach: remove exception
[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$
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 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <vlc/libvlc.h>
30 #include <vlc/libvlc_media.h>
31 #include <vlc/libvlc_media_list.h>
32 #include <vlc/libvlc_media_list_view.h>
33 #include <vlc/libvlc_events.h>
34
35 #include "libvlc_internal.h"  // Abuse, could and should be removed
36
37 #include "media_internal.h"  // Abuse, could and should be removed
38 #include "media_list_internal.h"  // Abuse, could and should be removed
39 #include "media_list_view_internal.h"
40
41 //#define DEBUG_FLAT_LIST
42
43 #ifdef DEBUG_FLAT_LIST
44 # define trace( fmt, ... ) printf( "%s(): " fmt, __FUNCTION__, ##__VA_ARGS__ )
45 #else
46 # define trace( ... )
47 #endif
48
49 /*
50  * Private functions
51  */
52 static void
53 media_list_item_added( const libvlc_event_t * p_event, void * p_user_data );
54 static void
55 media_list_item_removed( const libvlc_event_t * p_event, void * p_user_data );
56 static void
57 media_list_subitem_added( const libvlc_event_t * p_event, void * p_user_data );
58
59 static void
60 install_md_listener( libvlc_media_list_view_t * p_mlv,
61                      libvlc_media_t * p_md)
62 {
63     libvlc_media_list_t * p_mlist;
64     if((p_mlist = libvlc_media_subitems( p_md )))
65     {
66         libvlc_media_list_lock( p_mlist );
67         int i, count = libvlc_media_list_count( p_mlist, NULL );
68         for( i = 0; i < count; i++)
69         {
70             libvlc_event_t added_event;
71             libvlc_media_t * p_submd;
72             p_submd = libvlc_media_list_item_at_index( p_mlist, i, NULL );
73
74             /* Install our listeners */
75             install_md_listener( p_mlv, p_submd );
76
77             /* For each item, send a notification to the mlv subclasses */
78             added_event.u.media_list_item_added.item = p_submd;
79             added_event.u.media_list_item_added.index = 0;
80             if( p_mlv->pf_ml_item_added ) p_mlv->pf_ml_item_added( &added_event, p_mlv );
81             libvlc_media_release( p_submd );
82         }
83         libvlc_event_attach( p_mlist->p_event_manager,
84                              libvlc_MediaListItemAdded,
85                              media_list_item_added, p_mlv, NULL );
86         libvlc_event_attach( p_mlist->p_event_manager,
87                              libvlc_MediaListItemDeleted,
88                              media_list_item_removed, p_mlv, NULL );
89         libvlc_media_list_unlock( p_mlist );
90         libvlc_media_list_release( p_mlist );
91     }
92     else
93     {
94         /* No mlist, wait for a subitem added event */
95         libvlc_event_attach( p_md->p_event_manager,
96                             libvlc_MediaSubItemAdded,
97                             media_list_subitem_added, p_mlv, NULL );
98     }
99 }
100
101 static void
102 uninstall_md_listener( libvlc_media_list_view_t * p_mlv,
103                        libvlc_media_t * p_md)
104 {
105     libvlc_media_list_t * p_mlist;
106     libvlc_event_detach( p_md->p_event_manager,
107                          libvlc_MediaSubItemAdded,
108                          media_list_subitem_added, p_mlv );
109     if((p_mlist = libvlc_media_subitems( p_md )))
110     {
111         libvlc_media_list_lock( p_mlist );
112         libvlc_event_detach( p_mlist->p_event_manager,
113                              libvlc_MediaListItemAdded,
114                              media_list_item_added, p_mlv );
115         libvlc_event_detach( p_mlist->p_event_manager,
116                              libvlc_MediaListItemDeleted,
117                              media_list_item_removed, p_mlv );
118
119         int i, count = libvlc_media_list_count( p_mlist, NULL );
120         for( i = 0; i < count; i++)
121         {
122             libvlc_media_t * p_submd;
123             p_submd = libvlc_media_list_item_at_index( p_mlist,i, NULL );
124             uninstall_md_listener( p_mlv, p_submd );
125             libvlc_media_release( p_submd );
126         }
127         libvlc_media_list_unlock( p_mlist );
128         libvlc_media_list_release( p_mlist );
129     }
130 }
131
132 static void
133 media_list_item_added( const libvlc_event_t * p_event, void * p_user_data )
134 {
135     libvlc_media_list_view_t * p_mlv = p_user_data;
136     libvlc_media_t * p_md = p_event->u.media_list_item_added.item;
137     install_md_listener( p_mlv, p_md );
138     if( p_mlv->pf_ml_item_added ) p_mlv->pf_ml_item_added( p_event, p_mlv );
139 }
140
141 static void
142 media_list_item_removed( const libvlc_event_t * p_event, void * p_user_data )
143 {
144     libvlc_media_list_view_t * p_mlv = p_user_data;
145     libvlc_media_t * p_md = p_event->u.media_list_item_added.item;
146     uninstall_md_listener( p_mlv, p_md );
147     if( p_mlv->pf_ml_item_removed ) p_mlv->pf_ml_item_removed( p_event, p_mlv );
148 }
149
150 static void
151 media_list_subitem_added( const libvlc_event_t * p_event, void * p_user_data )
152 {
153     libvlc_media_list_t * p_mlist;
154     libvlc_event_t added_event;
155     libvlc_media_list_view_t * p_mlv = p_user_data;
156     libvlc_media_t * p_submd = p_event->u.media_subitem_added.new_child;
157     libvlc_media_t * p_md = p_event->p_obj;
158
159     if((p_mlist = libvlc_media_subitems( p_md )))
160     {
161         /* We have a mlist to which we're going to listen to events
162          * thus, no need to wait for SubItemAdded events */
163         libvlc_event_detach( p_md->p_event_manager,
164                              libvlc_MediaSubItemAdded,
165                              media_list_subitem_added, p_mlv );
166         libvlc_media_list_lock( p_mlist );
167
168         libvlc_event_attach( p_mlist->p_event_manager,
169                              libvlc_MediaListItemAdded,
170                              media_list_item_added, p_mlv, NULL );
171         libvlc_event_attach( p_mlist->p_event_manager,
172                              libvlc_MediaListItemDeleted,
173                              media_list_item_removed, p_mlv, NULL );
174         libvlc_media_list_unlock( p_mlist );
175         libvlc_media_list_release( p_mlist );
176     }
177
178     install_md_listener( p_mlv, p_submd );
179
180     added_event.u.media_list_item_added.item = p_submd;
181     added_event.u.media_list_item_added.index = 0;
182     if( p_mlv->pf_ml_item_added ) p_mlv->pf_ml_item_added( &added_event, p_mlv );
183 }
184
185 /*
186  * LibVLC Internal functions
187  */
188 /**************************************************************************
189  *       libvlc_media_list_view_set_ml_notification_callback (Internal)
190  * The mlist lock should be held when entered
191  **************************************************************************/
192 void
193 libvlc_media_list_view_set_ml_notification_callback(
194                 libvlc_media_list_view_t * p_mlv,
195                 void (*item_added)(const libvlc_event_t *, libvlc_media_list_view_t *),
196                 void (*item_removed)(const libvlc_event_t *, libvlc_media_list_view_t *) )
197 {
198     p_mlv->pf_ml_item_added = item_added;
199     p_mlv->pf_ml_item_removed = item_removed;
200     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
201                          libvlc_MediaListItemAdded,
202                          media_list_item_added, p_mlv, NULL );
203     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
204                          libvlc_MediaListItemDeleted,
205                          media_list_item_removed, p_mlv, NULL );
206     int i, count = libvlc_media_list_count( p_mlv->p_mlist, NULL );
207     for( i = 0; i < count; i++)
208     {
209         libvlc_media_t * p_md;
210         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
211         install_md_listener( p_mlv, p_md );
212         libvlc_media_release( p_md );
213     }
214 }
215
216 /**************************************************************************
217  *       libvlc_media_list_view_notify_deletion (Internal)
218  **************************************************************************/
219 void
220 libvlc_media_list_view_will_delete_item(
221                 libvlc_media_list_view_t * p_mlv,
222                 libvlc_media_t * p_item,
223                 int index )
224 {
225     libvlc_event_t event;
226
227     /* Construct the event */
228     event.type = libvlc_MediaListViewWillDeleteItem;
229     event.u.media_list_view_will_delete_item.item = p_item;
230     event.u.media_list_view_will_delete_item.index = index;
231
232     /* Send the event */
233     libvlc_event_send( p_mlv->p_event_manager, &event );
234 }
235
236 /**************************************************************************
237  *       libvlc_media_list_view_item_deleted (Internal)
238  **************************************************************************/
239 void
240 libvlc_media_list_view_item_deleted(
241                 libvlc_media_list_view_t * p_mlv,
242                 libvlc_media_t * p_item,
243                 int index )
244 {
245     libvlc_event_t event;
246
247     /* Construct the event */
248     event.type = libvlc_MediaListViewItemDeleted;
249     event.u.media_list_view_item_deleted.item = p_item;
250     event.u.media_list_view_item_deleted.index = index;
251
252     /* Send the event */
253     libvlc_event_send( p_mlv->p_event_manager, &event );
254 }
255
256 /**************************************************************************
257  *       libvlc_media_list_view_will_add_item (Internal)
258  **************************************************************************/
259 void
260 libvlc_media_list_view_will_add_item(
261                 libvlc_media_list_view_t * p_mlv,
262                 libvlc_media_t * p_item,
263                 int index )
264 {
265     libvlc_event_t event;
266
267     /* Construct the event */
268     event.type = libvlc_MediaListViewWillAddItem;
269     event.u.media_list_view_will_add_item.item = p_item;
270     event.u.media_list_view_will_add_item.index = index;
271
272     /* Send the event */
273     libvlc_event_send( p_mlv->p_event_manager, &event );
274 }
275
276 /**************************************************************************
277  *       libvlc_media_list_view_item_added (Internal)
278  **************************************************************************/
279 void
280 libvlc_media_list_view_item_added(
281                 libvlc_media_list_view_t * p_mlv,
282                 libvlc_media_t * p_item,
283                 int index )
284 {
285     libvlc_event_t event;
286
287     /* Construct the event */
288     event.type = libvlc_MediaListViewItemAdded;
289     event.u.media_list_view_item_added.item = p_item;
290     event.u.media_list_view_item_added.index = index;
291
292     /* Send the event */
293     libvlc_event_send( p_mlv->p_event_manager, &event );
294 }
295
296 /**************************************************************************
297  *       libvlc_media_list_view_new (Internal)
298  **************************************************************************/
299 libvlc_media_list_view_t *
300 libvlc_media_list_view_new( libvlc_media_list_t * p_mlist,
301                             libvlc_media_list_view_count_func_t pf_count,
302                             libvlc_media_list_view_item_at_index_func_t pf_item_at_index,
303                             libvlc_media_list_view_children_at_index_func_t pf_children_at_index,
304                             libvlc_media_list_view_constructor_func_t pf_constructor,
305                             libvlc_media_list_view_release_func_t pf_release,
306                             void * this_view_data,
307                             libvlc_exception_t * p_e )
308 {
309     libvlc_media_list_view_t * p_mlv;
310     p_mlv = calloc( 1, sizeof(libvlc_media_list_view_t) );
311     if( !p_mlv )
312         return NULL;
313
314     p_mlv->p_libvlc_instance = p_mlist->p_libvlc_instance;
315     p_mlv->p_event_manager = libvlc_event_manager_new( p_mlist,
316                                     p_mlv->p_libvlc_instance, p_e );
317
318     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
319             libvlc_MediaListViewItemAdded, p_e );
320     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
321             libvlc_MediaListViewWillAddItem, p_e );
322     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
323             libvlc_MediaListViewItemDeleted, p_e );
324     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
325             libvlc_MediaListViewWillDeleteItem, p_e );
326
327     libvlc_media_list_retain( p_mlist );
328     p_mlv->p_mlist = p_mlist;
329
330     p_mlv->pf_count             = pf_count;
331     p_mlv->pf_item_at_index     = pf_item_at_index;
332     p_mlv->pf_children_at_index = pf_children_at_index;
333     p_mlv->pf_constructor       = pf_constructor;
334     p_mlv->pf_release           = pf_release;
335
336     p_mlv->p_this_view_data = this_view_data;
337
338     vlc_mutex_init( &p_mlv->object_lock );
339     p_mlv->i_refcount = 1;
340
341     return p_mlv;
342 }
343
344
345 /*
346  * Public libvlc functions
347  */
348
349 /**************************************************************************
350  *       libvlc_media_list_view_retain (Public)
351  **************************************************************************/
352 void
353 libvlc_media_list_view_retain( libvlc_media_list_view_t * p_mlv )
354 {
355     vlc_mutex_lock( &p_mlv->object_lock );
356     p_mlv->i_refcount++;
357     vlc_mutex_unlock( &p_mlv->object_lock );
358 }
359
360 /**************************************************************************
361  *       libvlc_media_list_view_release (Public)
362  **************************************************************************/
363 void
364 libvlc_media_list_view_release( libvlc_media_list_view_t * p_mlv )
365 {
366     vlc_mutex_lock( &p_mlv->object_lock );
367     p_mlv->i_refcount--;
368     if( p_mlv->i_refcount > 0 )
369     {
370         vlc_mutex_unlock( &p_mlv->object_lock );
371         return;
372     }
373     vlc_mutex_unlock( &p_mlv->object_lock );
374
375     /* Refcount null, time to free */
376     libvlc_media_list_lock( p_mlv->p_mlist );
377
378     if( p_mlv->pf_ml_item_added )
379     {
380         libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
381                             libvlc_MediaListItemAdded,
382                             media_list_item_added, p_mlv );
383     }
384     if( p_mlv->pf_ml_item_removed )
385     {
386         libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
387                             libvlc_MediaListItemDeleted,
388                             media_list_item_removed, p_mlv );
389     }
390     int i, count = libvlc_media_list_count( p_mlv->p_mlist, NULL );
391     for( i = 0; i < count; i++)
392     {
393         libvlc_media_t * p_md;
394         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
395         uninstall_md_listener( p_mlv, p_md );
396         libvlc_media_release( p_md );
397     }
398     libvlc_media_list_unlock( p_mlv->p_mlist );
399
400     libvlc_event_manager_release( p_mlv->p_event_manager );
401
402     if( p_mlv->pf_release ) p_mlv->pf_release( p_mlv );
403     libvlc_media_list_release( p_mlv->p_mlist );
404     vlc_mutex_destroy( &p_mlv->object_lock );
405 }
406
407 /**************************************************************************
408  *       libvlc_media_list_view_event_manager (Public)
409  **************************************************************************/
410 libvlc_event_manager_t *
411 libvlc_media_list_view_event_manager( libvlc_media_list_view_t * p_mlv )
412 {
413     libvlc_event_manager_t * p_em;
414     vlc_mutex_lock( &p_mlv->object_lock );
415     p_em = p_mlv->p_event_manager;
416     vlc_mutex_unlock( &p_mlv->object_lock );
417     return p_em;
418 }
419
420 /**************************************************************************
421  *       libvlc_media_list_view_parent_media_list (Public)
422  **************************************************************************/
423 libvlc_media_list_t *
424 libvlc_media_list_view_parent_media_list( libvlc_media_list_view_t * p_mlv,
425                                          libvlc_exception_t * p_e)
426 {
427     (void)p_e;
428     libvlc_media_list_t * p_mlist;
429     vlc_mutex_lock( &p_mlv->object_lock );
430     p_mlist = p_mlv->p_mlist;
431     libvlc_media_list_retain( p_mlv->p_mlist );
432     vlc_mutex_unlock( &p_mlv->object_lock );
433     return p_mlist;
434 }
435
436 /**************************************************************************
437  *       libvlc_media_list_view_children_for_item (Public)
438  **************************************************************************/
439 libvlc_media_list_view_t *
440 libvlc_media_list_view_children_for_item( libvlc_media_list_view_t * p_mlv,
441                                           libvlc_media_t * p_md,
442                                           libvlc_exception_t * p_e)
443 {
444     (void)p_e;
445     libvlc_media_list_t * p_mlist;
446     libvlc_media_list_view_t * ret;
447
448     p_mlist = libvlc_media_subitems(p_md);
449     if(!p_mlist) return NULL;
450
451     ret = p_mlv->pf_constructor( p_mlist, p_e );
452     libvlc_media_list_release( p_mlist );
453
454     return ret;
455 }
456
457 /* Limited to four args, because it should be enough */
458
459 #define AN_SELECT( collapser, dec1, dec2, dec3, dec4, p, ...) p
460 #define ARGS(...) AN_SELECT( collapser, ##__VA_ARGS__, \
461                                               (p_mlv, arg1, arg2, arg3, arg4, p_e), \
462                                               (p_mlv, arg1, arg2, arg3, p_e), \
463                                               (p_mlv, arg1, arg2, p_e), \
464                                               (p_mlv, arg1, p_e), (p_mlv, p_e) )
465
466 #define MEDIA_LIST_VIEW_FUNCTION( name, ret_type, default_ret_value, /* Params */ ... ) \
467     ret_type \
468     libvlc_media_list_view_##name( libvlc_media_list_view_t * p_mlv, \
469                                   ##__VA_ARGS__, \
470                                   libvlc_exception_t * p_e ) \
471     { \
472         if( p_mlv->pf_##name ) \
473             return p_mlv->pf_##name ARGS(__VA_ARGS__) ; \
474         libvlc_exception_raise( p_e ); \
475         libvlc_printerr( "No '" #name "' method in this media_list_view" ); \
476         return default_ret_value;\
477     }
478
479 #define MEDIA_LIST_VIEW_FUNCTION_VOID_RET( name, /* Params */ ... ) \
480     void \
481     libvlc_media_list_view_##name( libvlc_media_list_view_t * p_mlv, \
482                                   ##__VA_ARGS__, \
483                                   libvlc_exception_t * p_e ) \
484     { \
485         if( p_mlv->pf_##name ) \
486         { \
487             p_mlv->pf_##name ARGS(__VA_ARGS__) ; \
488             return; \
489         } \
490         libvlc_exception_raise( p_e ); \
491         libvlc_printerr( "No '" #name "' method in this media_list_view" ); \
492     }
493
494
495 MEDIA_LIST_VIEW_FUNCTION( count, int, 0 )
496 MEDIA_LIST_VIEW_FUNCTION( item_at_index, libvlc_media_t *, NULL, int arg1 )
497 MEDIA_LIST_VIEW_FUNCTION( children_at_index, libvlc_media_list_view_t *, NULL, int arg1 )
498