]> git.sesse.net Git - vlc/blob - modules/gui/macosx/controls.m
fb20d9c3d47f4ec0b6079142298def08f485bdf2
[vlc] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
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 "VideoView.h"
37 #import "open.h"
38 #import "controls.h"
39 #import "playlist.h"
40 #import "MainMenu.h"
41 #import "CoreInteraction.h"
42 #import <vlc_keys.h>
43
44 #pragma mark -
45 /*****************************************************************************
46  * VLCControls implementation
47  *****************************************************************************/
48 @implementation VLCControls
49
50 - (void)awakeFromNib
51 {
52     [o_specificTime_mi setTitle: _NS("Jump To Time")];
53     [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
54     [o_specificTime_ok_btn setTitle: _NS("OK")];
55     [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
56     [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
57
58     i_lastScrollWheelDirection = 0;
59 }
60
61
62 - (void)dealloc
63 {
64     [[NSNotificationCenter defaultCenter] removeObserver: self];
65
66     [super dealloc];
67 }
68
69 - (IBAction)play:(id)sender
70 {
71     [[VLCCoreInteraction sharedInstance] play];
72 }
73
74 - (IBAction)stop:(id)sender
75 {
76     [[VLCCoreInteraction sharedInstance] stop];
77 }
78
79 - (IBAction)prev:(id)sender
80 {
81     [[VLCCoreInteraction sharedInstance] previous];
82 }
83
84 - (IBAction)next:(id)sender
85 {
86     [[VLCCoreInteraction sharedInstance] next];
87 }
88
89 - (IBAction)random:(id)sender
90 {
91     [[VLCCoreInteraction sharedInstance] shuffle];
92 }
93
94 - (IBAction)repeat:(id)sender
95 {
96     vlc_value_t val;
97     intf_thread_t * p_intf = VLCIntf;
98     playlist_t * p_playlist = pl_Get(p_intf);
99
100     var_Get(p_playlist, "repeat", &val);
101     if (! val.b_bool)
102         [[VLCCoreInteraction sharedInstance] repeatOne];
103     else
104         [[VLCCoreInteraction sharedInstance] repeatOff];
105 }
106
107 - (IBAction)loop:(id)sender
108 {
109     vlc_value_t val;
110     intf_thread_t * p_intf = VLCIntf;
111     playlist_t * p_playlist = pl_Get(p_intf);
112
113     var_Get(p_playlist, "loop", &val);
114     if (! val.b_bool)
115         [[VLCCoreInteraction sharedInstance] repeatAll];
116     else
117         [[VLCCoreInteraction sharedInstance] repeatOff];
118 }
119
120 - (IBAction)quitAfterPlayback:(id)sender
121 {
122     vlc_value_t val;
123     playlist_t * p_playlist = pl_Get(VLCIntf);
124     var_ToggleBool(p_playlist, "play-and-exit");
125 }
126
127 - (IBAction)forward:(id)sender
128 {
129     [[VLCCoreInteraction sharedInstance] forward];
130 }
131
132 - (IBAction)backward:(id)sender
133 {
134     [[VLCCoreInteraction sharedInstance] backward];
135 }
136
137 - (IBAction)volumeUp:(id)sender
138 {
139     [[VLCCoreInteraction sharedInstance] volumeUp];
140 }
141
142 - (IBAction)volumeDown:(id)sender
143 {
144     [[VLCCoreInteraction sharedInstance] volumeDown];
145 }
146
147 - (IBAction)mute:(id)sender
148 {
149     [[VLCCoreInteraction sharedInstance] setMute: YES];
150 }
151
152 - (IBAction)volumeSliderUpdated:(id)sender
153 {
154     [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
155 }
156
157 - (IBAction)showPosition: (id)sender
158 {
159     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
160     if (p_input != NULL) {
161         vout_thread_t *p_vout = input_GetVout(p_input);
162         if (p_vout != NULL) {
163             var_SetInteger(VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION);
164             vlc_object_release(p_vout);
165         }
166         vlc_object_release(p_input);
167     }
168 }
169
170 - (IBAction)telxTransparent:(id)sender
171 {
172     vlc_object_t *p_vbi;
173     p_vbi = (vlc_object_t *) vlc_object_find_name(pl_Get(VLCIntf), "zvbi");
174     if (p_vbi) {
175         var_SetBool(p_vbi, "vbi-opaque", [sender state]);
176         [sender setState: ![sender state]];
177         vlc_object_release(p_vbi);
178     }
179 }
180
181 - (IBAction)telxNavLink:(id)sender
182 {
183     intf_thread_t * p_intf = VLCIntf;
184     vlc_object_t *p_vbi;
185     int i_page = 0;
186
187     if ([[sender title] isEqualToString: _NS("Index")])
188         i_page = 'i' << 16;
189     else if ([[sender title] isEqualToString: _NS("Red")])
190         i_page = 'r' << 16;
191     else if ([[sender title] isEqualToString: _NS("Green")])
192         i_page = 'g' << 16;
193     else if ([[sender title] isEqualToString: _NS("Yellow")])
194         i_page = 'y' << 16;
195     else if ([[sender title] isEqualToString: _NS("Blue")])
196         i_page = 'b' << 16;
197     if (i_page == 0) return;
198
199     p_vbi = (vlc_object_t *) vlc_object_find_name(pl_Get(VLCIntf), "zvbi");
200     if (p_vbi) {
201         var_SetInteger(p_vbi, "vbi-page", i_page);
202         vlc_object_release(p_vbi);
203     }
204 }
205
206 - (IBAction)lockVideosAspectRatio:(id)sender
207 {
208     [[VLCCoreInteraction sharedInstance] setAspectRatioIsLocked: ![sender state]];
209     [sender setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
210 }
211
212 - (IBAction)addSubtitleFile:(id)sender
213 {
214     NSInteger i_returnValue = 0;
215     input_thread_t * p_input = pl_CurrentInput(VLCIntf);
216     if (!p_input)
217         return;
218
219     input_item_t *p_item = input_GetItem(p_input);
220     if (!p_item) {
221         vlc_object_release(p_input);
222         return;
223     }
224
225     char *path = input_item_GetURI(p_item);
226     if (!path)
227         path = strdup("");
228
229     NSOpenPanel * openPanel = [NSOpenPanel openPanel];
230     [openPanel setCanChooseFiles: YES];
231     [openPanel setCanChooseDirectories: NO];
232     [openPanel setAllowsMultipleSelection: YES];
233     [openPanel setAllowedFileTypes: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi",@"txt",@"smil", nil]];
234     [openPanel setDirectoryURL:[NSURL fileURLWithPath:[[NSString stringWithUTF8String:path] stringByExpandingTildeInPath]]];
235     i_returnValue = [openPanel runModal];
236     free(path);
237
238     if (i_returnValue == NSOKButton) {
239         NSUInteger c = 0;
240         if (!p_input)
241             return;
242
243         c = [[openPanel URLs] count];
244
245         for (int i = 0; i < c ; i++) {
246             msg_Dbg(VLCIntf, "loading subs from %s", [[[[openPanel URLs] objectAtIndex: i] path] UTF8String]);
247             if (input_AddSubtitle(p_input, [[[[openPanel URLs] objectAtIndex: i] path] UTF8String], TRUE))
248                 msg_Warn(VLCIntf, "unable to load subtitles from '%s'",
249                          [[[[openPanel URLs] objectAtIndex: i] path] UTF8String]);
250         }
251     }
252     vlc_object_release(p_input);
253 }
254
255 - (void)resetScrollWheelDirection
256 {
257     /* release the scroll direction 0.8 secs after the last event */
258     if (([NSDate timeIntervalSinceReferenceDate] - t_lastScrollEvent) >= 0.80)
259         i_lastScrollWheelDirection = 0;
260 }
261
262 - (void)scrollWheel:(NSEvent *)theEvent
263 {
264     intf_thread_t * p_intf = VLCIntf;
265     BOOL b_invertedEventFromDevice = NO;
266     CGFloat f_deltaY, f_deltaX = .0;
267
268     if (!OSX_SNOW_LEOPARD) {
269         if ([theEvent isDirectionInvertedFromDevice])
270             b_invertedEventFromDevice = YES;
271     }
272
273     f_deltaY = [theEvent deltaY];
274     f_deltaX = [theEvent deltaX];
275
276     CGFloat f_yabsvalue = f_deltaY > 0.0f ? f_deltaY : -f_deltaY;
277     CGFloat f_xabsvalue = f_deltaX > 0.0f ? f_deltaX : -f_deltaX;
278
279     int i_yvlckey, i_xvlckey = 0;
280
281     if (b_invertedEventFromDevice) {
282         if (f_deltaY > 0.0f)
283             i_yvlckey = KEY_MOUSEWHEELDOWN;
284         else
285             i_yvlckey = KEY_MOUSEWHEELUP;
286
287         if (f_deltaX > 0.0f)
288             i_xvlckey = KEY_MOUSEWHEELRIGHT;
289         else
290             i_xvlckey = KEY_MOUSEWHEELLEFT;
291     } else {
292         if (f_deltaY < 0.0f)
293             i_yvlckey = KEY_MOUSEWHEELDOWN;
294         else
295             i_yvlckey = KEY_MOUSEWHEELUP;
296
297         if (f_deltaX < 0.0f)
298             i_xvlckey = KEY_MOUSEWHEELRIGHT;
299         else
300             i_xvlckey = KEY_MOUSEWHEELLEFT;
301     }
302
303     /* in the following, we're forwarding either a x or a y event */
304     /* Multiple key events are send depending on the intensity of the event */
305     /* the opposite direction is being blocked for 0.8 secs */
306     if (f_yabsvalue > 0.05)
307     {
308         if (i_lastScrollWheelDirection < 0) // last was a X
309             return;
310
311         i_lastScrollWheelDirection = 1; // Y
312         for (NSUInteger i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
313             var_SetInteger(p_intf->p_libvlc, "key-pressed", i_yvlckey);
314
315         t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
316         [self performSelector:@selector(resetScrollWheelDirection)
317                    withObject: NULL
318                    afterDelay:1.00];
319         return;
320     }
321     if (f_xabsvalue > 0.05)
322     {
323         if (i_lastScrollWheelDirection > 0) // last was a Y
324             return;
325
326         i_lastScrollWheelDirection = -1; // X
327         for (NSUInteger i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
328             var_SetInteger(p_intf->p_libvlc, "key-pressed", i_xvlckey);
329
330         t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
331         [self performSelector:@selector(resetScrollWheelDirection)
332                    withObject: NULL
333                    afterDelay:1.00];
334     }
335 }
336
337 - (BOOL)keyEvent:(NSEvent *)o_event
338 {
339     BOOL eventHandled = NO;
340     NSString * characters = [o_event charactersIgnoringModifiers];
341     if ([characters length] > 0) {
342         unichar key = [characters characterAtIndex: 0];
343
344         if (key) {
345             input_thread_t * p_input = pl_CurrentInput(VLCIntf);
346             if (p_input != NULL) {
347                 vout_thread_t *p_vout = input_GetVout(p_input);
348
349                 if (p_vout != NULL) {
350                     /* Escape */
351                     if (key == (unichar) 0x1b) {
352                         if (var_GetBool(p_vout, "fullscreen")) {
353                             [[VLCCoreInteraction sharedInstance] toggleFullscreen];
354                             eventHandled = YES;
355                         }
356                     }
357                     else if (key == ' ') {
358                         [self play:self];
359                         eventHandled = YES;
360                     }
361                     vlc_object_release(p_vout);
362                 }
363                 vlc_object_release(p_input);
364             }
365         }
366     }
367     return eventHandled;
368 }
369
370 - (IBAction)goToSpecificTime:(id)sender
371 {
372     if (sender == o_specificTime_cancel_btn)
373     {
374         [NSApp endSheet: o_specificTime_win];
375         [o_specificTime_win close];
376     } else if (sender == o_specificTime_ok_btn) {
377         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
378         if (p_input) {
379             int64_t timeInSec = 0;
380             NSString * fieldContent = [o_specificTime_enter_fld stringValue];
381             if ([[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
382                [[fieldContent componentsSeparatedByString: @":"] count] <= 3) {
383                 NSArray * ourTempArray = \
384                     [fieldContent componentsSeparatedByString: @":"];
385
386                 if ([[fieldContent componentsSeparatedByString: @":"] count] == 3) {
387                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
388                     timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
389                     timeInSec += [[ourTempArray objectAtIndex: 2] intValue];        //s
390                 } else {
391                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
392                     timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
393                 }
394             }
395             else
396                 timeInSec = [fieldContent intValue];
397
398             input_Control(p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
399             vlc_object_release(p_input);
400         }
401
402         [NSApp endSheet: o_specificTime_win];
403         [o_specificTime_win close];
404     } else {
405         input_thread_t * p_input = pl_CurrentInput(VLCIntf);
406         if (p_input) {
407             /* we can obviously only do that if an input is available */
408             vlc_value_t pos, length;
409             var_Get(p_input, "time", &pos);
410             [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
411             var_Get(p_input, "length", &length);
412             [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];
413
414             [NSApp beginSheet: o_specificTime_win modalForWindow: \
415                 [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
416                 contextInfo: nil];
417             [o_specificTime_win makeKeyWindow];
418             vlc_object_release(p_input);
419         }
420     }
421 }
422
423 @end
424
425 @implementation VLCControls (NSMenuValidation)
426
427 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
428 {
429     return [[VLCMainMenu sharedInstance] validateMenuItem:o_mi];
430 }
431
432 @end