]> git.sesse.net Git - vlc/blob - plugins/macosx/intf_vlc_wrapper.m
Removed unused headers.
[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.6 2002/05/19 23:51:37 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)playSlower
206 {
207     if( p_input_bank->pp_input[0] != NULL )
208     {
209         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_SLOWER );
210
211         vlc_mutex_lock( &p_main->p_playlist->change_lock );
212         p_main->p_playlist->b_stopped = 0;
213         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
214     }
215 }
216
217 - (void)playFaster
218 {
219     if( p_input_bank->pp_input[0] != NULL )
220     {
221         input_SetStatus( p_input_bank->pp_input[0], INPUT_STATUS_FASTER );
222
223         vlc_mutex_lock( &p_main->p_playlist->change_lock );
224         p_main->p_playlist->b_stopped = 0;
225         vlc_mutex_unlock( &p_main->p_playlist->change_lock );
226     }
227 }
228
229 - (void)mute
230 {
231     if( p_aout_bank->pp_aout[0] == NULL ) return;
232
233     if( p_main->p_intf->p_sys->b_mute )
234     {
235         p_aout_bank->pp_aout[0]->i_volume = 
236                             p_main->p_intf->p_sys->i_saved_volume;
237     }
238     else
239     {
240         p_main->p_intf->p_sys->i_saved_volume = 
241                             p_aout_bank->pp_aout[0]->i_volume;
242         p_aout_bank->pp_aout[0]->i_volume = 0;
243     }
244     p_main->p_intf->p_sys->b_mute = !p_main->p_intf->p_sys->b_mute;
245 }
246
247 - (void)maxvolume
248 {
249     if( p_aout_bank->pp_aout[0] == NULL ) return;
250
251     if( p_main->p_intf->p_sys->b_mute )
252     {
253         p_main->p_intf->p_sys->i_saved_volume = VOLUME_MAX;
254     }
255     else
256     {
257         p_aout_bank->pp_aout[0]->i_volume = VOLUME_MAX;
258     }
259 }
260
261 - (void)fullscreen
262 {
263     if( p_vout_bank->pp_vout[0] != NULL )
264     {
265         p_vout_bank->pp_vout[0]->i_changes |= VOUT_FULLSCREEN_CHANGE;
266     }
267 }
268
269 - (void)eject
270 {
271     /* FIXME : this will only eject the first drive found */
272     NSArray * o_devices = GetEjectableMediaOfClass(kIODVDMediaClass);
273     const char * psz_device;
274
275     if ( p_input_bank->pp_input[0] != NULL &&
276          (p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_VCD ||
277           p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_DVD ||
278           p_input_bank->pp_input[0]->stream.i_method == INPUT_METHOD_DISC) )
279     {
280         intf_ErrMsg("error: cannot eject the disc while you're reading from it");
281         return;
282     }
283
284     if ( o_devices == nil )
285     {
286         o_devices = GetEjectableMediaOfClass(kIOCDMediaClass);
287     }
288
289     if ( o_devices != nil && [o_devices count] )
290     { 
291         psz_device = [[o_devices objectAtIndex:0] cString];
292         intf_Eject( psz_device );
293     }
294 }
295
296 /* playback info */
297
298 #define p_area p_input_bank->pp_input[0]->stream.p_selected_area
299
300 - (NSString *)getTimeAsString
301 {
302     static char psz_currenttime[ OFFSETTOTIME_MAX_SIZE ];
303         
304     if( p_input_bank->pp_input[0] == NULL )
305     {
306         return [NSString stringWithCString:"00:00:00"];
307     }     
308    
309     input_OffsetToTime( p_input_bank->pp_input[0], 
310                         psz_currenttime, p_area->i_tell );        
311
312     return( [NSString stringWithCString: psz_currenttime] );
313 }
314     
315 - (float)getTimeAsFloat
316 {
317     float f_time = 0.0;
318
319     if( p_input_bank->pp_input[0] != NULL )
320     {
321         f_time = (float)p_area->i_tell / (float)p_area->i_size;
322     }    
323
324     return( f_time );
325 }
326
327 - (void)setTimeAsFloat:(float)f_position
328 {
329     if( p_input_bank->pp_input[0] != NULL )
330     {
331         input_Seek( p_input_bank->pp_input[0], p_area->i_size * f_position );
332     }
333 }
334
335 #undef p_area
336
337 - (bool)playlistPlaying
338 {
339     return( !p_main->p_playlist->b_stopped );
340 }
341
342 - (NSArray *)playlistAsArray
343 {
344     int i;
345     NSMutableArray* p_list = 
346         [NSMutableArray arrayWithCapacity: p_main->p_playlist->i_size];
347     
348     vlc_mutex_lock( &p_main->p_playlist->change_lock );
349
350     for( i = 0; i < p_main->p_playlist->i_size; i++ )
351     {
352         [p_list addObject: [NSString 
353             stringWithCString: p_main->p_playlist->p_item[i].psz_name]];
354     }
355
356     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
357         
358     return( [NSArray arrayWithArray: p_list] );
359 }
360
361 /*
362 - (int)playlistLength
363 {
364     return( p_main->p_playlist->i_size );
365 }
366
367 - (NSString*)playlistItem:(int)i_pos
368 {
369     NSString *o_item = nil;
370
371     vlc_mutex_lock( &p_main->p_playlist->change_lock );
372     
373     if( i_pos < p_main->p_playlist->i_size )
374     {
375         o_item = [NSString 
376             stringWithCString: p_main->p_playlist->p_item[i_pos].psz_name];
377     }
378
379     vlc_mutex_unlock( &p_main->p_playlist->change_lock );
380
381     return( o_item );
382 }
383
384 - (void)playlistPlayItem:(int)i_item
385 {
386     [self playlistStop];
387
388     vlc_mutex_lock( &p_main->p_playlist->change_lock );
389
390     if( i_item<p_main->p_playlist->i_size )
391     {
392         p_main->p_playlist->i_index--;
393     }
394
395     vlc_mutex_unlock( &p_main->p_playlist->change_lock );        
396
397     [self playlistPlayCurrent];
398 }
399     
400 - (void)playlistAdd:(NSString *)o_filename
401 {
402     intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
403                       [o_filename lossyCString] );
404 }
405     
406 - (void)clearPlaylist
407 {
408     int i;
409     
410     vlc_mutex_lock( &p_main->p_playlist->change_lock );
411
412     for( i = 0; i < p_main->p_playlist->i_size; i++ )
413     {
414         intf_PlaylistDelete( p_main->p_playlist, i );
415     }
416
417     vlc_mutex_unlock( &p_main->p_playlist->change_lock );        
418 }
419 */
420
421 /* open file/disc/network */
422
423 - (void)openFiles:(NSArray*)o_files
424 {
425     NSString *o_file;
426     int i_end = p_main->p_playlist->i_size;
427     NSEnumerator *o_enum = [o_files objectEnumerator];
428
429     while( ( o_file = (NSString *)[o_enum nextObject] ) )
430     {
431         intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END, 
432                           [o_file lossyCString] );
433     }
434
435     /* end current item, select first added item */
436     if( p_input_bank->pp_input[0] != NULL )
437     {
438         p_input_bank->pp_input[0]->b_eof = 1;
439     }
440
441     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
442 }
443
444 - (void)openDisc:(NSString*)o_type device:(NSString*)o_device title:(int)i_title chapter:(int)i_chapter
445 {
446     NSString *o_source;
447     int i_end = p_main->p_playlist->i_size;
448
449     o_source = [NSString stringWithFormat: @"%@:%@@%d,%d", 
450                     o_type, o_device, i_title, i_chapter];
451
452     intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
453                       [o_source lossyCString] );
454
455     /* stop current item, select added item */
456     if( p_input_bank->pp_input[0] != NULL )
457     {
458         p_input_bank->pp_input[0]->b_eof = 1;
459     }
460
461     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
462 }
463
464 - (void)openNet:(NSString*)o_protocol addr:(NSString*)o_addr port:(int)i_port baddr:(NSString*)o_baddr
465 {
466     NSString *o_source;
467     int i_end = p_main->p_playlist->i_size;
468
469     if( p_input_bank->pp_input[0] != NULL )
470     {
471         p_input_bank->pp_input[0]->b_eof = 1;
472     }
473
474     config_PutIntVariable( "network_channel", 0 );
475
476     if( o_baddr != nil )
477     {
478         o_source = [NSString stringWithFormat: @"%@://%@@:%i/%@",
479                         o_protocol, o_addr, i_port, o_baddr];
480     }
481     else
482     {
483         o_source = [NSString stringWithFormat: @"%@://%@@:%i",
484                         o_protocol, o_addr, i_port];
485     }
486
487     intf_PlaylistAdd( p_main->p_playlist, PLAYLIST_END,
488                       [o_source lossyCString] );
489
490     intf_PlaylistJumpto( p_main->p_playlist, i_end - 1 );
491 }
492
493 - (void)openNetChannel:(NSString*)o_addr port:(int)i_port
494 {
495     if( p_input_bank->pp_input[0] != NULL )
496     {
497         p_input_bank->pp_input[0]->b_eof = 1;
498     }
499
500     config_PutIntVariable( "network_channel", 1 );
501
502     if( p_main->p_channel == NULL )
503     {
504         network_ChannelCreate();
505     }
506
507     config_PutPszVariable( "channel_server", (char*)[o_addr lossyCString] );
508     config_PutIntVariable( "channel_port", i_port ); 
509 }
510
511 - (void)toggleProgram:(id)sender
512 {
513     NSMenuItem * o_item = (NSMenuItem *)sender;
514     input_thread_t * p_input = p_input_bank->pp_input[0];
515
516     if( [o_item state] == NSOffState )
517     {
518         u16 i_program_id = [o_item tag];
519
520         input_ChangeProgram( p_input, i_program_id );
521
522         vlc_mutex_lock( &p_input->stream.stream_lock );
523         [self setupMenus];
524         vlc_mutex_unlock( &p_input->stream.stream_lock );
525
526         input_SetStatus( p_input, INPUT_STATUS_PLAY );
527     }
528 }
529
530 - (void)toggleTitle:(id)sender
531 {
532     NSMenuItem * o_item = (NSMenuItem *)sender;
533     input_thread_t * p_input = p_input_bank->pp_input[0];
534
535     if( [o_item state] == NSOffState )
536     {
537         int i_title = [o_item tag];
538
539         input_ChangeArea( p_input,
540                           p_input->stream.pp_areas[i_title] );
541
542         vlc_mutex_lock( &p_input->stream.stream_lock );
543         [self setupMenus];
544         vlc_mutex_unlock( &p_input->stream.stream_lock );
545
546         input_SetStatus( p_input, INPUT_STATUS_PLAY );
547     }
548 }
549
550 - (void)toggleChapter:(id)sender
551 {
552     NSMenuItem * o_item = (NSMenuItem *)sender;
553     input_thread_t * p_input = p_input_bank->pp_input[0];
554
555     if( [o_item state] == NSOffState )
556     {
557         int i_chapter = [o_item tag];
558
559         p_input->stream.p_selected_area->i_part = i_chapter;
560         input_ChangeArea( p_input,
561                           p_input->stream.p_selected_area );
562
563         vlc_mutex_lock( &p_input->stream.stream_lock );
564         [self setupMenus];
565         vlc_mutex_unlock( &p_input->stream.stream_lock );
566
567         input_SetStatus( p_input, INPUT_STATUS_PLAY );
568     }
569 }
570
571 - (void)toggleLanguage:(id)sender
572 {
573     NSMenuItem * o_item = (NSMenuItem *)sender;
574     input_thread_t * p_input = p_input_bank->pp_input[0];
575
576     int i_es = [o_item tag];
577
578     if( [o_item state] == NSOnState )
579     {
580         /* We just have one ES to disable */
581         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 0 );
582     }
583     else
584     {
585         /* Unselect the selected ES in the same class */
586         int i;
587         vlc_mutex_lock( &p_input->stream.stream_lock );
588         for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
589         {
590             if( p_input->stream.pp_selected_es[i]->i_cat == AUDIO_ES )
591             {
592                 vlc_mutex_unlock( &p_input->stream.stream_lock );
593                 input_ToggleES( p_input, p_input->stream.pp_selected_es[i], 0 );
594                 vlc_mutex_lock( &p_input->stream.stream_lock );
595                 break;
596             }
597         }
598         vlc_mutex_unlock( &p_input->stream.stream_lock );
599
600         /* Select the wanted ES */
601         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 1 );
602     }
603
604     vlc_mutex_lock( &p_input->stream.stream_lock );
605     [self setupMenus];
606     vlc_mutex_unlock( &p_input->stream.stream_lock );
607
608     input_SetStatus( p_input, INPUT_STATUS_PLAY );
609 }
610
611 - (void)toggleSubtitle:(id)sender
612 {
613     NSMenuItem * o_item = (NSMenuItem *)sender;
614     input_thread_t * p_input = p_input_bank->pp_input[0];
615
616     int i_es = [o_item tag];
617
618     if( [o_item state] == NSOnState )
619     {
620         /* We just have one ES to disable */
621         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 0 );
622     }
623     else
624     {
625         /* Unselect the selected ES in the same class */
626         int i;
627         vlc_mutex_lock( &p_input->stream.stream_lock );
628         for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
629         {
630             if( p_input->stream.pp_selected_es[i]->i_cat == SPU_ES )
631             {
632                 vlc_mutex_unlock( &p_input->stream.stream_lock );
633                 input_ToggleES( p_input, p_input->stream.pp_selected_es[i], 0 );
634                 vlc_mutex_lock( &p_input->stream.stream_lock );
635                 break;
636             }
637         }
638         vlc_mutex_unlock( &p_input->stream.stream_lock );
639
640         /* Select the wanted ES */
641         input_ToggleES( p_input, p_input->stream.pp_es[i_es], 1 );
642     }
643
644     vlc_mutex_lock( &p_input->stream.stream_lock );
645     [self setupMenus];
646     vlc_mutex_unlock( &p_input->stream.stream_lock );
647
648     input_SetStatus( p_input, INPUT_STATUS_PLAY );
649 }
650
651 - (void)setupMenus
652 {
653     NSMenu *o_main_menu;
654     NSMenuItem *o_controls_item;
655     NSMenuItem *o_program_item, *o_title_item, *o_chapter_item, *o_language_item,
656                *o_subtitle_item;
657     input_thread_t * p_input = p_input_bank->pp_input[0];
658
659     o_main_menu  = [NSApp mainMenu];
660     o_controls_item  = [o_main_menu itemWithTitle: @"Controls"];
661     o_program_item = [[o_controls_item submenu] itemWithTitle: @"Program"]; 
662     o_title_item = [[o_controls_item submenu] itemWithTitle: @"Title"]; 
663     o_chapter_item = [[o_controls_item submenu] itemWithTitle: @"Chapter"]; 
664     o_language_item = [[o_controls_item submenu] itemWithTitle: @"Language"]; 
665     o_subtitle_item = [[o_controls_item submenu] itemWithTitle: @"Subtitles"]; 
666
667     if( p_input == NULL )
668     {
669         [o_program_item setEnabled:0];
670         [o_title_item setEnabled:0];
671         [o_chapter_item setEnabled:0];
672         [o_language_item setEnabled:0];
673         [o_subtitle_item setEnabled:0];
674     }
675     else
676     {
677         NSMenu *o_program, *o_title, *o_chapter, *o_language, *o_subtitle;
678         SEL pf_toggle_program, pf_toggle_title, pf_toggle_chapter,
679             pf_toggle_language, pf_toggle_subtitle;
680
681         int i, i_nb_items;
682         pgrm_descriptor_t * p_pgrm;
683
684         /* ----- PROGRAMS ----- */
685         if( p_input->stream.i_pgrm_number < 2 )
686         {
687             [o_program_item setEnabled:0];
688         }
689         else
690         {
691             [o_program_item setEnabled:1];
692             o_program = [o_program_item submenu];
693             pf_toggle_program = @selector(toggleProgram:);
694     
695             /* Remove previous program menu */
696             i_nb_items = [o_program numberOfItems];
697             for( i = 0; i < i_nb_items; i++ )
698             {
699                 [o_program removeItemAtIndex:0];
700             }
701     
702             if( p_input->stream.p_new_program )
703             {
704                 p_pgrm = p_input->stream.p_new_program;
705             }
706             else
707             {
708                 p_pgrm = p_input->stream.p_selected_program;
709             }
710     
711             /* Create program menu */
712             for( i = 0 ; i < p_input->stream.i_pgrm_number ; i++ )
713             {
714                 char psz_title[ 256 ];
715                 NSString * o_menu_title;
716                 NSMenuItem * o_item;
717     
718                 snprintf( psz_title, sizeof(psz_title), "id %d",
719                     p_input->stream.pp_programs[i]->i_number );
720                 psz_title[sizeof(psz_title) - 1] = '\0';
721     
722                 o_menu_title = [NSString stringWithCString: psz_title];
723     
724                 o_item = [o_program addItemWithTitle: o_menu_title
725                         action: pf_toggle_program keyEquivalent: @""];
726                 [o_item setTarget: self];
727                 [o_item setTag: p_input->stream.pp_programs[i]->i_number];
728                 if( p_pgrm == p_input->stream.pp_programs[i] )
729                 {
730                     [o_item setState: 1];
731                 }
732             }
733         }
734         vlc_mutex_unlock( &p_input->stream.stream_lock );
735         vlc_mutex_lock( &p_input->stream.stream_lock );
736
737         /* ----- TITLES ----- */
738         if( p_input->stream.i_area_nb < 2 )
739         {
740             [o_title_item setEnabled:0];
741         }
742         else
743         {
744             [o_title_item setEnabled:1];
745             o_title = [o_title_item submenu];
746             pf_toggle_title = @selector(toggleTitle:);
747     
748             /* Remove previous title menu */
749             i_nb_items = [o_title numberOfItems];
750             for( i = 0; i < i_nb_items; i++ )
751             {
752                 [o_title removeItemAtIndex:0];
753             }
754     
755             /* Create title menu */
756             for( i = 1 ; i < p_input->stream.i_area_nb ; i++ )
757             {
758                 char psz_title[ 256 ];
759                 NSString * o_menu_title;
760                 NSMenuItem * o_item;
761     
762                 snprintf( psz_title, sizeof(psz_title), "Title %d (%d)", i,
763                     p_input->stream.pp_areas[i]->i_part_nb );
764                 psz_title[sizeof(psz_title) - 1] = '\0';
765     
766                 o_menu_title = [NSString stringWithCString: psz_title];
767     
768                 o_item = [o_title addItemWithTitle: o_menu_title
769                         action: pf_toggle_title keyEquivalent: @""];
770                 [o_item setTag: i];
771                 [o_item setTarget: self];
772                 if( ( p_input->stream.pp_areas[i] ==
773                     p_input->stream.p_selected_area ) )
774                 {
775                     [o_item setState: 1];
776                 }
777             }
778         }
779         vlc_mutex_unlock( &p_input->stream.stream_lock );
780         vlc_mutex_lock( &p_input->stream.stream_lock );
781
782         /* ----- CHAPTERS ----- */
783         if( p_input->stream.p_selected_area->i_part_nb < 2 )
784         {
785             [o_chapter_item setEnabled:0];
786         }
787         else
788         {
789             [o_chapter_item setEnabled:1];
790             o_chapter = [o_chapter_item submenu];
791             pf_toggle_chapter = @selector(toggleChapter:);
792     
793             /* Remove previous chapter menu */
794             i_nb_items = [o_chapter numberOfItems];
795             for( i = 0; i < i_nb_items; i++ )
796             {
797                 [o_chapter removeItemAtIndex:0];
798             }
799     
800             /* Create chapter menu */
801             for( i = 0 ; i < p_input->stream.p_selected_area->i_part_nb ; i++ )
802             {
803                 char psz_title[ 256 ];
804                 NSString * o_menu_title;
805                 NSMenuItem * o_item;
806     
807                 snprintf( psz_title, sizeof(psz_title), "Chapter %d", i + 1 );
808                 psz_title[sizeof(psz_title) - 1] = '\0';
809     
810                 o_menu_title = [NSString stringWithCString: psz_title];
811     
812                 o_item = [o_chapter addItemWithTitle: o_menu_title
813                         action: pf_toggle_chapter keyEquivalent: @""];
814                 [o_item setTag: i];
815                 [o_item setTarget: self];
816                 if( ( p_input->stream.p_selected_area->i_part == i + 1 ) )
817                 {
818                     [o_item setState: 1];
819                 }
820             }
821         }
822         p_main->p_intf->p_sys->i_part = p_input->stream.p_selected_area->i_part;
823         vlc_mutex_unlock( &p_input->stream.stream_lock );
824         vlc_mutex_lock( &p_input->stream.stream_lock );
825
826         /* ----- LANGUAGES & SUBTITLES ----- */
827         o_language = [o_language_item submenu];
828         o_subtitle = [o_subtitle_item submenu];
829         pf_toggle_language = @selector(toggleLanguage:);
830         pf_toggle_subtitle = @selector(toggleSubtitle:);
831
832         /* Remove previous language menu */
833         i_nb_items = [o_language numberOfItems];
834         for( i = 0; i < i_nb_items; i++ )
835         {
836             [o_language removeItemAtIndex:0];
837         }
838
839         /* Remove previous subtitle menu */
840         i_nb_items = [o_subtitle numberOfItems];
841         for( i = 0; i < i_nb_items; i++ )
842         {
843             [o_subtitle removeItemAtIndex:0];
844         }
845
846         /* Create language & subtitles menus */
847         for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
848         {
849             es_descriptor_t * p_es = p_input->stream.pp_es[i];
850             if( p_es->p_pgrm != NULL
851                  && p_es->p_pgrm != p_input->stream.p_selected_program )
852             {
853                 continue;
854             }
855
856             if( p_es->i_cat == AUDIO_ES )
857             {
858                 NSString * o_menu_title;
859                 NSMenuItem * o_item;
860
861                 if( *p_es->psz_desc )
862                 {
863                     o_menu_title = [NSString stringWithCString: p_es->psz_desc];
864                 }
865                 else
866                 {
867                     char psz_title[ 256 ];
868                     snprintf( psz_title, sizeof(psz_title), "Language 0x%x",
869                               p_es->i_id );
870                     psz_title[sizeof(psz_title) - 1] = '\0';
871     
872                     o_menu_title = [NSString stringWithCString: psz_title];
873                 }
874     
875                 o_item = [o_language addItemWithTitle: o_menu_title
876                         action: pf_toggle_language keyEquivalent: @""];
877                 [o_item setTag: i];
878                 [o_item setTarget: self];
879                 if( p_es->p_decoder_fifo != NULL )
880                 {
881                     [o_item setState: 1];
882                 }
883             }
884             else if( p_es->i_cat == SPU_ES )
885             {
886                 NSString * o_menu_title;
887                 NSMenuItem * o_item;
888
889                 if( *p_es->psz_desc )
890                 {
891                     o_menu_title = [NSString stringWithCString: p_es->psz_desc];
892                 }
893                 else
894                 {
895                     char psz_title[ 256 ];
896                     snprintf( psz_title, sizeof(psz_title), "Subtitle 0x%x",
897                               p_es->i_id );
898                     psz_title[sizeof(psz_title) - 1] = '\0';
899     
900                     o_menu_title = [NSString stringWithCString: psz_title];
901                 }
902     
903                 o_item = [o_subtitle addItemWithTitle: o_menu_title
904                         action: pf_toggle_subtitle keyEquivalent: @""];
905                 [o_item setTag: i];
906                 [o_item setTarget: self];
907                 if( p_es->p_decoder_fifo != NULL )
908                 {
909                     [o_item setState: 1];
910                 }
911             }
912         }
913
914         if( [o_language numberOfItems] )
915         {
916             [o_language_item setEnabled: 1];
917         }
918         else
919         {
920             [o_language_item setEnabled: 0];
921         }
922         if( [o_subtitle numberOfItems] )
923         {
924             [o_subtitle_item setEnabled: 1];
925         }
926         else
927         {
928             [o_subtitle_item setEnabled: 0];
929         }
930         p_input->stream.b_changed = 0;
931     }
932 }
933
934 @end