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