]> git.sesse.net Git - vlc/blob - modules/gui/macosx/controls.m
* include/vlc_keys.h: added StringToKey()
[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.53 2003/11/11 23:50:41 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( (vlc_object_t *)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( (vlc_object_t *)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( (vlc_object_t *)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( (vlc_object_t *)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( (vlc_object_t *)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( (vlc_object_t *)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( (vlc_object_t *)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( (vlc_object_t *)p_intf, _( "Shuffle On" ) );
235     }
236     else
237     {
238         vout_OSDMessage( (vlc_object_t *)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( (vlc_object_t *)p_intf, _( "Repeat On" ) );
261     }
262     else
263     {
264         vout_OSDMessage( (vlc_object_t *)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( (vlc_object_t *)p_intf, _( "Loop On" ) );
287     }
288     else
289     {
290         vout_OSDMessage( (vlc_object_t *)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 = 10 * 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 = -10 * 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( (vlc_object_t *)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                 break;
416             }
417         }
418         vlc_object_release( (vlc_object_t *)p_vout );
419     }
420 }
421
422 - (void)setupVarMenuItem:(NSMenuItem *)o_mi
423                     target:(vlc_object_t *)p_object
424                     var:(const char *)psz_variable
425                     selector:(SEL)pf_callback
426 {
427     vlc_value_t val, text;
428     int i_type = var_Type( p_object, psz_variable );
429
430     switch( i_type & VLC_VAR_TYPE )
431     {
432     case VLC_VAR_VOID:
433     case VLC_VAR_BOOL:
434     case VLC_VAR_VARIABLE:
435     case VLC_VAR_STRING:
436     case VLC_VAR_INTEGER:
437         break;
438     default:
439         /* Variable doesn't exist or isn't handled */
440         return;
441     }
442     
443     /* Make sure we want to display the variable */
444     if( i_type & VLC_VAR_HASCHOICE )
445     {
446         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
447         if( val.i_int == 0 ) return;
448         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
449             return;
450     }
451     
452     /* Get the descriptive name of the variable */
453     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
454     [o_mi setTitle: [NSApp localizedString: text.psz_string ?
455                                         text.psz_string : strdup( psz_variable ) ]];
456
457     var_Get( p_object, psz_variable, &val );
458     if( i_type & VLC_VAR_HASCHOICE )
459     {
460         NSMenu *o_menu = [o_mi submenu];
461
462         [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
463                         var:psz_variable selector:pf_callback];
464         
465         if( text.psz_string ) free( text.psz_string );
466         return;
467     }
468
469     VLCMenuExt *o_data;
470     switch( i_type & VLC_VAR_TYPE )
471     {
472     case VLC_VAR_VOID:
473         o_data = [[VLCMenuExt alloc] initWithVar: psz_variable Object: p_object->i_object_id
474                 Value: val ofType: i_type];
475         [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
476         break;
477
478     case VLC_VAR_BOOL:
479         o_data = [[VLCMenuExt alloc] initWithVar: psz_variable Object: p_object->i_object_id
480                 Value: val ofType: i_type];
481         [o_mi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
482         [o_mi setState: val.b_bool ? TRUE : FALSE ];
483         break;
484
485     default:
486         if( text.psz_string ) free( text.psz_string );
487         return;
488     }
489
490     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
491     if( text.psz_string ) free( text.psz_string );
492 }
493
494
495 - (void)setupVarMenu:(NSMenu *)o_menu
496                     forMenuItem: (NSMenuItem *)o_parent
497                     target:(vlc_object_t *)p_object
498                     var:(const char *)psz_variable
499                     selector:(SEL)pf_callback
500 {
501     vlc_value_t val, val_list, text_list;
502     int i_type, i, i_nb_items;
503
504     /* remove previous items */
505     i_nb_items = [o_menu numberOfItems];
506     for( i = 0; i < i_nb_items; i++ )
507     {
508         [o_menu removeItemAtIndex: 0];
509     }
510
511     /* Check the type of the object variable */
512     i_type = var_Type( p_object, psz_variable );
513
514     /* Make sure we want to display the variable */
515     if( i_type & VLC_VAR_HASCHOICE )
516     {
517         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
518         if( val.i_int == 0 ) return;
519         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
520             return;
521     }
522     else
523     {
524         return;
525     }
526
527     switch( i_type & VLC_VAR_TYPE )
528     {
529     case VLC_VAR_VOID:
530     case VLC_VAR_BOOL:
531     case VLC_VAR_VARIABLE:
532     case VLC_VAR_STRING:
533     case VLC_VAR_INTEGER:
534         break;
535     default:
536         /* Variable doesn't exist or isn't handled */
537         return;
538     }
539
540     if( var_Get( p_object, psz_variable, &val ) < 0 )
541     {
542         return;
543     }
544
545     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
546                     &val_list, &text_list ) < 0 )
547     {
548         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
549         return;
550     }
551
552     /* make (un)sensitive */
553     [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];
554
555     for( i = 0; i < val_list.p_list->i_count; i++ )
556     {
557         vlc_value_t another_val;
558         NSMenuItem * o_lmi;
559         NSString *o_title = @"";
560         VLCMenuExt *o_data;
561
562         switch( i_type & VLC_VAR_TYPE )
563         {
564         case VLC_VAR_VARIABLE:
565
566             /* This is causing crashes for the moment.
567             o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
568                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
569             
570             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
571                 Value: val ofType: i_type];
572             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
573
574             // Create a submenu
575             NSMenu *o_menu = [o_lmi submenu];
576
577             [self setupVarMenu: o_menu forMenuItem: o_lmi target:p_object
578                             var:psz_variable selector:pf_callback];
579 */
580             return;
581
582         case VLC_VAR_STRING:
583             another_val.psz_string =
584                 strdup(val_list.p_list->p_values[i].psz_string);
585
586             o_title = [NSApp localizedString: text_list.p_list->p_values[i].psz_string ?
587                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
588
589             o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
590             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
591                     Value: another_val ofType: i_type];
592             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[o_data retain]]];
593             [o_lmi setTarget: self];
594             
595             if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) )
596                 [o_lmi setState: TRUE ];
597
598             break;
599
600         case VLC_VAR_INTEGER:
601
602              o_title = text_list.p_list->p_values[i].psz_string ?
603                                  [NSApp localizedString: strdup( text_list.p_list->p_values[i].psz_string )] :
604                                  [NSString stringWithFormat: @"%d",
605                                  val_list.p_list->p_values[i].i_int];
606
607             o_lmi = [[o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""] retain ];
608             o_data = [[VLCMenuExt alloc] initWithVar: strdup(psz_variable) Object: p_object->i_object_id
609                     Value: val_list.p_list->p_values[i] ofType: i_type];
610             [o_lmi setRepresentedObject: [NSValue valueWithPointer:[ o_data retain]]];
611             [o_lmi setTarget: self];
612
613             if( val_list.p_list->p_values[i].i_int == val.i_int )
614                 [o_lmi setState: TRUE ];
615             break;
616
617         default:
618           break;
619         }
620     }
621     
622     /* clean up everything */
623     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
624     var_Change( p_object, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list );
625 }
626
627 - (IBAction)toggleVar:(id)sender
628 {
629     NSMenuItem *o_mi = (NSMenuItem *)sender;
630     VLCMenuExt *o_data = [[o_mi representedObject] pointerValue];
631     [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
632         toTarget: self withObject: o_data];
633
634     return;
635 }
636
637 - (int)toggleVarThread: (id)_o_data
638 {
639     vlc_object_t *p_object;
640     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
641     VLCMenuExt *o_data = (VLCMenuExt *)_o_data;
642
643     vlc_thread_set_priority( [NSApp getIntf] , VLC_THREAD_PRIORITY_LOW );
644
645     p_object = (vlc_object_t *)vlc_object_get( [NSApp getIntf],
646                                     [o_data objectID] );
647
648     if( p_object != NULL )
649     {
650         var_Set( p_object, strdup([o_data name]), [o_data value] );
651         vlc_object_release( p_object );
652         [o_pool release];
653         return VLC_TRUE;
654     }
655     [o_pool release];
656     return VLC_EGENERIC;
657 }
658
659 @end
660
661 @implementation VLCControls (NSMenuValidation)
662  
663 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
664 {
665     BOOL bEnabled = TRUE;
666     vlc_value_t val;
667     intf_thread_t * p_intf = [NSApp getIntf];
668     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
669                                                        FIND_ANYWHERE );
670
671     if( p_playlist != NULL )
672     {
673         vlc_mutex_lock( &p_playlist->object_lock );
674     }
675
676 #define p_input p_playlist->p_input
677
678     if( [[o_mi title] isEqualToString: _NS("Faster")] ||
679         [[o_mi title] isEqualToString: _NS("Slower")] )
680     {
681         if( p_playlist != NULL && p_input != NULL )
682         {
683             vlc_mutex_lock( &p_input->stream.stream_lock );
684             bEnabled = p_input->stream.b_pace_control;
685             vlc_mutex_unlock( &p_input->stream.stream_lock );
686         }
687         else
688         {
689             bEnabled = FALSE;
690         }
691     }
692     else if( [[o_mi title] isEqualToString: _NS("Stop")] )
693     {
694         if( p_playlist == NULL || p_input == NULL )
695         {
696             bEnabled = FALSE;
697         }
698     }
699     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
700              [[o_mi title] isEqualToString: _NS("Next")] )
701     {
702         if( p_playlist == NULL )
703         {
704             bEnabled = FALSE;
705         }
706         else
707         {
708             bEnabled = p_playlist->i_size > 1;
709
710             if( p_input != NULL )
711             {
712                 vlc_mutex_lock( &p_input->stream.stream_lock );
713                 bEnabled |= p_input->stream.i_area_nb > 1;
714                 vlc_mutex_unlock( &p_input->stream.stream_lock );
715             }
716         }
717     }
718     else if( [[o_mi title] isEqualToString: _NS("Shuffle")] )
719     {
720         int i_state;
721         var_Get( p_playlist, "random", &val );
722         i_state = val.b_bool ? NSOnState : NSOffState;
723         [o_mi setState: i_state];
724     }
725     else if( [[o_mi title] isEqualToString: _NS("Repeat Item")] )
726     {
727         int i_state;
728         var_Get( p_playlist, "repeat", &val );
729         i_state = val.b_bool ? NSOnState : NSOffState;
730         [o_mi setState: i_state];
731     }
732     else if( [[o_mi title] isEqualToString: _NS("Repeat Playlist")] )
733     {
734         int i_state;
735         var_Get( p_playlist, "loop", &val );
736         i_state = val.b_bool ? NSOnState : NSOffState;
737         [o_mi setState: i_state];
738     }
739     else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
740              [[o_mi title] isEqualToString: _NS("Step Backward")] )
741     {
742         if( p_playlist != NULL && p_input != NULL )
743         {
744             vlc_mutex_lock( &p_input->stream.stream_lock );
745             bEnabled = p_input->stream.b_seekable;
746             vlc_mutex_unlock( &p_input->stream.stream_lock );
747         }
748         else
749         {
750             bEnabled = FALSE;
751         }
752     }
753     else if( [[o_mi title] isEqualToString: _NS("Mute")] ) 
754     {
755         [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
756     }
757     else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
758                 [[o_mi title] isEqualToString: _NS("Half Size")] ||
759                 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
760                 [[o_mi title] isEqualToString: _NS("Double Size")] ||
761                 [[o_mi title] isEqualToString: _NS("Fit To Screen")] ||
762                 [[o_mi title] isEqualToString: _NS("Float On Top")] )
763     {
764         id o_window;
765         NSArray *o_windows = [NSApp windows];
766         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
767         bEnabled = FALSE;
768         
769         if ( [[o_mi title] isEqualToString: _NS("Float On Top")] )
770         {
771             int i_state = config_GetInt( p_playlist, "macosx-float" ) ?
772                       NSOnState : NSOffState;
773             [o_mi setState: i_state];
774         }
775         
776         vout_thread_t   *p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
777                                               FIND_ANYWHERE );
778         if( p_vout != NULL )
779         {
780             while ((o_window = [o_enumerator nextObject]))
781             {
782                 if( [[o_window className] isEqualToString: @"VLCWindow"] )
783                 {
784                     bEnabled = TRUE;
785                     break;
786                 }
787             }
788             vlc_object_release( (vlc_object_t *)p_vout );
789         }
790     }
791
792     if( p_playlist != NULL )
793     {
794         vlc_mutex_unlock( &p_playlist->object_lock );
795         vlc_object_release( p_playlist );
796     }
797
798     return( bEnabled );
799 }
800
801 @end
802
803 /*****************************************************************************
804  * VLCMenuExt implementation 
805  *****************************************************************************
806  * Object connected to a playlistitem which remembers the data belonging to
807  * the variable of the autogenerated menu
808  *****************************************************************************/
809 @implementation VLCMenuExt
810
811 - (id)initWithVar: (const char *)_psz_name Object: (int)i_id
812         Value: (vlc_value_t)val ofType: (int)_i_type
813 {
814     self = [super init];
815
816     if( self != nil )
817     {
818         psz_name = strdup( _psz_name );
819         i_object_id = i_id;
820         value = val;
821         i_type = _i_type;
822     }
823
824     return( self );
825 }
826
827 - (void)dealloc
828 {
829     free( psz_name );
830 }
831
832 - (char *)name
833 {
834     return psz_name;
835 }
836
837 - (int)objectID
838 {
839     return i_object_id;
840 }
841
842 - (vlc_value_t)value
843 {
844     return value;
845 }
846
847 - (int)type
848 {
849     return i_type;
850 }
851
852 @end