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