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