1 /*****************************************************************************
2 * controls.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: controls.m,v 1.24 2003/02/09 01:13:43 massiot 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)volumeUp:(id)sender;
57 - (IBAction)volumeDown:(id)sender;
58 - (IBAction)mute:(id)sender;
59 - (IBAction)volumeSliderUpdated:(id)sender;
60 - (void)updateVolumeSlider;
62 - (IBAction)halfWindow:(id)sender;
63 - (IBAction)normalWindow:(id)sender;
64 - (IBAction)doubleWindow:(id)sender;
65 - (IBAction)fullscreen:(id)sender;
66 - (IBAction)deinterlace:(id)sender;
68 - (IBAction)toggleProgram:(id)sender;
69 - (IBAction)toggleTitle:(id)sender;
70 - (IBAction)toggleChapter:(id)sender;
71 - (IBAction)toggleLanguage:(id)sender;
72 - (IBAction)toggleVar:(id)sender;
76 /*****************************************************************************
77 * VLCControls implementation
78 *****************************************************************************/
79 @implementation VLCControls
81 - (IBAction)play:(id)sender
83 intf_thread_t * p_intf = [NSApp getIntf];
85 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
87 if( p_playlist == NULL )
92 if( playlist_IsPlaying( p_playlist ) )
94 playlist_Pause( p_playlist );
95 vlc_object_release( p_playlist );
99 if( !playlist_IsEmpty( p_playlist ) )
101 playlist_Play( p_playlist );
102 vlc_object_release( p_playlist );
106 vlc_object_release( p_playlist );
107 [o_open openFile: nil];
112 - (IBAction)stop:(id)sender
114 intf_thread_t * p_intf = [NSApp getIntf];
116 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
118 if( p_playlist == NULL )
123 playlist_Stop( p_playlist );
124 vlc_object_release( p_playlist );
127 - (IBAction)faster:(id)sender
129 intf_thread_t * p_intf = [NSApp getIntf];
131 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
133 if( p_playlist == NULL )
138 vlc_mutex_lock( &p_playlist->object_lock );
139 if( p_playlist->p_input != NULL )
141 input_SetStatus( p_playlist->p_input, INPUT_STATUS_FASTER );
143 vlc_mutex_unlock( &p_playlist->object_lock );
145 vlc_object_release( p_playlist );
148 - (IBAction)slower:(id)sender
150 intf_thread_t * p_intf = [NSApp getIntf];
152 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
154 if( p_playlist == NULL )
159 vlc_mutex_lock( &p_playlist->object_lock );
160 if( p_playlist->p_input != NULL )
162 input_SetStatus( p_playlist->p_input, INPUT_STATUS_SLOWER );
164 vlc_mutex_unlock( &p_playlist->object_lock );
166 vlc_object_release( p_playlist );
169 - (IBAction)prev:(id)sender
171 intf_thread_t * p_intf = [NSApp getIntf];
173 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
175 if( p_playlist == NULL )
180 vlc_mutex_lock( &p_playlist->object_lock );
182 if( p_playlist->p_input == NULL )
184 vlc_mutex_unlock( &p_playlist->object_lock );
185 vlc_object_release( p_playlist );
189 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
191 #define p_area p_playlist->p_input->stream.p_selected_area
193 if( p_area->i_part_nb > 1 && p_area->i_part > 1 )
197 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
198 input_ChangeArea( p_playlist->p_input, p_area );
199 vlc_mutex_unlock( &p_playlist->object_lock );
201 p_intf->p_sys->b_chapter_update = VLC_TRUE;
205 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
206 vlc_mutex_unlock( &p_playlist->object_lock );
207 playlist_Prev( p_playlist );
212 vlc_object_release( p_playlist );
215 - (IBAction)next:(id)sender
217 intf_thread_t * p_intf = [NSApp getIntf];
219 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
221 if( p_playlist == NULL )
226 vlc_mutex_lock( &p_playlist->object_lock );
228 if( p_playlist->p_input == NULL )
230 vlc_mutex_unlock( &p_playlist->object_lock );
231 vlc_object_release( p_playlist );
235 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
237 #define p_area p_playlist->p_input->stream.p_selected_area
239 if( p_area->i_part_nb > 1 && p_area->i_part + 1 < p_area->i_part_nb )
243 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
244 input_ChangeArea( p_playlist->p_input, p_area );
245 vlc_mutex_unlock( &p_playlist->object_lock );
247 p_intf->p_sys->b_chapter_update = VLC_TRUE;
251 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
252 vlc_mutex_unlock( &p_playlist->object_lock );
253 playlist_Next( p_playlist );
258 vlc_object_release( p_playlist );
261 - (IBAction)loop:(id)sender
263 intf_thread_t * p_intf = [NSApp getIntf];
265 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
267 if( p_playlist == NULL )
272 config_PutInt( p_playlist, "loop",
273 !config_GetInt( p_playlist, "loop" ) );
275 vlc_object_release( p_playlist );
278 - (IBAction)volumeUp:(id)sender
280 intf_thread_t * p_intf = [NSApp getIntf];
282 aout_VolumeUp( p_intf, 1, NULL );
284 if( p_intf->p_sys->b_mute )
289 [self updateVolumeSlider];
292 - (IBAction)volumeDown:(id)sender
294 intf_thread_t * p_intf = [NSApp getIntf];
296 aout_VolumeDown( p_intf, 1, NULL );
298 if( p_intf->p_sys->b_mute )
303 [self updateVolumeSlider];
306 - (IBAction)mute:(id)sender
308 intf_thread_t * p_intf = [NSApp getIntf];
309 audio_volume_t i_volume;
311 aout_VolumeMute( p_intf, &i_volume );
312 p_intf->p_sys->b_mute = ( i_volume == 0 );
314 [self updateVolumeSlider];
317 - (IBAction)volumeSliderUpdated:(id)sender
319 intf_thread_t * p_intf = [NSApp getIntf];
320 audio_volume_t i_volume = (audio_volume_t)[sender intValue];
322 aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
325 - (void)updateVolumeSlider
327 intf_thread_t * p_intf = [NSApp getIntf];
328 audio_volume_t i_volume;
330 aout_VolumeGet( p_intf, &i_volume );
332 [o_volumeslider setFloatValue: (float)(i_volume / AOUT_VOLUME_STEP)];
335 - (IBAction)halfWindow:(id)sender
337 id o_window = [NSApp keyWindow];
338 NSArray *o_windows = [NSApp windows];
339 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
341 while ((o_window = [o_enumerator nextObject]))
343 if( [[o_window className] isEqualToString: @"VLCWindow"] )
345 [o_window scaleWindowWithFactor: 0.5];
350 - (IBAction)normalWindow:(id)sender
352 id o_window = [NSApp keyWindow];
353 NSArray *o_windows = [NSApp windows];
354 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
356 while ((o_window = [o_enumerator nextObject]))
358 if( [[o_window className] isEqualToString: @"VLCWindow"] )
360 [o_window scaleWindowWithFactor: 1];
365 - (IBAction)doubleWindow:(id)sender
367 id o_window = [NSApp keyWindow];
368 NSArray *o_windows = [NSApp windows];
369 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
371 while ((o_window = [o_enumerator nextObject]))
373 if( [[o_window className] isEqualToString: @"VLCWindow"] )
375 [o_window scaleWindowWithFactor: 2];
381 - (IBAction)fullscreen:(id)sender
383 id o_window = [NSApp keyWindow];
384 NSArray *o_windows = [NSApp windows];
385 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
387 while ((o_window = [o_enumerator nextObject]))
389 if( [[o_window className] isEqualToString: @"VLCWindow"] )
391 [o_window toggleFullscreen];
396 - (IBAction)deinterlace:(id)sender
401 - (IBAction)toggleProgram:(id)sender
403 NSMenuItem * o_mi = (NSMenuItem *)sender;
404 intf_thread_t * p_intf = [NSApp getIntf];
406 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
408 if( p_playlist == NULL )
413 vlc_mutex_lock( &p_playlist->object_lock );
415 if( p_playlist->p_input == NULL )
417 vlc_mutex_unlock( &p_playlist->object_lock );
418 vlc_object_release( p_playlist );
422 if( [o_mi state] == NSOffState )
424 u16 i_program_id = [o_mi tag];
426 input_ChangeProgram( p_playlist->p_input, i_program_id );
427 input_SetStatus( p_playlist->p_input, INPUT_STATUS_PLAY );
430 vlc_mutex_unlock( &p_playlist->object_lock );
431 vlc_object_release( p_playlist );
434 - (IBAction)toggleTitle:(id)sender
436 NSMenuItem * o_mi = (NSMenuItem *)sender;
437 intf_thread_t * p_intf = [NSApp getIntf];
439 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
441 if( p_playlist == NULL )
446 vlc_mutex_lock( &p_playlist->object_lock );
448 if( p_playlist->p_input == NULL )
450 vlc_mutex_unlock( &p_playlist->object_lock );
451 vlc_object_release( p_playlist );
455 if( [o_mi state] == NSOffState )
457 int i_title = [o_mi tag];
459 #define p_input p_playlist->p_input
460 input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
461 input_SetStatus( p_input, INPUT_STATUS_PLAY );
465 vlc_mutex_unlock( &p_playlist->object_lock );
466 vlc_object_release( p_playlist );
469 - (IBAction)toggleChapter:(id)sender
471 NSMenuItem * o_mi = (NSMenuItem *)sender;
472 intf_thread_t * p_intf = [NSApp getIntf];
474 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
476 if( p_playlist == NULL )
481 vlc_mutex_lock( &p_playlist->object_lock );
483 if( p_playlist->p_input == NULL )
485 vlc_mutex_unlock( &p_playlist->object_lock );
486 vlc_object_release( p_playlist );
490 if( [o_mi state] == NSOffState )
492 int i_chapter = [o_mi tag];
494 #define p_input p_playlist->p_input
495 p_input->stream.p_selected_area->i_part = i_chapter;
496 input_ChangeArea( p_input, p_input->stream.p_selected_area );
497 input_SetStatus( p_input, INPUT_STATUS_PLAY );
501 vlc_mutex_unlock( &p_playlist->object_lock );
502 vlc_object_release( p_playlist );
505 - (IBAction)toggleLanguage:(id)sender
507 NSMenuItem * o_mi = (NSMenuItem *)sender;
508 intf_thread_t * p_intf = [NSApp getIntf];
510 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
512 if( p_playlist == NULL )
517 vlc_mutex_lock( &p_playlist->object_lock );
519 if( p_playlist->p_input == NULL )
521 vlc_mutex_unlock( &p_playlist->object_lock );
522 vlc_object_release( p_playlist );
527 /* We do not use this code, because you need to start stop .avi for
528 * it to work, so not very useful now --hartman */
529 if ( [o_mi state] == NSOffState && [o_mi tag] == 2000 )
531 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
533 [o_open_panel setAllowsMultipleSelection: NO];
534 [o_open_panel setTitle: _NS("Open subtitle file")];
535 [o_open_panel setPrompt: _NS("Open")];
537 if( [o_open_panel runModalForDirectory: nil
538 file: nil types: nil] == NSOKButton )
540 NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
541 config_PutPsz( p_intf, "sub-file", strdup( [o_filename cString] ));
546 #define p_input p_playlist->p_input
548 if( !p_intf->p_sys->b_audio_update )
550 NSValue * o_value = [o_mi representedObject];
551 es_descriptor_t * p_es = [o_value pointerValue];
553 if( [o_mi state] == NSOnState )
555 /* we just have one ES to disable */
556 input_ToggleES( p_input, p_es, 0 );
561 int i_cat = [o_mi tag];
563 vlc_mutex_lock( &p_input->stream.stream_lock );
565 #define ES p_input->stream.pp_selected_es[i]
567 /* unselect the selected ES in the same class */
568 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
570 if( ES->i_cat == i_cat )
572 vlc_mutex_unlock( &p_input->stream.stream_lock );
573 input_ToggleES( p_input, ES, 0 );
574 vlc_mutex_lock( &p_input->stream.stream_lock );
581 vlc_mutex_unlock( &p_input->stream.stream_lock );
583 input_ToggleES( p_input, p_es, 1 );
589 vlc_mutex_unlock( &p_playlist->object_lock );
590 vlc_object_release( p_playlist );
593 - (IBAction)toggleVar:(id)sender
595 NSMenuItem * o_mi = (NSMenuItem *)sender;
597 if( [o_mi state] == NSOffState )
599 const char * psz_variable = (const char *)[o_mi tag];
600 char * psz_value = [NSApp delocalizeString: [o_mi title]];
601 vlc_object_t * p_object = (vlc_object_t *)
602 [[o_mi representedObject] pointerValue];
604 /* psz_string sucks */
605 val.psz_string = (char *)psz_value;
607 if ( var_Set( p_object, psz_variable, val ) < 0 )
609 msg_Warn( p_object, "cannot set variable (%s)", psz_value );
618 @implementation VLCControls (NSMenuValidation)
620 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
622 BOOL bEnabled = TRUE;
623 NSMenu * o_menu = [o_mi menu];
624 intf_thread_t * p_intf = [NSApp getIntf];
626 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
629 if( p_playlist != NULL )
631 vlc_mutex_lock( &p_playlist->object_lock );
634 #define p_input p_playlist->p_input
636 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
637 [[o_mi title] isEqualToString: _NS("Slower")] )
639 if( p_playlist != NULL && p_input != NULL )
641 vlc_mutex_lock( &p_input->stream.stream_lock );
642 bEnabled = p_input->stream.b_pace_control;
643 vlc_mutex_unlock( &p_input->stream.stream_lock );
650 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
652 if( p_playlist == NULL || p_input == NULL )
657 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
658 [[o_mi title] isEqualToString: _NS("Next")] )
660 if( p_playlist == NULL )
666 bEnabled = p_playlist->i_size > 1;
668 if( p_input != NULL )
670 vlc_mutex_lock( &p_input->stream.stream_lock );
671 bEnabled |= p_input->stream.p_selected_area->i_part_nb > 1;
672 vlc_mutex_unlock( &p_input->stream.stream_lock );
676 else if( [[o_mi title] isEqualToString: _NS("Loop")] )
678 int i_state = config_GetInt( p_playlist, "loop" ) ?
679 NSOnState : NSOffState;
681 [o_mi setState: i_state];
683 else if( [[o_mi title] isEqualToString: _NS("Mute")] )
685 [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
687 else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
688 [[o_mi title] isEqualToString: _NS("Half Size")] ||
689 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
690 [[o_mi title] isEqualToString: _NS("Double Size")])
693 NSArray *o_windows = [NSApp windows];
694 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
697 while ((o_window = [o_enumerator nextObject]))
699 if( [[o_window className] isEqualToString: @"VLCWindow"] )
706 else if( o_menu != nil &&
707 [[o_menu title] isEqualToString: _NS("Deinterlace")] )
712 if( p_playlist != NULL )
714 vlc_mutex_unlock( &p_playlist->object_lock );
715 vlc_object_release( p_playlist );