macosx: remove 2 interface update timers (2 threads), 1 additional interface update...
[vlc.git] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <hartman at videolan dot org>
10  *          Benjamin Pracht <bigben at videolan doit org>
11  *          Felix Paul K├╝hne <fkuehne at videolan dot org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <sys/param.h>                                    /* for MAXPATHLEN */
33 #include <string.h>
34
35 #import "intf.h"
36 #import "vout.h"
37 #import "open.h"
38 #import "controls.h"
39 #import "playlist.h"
40 #import "CoreInteraction.h"
41 #import <vlc_keys.h>
42
43 #pragma mark -
44 /*****************************************************************************
45  * VLCControls implementation
46  *****************************************************************************/
47 @implementation VLCControls
48
49 - (id)init
50 {
51     [super init];
52     o_fs_panel = [[VLCFSPanel alloc] init];
53     return self;
54 }
55
56 - (void)awakeFromNib
57 {
58     [o_specificTime_mi setTitle: _NS("Jump To Time")];
59     [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
60     [o_specificTime_ok_btn setTitle: _NS("OK")];
61     [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
62     [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
63 }
64
65
66 - (void)dealloc
67 {
68     [[NSNotificationCenter defaultCenter] removeObserver: self];
69
70     [super dealloc];
71 }
72
73 - (IBAction)play:(id)sender
74 {
75     [[VLCCoreInteraction sharedInstance] play];
76 }
77
78 - (IBAction)stop:(id)sender
79 {
80     [[VLCCoreInteraction sharedInstance] stop];
81 }
82
83 - (IBAction)prev:(id)sender
84 {
85     [[VLCCoreInteraction sharedInstance] previous];
86 }
87
88 - (IBAction)next:(id)sender
89 {
90     [[VLCCoreInteraction sharedInstance] next];
91 }
92
93 - (IBAction)random:(id)sender
94 {
95     [[VLCCoreInteraction sharedInstance] shuffle];
96 }
97
98 - (IBAction)repeat:(id)sender
99 {
100     vlc_value_t val;
101     intf_thread_t * p_intf = VLCIntf;
102     playlist_t * p_playlist = pl_Get( p_intf );
103
104     var_Get( p_playlist, "repeat", &val );
105     if(! val.b_bool )
106         [[VLCCoreInteraction sharedInstance] repeatOne];
107     else
108         [[VLCCoreInteraction sharedInstance] repeatOff];
109 }
110
111 - (IBAction)loop:(id)sender
112 {
113     vlc_value_t val;
114     intf_thread_t * p_intf = VLCIntf;
115     playlist_t * p_playlist = pl_Get( p_intf );
116
117     var_Get( p_playlist, "loop", &val );
118     if(! val.b_bool )
119         [[VLCCoreInteraction sharedInstance] repeatAll];
120     else
121         [[VLCCoreInteraction sharedInstance] repeatOff];
122 }
123
124 - (IBAction)quitAfterPlayback:(id)sender
125 {
126     vlc_value_t val;
127     playlist_t * p_playlist = pl_Get( VLCIntf );
128     var_ToggleBool( p_playlist, "play-and-exit" );
129 }
130
131 - (IBAction)forward:(id)sender
132 {
133     [[VLCCoreInteraction sharedInstance] forward];
134 }
135
136 - (IBAction)backward:(id)sender
137 {
138     [[VLCCoreInteraction sharedInstance] backward];
139 }
140
141 - (IBAction)volumeUp:(id)sender
142 {
143     [[VLCCoreInteraction sharedInstance] volumeUp];
144 }
145
146 - (IBAction)volumeDown:(id)sender
147 {
148     [[VLCCoreInteraction sharedInstance] volumeDown];
149 }
150
151 - (IBAction)mute:(id)sender
152 {
153     [[VLCCoreInteraction sharedInstance] mute];
154 }
155
156 - (IBAction)volumeSliderUpdated:(id)sender
157 {
158     [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
159 }
160
161 - (IBAction)showPosition: (id)sender
162 {
163     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
164     if( p_input != NULL )
165     {
166         vout_thread_t *p_vout = input_GetVout( p_input );
167         if( p_vout != NULL )
168         {
169             var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION );
170             vlc_object_release( (vlc_object_t *)p_vout );
171         }
172         vlc_object_release( p_input );
173     }
174 }
175
176 - (IBAction)toogleFullscreen:(id)sender {
177     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
178 }
179
180 - (BOOL) isFullscreen {
181     id o_vout_view = [[VLCCoreInteraction sharedInstance] voutView];
182     if( o_vout_view )
183     {
184         return [o_vout_view isFullscreen];
185     }
186     return NO;
187 }
188
189 - (IBAction)windowAction:(id)sender
190 {
191     NSString *o_title = [sender title];
192     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
193
194     if( p_input != NULL )
195     {
196         vout_thread_t *p_vout = input_GetVout( p_input );
197         if( p_vout != NULL )
198         {
199             id o_vout_view = [[VLCCoreInteraction sharedInstance] voutView];
200             if( o_vout_view )
201             {
202                 if( [o_title isEqualToString: _NS("Half Size") ] )
203                     [o_vout_view scaleWindowWithFactor: 0.5 animate: YES];
204                 else if( [o_title isEqualToString: _NS("Normal Size") ] )
205                     [o_vout_view scaleWindowWithFactor: 1.0 animate: YES];
206                 else if( [o_title isEqualToString: _NS("Double Size") ] )
207                     [o_vout_view scaleWindowWithFactor: 2.0 animate: YES];
208                 else if( [o_title isEqualToString: _NS("Float on Top") ] )
209                     [o_vout_view toggleFloatOnTop];
210                 else if( [o_title isEqualToString: _NS("Fit to Screen") ] )
211                 {
212                     id o_window = [o_vout_view voutWindow];
213                     if( ![o_window isZoomed] )
214                         [o_window performZoom:self];
215                 }
216                 else if( [o_title isEqualToString: _NS("Snapshot") ] )
217                 {
218                     [o_vout_view snapshot];
219                 }
220                 else
221                 {
222                     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
223                 }
224             }
225             vlc_object_release( (vlc_object_t *)p_vout );
226         }
227         else
228         {
229             [[VLCCoreInteraction sharedInstance] toggleFullscreen];
230         }
231         vlc_object_release( p_input );
232     }
233 }
234
235 - (IBAction)telxTransparent:(id)sender
236 {
237     vlc_object_t *p_vbi;
238     p_vbi = (vlc_object_t *) vlc_object_find_name( pl_Get( VLCIntf ), "zvbi" );
239     if( p_vbi )
240     {
241         var_SetBool( p_vbi, "vbi-opaque", [sender state] );
242         [sender setState: ![sender state]];
243         vlc_object_release( p_vbi );
244     }
245 }
246
247 - (IBAction)telxNavLink:(id)sender
248 {
249     intf_thread_t * p_intf = VLCIntf;
250     vlc_object_t *p_vbi;
251     int i_page = 0;
252
253     if( [[sender title] isEqualToString: _NS("Index")] )
254         i_page = 'i' << 16;
255     else if( [[sender title] isEqualToString: _NS("Red")] )
256         i_page = 'r' << 16;
257     else if( [[sender title] isEqualToString: _NS("Green")] )
258         i_page = 'g' << 16;
259     else if( [[sender title] isEqualToString: _NS("Yellow")] )
260         i_page = 'y' << 16;
261     else if( [[sender title] isEqualToString: _NS("Blue")] )
262         i_page = 'b' << 16;
263     if( i_page == 0 ) return;
264
265     p_vbi = (vlc_object_t *) vlc_object_find_name( pl_Get( VLCIntf ), "zvbi" );
266     if( p_vbi )
267     {
268         var_SetInteger( p_vbi, "vbi-page", i_page );
269         vlc_object_release( p_vbi );
270     }
271 }
272
273 - (IBAction)lockVideosAspectRatio:(id)sender
274 {
275     [[VLCCoreInteraction sharedInstance] setAspectRatioLocked: [sender state]];
276     [sender setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
277 }
278
279 - (IBAction)addSubtitleFile:(id)sender
280 {
281     NSInteger i_returnValue = 0;
282     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
283     if( !p_input ) return;
284
285     input_item_t *p_item = input_GetItem( p_input );
286     if( !p_item ) return;
287
288     char *path = input_item_GetURI( p_item );
289     if( !path ) path = strdup( "" );
290
291     NSOpenPanel * openPanel = [NSOpenPanel openPanel];
292     [openPanel setCanChooseFiles: YES];
293     [openPanel setCanChooseDirectories: NO];
294     [openPanel setAllowsMultipleSelection: YES];
295     [openPanel setAllowedFileTypes: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi",@"txt",@"smil", nil]];
296     [openPanel setDirectoryURL:[NSURL fileURLWithPath:[[NSString stringWithUTF8String:path] stringByExpandingTildeInPath]]];
297     i_returnValue = [openPanel runModal];
298     free( path );
299
300     if( i_returnValue == NSOKButton )
301     {
302         NSUInteger c = 0;
303         if( !p_input ) return;
304
305         c = [[openPanel URLs] count];
306
307         for (int i = 0; i < c ; i++)
308         {
309             msg_Dbg( VLCIntf, "loading subs from %s", [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
310             if( input_AddSubtitle( p_input, [[[[openPanel URLs] objectAtIndex: i] path] UTF8String], TRUE ) )
311                 msg_Warn( VLCIntf, "unable to load subtitles from '%s'",
312                          [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
313         }
314     }
315 }
316
317 - (id)fspanel
318 {
319     if( o_fs_panel )
320         return o_fs_panel;
321     else
322     {
323         msg_Err( VLCIntf, "FSPanel is nil" );
324         return NULL;
325     }
326 }
327
328 - (void)scrollWheel:(NSEvent *)theEvent
329 {
330     intf_thread_t * p_intf = VLCIntf;
331     BOOL b_invertedEventFromDevice = NO;
332     if ([theEvent respondsToSelector:@selector(isDirectionInvertedFromDevice)])
333     {
334         if ([theEvent isDirectionInvertedFromDevice])
335             b_invertedEventFromDevice = YES;
336     }
337
338     float f_yabsvalue = [theEvent deltaY] > 0.0f ? [theEvent deltaY] : -[theEvent deltaY];
339     float f_xabsvalue = [theEvent deltaX] > 0.0f ? [theEvent deltaX] : -[theEvent deltaX];
340     int i, i_yvlckey, i_xvlckey;
341
342     if (b_invertedEventFromDevice)
343     {
344         if ([theEvent deltaY] > 0.0f)
345             i_yvlckey = KEY_MOUSEWHEELDOWN;
346         else
347             i_yvlckey = KEY_MOUSEWHEELUP;
348
349         if ([theEvent deltaX] > 0.0f)
350             i_xvlckey = KEY_MOUSEWHEELRIGHT;
351         else
352             i_xvlckey = KEY_MOUSEWHEELLEFT;
353     }
354     else
355     {
356         if ([theEvent deltaY] < 0.0f)
357             i_yvlckey = KEY_MOUSEWHEELDOWN;
358         else
359             i_yvlckey = KEY_MOUSEWHEELUP;
360
361         if ([theEvent deltaX] < 0.0f)
362             i_xvlckey = KEY_MOUSEWHEELRIGHT;
363         else
364             i_xvlckey = KEY_MOUSEWHEELLEFT;
365     }
366
367     /* Send multiple key event, depending on the intensity of the event */
368     for (i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
369         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_yvlckey );
370
371     /* Prioritize Y event (sound volume) over X event */
372     if (f_yabsvalue < 0.05)
373     {
374         for (i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
375          var_SetInteger( p_intf->p_libvlc, "key-pressed", i_xvlckey );
376     }
377 }
378
379 - (BOOL)keyEvent:(NSEvent *)o_event
380 {
381     BOOL eventHandled = NO;
382     unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
383
384     if( key )
385     {
386         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
387         if( p_input != NULL )
388         {
389             vout_thread_t *p_vout = input_GetVout( p_input );
390
391             if( p_vout != NULL )
392             {
393                 /* Escape */
394                 if( key == (unichar) 0x1b )
395                 {
396                     id o_vout_view = [[VLCCoreInteraction sharedInstance] voutView];
397                     if( o_vout_view && [o_vout_view isFullscreen] )
398                     {
399                         [o_vout_view toggleFullscreen];
400                         eventHandled = YES;
401                     }
402                 }
403                 else if( key == ' ' )
404                 {
405                     [self play:self];
406                     eventHandled = YES;
407                 }
408                 vlc_object_release( (vlc_object_t *)p_vout );
409             }
410             vlc_object_release( p_input );
411         }
412     }
413     return eventHandled;
414 }
415
416 - (IBAction)goToSpecificTime:(id)sender
417 {
418     if( sender == o_specificTime_cancel_btn )
419     {
420         [NSApp endSheet: o_specificTime_win];
421         [o_specificTime_win close];
422     }
423     else if( sender == o_specificTime_ok_btn )
424     {
425         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
426         if( p_input )
427         {
428             int64_t timeInSec = 0;
429             NSString * fieldContent = [o_specificTime_enter_fld stringValue];
430             if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
431                 [[fieldContent componentsSeparatedByString: @":"] count] <= 3 )
432             {
433                 NSArray * ourTempArray = \
434                     [fieldContent componentsSeparatedByString: @":"];
435
436                 if( [[fieldContent componentsSeparatedByString: @":"] count] == 3 )
437                 {
438                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
439                     timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
440                     timeInSec += [[ourTempArray objectAtIndex: 2] intValue];        //s
441                 }
442                 else
443                 {
444                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
445                     timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
446                 }
447             }
448             else
449                 timeInSec = [fieldContent intValue];
450
451             input_Control( p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
452             vlc_object_release( p_input );
453         }
454
455         [NSApp endSheet: o_specificTime_win];
456         [o_specificTime_win close];
457     }
458     else
459     {
460         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
461         if( p_input )
462         {
463             /* we can obviously only do that if an input is available */
464             vlc_value_t pos, length;
465             var_Get( p_input, "time", &pos );
466             [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
467             var_Get( p_input, "length", &length );
468             [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];
469
470             [NSApp beginSheet: o_specificTime_win modalForWindow: \
471                 [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
472                 contextInfo: nil];
473             [o_specificTime_win makeKeyWindow];
474             vlc_object_release( p_input );
475         }
476     }
477 }
478
479 @end