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