Removed useless vlc_thread_set_priority() calls in macosx code.
[vlc/vlc-skelet.git] / modules / gui / macosx / controls.m
blob2020ad304c840aa0d93d5f6aca0e71686d09812b
1 /*****************************************************************************
2  * controls.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2009 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 Paul Kühne <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  *****************************************************************************/
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <sys/param.h>                                    /* for MAXPATHLEN */
33 #include <string.h>
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 #include <vlc_keys.h>
43 #pragma mark -
44 /*****************************************************************************
45  * VLCControls implementation
46  *****************************************************************************/
47 @implementation VLCControls
49 - (id)init
51     [super init];
52     o_fs_panel = [[VLCFSPanel alloc] init];
53     b_lockAspectRatio = YES;
54     return self;
57 - (void)awakeFromNib
59     [o_specificTime_mi setTitle: _NS("Jump To Time")];
60     [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
61     [o_specificTime_ok_btn setTitle: _NS("OK")];
62     [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
63     [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
65     o_repeat_off = [NSImage imageNamed:@"repeat_embedded"];
70 - (void)dealloc
72     [[NSNotificationCenter defaultCenter] removeObserver: self];
74     [o_fs_panel release];
75     [o_repeat_single release];
76     [o_repeat_all release];
77     [o_repeat_off release];
79     [super dealloc];
82 - (IBAction)play:(id)sender
84     intf_thread_t * p_intf = VLCIntf;
85     playlist_t * p_playlist = pl_Get( p_intf );
86     bool empty;
88     PL_LOCK;
89     empty = playlist_IsEmpty( p_playlist );
90     PL_UNLOCK;
92     if( empty )
93         [o_main intfOpenFileGeneric: (id)sender];
95     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
98 - (id)voutView
100     id o_window;
101     id o_voutView = nil;
102     id o_embeddedViewList = [[VLCMain sharedInstance] embeddedList];
103     NSEnumerator *o_enumerator = [[NSApp orderedWindows] objectEnumerator];
104     while( !o_voutView && ( o_window = [o_enumerator nextObject] ) )
105     {
106         /* We have an embedded vout */
107         if( [o_embeddedViewList windowContainsEmbedded: o_window] )
108         {
109             o_voutView = [o_embeddedViewList viewForWindow: o_window];
110         }
111         /* We have a detached vout */
112         else if( [[o_window className] isEqualToString: @"VLCVoutWindow"] )
113         {
114             o_voutView = [o_window voutView];
115         }
116     }
117     return [[o_voutView retain] autorelease];
120 - (BOOL)aspectRatioIsLocked
122     return b_lockAspectRatio;
125 - (IBAction)stop:(id)sender
127     intf_thread_t * p_intf = VLCIntf;
128     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_STOP );
129     /* Close the window directly, because we do know that there
130      * won't be anymore video. It's currently waiting a bit. */
131     [[[self voutView] window] orderOut:self];
134 - (IBAction)faster:(id)sender
136     intf_thread_t * p_intf = VLCIntf;
137     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_FASTER );
140 - (IBAction)slower:(id)sender
142     intf_thread_t * p_intf = VLCIntf;
143     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_SLOWER );
146 - (IBAction)normalSpeed:(id)sender
148     intf_thread_t * p_intf = VLCIntf;
149     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_NORMAL );
152 - (IBAction)prev:(id)sender
154     intf_thread_t * p_intf = VLCIntf;
155     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PREV );
158 - (IBAction)next:(id)sender
160     intf_thread_t * p_intf = VLCIntf;
161     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_NEXT );
164 - (IBAction)random:(id)sender
166     vlc_value_t val;
167     intf_thread_t * p_intf = VLCIntf;
168     playlist_t * p_playlist = pl_Get( p_intf );
170     var_Get( p_playlist, "random", &val );
171     val.b_bool = !val.b_bool;
172     var_Set( p_playlist, "random", val );
173     if( val.b_bool )
174     {
175         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Random On" ) );
176         config_PutInt( p_playlist, "random", 1 );
177     }
178     else
179     {
180         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Random Off" ) );
181         config_PutInt( p_playlist, "random", 0 );
182     }
184     p_intf->p_sys->b_playmode_update = true;
185     p_intf->p_sys->b_intf_update = true;
188 /* three little ugly helpers */
189 - (void)repeatOne
191     [o_btn_repeat setImage: o_repeat_single];
192     [o_btn_repeat setAlternateImage: o_repeat_all];
193     [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOneOn"]];
195 - (void)repeatAll
197     [o_btn_repeat setImage: o_repeat_all];
198     [o_btn_repeat setAlternateImage: o_repeat_off];
199     [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOn"]];
201 - (void)repeatOff
203     [o_btn_repeat setImage: o_repeat_off];
204     [o_btn_repeat setAlternateImage: o_repeat_single];
205     [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeat"]];
207 - (void)shuffle
209     vlc_value_t val;
210     playlist_t *p_playlist = pl_Get( VLCIntf );
211     var_Get( p_playlist, "random", &val );
212     [o_btn_shuffle setState: val.b_bool];
213         if(val.b_bool)
214         [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffleOn"]];
215         else
216         [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffle"]];
219 - (IBAction)repeatButtonAction:(id)sender
221     vlc_value_t looping,repeating;
222     intf_thread_t * p_intf = VLCIntf;
223     playlist_t * p_playlist = pl_Get( p_intf );
225     var_Get( p_playlist, "repeat", &repeating );
226     var_Get( p_playlist, "loop", &looping );
228     if( !repeating.b_bool && !looping.b_bool )
229     {
230         /* was: no repeating at all, switching to Repeat One */
232         /* set our button's look */
233         [self repeatOne];
235         /* prepare core communication */
236         repeating.b_bool = true;
237         looping.b_bool = false;
238         config_PutInt( p_playlist, "repeat", 1 );
239         config_PutInt( p_playlist, "loop", 0 );
241         /* show the change */
242         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat One" ) );
243     }
244     else if( repeating.b_bool && !looping.b_bool )
245     {
246         /* was: Repeat One, switching to Repeat All */
248         /* set our button's look */
249         [self repeatAll];
251         /* prepare core communication */
252         repeating.b_bool = false;
253         looping.b_bool = true;
254         config_PutInt( p_playlist, "repeat", 0 );
255         config_PutInt( p_playlist, "loop", 1 );
257         /* show the change */
258         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat All" ) );
259     }
260     else
261     {
262         /* was: Repeat All or bug in VLC, switching to Repeat Off */
264         /* set our button's look */
265         [self repeatOff];
267         /* prepare core communication */
268         repeating.b_bool = false;
269         looping.b_bool = false;
270         config_PutInt( p_playlist, "repeat", 0 );
271         config_PutInt( p_playlist, "loop", 0 );
273         /* show the change */
274         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat Off" ) );
275     }
277     /* communicate with core and the main intf loop */
278     var_Set( p_playlist, "repeat", repeating );
279     var_Set( p_playlist, "loop", looping );
280     p_intf->p_sys->b_playmode_update = true;
281     p_intf->p_sys->b_intf_update = true;
285 - (IBAction)repeat:(id)sender
287     vlc_value_t val;
288     intf_thread_t * p_intf = VLCIntf;
289     playlist_t * p_playlist = pl_Get( p_intf );
291     var_Get( p_playlist, "repeat", &val );
292     if (!val.b_bool)
293     {
294         var_Set( p_playlist, "loop", val );
295     }
296     val.b_bool = !val.b_bool;
297     var_Set( p_playlist, "repeat", val );
298     if( val.b_bool )
299     {
300         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat One" ) );
301         config_PutInt( p_playlist, "repeat", 1 );
302     }
303     else
304     {
305         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat Off" ) );
306         config_PutInt( p_playlist, "repeat", 0 );
307     }
309     p_intf->p_sys->b_playmode_update = true;
310     p_intf->p_sys->b_intf_update = true;
313 - (IBAction)loop:(id)sender
315     vlc_value_t val;
316     intf_thread_t * p_intf = VLCIntf;
317     playlist_t * p_playlist = pl_Get( p_intf );
319     var_Get( p_playlist, "loop", &val );
320     if (!val.b_bool)
321     {
322         var_Set( p_playlist, "repeat", val );
323     }
324     val.b_bool = !val.b_bool;
325     var_Set( p_playlist, "loop", val );
326     if( val.b_bool )
327     {
328         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat All" ) );
329         config_PutInt( p_playlist, "loop", 1 );
330     }
331     else
332     {
333         //vout_OSDMessage( p_intf, SPU_DEFAULT_CHANNEL, "%s", _( "Repeat Off" ) );
334         config_PutInt( p_playlist, "loop", 0 );
335     }
337     p_intf->p_sys->b_playmode_update = true;
338     p_intf->p_sys->b_intf_update = true;
341 - (IBAction)quitAfterPlayback:(id)sender
343     vlc_value_t val;
344     playlist_t * p_playlist = pl_Get( VLCIntf );
345     var_ToggleBool( p_playlist, "play-and-exit" );
348 - (IBAction)forward:(id)sender
350     intf_thread_t * p_intf = VLCIntf;
351     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT );
354 - (IBAction)backward:(id)sender
356     vlc_value_t val;
357     intf_thread_t * p_intf = VLCIntf;
358     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_SHORT );
362 - (IBAction)volumeUp:(id)sender
364     intf_thread_t * p_intf = VLCIntf;
365     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_UP );
366     /* Manage volume status */
367     [o_main manageVolumeSlider];
370 - (IBAction)volumeDown:(id)sender
372     intf_thread_t * p_intf = VLCIntf;
373     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_DOWN );
374     /* Manage volume status */
375     [o_main manageVolumeSlider];
378 - (IBAction)mute:(id)sender
380     intf_thread_t * p_intf = VLCIntf;
381     var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_MUTE );
382     /* Manage volume status */
383     [o_main manageVolumeSlider];
386 - (IBAction)volumeSliderUpdated:(id)sender
388     intf_thread_t * p_intf = VLCIntf;
389     playlist_t * p_playlist = pl_Get( p_intf );
390     audio_volume_t i_volume = (audio_volume_t)[sender intValue];
391     int i_volume_step;
393     i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
394     aout_VolumeSet( p_playlist, i_volume * i_volume_step );
395     /* Manage volume status */
396     [o_main manageVolumeSlider];
399 - (IBAction)showPosition: (id)sender
401     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
402     if( p_input != NULL )
403     {
404         vout_thread_t *p_vout = input_GetVout( p_input );
405         if( p_vout != NULL )
406         {
407             var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION );
408             vlc_object_release( (vlc_object_t *)p_vout );
409         }
410         vlc_object_release( p_input );
411     }
414 - (IBAction)toogleFullscreen:(id)sender {
415     NSMenuItem *o_mi = [[NSMenuItem alloc] initWithTitle: _NS("Fullscreen") action: nil keyEquivalent:@""];
416     [self windowAction: [o_mi autorelease]];
419 - (BOOL) isFullscreen {
420     id o_vout_view = [self voutView];
421     if( o_vout_view )
422     {
423         return [o_vout_view isFullscreen];
424     }
425     return NO;
428 - (IBAction)windowAction:(id)sender
430     NSString *o_title = [sender title];
431     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
433     if( p_input != NULL )
434     {
435         vout_thread_t *p_vout = input_GetVout( p_input );
436         if( p_vout != NULL )
437         {
438             id o_vout_view = [self voutView];
439             if( o_vout_view )
440             {
441                 if( [o_title isEqualToString: _NS("Half Size") ] )
442                     [o_vout_view scaleWindowWithFactor: 0.5 animate: YES];
443                 else if( [o_title isEqualToString: _NS("Normal Size") ] )
444                     [o_vout_view scaleWindowWithFactor: 1.0 animate: YES];
445                 else if( [o_title isEqualToString: _NS("Double Size") ] )
446                     [o_vout_view scaleWindowWithFactor: 2.0 animate: YES];
447                 else if( [o_title isEqualToString: _NS("Float on Top") ] )
448                     [o_vout_view toggleFloatOnTop];
449                 else if( [o_title isEqualToString: _NS("Fit to Screen") ] )
450                 {
451                     id o_window = [o_vout_view voutWindow];
452                     if( ![o_window isZoomed] )
453                         [o_window performZoom:self];
454                 }
455                 else if( [o_title isEqualToString: _NS("Snapshot") ] )
456                 {
457                     [o_vout_view snapshot];
458                 }
459                 else
460                 {
461                     /* Fullscreen state for next time will be saved here too */
462                     [o_vout_view toggleFullscreen];
463                 }
464             }
465             vlc_object_release( (vlc_object_t *)p_vout );
466         }
467         else
468         {
469             playlist_t * p_playlist = pl_Get( VLCIntf );
471             if( [o_title isEqualToString: _NS("Fullscreen")] ||
472                 [sender isKindOfClass:[NSButton class]] )
473             {
474                 var_ToggleBool( p_playlist, "fullscreen" );
475             }
476         }
477         vlc_object_release( p_input );
478     }
481 - (IBAction)telxTransparent:(id)sender
483     intf_thread_t * p_intf = VLCIntf;
484     vlc_object_t *p_vbi;
485     p_vbi = (vlc_object_t *) vlc_object_find_name( p_intf,
486                     "zvbi", FIND_ANYWHERE );
487     if( p_vbi )
488     {
489         var_SetBool( p_vbi, "vbi-opaque", [sender state] );
490         [sender setState: ![sender state]];
491         vlc_object_release( p_vbi );
492     }
495 - (IBAction)telxNavLink:(id)sender
497     intf_thread_t * p_intf = VLCIntf;
498     vlc_object_t *p_vbi;
499     int i_page = 0;
501     if( [[sender title] isEqualToString: _NS("Index")] )
502         i_page = 'i' << 16;
503     else if( [[sender title] isEqualToString: _NS("Red")] )
504         i_page = 'r' << 16;
505     else if( [[sender title] isEqualToString: _NS("Green")] )
506         i_page = 'g' << 16;
507     else if( [[sender title] isEqualToString: _NS("Yellow")] )
508         i_page = 'y' << 16;
509     else if( [[sender title] isEqualToString: _NS("Blue")] )
510         i_page = 'b' << 16;
511     if( i_page == 0 ) return;
513     p_vbi = (vlc_object_t *) vlc_object_find_name( p_intf,
514                 "zvbi", FIND_ANYWHERE );
515     if( p_vbi )
516     {
517         var_SetInteger( p_vbi, "vbi-page", i_page );
518         vlc_object_release( p_vbi );
519     }
522 - (IBAction)lockVideosAspectRatio:(id)sender
524     if( [sender state] == NSOffState )
525         [sender setState: NSOnState];
526     else
527         [sender setState: NSOffState];
529     b_lockAspectRatio = !b_lockAspectRatio;
532 - (IBAction)addSubtitleFile:(id)sender
534     NSInteger i_returnValue = 0;
535     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
536     if( !p_input ) return;
538     input_item_t *p_item = input_GetItem( p_input );
539     if( !p_item ) return;
541     char *path = input_item_GetURI( p_item );
542     if( !path ) path = strdup( "" );
544     NSOpenPanel * openPanel = [NSOpenPanel openPanel];
545     [openPanel setCanChooseFiles: YES];
546     [openPanel setCanChooseDirectories: NO];
547     [openPanel setAllowsMultipleSelection: YES];
548     [openPanel setAllowedFileTypes: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi",@"txt",@"smil", nil]];
549     [openPanel setDirectoryURL:[NSURL fileURLWithPath:[[NSString stringWithUTF8String:path] stringByExpandingTildeInPath]]];
550     i_returnValue = [openPanel runModal];
551     free( path );
553     if( i_returnValue == NSOKButton )
554     {
555         NSUInteger c = 0;
556         if( !p_input ) return;
558         c = [[openPanel URLs] count];
560         for (int i = 0; i < c ; i++)
561         {
562             msg_Dbg( VLCIntf, "loading subs from %s", [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
563             if( input_AddSubtitle( p_input, [[[[openPanel URLs] objectAtIndex: i] path] UTF8String], TRUE ) )
564                 msg_Warn( VLCIntf, "unable to load subtitles from '%s'",
565                          [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
566         }
567     }
570 - (void)scrollWheel:(NSEvent *)theEvent
572     intf_thread_t * p_intf = VLCIntf;
573     float f_yabsvalue = [theEvent deltaY] > 0.0f ? [theEvent deltaY] : -[theEvent deltaY];
574     float f_xabsvalue = [theEvent deltaX] > 0.0f ? [theEvent deltaX] : -[theEvent deltaX];
575     int i, i_yvlckey, i_xvlckey;
577     if ([theEvent deltaY] < 0.0f)
578         i_yvlckey = KEY_MOUSEWHEELDOWN;
579     else
580         i_yvlckey = KEY_MOUSEWHEELUP;
582     if ([theEvent deltaX] < 0.0f)
583         i_xvlckey = KEY_MOUSEWHEELRIGHT;
584     else
585         i_xvlckey = KEY_MOUSEWHEELLEFT;
587     /* Send multiple key event, depending on the intensity of the event */
588     for (i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
589         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_yvlckey );
591     /* Prioritize Y event (sound volume) over X event */
592     if (f_yabsvalue < 0.05)
593     {
594         for (i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
595          var_SetInteger( p_intf->p_libvlc, "key-pressed", i_xvlckey );
596     }
599 - (BOOL)keyEvent:(NSEvent *)o_event
601     BOOL eventHandled = NO;
602     unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
604     if( key )
605     {
606         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
607         if( p_input != NULL )
608         {
609             vout_thread_t *p_vout = input_GetVout( p_input );
611             if( p_vout != NULL )
612             {
613                 /* Escape */
614                 if( key == (unichar) 0x1b )
615                 {
616                     id o_vout_view = [self voutView];
617                     if( o_vout_view && [o_vout_view isFullscreen] )
618                     {
619                         [o_vout_view toggleFullscreen];
620                         eventHandled = YES;
621                     }
622                 }
623                 else if( key == ' ' )
624                 {
625                     [self play:self];
626                     eventHandled = YES;
627                 }
628                 vlc_object_release( (vlc_object_t *)p_vout );
629             }
630             vlc_object_release( p_input );
631         }
632     }
633     return eventHandled;
636 - (void)setupVarMenuItem:(NSMenuItem *)o_mi
637                     target:(vlc_object_t *)p_object
638                     var:(const char *)psz_variable
639                     selector:(SEL)pf_callback
641     vlc_value_t val, text;
642     int i_type = var_Type( p_object, psz_variable );
644     switch( i_type & VLC_VAR_TYPE )
645     {
646     case VLC_VAR_VOID:
647     case VLC_VAR_BOOL:
648     case VLC_VAR_VARIABLE:
649     case VLC_VAR_STRING:
650     case VLC_VAR_INTEGER:
651         break;
652     default:
653         /* Variable doesn't exist or isn't handled */
654         return;
655     }
657     /* Make sure we want to display the variable */
658     if( i_type & VLC_VAR_HASCHOICE )
659     {
660         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
661         if( val.i_int == 0 ) return;
662         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
663             return;
664     }
666     /* Get the descriptive name of the variable */
667     var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
668     [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
669                                         text.psz_string : psz_variable ]];
671     if( i_type & VLC_VAR_HASCHOICE )
672     {
673         NSMenu *o_menu = [o_mi submenu];
675         [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
676                         var:psz_variable selector:pf_callback];
678         free( text.psz_string );
679         return;
680     }
681     if( var_Get( p_object, psz_variable, &val ) < 0 )
682     {
683         return;
684     }
686     VLCAutoGeneratedMenuContent *o_data;
687     switch( i_type & VLC_VAR_TYPE )
688     {
689     case VLC_VAR_VOID:
690         o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
691                 andValue: val ofType: i_type];
692         [o_mi setRepresentedObject: [o_data autorelease]];
693         break;
695     case VLC_VAR_BOOL:
696         o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
697                 andValue: val ofType: i_type];
698         [o_mi setRepresentedObject: [o_data autorelease]];
699         if( !( i_type & VLC_VAR_ISCOMMAND ) )
700             [o_mi setState: val.b_bool ? TRUE : FALSE ];
701         break;
703     default:
704         break;
705     }
707     if( ( i_type & VLC_VAR_TYPE ) == VLC_VAR_STRING ) free( val.psz_string );
708     free( text.psz_string );
712 - (void)setupVarMenu:(NSMenu *)o_menu
713                     forMenuItem: (NSMenuItem *)o_parent
714                     target:(vlc_object_t *)p_object
715                     var:(const char *)psz_variable
716                     selector:(SEL)pf_callback
718     vlc_value_t val, val_list, text_list;
719     int i_type, i, i_nb_items;
721     /* remove previous items */
722     i_nb_items = [o_menu numberOfItems];
723     for( i = 0; i < i_nb_items; i++ )
724     {
725         [o_menu removeItemAtIndex: 0];
726     }
728     /* Check the type of the object variable */
729     i_type = var_Type( p_object, psz_variable );
731     /* Make sure we want to display the variable */
732     if( i_type & VLC_VAR_HASCHOICE )
733     {
734         var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
735         if( val.i_int == 0 ) return;
736         if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
737             return;
738     }
739     else
740     {
741         return;
742     }
744     switch( i_type & VLC_VAR_TYPE )
745     {
746     case VLC_VAR_VOID:
747     case VLC_VAR_BOOL:
748     case VLC_VAR_VARIABLE:
749     case VLC_VAR_STRING:
750     case VLC_VAR_INTEGER:
751         break;
752     default:
753         /* Variable doesn't exist or isn't handled */
754         return;
755     }
757     if( var_Get( p_object, psz_variable, &val ) < 0 )
758     {
759         return;
760     }
762     if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
763                     &val_list, &text_list ) < 0 )
764     {
765         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
766         return;
767     }
769     /* make (un)sensitive */
770     [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];
772     /* Aspect Ratio */
773     if( [[o_parent title] isEqualToString: _NS("Aspect-ratio")] == YES )
774     {
775         NSMenuItem *o_lmi_tmp2;
776         o_lmi_tmp2 = [o_menu addItemWithTitle: _NS("Lock Aspect Ratio") action: @selector(lockVideosAspectRatio:) keyEquivalent: @""];
777         [o_lmi_tmp2 setTarget: self];
778         [o_lmi_tmp2 setEnabled: YES];
779         [o_lmi_tmp2 setState: b_lockAspectRatio];
780         [o_parent setEnabled: YES];
781         [o_menu addItem: [NSMenuItem separatorItem]];
782     }
784     /* special case for the subtitles items */
785     if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
786     {
787         NSMenuItem * o_lmi_tmp;
788         o_lmi_tmp = [o_menu addItemWithTitle: _NS("Open File...") action: @selector(addSubtitleFile:) keyEquivalent: @""];
789         [o_lmi_tmp setTarget: self];
790         [o_lmi_tmp setEnabled: YES];
791         [o_parent setEnabled: YES];
792         [o_menu addItem: [NSMenuItem separatorItem]];
793     }
795     for( i = 0; i < val_list.p_list->i_count; i++ )
796     {
797         NSMenuItem * o_lmi;
798         NSString *o_title = @"";
799         VLCAutoGeneratedMenuContent *o_data;
801         switch( i_type & VLC_VAR_TYPE )
802         {
803         case VLC_VAR_STRING:
805             o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
806                 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
808             o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
809             o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
810                     andValue: val_list.p_list->p_values[i] ofType: i_type];
811             [o_lmi setRepresentedObject: [o_data autorelease]];
812             [o_lmi setTarget: self];
814             if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) && !( i_type & VLC_VAR_ISCOMMAND ) )
815                 [o_lmi setState: TRUE ];
817             break;
819         case VLC_VAR_INTEGER:
821              o_title = text_list.p_list->p_values[i].psz_string ?
822                                  [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string] :
823                                  [NSString stringWithFormat: @"%"PRId64,
824                                  val_list.p_list->p_values[i].i_int];
826             o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
827             o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
828                     andValue: val_list.p_list->p_values[i] ofType: i_type];
829             [o_lmi setRepresentedObject: [o_data autorelease]];
830             [o_lmi setTarget: self];
832             if( val_list.p_list->p_values[i].i_int == val.i_int && !( i_type & VLC_VAR_ISCOMMAND ) )
833                 [o_lmi setState: TRUE ];
834             break;
836         default:
837           break;
838         }
839     }
841     /* special case for the subtitles sub-menu
842      * In case that we don't have any subs, we don't want a separator item at the end */
843     if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
844     {
845         if( [o_menu numberOfItems] == 2 )
846             [o_menu removeItemAtIndex: 1];
847     }
849     /* clean up everything */
850     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
851     var_FreeList( &val_list, &text_list );
854 - (IBAction)toggleVar:(id)sender
856     NSMenuItem *o_mi = (NSMenuItem *)sender;
857     VLCAutoGeneratedMenuContent *o_data = [o_mi representedObject];
858     [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
859         toTarget: self withObject: o_data];
861     return;
864 - (int)toggleVarThread: (id)data
866     vlc_object_t *p_object;
867     NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
869     assert([data isKindOfClass:[VLCAutoGeneratedMenuContent class]]);
870     VLCAutoGeneratedMenuContent *menuContent = (VLCAutoGeneratedMenuContent *)data;
872     p_object = [menuContent vlcObject];
874     if( p_object != NULL )
875     {
876         var_Set( p_object, [menuContent name], [menuContent value] );
877         vlc_object_release( p_object );
878         [o_pool release];
879         return true;
880     }
881     [o_pool release];
882     return VLC_EGENERIC;
885 - (IBAction)goToSpecificTime:(id)sender
887     if( sender == o_specificTime_cancel_btn )
888     {
889         [NSApp endSheet: o_specificTime_win];
890         [o_specificTime_win close];
891     }
892     else if( sender == o_specificTime_ok_btn )
893     {
894         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
895         if( p_input )
896         {
897             unsigned int timeInSec = 0;
898             NSString * fieldContent = [o_specificTime_enter_fld stringValue];
899             if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
900                 [[fieldContent componentsSeparatedByString: @":"] count] <= 3 )
901             {
902                 NSArray * ourTempArray = \
903                     [fieldContent componentsSeparatedByString: @":"];
905                 if( [[fieldContent componentsSeparatedByString: @":"] count] == 3 )
906                 {
907                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
908                     timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
909                     timeInSec += [[ourTempArray objectAtIndex: 2] intValue];        //s
910                 }
911                 else
912                 {
913                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
914                     timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
915                 }
916             }
917             else
918                 timeInSec = [fieldContent intValue];
920             input_Control( p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
921             vlc_object_release( p_input );
922         }
924         [NSApp endSheet: o_specificTime_win];
925         [o_specificTime_win close];
926     }
927     else
928     {
929         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
930         if( p_input )
931         {
932             /* we can obviously only do that if an input is available */
933             vlc_value_t pos, length;
934             var_Get( p_input, "time", &pos );
935             [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
936             var_Get( p_input, "length", &length );
937             [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];
939             [NSApp beginSheet: o_specificTime_win modalForWindow: \
940                 [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
941                 contextInfo: nil];
942             [o_specificTime_win makeKeyWindow];
943             vlc_object_release( p_input );
944         }
945     }
948 - (id)fspanel
950     if( o_fs_panel )
951         return o_fs_panel;
952     else
953     {
954         msg_Err( VLCIntf, "FSPanel is nil" );
955         return NULL;
956     }
959 @end
961 @implementation VLCControls (NSMenuValidation)
963 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
965     BOOL bEnabled = TRUE;
966     vlc_value_t val;
967     intf_thread_t * p_intf = VLCIntf;
968     playlist_t * p_playlist = pl_Get( p_intf );
969     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
971     if( [[o_mi title] isEqualToString: _NS("Faster")] ||
972         [[o_mi title] isEqualToString: _NS("Slower")] ||
973         [[o_mi title] isEqualToString: _NS("Normal rate")] )
974     {
975         if( p_input != NULL )
976         {
977             bEnabled = var_GetBool( p_input, "can-rate" );
978         }
979         else
980         {
981             bEnabled = FALSE;
982         }
983     }
984     else if( [[o_mi title] isEqualToString: _NS("Stop")] )
985     {
986         if( p_input == NULL )
987         {
988             bEnabled = FALSE;
989         }
990         [o_main setupMenus]; /* Make sure input menu is up to date */
991     }
992     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
993              [[o_mi title] isEqualToString: _NS("Next")] )
994     {
995         PL_LOCK;
996         bEnabled = playlist_CurrentSize( p_playlist ) > 1;
997         PL_UNLOCK;
998     }
999     else if( [[o_mi title] isEqualToString: _NS("Random")] )
1000     {
1001         int i_state;
1002         var_Get( p_playlist, "random", &val );
1003         i_state = val.b_bool ? NSOnState : NSOffState;
1004         [o_mi setState: i_state];
1005     }
1006     else if( [[o_mi title] isEqualToString: _NS("Repeat One")] )
1007     {
1008         int i_state;
1009         var_Get( p_playlist, "repeat", &val );
1010         i_state = val.b_bool ? NSOnState : NSOffState;
1011         [o_mi setState: i_state];
1012     }
1013     else if( [[o_mi title] isEqualToString: _NS("Repeat All")] )
1014     {
1015         int i_state;
1016         var_Get( p_playlist, "loop", &val );
1017         i_state = val.b_bool ? NSOnState : NSOffState;
1018         [o_mi setState: i_state];
1019     }
1020     else if( [[o_mi title] isEqualToString: _NS("Quit after Playback")] )
1021     {
1022         int i_state;
1023         var_Get( p_playlist, "play-and-exit", &val );
1024         i_state = val.b_bool ? NSOnState : NSOffState;
1025         [o_mi setState: i_state];
1026     }
1027     else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
1028              [[o_mi title] isEqualToString: _NS("Step Backward")] ||
1029              [[o_mi title] isEqualToString: _NS("Jump To Time")])
1030     {
1031         if( p_input != NULL )
1032         {
1033             var_Get( p_input, "can-seek", &val);
1034             bEnabled = val.b_bool;
1035         }
1036         else bEnabled = FALSE;
1037     }
1038     else if( [[o_mi title] isEqualToString: _NS("Mute")] )
1039     {
1040         [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
1041         [o_main setupMenus]; /* Make sure audio menu is up to date */
1042     }
1043     else if( [[o_mi title] isEqualToString: _NS("Half Size")] ||
1044                 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
1045                 [[o_mi title] isEqualToString: _NS("Double Size")] ||
1046                 [[o_mi title] isEqualToString: _NS("Fit to Screen")] ||
1047                 [[o_mi title] isEqualToString: _NS("Snapshot")] ||
1048                 [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
1049                 [[o_mi title] isEqualToString: _NS("Float on Top")] )
1050     {
1051         id o_window;
1052         NSArray *o_windows = [NSApp orderedWindows];
1053         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
1054         bEnabled = FALSE;
1056         if( p_input != NULL )
1057         {
1058             vout_thread_t *p_vout = input_GetVout( p_input );
1059             if( p_vout != NULL )
1060             {
1061                 if( [[o_mi title] isEqualToString: _NS("Float on Top")] )
1062                 {
1063                     var_Get( p_vout, "video-on-top", &val );
1064                     [o_mi setState: val.b_bool ?  NSOnState : NSOffState];
1065                 }
1067                 while( (o_window = [o_enumerator nextObject]))
1068                 {
1069                     if( [[o_window className] isEqualToString: @"VLCVoutWindow"] ||
1070                                 [[[VLCMain sharedInstance] embeddedList]
1071                                 windowContainsEmbedded: o_window])
1072                     {
1073                         bEnabled = TRUE;
1074                         break;
1075                     }
1076                 }
1078                 vlc_object_release( (vlc_object_t *)p_vout );
1079             }
1080         }
1081         if( [[o_mi title] isEqualToString: _NS("Fullscreen")] )
1082         {
1083             var_Get( p_playlist, "fullscreen", &val );
1084             [o_mi setState: val.b_bool];
1085             bEnabled = TRUE;
1086         }
1087         [o_main setupMenus]; /* Make sure video menu is up to date */
1088     }
1090     /* Special case for telx menu */
1091     if( [[o_mi title] isEqualToString: _NS("Normal Size")] )
1092     {
1093         NSMenuItem *item = [[o_mi menu] itemWithTitle:_NS("Teletext")];
1094                 bool b_telx = p_input && var_GetInteger( p_input, "teletext-es" ) >= 0;
1096         [[item submenu] setAutoenablesItems:NO];
1097         for( int k=0; k < [[item submenu] numberOfItems]; k++ )
1098         {
1099             [[[item submenu] itemAtIndex:k] setEnabled: b_telx];
1100         }
1101     }
1103     if( p_input ) vlc_object_release( p_input );
1105     return( bEnabled );
1108 @end
1110 /*****************************************************************************
1111  * VLCAutoGeneratedMenuContent implementation
1112  *****************************************************************************
1113  * Object connected to a playlistitem which remembers the data belonging to
1114  * the variable of the autogenerated menu
1115  *****************************************************************************/
1116 @implementation VLCAutoGeneratedMenuContent
1118 -(id) initWithVariableName:(const char *)name ofObject:(vlc_object_t *)object
1119         andValue:(vlc_value_t)val ofType:(int)type
1121     self = [super init];
1123     if( self != nil )
1124     {
1125         _vlc_object = vlc_object_hold( object );
1126         psz_name = strdup( name );
1127         i_type = type;
1128         value = val;
1129         if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
1130             value.psz_string = strdup( val.psz_string );
1131     }
1133     return( self );
1136 - (void)dealloc
1138     vlc_object_release( _vlc_object );
1139     if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
1140         free( value.psz_string );
1141     free( psz_name );
1142     [super dealloc];
1145 - (const char *)name
1147     return psz_name;
1150 - (vlc_value_t)value
1152     return value;
1155 - (vlc_object_t *)vlcObject
1157     return vlc_object_hold( _vlc_object );
1161 - (int)type
1163     return i_type;
1166 @end
1169 /*****************************************************************************
1170  * VLCTimeField implementation
1171  *****************************************************************************
1172  * we need this to catch our click-event in the controller window
1173  *****************************************************************************/
1175 @implementation VLCTimeField
1176 - (void)mouseDown: (NSEvent *)ourEvent
1178     if( [ourEvent clickCount] > 1 )
1179         [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
1180     else
1181         [[VLCMain sharedInstance] timeFieldWasClicked: self];
1183 @end