core: remove the 360 video viewpoint zoom
[vlc.git] / modules / gui / macosx / VLCVoutView.m
blobc36b4112958464324576ff719f36eb408c5f4a5f
1 /*****************************************************************************
2  * VLCVoutView.m: MacOS X video output module
3  *****************************************************************************
4  * Copyright (C) 2002-2014 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  *          David Fuhrmann <david dot fuhrmann at googlemail dot com>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27  *****************************************************************************/
29 /*****************************************************************************
30  * Preamble
31  *****************************************************************************/
32 #import <stdlib.h>                                                 /* free() */
34 #import "CompatibilityFixes.h"
35 #import "VLCMain.h"
36 #import "VLCVoutView.h"
37 #import "VLCCoreInteraction.h"
38 #import "VLCMainMenu.h"
40 #import <QuartzCore/QuartzCore.h>
42 #import <vlc_keys.h>
45 /*****************************************************************************
46  * VLCVoutView implementation
47  *****************************************************************************/
48 @interface VLCVoutView()
50     NSTimer *p_scrollTimer;
51     NSInteger i_lastScrollWheelDirection;
53     CGFloat f_cumulatedXScrollValue;
54     CGFloat f_cumulatedYScrollValue;
56     CGFloat f_cumulated_magnification;
58     vout_thread_t *p_vout;
60 @end
62 @implementation VLCVoutView
64 #pragma mark -
65 #pragma mark drag & drop support
67 - (void)dealloc
69     if (p_vout)
70         vlc_object_release(p_vout);
72     [self unregisterDraggedTypes];
75 -(id)initWithFrame:(NSRect)frameRect
77     if (self = [super initWithFrame:frameRect]) {
78         [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
79     }
81     i_lastScrollWheelDirection = 0;
82     f_cumulated_magnification = 0.0;
84     return self;
87 - (void)addVoutLayer:(CALayer *)aLayer
89     if (self.layer == nil) {
90         [self setLayer:[CALayer layer]];
91         [self setWantsLayer:YES];
92     }
94     [CATransaction begin];
95     aLayer.opaque = 1.;
96     aLayer.hidden = NO;
97     aLayer.bounds = self.layer.bounds;
98     [self.layer addSublayer:aLayer];
99     [self setNeedsDisplay:YES];
100     [aLayer setNeedsDisplay];
101     CGRect frame = aLayer.bounds;
102     frame.origin.x = frame.origin.y = 0.;
103     aLayer.frame = frame;
104     [CATransaction commit];
107 - (void)removeVoutLayer:(CALayer *)aLayer
109     [CATransaction begin];
110     [aLayer removeFromSuperlayer];
111     [CATransaction commit];
114 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
116     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric)
117         return NSDragOperationGeneric;
118     return NSDragOperationNone;
121 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
123     return YES;
126 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
128     BOOL b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation:sender];
130     [self setNeedsDisplay:YES];
131     return b_returned;
134 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
136     [self setNeedsDisplay:YES];
139 #pragma mark -
140 #pragma mark vout actions
142 - (void)keyDown:(NSEvent *)o_event
144     unichar key = 0;
145     vlc_value_t val;
146     unsigned int i_pressed_modifiers = 0;
147     val.i_int = 0;
149     i_pressed_modifiers = [o_event modifierFlags];
151     if (i_pressed_modifiers & NSShiftKeyMask)
152         val.i_int |= KEY_MODIFIER_SHIFT;
153     if (i_pressed_modifiers & NSControlKeyMask)
154         val.i_int |= KEY_MODIFIER_CTRL;
155     if (i_pressed_modifiers & NSAlternateKeyMask)
156         val.i_int |= KEY_MODIFIER_ALT;
157     if (i_pressed_modifiers & NSCommandKeyMask)
158         val.i_int |= KEY_MODIFIER_COMMAND;
160     NSString * characters = [o_event charactersIgnoringModifiers];
161     if ([characters length] > 0) {
162         key = [[characters lowercaseString] characterAtIndex: 0];
164         if (key) {
165             /* Escape should always get you out of fullscreen */
166             if (key == (unichar) 0x1b) {
167                 playlist_t * p_playlist = pl_Get(getIntf());
168                  if (var_GetBool(p_playlist, "fullscreen"))
169                      [[VLCCoreInteraction sharedInstance] toggleFullscreen];
170             }
171             /* handle Lion's default key combo for fullscreen-toggle in addition to our own hotkeys */
172             else if (key == 'f' && i_pressed_modifiers & NSControlKeyMask && i_pressed_modifiers & NSCommandKeyMask)
173                 [[VLCCoreInteraction sharedInstance] toggleFullscreen];
174             else if (p_vout) {
175                 val.i_int |= (int)CocoaKeyToVLC(key);
176                 var_Set(p_vout->obj.libvlc, "key-pressed", val);
177             }
178             else
179                 msg_Dbg(getIntf(), "could not send keyevent to VLC core");
181             return;
182         }
183     }
184     [super keyDown: o_event];
187 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
189     return [[[VLCMain sharedInstance] mainWindow] performKeyEquivalent: o_event];
192 - (void)mouseDown:(NSEvent *)o_event
194     if (([o_event type] == NSLeftMouseDown) && (! ([o_event modifierFlags] &  NSControlKeyMask))) {
195         if ([o_event clickCount] == 2)
196             [[VLCCoreInteraction sharedInstance] toggleFullscreen];
198     } else if (([o_event type] == NSRightMouseDown) ||
199                (([o_event type] == NSLeftMouseDown) &&
200                ([o_event modifierFlags] &  NSControlKeyMask)))
201         [NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
203     [super mouseDown: o_event];
206 - (void)rightMouseDown:(NSEvent *)o_event
208     if ([o_event type] == NSRightMouseDown)
209         [NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
211     [super mouseDown: o_event];
214 - (void)rightMouseUp:(NSEvent *)o_event
216     if ([o_event type] == NSRightMouseUp)
217         [NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
219     [super mouseUp: o_event];
222 - (void)mouseMoved:(NSEvent *)o_event
224     NSPoint ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
225     if ([self mouse: ml inRect: [self bounds]])
226         [[VLCMain sharedInstance] showFullscreenController];
228     [super mouseMoved: o_event];
231 - (void)resetScrollWheelDirection
233     i_lastScrollWheelDirection = 0;
234     f_cumulatedXScrollValue = f_cumulatedYScrollValue = 0.;
235     msg_Dbg(getIntf(), "Reset scrolling timer");
238 - (void)scrollWheel:(NSEvent *)theEvent
240     const CGFloat f_xThreshold = 0.8;
241     const CGFloat f_yThreshold = 1.0;
242     const CGFloat f_directionThreshold = 0.05;
244     intf_thread_t * p_intf = getIntf();
245     CGFloat f_deltaX = [theEvent deltaX];
246     CGFloat f_deltaY = [theEvent deltaY];
248     if ([theEvent isDirectionInvertedFromDevice]) {
249         f_deltaX = -f_deltaX;
250         f_deltaY = -f_deltaY;
251     }
253     CGFloat f_deltaXAbs = ABS(f_deltaX);
254     CGFloat f_deltaYAbs = ABS(f_deltaY);
256     // A mouse scroll wheel has lower sensitivity. We want to scroll at least
257     // with every event here.
258     BOOL isMouseScrollWheel = ([theEvent subtype] == NSMouseEventSubtype);
259     if (isMouseScrollWheel && f_deltaYAbs < f_yThreshold)
260         f_deltaY = f_deltaY > 0. ? f_yThreshold : -f_yThreshold;
262     if (isMouseScrollWheel && f_deltaXAbs < f_xThreshold)
263         f_deltaX = f_deltaX > 0. ? f_xThreshold : -f_xThreshold;
265     /* in the following, we're forwarding either a x or a y event */
266     /* Multiple key events are send depending on the intensity of the event */
267     /* the opposite direction is being blocked for a couple of milli seconds */
268     if (f_deltaYAbs > f_directionThreshold) {
269         if (i_lastScrollWheelDirection < 0) // last was a X
270             return;
271         i_lastScrollWheelDirection = 1; // Y
273         f_cumulatedYScrollValue += f_deltaY;
274         int key = f_cumulatedYScrollValue < 0.0f ? KEY_MOUSEWHEELDOWN : KEY_MOUSEWHEELUP;
276         while (ABS(f_cumulatedYScrollValue) >= f_yThreshold) {
277             f_cumulatedYScrollValue -= (f_cumulatedYScrollValue > 0 ? f_yThreshold : -f_yThreshold);
278             var_SetInteger(p_intf->obj.libvlc, "key-pressed", key);
279             msg_Dbg(p_intf, "Scrolling in y direction");
280         }
282     } else if (f_deltaXAbs > f_directionThreshold) {
283         if (i_lastScrollWheelDirection > 0) // last was a Y
284             return;
285         i_lastScrollWheelDirection = -1; // X
287         f_cumulatedXScrollValue += f_deltaX;
288         int key = f_cumulatedXScrollValue < 0.0f ? KEY_MOUSEWHEELRIGHT : KEY_MOUSEWHEELLEFT;
290         while (ABS(f_cumulatedXScrollValue) >= f_xThreshold) {
291             f_cumulatedXScrollValue -= (f_cumulatedXScrollValue > 0 ? f_xThreshold : -f_xThreshold);
292             var_SetInteger(p_intf->obj.libvlc, "key-pressed", key);
293             msg_Dbg(p_intf, "Scrolling in x direction");
294         }
295     }
297     if (p_scrollTimer) {
298         [p_scrollTimer invalidate];
299         p_scrollTimer = nil;
300     }
301     p_scrollTimer = [NSTimer scheduledTimerWithTimeInterval:0.4 target:self selector:@selector(resetScrollWheelDirection) userInfo:nil repeats:NO];
304 #pragma mark -
305 #pragma mark Handling of vout related actions
307 - (void)setVoutThread:(vout_thread_t *)p_vout_thread
309     assert(p_vout == NULL);
310     p_vout = p_vout_thread;
311     vlc_object_hold(p_vout);
314 - (vout_thread_t *)voutThread
316     if (p_vout) {
317         vlc_object_hold(p_vout);
318         return p_vout;
319     }
321     return NULL;
324 - (void)releaseVoutThread
326     if (p_vout) {
327         vlc_object_release(p_vout);
328         p_vout = NULL;
329     }
332 #pragma mark -
333 #pragma mark Basic view behaviour and touch events handling
335 - (BOOL)mouseDownCanMoveWindow
337     return YES;
340 - (BOOL)acceptsFirstResponder
342     return YES;
345 - (BOOL)becomeFirstResponder
347     return YES;
350 - (BOOL)resignFirstResponder
352     /* while we need to be the first responder most of the time, we need to give up that status when toggling the playlist */
353     return YES;
356 -(void)didAddSubview:(NSView *)subview
358     [[self window] makeFirstResponder: subview];
361 - (void)magnifyWithEvent:(NSEvent *)event
363     f_cumulated_magnification += [event magnification];
365     // This is the result of [NSEvent standardMagnificationThreshold].
366     // Unfortunately, this is a private API, currently.
367     CGFloat f_threshold = 0.3;
368     BOOL b_fullscreen = [(VLCVideoWindowCommon *)[self window] fullscreen];
370     if ((f_cumulated_magnification > f_threshold && !b_fullscreen) || (f_cumulated_magnification < -f_threshold && b_fullscreen)) {
371         f_cumulated_magnification = 0.0;
372         [[VLCCoreInteraction sharedInstance] toggleFullscreen];
373     }
376 - (void)beginGestureWithEvent:(NSEvent *)event
378     f_cumulated_magnification = 0.0;
381 @end