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