]> git.sesse.net Git - vlc/blob - modules/gui/macosx/controls.m
* modules/demux/mkv.cpp: Set English as the default for track language.
[vlc] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface plugin
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: controls.m,v 1.50 2003/10/31 15:54:53 hartman Exp $
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <thedj@users.sourceforge.net>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <sys/param.h>                                    /* for MAXPATHLEN */
31 #include <string.h>
32
33 #include "intf.h"
34 #include "vout.h"
35 #include "open.h"
36 #include "controls.h"
37 #include <osd.h>
38
39 /*****************************************************************************
40  * VLCControls implementation 
41  *****************************************************************************/
42 @implementation VLCControls
43
44 - (IBAction)play:(id)sender
45 {
46     intf_thread_t * p_intf = [NSApp getIntf];
47
48     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
49                                                        FIND_ANYWHERE );
50     if( p_playlist == NULL )
51     {
52         return;
53     }
54
55     if( playlist_IsPlaying( p_playlist ) )
56     {
57         vout_OSDMessage( p_intf, _( "Pause" ) );
58         playlist_Pause( p_playlist );
59         vlc_object_release( p_playlist );
60     }
61     else
62     {
63         if( !playlist_IsEmpty( p_playlist ) )
64         {
65             playlist_Play( p_playlist );
66             vout_OSDMessage( p_intf, _( "Play" ) );
67             vlc_object_release( p_playlist );
68         }
69         else
70         {
71             vlc_object_release( p_playlist );
72             [o_open openFileGeneric: nil];
73         }
74     }
75 }
76
77 - (IBAction)stop:(id)sender
78 {
79     intf_thread_t * p_intf = [NSApp getIntf];
80     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
81                                                        FIND_ANYWHERE );
82     if( p_playlist != NULL )
83     {
84         vout_OSDMessage( p_intf, _( "Stop" ) );
85         playlist_Stop( p_playlist );
86         vlc_object_release( p_playlist );
87     }
88 }
89
90 - (IBAction)faster:(id)sender
91 {
92     intf_thread_t * p_intf = [NSApp getIntf];
93     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
94                                                        FIND_ANYWHERE );
95     if( p_input != NULL )
96     {
97         vlc_value_t val; val.b_bool = VLC_TRUE;
98
99         var_Set( p_input, "rate-faster", val );
100         vout_OSDMessage( p_intf, _( "Faster" ) );
101         vlc_object_release( p_input );
102     }
103 }
104
105 - (IBAction)slower:(id)sender
106 {
107     intf_thread_t * p_intf = [NSApp getIntf];
108     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
109                                                        FIND_ANYWHERE );
110     if( p_input != NULL )
111     {
112         vlc_value_t val; val.b_bool = VLC_TRUE;
113
114         var_Set( p_input, "rate-slower", val );
115         vout_OSDMessage( p_intf, _( "Slower" ) );
116         vlc_object_release( p_input );
117     }
118 }
119
120 - (IBAction)prev:(id)sender
121 {
122     vlc_value_t val;
123     intf_thread_t * p_intf = [NSApp getIntf];
124
125     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
126                                                        FIND_ANYWHERE );
127     if( p_playlist == NULL )
128     {
129         return;
130     }
131
132     vlc_mutex_lock( &p_playlist->object_lock );
133
134     if( p_playlist->p_input == NULL )
135     {
136         vlc_mutex_unlock( &p_playlist->object_lock );
137         vlc_object_release( p_playlist );  
138         return;
139     }
140
141     vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
142     val.b_bool = VLC_TRUE;
143
144 #define p_area p_playlist->p_input->stream.p_selected_area
145     if( p_area->i_part > 0 && p_area->i_part_nb > 1)
146     {
147         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
148         var_Set( p_playlist->p_input, "prev-chapter", val );
149         vlc_mutex_unlock( &p_playlist->object_lock );
150     }
151     else if( p_area->i_id > 1 )
152     {
153         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
154         var_Set( p_playlist->p_input, "prev-title", val );
155         vlc_mutex_unlock( &p_playlist->object_lock );
156     }
157     else
158     {
159         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
160         vlc_mutex_unlock( &p_playlist->object_lock );
161         playlist_Prev( p_playlist );
162     }
163 #undef p_area
164
165     vlc_object_release( p_playlist );
166     vout_OSDMessage( p_intf, _( "Previous" ) );
167 }
168
169 - (IBAction)next:(id)sender
170 {
171     vlc_value_t val;
172     intf_thread_t * p_intf = [NSApp getIntf];
173
174     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
175                                                        FIND_ANYWHERE );
176     if( p_playlist == NULL )
177     {
178         return;
179     }
180     
181     vlc_mutex_lock( &p_playlist->object_lock );
182
183     if( p_playlist->p_input == NULL )
184     {
185         vlc_mutex_unlock( &p_playlist->object_lock );
186         vlc_object_release( p_playlist );  
187         return;
188     }
189
190     vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
191     val.b_bool = VLC_TRUE;
192
193 #define p_area p_playlist->p_input->stream.p_selected_area
194     if( p_area->i_part < p_area->i_part_nb - 1 && p_area->i_part_nb > 1 )
195     {
196         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
197         var_Set( p_playlist->p_input, "next-chapter", val );
198         vlc_mutex_unlock( &p_playlist->object_lock );
199     }
200     else if( p_area->i_id < p_playlist->p_input->stream.i_area_nb && p_playlist->p_input->stream.i_area_nb > 1 )
201     {
202         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
203         var_Set( p_playlist->p_input, "next-title", val );
204         vlc_mutex_unlock( &p_playlist->object_lock );
205     }
206     else
207     {
208         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
209         vlc_mutex_unlock( &p_playlist->object_lock );
210         playlist_Next( p_playlist );
211     }
212 #undef p_area
213
214     vlc_object_release( p_playlist );
215     vout_OSDMessage( p_intf, _( "Next" ) );
216 }
217
218 - (IBAction)random:(id)sender
219 {
220     intf_thread_t * p_intf = [NSApp getIntf];
221     vlc_value_t val;
222     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
223                                                        FIND_ANYWHERE );
224     if( p_playlist == NULL )
225     {
226         return;
227     }
228
229     var_Get( p_playlist, "random", &val );
230     val.b_bool = !val.b_bool;
231     var_Set( p_playlist, "random", val );
232     if( val.b_bool )
233     {
234         vout_OSDMessage( p_intf, _( "Shuffle On" ) );
235     }
236     else
237     {
238         vout_OSDMessage( p_intf, _( "Shuffle Off" ) );
239     }    
240
241     vlc_object_release( p_playlist );
242 }
243
244 - (IBAction)repeat:(id)sender
245 {
246     intf_thread_t * p_intf = [NSApp getIntf];
247     vlc_value_t val;
248     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
249                                                        FIND_ANYWHERE );
250     if( p_playlist == NULL )
251     {
252         return;
253     }
254
255     var_Get( p_playlist, "repeat", &val );
256     val.b_bool = !val.b_bool;
257     var_Set( p_playlist, "repeat", val );
258     if( val.b_bool )
259     {
260         vout_OSDMessage( p_intf, _( "Repeat On" ) );
261     }
262     else
263     {
264         vout_OSDMessage( p_intf, _( "Repeat Off" ) );
265     }    
266
267     vlc_object_release( p_playlist );
268 }
269
270 - (IBAction)loop:(id)sender
271 {
272     intf_thread_t * p_intf = [NSApp getIntf];
273     vlc_value_t val;
274     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
275                                                        FIND_ANYWHERE );
276     if( p_playlist == NULL )
277     {
278         return;
279     }
280
281     var_Get( p_playlist, "loop", &val );
282     val.b_bool = !val.b_bool;
283     var_Set( p_playlist, "loop", val );
284     if( val.b_bool )
285     {
286         vout_OSDMessage( p_intf, _( "Loop On" ) );
287     }
288     else
289     {
290         vout_OSDMessage( p_intf, _( "Loop Off" ) );
291     }    
292
293     vlc_object_release( p_playlist );
294 }
295
296 - (IBAction)forward:(id)sender
297 {
298     intf_thread_t * p_intf = [NSApp getIntf];
299     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
300                                                        FIND_ANYWHERE );
301     if( p_input != NULL )
302     {
303         vlc_value_t time;
304         time.i_time = 5 * 1000000;
305         var_Set( p_input, "time-offset", time );
306         vlc_object_release( p_input );
307     }
308 }
309
310 - (IBAction)backward:(id)sender
311 {
312     intf_thread_t * p_intf = [NSApp getIntf];
313     input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
314                                                        FIND_ANYWHERE );
315     if( p_input != NULL )
316     {
317         vlc_value_t time;
318         time.i_time = -5 * 1000000;
319         var_Set( p_input, "time-offset", time );
320         vlc_object_release( p_input );
321     }
322 }
323
324 - (IBAction)volumeUp:(id)sender
325 {
326     intf_thread_t * p_intf = [NSApp getIntf];
327
328     if( p_intf->p_sys->b_mute )
329     {
330         [self mute: nil];
331     }
332
333     aout_VolumeUp( p_intf, 1, NULL );
334
335     [self updateVolumeSlider];
336 }
337
338 - (IBAction)volumeDown:(id)sender
339 {
340     intf_thread_t * p_intf = [NSApp getIntf];
341
342     if( p_intf->p_sys->b_mute )
343     {
344         [self mute: nil];
345     }
346     
347     aout_VolumeDown( p_intf, 1, NULL );
348
349     [self updateVolumeSlider];
350 }
351
352 - (IBAction)mute:(id)sender
353 {
354     intf_thread_t * p_intf = [NSApp getIntf];
355     audio_volume_t i_volume;
356
357     aout_VolumeMute( p_intf, &i_volume );
358     p_intf->p_sys->b_mute = ( i_volume == 0 );
359
360     [self updateVolumeSlider];
361 }
362
363 - (IBAction)volumeSliderUpdated:(id)sender
364 {
365     intf_thread_t * p_intf = [NSApp getIntf];
366     audio_volume_t i_volume = (audio_volume_t)[sender intValue];
367
368     aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
369 }
370
371 - (void)updateVolumeSlider
372 {
373     intf_thread_t * p_intf = [NSApp getIntf];
374     audio_volume_t i_volume;
375     char string[9];
376
377     aout_VolumeGet( p_intf, &i_volume );
378
379     [o_volumeslider setFloatValue: (float)(i_volume / AOUT_VOLUME_STEP)];
380
381     sprintf( string, "Vol %d%%", i_volume*100/AOUT_VOLUME_MAX );
382     vout_OSDMessage( p_intf, string );
383 }
384
385 - (IBAction)windowAction:(id)sender
386 {
387     id o_window = [NSApp keyWindow];
388     NSString *o_title = [sender title];
389     NSArray *o_windows = [NSApp windows];
390     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
391     vout_thread_t   *p_vout = vlc_object_find( [NSApp getIntf], VLC_OBJECT_VOUT,
392                                               FIND_ANYWHERE );
393
394     if( p_vout != NULL )
395     {
396         while ((o_window = [o_enumerator nextObject]))
397         {
398             if( [[o_window className] isEqualToString: @"VLCWindow"] )
399             {
400                 if( [o_title isEqualToString: _NS("Fullscreen") ] )
401                     [o_window toggleFullscreen];
402                 else if( [o_title isEqualToString: _NS("Half Size") ] )
403                     [o_window scaleWindowWithFactor: 0.5];
404                 else if( [o_title isEqualToString: _NS("Normal Size") ] )
405                     [o_window scaleWindowWithFactor: 1.0];
406                 else if( [o_title isEqualToString: _NS("Double Size") ] )
407                     [o_window scaleWindowWithFactor: 2.0];
408                 else if( [o_title isEqualToString: _NS("Float On Top") ] )
409                     [o_window toggleFloatOnTop];
410                 else if( [o_title isEqualToString: _NS("Fit To Screen") ] )
411                 {
412                     if( ![o_window isZoomed] )
413                         [o_window performZoom:self];
414                 }
415             }
416         }
417         vlc_object_release( (vlc_object_t *)p_vout );
418     }
419 }
420
421 - (void)setupVarMenuItem:(NSMenuItem *)o_mi
422                     target:(vlc_object_t *)p_object
423                     var:(const char *)psz_variable
424                     selector:(SEL)pf_callback
425 {
426     vlc_value_t val, text;
427     int i_type = var_Type( p_object, psz_variable );
428
429     switch( i_type & VLC_VAR_TYPE )
430     {
431     case VLC_VAR_VOID:
432     case VLC_VAR_BOOL:
433     case VLC_VAR_VARIABLE:
434     case VLC_VAR_STRING:
435     case VLC_VAR_INTEGER:
436         break;
437     default:
438         /* Variable doesn't exist or isn't handled */
439         return;
440     }
441     
442     /* Make sure we want to display the variable */
443     if( i_type & VLC_VAR_HASCHOICE )
444     {
445         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
446         if( val.i_int == 0 ) return;
447         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
448             return;
449     }
450     
451     /* Get the descriptive name of the variable */
452     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
453     [o_mi setTitle: [NSApp localizedString: text.psz_string ?
454                                         text.psz_string : strdup( psz_variable ) ]];
455
456     var_Get( p_object, psz_variable, &val );
457     if( i_type & VLC_VAR_HASCHOICE )
458     {
459         NSMenu *o_menu = [o_mi submenu];
460
461         [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
462                         var:psz_variable selector:pf_callback];
463         
464         if( text.psz_string ) free( text.psz_string );
465         return;
466     }
467
468     VLCMenuExt *o_data;
469     switch( i_type & VLC_VAR_TYPE )
470     {
471     case VLC_VAR_VOID:
472         o_data = [[VLCMenuExt alloc] initWithVar: psz_variable Object: p_object->i_object_id
473                 Value: val ofType: i_type];
474         [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
475         break;
476
477     case VLC_VAR_BOOL:
478         o_data = [[VLCMenuExt alloc] initWithVar: psz_variable Object: p_object->i_object_id
479                 Value: val ofType: i_type];
480         [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
481         [o_mi setState: val.b_bool ? TRUE : FALSE ];
482         break;
483
484     default:
485         if( text.psz_string ) free( text.psz_string );
486         return;
487     }
488
489     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
490     if( text.psz_string ) free( text.psz_string );
491 }
492
493
494 - (void)setupVarMenu:(NSMenu *)o_menu
495                     forMenuItem: (NSMenuItem *)o_parent
496                     target:(vlc_object_t *)p_object
497                     var:(const char *)psz_variable
498                     selector:(SEL)pf_callback
499 {
500     vlc_value_t val, val_list, text_list;
501     int i_type, i, i_nb_items;
502
503     /* remove previous items */
504     i_nb_items = [o_menu numberOfItems];
505     for( i = 0; i < i_nb_items; i++ )
506     {
507         [o_menu removeItemAtIndex: 0];
508     }
509
510     /* Check the type of the object variable */
511     i_type = var_Type( p_object, psz_variable );
512
513     /* Make sure we want to display the variable */
514     if( i_type & VLC_VAR_HASCHOICE )
515     {
516         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
517         if( val.i_int == 0 ) return;
518         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
519             return;
520     }
521     else
522     {
523         return;
524     }
525
526     switch( i_type & VLC_VAR_TYPE )
527     {
528     case VLC_VAR_VOID:
529     case VLC_VAR_BOOL:
530     case VLC_VAR_VARIABLE:
531     case VLC_VAR_STRING:
532     case VLC_VAR_INTEGER:
533         break;
534     default:
535         /* Variable doesn't exist or isn't handled */
536         return;
537     }
538
539     if( var_Get( p_object, psz_variable, &val ) < 0 )
540     {
541         return;
542     }
543
544     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
545                     &val_list, &text_list ) < 0 )
546     {
547         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
548         return;
549     }
550
551     /* make (un)sensitive */
552     [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];
553
554     for( i = 0; i < val_list.p_list->i_count; i++ )
555     {
556         vlc_value_t another_val;
557         NSMenuItem * o_lmi;
558         NSString *o_title = @"";
559         VLCMenuExt *o_data;
560
561         switch( i_type & VLC_VAR_TYPE )
562         {
563         case VLC_VAR_VARIABLE:
564
565             /* This is causing crashes for the moment.
566             o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
567                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
568             
569             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
570                 Value: val ofType: i_type];
571             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
572
573             // Create a submenu
574             NSMenu *o_menu = [o_lmi submenu];
575
576             [self setupVarMenu: o_menu forMenuItem: o_lmi target:p_object
577                             var:psz_variable selector:pf_callback];
578 */
579             return;
580
581         case VLC_VAR_STRING:
582             another_val.psz_string =
583                 strdup(val_list.p_list->p_values[i].psz_string);
584
585             o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
586                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
587
588             o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
589             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
590                     Value: another_val ofType: i_type];
591             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
592             [o_lmi setTarget: self];
593             
594             if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) )
595                 [o_lmi setState: TRUE ];
596
597             break;
598
599         case VLC_VAR_INTEGER:
600
601              o_title = text_list.p_list->p_values[i].psz_string ?
602                                  [NSApp localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
603                                  [NSString stringWithFormat: @"%d",
604                                  val_list.p_list->p_values[i].i_int];
605
606             o_lmi = [[o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""] retain ];
607             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
608                     Value: val_list.p_list->p_values[i] ofType: i_type];
609             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[ o_data retain]]];
610             [o_lmi setTarget: self];
611
612             if( val_list.p_list->p_values[i].i_int == val.i_int )
613                 [o_lmi setState: TRUE ];
614             break;
615
616         default:
617           break;
618         }
619     }
620     
621     /* clean up everything */
622     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
623     var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
624 }
625
626 - (IBAction)toggleVar:(id)sender
627 {
628     NSMenuItem *o_mi = (NSMenuItem *)sender;
629     VLCMenuExt *o_data = [[o_mi representedObject] pointerValue];
630     [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
631         toTarget: self withObject: o_data];
632
633     return;
634 }
635
636 - (int)toggleVarThread: (id)_o_data
637 {
638     vlc_object_t *p_object;
639     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
640     VLCMenuExt *o_data = (VLCMenuExt *)_o_data;
641
642     vlc_thread_set_priority( [NSApp getIntf] , VLC_THREAD_PRIORITY_LOW );
643
644     p_object = (vlc_object_t *)vlc_object_get( [NSApp getIntf],
645                                     [o_data objectID] );
646
647     if( p_object != NULL )
648     {
649         var_Set( p_object, strdup([o_data name]), [o_data value] );
650         vlc_object_release( p_object );
651         [o_pool release];
652         return VLC_TRUE;
653     }
654     [o_pool release];
655     return VLC_EGENERIC;
656 }
657
658 @end
659
660 @implementation VLCControls (NSMenuValidation)
661  
662 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
663 {
664     BOOL bEnabled = TRUE;
665     vlc_value_t val;
666     intf_thread_t * p_intf = [NSApp getIntf];
667     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
668                                                        FIND_ANYWHERE );
669
670     if( p_playlist != NULL )
671     {
672         vlc_mutex_lock( &p_playlist->object_lock );
673     }
674
675 #define p_input p_playlist->p_input
676
677     if( [[o_mi title] isEqualToString: _NS("Faster")] ||
678         [[o_mi title] isEqualToString: _NS("Slower")] )
679     {
680         if( p_playlist != NULL && p_input != NULL )
681         {
682             vlc_mutex_lock( &p_input->stream.stream_lock );
683             bEnabled = p_input->stream.b_pace_control;
684             vlc_mutex_unlock( &p_input->stream.stream_lock );
685         }
686         else
687         {
688             bEnabled = FALSE;
689         }
690     }
691     else if( [[o_mi title] isEqualToString: _NS("Stop")] )
692     {
693         if( p_playlist == NULL || p_input == NULL )
694         {
695             bEnabled = FALSE;
696         }
697     }
698     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
699              [[o_mi title] isEqualToString: _NS("Next")] )
700     {
701         if( p_playlist == NULL )
702         {
703             bEnabled = FALSE;
704         }
705         else
706         {
707             bEnabled = p_playlist->i_size > 1;
708
709             if( p_input != NULL )
710             {
711                 vlc_mutex_lock( &p_input->stream.stream_lock );
712                 bEnabled |= p_input->stream.i_area_nb > 1;
713                 vlc_mutex_unlock( &p_input->stream.stream_lock );
714             }
715         }
716     }
717     else if( [[o_mi title] isEqualToString: _NS("Shuffle")] )
718     {
719         int i_state;
720         var_Get( p_playlist, "random", &val );
721         i_state = val.b_bool ? NSOnState : NSOffState;
722         [o_mi setState: i_state];
723     }
724     else if( [[o_mi title] isEqualToString: _NS("Repeat Item")] )
725     {
726         int i_state;
727         var_Get( p_playlist, "repeat", &val );
728         i_state = val.b_bool ? NSOnState : NSOffState;
729         [o_mi setState: i_state];
730     }
731     else if( [[o_mi title] isEqualToString: _NS("Repeat Playlist")] )
732     {
733         int i_state;
734         var_Get( p_playlist, "loop", &val );
735         i_state = val.b_bool ? NSOnState : NSOffState;
736         [o_mi setState: i_state];
737     }
738     else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
739              [[o_mi title] isEqualToString: _NS("Step Backward")] )
740     {
741         if( p_playlist != NULL && p_input != NULL )
742         {
743             vlc_mutex_lock( &p_input->stream.stream_lock );
744             bEnabled = p_input->stream.b_seekable;
745             vlc_mutex_unlock( &p_input->stream.stream_lock );
746         }
747         else
748         {
749             bEnabled = FALSE;
750         }
751     }
752     else if( [[o_mi title] isEqualToString: _NS("Mute")] ) 
753     {
754         [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
755     }
756     else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
757                 [[o_mi title] isEqualToString: _NS("Half Size")] ||
758                 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
759                 [[o_mi title] isEqualToString: _NS("Double Size")] ||
760                 [[o_mi title] isEqualToString: _NS("Fit To Screen")] ||
761                 [[o_mi title] isEqualToString: _NS("Float On Top")] )
762     {
763         id o_window;
764         NSArray *o_windows = [NSApp windows];
765         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
766         bEnabled = FALSE;
767         
768         if ( [[o_mi title] isEqualToString: _NS("Float On Top")] )
769         {
770             int i_state = config_GetInt( p_playlist, "macosx-float" ) ?
771                       NSOnState : NSOffState;
772             [o_mi setState: i_state];
773         }
774         
775         vout_thread_t   *p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
776                                               FIND_ANYWHERE );
777         if( p_vout != NULL )
778         {
779             while ((o_window = [o_enumerator nextObject]))
780             {
781                 if( [[o_window className] isEqualToString: @"VLCWindow"] )
782                 {
783                     bEnabled = TRUE;
784                     break;
785                 }
786             }
787             vlc_object_release( (vlc_object_t *)p_vout );
788         }
789     }
790
791     if( p_playlist != NULL )
792     {
793         vlc_mutex_unlock( &p_playlist->object_lock );
794         vlc_object_release( p_playlist );
795     }
796
797     return( bEnabled );
798 }
799
800 @end
801
802 /*****************************************************************************
803  * VLCMenuExt implementation 
804  *****************************************************************************
805  * Object connected to a playlistitem which remembers the data belonging to
806  * the variable of the autogenerated menu
807  *****************************************************************************/
808 @implementation VLCMenuExt
809
810 - (id)initWithVar: (const char *)_psz_name Object: (int)i_id
811         Value: (vlc_value_t)val ofType: (int)_i_type
812 {
813     self = [super init];
814
815     if( self != nil )
816     {
817         psz_name = strdup( _psz_name );
818         i_object_id = i_id;
819         value = val;
820         i_type = _i_type;
821     }
822
823     return( self );
824 }
825
826 - (void)dealloc
827 {
828     free( psz_name );
829 }
830
831 - (char *)name
832 {
833     return psz_name;
834 }
835
836 - (int)objectID
837 {
838     return i_object_id;
839 }
840
841 - (vlc_value_t)value
842 {
843     return value;
844 }
845
846 - (int)type
847 {
848     return i_type;
849 }
850
851 @end