]> git.sesse.net Git - vlc/blob - modules/gui/macosx/controls.m
ffaab6cd61e12d7586163e0667b68505dc7d4aef
[vlc] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface plugin
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: controls.m,v 1.17 2003/01/29 11:34:11 jlj Exp $
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <thedj@users.sourceforge.net>
10  *
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.
15  * 
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.
20  *
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  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <sys/param.h>                                    /* for MAXPATHLEN */
31 #include <string.h>
32
33 #include <vlc/vlc.h>
34 #include <vlc/intf.h>
35 #include <vlc/aout.h>
36 #include <vlc/input.h>
37
38 #include <Cocoa/Cocoa.h> 
39
40 #include "intf.h"
41 #include "vout.h"
42
43 /*****************************************************************************
44  * VLCControls interface 
45  *****************************************************************************/
46 @interface VLCControls : NSObject
47 {
48     IBOutlet id o_open;
49     IBOutlet id o_main;
50     IBOutlet id o_mi_mute;
51     IBOutlet id o_volumeslider;
52 }
53
54 - (IBAction)play:(id)sender;
55 - (IBAction)stop:(id)sender;
56 - (IBAction)faster:(id)sender;
57 - (IBAction)slower:(id)sender;
58
59 - (IBAction)prev:(id)sender;
60 - (IBAction)next:(id)sender;
61 - (IBAction)loop:(id)sender;
62
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;
69
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;
75
76 - (void)setVolumeSlider;
77
78 @end
79
80 /*****************************************************************************
81  * VLCControls implementation 
82  *****************************************************************************/
83 @implementation VLCControls
84
85 - (IBAction)play:(id)sender
86 {
87     intf_thread_t * p_intf = [NSApp getIntf];
88
89     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
90                                                        FIND_ANYWHERE );
91     if( p_playlist == NULL )
92     {
93         return;
94     }
95
96     if( playlist_IsPlaying( p_playlist ) )
97     {
98         playlist_Pause( p_playlist );
99         vlc_object_release( p_playlist );
100     }
101     else
102     {
103         vlc_bool_t b_empty;
104
105         b_empty = playlist_IsEmpty( p_playlist );
106         vlc_object_release( p_playlist );
107
108         if( !b_empty )
109         {
110             playlist_Play( p_playlist );
111         }
112         else
113         {
114             [o_open openFile: nil];
115         }
116     }
117 }
118
119 - (IBAction)stop:(id)sender
120 {
121     intf_thread_t * p_intf = [NSApp getIntf];
122
123     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
124                                                        FIND_ANYWHERE );
125     if( p_playlist == NULL )
126     {
127         return;
128     }
129
130     playlist_Stop( p_playlist );
131     vlc_object_release( p_playlist );
132
133     p_intf->p_sys->b_stopping = 1;
134 }
135
136 - (IBAction)faster:(id)sender
137 {
138     intf_thread_t * p_intf = [NSApp getIntf];
139
140     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
141                                                        FIND_ANYWHERE );
142     if( p_playlist == NULL )
143     {
144         return;
145     }
146
147     vlc_mutex_lock( &p_playlist->object_lock );
148     if( p_playlist->p_input != NULL )
149     {
150         input_SetStatus( p_playlist->p_input, INPUT_STATUS_FASTER );
151     } 
152     vlc_mutex_unlock( &p_playlist->object_lock );
153
154     vlc_object_release( p_playlist );
155 }
156
157 - (IBAction)slower:(id)sender
158 {
159     intf_thread_t * p_intf = [NSApp getIntf];
160
161     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
162                                                        FIND_ANYWHERE );
163     if( p_playlist == NULL )
164     {
165         return;
166     }
167
168     vlc_mutex_lock( &p_playlist->object_lock );
169     if( p_playlist->p_input != NULL )
170     {
171         input_SetStatus( p_playlist->p_input, INPUT_STATUS_SLOWER );
172     }
173     vlc_mutex_unlock( &p_playlist->object_lock );
174
175     vlc_object_release( p_playlist );
176 }
177
178 - (IBAction)prev:(id)sender
179 {
180     intf_thread_t * p_intf = [NSApp getIntf];
181
182     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
183                                                        FIND_ANYWHERE );
184     if( p_playlist == NULL )
185     {
186         return;
187     }
188
189     vlc_mutex_lock( &p_playlist->object_lock );
190
191     if( p_playlist->p_input == NULL )
192     {
193         vlc_mutex_unlock( &p_playlist->object_lock );
194         vlc_object_release( p_playlist );  
195         return;
196     }
197
198     vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
199
200 #define p_area p_playlist->p_input->stream.p_selected_area
201
202     if( p_area->i_part_nb > 1 && p_area->i_part > 1 )
203     {
204         p_area->i_part--;
205
206         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
207         input_ChangeArea( p_playlist->p_input, p_area );
208         vlc_mutex_unlock( &p_playlist->object_lock );
209
210         p_intf->p_sys->b_chapter_update = VLC_TRUE;
211     }
212     else
213     {
214         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
215         vlc_mutex_unlock( &p_playlist->object_lock );
216         playlist_Prev( p_playlist );
217     }
218
219 #undef p_area
220
221     vlc_object_release( p_playlist );
222 }
223
224 - (IBAction)next:(id)sender
225 {
226     intf_thread_t * p_intf = [NSApp getIntf];
227
228     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
229                                                        FIND_ANYWHERE );
230     if( p_playlist == NULL )
231     {
232         return;
233     }
234
235     vlc_mutex_lock( &p_playlist->object_lock );
236
237     if( p_playlist->p_input == NULL )
238     {
239         vlc_mutex_unlock( &p_playlist->object_lock );
240         vlc_object_release( p_playlist );  
241         return;
242     }
243
244     vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
245
246 #define p_area p_playlist->p_input->stream.p_selected_area
247
248     if( p_area->i_part_nb > 1 && p_area->i_part + 1 < p_area->i_part_nb )
249     {
250         p_area->i_part++;
251
252         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
253         input_ChangeArea( p_playlist->p_input, p_area );
254         vlc_mutex_unlock( &p_playlist->object_lock );
255
256         p_intf->p_sys->b_chapter_update = VLC_TRUE;
257     }
258     else
259     {
260         vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
261         vlc_mutex_unlock( &p_playlist->object_lock );
262         playlist_Next( p_playlist );
263     }
264
265 #undef p_area
266
267     vlc_object_release( p_playlist );
268 }
269
270 - (IBAction)loop:(id)sender
271 {
272     intf_thread_t * p_intf = [NSApp getIntf];
273
274     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
275                                                        FIND_ANYWHERE );
276     if( p_playlist == NULL )
277     {
278         return;
279     }
280
281     config_PutInt( p_playlist, "loop",
282                    !config_GetInt( p_playlist, "loop" ) );
283
284     vlc_object_release( p_playlist );
285 }
286
287 - (IBAction)volumeUp:(id)sender
288 {
289     intf_thread_t * p_intf = [NSApp getIntf];
290     aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
291                                                 FIND_ANYWHERE );
292     if ( p_aout != NULL )
293     {
294         if (p_intf->p_sys->b_mute)
295         {
296             [self mute:o_mi_mute];
297         }
298         aout_VolumeUp( p_aout, 1, NULL );
299         vlc_object_release( (vlc_object_t *)p_aout );
300     }
301     [self setVolumeSlider];
302 }
303
304 - (IBAction)volumeDown:(id)sender
305 {
306     intf_thread_t * p_intf = [NSApp getIntf];
307     aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
308                                                 FIND_ANYWHERE );
309     if ( p_aout != NULL )
310     {
311         if (p_intf->p_sys->b_mute)
312         {
313             [self mute:o_mi_mute];
314         }
315         aout_VolumeDown( p_aout, 1, NULL );
316         vlc_object_release( (vlc_object_t *)p_aout );
317     }
318     [self setVolumeSlider];
319 }
320
321 - (IBAction)mute:(id)sender
322 {
323     intf_thread_t * p_intf = [NSApp getIntf];
324     aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
325                                                 FIND_ANYWHERE );
326     audio_volume_t i_volume;
327
328     if ( p_aout != NULL )
329     {
330         aout_VolumeMute( p_aout, &i_volume );
331         vlc_object_release( (vlc_object_t *)p_aout );
332     }
333
334     p_intf->p_sys->b_mute = (i_volume == 0);
335     [o_mi_mute setState: p_intf->p_sys->b_mute ? NSOnState : NSOffState];
336     [o_volumeslider setEnabled: p_intf->p_sys->b_mute ? FALSE : TRUE];
337     [self setVolumeSlider];
338 }
339
340 - (IBAction)volumeSliderUpdate:(id)sender
341 {
342     intf_thread_t * p_intf = [NSApp getIntf];
343     aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
344                                                 FIND_ANYWHERE );
345     audio_volume_t i_volume;
346
347     if ( p_aout != NULL )
348     {
349         i_volume = (int) [sender floatValue];
350         aout_VolumeSet( p_aout, i_volume * AOUT_VOLUME_STEP);
351         vlc_object_release( (vlc_object_t *)p_aout );
352     }
353 }
354
355 - (void)setVolumeSlider
356 {
357     intf_thread_t * p_intf = [NSApp getIntf];
358     aout_instance_t * p_aout = vlc_object_find( p_intf, VLC_OBJECT_AOUT,
359                                                 FIND_ANYWHERE );
360     audio_volume_t i_volume;
361     
362     if ( p_aout != NULL )
363     {
364         aout_VolumeGet( p_aout, &i_volume );
365         vlc_object_release( (vlc_object_t *)p_aout );
366         [o_volumeslider setFloatValue: (float) (i_volume / AOUT_VOLUME_STEP)]; 
367     }
368     else
369     {
370         [o_volumeslider setFloatValue: config_GetInt( p_intf, "volume" )];
371     }
372 }
373
374 - (IBAction)fullscreen:(id)sender
375 {
376     id o_window = [NSApp keyWindow];
377     NSArray *o_windows = [NSApp windows];
378     NSEnumerator *o_enumerator = [o_windows objectEnumerator];
379     
380     while ((o_window = [o_enumerator nextObject]))
381     {
382         if( [[o_window className] isEqualToString: @"VLCWindow"] )
383         {
384             [o_window toggleFullscreen];
385         }
386     }
387 }
388
389 - (IBAction)deinterlace:(id)sender
390 {
391     intf_thread_t * p_intf = [NSApp getIntf];
392     NSMenuItem *o_mi = (NSMenuItem *)sender;
393     NSString *mode = [o_mi title];
394     char *psz_filter;
395     unsigned int  i;
396
397     psz_filter = config_GetPsz( p_intf, "filter" );
398
399     if( [mode isEqualToString: @"none"] )
400     {
401         config_PutPsz( p_intf, "filter", "" );
402     }
403     else
404     {
405         if( !psz_filter || !*psz_filter )
406         {
407             config_PutPsz( p_intf, "filter", "deinterlace" );
408         }
409         else
410         {
411             if( strstr( psz_filter, "deinterlace" ) == NULL )
412             {
413                 psz_filter = realloc( psz_filter, strlen( psz_filter ) + 20 );
414                 strcat( psz_filter, ",deinterlace" );
415             }
416             config_PutPsz( p_intf, "filter", psz_filter );
417         }
418     }
419
420     if( psz_filter )
421         free( psz_filter );
422
423     /* now restart all video stream */
424     if( p_intf->p_sys->p_input )
425     {
426         vout_thread_t *p_vout;
427         vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
428
429         /* Warn the vout we are about to change the filter chain */
430         p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
431                                   FIND_ANYWHERE );
432         if( p_vout )
433         {
434             p_vout->b_filter_change = VLC_TRUE;
435             vlc_object_release( p_vout );
436         }
437
438 #define ES p_intf->p_sys->p_input->stream.pp_es[i]
439         for( i = 0 ; i < p_intf->p_sys->p_input->stream.i_es_number ; i++ )
440         {
441             if( ( ES->i_cat == VIDEO_ES ) &&
442                     ES->p_decoder_fifo != NULL )
443             {
444                 input_UnselectES( p_intf->p_sys->p_input, ES );
445                 input_SelectES( p_intf->p_sys->p_input, ES );
446             }
447 #undef ES
448         }
449         vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
450     }
451
452     if( ![mode isEqualToString: @"none"] )
453     {
454         vout_thread_t *p_vout;
455         p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT,
456                                   FIND_ANYWHERE );
457         if( p_vout )
458         {
459             vlc_value_t val;
460
461             val.psz_string = (char *)[mode cString];
462             if( var_Set( p_vout, "deinterlace-mode", val ) != VLC_SUCCESS )
463                 config_PutPsz( p_intf, "deinterlace-mode", (char *)[mode cString] );
464
465             vlc_object_release( p_vout );
466         }
467         else {
468             config_PutPsz( p_intf, "deinterlace-mode", (char *)[mode cString] );
469         }
470     }
471 }
472
473 - (IBAction)toggleProgram:(id)sender
474 {
475     NSMenuItem * o_mi = (NSMenuItem *)sender;
476     intf_thread_t * p_intf = [NSApp getIntf];
477
478     if( [o_mi state] == NSOffState )
479     {
480         u16 i_program_id = [o_mi tag];
481
482         input_ChangeProgram( p_intf->p_sys->p_input, i_program_id );
483         input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
484     }
485 }
486
487 - (IBAction)toggleTitle:(id)sender
488 {
489     NSMenuItem * o_mi = (NSMenuItem *)sender;
490     intf_thread_t * p_intf = [NSApp getIntf];
491
492     if( [o_mi state] == NSOffState )
493     {
494         int i_title = [o_mi tag];
495
496 #define p_input p_intf->p_sys->p_input
497         input_ChangeArea( p_input, p_input->stream.pp_areas[i_title] );
498         input_SetStatus( p_input, INPUT_STATUS_PLAY );
499 #undef p_input
500     }
501 }
502
503 - (IBAction)toggleChapter:(id)sender
504 {
505     NSMenuItem * o_mi = (NSMenuItem *)sender;
506     intf_thread_t * p_intf = [NSApp getIntf];
507
508     if( [o_mi state] == NSOffState )
509     {
510         int i_chapter = [o_mi tag];
511
512 #define p_input p_intf->p_sys->p_input
513         p_input->stream.p_selected_area->i_part = i_chapter;
514         input_ChangeArea( p_input, p_input->stream.p_selected_area );
515         input_SetStatus( p_input, INPUT_STATUS_PLAY );
516 #undef p_input
517     }
518 }
519
520 - (IBAction)toggleLanguage:(id)sender
521 {
522     NSMenuItem * o_mi = (NSMenuItem *)sender;
523     intf_thread_t * p_intf = [NSApp getIntf];
524
525 #if 0
526     /* We do not use this code, because you need to start stop .avi for
527      * it to work, so not very useful now  --hartman */
528     if ( [o_mi state] == NSOffState && [o_mi tag] == 2000 )
529     {
530         NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
531         
532         [o_open_panel setAllowsMultipleSelection: NO];
533         [o_open_panel setTitle: _NS("Open subtitlefile")];
534         [o_open_panel setPrompt: _NS("Open")];
535     
536         if( [o_open_panel runModalForDirectory: nil 
537                 file: nil types: nil] == NSOKButton )
538         {
539             NSString *o_filename = [[o_open_panel filenames] objectAtIndex: 0];
540             config_PutPsz( p_intf, "sub-file", strdup( [o_filename cString] ));
541         }
542     }
543 #endif
544
545 #define p_input p_intf->p_sys->p_input
546
547     if( !p_intf->p_sys->b_audio_update )
548     {
549         NSValue * o_value = [o_mi representedObject];
550         es_descriptor_t * p_es = [o_value pointerValue];
551
552         if( [o_mi state] == NSOnState )
553         {
554             /* we just have one ES to disable */
555             input_ToggleES( p_input, p_es, 0 );
556         }
557         else
558         {
559             unsigned int i;
560             int i_cat = [o_mi tag];
561
562             vlc_mutex_lock( &p_input->stream.stream_lock );
563
564 #define ES p_input->stream.pp_selected_es[i]
565
566             /* unselect the selected ES in the same class */
567             for( i = 0; i < p_input->stream.i_selected_es_number; i++ )
568             {
569                 if( ES->i_cat == i_cat )
570                 {
571                     vlc_mutex_unlock( &p_input->stream.stream_lock );
572                     input_ToggleES( p_input, ES, 0 );
573                     vlc_mutex_lock( &p_input->stream.stream_lock );
574                     break;
575                 }
576             }
577
578 #undef ES
579
580             vlc_mutex_unlock( &p_input->stream.stream_lock );
581
582             input_ToggleES( p_input, p_es, 1 );
583         }
584     }
585
586 #undef p_input
587 }
588
589 - (IBAction)toggleVar:(id)sender
590 {
591     NSMenuItem * o_mi = (NSMenuItem *)sender;
592     
593     if( [o_mi state] == NSOffState )
594     {
595         const char * psz_variable = (const char *)[o_mi tag];
596         const char * psz_value = [[o_mi title] cString];
597         vlc_object_t * p_object = (vlc_object_t *)
598             [[o_mi representedObject] pointerValue];
599         vlc_value_t val;
600         /* psz_string sucks */
601         val.psz_string = (char *)psz_value;
602
603         if ( var_Set( p_object, psz_variable, val ) < 0 )
604         {
605             msg_Warn( p_object, "cannot set variable (%s)", psz_value );
606         }
607     }
608 }
609
610 @end
611
612 @implementation VLCControls (NSMenuValidation)
613  
614 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
615 {
616     BOOL bEnabled = TRUE;
617     NSMenu * o_menu = [o_mi menu];
618     intf_thread_t * p_intf = [NSApp getIntf];
619
620     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
621                                                        FIND_ANYWHERE );
622
623     if( p_playlist != NULL )
624     {
625         vlc_mutex_lock( &p_playlist->object_lock );
626     }
627
628     if( [[o_mi title] isEqualToString: _NS("Faster")] ||
629         [[o_mi title] isEqualToString: _NS("Slower")] )
630     {
631         if( p_playlist != NULL && p_playlist->p_input != NULL )
632         {
633             vlc_mutex_lock( &p_playlist->p_input->stream.stream_lock );
634             bEnabled = p_playlist->p_input->stream.b_pace_control;
635             vlc_mutex_unlock( &p_playlist->p_input->stream.stream_lock );
636         }
637         else
638         {
639             bEnabled = FALSE;
640         }
641     }
642     else if( [[o_mi title] isEqualToString: _NS("Stop")] )
643     {
644         if( p_playlist == NULL || p_playlist->p_input == NULL )
645         {
646             bEnabled = FALSE;
647         }
648     }
649     else if( [[o_mi title] isEqualToString: _NS("Previous")] ||
650              [[o_mi title] isEqualToString: _NS("Next")] )
651     {
652         if( p_playlist == NULL )
653         {
654             bEnabled = FALSE;
655         }
656         else
657         {
658             bEnabled = p_playlist->i_size > 1;
659         }
660     }
661     else if( [[o_mi title] isEqualToString: _NS("Loop")] )
662     {
663         int i_state = config_GetInt( p_playlist, "loop" ) ?
664                       NSOnState : NSOffState;
665
666         [o_mi setState: i_state];
667     }
668     else if( [[o_mi title] isEqualToString: _NS("Fullscreen")] )    
669     {
670         id o_window;
671         NSArray *o_windows = [NSApp windows];
672         NSEnumerator *o_enumerator = [o_windows objectEnumerator];
673         bEnabled = FALSE;
674         
675         while ((o_window = [o_enumerator nextObject]))
676         {
677             if( [[o_window className] isEqualToString: @"VLCWindow"] )
678             {
679                 bEnabled = TRUE;
680                 break;
681             }
682         }
683     }
684     else if( o_menu != nil && 
685              [[o_menu title] isEqualToString: _NS("Deinterlace")] )
686     { 
687         char * psz_filter = config_GetPsz( p_intf, "filter" );
688
689         if( psz_filter != NULL )
690         {
691             free( psz_filter );
692
693             psz_filter = config_GetPsz( p_intf, "deinterlace-mode" );
694         }
695
696         if( psz_filter != NULL )
697         {
698             if( strcmp( psz_filter, [[o_mi title] lossyCString] ) == 0 )
699             {
700                 [o_mi setState: NSOnState]; 
701             }
702             else
703             {
704                 [o_mi setState: NSOffState];
705             }
706
707             free( psz_filter );
708         } 
709         else
710         {
711             [o_mi setState: NSOffState];
712         }
713     } 
714
715     if( p_playlist != NULL )
716     {
717         vlc_mutex_unlock( &p_playlist->object_lock );
718         vlc_object_release( p_playlist );
719     }
720
721     return( bEnabled );
722 }
723
724 @end