1 /*****************************************************************************
2 * controls.m: MacOS X interface module
3 *****************************************************************************
4 * Copyright (C) 2002-2009 the VideoLAN team
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>
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.
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.
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 /*****************************************************************************
30 *****************************************************************************/
31 #include <stdlib.h> /* malloc(), free() */
32 #include <sys/param.h> /* for MAXPATHLEN */
44 /*****************************************************************************
45 * VLCControls implementation
46 *****************************************************************************/
47 @implementation VLCControls
52 o_fs_panel = [[VLCFSPanel alloc] init];
53 b_lockAspectRatio = YES;
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"];
67 [self controlTintChanged];
69 [[NSNotificationCenter defaultCenter] addObserver: self
70 selector: @selector( controlTintChanged )
71 name: NSControlTintDidChangeNotification
75 - (void)controlTintChanged
78 if( [o_btn_repeat image] == o_repeat_single )
80 else if( [o_btn_repeat image] == o_repeat_all )
83 if( [NSColor currentControlTint] == NSGraphiteControlTint )
85 o_repeat_single = [NSImage imageNamed:@"repeat_single_embedded_graphite"];
86 o_repeat_all = [NSImage imageNamed:@"repeat_embedded_graphite"];
88 [o_btn_shuffle setAlternateImage: [NSImage imageNamed: @"shuffle_embedded_graphite"]];
89 [o_btn_addNode setAlternateImage: [NSImage imageNamed: @"add_embedded_graphite"]];
93 o_repeat_single = [NSImage imageNamed:@"repeat_single_embedded_blue"];
94 o_repeat_all = [NSImage imageNamed:@"repeat_embedded_blue"];
96 [o_btn_shuffle setAlternateImage: [NSImage imageNamed: @"shuffle_embedded_blue"]];
97 [o_btn_addNode setAlternateImage: [NSImage imageNamed: @"add_embedded_blue"]];
100 /* update the repeat button, but keep its state */
103 else if( i_repeat == 2 )
111 [[NSNotificationCenter defaultCenter] removeObserver: self];
113 [o_fs_panel release];
114 [o_repeat_single release];
115 [o_repeat_all release];
116 [o_repeat_off release];
121 - (IBAction)play:(id)sender
123 intf_thread_t * p_intf = VLCIntf;
124 playlist_t * p_playlist = pl_Hold( p_intf );
128 empty = playlist_IsEmpty( p_playlist );
131 pl_Release( p_intf );
134 [o_main intfOpenFileGeneric: (id)sender];
136 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
143 id o_embeddedViewList = [[VLCMain sharedInstance] embeddedList];
144 NSEnumerator *o_enumerator = [[NSApp orderedWindows] objectEnumerator];
145 while( !o_voutView && ( o_window = [o_enumerator nextObject] ) )
147 /* We have an embedded vout */
148 if( [o_embeddedViewList windowContainsEmbedded: o_window] )
150 o_voutView = [o_embeddedViewList viewForWindow: o_window];
152 /* We have a detached vout */
153 else if( [[o_window className] isEqualToString: @"VLCVoutWindow"] )
155 o_voutView = [o_window voutView];
158 return [[o_voutView retain] autorelease];
161 - (BOOL)aspectRatioIsLocked
163 return b_lockAspectRatio;
166 - (IBAction)stop:(id)sender
168 intf_thread_t * p_intf = VLCIntf;
169 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_STOP );
170 /* Close the window directly, because we do know that there
171 * won't be anymore video. It's currently waiting a bit. */
172 [[[self voutView] window] orderOut:self];
175 - (IBAction)faster:(id)sender
177 intf_thread_t * p_intf = VLCIntf;
178 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_FASTER );
181 - (IBAction)slower:(id)sender
183 intf_thread_t * p_intf = VLCIntf;
184 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_SLOWER );
187 - (IBAction)normalSpeed:(id)sender
189 intf_thread_t * p_intf = VLCIntf;
190 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_NORMAL );
193 - (IBAction)prev:(id)sender
195 intf_thread_t * p_intf = VLCIntf;
196 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PREV );
199 - (IBAction)next:(id)sender
201 intf_thread_t * p_intf = VLCIntf;
202 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_NEXT );
205 - (IBAction)random:(id)sender
208 intf_thread_t * p_intf = VLCIntf;
209 playlist_t * p_playlist = pl_Hold( p_intf );
211 var_Get( p_playlist, "random", &val );
212 val.b_bool = !val.b_bool;
213 var_Set( p_playlist, "random", val );
216 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Random On" ) );
217 config_PutInt( p_playlist, "random", 1 );
221 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Random Off" ) );
222 config_PutInt( p_playlist, "random", 0 );
225 p_intf->p_sys->b_playmode_update = true;
226 p_intf->p_sys->b_intf_update = true;
227 pl_Release( p_intf );
230 /* three little ugly helpers */
233 [o_btn_repeat setImage: o_repeat_single];
234 [o_btn_repeat setAlternateImage: o_repeat_all];
235 [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOneOn"]];
239 [o_btn_repeat setImage: o_repeat_all];
240 [o_btn_repeat setAlternateImage: o_repeat_off];
241 [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOn"]];
245 [o_btn_repeat setImage: o_repeat_off];
246 [o_btn_repeat setAlternateImage: o_repeat_single];
247 [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeat"]];
252 playlist_t *p_playlist = pl_Hold( VLCIntf );
253 var_Get( p_playlist, "random", &val );
254 [o_btn_shuffle setState: val.b_bool];
256 [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffleOn"]];
258 [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffle"]];
259 pl_Release( VLCIntf );
262 - (IBAction)repeatButtonAction:(id)sender
264 vlc_value_t looping,repeating;
265 intf_thread_t * p_intf = VLCIntf;
266 playlist_t * p_playlist = pl_Hold( p_intf );
268 var_Get( p_playlist, "repeat", &repeating );
269 var_Get( p_playlist, "loop", &looping );
271 if( !repeating.b_bool && !looping.b_bool )
273 /* was: no repeating at all, switching to Repeat One */
275 /* set our button's look */
278 /* prepare core communication */
279 repeating.b_bool = true;
280 looping.b_bool = false;
281 config_PutInt( p_playlist, "repeat", 1 );
282 config_PutInt( p_playlist, "loop", 0 );
284 /* show the change */
285 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat One" ) );
287 else if( repeating.b_bool && !looping.b_bool )
289 /* was: Repeat One, switching to Repeat All */
291 /* set our button's look */
294 /* prepare core communication */
295 repeating.b_bool = false;
296 looping.b_bool = true;
297 config_PutInt( p_playlist, "repeat", 0 );
298 config_PutInt( p_playlist, "loop", 1 );
300 /* show the change */
301 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat All" ) );
305 /* was: Repeat All or bug in VLC, switching to Repeat Off */
307 /* set our button's look */
310 /* prepare core communication */
311 repeating.b_bool = false;
312 looping.b_bool = false;
313 config_PutInt( p_playlist, "repeat", 0 );
314 config_PutInt( p_playlist, "loop", 0 );
316 /* show the change */
317 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat Off" ) );
320 /* communicate with core and the main intf loop */
321 var_Set( p_playlist, "repeat", repeating );
322 var_Set( p_playlist, "loop", looping );
323 p_intf->p_sys->b_playmode_update = true;
324 p_intf->p_sys->b_intf_update = true;
326 pl_Release( p_intf );
330 - (IBAction)repeat:(id)sender
333 intf_thread_t * p_intf = VLCIntf;
334 playlist_t * p_playlist = pl_Hold( p_intf );
336 var_Get( p_playlist, "repeat", &val );
339 var_Set( p_playlist, "loop", val );
341 val.b_bool = !val.b_bool;
342 var_Set( p_playlist, "repeat", val );
345 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat One" ) );
346 config_PutInt( p_playlist, "repeat", 1 );
350 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat Off" ) );
351 config_PutInt( p_playlist, "repeat", 0 );
354 p_intf->p_sys->b_playmode_update = true;
355 p_intf->p_sys->b_intf_update = true;
356 pl_Release( p_intf );
359 - (IBAction)loop:(id)sender
362 intf_thread_t * p_intf = VLCIntf;
363 playlist_t * p_playlist = pl_Hold( p_intf );
365 var_Get( p_playlist, "loop", &val );
368 var_Set( p_playlist, "repeat", val );
370 val.b_bool = !val.b_bool;
371 var_Set( p_playlist, "loop", val );
374 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat All" ) );
375 config_PutInt( p_playlist, "loop", 1 );
379 vout_OSDMessage( p_intf, DEFAULT_CHAN, "%s", _( "Repeat Off" ) );
380 config_PutInt( p_playlist, "loop", 0 );
383 p_intf->p_sys->b_playmode_update = true;
384 p_intf->p_sys->b_intf_update = true;
385 pl_Release( p_intf );
388 - (IBAction)quitAfterPlayback:(id)sender
391 playlist_t * p_playlist = pl_Hold( VLCIntf );
392 var_Get( p_playlist, "play-and-exit", &val );
393 val.b_bool = !val.b_bool;
394 var_Set( p_playlist, "play-and-exit", val );
395 pl_Release( VLCIntf );
398 - (IBAction)forward:(id)sender
400 intf_thread_t * p_intf = VLCIntf;
401 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_SHORT );
404 - (IBAction)backward:(id)sender
407 intf_thread_t * p_intf = VLCIntf;
408 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_SHORT );
412 - (IBAction)volumeUp:(id)sender
414 intf_thread_t * p_intf = VLCIntf;
415 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_UP );
416 /* Manage volume status */
417 [o_main manageVolumeSlider];
420 - (IBAction)volumeDown:(id)sender
422 intf_thread_t * p_intf = VLCIntf;
423 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_DOWN );
424 /* Manage volume status */
425 [o_main manageVolumeSlider];
428 - (IBAction)mute:(id)sender
430 intf_thread_t * p_intf = VLCIntf;
431 var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_MUTE );
432 /* Manage volume status */
433 [o_main manageVolumeSlider];
436 - (IBAction)volumeSliderUpdated:(id)sender
438 intf_thread_t * p_intf = VLCIntf;
439 playlist_t * p_playlist = pl_Hold( p_intf );
440 audio_volume_t i_volume = (audio_volume_t)[sender intValue];
443 i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
444 aout_VolumeSet( p_playlist, i_volume * i_volume_step );
445 pl_Release( p_intf );
446 /* Manage volume status */
447 [o_main manageVolumeSlider];
450 - (IBAction)showPosition: (id)sender
452 input_thread_t * p_input = pl_CurrentInput( VLCIntf );
453 if( p_input != NULL )
455 vout_thread_t *p_vout = input_GetVout( p_input );
458 var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION );
459 vlc_object_release( (vlc_object_t *)p_vout );
461 vlc_object_release( p_input );
465 - (IBAction)toogleFullscreen:(id)sender {
466 NSMenuItem *o_mi = [[NSMenuItem alloc] initWithTitle: _NS("Fullscreen") action: nil keyEquivalent:@""];
467 [self windowAction: [o_mi autorelease]];
470 - (BOOL) isFullscreen {
471 id o_vout_view = [self voutView];
474 return [o_vout_view isFullscreen];
479 - (IBAction)windowAction:(id)sender
481 NSString *o_title = [sender title];
482 input_thread_t * p_input = pl_CurrentInput( VLCIntf );
484 if( p_input != NULL )
486 vout_thread_t *p_vout = input_GetVout( p_input );
489 id o_vout_view = [self voutView];
492 if( [o_title isEqualToString: _NS("Half Size") ] )
493 [o_vout_view scaleWindowWithFactor: 0.5 animate: YES];
494 else if( [o_title isEqualToString: _NS("Normal Size") ] )
495 [o_vout_view scaleWindowWithFactor: 1.0 animate: YES];
496 else if( [o_title isEqualToString: _NS("Double Size") ] )
497 [o_vout_view scaleWindowWithFactor: 2.0 animate: YES];
498 else if( [o_title isEqualToString: _NS("Float on Top") ] )
499 [o_vout_view toggleFloatOnTop];
500 else if( [o_title isEqualToString: _NS("Fit to Screen") ] )
502 id o_window = [o_vout_view voutWindow];
503 if( ![o_window isZoomed] )
504 [o_window performZoom:self];
506 else if( [o_title isEqualToString: _NS("Snapshot") ] )
508 [o_vout_view snapshot];
512 /* Fullscreen state for next time will be saved here too */
513 [o_vout_view toggleFullscreen];
516 vlc_object_release( (vlc_object_t *)p_vout );
520 playlist_t * p_playlist = pl_Hold( VLCIntf );
522 if( [o_title isEqualToString: _NS("Fullscreen")] ||
523 [sender isKindOfClass:[NSButton class]] )
525 var_ToggleBool( p_playlist, "fullscreen" );
528 pl_Release( VLCIntf );
530 vlc_object_release( p_input );
534 - (IBAction)telxTransparent:(id)sender
536 intf_thread_t * p_intf = VLCIntf;
538 p_vbi = (vlc_object_t *) vlc_object_find_name( p_intf,
539 "zvbi", FIND_ANYWHERE );
542 var_SetBool( p_vbi, "vbi-opaque", [sender state] );
543 [sender setState: ![sender state]];
544 vlc_object_release( p_vbi );
548 - (IBAction)telxNavLink:(id)sender
550 intf_thread_t * p_intf = VLCIntf;
554 if( [[sender title] isEqualToString: _NS("Index")] )
556 else if( [[sender title] isEqualToString: _NS("Red")] )
558 else if( [[sender title] isEqualToString: _NS("Green")] )
560 else if( [[sender title] isEqualToString: _NS("Yellow")] )
562 else if( [[sender title] isEqualToString: _NS("Blue")] )
564 if( i_page == 0 ) return;
566 p_vbi = (vlc_object_t *) vlc_object_find_name( p_intf,
567 "zvbi", FIND_ANYWHERE );
570 var_SetInteger( p_vbi, "vbi-page", i_page );
571 vlc_object_release( p_vbi );
575 - (IBAction)lockVideosAspectRatio:(id)sender
577 if( [sender state] == NSOffState )
578 [sender setState: NSOnState];
580 [sender setState: NSOffState];
582 b_lockAspectRatio = !b_lockAspectRatio;
585 - (IBAction)addSubtitleFile:(id)sender
587 NSInteger i_returnValue = 0;
588 input_thread_t * p_input = pl_CurrentInput( VLCIntf );
589 if( !p_input ) return;
591 input_item_t *p_item = input_GetItem( p_input );
592 if( !p_item ) return;
594 char *path = input_item_GetURI( p_item );
595 if( !path ) path = strdup( "" );
597 NSOpenPanel * openPanel = [NSOpenPanel openPanel];
598 [openPanel setCanChooseFiles: YES];
599 [openPanel setCanChooseDirectories: NO];
600 [openPanel setAllowsMultipleSelection: YES];
601 i_returnValue = [openPanel runModalForDirectory: [NSString stringWithUTF8String: path] file: nil types: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi", nil]];
604 if( i_returnValue == NSOKButton )
607 if( !p_input ) return;
609 c = [[openPanel filenames] count];
611 for (int i = 0; i < [[openPanel filenames] count] ; i++)
613 msg_Dbg( VLCIntf, "loading subs from %s", [[[openPanel filenames] objectAtIndex: i] UTF8String] );
614 if( input_AddSubtitle( p_input, [[[openPanel filenames] objectAtIndex: i] UTF8String], TRUE ) )
615 msg_Warn( VLCIntf, "unable to load subtitles from '%s'",
616 [[[openPanel filenames] objectAtIndex: i] UTF8String] );
621 - (void)scrollWheel:(NSEvent *)theEvent
623 intf_thread_t * p_intf = VLCIntf;
624 float f_yabsvalue = [theEvent deltaY] > 0.0f ? [theEvent deltaY] : -[theEvent deltaY];
625 float f_xabsvalue = [theEvent deltaX] > 0.0f ? [theEvent deltaX] : -[theEvent deltaX];
626 int i, i_yvlckey, i_xvlckey;
628 if ([theEvent deltaY] < 0.0f)
629 i_yvlckey = KEY_MOUSEWHEELDOWN;
631 i_yvlckey = KEY_MOUSEWHEELUP;
633 if ([theEvent deltaX] < 0.0f)
634 i_xvlckey = KEY_MOUSEWHEELRIGHT;
636 i_xvlckey = KEY_MOUSEWHEELLEFT;
638 /* Send multiple key event, depending on the intensity of the event */
639 for (i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
640 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_yvlckey );
642 /* Prioritize Y event (sound volume) over X event */
643 if (f_yabsvalue < 0.05)
645 for (i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
646 var_SetInteger( p_intf->p_libvlc, "key-pressed", i_xvlckey );
650 - (BOOL)keyEvent:(NSEvent *)o_event
652 BOOL eventHandled = NO;
653 unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
657 input_thread_t * p_input = pl_CurrentInput( VLCIntf );
658 if( p_input != NULL )
660 vout_thread_t *p_vout = input_GetVout( p_input );
665 if( key == (unichar) 0x1b )
667 id o_vout_view = [self voutView];
668 if( o_vout_view && [o_vout_view isFullscreen] )
670 [o_vout_view toggleFullscreen];
674 else if( key == ' ' )
679 vlc_object_release( (vlc_object_t *)p_vout );
681 vlc_object_release( p_input );
687 - (void)setupVarMenuItem:(NSMenuItem *)o_mi
688 target:(vlc_object_t *)p_object
689 var:(const char *)psz_variable
690 selector:(SEL)pf_callback
692 vlc_value_t val, text;
693 int i_type = var_Type( p_object, psz_variable );
695 switch( i_type & VLC_VAR_TYPE )
699 case VLC_VAR_VARIABLE:
701 case VLC_VAR_INTEGER:
704 /* Variable doesn't exist or isn't handled */
708 /* Make sure we want to display the variable */
709 if( i_type & VLC_VAR_HASCHOICE )
711 var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
712 if( val.i_int == 0 ) return;
713 if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
717 /* Get the descriptive name of the variable */
718 var_Change( p_object, psz_variable, VLC_VAR_GETTEXT, &text, NULL );
719 [o_mi setTitle: [[VLCMain sharedInstance] localizedString: text.psz_string ?
720 text.psz_string : psz_variable ]];
722 if( i_type & VLC_VAR_HASCHOICE )
724 NSMenu *o_menu = [o_mi submenu];
726 [self setupVarMenu: o_menu forMenuItem: o_mi target:p_object
727 var:psz_variable selector:pf_callback];
729 free( text.psz_string );
732 if( var_Get( p_object, psz_variable, &val ) < 0 )
737 VLCAutoGeneratedMenuContent *o_data;
738 switch( i_type & VLC_VAR_TYPE )
741 o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
742 andValue: val ofType: i_type];
743 [o_mi setRepresentedObject: [o_data autorelease]];
747 o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
748 andValue: val ofType: i_type];
749 [o_mi setRepresentedObject: [o_data autorelease]];
750 if( !( i_type & VLC_VAR_ISCOMMAND ) )
751 [o_mi setState: val.b_bool ? TRUE : FALSE ];
758 if( ( i_type & VLC_VAR_TYPE ) == VLC_VAR_STRING ) free( val.psz_string );
759 free( text.psz_string );
763 - (void)setupVarMenu:(NSMenu *)o_menu
764 forMenuItem: (NSMenuItem *)o_parent
765 target:(vlc_object_t *)p_object
766 var:(const char *)psz_variable
767 selector:(SEL)pf_callback
769 vlc_value_t val, val_list, text_list;
770 int i_type, i, i_nb_items;
772 /* remove previous items */
773 i_nb_items = [o_menu numberOfItems];
774 for( i = 0; i < i_nb_items; i++ )
776 [o_menu removeItemAtIndex: 0];
779 /* Check the type of the object variable */
780 i_type = var_Type( p_object, psz_variable );
782 /* Make sure we want to display the variable */
783 if( i_type & VLC_VAR_HASCHOICE )
785 var_Change( p_object, psz_variable, VLC_VAR_CHOICESCOUNT, &val, NULL );
786 if( val.i_int == 0 ) return;
787 if( (i_type & VLC_VAR_TYPE) != VLC_VAR_VARIABLE && val.i_int == 1 )
795 switch( i_type & VLC_VAR_TYPE )
799 case VLC_VAR_VARIABLE:
801 case VLC_VAR_INTEGER:
804 /* Variable doesn't exist or isn't handled */
808 if( var_Get( p_object, psz_variable, &val ) < 0 )
813 if( var_Change( p_object, psz_variable, VLC_VAR_GETLIST,
814 &val_list, &text_list ) < 0 )
816 if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
820 /* make (un)sensitive */
821 [o_parent setEnabled: ( val_list.p_list->i_count > 1 )];
824 if( [[o_parent title] isEqualToString: _NS("Aspect-ratio")] == YES )
826 NSMenuItem *o_lmi_tmp2;
827 o_lmi_tmp2 = [o_menu addItemWithTitle: _NS("Lock Aspect Ratio") action: @selector(lockVideosAspectRatio:) keyEquivalent: @""];
828 [o_lmi_tmp2 setTarget: self];
829 [o_lmi_tmp2 setEnabled: YES];
830 [o_lmi_tmp2 setState: b_lockAspectRatio];
831 [o_parent setEnabled: YES];
832 [o_menu addItem: [NSMenuItem separatorItem]];
835 /* special case for the subtitles items */
836 if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
838 NSMenuItem * o_lmi_tmp;
839 o_lmi_tmp = [o_menu addItemWithTitle: _NS("Open File...") action: @selector(addSubtitleFile:) keyEquivalent: @""];
840 [o_lmi_tmp setTarget: self];
841 [o_lmi_tmp setEnabled: YES];
842 [o_parent setEnabled: YES];
843 [o_menu addItem: [NSMenuItem separatorItem]];
846 for( i = 0; i < val_list.p_list->i_count; i++ )
849 NSString *o_title = @"";
850 VLCAutoGeneratedMenuContent *o_data;
852 switch( i_type & VLC_VAR_TYPE )
856 o_title = [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string ?
857 text_list.p_list->p_values[i].psz_string : val_list.p_list->p_values[i].psz_string ];
859 o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
860 o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
861 andValue: val_list.p_list->p_values[i] ofType: i_type];
862 [o_lmi setRepresentedObject: [o_data autorelease]];
863 [o_lmi setTarget: self];
865 if( !strcmp( val.psz_string, val_list.p_list->p_values[i].psz_string ) && !( i_type & VLC_VAR_ISCOMMAND ) )
866 [o_lmi setState: TRUE ];
870 case VLC_VAR_INTEGER:
872 o_title = text_list.p_list->p_values[i].psz_string ?
873 [[VLCMain sharedInstance] localizedString: text_list.p_list->p_values[i].psz_string] :
874 [NSString stringWithFormat: @"%d",
875 val_list.p_list->p_values[i].i_int];
877 o_lmi = [o_menu addItemWithTitle: o_title action: pf_callback keyEquivalent: @""];
878 o_data = [[VLCAutoGeneratedMenuContent alloc] initWithVariableName: psz_variable ofObject: p_object
879 andValue: val_list.p_list->p_values[i] ofType: i_type];
880 [o_lmi setRepresentedObject: [o_data autorelease]];
881 [o_lmi setTarget: self];
883 if( val_list.p_list->p_values[i].i_int == val.i_int && !( i_type & VLC_VAR_ISCOMMAND ) )
884 [o_lmi setState: TRUE ];
892 /* special case for the subtitles sub-menu
893 * In case that we don't have any subs, we don't want a separator item at the end */
894 if( [[o_parent title] isEqualToString: _NS("Subtitles Track")] == YES )
896 if( [o_menu numberOfItems] == 2 )
897 [o_menu removeItemAtIndex: 1];
900 /* clean up everything */
901 if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING ) free( val.psz_string );
902 var_FreeList( &val_list, &text_list );
905 - (IBAction)toggleVar:(id)sender
907 NSMenuItem *o_mi = (NSMenuItem *)sender;
908 VLCAutoGeneratedMenuContent *o_data = [o_mi representedObject];
909 [NSThread detachNewThreadSelector: @selector(toggleVarThread:)
910 toTarget: self withObject: o_data];
915 - (int)toggleVarThread: (id)data
917 vlc_object_t *p_object;
918 NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
920 assert([data isKindOfClass:[VLCAutoGeneratedMenuContent class]]);
921 VLCAutoGeneratedMenuContent *menuContent = (VLCAutoGeneratedMenuContent *)data;
923 vlc_thread_set_priority( VLCIntf , VLC_THREAD_PRIORITY_LOW );
925 p_object = [menuContent vlcObject];
927 if( p_object != NULL )
929 var_Set( p_object, [menuContent name], [menuContent value] );
930 vlc_object_release( p_object );
938 - (IBAction)goToSpecificTime:(id)sender
940 if( sender == o_specificTime_cancel_btn )
942 [NSApp endSheet: o_specificTime_win];
943 [o_specificTime_win close];
945 else if( sender == o_specificTime_ok_btn )
947 input_thread_t * p_input = pl_CurrentInput( VLCIntf );
950 unsigned int timeInSec = 0;
951 NSString * fieldContent = [o_specificTime_enter_fld stringValue];
952 if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
953 [[fieldContent componentsSeparatedByString: @":"] count] <= 3 )
955 NSArray * ourTempArray = \
956 [fieldContent componentsSeparatedByString: @":"];
958 if( [[fieldContent componentsSeparatedByString: @":"] count] == 3 )
960 timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
961 timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
962 timeInSec += [[ourTempArray objectAtIndex: 2] intValue]; //s
966 timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
967 timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
971 timeInSec = [fieldContent intValue];
973 input_Control( p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
974 vlc_object_release( p_input );
977 [NSApp endSheet: o_specificTime_win];
978 [o_specificTime_win close];
982 input_thread_t * p_input = pl_CurrentInput( VLCIntf );
985 /* we can obviously only do that if an input is available */
986 vlc_value_t pos, length;
987 var_Get( p_input, "time", &pos );
988 [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
989 var_Get( p_input, "length", &length );
990 [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];
992 [NSApp beginSheet: o_specificTime_win modalForWindow: \
993 [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
995 [o_specificTime_win makeKeyWindow];
996 vlc_object_release( p_input );
1007 msg_Err( VLCIntf, "FSPanel is nil" );
1014 @implementation VLCControls (NSMenuValidation)
1016 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
1018 BOOL bEnabled = TRUE;
1020 intf_thread_t * p_intf = VLCIntf;
1021 playlist_t * p_playlist = pl_Hold( p_intf );
1022 input_thread_t * p_input = playlist_CurrentInput( p_playlist );
1024 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
1025 [[o_mi title] isEqualToString: _NS("Slower")] ||
1026 [[o_mi title] isEqualToString: _NS("Normal rate")] )
1028 if( p_input != NULL )
1030 bEnabled = var_GetBool( p_input, "can-rate" );
1037 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
1039 if( p_input == NULL )
1043 [o_main setupMenus]; /* Make sure input menu is up to date */
1045 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
1046 [[o_mi title] isEqualToString: _NS("Next")] )
1049 bEnabled = playlist_CurrentSize( p_playlist ) > 1;
1052 else if( [[o_mi title] isEqualToString: _NS("Random")] )
1055 var_Get( p_playlist, "random", &val );
1056 i_state = val.b_bool ? NSOnState : NSOffState;
1057 [o_mi setState: i_state];
1059 else if( [[o_mi title] isEqualToString: _NS("Repeat One")] )
1062 var_Get( p_playlist, "repeat", &val );
1063 i_state = val.b_bool ? NSOnState : NSOffState;
1064 [o_mi setState: i_state];
1066 else if( [[o_mi title] isEqualToString: _NS("Repeat All")] )
1069 var_Get( p_playlist, "loop", &val );
1070 i_state = val.b_bool ? NSOnState : NSOffState;
1071 [o_mi setState: i_state];
1073 else if( [[o_mi title] isEqualToString: _NS("Quit after Playback")] )
1076 var_Get( p_playlist, "play-and-exit", &val );
1077 i_state = val.b_bool ? NSOnState : NSOffState;
1078 [o_mi setState: i_state];
1080 else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
1081 [[o_mi title] isEqualToString: _NS("Step Backward")] ||
1082 [[o_mi title] isEqualToString: _NS("Jump To Time")])
1084 if( p_input != NULL )
1086 var_Get( p_input, "can-seek", &val);
1087 bEnabled = val.b_bool;
1089 else bEnabled = FALSE;
1091 else if( [[o_mi title] isEqualToString: _NS("Mute")] )
1093 [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
1094 [o_main setupMenus]; /* Make sure audio menu is up to date */
1096 else if( [[o_mi title] isEqualToString: _NS("Half Size")] ||
1097 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
1098 [[o_mi title] isEqualToString: _NS("Double Size")] ||
1099 [[o_mi title] isEqualToString: _NS("Fit to Screen")] ||
1100 [[o_mi title] isEqualToString: _NS("Snapshot")] ||
1101 [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
1102 [[o_mi title] isEqualToString: _NS("Float on Top")] )
1105 NSArray *o_windows = [NSApp orderedWindows];
1106 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
1109 if( p_input != NULL )
1111 vout_thread_t *p_vout = input_GetVout( p_input );
1112 if( p_vout != NULL )
1114 if( [[o_mi title] isEqualToString: _NS("Float on Top")] )
1116 var_Get( p_vout, "video-on-top", &val );
1117 [o_mi setState: val.b_bool ? NSOnState : NSOffState];
1120 while( (o_window = [o_enumerator nextObject]))
1122 if( [[o_window className] isEqualToString: @"VLCVoutWindow"] ||
1123 [[[VLCMain sharedInstance] embeddedList]
1124 windowContainsEmbedded: o_window])
1131 vlc_object_release( (vlc_object_t *)p_vout );
1134 if( [[o_mi title] isEqualToString: _NS("Fullscreen")] )
1136 var_Get( p_playlist, "fullscreen", &val );
1137 [o_mi setState: val.b_bool];
1140 [o_main setupMenus]; /* Make sure video menu is up to date */
1143 /* Special case for telx menu */
1144 if( [[o_mi title] isEqualToString: _NS("Normal Size")] )
1146 NSMenuItem *item = [[o_mi menu] itemWithTitle:_NS("Teletext")];
1147 bool b_telx = p_input && var_GetInteger( p_input, "teletext-es" ) >= 0;
1149 [[item submenu] setAutoenablesItems:NO];
1150 for( int k=0; k < [[item submenu] numberOfItems]; k++ )
1152 [[[item submenu] itemAtIndex:k] setEnabled: b_telx];
1156 if( p_input ) vlc_object_release( p_input );
1157 pl_Release( p_intf );
1164 /*****************************************************************************
1165 * VLCAutoGeneratedMenuContent implementation
1166 *****************************************************************************
1167 * Object connected to a playlistitem which remembers the data belonging to
1168 * the variable of the autogenerated menu
1169 *****************************************************************************/
1170 @implementation VLCAutoGeneratedMenuContent
1172 -(id) initWithVariableName:(const char *)name ofObject:(vlc_object_t *)object
1173 andValue:(vlc_value_t)val ofType:(int)type
1175 self = [super init];
1179 _vlc_object = vlc_object_hold( object );
1180 psz_name = strdup( name );
1183 if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
1184 value.psz_string = strdup( val.psz_string );
1192 vlc_object_release( _vlc_object );
1193 if( (i_type & VLC_VAR_TYPE) == VLC_VAR_STRING )
1194 free( value.psz_string );
1199 - (const char *)name
1204 - (vlc_value_t)value
1209 - (vlc_object_t *)vlcObject
1211 return vlc_object_hold( _vlc_object );
1223 /*****************************************************************************
1224 * VLCTimeField implementation
1225 *****************************************************************************
1226 * we need this to catch our click-event in the controller window
1227 *****************************************************************************/
1229 @implementation VLCTimeField
1230 - (void)mouseDown: (NSEvent *)ourEvent
1232 if( [ourEvent clickCount] > 1 )
1233 [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
1235 [[VLCMain sharedInstance] timeFieldWasClicked: self];