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