* reselect current playlist item when reordering items.
[vlc.git] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface plugin
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: controls.m,v 1.30 2003/04/06 23:21:13 massiot Exp $
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <thedj@users.sourceforge.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <sys/param.h>                                    /* for MAXPATHLEN */
31 #include <string.h>
32
33 #include "intf.h"
34 #include "vout.h"
35 #include "controls.h"
36
37 /*****************************************************************************
38  * VLCControls implementation 
39  *****************************************************************************/
40 @implementation VLCControls
41
42 - (IBAction)play:(id)sender
43 {
44     intf_thread_t * p_intf = [NSApp getIntf];
45
46     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
47                                                        FIND_ANYWHERE );
48     if( p_playlist == NULL )
49     {
50         return;
51     }
52
53     if( playlist_IsPlaying( p_playlist ) )
54     {
55         playlist_Pause( p_playlist );
56         vlc_object_release( p_playlist );
57     }
58     else
59     {
60         if( !playlist_IsEmpty( p_playlist ) )
61         {
62             playlist_Play( p_playlist );
63             vlc_object_release( p_playlist );
64         }
65         else
66         {
67             vlc_object_release( p_playlist );
68             [o_open openFile: nil];
69         }
70     }
71 }
72
73 - (IBAction)stop:(id)sender
74 {
75     intf_thread_t * p_intf = [NSApp getIntf];
76
77     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
78                                                        FIND_ANYWHERE );
79     if( p_playlist == NULL )
80     {
81         return;
82     }
83
84     playlist_Stop( p_playlist );
85     vlc_object_release( p_playlist );
86 }
87
88 - (IBAction)faster:(id)sender
89 {
90     intf_thread_t * p_intf = [NSApp getIntf];
91
92     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
93                                                        FIND_ANYWHERE );
94     if( p_playlist == NULL )
95     {
96         return;
97     }
98
99     vlc_mutex_lock( &p_playlist->object_lock );
100     if( p_playlist->p_input != NULL )
101     {
102         input_SetStatus( p_playlist->p_input, INPUT_STATUS_FASTER );
103     } 
104     vlc_mutex_unlock( &p_playlist->object_lock );
105
106     vlc_object_release( p_playlist );
107 }
108
109 - (IBAction)slower:(id)sender
110 {
111     intf_thread_t * p_intf = [NSApp getIntf];
112
113     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
114                                                        FIND_ANYWHERE );
115     if( p_playlist == NULL )
116     {
117         return;
118     }
119
120     vlc_mutex_lock( &p_playlist->object_lock );
121     if( p_playlist->p_input != NULL )
122     {
123         input_SetStatus( p_playlist->p_input, INPUT_STATUS_SLOWER );
124     }
125     vlc_mutex_unlock( &p_playlist->object_lock );
126
127     vlc_object_release( p_playlist );
128 }
129
130 - (IBAction)prev:(id)sender
131 {
132     intf_thread_t * p_intf = [NSApp getIntf];
133
134     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
135                                                        FIND_ANYWHERE );
136     if( p_playlist == NULL )
137     {
138         return;
139     }
140
141     vlc_mutex_lock( &p_playlist->object_lock );
142
143     if( p_playlist->p_input == NULL )
144     {
145         vlc_mutex_unlock( &p_playlist->object_lock );
146         vlc_object_release( p_playlist );  
147         return;
148     }
149
150     vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
151
152 #define p_area p_playlist->p_input->stream.p_selected_area
153
154     if( p_area->i_part_nb > 1 && p_area->i_part > 1 )
155     {
156         p_area->i_part--;
157
158         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
159         input_ChangeArea( p_playlist->p_input, p_area );
160         vlc_mutex_unlock( &p_playlist->object_lock );
161
162         p_intf->p_sys->b_chapter_update = VLC_TRUE;
163     }
164     else
165     {
166         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
167         vlc_mutex_unlock( &p_playlist->object_lock );
168         playlist_Prev( p_playlist );
169     }
170
171 #undef p_area
172
173     vlc_object_release( p_playlist );
174 }
175
176 - (IBAction)next:(id)sender
177 {
178     intf_thread_t * p_intf = [NSApp getIntf];
179
180     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
181                                                        FIND_ANYWHERE );
182     if( p_playlist == NULL )
183     {
184         return;
185     }
186
187     vlc_mutex_lock( &p_playlist->object_lock );
188
189     if( p_playlist->p_input == NULL )
190     {
191         vlc_mutex_unlock( &p_playlist->object_lock );
192         vlc_object_release( p_playlist );  
193         return;
194     }
195
196     vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
197
198 #define p_area p_playlist->p_input->stream.p_selected_area
199
200     if( p_area->i_part_nb > 1 && p_area->i_part + 1 < p_area->i_part_nb )
201     {
202         p_area->i_part++;
203
204         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
205         input_ChangeArea( p_playlist->p_input, p_area );
206         vlc_mutex_unlock( &p_playlist->object_lock );
207
208         p_intf->p_sys->b_chapter_update = VLC_TRUE;
209     }
210     else
211     {
212         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
213         vlc_mutex_unlock( &p_playlist->object_lock );
214         playlist_Next( p_playlist );
215     }
216
217 #undef p_area
218
219     vlc_object_release( p_playlist );
220 }
221
222 - (IBAction)loop:(id)sender
223 {
224     intf_thread_t * p_intf = [NSApp getIntf];
225
226     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
227                                                        FIND_ANYWHERE );
228     if( p_playlist == NULL )
229     {
230         return;
231     }
232
233     config_PutInt( p_playlist, "loop",
234                    !config_GetInt( p_playlist, "loop" ) );
235
236     vlc_object_release( p_playlist );
237 }
238
239 - (IBAction)forward:(id)sender
240 {
241     intf_thread_t * p_intf = [NSApp getIntf];
242     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
243                                                        FIND_ANYWHERE );
244     if( p_playlist == NULL || p_playlist->p_input == NULL )
245     {
246         if ( p_playlist != NULL ) vlc_object_release( p_playlist );
247         return;
248     }
249
250     input_Seek( p_playlist->p_input, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
251     vlc_object_release( p_playlist );
252 }
253
254 - (IBAction)backward:(id)sender
255 {
256     intf_thread_t * p_intf = [NSApp getIntf];
257     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
258                                                        FIND_ANYWHERE );
259     if( p_playlist == NULL || p_playlist->p_input == NULL )
260     {
261         if ( p_playlist != NULL ) vlc_object_release( p_playlist );
262         return;
263     }
264
265     input_Seek( p_playlist->p_input, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
266     vlc_object_release( p_playlist );
267 }
268
269 - (IBAction)volumeUp:(id)sender
270 {
271     intf_thread_t * p_intf = [NSApp getIntf];
272
273     if( p_intf->p_sys->b_mute )
274     {
275         [self mute: nil];
276     }
277
278     aout_VolumeUp( p_intf, 1, NULL );
279
280     [self updateVolumeSlider];
281 }
282
283 - (IBAction)volumeDown:(id)sender
284 {
285     intf_thread_t * p_intf = [NSApp getIntf];
286
287     if( p_intf->p_sys->b_mute )
288     {
289         [self mute: nil];
290     }
291     
292     aout_VolumeDown( p_intf, 1, NULL );
293
294     [self updateVolumeSlider];
295 }
296
297 - (IBAction)mute:(id)sender
298 {
299     intf_thread_t * p_intf = [NSApp getIntf];
300     audio_volume_t i_volume;
301
302     aout_VolumeMute( p_intf, &i_volume );
303     p_intf->p_sys->b_mute = ( i_volume == 0 );
304
305     [self updateVolumeSlider];
306 }
307
308 - (IBAction)volumeSliderUpdated:(id)sender
309 {
310     intf_thread_t * p_intf = [NSApp getIntf];
311     audio_volume_t i_volume = (audio_volume_t)[sender intValue];
312
313     aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
314 }
315
316 - (void)updateVolumeSlider
317 {
318     intf_thread_t * p_intf = [NSApp getIntf];
319     audio_volume_t i_volume;
320
321     aout_VolumeGet( p_intf, &i_volume );
322
323     [o_volumeslider setFloatValue: (float)(i_volume / AOUT_VOLUME_STEP)]; 
324 }
325
326 - (IBAction)halfWindow:(id)sender
327 {
328     id o_window = [NSApp keyWindow];
329     NSArray *o_windows = [NSApp windows];
330     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
331     
332     while ((o_window = [o_enumerator nextObject]))
333     {
334         if( [[o_window className] isEqualToString: @"VLCWindow"] )
335         {
336             [o_window scaleWindowWithFactor: 0.5];
337         }
338     }
339 }
340
341 - (IBAction)normalWindow:(id)sender
342 {
343     id o_window = [NSApp keyWindow];
344     NSArray *o_windows = [NSApp windows];
345     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
346     
347     while ((o_window = [o_enumerator nextObject]))
348     {
349         if( [[o_window className] isEqualToString: @"VLCWindow"] )
350         {
351             [o_window scaleWindowWithFactor: 1];
352         }
353     }
354 }
355
356 - (IBAction)doubleWindow:(id)sender
357 {
358     id o_window = [NSApp keyWindow];
359     NSArray *o_windows = [NSApp windows];
360     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
361     
362     while ((o_window = [o_enumerator nextObject]))
363     {
364         if( [[o_window className] isEqualToString: @"VLCWindow"] )
365         {
366             [o_window scaleWindowWithFactor: 2];
367         }
368     }
369 }
370
371
372 - (IBAction)fullscreen:(id)sender
373 {
374     id o_window = [NSApp keyWindow];
375     NSArray *o_windows = [NSApp windows];
376     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
377     
378     while ((o_window = [o_enumerator nextObject]))
379     {
380         if( [[o_window className] isEqualToString: @"VLCWindow"] )
381         {
382             [o_window toggleFullscreen];
383         }
384     }
385 }
386
387 - (IBAction)deinterlace:(id)sender
388 {
389     intf_thread_t * p_intf = [NSApp getIntf];
390     BOOL bEnable = [sender state] == NSOffState;
391
392     if( bEnable )
393     {
394         config_PutPsz( p_intf, "filter", "deinterlace" );
395         config_PutPsz( p_intf, "deinterlace-mode",
396                     [[sender title] lossyCString] );
397     }
398     else
399     {
400         config_PutPsz( p_intf, "filter", NULL );
401     }
402 }
403
404 - (IBAction)toggleProgram:(id)sender
405 {
406     NSMenuItem * o_mi = (NSMenuItem *)sender;
407     intf_thread_t * p_intf = [NSApp getIntf];
408
409     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
410                                                        FIND_ANYWHERE );
411     if( p_playlist == NULL )
412     {
413         return;
414     }
415
416     vlc_mutex_lock( &p_playlist->object_lock );
417
418     if( p_playlist->p_input == NULL )
419     {
420         vlc_mutex_unlock( &p_playlist->object_lock );
421         vlc_object_release( p_playlist );
422         return;
423     }
424
425     if( [o_mi state] == NSOffState )
426     {
427         u16 i_program_id = [o_mi tag];
428
429         input_ChangeProgram( p_playlist->p_input, i_program_id );
430         input_SetStatus( p_playlist->p_input, INPUT_STATUS_PLAY );
431     }
432
433     vlc_mutex_unlock( &p_playlist->object_lock );
434     vlc_object_release( p_playlist );
435 }
436
437 - (IBAction)toggleTitle:(id)sender
438 {
439     NSMenuItem * o_mi = (NSMenuItem *)sender;
440     intf_thread_t * p_intf = [NSApp getIntf];
441
442     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
443                                                        FIND_ANYWHERE );
444     if( p_playlist == NULL )
445     {
446         return;
447     }
448
449     vlc_mutex_lock( &p_playlist->object_lock );
450
451     if( p_playlist->p_input == NULL )
452     {
453         vlc_mutex_unlock( &p_playlist->object_lock );
454         vlc_object_release( p_playlist );
455         return;
456     }
457
458     if( [o_mi state] == NSOffState )
459     {
460         int i_title = [o_mi tag];
461
462 #define p_input p_playlist->p_input
463         input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
464         input_SetStatus( p_input, INPUT_STATUS_PLAY );
465 #undef p_input
466     }
467
468     vlc_mutex_unlock( &p_playlist->object_lock );
469     vlc_object_release( p_playlist );
470 }
471
472 - (IBAction)toggleChapter:(id)sender
473 {
474     NSMenuItem * o_mi = (NSMenuItem *)sender;
475     intf_thread_t * p_intf = [NSApp getIntf];
476
477     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
478                                                        FIND_ANYWHERE );
479     if( p_playlist == NULL )
480     {
481         return;
482     }
483
484     vlc_mutex_lock( &p_playlist->object_lock );
485
486     if( p_playlist->p_input == NULL )
487     {
488         vlc_mutex_unlock( &p_playlist->object_lock );
489         vlc_object_release( p_playlist );
490         return;
491     }
492
493     if( [o_mi state] == NSOffState )
494     {
495         int i_chapter = [o_mi tag];
496
497 #define p_input p_playlist->p_input
498         p_input->stream.p_selected_area->i_part = i_chapter;
499         input_ChangeArea( p_input, p_input->stream.p_selected_area );
500         input_SetStatus( p_input, INPUT_STATUS_PLAY );
501 #undef p_input
502     }
503
504     vlc_mutex_unlock( &p_playlist->object_lock );
505     vlc_object_release( p_playlist );
506 }
507
508 - (IBAction)toggleLanguage:(id)sender
509 {
510     NSMenuItem * o_mi = (NSMenuItem *)sender;
511     intf_thread_t * p_intf = [NSApp getIntf];
512
513     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
514                                                        FIND_ANYWHERE );
515     if( p_playlist == NULL )
516     {
517         return;
518     }
519
520     vlc_mutex_lock( &p_playlist->object_lock );
521
522     if( p_playlist->p_input == NULL )
523     {
524         vlc_mutex_unlock( &p_playlist->object_lock );
525         vlc_object_release( p_playlist );
526         return;
527     }
528
529 #if 0
530     /* We do not use this code, because you need to start stop .avi for
531      * it to work, so not very useful now  --hartman */
532     if ( [o_mi state] == NSOffState && [o_mi tag] == 2000 )
533     {
534         NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
535         
536         [o_open_panel setAllowsMultipleSelection: NO];
537         [o_open_panel setTitle: _NS("Open subtitle file")];
538         [o_open_panel setPrompt: _NS("Open")];
539     
540         if( [o_open_panel runModalForDirectory: nil 
541                 file: nil types: nil] == NSOKButton )
542         {
543             NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
544             config_PutPsz( p_intf, "sub-file", strdup( [o_filename cString] ));
545         }
546     }
547 #endif
548
549 #define p_input p_playlist->p_input
550
551     if( !p_intf->p_sys->b_audio_update )
552     {
553         NSValue * o_value = [o_mi representedObject];
554         es_descriptor_t * p_es = [o_value pointerValue];
555
556         if( [o_mi state] == NSOnState )
557         {
558             /* we just have one ES to disable */
559             input_ToggleES( p_input, p_es, 0 );
560         }
561         else
562         {
563             unsigned int i;
564             int i_cat = [o_mi tag];
565
566             vlc_mutex_lock( &p_input->stream.stream_lock );
567
568 #define ES p_input->stream.pp_selected_es[i]
569
570             /* unselect the selected ES in the same class */
571             for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
572             {
573                 if( ES->i_cat == i_cat )
574                 {
575                     vlc_mutex_unlock( &p_input->stream.stream_lock );
576                     input_ToggleES( p_input, ES, 0 );
577                     vlc_mutex_lock( &p_input->stream.stream_lock );
578                     break;
579                 }
580             }
581
582 #undef ES
583
584             vlc_mutex_unlock( &p_input->stream.stream_lock );
585
586             input_ToggleES( p_input, p_es, 1 );
587         }
588     }
589
590 #undef p_input
591
592     vlc_mutex_unlock( &p_playlist->object_lock );
593     vlc_object_release( p_playlist );
594 }
595
596 - (IBAction)toggleVar:(id)sender
597 {
598     NSMenuItem * o_mi = (NSMenuItem *)sender;
599     
600     if( [o_mi state] == NSOffState )
601     {
602         const char * psz_variable = (const char *)[o_mi tag];
603         char * psz_value = [NSApp delocalizeString: [o_mi title]];
604         vlc_object_t * p_object = (vlc_object_t *)
605             [[o_mi representedObject] pointerValue];
606         vlc_value_t val;
607         /* psz_string sucks */
608         val.psz_string = (char *)psz_value;
609
610         if ( var_Set( p_object, psz_variable, val ) < 0 )
611         {
612             msg_Warn( p_object, "cannot set variable (%s)", psz_value );
613         }
614
615         free( psz_value );
616     }
617 }
618
619 @end
620
621 @implementation VLCControls (NSMenuValidation)
622  
623 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
624 {
625     BOOL bEnabled = TRUE;
626     NSMenu * o_menu = [o_mi menu];
627     intf_thread_t * p_intf = [NSApp getIntf];
628
629     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
630                                                        FIND_ANYWHERE );
631
632     if( p_playlist != NULL )
633     {
634         vlc_mutex_lock( &p_playlist->object_lock );
635     }
636
637 #define p_input p_playlist->p_input
638
639     if( [[o_mi title] isEqualToString: _NS("Faster")] ||
640         [[o_mi title] isEqualToString: _NS("Slower")] )
641     {
642         if( p_playlist != NULL && p_input != NULL )
643         {
644             vlc_mutex_lock( &p_input->stream.stream_lock );
645             bEnabled = p_input->stream.b_pace_control;
646             vlc_mutex_unlock( &p_input->stream.stream_lock );
647         }
648         else
649         {
650             bEnabled = FALSE;
651         }
652     }
653     else if( [[o_mi title] isEqualToString: _NS("Stop")] )
654     {
655         if( p_playlist == NULL || p_input == NULL )
656         {
657             bEnabled = FALSE;
658         }
659     }
660     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
661              [[o_mi title] isEqualToString: _NS("Next")] )
662     {
663         if( p_playlist == NULL )
664         {
665             bEnabled = FALSE;
666         }
667         else
668         {
669             bEnabled = p_playlist->i_size > 1;
670
671             if( p_input != NULL )
672             {
673                 vlc_mutex_lock( &p_input->stream.stream_lock );
674                 bEnabled |= p_input->stream.p_selected_area->i_part_nb > 1;
675                 vlc_mutex_unlock( &p_input->stream.stream_lock );
676             }
677         }
678     }
679     else if( [[o_mi title] isEqualToString: _NS("Loop")] )
680     {
681         int i_state = config_GetInt( p_playlist, "loop" ) ?
682                       NSOnState : NSOffState;
683
684         [o_mi setState: i_state];
685     }
686     else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
687              [[o_mi title] isEqualToString: _NS("Step Backward")] )
688     {
689         if( p_playlist != NULL && p_input != NULL )
690         {
691             vlc_mutex_lock( &p_input->stream.stream_lock );
692             bEnabled = p_input->stream.b_seekable;
693             vlc_mutex_unlock( &p_input->stream.stream_lock );
694         }
695         else
696         {
697             bEnabled = FALSE;
698         }
699     }
700     else if( [[o_mi title] isEqualToString: _NS("Mute")] ) 
701     {
702         [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
703     }
704     else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
705                 [[o_mi title] isEqualToString: _NS("Half Size")] ||
706                 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
707                 [[o_mi title] isEqualToString: _NS("Double Size")])    
708     {
709         id o_window;
710         NSArray *o_windows = [NSApp windows];
711         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
712         bEnabled = FALSE;
713         
714         while ((o_window = [o_enumerator nextObject]))
715         {
716             if( [[o_window className] isEqualToString: @"VLCWindow"] )
717             {
718                 bEnabled = TRUE;
719                 break;
720             }
721         }
722     }
723     else if( o_menu != nil && 
724              [[o_menu title] isEqualToString: _NS("Deinterlace")] )
725     {
726         char * psz_filter = config_GetPsz( p_intf, "filter" );
727         
728         if( psz_filter != NULL )
729         {
730             free( psz_filter );
731             
732             psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
733         }
734
735         if( psz_filter != NULL )
736         {
737             if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
738             {
739                 [o_mi setState: NSOnState];
740             }
741             else
742             {
743                 [o_mi setState: NSOffState];
744             }
745
746             free( psz_filter );
747         }
748         else
749         {
750             [o_mi setState: NSOffState];
751         }
752     }
753
754     if( p_playlist != NULL )
755     {
756         vlc_mutex_unlock( &p_playlist->object_lock );
757         vlc_object_release( p_playlist );
758     }
759
760     return( bEnabled );
761 }
762
763 @end