1 /*****************************************************************************
2 * controls.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002-2003 VideoLAN
5 * $Id: controls.m,v 1.35 2003/05/05 22:04:11 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 */
38 /*****************************************************************************
39 * VLCControls implementation
40 *****************************************************************************/
41 @implementation VLCControls
43 - (IBAction)play:(id)sender
45 intf_thread_t * p_intf = [NSApp getIntf];
47 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
49 if( p_playlist == NULL )
54 if( playlist_IsPlaying( p_playlist ) )
56 playlist_Pause( p_playlist );
57 vlc_object_release( p_playlist );
61 if( !playlist_IsEmpty( p_playlist ) )
63 playlist_Play( p_playlist );
64 vlc_object_release( p_playlist );
68 vlc_object_release( p_playlist );
69 [o_open openFileGeneric: nil];
74 - (IBAction)stop:(id)sender
76 intf_thread_t * p_intf = [NSApp getIntf];
78 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
80 if( p_playlist == NULL )
85 playlist_Stop( p_playlist );
86 vlc_object_release( p_playlist );
89 - (IBAction)faster:(id)sender
91 intf_thread_t * p_intf = [NSApp getIntf];
93 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
95 if( p_playlist == NULL )
100 vlc_mutex_lock( &p_playlist->object_lock );
101 if( p_playlist->p_input != NULL )
103 input_SetStatus( p_playlist->p_input, INPUT_STATUS_FASTER );
105 vlc_mutex_unlock( &p_playlist->object_lock );
107 vlc_object_release( p_playlist );
110 - (IBAction)slower:(id)sender
112 intf_thread_t * p_intf = [NSApp getIntf];
114 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
116 if( p_playlist == NULL )
121 vlc_mutex_lock( &p_playlist->object_lock );
122 if( p_playlist->p_input != NULL )
124 input_SetStatus( p_playlist->p_input, INPUT_STATUS_SLOWER );
126 vlc_mutex_unlock( &p_playlist->object_lock );
128 vlc_object_release( p_playlist );
131 - (IBAction)prev:(id)sender
133 intf_thread_t * p_intf = [NSApp getIntf];
135 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
137 if( p_playlist == NULL )
142 vlc_mutex_lock( &p_playlist->object_lock );
144 if( p_playlist->p_input == NULL )
146 vlc_mutex_unlock( &p_playlist->object_lock );
147 vlc_object_release( p_playlist );
151 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
153 #define p_area p_playlist->p_input->stream.p_selected_area
155 if( p_area->i_part_nb > 1 && p_area->i_part > 1 )
159 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
160 input_ChangeArea( p_playlist->p_input, p_area );
161 vlc_mutex_unlock( &p_playlist->object_lock );
163 p_intf->p_sys->b_chapter_update = VLC_TRUE;
167 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
168 vlc_mutex_unlock( &p_playlist->object_lock );
169 playlist_Prev( p_playlist );
174 vlc_object_release( p_playlist );
177 - (IBAction)next:(id)sender
179 intf_thread_t * p_intf = [NSApp getIntf];
181 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
183 if( p_playlist == NULL )
188 vlc_mutex_lock( &p_playlist->object_lock );
190 if( p_playlist->p_input == NULL )
192 vlc_mutex_unlock( &p_playlist->object_lock );
193 vlc_object_release( p_playlist );
197 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
199 #define p_area p_playlist->p_input->stream.p_selected_area
201 if( p_area->i_part_nb > 1 && p_area->i_part + 1 < p_area->i_part_nb )
205 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
206 input_ChangeArea( p_playlist->p_input, p_area );
207 vlc_mutex_unlock( &p_playlist->object_lock );
209 p_intf->p_sys->b_chapter_update = VLC_TRUE;
213 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
214 vlc_mutex_unlock( &p_playlist->object_lock );
215 playlist_Next( p_playlist );
220 vlc_object_release( p_playlist );
223 - (IBAction)loop:(id)sender
225 intf_thread_t * p_intf = [NSApp getIntf];
227 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
229 if( p_playlist == NULL )
234 config_PutInt( p_playlist, "loop",
235 !config_GetInt( p_playlist, "loop" ) );
237 vlc_object_release( p_playlist );
240 - (IBAction)forward:(id)sender
242 intf_thread_t * p_intf = [NSApp getIntf];
243 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
245 if( p_playlist == NULL || p_playlist->p_input == NULL )
247 if ( p_playlist != NULL ) vlc_object_release( p_playlist );
251 input_Seek( p_playlist->p_input, 5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
252 vlc_object_release( p_playlist );
255 - (IBAction)backward:(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 || p_playlist->p_input == NULL )
262 if ( p_playlist != NULL ) vlc_object_release( p_playlist );
266 input_Seek( p_playlist->p_input, -5, INPUT_SEEK_SECONDS | INPUT_SEEK_CUR );
267 vlc_object_release( p_playlist );
270 - (IBAction)volumeUp:(id)sender
272 intf_thread_t * p_intf = [NSApp getIntf];
274 if( p_intf->p_sys->b_mute )
279 aout_VolumeUp( p_intf, 1, NULL );
281 [self updateVolumeSlider];
284 - (IBAction)volumeDown:(id)sender
286 intf_thread_t * p_intf = [NSApp getIntf];
288 if( p_intf->p_sys->b_mute )
293 aout_VolumeDown( p_intf, 1, NULL );
295 [self updateVolumeSlider];
298 - (IBAction)mute:(id)sender
300 intf_thread_t * p_intf = [NSApp getIntf];
301 audio_volume_t i_volume;
303 aout_VolumeMute( p_intf, &i_volume );
304 p_intf->p_sys->b_mute = ( i_volume == 0 );
306 [self updateVolumeSlider];
309 - (IBAction)volumeSliderUpdated:(id)sender
311 intf_thread_t * p_intf = [NSApp getIntf];
312 audio_volume_t i_volume = (audio_volume_t)[sender intValue];
314 aout_VolumeSet( p_intf, i_volume * AOUT_VOLUME_STEP );
317 - (void)updateVolumeSlider
319 intf_thread_t * p_intf = [NSApp getIntf];
320 audio_volume_t i_volume;
322 aout_VolumeGet( p_intf, &i_volume );
324 [o_volumeslider setFloatValue: (float)(i_volume / AOUT_VOLUME_STEP)];
327 - (IBAction)halfWindow:(id)sender
329 id o_window = [NSApp keyWindow];
330 NSArray *o_windows = [NSApp windows];
331 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
333 while ((o_window = [o_enumerator nextObject]))
335 if( [[o_window className] isEqualToString: @"VLCWindow"] )
337 [o_window scaleWindowWithFactor: 0.5];
342 - (IBAction)normalWindow:(id)sender
344 id o_window = [NSApp keyWindow];
345 NSArray *o_windows = [NSApp windows];
346 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
348 while ((o_window = [o_enumerator nextObject]))
350 if( [[o_window className] isEqualToString: @"VLCWindow"] )
352 [o_window scaleWindowWithFactor: 1];
357 - (IBAction)doubleWindow:(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 scaleWindowWithFactor: 2];
373 - (IBAction)fullscreen:(id)sender
375 id o_window = [NSApp keyWindow];
376 NSArray *o_windows = [NSApp windows];
377 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
379 while ((o_window = [o_enumerator nextObject]))
381 if( [[o_window className] isEqualToString: @"VLCWindow"] )
383 [o_window toggleFullscreen];
388 - (IBAction)floatOnTop:(id)sender
390 id o_window = [NSApp keyWindow];
391 NSArray *o_windows = [NSApp windows];
392 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
394 while ((o_window = [o_enumerator nextObject]))
396 if( [[o_window className] isEqualToString: @"VLCWindow"] )
398 [o_window toggleFloatOnTop];
403 - (IBAction)deinterlace:(id)sender
405 intf_thread_t * p_intf = [NSApp getIntf];
406 BOOL bEnable = [sender state] == NSOffState;
408 if( bEnable && ![[sender title] isEqualToString: @"none"] )
410 config_PutPsz( p_intf, "filter", "deinterlace" );
411 config_PutPsz( p_intf, "deinterlace-mode",
412 [[sender title] lossyCString] );
416 config_PutPsz( p_intf, "filter", NULL );
420 - (IBAction)toggleProgram:(id)sender
422 NSMenuItem * o_mi = (NSMenuItem *)sender;
423 intf_thread_t * p_intf = [NSApp getIntf];
425 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
427 if( p_playlist == NULL )
432 vlc_mutex_lock( &p_playlist->object_lock );
434 if( p_playlist->p_input == NULL )
436 vlc_mutex_unlock( &p_playlist->object_lock );
437 vlc_object_release( p_playlist );
441 if( [o_mi state] == NSOffState )
443 u16 i_program_id = [o_mi tag];
445 input_ChangeProgram( p_playlist->p_input, i_program_id );
446 input_SetStatus( p_playlist->p_input, INPUT_STATUS_PLAY );
449 vlc_mutex_unlock( &p_playlist->object_lock );
450 vlc_object_release( p_playlist );
453 - (IBAction)toggleTitle:(id)sender
455 NSMenuItem * o_mi = (NSMenuItem *)sender;
456 intf_thread_t * p_intf = [NSApp getIntf];
458 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
460 if( p_playlist == NULL )
465 vlc_mutex_lock( &p_playlist->object_lock );
467 if( p_playlist->p_input == NULL )
469 vlc_mutex_unlock( &p_playlist->object_lock );
470 vlc_object_release( p_playlist );
474 if( [o_mi state] == NSOffState )
476 int i_title = [o_mi tag];
478 #define p_input p_playlist->p_input
479 input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
480 input_SetStatus( p_input, INPUT_STATUS_PLAY );
484 vlc_mutex_unlock( &p_playlist->object_lock );
485 vlc_object_release( p_playlist );
488 - (IBAction)toggleChapter:(id)sender
490 NSMenuItem * o_mi = (NSMenuItem *)sender;
491 intf_thread_t * p_intf = [NSApp getIntf];
493 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
495 if( p_playlist == NULL )
500 vlc_mutex_lock( &p_playlist->object_lock );
502 if( p_playlist->p_input == NULL )
504 vlc_mutex_unlock( &p_playlist->object_lock );
505 vlc_object_release( p_playlist );
509 if( [o_mi state] == NSOffState )
511 int i_chapter = [o_mi tag];
513 #define p_input p_playlist->p_input
514 p_input->stream.p_selected_area->i_part = i_chapter;
515 input_ChangeArea( p_input, p_input->stream.p_selected_area );
516 input_SetStatus( p_input, INPUT_STATUS_PLAY );
520 vlc_mutex_unlock( &p_playlist->object_lock );
521 vlc_object_release( p_playlist );
524 - (IBAction)toggleLanguage:(id)sender
526 NSMenuItem * o_mi = (NSMenuItem *)sender;
527 intf_thread_t * p_intf = [NSApp getIntf];
529 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
531 if( p_playlist == NULL )
536 vlc_mutex_lock( &p_playlist->object_lock );
538 if( p_playlist->p_input == NULL )
540 vlc_mutex_unlock( &p_playlist->object_lock );
541 vlc_object_release( p_playlist );
546 /* We do not use this code, because you need to start stop .avi for
547 * it to work, so not very useful now --hartman */
548 if ( [o_mi state] == NSOffState && [o_mi tag] == 2000 )
550 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
552 [o_open_panel setAllowsMultipleSelection: NO];
553 [o_open_panel setTitle: _NS("Open subtitle file")];
554 [o_open_panel setPrompt: _NS("Open")];
556 if( [o_open_panel runModalForDirectory: nil
557 file: nil types: nil] == NSOKButton )
559 NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
560 config_PutPsz( p_intf, "sub-file", strdup( [o_filename cString] ));
565 #define p_input p_playlist->p_input
567 if( !p_intf->p_sys->b_audio_update )
569 NSValue * o_value = [o_mi representedObject];
570 es_descriptor_t * p_es = [o_value pointerValue];
572 if( [o_mi state] == NSOnState )
574 /* we just have one ES to disable */
575 input_ToggleES( p_input, p_es, 0 );
580 int i_cat = [o_mi tag];
582 vlc_mutex_lock( &p_input->stream.stream_lock );
584 #define ES p_input->stream.pp_selected_es[i]
586 /* unselect the selected ES in the same class */
587 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
589 if( ES->i_cat == i_cat )
591 vlc_mutex_unlock( &p_input->stream.stream_lock );
592 input_ToggleES( p_input, ES, 0 );
593 vlc_mutex_lock( &p_input->stream.stream_lock );
600 vlc_mutex_unlock( &p_input->stream.stream_lock );
602 input_ToggleES( p_input, p_es, 1 );
608 vlc_mutex_unlock( &p_playlist->object_lock );
609 vlc_object_release( p_playlist );
612 - (IBAction)toggleVar:(id)sender
614 NSMenuItem *o_mi = (NSMenuItem *)sender;
615 NSMenu *o_mu = [o_mi menu];
617 if( [o_mi state] == NSOffState )
619 const char * psz_variable = (const char *)
620 [[[o_mu supermenu] itemWithTitle: [o_mu title]] tag];
621 vlc_object_t * p_object = (vlc_object_t *)
622 [[o_mi representedObject] pointerValue];
624 val.i_int = (int)[o_mi tag];
626 if ( var_Set( p_object, psz_variable, val ) < 0 )
628 msg_Warn( p_object, "cannot set variable %s: with %d", psz_variable, val.i_int );
630 if (psz_variable) free(psz_variable);
636 @implementation VLCControls (NSMenuValidation)
638 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
640 BOOL bEnabled = TRUE;
641 NSMenu * o_menu = [o_mi menu];
642 intf_thread_t * p_intf = [NSApp getIntf];
644 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
647 if( p_playlist != NULL )
649 vlc_mutex_lock( &p_playlist->object_lock );
652 #define p_input p_playlist->p_input
654 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
655 [[o_mi title] isEqualToString: _NS("Slower")] )
657 if( p_playlist != NULL && p_input != NULL )
659 vlc_mutex_lock( &p_input->stream.stream_lock );
660 bEnabled = p_input->stream.b_pace_control;
661 vlc_mutex_unlock( &p_input->stream.stream_lock );
668 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
670 if( p_playlist == NULL || p_input == NULL )
675 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
676 [[o_mi title] isEqualToString: _NS("Next")] )
678 if( p_playlist == NULL )
684 bEnabled = p_playlist->i_size > 1;
686 if( p_input != NULL )
688 vlc_mutex_lock( &p_input->stream.stream_lock );
689 bEnabled |= p_input->stream.p_selected_area->i_part_nb > 1;
690 vlc_mutex_unlock( &p_input->stream.stream_lock );
694 else if( [[o_mi title] isEqualToString: _NS("Loop")] )
696 int i_state = config_GetInt( p_playlist, "loop" ) ?
697 NSOnState : NSOffState;
699 [o_mi setState: i_state];
701 else if( [[o_mi title] isEqualToString: _NS("Step Forward")] ||
702 [[o_mi title] isEqualToString: _NS("Step Backward")] )
704 if( p_playlist != NULL && p_input != NULL )
706 vlc_mutex_lock( &p_input->stream.stream_lock );
707 bEnabled = p_input->stream.b_seekable;
708 vlc_mutex_unlock( &p_input->stream.stream_lock );
715 else if( [[o_mi title] isEqualToString: _NS("Mute")] )
717 [o_mi setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
719 else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] ||
720 [[o_mi title] isEqualToString: _NS("Half Size")] ||
721 [[o_mi title] isEqualToString: _NS("Normal Size")] ||
722 [[o_mi title] isEqualToString: _NS("Double Size")] ||
723 [[o_mi title] isEqualToString: _NS("Float On Top")] )
726 NSArray *o_windows = [NSApp windows];
727 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
730 if ( [[o_mi title] isEqualToString: _NS("Float On Top")] )
732 int i_state = config_GetInt( p_playlist, "macosx-float" ) ?
733 NSOnState : NSOffState;
734 [o_mi setState: i_state];
737 while ((o_window = [o_enumerator nextObject]))
739 if( [[o_window className] isEqualToString: @"VLCWindow"] )
746 else if( [[o_mi title] isEqualToString: _NS("Float On Top")] )
751 else if( o_menu != nil &&
752 [[o_menu title] isEqualToString: _NS("Deinterlace")] )
754 char * psz_filter = config_GetPsz( p_intf, "filter" );
756 if( psz_filter != NULL )
760 psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
763 if( psz_filter != NULL )
765 if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
767 [o_mi setState: NSOnState];
771 [o_mi setState: NSOffState];
778 if( [[o_mi title] isEqualToString: @"none"] )
780 [o_mi setState: NSOnState];
784 [o_mi setState: NSOffState];
789 if( p_playlist != NULL )
791 vlc_mutex_unlock( &p_playlist->object_lock );
792 vlc_object_release( p_playlist );