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