1 /*****************************************************************************
2 * controls.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: controls.m,v 1.10 2003/01/22 01:48:06 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)fastForward:(id)sender;
61 - (IBAction)prev:(id)sender;
62 - (IBAction)next:(id)sender;
63 - (IBAction)loop:(id)sender;
65 - (IBAction)volumeUp:(id)sender;
66 - (IBAction)volumeDown:(id)sender;
67 - (IBAction)mute:(id)sender;
68 - (IBAction)volumeSliderUpdate:(id)sender;
69 - (IBAction)fullscreen:(id)sender;
70 - (IBAction)deinterlace:(id)sender;
72 - (IBAction)toggleProgram:(id)sender;
73 - (IBAction)toggleTitle:(id)sender;
74 - (IBAction)toggleChapter:(id)sender;
75 - (IBAction)toggleLanguage:(id)sender;
76 - (IBAction)toggleVar:(id)sender;
78 - (void)setVolumeSlider;
82 /*****************************************************************************
83 * VLCControls implementation
84 *****************************************************************************/
85 @implementation VLCControls
87 - (IBAction)play:(id)sender
89 intf_thread_t * p_intf = [NSApp getIntf];
90 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
92 if( p_playlist == NULL )
97 if ( p_intf->p_sys->p_input != NULL && p_intf->p_sys->p_input->stream.control.i_status != PAUSE_S)
99 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PAUSE );
100 vlc_object_release( p_playlist );
104 /* If the playlist is empty, open a file requester instead */
105 vlc_mutex_lock( &p_playlist->object_lock );
106 if( p_playlist->i_size )
108 vlc_mutex_unlock( &p_playlist->object_lock );
109 playlist_Play( p_playlist );
110 vlc_object_release( p_playlist );
114 vlc_mutex_unlock( &p_playlist->object_lock );
115 vlc_object_release( p_playlist );
117 [o_open openFile: nil];
122 - (IBAction)stop:(id)sender
124 intf_thread_t * p_intf = [NSApp getIntf];
125 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
127 if( p_playlist == NULL )
132 playlist_Stop( p_playlist );
133 vlc_object_release( p_playlist );
134 p_intf->p_sys->b_stopping = 1;
137 - (IBAction)faster:(id)sender
139 intf_thread_t * p_intf = [NSApp getIntf];
141 if( p_intf->p_sys->p_input == NULL )
146 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_FASTER );
149 - (IBAction)slower:(id)sender
151 intf_thread_t * p_intf = [NSApp getIntf];
153 if( p_intf->p_sys->p_input == NULL )
158 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_SLOWER );
161 - (IBAction)fastForward:(id)sender
163 playlist_t * p_playlist = vlc_object_find( [NSApp getIntf], VLC_OBJECT_PLAYLIST,
167 switch( [[NSApp currentEvent] type] )
169 /* A button does not send a NSLeftMouseDown unfortunately.
170 * Therefore we need to count. I know, it is ugly. We could have used
171 * a bool as well, but now we can also accellerate after a certain period.
172 * Currently this method is called every second if the button is pressed.
173 * You can set this value in intf.m (hartman)
180 else if ( i_ff == 5 )
184 else if ( i_ff == 15 )
192 vlc_mutex_lock( &p_playlist->object_lock );
193 if( p_playlist->i_size )
195 vlc_mutex_unlock( &p_playlist->object_lock );
196 playlist_Play( p_playlist );
203 vlc_object_release( p_playlist );
206 - (IBAction)prev:(id)sender
208 intf_thread_t * p_intf = [NSApp getIntf];
209 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
211 if( p_playlist == NULL )
216 playlist_Prev( p_playlist );
217 vlc_object_release( p_playlist );
220 - (IBAction)next:(id)sender
222 intf_thread_t * p_intf = [NSApp getIntf];
223 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
225 if( p_playlist == NULL )
230 playlist_Next( p_playlist );
231 vlc_object_release( p_playlist );
234 - (IBAction)loop:(id)sender
236 NSMenuItem * o_mi = (NSMenuItem *)sender;
237 intf_thread_t * p_intf = [NSApp getIntf];
238 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
240 if( p_playlist == NULL )
245 if( p_intf->p_sys->b_loop )
247 [o_mi setState: NSOffState];
248 config_PutInt( p_playlist, "loop", 0 );
252 [o_mi setState: NSOnState];
253 config_PutInt( p_playlist, "loop", 1 );
256 p_intf->p_sys->b_loop = !p_intf->p_sys->b_loop;
258 vlc_object_release( p_playlist );
261 - (IBAction)volumeUp:(id)sender
263 intf_thread_t * p_intf = [NSApp getIntf];
264 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
266 if ( p_aout != NULL )
268 if (p_intf->p_sys->b_mute)
270 [self mute:o_mi_mute];
272 aout_VolumeUp( p_aout, 1, NULL );
273 vlc_object_release( (vlc_object_t *)p_aout );
275 [self setVolumeSlider];
278 - (IBAction)volumeDown:(id)sender
280 intf_thread_t * p_intf = [NSApp getIntf];
281 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
283 if ( p_aout != NULL )
285 if (p_intf->p_sys->b_mute)
287 [self mute:o_mi_mute];
289 aout_VolumeDown( p_aout, 1, NULL );
290 vlc_object_release( (vlc_object_t *)p_aout );
292 [self setVolumeSlider];
295 - (IBAction)mute:(id)sender
297 intf_thread_t * p_intf = [NSApp getIntf];
298 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
300 audio_volume_t i_volume;
302 if ( p_aout != NULL )
304 aout_VolumeMute( p_aout, &i_volume );
305 vlc_object_release( (vlc_object_t *)p_aout );
308 p_intf->p_sys->b_mute = (i_volume == 0);
309 [o_mi_mute setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
310 [o_volumeslider setEnabled: p_intf->p_sys->b_mute ? FALSE : TRUE];
311 [self setVolumeSlider];
314 - (IBAction)volumeSliderUpdate:(id)sender
316 intf_thread_t * p_intf = [NSApp getIntf];
317 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
319 audio_volume_t i_volume;
321 switch( [[NSApp currentEvent] type] )
323 case NSLeftMouseDragged:
324 if ( p_aout != NULL )
326 i_volume = (int) [sender floatValue];
327 aout_VolumeSet( p_aout, i_volume * AOUT_VOLUME_STEP);
328 vlc_object_release( (vlc_object_t *)p_aout );
333 if ( p_aout != NULL ) vlc_object_release( (vlc_object_t *)p_aout );
338 - (void)setVolumeSlider
340 intf_thread_t * p_intf = [NSApp getIntf];
341 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
343 audio_volume_t i_volume;
345 if ( p_aout != NULL )
347 aout_VolumeGet( p_aout, &i_volume );
348 vlc_object_release( (vlc_object_t *)p_aout );
349 [o_volumeslider setFloatValue: (float) (i_volume / AOUT_VOLUME_STEP)];
353 [o_volumeslider setFloatValue: config_GetInt( p_intf, "volume" )];
357 - (IBAction)fullscreen:(id)sender
359 id o_window = [NSApp keyWindow];
360 NSArray *o_windows = [NSApp windows];
361 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
363 while ((o_window = [o_enumerator nextObject]))
365 if( [[o_window className] isEqualToString: @"VLCWindow"] )
367 [o_window toggleFullscreen];
372 - (IBAction)deinterlace:(id)sender
374 intf_thread_t * p_intf = [NSApp getIntf];
375 BOOL bEnable = [sender state] == NSOffState;
379 config_PutPsz( p_intf, "filter", "deinterlace" );
380 config_PutPsz( p_intf, "deinterlace-mode",
381 [[sender title] lossyCString] );
385 config_PutPsz( p_intf, "filter", NULL );
389 - (IBAction)toggleProgram:(id)sender
391 NSMenuItem * o_mi = (NSMenuItem *)sender;
392 intf_thread_t * p_intf = [NSApp getIntf];
394 if( [o_mi state] == NSOffState )
396 u16 i_program_id = [o_mi tag];
398 input_ChangeProgram( p_intf->p_sys->p_input, i_program_id );
399 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
403 - (IBAction)toggleTitle:(id)sender
405 NSMenuItem * o_mi = (NSMenuItem *)sender;
406 intf_thread_t * p_intf = [NSApp getIntf];
408 if( [o_mi state] == NSOffState )
410 int i_title = [o_mi tag];
412 #define p_input p_intf->p_sys->p_input
413 input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
414 input_SetStatus( p_input, INPUT_STATUS_PLAY );
419 - (IBAction)toggleChapter:(id)sender
421 NSMenuItem * o_mi = (NSMenuItem *)sender;
422 intf_thread_t * p_intf = [NSApp getIntf];
424 if( [o_mi state] == NSOffState )
426 int i_chapter = [o_mi tag];
428 #define p_input p_intf->p_sys->p_input
429 p_input->stream.p_selected_area->i_part = i_chapter;
430 input_ChangeArea( p_input, p_input->stream.p_selected_area );
431 input_SetStatus( p_input, INPUT_STATUS_PLAY );
436 - (IBAction)toggleLanguage:(id)sender
438 NSMenuItem * o_mi = (NSMenuItem *)sender;
439 intf_thread_t * p_intf = [NSApp getIntf];
441 #define p_input p_intf->p_sys->p_input
443 if( !p_intf->p_sys->b_audio_update )
445 NSValue * o_value = [o_mi representedObject];
446 es_descriptor_t * p_es = [o_value pointerValue];
448 if( [o_mi state] == NSOnState )
450 /* we just have one ES to disable */
451 input_ToggleES( p_input, p_es, 0 );
456 int i_cat = [o_mi tag];
458 vlc_mutex_lock( &p_input->stream.stream_lock );
460 #define ES p_input->stream.pp_selected_es[i]
462 /* unselect the selected ES in the same class */
463 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
465 if( ES->i_cat == i_cat )
467 vlc_mutex_unlock( &p_input->stream.stream_lock );
468 input_ToggleES( p_input, ES, 0 );
469 vlc_mutex_lock( &p_input->stream.stream_lock );
476 vlc_mutex_unlock( &p_input->stream.stream_lock );
478 input_ToggleES( p_input, p_es, 1 );
485 - (IBAction)toggleVar:(id)sender
487 NSMenuItem * o_mi = (NSMenuItem *)sender;
489 if( [o_mi state] == NSOffState )
491 const char * psz_variable = (const char *)[o_mi tag];
492 const char * psz_value = [[o_mi title] cString];
493 vlc_object_t * p_object = (vlc_object_t *)
494 [[o_mi representedObject] pointerValue];
496 /* psz_string sucks */
497 val.psz_string = (char *)psz_value;
499 if ( var_Set( p_object, psz_variable, val ) < 0 )
501 msg_Warn( p_object, "cannot set variable (%s)", psz_value );
508 @implementation VLCControls (NSMenuValidation)
510 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
512 BOOL bEnabled = TRUE;
513 NSMenu * o_menu = [o_mi menu];
514 intf_thread_t * p_intf = [NSApp getIntf];
516 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
517 [[o_mi title] isEqualToString: _NS("Slower")] )
519 if( p_intf->p_sys->p_input != NULL )
521 #define p_input p_intf->p_sys->p_input
522 vlc_mutex_lock( &p_input->stream.stream_lock );
523 bEnabled = p_input->stream.b_pace_control;
524 vlc_mutex_unlock( &p_input->stream.stream_lock );
532 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
534 bEnabled = p_intf->p_sys->p_input != NULL;
536 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
537 [[o_mi title] isEqualToString: _NS("Next")] )
539 playlist_t * p_playlist = vlc_object_find( p_intf,
542 if( p_playlist == NULL )
548 vlc_mutex_lock( &p_playlist->object_lock );
549 bEnabled = p_playlist->i_size > 1;
550 vlc_mutex_unlock( &p_playlist->object_lock );
551 vlc_object_release( p_playlist );
554 else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] )
557 NSArray *o_windows = [NSApp windows];
558 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
561 while ((o_window = [o_enumerator nextObject]))
563 if( [[o_window className] isEqualToString: @"VLCWindow"] )
570 else if( o_menu != nil &&
571 [[o_menu title] isEqualToString: _NS("Deinterlace")] )
573 char * psz_filter = config_GetPsz( p_intf, "filter" );
575 if( psz_filter != NULL )
579 psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
582 if( psz_filter != NULL )
584 if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
586 [o_mi setState: NSOnState];
590 [o_mi setState: NSOffState];
597 [o_mi setState: NSOffState];