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