1 /*****************************************************************************
2 * controls.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: controls.m,v 1.18 2003/01/29 11:41:48 jlj 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 #include <vlc/input.h>
38 #include <Cocoa/Cocoa.h>
43 /*****************************************************************************
44 * VLCControls interface
45 *****************************************************************************/
46 @interface VLCControls : NSObject
50 IBOutlet id o_mi_mute;
51 IBOutlet id o_volumeslider;
54 - (IBAction)play:(id)sender;
55 - (IBAction)stop:(id)sender;
56 - (IBAction)faster:(id)sender;
57 - (IBAction)slower:(id)sender;
59 - (IBAction)prev:(id)sender;
60 - (IBAction)next:(id)sender;
61 - (IBAction)loop:(id)sender;
63 - (IBAction)volumeUp:(id)sender;
64 - (IBAction)volumeDown:(id)sender;
65 - (IBAction)mute:(id)sender;
66 - (IBAction)volumeSliderUpdate:(id)sender;
67 - (IBAction)fullscreen:(id)sender;
68 - (IBAction)deinterlace:(id)sender;
70 - (IBAction)toggleProgram:(id)sender;
71 - (IBAction)toggleTitle:(id)sender;
72 - (IBAction)toggleChapter:(id)sender;
73 - (IBAction)toggleLanguage:(id)sender;
74 - (IBAction)toggleVar:(id)sender;
76 - (void)setVolumeSlider;
80 /*****************************************************************************
81 * VLCControls implementation
82 *****************************************************************************/
83 @implementation VLCControls
85 - (IBAction)play:(id)sender
87 intf_thread_t * p_intf = [NSApp getIntf];
89 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
91 if( p_playlist == NULL )
96 if( playlist_IsPlaying( p_playlist ) )
98 playlist_Pause( p_playlist );
99 vlc_object_release( p_playlist );
103 if( !playlist_IsEmpty( p_playlist ) )
105 playlist_Play( p_playlist );
106 vlc_object_release( p_playlist );
110 vlc_object_release( p_playlist );
111 [o_open openFile: nil];
116 - (IBAction)stop:(id)sender
118 intf_thread_t * p_intf = [NSApp getIntf];
120 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
122 if( p_playlist == NULL )
127 playlist_Stop( p_playlist );
128 vlc_object_release( p_playlist );
130 p_intf->p_sys->b_stopping = 1;
133 - (IBAction)faster:(id)sender
135 intf_thread_t * p_intf = [NSApp getIntf];
137 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
139 if( p_playlist == NULL )
144 vlc_mutex_lock( &p_playlist->object_lock );
145 if( p_playlist->p_input != NULL )
147 input_SetStatus( p_playlist->p_input, INPUT_STATUS_FASTER );
149 vlc_mutex_unlock( &p_playlist->object_lock );
151 vlc_object_release( p_playlist );
154 - (IBAction)slower:(id)sender
156 intf_thread_t * p_intf = [NSApp getIntf];
158 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
160 if( p_playlist == NULL )
165 vlc_mutex_lock( &p_playlist->object_lock );
166 if( p_playlist->p_input != NULL )
168 input_SetStatus( p_playlist->p_input, INPUT_STATUS_SLOWER );
170 vlc_mutex_unlock( &p_playlist->object_lock );
172 vlc_object_release( p_playlist );
175 - (IBAction)prev:(id)sender
177 intf_thread_t * p_intf = [NSApp getIntf];
179 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
181 if( p_playlist == NULL )
186 vlc_mutex_lock( &p_playlist->object_lock );
188 if( p_playlist->p_input == NULL )
190 vlc_mutex_unlock( &p_playlist->object_lock );
191 vlc_object_release( p_playlist );
195 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
197 #define p_area p_playlist->p_input->stream.p_selected_area
199 if( p_area->i_part_nb > 1 && p_area->i_part > 1 )
203 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
204 input_ChangeArea( p_playlist->p_input, p_area );
205 vlc_mutex_unlock( &p_playlist->object_lock );
207 p_intf->p_sys->b_chapter_update = VLC_TRUE;
211 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
212 vlc_mutex_unlock( &p_playlist->object_lock );
213 playlist_Prev( p_playlist );
218 vlc_object_release( p_playlist );
221 - (IBAction)next:(id)sender
223 intf_thread_t * p_intf = [NSApp getIntf];
225 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
227 if( p_playlist == NULL )
232 vlc_mutex_lock( &p_playlist->object_lock );
234 if( p_playlist->p_input == NULL )
236 vlc_mutex_unlock( &p_playlist->object_lock );
237 vlc_object_release( p_playlist );
241 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
243 #define p_area p_playlist->p_input->stream.p_selected_area
245 if( p_area->i_part_nb > 1 && p_area->i_part + 1 < p_area->i_part_nb )
249 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
250 input_ChangeArea( p_playlist->p_input, p_area );
251 vlc_mutex_unlock( &p_playlist->object_lock );
253 p_intf->p_sys->b_chapter_update = VLC_TRUE;
257 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
258 vlc_mutex_unlock( &p_playlist->object_lock );
259 playlist_Next( p_playlist );
264 vlc_object_release( p_playlist );
267 - (IBAction)loop:(id)sender
269 intf_thread_t * p_intf = [NSApp getIntf];
271 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
273 if( p_playlist == NULL )
278 config_PutInt( p_playlist, "loop",
279 !config_GetInt( p_playlist, "loop" ) );
281 vlc_object_release( p_playlist );
284 - (IBAction)volumeUp:(id)sender
286 intf_thread_t * p_intf = [NSApp getIntf];
287 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
289 if ( p_aout != NULL )
291 if (p_intf->p_sys->b_mute)
293 [self mute:o_mi_mute];
295 aout_VolumeUp( p_aout, 1, NULL );
296 vlc_object_release( (vlc_object_t *)p_aout );
298 [self setVolumeSlider];
301 - (IBAction)volumeDown:(id)sender
303 intf_thread_t * p_intf = [NSApp getIntf];
304 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
306 if ( p_aout != NULL )
308 if (p_intf->p_sys->b_mute)
310 [self mute:o_mi_mute];
312 aout_VolumeDown( p_aout, 1, NULL );
313 vlc_object_release( (vlc_object_t *)p_aout );
315 [self setVolumeSlider];
318 - (IBAction)mute:(id)sender
320 intf_thread_t * p_intf = [NSApp getIntf];
321 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
323 audio_volume_t i_volume;
325 if ( p_aout != NULL )
327 aout_VolumeMute( p_aout, &i_volume );
328 vlc_object_release( (vlc_object_t *)p_aout );
331 p_intf->p_sys->b_mute = (i_volume == 0);
332 [o_mi_mute setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
333 [o_volumeslider setEnabled: p_intf->p_sys->b_mute ? FALSE : TRUE];
334 [self setVolumeSlider];
337 - (IBAction)volumeSliderUpdate:(id)sender
339 intf_thread_t * p_intf = [NSApp getIntf];
340 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
342 audio_volume_t i_volume;
344 if ( p_aout != NULL )
346 i_volume = (int) [sender floatValue];
347 aout_VolumeSet( p_aout, i_volume * AOUT_VOLUME_STEP);
348 vlc_object_release( (vlc_object_t *)p_aout );
352 - (void)setVolumeSlider
354 intf_thread_t * p_intf = [NSApp getIntf];
355 aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
357 audio_volume_t i_volume;
359 if ( p_aout != NULL )
361 aout_VolumeGet( p_aout, &i_volume );
362 vlc_object_release( (vlc_object_t *)p_aout );
363 [o_volumeslider setFloatValue: (float) (i_volume / AOUT_VOLUME_STEP)];
367 [o_volumeslider setFloatValue: config_GetInt( p_intf, "volume" )];
371 - (IBAction)fullscreen:(id)sender
373 id o_window = [NSApp keyWindow];
374 NSArray *o_windows = [NSApp windows];
375 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
377 while ((o_window = [o_enumerator nextObject]))
379 if( [[o_window className] isEqualToString: @"VLCWindow"] )
381 [o_window toggleFullscreen];
386 - (IBAction)deinterlace:(id)sender
388 intf_thread_t * p_intf = [NSApp getIntf];
389 NSMenuItem *o_mi = (NSMenuItem *)sender;
390 NSString *mode = [o_mi title];
394 psz_filter = config_GetPsz( p_intf, "filter" );
396 if( [mode isEqualToString: @"none"] )
398 config_PutPsz( p_intf, "filter", "" );
402 if( !psz_filter || !*psz_filter )
404 config_PutPsz( p_intf, "filter", "deinterlace" );
408 if( strstr( psz_filter, "deinterlace" ) == NULL )
410 psz_filter = realloc( psz_filter, strlen( psz_filter ) + 20 );
411 strcat( psz_filter, ",deinterlace" );
413 config_PutPsz( p_intf, "filter", psz_filter );
420 /* now restart all video stream */
421 if( p_intf->p_sys->p_input )
423 vout_thread_t *p_vout;
424 vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
426 /* Warn the vout we are about to change the filter chain */
427 p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
431 p_vout->b_filter_change = VLC_TRUE;
432 vlc_object_release( p_vout );
435 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
436 for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
438 if( ( ES->i_cat == VIDEO_ES ) &&
439 ES->p_decoder_fifo != NULL )
441 input_UnselectES( p_intf->p_sys->p_input, ES );
442 input_SelectES( p_intf->p_sys->p_input, ES );
446 vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
449 if( ![mode isEqualToString: @"none"] )
451 vout_thread_t *p_vout;
452 p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
458 val.psz_string = (char *)[mode cString];
459 if( var_Set( p_vout, "deinterlace-mode", val ) != VLC_SUCCESS )
460 config_PutPsz( p_intf, "deinterlace-mode", (char *)[mode cString] );
462 vlc_object_release( p_vout );
465 config_PutPsz( p_intf, "deinterlace-mode", (char *)[mode cString] );
470 - (IBAction)toggleProgram:(id)sender
472 NSMenuItem * o_mi = (NSMenuItem *)sender;
473 intf_thread_t * p_intf = [NSApp getIntf];
475 if( [o_mi state] == NSOffState )
477 u16 i_program_id = [o_mi tag];
479 input_ChangeProgram( p_intf->p_sys->p_input, i_program_id );
480 input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
484 - (IBAction)toggleTitle:(id)sender
486 NSMenuItem * o_mi = (NSMenuItem *)sender;
487 intf_thread_t * p_intf = [NSApp getIntf];
489 if( [o_mi state] == NSOffState )
491 int i_title = [o_mi tag];
493 #define p_input p_intf->p_sys->p_input
494 input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
495 input_SetStatus( p_input, INPUT_STATUS_PLAY );
500 - (IBAction)toggleChapter:(id)sender
502 NSMenuItem * o_mi = (NSMenuItem *)sender;
503 intf_thread_t * p_intf = [NSApp getIntf];
505 if( [o_mi state] == NSOffState )
507 int i_chapter = [o_mi tag];
509 #define p_input p_intf->p_sys->p_input
510 p_input->stream.p_selected_area->i_part = i_chapter;
511 input_ChangeArea( p_input, p_input->stream.p_selected_area );
512 input_SetStatus( p_input, INPUT_STATUS_PLAY );
517 - (IBAction)toggleLanguage:(id)sender
519 NSMenuItem * o_mi = (NSMenuItem *)sender;
520 intf_thread_t * p_intf = [NSApp getIntf];
523 /* We do not use this code, because you need to start stop .avi for
524 * it to work, so not very useful now --hartman */
525 if ( [o_mi state] == NSOffState && [o_mi tag] == 2000 )
527 NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
529 [o_open_panel setAllowsMultipleSelection: NO];
530 [o_open_panel setTitle: _NS("Open subtitlefile")];
531 [o_open_panel setPrompt: _NS("Open")];
533 if( [o_open_panel runModalForDirectory: nil
534 file: nil types: nil] == NSOKButton )
536 NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
537 config_PutPsz( p_intf, "sub-file", strdup( [o_filename cString] ));
542 #define p_input p_intf->p_sys->p_input
544 if( !p_intf->p_sys->b_audio_update )
546 NSValue * o_value = [o_mi representedObject];
547 es_descriptor_t * p_es = [o_value pointerValue];
549 if( [o_mi state] == NSOnState )
551 /* we just have one ES to disable */
552 input_ToggleES( p_input, p_es, 0 );
557 int i_cat = [o_mi tag];
559 vlc_mutex_lock( &p_input->stream.stream_lock );
561 #define ES p_input->stream.pp_selected_es[i]
563 /* unselect the selected ES in the same class */
564 for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
566 if( ES->i_cat == i_cat )
568 vlc_mutex_unlock( &p_input->stream.stream_lock );
569 input_ToggleES( p_input, ES, 0 );
570 vlc_mutex_lock( &p_input->stream.stream_lock );
577 vlc_mutex_unlock( &p_input->stream.stream_lock );
579 input_ToggleES( p_input, p_es, 1 );
586 - (IBAction)toggleVar:(id)sender
588 NSMenuItem * o_mi = (NSMenuItem *)sender;
590 if( [o_mi state] == NSOffState )
592 const char * psz_variable = (const char *)[o_mi tag];
593 const char * psz_value = [[o_mi title] cString];
594 vlc_object_t * p_object = (vlc_object_t *)
595 [[o_mi representedObject] pointerValue];
597 /* psz_string sucks */
598 val.psz_string = (char *)psz_value;
600 if ( var_Set( p_object, psz_variable, val ) < 0 )
602 msg_Warn( p_object, "cannot set variable (%s)", psz_value );
609 @implementation VLCControls (NSMenuValidation)
611 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
613 BOOL bEnabled = TRUE;
614 NSMenu * o_menu = [o_mi menu];
615 intf_thread_t * p_intf = [NSApp getIntf];
617 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
620 if( p_playlist != NULL )
622 vlc_mutex_lock( &p_playlist->object_lock );
625 if( [[o_mi title] isEqualToString: _NS("Faster")] ||
626 [[o_mi title] isEqualToString: _NS("Slower")] )
628 if( p_playlist != NULL && p_playlist->p_input != NULL )
630 vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
631 bEnabled = p_playlist->p_input->stream.b_pace_control;
632 vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
639 else if( [[o_mi title] isEqualToString: _NS("Stop")] )
641 if( p_playlist == NULL || p_playlist->p_input == NULL )
646 else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
647 [[o_mi title] isEqualToString: _NS("Next")] )
649 if( p_playlist == NULL )
655 bEnabled = p_playlist->i_size > 1;
658 else if( [[o_mi title] isEqualToString: _NS("Loop")] )
660 int i_state = config_GetInt( p_playlist, "loop" ) ?
661 NSOnState : NSOffState;
663 [o_mi setState: i_state];
665 else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] )
668 NSArray *o_windows = [NSApp windows];
669 NSEnumerator *o_enumerator = [o_windows objectEnumerator];
672 while ((o_window = [o_enumerator nextObject]))
674 if( [[o_window className] isEqualToString: @"VLCWindow"] )
681 else if( o_menu != nil &&
682 [[o_menu title] isEqualToString: _NS("Deinterlace")] )
684 char * psz_filter = config_GetPsz( p_intf, "filter" );
686 if( psz_filter != NULL )
690 psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
693 if( psz_filter != NULL )
695 if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
697 [o_mi setState: NSOnState];
701 [o_mi setState: NSOffState];
708 [o_mi setState: NSOffState];
712 if( p_playlist != NULL )
714 vlc_mutex_unlock( &p_playlist->object_lock );
715 vlc_object_release( p_playlist );