]> git.sesse.net Git - vlc/blob - modules/gui/macosx/VideoView.m
cd88942d5f47d1a5c05ae25589062607147898f6
[vlc] / modules / gui / macosx / VideoView.m
1 /*****************************************************************************
2  * VideoView.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan dot org>
8  *          Eric Petit <titer@m0k.org>
9  *          Benjamin Pracht <bigben at videolan dot org>
10  *          Pierre d'Herbemont <pdherbemont # videolan 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 #import <stdlib.h>                                                 /* free() */
32 #import <string.h>
33
34 #import "intf.h"
35 #import "VideoView.h"
36 #import "CoreInteraction.h"
37 #import "MainMenu.h"
38 #import "MainWindow.h"
39
40 #import <vlc_common.h>
41 #import <vlc_keys.h>
42
43
44 /*****************************************************************************
45  * VLCVoutView implementation
46  *****************************************************************************/
47 @implementation VLCVoutView
48
49 #pragma mark -
50 #pragma mark drag & drop support
51
52 - (void)dealloc
53 {
54     if (p_vout)
55         vlc_object_release(p_vout);
56
57     [self unregisterDraggedTypes];
58     [super dealloc];
59 }
60
61 -(id)initWithFrame:(NSRect)frameRect
62 {
63     if (self = [super initWithFrame:frameRect]) {
64         [self registerForDraggedTypes:[NSArray arrayWithObject: NSFilenamesPboardType]];
65     }
66
67     i_lastScrollWheelDirection = 0;
68     f_cumulated_magnification = 0.0;
69
70     return self;
71 }
72
73 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
74 {
75     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric)
76         return NSDragOperationGeneric;
77     return NSDragOperationNone;
78 }
79
80 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
81 {
82     return YES;
83 }
84
85 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
86 {
87     BOOL b_returned;
88     b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation: sender];
89
90     [self setNeedsDisplay:YES];
91     return b_returned;
92 }
93
94 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
95 {
96     [self setNeedsDisplay:YES];
97 }
98
99 #pragma mark -
100 #pragma mark vout actions
101
102 - (void)keyDown:(NSEvent *)o_event
103 {
104     unichar key = 0;
105     vlc_value_t val;
106     unsigned int i_pressed_modifiers = 0;
107     val.i_int = 0;
108
109     i_pressed_modifiers = [o_event modifierFlags];
110
111     if (i_pressed_modifiers & NSShiftKeyMask)
112         val.i_int |= KEY_MODIFIER_SHIFT;
113     if (i_pressed_modifiers & NSControlKeyMask)
114         val.i_int |= KEY_MODIFIER_CTRL;
115     if (i_pressed_modifiers & NSAlternateKeyMask)
116         val.i_int |= KEY_MODIFIER_ALT;
117     if (i_pressed_modifiers & NSCommandKeyMask)
118         val.i_int |= KEY_MODIFIER_COMMAND;
119
120     NSString * characters = [o_event charactersIgnoringModifiers];
121     if ([characters length] > 0) {
122         key = [[characters lowercaseString] characterAtIndex: 0];
123
124         if (key) {
125             /* Escape should always get you out of fullscreen */
126             if (key == (unichar) 0x1b) {
127                 playlist_t * p_playlist = pl_Get(VLCIntf);
128                  if (var_GetBool(p_playlist, "fullscreen"))
129                      [[VLCCoreInteraction sharedInstance] toggleFullscreen];
130             }
131             /* handle Lion's default key combo for fullscreen-toggle in addition to our own hotkeys */
132             else if (key == 'f' && i_pressed_modifiers & NSControlKeyMask && i_pressed_modifiers & NSCommandKeyMask)
133                 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
134             else if (p_vout) {
135                 if (key == ' ')
136                     [[VLCCoreInteraction sharedInstance] play];
137                 else {
138                     val.i_int |= (int)CocoaKeyToVLC(key);
139                     var_Set(p_vout->p_libvlc, "key-pressed", val);
140                 }
141             }
142             else
143                 msg_Dbg(VLCIntf, "could not send keyevent to VLC core");
144
145             return;
146         }
147     }
148     [super keyDown: o_event];
149 }
150
151 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
152 {
153     return [[VLCMainWindow sharedInstance] performKeyEquivalent: o_event];
154 }
155
156 - (void)mouseDown:(NSEvent *)o_event
157 {
158     if (([o_event type] == NSLeftMouseDown) && (! ([o_event modifierFlags] &  NSControlKeyMask))) {
159         if ([o_event clickCount] > 1)
160             [[VLCCoreInteraction sharedInstance] toggleFullscreen];
161     } else if (([o_event type] == NSRightMouseDown) ||
162                (([o_event type] == NSLeftMouseDown) &&
163                ([o_event modifierFlags] &  NSControlKeyMask)))
164         [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
165
166     [super mouseDown: o_event];
167 }
168
169 - (void)rightMouseDown:(NSEvent *)o_event
170 {
171     if ([o_event type] == NSRightMouseDown)
172         [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
173
174     [super mouseDown: o_event];
175 }
176
177 - (void)rightMouseUp:(NSEvent *)o_event
178 {
179     if ([o_event type] == NSRightMouseUp)
180         [NSMenu popUpContextMenu: [[VLCMainMenu sharedInstance] voutMenu] withEvent: o_event forView: self];
181
182     [super mouseUp: o_event];
183 }
184
185 - (void)mouseMoved:(NSEvent *)o_event
186 {
187     NSPoint ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
188     if ([self mouse: ml inRect: [self bounds]])
189         [[VLCMain sharedInstance] showFullscreenController];
190
191     [super mouseMoved: o_event];
192 }
193
194 - (void)resetScrollWheelDirection
195 {
196     /* release the scroll direction 0.8 secs after the last event */
197     if (([NSDate timeIntervalSinceReferenceDate] - t_lastScrollEvent) >= 0.80)
198         i_lastScrollWheelDirection = 0;
199 }
200
201 - (void)scrollWheel:(NSEvent *)theEvent
202 {
203     intf_thread_t * p_intf = VLCIntf;
204     CGFloat f_deltaX = [theEvent deltaX];
205     CGFloat f_deltaY = [theEvent deltaY];
206
207     if (!OSX_SNOW_LEOPARD && [theEvent isDirectionInvertedFromDevice]) {
208         f_deltaX = -f_deltaX;
209         f_deltaY = -f_deltaY;
210     }
211
212     CGFloat f_yabsvalue = f_deltaY > 0.0f ? f_deltaY : -f_deltaY;
213     CGFloat f_xabsvalue = f_deltaX > 0.0f ? f_deltaX : -f_deltaX;
214
215     int i_yvlckey, i_xvlckey = 0;
216     if (f_deltaY < 0.0f)
217         i_yvlckey = KEY_MOUSEWHEELDOWN;
218     else
219         i_yvlckey = KEY_MOUSEWHEELUP;
220
221     if (f_deltaX < 0.0f)
222         i_xvlckey = KEY_MOUSEWHEELRIGHT;
223     else
224         i_xvlckey = KEY_MOUSEWHEELLEFT;
225
226     /* in the following, we're forwarding either a x or a y event */
227     /* Multiple key events are send depending on the intensity of the event */
228     /* the opposite direction is being blocked for 0.8 secs */
229     if (f_yabsvalue > 0.05) {
230         if (i_lastScrollWheelDirection < 0) // last was a X
231             return;
232
233         i_lastScrollWheelDirection = 1; // Y
234         for (NSUInteger i = 0; i < (int)(f_yabsvalue/4.+1.); i++)
235             var_SetInteger(p_intf->p_libvlc, "key-pressed", i_yvlckey);
236
237         t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
238         [self performSelector:@selector(resetScrollWheelDirection)
239                    withObject: NULL
240                    afterDelay:1.00];
241         return;
242     }
243     if (f_xabsvalue > 0.05) {
244         if (i_lastScrollWheelDirection > 0) // last was a Y
245             return;
246
247         i_lastScrollWheelDirection = -1; // X
248         for (NSUInteger i = 0; i < (int)(f_xabsvalue/6.+1.); i++)
249             var_SetInteger(p_intf->p_libvlc, "key-pressed", i_xvlckey);
250
251         t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
252         [self performSelector:@selector(resetScrollWheelDirection)
253                    withObject: NULL
254                    afterDelay:1.00];
255     }
256 }
257
258 #pragma mark -
259 #pragma mark Handling of vout related actions
260
261 - (void)setVoutThread:(vout_thread_t *)p_vout_thread
262 {
263     assert(p_vout == NULL);
264     p_vout = p_vout_thread;
265     vlc_object_hold(p_vout);
266 }
267
268 - (vout_thread_t *)voutThread
269 {
270     if (p_vout) {
271         vlc_object_hold(p_vout);
272         return p_vout;
273     }
274
275     return NULL;
276 }
277
278 - (void)releaseVoutThread
279 {
280     if (p_vout) {
281         vlc_object_release(p_vout);
282         p_vout = NULL;
283     }
284 }
285
286 #pragma mark -
287 #pragma mark Basic view behaviour and touch events handling
288
289 - (BOOL)mouseDownCanMoveWindow
290 {
291     return YES;
292 }
293
294 - (BOOL)acceptsFirstResponder
295 {
296     return YES;
297 }
298
299 - (BOOL)becomeFirstResponder
300 {
301     return YES;
302 }
303
304 - (BOOL)resignFirstResponder
305 {
306     /* while we need to be the first responder most of the time, we need to give up that status when toggling the playlist */
307     return YES;
308 }
309
310 -(void)didAddSubview:(NSView *)subview
311 {
312     [[self window] makeFirstResponder: subview];
313 }
314
315 - (void)magnifyWithEvent:(NSEvent *)event
316 {
317     f_cumulated_magnification += [event magnification];
318
319     // This is the result of [NSEvent standardMagnificationThreshold].
320     // Unfortunately, this is a private API, currently.
321     CGFloat f_threshold = 0.3;
322     BOOL b_fullscreen = [[VLCMainWindow sharedInstance] fullscreen];
323
324     if ((f_cumulated_magnification > f_threshold && !b_fullscreen) || (f_cumulated_magnification < -f_threshold && b_fullscreen)) {
325         f_cumulated_magnification = 0.0;
326         [[VLCCoreInteraction sharedInstance] toggleFullscreen];
327     }
328 }
329
330 - (void)beginGestureWithEvent:(NSEvent *)event
331 {
332     f_cumulated_magnification = 0.0;
333 }
334
335 @end