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