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