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