1 /*****************************************************************************
2 * controls.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: controls.m,v 1.12 2003/01/23 22:57:28 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 */
37 #include <Cocoa/Cocoa.h>
38 #include <CoreAudio/AudioHardware.h>
43 /*****************************************************************************
44 * VLCControls interface
45 *****************************************************************************/
46 @interface VLCControls : NSObject
50 IBOutlet id o_mi_mute;
51 IBOutlet id o_volumeslider;
55 - (IBAction)play:(id)sender;
56 - (IBAction)stop:(id)sender;
57 - (IBAction)faster:(id)sender;
58 - (IBAction)slower:(id)sender;
59 - (IBAction)slowMotion:(id)sender;
60 - (IBAction)fastForward:(id)sender;
62 - (IBAction)prev:(id)sender;
63 - (IBAction)next:(id)sender;
64 - (IBAction)loop:(id)sender;
66 - (IBAction)volumeUp:(id)sender;
67 - (IBAction)volumeDown:(id)sender;
68 - (IBAction)mute:(id)sender;
69 - (IBAction)volumeSliderUpdate:(id)sender;
70 - (IBAction)fullscreen:(id)sender;
71 - (IBAction)deinterlace:(id)sender;
73 - (IBAction)toggleProgram:(id)sender;
74 - (IBAction)toggleTitle:(id)sender;
75 - (IBAction)toggleChapter:(id)sender;
76 - (IBAction)toggleLanguage:(id)sender;
77 - (IBAction)toggleVar:(id)sender;
79 - (void)setVolumeSlider;
83 /*****************************************************************************
84 * VLCControls implementation
85 *****************************************************************************/
86 @implementation VLCControls
88 - (IBAction)play:(id)sender
90 intf_thread_t * p_intf = [NSApp getIntf];
91 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
93 if( p_playlist == NULL )
98 if ( p_intf->p_sys->p_input != NULL && p_intf->p_sys->p_input->stream.control.i_status != PAUSE_S)
100 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
101 vlc_object_release( p_playlist );
105 /* If the playlist is empty, open a file requester instead */
106 vlc_mutex_lock( &p_playlist->object_lock );
107 if( p_playlist->i_size )
109 vlc_mutex_unlock( &p_playlist->object_lock );
110 playlist_Play( p_playlist );
111 vlc_object_release( p_playlist );
115 vlc_mutex_unlock( &p_playlist->object_lock );
116 vlc_object_release( p_playlist );
118 [o_open openFile: nil];
123 - (IBAction)stop:(id)sender
125 intf_thread_t * p_intf = [NSApp getIntf];
126 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
128 if( p_playlist == NULL )
133 playlist_Stop( p_playlist );
134 vlc_object_release( p_playlist );
135 p_intf->p_sys->b_stopping = 1;
138 - (IBAction)faster:(id)sender
140 intf_thread_t * p_intf = [NSApp getIntf];
142 if( p_intf->p_sys->p_input == NULL )
147 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
150 - (IBAction)slower:(id)sender
152 intf_thread_t * p_intf = [NSApp getIntf];
154 if( p_intf->p_sys->p_input == NULL )
159 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
162 - (IBAction)slowMotion:(id)sender
165 switch( [[NSApp currentEvent] type] )
170 [self slower:sender];
177 intf_thread_t * p_intf = [NSApp getIntf];
179 [self faster:sender];
180 if ( p_intf->p_sys->p_input != NULL &&
181 p_intf->p_sys->p_input->stream.control.i_status != PAUSE_S)
183 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
194 - (IBAction)fastForward:(id)sender
196 playlist_t * p_playlist = vlc_object_find( [NSApp getIntf], VLC_OBJECT_PLAYLIST,
200 switch( [[NSApp currentEvent] type] )
202 /* A button does not send a NSLeftMouseDown unfortunately.
203 * Therefore we need to count. I know, it is ugly. We could have used
204 * a bool as well, but now we can also accellerate after a certain period.
205 * Currently this method is called every second if the button is pressed.
206 * You can set this value in intf.m (hartman)
213 else if ( i_ff == 5 )
217 else if ( i_ff == 15 )
226 vlc_mutex_lock( &p_playlist->object_lock );
227 int i_playlist_size = p_playlist->i_size ;
228 vlc_mutex_unlock( &p_playlist->object_lock );
229 if( i_playlist_size )
231 playlist_Play( p_playlist );
238 vlc_object_release( p_playlist );
241 - (IBAction)prev:(id)sender
243 intf_thread_t * p_intf = [NSApp getIntf];
244 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
246 if( p_playlist == NULL )
251 playlist_Prev( p_playlist );
252 vlc_object_release( p_playlist );
255 - (IBAction)next:(id)sender
257 intf_thread_t * p_intf = [NSApp getIntf];
258 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
260 if( p_playlist == NULL )
265 playlist_Next( p_playlist );
266 vlc_object_release( p_playlist );
269 - (IBAction)loop:(id)sender
271 NSMenuItem * o_mi = (NSMenuItem *)sender;
272 intf_thread_t * p_intf = [NSApp getIntf];
273 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
275 if( p_playlist == NULL )
280 if( p_intf->p_sys->b_loop )
282 [o_mi setState: NSOffState];
283 config_PutInt( p_playlist, "loop", 0 );
287 [o_mi setState: NSOnState];
288 config_PutInt( p_playlist, "loop", 1 );
291 p_intf->p_sys->b_loop = !p_intf->p_sys->b_loop;
293 vlc_object_release( p_playlist );
296 - (IBAction)volumeUp:(id)sender
298 intf_thread_t * p_intf = [NSApp getIntf];
299 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
301 if ( p_aout != NULL )
303 if (p_intf->p_sys->b_mute)
305 [self mute:o_mi_mute];
307 aout_VolumeUp( p_aout, 1, NULL );
308 vlc_object_release( (vlc_object_t *)p_aout );
310 [self setVolumeSlider];
313 - (IBAction)volumeDown:(id)sender
315 intf_thread_t * p_intf = [NSApp getIntf];
316 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
318 if ( p_aout != NULL )
320 if (p_intf->p_sys->b_mute)
322 [self mute:o_mi_mute];
324 aout_VolumeDown( p_aout, 1, NULL );
325 vlc_object_release( (vlc_object_t *)p_aout );
327 [self setVolumeSlider];
330 - (IBAction)mute:(id)sender
332 intf_thread_t * p_intf = [NSApp getIntf];
333 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
335 audio_volume_t i_volume;
337 if ( p_aout != NULL )
339 aout_VolumeMute( p_aout, &i_volume );
340 vlc_object_release( (vlc_object_t *)p_aout );
343 p_intf->p_sys->b_mute = (i_volume == 0);
344 [o_mi_mute setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
345 [o_volumeslider setEnabled: p_intf->p_sys->b_mute ? FALSE : TRUE];
346 [self setVolumeSlider];
349 - (IBAction)volumeSliderUpdate:(id)sender
351 intf_thread_t * p_intf = [NSApp getIntf];
352 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
354 audio_volume_t i_volume;
356 switch( [[NSApp currentEvent] type] )
358 case NSLeftMouseDragged:
359 if ( p_aout != NULL )
361 i_volume = (int) [sender floatValue];
362 aout_VolumeSet( p_aout, i_volume * AOUT_VOLUME_STEP);
363 vlc_object_release( (vlc_object_t *)p_aout );
368 if ( p_aout != NULL ) vlc_object_release( (vlc_object_t *)p_aout );
373 - (void)setVolumeSlider
375 intf_thread_t * p_intf = [NSApp getIntf];
376 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
378 audio_volume_t i_volume;
380 if ( p_aout != NULL )
382 aout_VolumeGet( p_aout, &i_volume );
383 vlc_object_release( (vlc_object_t *)p_aout );
384 [o_volumeslider setFloatValue: (float) (i_volume / AOUT_VOLUME_STEP)];
388 [o_volumeslider setFloatValue: config_GetInt( p_intf, "volume" )];
392 - (IBAction)fullscreen:(id)sender
394 id o_window = [NSApp keyWindow];
395 NSArray *o_windows = [NSApp windows];
396 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
398 while ((o_window = [o_enumerator nextObject]))
400 if( [[o_window className] isEqualToString: @"VLCWindow"] )
402 [o_window toggleFullscreen];
407 - (IBAction)deinterlace:(id)sender
409 intf_thread_t * p_intf = [NSApp getIntf];
410 BOOL bEnable = [sender state] == NSOffState;
414 config_PutPsz( p_intf, "filter", "deinterlace" );
415 config_PutPsz( p_intf, "deinterlace-mode",
416 [[sender title] lossyCString] );
420 config_PutPsz( p_intf, "filter", NULL );
424 - (IBAction)toggleProgram:(id)sender
426 NSMenuItem * o_mi = (NSMenuItem *)sender;
427 intf_thread_t * p_intf = [NSApp getIntf];
429 if( [o_mi state] == NSOffState )
431 u16 i_program_id = [o_mi tag];
433 input_ChangeProgram( p_intf->p_sys->p_input, i_program_id );
434 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
438 - (IBAction)toggleTitle:(id)sender
440 NSMenuItem * o_mi = (NSMenuItem *)sender;
441 intf_thread_t * p_intf = [NSApp getIntf];
443 if( [o_mi state] == NSOffState )
445 int i_title = [o_mi tag];
447 #define p_input p_intf->p_sys->p_input
448 input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
449 input_SetStatus( p_input, INPUT_STATUS_PLAY );
454 - (IBAction)toggleChapter:(id)sender
456 NSMenuItem * o_mi = (NSMenuItem *)sender;
457 intf_thread_t * p_intf = [NSApp getIntf];
459 if( [o_mi state] == NSOffState )
461 int i_chapter = [o_mi tag];
463 #define p_input p_intf->p_sys->p_input
464 p_input->stream.p_selected_area->i_part = i_chapter;
465 input_ChangeArea( p_input, p_input->stream.p_selected_area );
466 input_SetStatus( p_input, INPUT_STATUS_PLAY );
471 - (IBAction)toggleLanguage:(id)sender
473 NSMenuItem * o_mi = (NSMenuItem *)sender;
474 intf_thread_t * p_intf = [NSApp getIntf];
476 #define p_input p_intf->p_sys->p_input
478 if( !p_intf->p_sys->b_audio_update )
480 NSValue * o_value = [o_mi representedObject];
481 es_descriptor_t * p_es = [o_value pointerValue];
483 if( [o_mi state] == NSOnState )
485 /* we just have one ES to disable */
486 input_ToggleES( p_input, p_es, 0 );
491 int i_cat = [o_mi tag];
493 vlc_mutex_lock( &p_input->stream.stream_lock );
495 #define ES p_input->stream.pp_selected_es[i]
497 /* unselect the selected ES in the same class */
498 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
500 if( ES->i_cat == i_cat )
502 vlc_mutex_unlock( &p_input->stream.stream_lock );
503 input_ToggleES( p_input, ES, 0 );
504 vlc_mutex_lock( &p_input->stream.stream_lock );
511 vlc_mutex_unlock( &p_input->stream.stream_lock );
513 input_ToggleES( p_input, p_es, 1 );
520 - (IBAction)toggleVar:(id)sender
522 NSMenuItem * o_mi = (NSMenuItem *)sender;
524 if( [o_mi state] == NSOffState )
526 const char * psz_variable = (const char *)[o_mi tag];
527 const char * psz_value = [[o_mi title] cString];
528 vlc_object_t * p_object = (vlc_object_t *)
529 [[o_mi representedObject] pointerValue];
531 /* psz_string sucks */
532 val.psz_string = (char *)psz_value;
534 if ( var_Set( p_object, psz_variable, val ) < 0 )
536 msg_Warn( p_object, "cannot set variable (%s)", psz_value );
543 @implementation VLCControls (NSMenuValidation)
545 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
547 BOOL bEnabled = TRUE;
548 NSMenu * o_menu = [o_mi menu];
549 intf_thread_t * p_intf = [NSApp getIntf];
551 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
552 [[o_mi title] isEqualToString: _NS("Slower")] )
554 if( p_intf->p_sys->p_input != NULL )
556 #define p_input p_intf->p_sys->p_input
557 vlc_mutex_lock( &p_input->stream.stream_lock );
558 bEnabled = p_input->stream.b_pace_control;
559 vlc_mutex_unlock( &p_input->stream.stream_lock );
567 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
569 bEnabled = p_intf->p_sys->p_input != NULL;
571 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
572 [[o_mi title] isEqualToString: _NS("Next")] )
574 playlist_t * p_playlist = vlc_object_find( p_intf,
577 if( p_playlist == NULL )
583 vlc_mutex_lock( &p_playlist->object_lock );
584 bEnabled = p_playlist->i_size > 1;
585 vlc_mutex_unlock( &p_playlist->object_lock );
586 vlc_object_release( p_playlist );
589 else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] )
592 NSArray *o_windows = [NSApp windows];
593 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
596 while ((o_window = [o_enumerator nextObject]))
598 if( [[o_window className] isEqualToString: @"VLCWindow"] )
605 else if( o_menu != nil &&
606 [[o_menu title] isEqualToString: _NS("Deinterlace")] )
608 char * psz_filter = config_GetPsz( p_intf, "filter" );
610 if( psz_filter != NULL )
614 psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
617 if( psz_filter != NULL )
619 if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
621 [o_mi setState: NSOnState];
625 [o_mi setState: NSOffState];
632 [o_mi setState: NSOffState];