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