]> git.sesse.net Git - vlc/blob - plugins/macosx/intf_vlc_wrapper.m
4a1cd8f4a26901cd0178aff06317d67152e099ce
[vlc] / plugins / macosx / intf_vlc_wrapper.m
1 /*****************************************************************************
2  * intf_vlc_wrapper.c: MacOS X plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: intf_vlc_wrapper.m,v 1.11 2002/06/02 12:16:31 massiot Exp $
6  *
7  * Authors: Florian G. Pflug <fgp@phlo.org>
8  *          Jon Lech Johansen <jon-vl@nanocrew.net>
9  *          Christophe Massiot <massiot@via.ecp.fr>
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 #include <stdlib.h>                                      /* malloc(), free() */
27 #include <sys/param.h>                                    /* for MAXPATHLEN */
28 #include <string.h>
29
30 #include <IOKit/storage/IOCDMedia.h>
31 #include <IOKit/storage/IODVDMedia.h>
32
33 #include <videolan/vlc.h>
34
35 #include "interface.h"
36 #include "intf_playlist.h"
37 #include "intf_eject.h"
38
39 #include "video.h"
40 #include "video_output.h"
41 #include "audio_output.h"
42
43 #include "stream_control.h"
44 #include "input_ext-intf.h"
45
46 #include "macosx.h"
47 #include "intf_open.h"
48 #include "intf_vlc_wrapper.h"
49
50 #include "netutils.h"
51
52 @implementation Intf_VLCWrapper
53
54 static Intf_VLCWrapper *o_intf = nil;
55
56 /* Initialization */
57
58 + (Intf_VLCWrapper *)instance
59 {
60     if( o_intf == nil )
61     {
62         o_intf = [[[Intf_VLCWrapper alloc] init] autorelease];
63     }
64
65     return( o_intf );
66 }
67
68 - (void)dealloc
69 {
70     o_intf = nil;
71     [super dealloc];
72 }
73
74 - (bool)manage
75 {
76     p_main->p_intf->pf_manage( p_main->p_intf );
77
78     if( p_main->p_intf->b_die )
79     {
80         /* Vout depends on intf */
81         input_EndBank();
82         vout_EndBank();
83         input_InitBank();
84         vout_InitBank();
85
86         return( 1 );
87     }
88
89     if( p_input_bank->pp_input[0] != NULL )
90     {
91         vlc_mutex_lock( &p_input_bank->pp_input[0]->stream.stream_lock );
92
93         if( !p_input_bank->pp_input[0]->b_die )
94         {
95             /* New input or stream map change */
96             if( p_input_bank->pp_input[0]->stream.b_changed ||
97                 p_main->p_intf->p_sys->i_part !=
98                 p_input_bank->pp_input[0]->stream.p_selected_area->i_part )
99             {
100                 [self setupMenus];
101                 p_main->p_intf->p_sys->b_disabled_menus = 0;
102             }
103         }
104
105         vlc_mutex_unlock( &p_input_bank->pp_input[0]->stream.stream_lock );
106     }
107     else if ( !p_main->p_intf->p_sys->b_disabled_menus )
108     {
109         [self setupMenus];
110         p_main->p_intf->p_sys->b_disabled_menus = 1;
111     }
112
113     return( 0 );
114 }
115
116 - (void)quit
117 {
118     p_main->p_intf->b_die = 1;
119 }
120
121 /* playlist control */
122     
123 - (bool)playlistPlay
124 {
125     if( p_input_bank->pp_input[0] != NULL )
126     {
127         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PLAY );
128         p_main->p_playlist->b_stopped = 0;
129     }
130     else
131     {
132         vlc_mutex_lock( &p_main->p_playlist->change_lock );
133
134         if( p_main->p_playlist->b_stopped )
135         {
136             if( p_main->p_playlist->i_size )
137             {
138                 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
139                 intf_PlaylistJumpto( p_main->p_playlist,
140                                      p_main->p_playlist->i_index );
141             }
142             else
143             {
144                 vlc_mutex_unlock( &p_main->p_playlist->change_lock );
145                 [[Intf_Open instance] openFile: nil];
146             }
147         }
148         else
149         {
150             vlc_mutex_unlock( &p_main->p_playlist->change_lock );
151         }
152     }
153
154     return( TRUE );
155 }
156
157 - (void)playlistPause
158 {
159     if ( p_input_bank->pp_input[0] != NULL )
160     {
161         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_PAUSE );
162
163         vlc_mutex_lock( &p_main->p_playlist->change_lock );
164         p_main->p_playlist->b_stopped = 0;
165         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
166     }
167 }
168     
169 - (void)playlistStop
170 {
171     if( p_input_bank->pp_input[0] != NULL )
172     {
173         /* end playing item */
174         p_input_bank->pp_input[0]->b_eof = 1;
175
176         /* update playlist */
177         vlc_mutex_lock( &p_main->p_playlist->change_lock );
178
179         p_main->p_playlist->i_index--;
180         p_main->p_playlist->b_stopped = 1;
181
182         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
183     }
184 }
185
186 - (void)playlistNext
187 {
188     if( p_input_bank->pp_input[0] != NULL )
189     {
190         p_input_bank->pp_input[0]->b_eof = 1;
191     }
192 }
193
194 - (void)playlistPrev
195 {
196     if( p_input_bank->pp_input[0] != NULL )
197     {
198         /* FIXME: temporary hack */
199         intf_PlaylistPrev( p_main->p_playlist );
200         intf_PlaylistPrev( p_main->p_playlist );
201         p_input_bank->pp_input[0]->b_eof = 1;
202     }
203 }
204
205 - (void)channelNext
206 {
207     intf_thread_t * p_intf = p_main->p_intf;
208
209     p_intf->p_sys->i_channel++;
210
211     intf_WarnMsg( 3, "intf info: joining channel %d", p_intf->p_sys->i_channel );
212
213     vlc_mutex_lock( &p_intf->change_lock );
214     if( p_input_bank->pp_input[0] != NULL )
215     {
216         /* end playing item */
217         p_input_bank->pp_input[0]->b_eof = 1;
218
219         /* update playlist */
220         vlc_mutex_lock( &p_main->p_playlist->change_lock );
221
222         p_main->p_playlist->i_index--;
223         p_main->p_playlist->b_stopped = 1;
224
225         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
226
227         /* FIXME: ugly hack to close input and outputs */
228         p_intf->pf_manage( p_intf );
229     }
230
231     network_ChannelJoin( p_intf->p_sys->i_channel );
232
233     /* FIXME 2 */
234     p_main->p_playlist->b_stopped = 0;
235     p_intf->pf_manage( p_intf );
236
237     vlc_mutex_unlock( &p_intf->change_lock );
238 }
239
240 - (void)channelPrev
241 {
242     intf_thread_t * p_intf = p_main->p_intf;
243
244     if ( p_intf->p_sys->i_channel )
245     {
246         p_intf->p_sys->i_channel--;
247     }
248
249     intf_WarnMsg( 3, "intf info: joining channel %d", p_intf->p_sys->i_channel );
250
251     vlc_mutex_lock( &p_intf->change_lock );
252     if( p_input_bank->pp_input[0] != NULL )
253     {
254         /* end playing item */
255         p_input_bank->pp_input[0]->b_eof = 1;
256
257         /* update playlist */
258         vlc_mutex_lock( &p_main->p_playlist->change_lock );
259
260         p_main->p_playlist->i_index--;
261         p_main->p_playlist->b_stopped = 1;
262
263         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
264
265         /* FIXME: ugly hack to close input and outputs */
266         p_intf->pf_manage( p_intf );
267     }
268
269     network_ChannelJoin( p_intf->p_sys->i_channel );
270
271     /* FIXME 2 */
272     p_main->p_playlist->b_stopped = 0;
273     p_intf->pf_manage( p_intf );
274
275     vlc_mutex_unlock( &p_intf->change_lock );
276 }
277
278 - (void)loop
279 {
280     intf_thread_t * p_intf = p_main->p_intf;
281
282     if ( p_intf->p_sys->b_loop )
283     {
284         intf_PlaylistDelete( p_main->p_playlist,
285                              p_main->p_playlist->i_size - 1 );
286     }
287     else
288     {
289         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
290                           "vlc:loop" );
291     }
292     p_intf->p_sys->b_loop = !p_intf->p_sys->b_loop;
293 }
294
295 - (void)playSlower
296 {
297     if( p_input_bank->pp_input[0] != NULL )
298     {
299         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_SLOWER );
300
301         vlc_mutex_lock( &p_main->p_playlist->change_lock );
302         p_main->p_playlist->b_stopped = 0;
303         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
304     }
305 }
306
307 - (void)playFaster
308 {
309     if( p_input_bank->pp_input[0] != NULL )
310     {
311         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_FASTER );
312
313         vlc_mutex_lock( &p_main->p_playlist->change_lock );
314         p_main->p_playlist->b_stopped = 0;
315         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
316     }
317 }
318
319 - (void)mute
320 {
321     if( p_aout_bank->pp_aout[0] == NULL ) return;
322
323     if( p_main->p_intf->p_sys->b_mute )
324     {
325         p_aout_bank->pp_aout[0]->i_volume = 
326                             p_main->p_intf->p_sys->i_saved_volume;
327     }
328     else
329     {
330         p_main->p_intf->p_sys->i_saved_volume = 
331                             p_aout_bank->pp_aout[0]->i_volume;
332         p_aout_bank->pp_aout[0]->i_volume = 0;
333     }
334     p_main->p_intf->p_sys->b_mute = !p_main->p_intf->p_sys->b_mute;
335 }
336
337 - (void)maxvolume
338 {
339     if( p_aout_bank->pp_aout[0] == NULL ) return;
340
341     if( p_main->p_intf->p_sys->b_mute )
342     {
343         p_main->p_intf->p_sys->i_saved_volume = VOLUME_MAX;
344     }
345     else
346     {
347         p_aout_bank->pp_aout[0]->i_volume = VOLUME_MAX;
348     }
349 }
350
351 - (void)fullscreen
352 {
353     if( p_vout_bank->pp_vout[0] != NULL )
354     {
355         p_vout_bank->pp_vout[0]->i_changes |= VOUT_FULLSCREEN_CHANGE;
356     }
357 }
358
359 - (void)eject
360 {
361     /* FIXME : this will only eject the first drive found */
362     NSArray * o_devices = GetEjectableMediaOfClass(kIODVDMediaClass);
363     const char * psz_device;
364
365     if ( p_input_bank->pp_input[0] != NULL &&
366          (p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_VCD ||
367           p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_DVD ||
368           p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_DISC) )
369     {
370         intf_ErrMsg("error: cannot eject the disc while you're reading from it");
371         return;
372     }
373
374     if ( o_devices == nil )
375     {
376         o_devices = GetEjectableMediaOfClass(kIOCDMediaClass);
377     }
378
379     if ( o_devices != nil && [o_devices count] )
380     { 
381         psz_device = [[o_devices objectAtIndex:0] cString];
382         intf_Eject( psz_device );
383     }
384 }
385
386 /* playback info */
387
388 #define p_area p_input_bank->pp_input[0]->stream.p_selected_area
389
390 - (NSString *)getTimeAsString
391 {
392     static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ];
393         
394     if( p_input_bank->pp_input[0] == NULL )
395     {
396         return [NSString stringWithCString:"00:00:00"];
397     }     
398    
399     input_OffsetToTime( p_input_bank->pp_input[0], 
400                         psz_currenttime, p_area->i_tell );        
401
402     return( [NSString stringWithCString: psz_currenttime] );
403 }
404     
405 - (float)getTimeAsFloat
406 {
407     float f_time = 0.0;
408
409     if( p_input_bank->pp_input[0] != NULL )
410     {
411         f_time = (float)p_area->i_tell / (float)p_area->i_size;
412     }    
413
414     return( f_time );
415 }
416
417 - (void)setTimeAsFloat:(float)f_position
418 {
419     if( p_input_bank->pp_input[0] != NULL )
420     {
421         input_Seek( p_input_bank->pp_input[0]->p_this,
422                     p_area->i_size * f_position, INPUT_SEEK_SET );
423     }
424 }
425
426 #undef p_area
427
428 - (bool)playlistPlaying
429 {
430     return( !p_main->p_playlist->b_stopped );
431 }
432
433 - (NSArray *)playlistAsArray
434 {
435     int i;
436     NSMutableArray* p_list = 
437         [NSMutableArray arrayWithCapacity: p_main->p_playlist->i_size];
438     
439     vlc_mutex_lock( &p_main->p_playlist->change_lock );
440
441     for( i = 0; i < p_main->p_playlist->i_size; i++ )
442     {
443         [p_list addObject: [NSString 
444             stringWithCString: p_main->p_playlist->p_item[i].psz_name]];
445     }
446
447     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
448         
449     return( [NSArray arrayWithArray: p_list] );
450 }
451
452 /*
453 - (int)playlistLength
454 {
455     return( p_main->p_playlist->i_size );
456 }
457
458 - (NSString*)playlistItem:(int)i_pos
459 {
460     NSString *o_item = nil;
461
462     vlc_mutex_lock( &p_main->p_playlist->change_lock );
463     
464     if( i_pos < p_main->p_playlist->i_size )
465     {
466         o_item = [NSString 
467             stringWithCString: p_main->p_playlist->p_item[i_pos].psz_name];
468     }
469
470     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
471
472     return( o_item );
473 }
474
475 - (void)playlistPlayItem:(int)i_item
476 {
477     [self playlistStop];
478
479     vlc_mutex_lock( &p_main->p_playlist->change_lock );
480
481     if( i_item<p_main->p_playlist->i_size )
482     {
483         p_main->p_playlist->i_index--;
484     }
485
486     vlc_mutex_unlock( &p_main->p_playlist->change_lock );        
487
488     [self playlistPlayCurrent];
489 }
490     
491 - (void)playlistAdd:(NSString *)o_filename
492 {
493     intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
494                       [o_filename fileSystemRepresentation] );
495 }
496     
497 - (void)clearPlaylist
498 {
499     int i;
500     
501     vlc_mutex_lock( &p_main->p_playlist->change_lock );
502
503     for( i = 0; i < p_main->p_playlist->i_size; i++ )
504     {
505         intf_PlaylistDelete( p_main->p_playlist, i );
506     }
507
508     vlc_mutex_unlock( &p_main->p_playlist->change_lock );        
509 }
510 */
511
512 /* open file/disc/network */
513
514 - (void)openFiles:(NSArray*)o_files
515 {
516     NSString *o_file;
517     int i_end = p_main->p_playlist->i_size;
518     NSEnumerator *o_enum = [o_files objectEnumerator];
519     intf_thread_t * p_intf = p_main->p_intf;
520
521     if ( p_intf->p_sys->b_loop )
522     {
523         intf_PlaylistDelete( p_main->p_playlist,
524                              p_main->p_playlist->i_size - 1 );
525     }
526
527     while( ( o_file = (NSString *)[o_enum nextObject] ) )
528     {
529         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
530                           [o_file fileSystemRepresentation] );
531     }
532
533     /* end current item, select first added item */
534     if( p_input_bank->pp_input[0] != NULL )
535     {
536         p_input_bank->pp_input[0]->b_eof = 1;
537     }
538
539     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
540
541     if ( p_intf->p_sys->b_loop )
542     {
543         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
544                           "vlc:loop" );
545     }
546 }
547
548 - (void)openDisc:(NSString*)o_type device:(NSString*)o_device title:(int)i_title chapter:(int)i_chapter
549 {
550     NSString *o_source;
551     int i_end = p_main->p_playlist->i_size;
552     intf_thread_t * p_intf = p_main->p_intf;
553
554     o_source = [NSString stringWithFormat: @"%@:%@@%d,%d", 
555                     o_type, o_device, i_title, i_chapter];
556
557     if ( p_intf->p_sys->b_loop )
558     {
559         intf_PlaylistDelete( p_main->p_playlist,
560                              p_main->p_playlist->i_size - 1 );
561     }
562
563     intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
564                       [o_source fileSystemRepresentation] );
565
566     /* stop current item, select added item */
567     if( p_input_bank->pp_input[0] != NULL )
568     {
569         p_input_bank->pp_input[0]->b_eof = 1;
570     }
571
572     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
573
574     if ( p_intf->p_sys->b_loop )
575     {
576         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
577                           "vlc:loop" );
578     }
579 }
580
581 - (void)openNet:(NSString*)o_protocol addr:(NSString*)o_addr port:(int)i_port baddr:(NSString*)o_baddr
582 {
583     NSString *o_source;
584     int i_end = p_main->p_playlist->i_size;
585     intf_thread_t * p_intf = p_main->p_intf;
586
587     if( p_input_bank->pp_input[0] != NULL )
588     {
589         p_input_bank->pp_input[0]->b_eof = 1;
590     }
591
592     config_PutIntVariable( "network_channel", 0 );
593
594     if( o_baddr != nil )
595     {
596         o_source = [NSString stringWithFormat: @"%@://%@@:%i/%@",
597                         o_protocol, o_addr, i_port, o_baddr];
598     }
599     else
600     {
601         o_source = [NSString stringWithFormat: @"%@://%@@:%i",
602                         o_protocol, o_addr, i_port];
603     }
604
605     if ( p_intf->p_sys->b_loop )
606     {
607         intf_PlaylistDelete( p_main->p_playlist,
608                              p_main->p_playlist->i_size - 1 );
609     }
610
611     intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
612                       [o_source fileSystemRepresentation] );
613
614     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
615
616     if ( p_intf->p_sys->b_loop )
617     {
618         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
619                           "vlc:loop" );
620     }
621 }
622
623 - (void)openNetChannel:(NSString*)o_addr port:(int)i_port
624 {
625     if( p_input_bank->pp_input[0] != NULL )
626     {
627         p_input_bank->pp_input[0]->b_eof = 1;
628     }
629
630     config_PutIntVariable( "network_channel", 1 );
631
632     if( p_main->p_channel == NULL )
633     {
634         network_ChannelCreate();
635     }
636
637     config_PutPszVariable( "channel_server", (char*)[o_addr lossyCString] );
638     config_PutIntVariable( "channel_port", i_port ); 
639 }
640
641 - (void)toggleProgram:(id)sender
642 {
643     NSMenuItem * o_item = (NSMenuItem *)sender;
644     input_thread_t * p_input = p_input_bank->pp_input[0];
645
646     if( [o_item state] == NSOffState )
647     {
648         u16 i_program_id = [o_item tag];
649
650         input_ChangeProgram( p_input, i_program_id );
651
652         vlc_mutex_lock( &p_input->stream.stream_lock );
653         [self setupMenus];
654         vlc_mutex_unlock( &p_input->stream.stream_lock );
655
656         input_SetStatus( p_input, INPUT_STATUS_PLAY );
657     }
658 }
659
660 - (void)toggleTitle:(id)sender
661 {
662     NSMenuItem * o_item = (NSMenuItem *)sender;
663     input_thread_t * p_input = p_input_bank->pp_input[0];
664
665     if( [o_item state] == NSOffState )
666     {
667         int i_title = [o_item tag];
668
669         input_ChangeArea( p_input,
670                           p_input->stream.pp_areas[i_title] );
671
672         vlc_mutex_lock( &p_input->stream.stream_lock );
673         [self setupMenus];
674         vlc_mutex_unlock( &p_input->stream.stream_lock );
675
676         input_SetStatus( p_input, INPUT_STATUS_PLAY );
677     }
678 }
679
680 - (void)toggleChapter:(id)sender
681 {
682     NSMenuItem * o_item = (NSMenuItem *)sender;
683     input_thread_t * p_input = p_input_bank->pp_input[0];
684
685     if( [o_item state] == NSOffState )
686     {
687         int i_chapter = [o_item tag];
688
689         p_input->stream.p_selected_area->i_part = i_chapter;
690         input_ChangeArea( p_input,
691                           p_input->stream.p_selected_area );
692
693         vlc_mutex_lock( &p_input->stream.stream_lock );
694         [self setupMenus];
695         vlc_mutex_unlock( &p_input->stream.stream_lock );
696
697         input_SetStatus( p_input, INPUT_STATUS_PLAY );
698     }
699 }
700
701 - (void)toggleLanguage:(id)sender
702 {
703     NSMenuItem * o_item = (NSMenuItem *)sender;
704     input_thread_t * p_input = p_input_bank->pp_input[0];
705
706     int i_es = [o_item tag];
707
708     if( [o_item state] == NSOnState )
709     {
710         /* We just have one ES to disable */
711         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 0 );
712     }
713     else
714     {
715         /* Unselect the selected ES in the same class */
716         int i;
717         vlc_mutex_lock( &p_input->stream.stream_lock );
718         for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
719         {
720             if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
721             {
722                 vlc_mutex_unlock( &p_input->stream.stream_lock );
723                 input_ToggleES( p_input, p_input->stream.pp_selected_es[i], 0 );
724                 vlc_mutex_lock( &p_input->stream.stream_lock );
725                 break;
726             }
727         }
728         vlc_mutex_unlock( &p_input->stream.stream_lock );
729
730         /* Select the wanted ES */
731         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 1 );
732     }
733
734     vlc_mutex_lock( &p_input->stream.stream_lock );
735     [self setupMenus];
736     vlc_mutex_unlock( &p_input->stream.stream_lock );
737
738     input_SetStatus( p_input, INPUT_STATUS_PLAY );
739 }
740
741 - (void)toggleSubtitle:(id)sender
742 {
743     NSMenuItem * o_item = (NSMenuItem *)sender;
744     input_thread_t * p_input = p_input_bank->pp_input[0];
745
746     int i_es = [o_item tag];
747
748     if( [o_item state] == NSOnState )
749     {
750         /* We just have one ES to disable */
751         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 0 );
752     }
753     else
754     {
755         /* Unselect the selected ES in the same class */
756         int i;
757         vlc_mutex_lock( &p_input->stream.stream_lock );
758         for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
759         {
760             if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
761             {
762                 vlc_mutex_unlock( &p_input->stream.stream_lock );
763                 input_ToggleES( p_input, p_input->stream.pp_selected_es[i], 0 );
764                 vlc_mutex_lock( &p_input->stream.stream_lock );
765                 break;
766             }
767         }
768         vlc_mutex_unlock( &p_input->stream.stream_lock );
769
770         /* Select the wanted ES */
771         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 1 );
772     }
773
774     vlc_mutex_lock( &p_input->stream.stream_lock );
775     [self setupMenus];
776     vlc_mutex_unlock( &p_input->stream.stream_lock );
777
778     input_SetStatus( p_input, INPUT_STATUS_PLAY );
779 }
780
781 - (void)setupMenus
782 {
783     NSMenu *o_main_menu;
784     NSMenuItem *o_controls_item;
785     NSMenuItem *o_program_item, *o_title_item, *o_chapter_item, *o_language_item,
786                *o_subtitle_item, *o_next_channel_item, *o_prev_channel_item;
787     input_thread_t * p_input = p_input_bank->pp_input[0];
788
789     o_main_menu  = [NSApp mainMenu];
790     o_controls_item  = [o_main_menu itemWithTitle: @"Controls"];
791     o_program_item = [[o_controls_item submenu] itemWithTitle: @"Program"]; 
792     o_title_item = [[o_controls_item submenu] itemWithTitle: @"Title"]; 
793     o_chapter_item = [[o_controls_item submenu] itemWithTitle: @"Chapter"]; 
794     o_language_item = [[o_controls_item submenu] itemWithTitle: @"Language"]; 
795     o_subtitle_item = [[o_controls_item submenu] itemWithTitle: @"Subtitles"]; 
796     o_next_channel_item = [[o_controls_item submenu] itemWithTag: 13]; 
797     o_prev_channel_item = [[o_controls_item submenu] itemWithTag: 12]; 
798
799     if( p_input == NULL )
800     {
801         [o_program_item setEnabled:0];
802         [o_title_item setEnabled:0];
803         [o_chapter_item setEnabled:0];
804         [o_language_item setEnabled:0];
805         [o_subtitle_item setEnabled:0];
806     }
807     else
808     {
809         NSMenu *o_program, *o_title, *o_chapter, *o_language, *o_subtitle;
810         SEL pf_toggle_program, pf_toggle_title, pf_toggle_chapter,
811             pf_toggle_language, pf_toggle_subtitle;
812
813         int i, i_nb_items;
814         pgrm_descriptor_t * p_pgrm;
815
816         /* ----- PROGRAMS ----- */
817         if( p_input->stream.i_pgrm_number < 2 )
818         {
819             [o_program_item setEnabled:0];
820         }
821         else
822         {
823             [o_program_item setEnabled:1];
824             o_program = [o_program_item submenu];
825             pf_toggle_program = @selector(toggleProgram:);
826     
827             /* Remove previous program menu */
828             i_nb_items = [o_program numberOfItems];
829             for( i = 0; i < i_nb_items; i++ )
830             {
831                 [o_program removeItemAtIndex:0];
832             }
833     
834             if( p_input->stream.p_new_program )
835             {
836                 p_pgrm = p_input->stream.p_new_program;
837             }
838             else
839             {
840                 p_pgrm = p_input->stream.p_selected_program;
841             }
842     
843             /* Create program menu */
844             for( i = 0 ; i < p_input->stream.i_pgrm_number ; i++ )
845             {
846                 char psz_title[ 256 ];
847                 NSString * o_menu_title;
848                 NSMenuItem * o_item;
849     
850                 snprintf( psz_title, sizeof(psz_title), "id %d",
851                     p_input->stream.pp_programs[i]->i_number );
852                 psz_title[sizeof(psz_title) - 1] = '\0';
853     
854                 o_menu_title = [NSString stringWithCString: psz_title];
855     
856                 o_item = [o_program addItemWithTitle: o_menu_title
857                         action: pf_toggle_program keyEquivalent: @""];
858                 [o_item setTarget: self];
859                 [o_item setTag: p_input->stream.pp_programs[i]->i_number];
860                 if( p_pgrm == p_input->stream.pp_programs[i] )
861                 {
862                     [o_item setState: 1];
863                 }
864             }
865         }
866         vlc_mutex_unlock( &p_input->stream.stream_lock );
867         vlc_mutex_lock( &p_input->stream.stream_lock );
868
869         /* ----- TITLES ----- */
870         if( p_input->stream.i_area_nb < 2 )
871         {
872             [o_title_item setEnabled:0];
873         }
874         else
875         {
876             [o_title_item setEnabled:1];
877             o_title = [o_title_item submenu];
878             pf_toggle_title = @selector(toggleTitle:);
879     
880             /* Remove previous title menu */
881             i_nb_items = [o_title numberOfItems];
882             for( i = 0; i < i_nb_items; i++ )
883             {
884                 [o_title removeItemAtIndex:0];
885             }
886     
887             /* Create title menu */
888             for( i = 1 ; i < p_input->stream.i_area_nb ; i++ )
889             {
890                 char psz_title[ 256 ];
891                 NSString * o_menu_title;
892                 NSMenuItem * o_item;
893     
894                 snprintf( psz_title, sizeof(psz_title), "Title %d (%d)", i,
895                     p_input->stream.pp_areas[i]->i_part_nb );
896                 psz_title[sizeof(psz_title) - 1] = '\0';
897     
898                 o_menu_title = [NSString stringWithCString: psz_title];
899     
900                 o_item = [o_title addItemWithTitle: o_menu_title
901                         action: pf_toggle_title keyEquivalent: @""];
902                 [o_item setTag: i];
903                 [o_item setTarget: self];
904                 if( ( p_input->stream.pp_areas[i] ==
905                     p_input->stream.p_selected_area ) )
906                 {
907                     [o_item setState: 1];
908                 }
909             }
910         }
911         vlc_mutex_unlock( &p_input->stream.stream_lock );
912         vlc_mutex_lock( &p_input->stream.stream_lock );
913
914         /* ----- CHAPTERS ----- */
915         if( p_input->stream.p_selected_area->i_part_nb < 2 )
916         {
917             [o_chapter_item setEnabled:0];
918         }
919         else
920         {
921             [o_chapter_item setEnabled:1];
922             o_chapter = [o_chapter_item submenu];
923             pf_toggle_chapter = @selector(toggleChapter:);
924     
925             /* Remove previous chapter menu */
926             i_nb_items = [o_chapter numberOfItems];
927             for( i = 0; i < i_nb_items; i++ )
928             {
929                 [o_chapter removeItemAtIndex:0];
930             }
931     
932             /* Create chapter menu */
933             for( i = 0 ; i < p_input->stream.p_selected_area->i_part_nb ; i++ )
934             {
935                 char psz_title[ 256 ];
936                 NSString * o_menu_title;
937                 NSMenuItem * o_item;
938     
939                 snprintf( psz_title, sizeof(psz_title), "Chapter %d", i + 1 );
940                 psz_title[sizeof(psz_title) - 1] = '\0';
941     
942                 o_menu_title = [NSString stringWithCString: psz_title];
943     
944                 o_item = [o_chapter addItemWithTitle: o_menu_title
945                         action: pf_toggle_chapter keyEquivalent: @""];
946                 [o_item setTag: i + 1];
947                 [o_item setTarget: self];
948                 if( ( p_input->stream.p_selected_area->i_part == i + 1 ) )
949                 {
950                     [o_item setState: 1];
951                 }
952             }
953         }
954         p_main->p_intf->p_sys->i_part = p_input->stream.p_selected_area->i_part;
955         vlc_mutex_unlock( &p_input->stream.stream_lock );
956         vlc_mutex_lock( &p_input->stream.stream_lock );
957
958         /* ----- LANGUAGES & SUBTITLES ----- */
959         o_language = [o_language_item submenu];
960         o_subtitle = [o_subtitle_item submenu];
961         pf_toggle_language = @selector(toggleLanguage:);
962         pf_toggle_subtitle = @selector(toggleSubtitle:);
963
964         /* Remove previous language menu */
965         i_nb_items = [o_language numberOfItems];
966         for( i = 0; i < i_nb_items; i++ )
967         {
968             [o_language removeItemAtIndex:0];
969         }
970
971         /* Remove previous subtitle menu */
972         i_nb_items = [o_subtitle numberOfItems];
973         for( i = 0; i < i_nb_items; i++ )
974         {
975             [o_subtitle removeItemAtIndex:0];
976         }
977
978         /* Create language & subtitles menus */
979         for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
980         {
981             es_descriptor_t * p_es = p_input->stream.pp_es[i];
982             if( p_es->p_pgrm != NULL
983                  && p_es->p_pgrm != p_input->stream.p_selected_program )
984             {
985                 continue;
986             }
987
988             if( p_es->i_cat == AUDIO_ES )
989             {
990                 NSString * o_menu_title;
991                 NSMenuItem * o_item;
992
993                 if( *p_es->psz_desc )
994                 {
995                     o_menu_title = [NSString stringWithCString: p_es->psz_desc];
996                 }
997                 else
998                 {
999                     char psz_title[ 256 ];
1000                     snprintf( psz_title, sizeof(psz_title), "Language 0x%x",
1001                               p_es->i_id );
1002                     psz_title[sizeof(psz_title) - 1] = '\0';
1003     
1004                     o_menu_title = [NSString stringWithCString: psz_title];
1005                 }
1006     
1007                 o_item = [o_language addItemWithTitle: o_menu_title
1008                           action: pf_toggle_language keyEquivalent: @""];
1009                 [o_item setTag: i];
1010                 [o_item setTarget: self];
1011                 [o_item setEnabled: 1];
1012                 if( p_es->p_decoder_fifo != NULL )
1013                 {
1014                     [o_item setState: 1];
1015                 }
1016             }
1017             else if( p_es->i_cat == SPU_ES )
1018             {
1019                 NSString * o_menu_title;
1020                 NSMenuItem * o_item;
1021
1022                 if( *p_es->psz_desc )
1023                 {
1024                     o_menu_title = [NSString stringWithCString: p_es->psz_desc];
1025                 }
1026                 else
1027                 {
1028                     char psz_title[ 256 ];
1029                     snprintf( psz_title, sizeof(psz_title), "Subtitle 0x%x",
1030                               p_es->i_id );
1031                     psz_title[sizeof(psz_title) - 1] = '\0';
1032     
1033                     o_menu_title = [NSString stringWithCString: psz_title];
1034                 }
1035     
1036                 o_item = [o_subtitle addItemWithTitle: o_menu_title
1037                           action: pf_toggle_subtitle keyEquivalent: @""];
1038                 [o_item setTag: i];
1039                 [o_item setTarget: self];
1040                 [o_item setEnabled: 1];
1041                 if( p_es->p_decoder_fifo != NULL )
1042                 {
1043                     [o_item setState: 1];
1044                 }
1045             }
1046         }
1047
1048         if( [o_language numberOfItems] )
1049         {
1050             [o_language_item setEnabled: 1];
1051         }
1052         else
1053         {
1054             [o_language_item setEnabled: 0];
1055         }
1056         if( [o_subtitle numberOfItems] )
1057         {
1058             [o_subtitle_item setEnabled: 1];
1059         }
1060         else
1061         {
1062             [o_subtitle_item setEnabled: 0];
1063         }
1064         p_input->stream.b_changed = 0;
1065     }
1066 }
1067
1068 @end