1 /*****************************************************************************
2 * controls.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: controls.m,v 1.27 2003/02/10 00:41:45 hartman Exp $
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Christophe Massiot <massiot@via.ecp.fr>
9 * Derk-Jan Hartman <thedj@users.sourceforge.net>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
24 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
29 #include <stdlib.h> /* malloc(), free() */
30 #include <sys/param.h> /* for MAXPATHLEN */
36 /*****************************************************************************
37 * VLCControls interface
38 *****************************************************************************/
39 @interface VLCControls : NSObject
44 IBOutlet id o_volumeslider;
47 - (IBAction)play:(id)sender;
48 - (IBAction)stop:(id)sender;
49 - (IBAction)faster:(id)sender;
50 - (IBAction)slower:(id)sender;
52 - (IBAction)prev:(id)sender;
53 - (IBAction)next:(id)sender;
54 - (IBAction)loop:(id)sender;
56 - (IBAction)forward:(id)sender;
57 - (IBAction)backward:(id)sender;
59 - (IBAction)volumeUp:(id)sender;
60 - (IBAction)volumeDown:(id)sender;
61 - (IBAction)mute:(id)sender;
62 - (IBAction)volumeSliderUpdated:(id)sender;
63 - (void)updateVolumeSlider;
65 - (IBAction)halfWindow:(id)sender;
66 - (IBAction)normalWindow:(id)sender;
67 - (IBAction)doubleWindow:(id)sender;
68 - (IBAction)fullscreen:(id)sender;
69 - (IBAction)deinterlace:(id)sender;
71 - (IBAction)toggleProgram:(id)sender;
72 - (IBAction)toggleTitle:(id)sender;
73 - (IBAction)toggleChapter:(id)sender;
74 - (IBAction)toggleLanguage:(id)sender;
75 - (IBAction)toggleVar:(id)sender;
79 /*****************************************************************************
80 * VLCControls implementation
81 *****************************************************************************/
82 @implementation VLCControls
84 - (IBAction)play:(id)sender
86 intf_thread_t * p_intf = [NSApp getIntf];
88 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
90 if( p_playlist == NULL )
95 if( playlist_IsPlaying( p_playlist ) )
97 playlist_Pause( p_playlist );
98 vlc_object_release( p_playlist );
102 if( !playlist_IsEmpty( p_playlist ) )
104 playlist_Play( p_playlist );
105 vlc_object_release( p_playlist );
109 vlc_object_release( p_playlist );
110 [o_open openFile: nil];
115 - (IBAction)stop:(id)sender
117 intf_thread_t * p_intf = [NSApp getIntf];
119 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
121 if( p_playlist == NULL )
126 playlist_Stop( p_playlist );
127 vlc_object_release( p_playlist );
130 - (IBAction)faster:(id)sender
132 intf_thread_t * p_intf = [NSApp getIntf];
134 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
136 if( p_playlist == NULL )
141 vlc_mutex_lock( &p_playlist->object_lock );
142 if( p_playlist->p_input != NULL )
144 input_SetStatus( p_playlist->p_input, INPUT_STATUS_FASTER );
146 vlc_mutex_unlock( &p_playlist->object_lock );
148 vlc_object_release( p_playlist );
151 - (IBAction)slower:(id)sender
153 intf_thread_t * p_intf = [NSApp getIntf];
155 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
157 if( p_playlist == NULL )
162 vlc_mutex_lock( &p_playlist->object_lock );
163 if( p_playlist->p_input != NULL )
165 input_SetStatus( p_playlist->p_input, INPUT_STATUS_SLOWER );
167 vlc_mutex_unlock( &p_playlist->object_lock );
169 vlc_object_release( p_playlist );
172 - (IBAction)prev:(id)sender
174 intf_thread_t * p_intf = [NSApp getIntf];
176 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
178 if( p_playlist == NULL )
183 vlc_mutex_lock( &p_playlist->object_lock );
185 if( p_playlist->p_input == NULL )
187 vlc_mutex_unlock( &p_playlist->object_lock );
188 vlc_object_release( p_playlist );
192 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
194 #define p_area p_playlist->p_input->stream.p_selected_area
196 if( p_area->i_part_nb > 1 && p_area->i_part > 1 )
200 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
201 input_ChangeArea( p_playlist->p_input, p_area );
202 vlc_mutex_unlock( &p_playlist->object_lock );
204 p_intf->p_sys->b_chapter_update = VLC_TRUE;
208 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
209 vlc_mutex_unlock( &p_playlist->object_lock );
210 playlist_Prev( p_playlist );
215 vlc_object_release( p_playlist );
218 - (IBAction)next:(id)sender
220 intf_thread_t * p_intf = [NSApp getIntf];
222 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
224 if( p_playlist == NULL )
229 vlc_mutex_lock( &p_playlist->object_lock );
231 if( p_playlist->p_input == NULL )
233 vlc_mutex_unlock( &p_playlist->object_lock );
234 vlc_object_release( p_playlist );
238 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
240 #define p_area p_playlist->p_input->stream.p_selected_area
242 if( p_area->i_part_nb > 1 && p_area->i_part + 1 < p_area->i_part_nb )
246 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
247 input_ChangeArea( p_playlist->p_input, p_area );
248 vlc_mutex_unlock( &p_playlist->object_lock );
250 p_intf->p_sys->b_chapter_update = VLC_TRUE;
254 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
255 vlc_mutex_unlock( &p_playlist->object_lock );
256 playlist_Next( p_playlist );
261 vlc_object_release( p_playlist );
264 - (IBAction)loop:(id)sender
266 intf_thread_t * p_intf = [NSApp getIntf];
268 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
270 if( p_playlist == NULL )
275 config_PutInt( p_playlist, "loop",
276 !config_GetInt( p_playlist, "loop" ) );
278 vlc_object_release( p_playlist );
281 - (IBAction)forward:(id)sender
283 intf_thread_t * p_intf = [NSApp getIntf];
284 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
286 if( p_playlist == NULL || p_playlist->p_input == NULL )
288 if ( p_playlist != NULL ) vlc_object_release( p_playlist );
292 input_Seek( p_playlist->p_input, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
293 vlc_object_release( p_playlist );
296 - (IBAction)backward:(id)sender
298 intf_thread_t * p_intf = [NSApp getIntf];
299 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
301 if( p_playlist == NULL || p_playlist->p_input == NULL )
303 if ( p_playlist != NULL ) vlc_object_release( p_playlist );
307 input_Seek( p_playlist->p_input, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
308 vlc_object_release( p_playlist );
311 - (IBAction)volumeUp:(id)sender
313 intf_thread_t * p_intf = [NSApp getIntf];
315 aout_VolumeUp( p_intf, 1, NULL );
317 if( p_intf->p_sys->b_mute )
322 [self updateVolumeSlider];
325 - (IBAction)volumeDown:(id)sender
327 intf_thread_t * p_intf = [NSApp getIntf];
329 aout_VolumeDown( p_intf, 1, NULL );
331 if( p_intf->p_sys->b_mute )
336 [self updateVolumeSlider];
339 - (IBAction)mute:(id)sender
341 intf_thread_t * p_intf = [NSApp getIntf];
342 audio_volume_t i_volume;
344 aout_VolumeMute( p_intf, &i_volume );
345 p_intf->p_sys->b_mute = ( i_volume == 0 );
347 [self updateVolumeSlider];
350 - (IBAction)volumeSliderUpdated:(id)sender
352 intf_thread_t * p_intf = [NSApp getIntf];
353 audio_volume_t i_volume = (audio_volume_t)[sender intValue];
355 aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
358 - (void)updateVolumeSlider
360 intf_thread_t * p_intf = [NSApp getIntf];
361 audio_volume_t i_volume;
363 aout_VolumeGet( p_intf, &i_volume );
365 [o_volumeslider setFloatValue: (float)(i_volume / AOUT_VOLUME_STEP)];
368 - (IBAction)halfWindow:(id)sender
370 id o_window = [NSApp keyWindow];
371 NSArray *o_windows = [NSApp windows];
372 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
374 while ((o_window = [o_enumerator nextObject]))
376 if( [[o_window className] isEqualToString: @"VLCWindow"] )
378 [o_window scaleWindowWithFactor: 0.5];
383 - (IBAction)normalWindow:(id)sender
385 id o_window = [NSApp keyWindow];
386 NSArray *o_windows = [NSApp windows];
387 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
389 while ((o_window = [o_enumerator nextObject]))
391 if( [[o_window className] isEqualToString: @"VLCWindow"] )
393 [o_window scaleWindowWithFactor: 1];
398 - (IBAction)doubleWindow:(id)sender
400 id o_window = [NSApp keyWindow];
401 NSArray *o_windows = [NSApp windows];
402 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
404 while ((o_window = [o_enumerator nextObject]))
406 if( [[o_window className] isEqualToString: @"VLCWindow"] )
408 [o_window scaleWindowWithFactor: 2];
414 - (IBAction)fullscreen:(id)sender
416 id o_window = [NSApp keyWindow];
417 NSArray *o_windows = [NSApp windows];
418 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
420 while ((o_window = [o_enumerator nextObject]))
422 if( [[o_window className] isEqualToString: @"VLCWindow"] )
424 [o_window toggleFullscreen];
429 - (IBAction)deinterlace:(id)sender
431 intf_thread_t * p_intf = [NSApp getIntf];
432 BOOL bEnable = [sender state] == NSOffState;
436 config_PutPsz( p_intf, "filter", "deinterlace" );
437 config_PutPsz( p_intf, "deinterlace-mode",
438 [[sender title] lossyCString] );
442 config_PutPsz( p_intf, "filter", NULL );
446 - (IBAction)toggleProgram:(id)sender
448 NSMenuItem * o_mi = (NSMenuItem *)sender;
449 intf_thread_t * p_intf = [NSApp getIntf];
451 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
453 if( p_playlist == NULL )
458 vlc_mutex_lock( &p_playlist->object_lock );
460 if( p_playlist->p_input == NULL )
462 vlc_mutex_unlock( &p_playlist->object_lock );
463 vlc_object_release( p_playlist );
467 if( [o_mi state] == NSOffState )
469 u16 i_program_id = [o_mi tag];
471 input_ChangeProgram( p_playlist->p_input, i_program_id );
472 input_SetStatus( p_playlist->p_input, INPUT_STATUS_PLAY );
475 vlc_mutex_unlock( &p_playlist->object_lock );
476 vlc_object_release( p_playlist );
479 - (IBAction)toggleTitle:(id)sender
481 NSMenuItem * o_mi = (NSMenuItem *)sender;
482 intf_thread_t * p_intf = [NSApp getIntf];
484 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
486 if( p_playlist == NULL )
491 vlc_mutex_lock( &p_playlist->object_lock );
493 if( p_playlist->p_input == NULL )
495 vlc_mutex_unlock( &p_playlist->object_lock );
496 vlc_object_release( p_playlist );
500 if( [o_mi state] == NSOffState )
502 int i_title = [o_mi tag];
504 #define p_input p_playlist->p_input
505 input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
506 input_SetStatus( p_input, INPUT_STATUS_PLAY );
510 vlc_mutex_unlock( &p_playlist->object_lock );
511 vlc_object_release( p_playlist );
514 - (IBAction)toggleChapter:(id)sender
516 NSMenuItem * o_mi = (NSMenuItem *)sender;
517 intf_thread_t * p_intf = [NSApp getIntf];
519 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
521 if( p_playlist == NULL )
526 vlc_mutex_lock( &p_playlist->object_lock );
528 if( p_playlist->p_input == NULL )
530 vlc_mutex_unlock( &p_playlist->object_lock );
531 vlc_object_release( p_playlist );
535 if( [o_mi state] == NSOffState )
537 int i_chapter = [o_mi tag];
539 #define p_input p_playlist->p_input
540 p_input->stream.p_selected_area->i_part = i_chapter;
541 input_ChangeArea( p_input, p_input->stream.p_selected_area );
542 input_SetStatus( p_input, INPUT_STATUS_PLAY );
546 vlc_mutex_unlock( &p_playlist->object_lock );
547 vlc_object_release( p_playlist );
550 - (IBAction)toggleLanguage:(id)sender
552 NSMenuItem * o_mi = (NSMenuItem *)sender;
553 intf_thread_t * p_intf = [NSApp getIntf];
555 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
557 if( p_playlist == NULL )
562 vlc_mutex_lock( &p_playlist->object_lock );
564 if( p_playlist->p_input == NULL )
566 vlc_mutex_unlock( &p_playlist->object_lock );
567 vlc_object_release( p_playlist );
572 /* We do not use this code, because you need to start stop .avi for
573 * it to work, so not very useful now --hartman */
574 if ( [o_mi state] == NSOffState && [o_mi tag] == 2000 )
576 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
578 [o_open_panel setAllowsMultipleSelection: NO];
579 [o_open_panel setTitle: _NS("Open subtitle file")];
580 [o_open_panel setPrompt: _NS("Open")];
582 if( [o_open_panel runModalForDirectory: nil
583 file: nil types: nil] == NSOKButton )
585 NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
586 config_PutPsz( p_intf, "sub-file", strdup( [o_filename cString] ));
591 #define p_input p_playlist->p_input
593 if( !p_intf->p_sys->b_audio_update )
595 NSValue * o_value = [o_mi representedObject];
596 es_descriptor_t * p_es = [o_value pointerValue];
598 if( [o_mi state] == NSOnState )
600 /* we just have one ES to disable */
601 input_ToggleES( p_input, p_es, 0 );
606 int i_cat = [o_mi tag];
608 vlc_mutex_lock( &p_input->stream.stream_lock );
610 #define ES p_input->stream.pp_selected_es[i]
612 /* unselect the selected ES in the same class */
613 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
615 if( ES->i_cat == i_cat )
617 vlc_mutex_unlock( &p_input->stream.stream_lock );
618 input_ToggleES( p_input, ES, 0 );
619 vlc_mutex_lock( &p_input->stream.stream_lock );
626 vlc_mutex_unlock( &p_input->stream.stream_lock );
628 input_ToggleES( p_input, p_es, 1 );
634 vlc_mutex_unlock( &p_playlist->object_lock );
635 vlc_object_release( p_playlist );
638 - (IBAction)toggleVar:(id)sender
640 NSMenuItem * o_mi = (NSMenuItem *)sender;
642 if( [o_mi state] == NSOffState )
644 const char * psz_variable = (const char *)[o_mi tag];
645 char * psz_value = [NSApp delocalizeString: [o_mi title]];
646 vlc_object_t * p_object = (vlc_object_t *)
647 [[o_mi representedObject] pointerValue];
649 /* psz_string sucks */
650 val.psz_string = (char *)psz_value;
652 if ( var_Set( p_object, psz_variable, val ) < 0 )
654 msg_Warn( p_object, "cannot set variable (%s)", psz_value );
663 @implementation VLCControls (NSMenuValidation)
665 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
667 BOOL bEnabled = TRUE;
668 NSMenu * o_menu = [o_mi menu];
669 intf_thread_t * p_intf = [NSApp getIntf];
671 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
674 if( p_playlist != NULL )
676 vlc_mutex_lock( &p_playlist->object_lock );
679 #define p_input p_playlist->p_input
681 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
682 [[o_mi title] isEqualToString: _NS("Slower")] )
684 if( p_playlist != NULL && p_input != NULL )
686 vlc_mutex_lock( &p_input->stream.stream_lock );
687 bEnabled = p_input->stream.b_pace_control;
688 vlc_mutex_unlock( &p_input->stream.stream_lock );
695 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
697 if( p_playlist == NULL || p_input == NULL )
702 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
703 [[o_mi title] isEqualToString: _NS("Next")] )
705 if( p_playlist == NULL )
711 bEnabled = p_playlist->i_size > 1;
713 if( p_input != NULL )
715 vlc_mutex_lock( &p_input->stream.stream_lock );
716 bEnabled |= p_input->stream.p_selected_area->i_part_nb > 1;
717 vlc_mutex_unlock( &p_input->stream.stream_lock );
721 else if( [[o_mi title] isEqualToString: _NS("Loop")] )
723 int i_state = config_GetInt( p_playlist, "loop" ) ?
724 NSOnState : NSOffState;
726 [o_mi setState: i_state];
728 else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
729 [[o_mi title] isEqualToString: _NS("Step Backward")] )
731 if( p_playlist != NULL && p_input != NULL )
733 vlc_mutex_lock( &p_input->stream.stream_lock );
734 bEnabled = p_input->stream.b_seekable;
735 vlc_mutex_unlock( &p_input->stream.stream_lock );
742 else if( [[o_mi title] isEqualToString: _NS("Mute")] )
744 [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
746 else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
747 [[o_mi title] isEqualToString: _NS("Half Size")] ||
748 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
749 [[o_mi title] isEqualToString: _NS("Double Size")])
752 NSArray *o_windows = [NSApp windows];
753 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
756 while ((o_window = [o_enumerator nextObject]))
758 if( [[o_window className] isEqualToString: @"VLCWindow"] )
765 else if( o_menu != nil &&
766 [[o_menu title] isEqualToString: _NS("Deinterlace")] )
768 char * psz_filter = config_GetPsz( p_intf, "filter" );
770 if( psz_filter != NULL )
774 psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
777 if( psz_filter != NULL )
779 if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
781 [o_mi setState: NSOnState];
785 [o_mi setState: NSOffState];
792 [o_mi setState: NSOffState];
796 if( p_playlist != NULL )
798 vlc_mutex_unlock( &p_playlist->object_lock );
799 vlc_object_release( p_playlist );