]> git.sesse.net Git - vlc/blob - src/control/media_list_view.c
libvlc_event_manager: remove exceptions
[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 );
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 );
86         libvlc_event_attach( p_mlist->p_event_manager,
87                              libvlc_MediaListItemDeleted,
88                              media_list_item_removed, p_mlv );
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 );
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 );
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 );
171         libvlc_event_attach( p_mlist->p_event_manager,
172                              libvlc_MediaListItemDeleted,
173                              media_list_item_removed, p_mlv );
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 );
203     libvlc_event_attach( p_mlv->p_mlist->p_event_manager,
204                          libvlc_MediaListItemDeleted,
205                          media_list_item_removed, p_mlv );
206     int i, count = libvlc_media_list_count( p_mlv->p_mlist );
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( unlikely(p_mlv == NULL) )
312     {
313         libvlc_printerr( "Not enough memory" );
314         return NULL;
315     }
316
317     p_mlv->p_libvlc_instance = p_mlist->p_libvlc_instance;
318     p_mlv->p_event_manager = libvlc_event_manager_new( p_mlist,
319                                     p_mlv->p_libvlc_instance );
320     if( unlikely(p_mlv->p_event_manager == NULL) )
321     {
322         free(p_mlv);
323         return NULL;
324     }
325
326     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
327             libvlc_MediaListViewItemAdded );
328     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
329             libvlc_MediaListViewWillAddItem );
330     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
331             libvlc_MediaListViewItemDeleted );
332     libvlc_event_manager_register_event_type( p_mlv->p_event_manager,
333             libvlc_MediaListViewWillDeleteItem );
334
335     libvlc_media_list_retain( p_mlist );
336     p_mlv->p_mlist = p_mlist;
337
338     p_mlv->pf_count             = pf_count;
339     p_mlv->pf_item_at_index     = pf_item_at_index;
340     p_mlv->pf_children_at_index = pf_children_at_index;
341     p_mlv->pf_constructor       = pf_constructor;
342     p_mlv->pf_release           = pf_release;
343
344     p_mlv->p_this_view_data = this_view_data;
345
346     vlc_mutex_init( &p_mlv->object_lock );
347     p_mlv->i_refcount = 1;
348
349     return p_mlv;
350 }
351
352
353 /*
354  * Public libvlc functions
355  */
356
357 /**************************************************************************
358  *       libvlc_media_list_view_retain (Public)
359  **************************************************************************/
360 void
361 libvlc_media_list_view_retain( libvlc_media_list_view_t * p_mlv )
362 {
363     vlc_mutex_lock( &p_mlv->object_lock );
364     p_mlv->i_refcount++;
365     vlc_mutex_unlock( &p_mlv->object_lock );
366 }
367
368 /**************************************************************************
369  *       libvlc_media_list_view_release (Public)
370  **************************************************************************/
371 void
372 libvlc_media_list_view_release( libvlc_media_list_view_t * p_mlv )
373 {
374     vlc_mutex_lock( &p_mlv->object_lock );
375     p_mlv->i_refcount--;
376     if( p_mlv->i_refcount > 0 )
377     {
378         vlc_mutex_unlock( &p_mlv->object_lock );
379         return;
380     }
381     vlc_mutex_unlock( &p_mlv->object_lock );
382
383     /* Refcount null, time to free */
384     libvlc_media_list_lock( p_mlv->p_mlist );
385
386     if( p_mlv->pf_ml_item_added )
387     {
388         libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
389                             libvlc_MediaListItemAdded,
390                             media_list_item_added, p_mlv );
391     }
392     if( p_mlv->pf_ml_item_removed )
393     {
394         libvlc_event_detach( p_mlv->p_mlist->p_event_manager,
395                             libvlc_MediaListItemDeleted,
396                             media_list_item_removed, p_mlv );
397     }
398     int i, count = libvlc_media_list_count( p_mlv->p_mlist );
399     for( i = 0; i < count; i++)
400     {
401         libvlc_media_t * p_md;
402         p_md = libvlc_media_list_item_at_index( p_mlv->p_mlist, i, NULL );
403         uninstall_md_listener( p_mlv, p_md );
404         libvlc_media_release( p_md );
405     }
406     libvlc_media_list_unlock( p_mlv->p_mlist );
407
408     libvlc_event_manager_release( p_mlv->p_event_manager );
409
410     if( p_mlv->pf_release ) p_mlv->pf_release( p_mlv );
411     libvlc_media_list_release( p_mlv->p_mlist );
412     vlc_mutex_destroy( &p_mlv->object_lock );
413 }
414
415 /**************************************************************************
416  *       libvlc_media_list_view_event_manager (Public)
417  **************************************************************************/
418 libvlc_event_manager_t *
419 libvlc_media_list_view_event_manager( libvlc_media_list_view_t * p_mlv )
420 {
421     libvlc_event_manager_t * p_em;
422     vlc_mutex_lock( &p_mlv->object_lock );
423     p_em = p_mlv->p_event_manager;
424     vlc_mutex_unlock( &p_mlv->object_lock );
425     return p_em;
426 }
427
428 /**************************************************************************
429  *       libvlc_media_list_view_parent_media_list (Public)
430  **************************************************************************/
431 libvlc_media_list_t *
432 libvlc_media_list_view_parent_media_list( libvlc_media_list_view_t * p_mlv,
433                                          libvlc_exception_t * p_e)
434 {
435     (void)p_e;
436     libvlc_media_list_t * p_mlist;
437     vlc_mutex_lock( &p_mlv->object_lock );
438     p_mlist = p_mlv->p_mlist;
439     libvlc_media_list_retain( p_mlv->p_mlist );
440     vlc_mutex_unlock( &p_mlv->object_lock );
441     return p_mlist;
442 }
443
444 /**************************************************************************
445  *       libvlc_media_list_view_children_for_item (Public)
446  **************************************************************************/
447 libvlc_media_list_view_t *
448 libvlc_media_list_view_children_for_item( libvlc_media_list_view_t * p_mlv,
449                                           libvlc_media_t * p_md,
450                                           libvlc_exception_t * p_e)
451 {
452     (void)p_e;
453     libvlc_media_list_t * p_mlist;
454     libvlc_media_list_view_t * ret;
455
456     p_mlist = libvlc_media_subitems(p_md);
457     if(!p_mlist) return NULL;
458
459     ret = p_mlv->pf_constructor( p_mlist, p_e );
460     libvlc_media_list_release( p_mlist );
461
462     return ret;
463 }
464
465 /* Limited to four args, because it should be enough */
466
467 #define AN_SELECT( collapser, dec1, dec2, dec3, dec4, p, ...) p
468 #define ARGS(...) AN_SELECT( collapser, ##__VA_ARGS__, \
469                                               (p_mlv, arg1, arg2, arg3, arg4, p_e), \
470                                               (p_mlv, arg1, arg2, arg3, p_e), \
471                                               (p_mlv, arg1, arg2, p_e), \
472                                               (p_mlv, arg1, p_e), (p_mlv, p_e) )
473
474 #define MEDIA_LIST_VIEW_FUNCTION( name, ret_type, default_ret_value, /* Params */ ... ) \
475     ret_type \
476     libvlc_media_list_view_##name( libvlc_media_list_view_t * p_mlv, \
477                                   ##__VA_ARGS__, \
478                                   libvlc_exception_t * p_e ) \
479     { \
480         if( p_mlv->pf_##name ) \
481             return p_mlv->pf_##name ARGS(__VA_ARGS__) ; \
482         libvlc_exception_raise( p_e ); \
483         libvlc_printerr( "No '" #name "' method in this media_list_view" ); \
484         return default_ret_value;\
485     }
486
487 #define MEDIA_LIST_VIEW_FUNCTION_VOID_RET( name, /* Params */ ... ) \
488     void \
489     libvlc_media_list_view_##name( libvlc_media_list_view_t * p_mlv, \
490                                   ##__VA_ARGS__, \
491                                   libvlc_exception_t * p_e ) \
492     { \
493         if( p_mlv->pf_##name ) \
494         { \
495             p_mlv->pf_##name ARGS(__VA_ARGS__) ; \
496             return; \
497         } \
498         libvlc_exception_raise( p_e ); \
499         libvlc_printerr( "No '" #name "' method in this media_list_view" ); \
500     }
501
502
503 MEDIA_LIST_VIEW_FUNCTION( count, int, 0 )
504 MEDIA_LIST_VIEW_FUNCTION( item_at_index, libvlc_media_t *, NULL, int arg1 )
505 MEDIA_LIST_VIEW_FUNCTION( children_at_index, libvlc_media_list_view_t *, NULL, int arg1 )
506