VideoView.m 10.6 KB
Newer Older
1
/*****************************************************************************
2
 * VideoView.m: MacOS X video output module
3
 *****************************************************************************
4
 * Copyright (C) 2002-2014 VLC authors and VideoLAN
Benjamin Pracht's avatar
...  
Benjamin Pracht committed
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 15 16 17
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
18
 *
19 20 21 22 23 24 25
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
26
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 28 29 30 31
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
32 33
#import <stdlib.h>                                                 /* free() */

34
#import "CompatibilityFixes.h"
35
#import "intf.h"
36
#import "VideoView.h"
37
#import "VLCCoreInteraction.h"
David Fuhrmann's avatar
David Fuhrmann committed
38
#import "VLCMainMenu.h"
39

40 41
#import <QuartzCore/QuartzCore.h>

42
#import <vlc_keys.h>
43

44

45 46 47
/*****************************************************************************
 * VLCVoutView implementation
 *****************************************************************************/
48 49 50 51 52 53 54 55 56 57 58
@interface VLCVoutView()
{
    NSInteger i_lastScrollWheelDirection;
    NSTimeInterval t_lastScrollEvent;

    CGFloat f_cumulated_magnification;

    vout_thread_t *p_vout;
}
@end

59
@implementation VLCVoutView
60 61 62 63 64 65

#pragma mark -
#pragma mark drag & drop support

- (void)dealloc
{
66 67 68
    if (p_vout)
        vlc_object_release(p_vout);

69 70 71
    [self unregisterDraggedTypes];
}

72
-(id)initWithFrame:(NSRect)frameRect
73
{
74
    if (self = [super initWithFrame:frameRect]) {
75
        [self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
76
    }
77

78
    i_lastScrollWheelDirection = 0;
79
    f_cumulated_magnification = 0.0;
80 81

    return self;
82 83
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
- (void)addVoutLayer:(CALayer *)aLayer
{
    if (self.layer == nil) {
        [self setLayer:[CALayer layer]];
        [self setWantsLayer:YES];
    }

    [CATransaction begin];
    aLayer.opaque = 1.;
    aLayer.hidden = NO;
    aLayer.bounds = self.layer.bounds;
    [self.layer addSublayer:aLayer];
    [self setNeedsDisplay:YES];
    [aLayer setNeedsDisplay];
    CGRect frame = aLayer.bounds;
    frame.origin.x = frame.origin.y = 0.;
    aLayer.frame = frame;
    [CATransaction commit];
}

- (void)removeVoutLayer:(CALayer *)aLayer
{
    [CATransaction begin];
    [aLayer removeFromSuperlayer];
    [CATransaction commit];
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
{
    if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) == NSDragOperationGeneric)
        return NSDragOperationGeneric;
    return NSDragOperationNone;
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
    return YES;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
David Fuhrmann's avatar
David Fuhrmann committed
125
    BOOL b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation:sender];
126 127 128 129 130 131 132 133 134 135 136 137 138

    [self setNeedsDisplay:YES];
    return b_returned;
}

- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
    [self setNeedsDisplay:YES];
}

#pragma mark -
#pragma mark vout actions

139 140 141
- (void)keyDown:(NSEvent *)o_event
{
    unichar key = 0;
142
    vlc_value_t val;
143
    unsigned int i_pressed_modifiers = 0;
144
    val.i_int = 0;
145

146
    i_pressed_modifiers = [o_event modifierFlags];
147

148
    if (i_pressed_modifiers & NSShiftKeyMask)
149
        val.i_int |= KEY_MODIFIER_SHIFT;
150
    if (i_pressed_modifiers & NSControlKeyMask)
151
        val.i_int |= KEY_MODIFIER_CTRL;
152
    if (i_pressed_modifiers & NSAlternateKeyMask)
153
        val.i_int |= KEY_MODIFIER_ALT;
154
    if (i_pressed_modifiers & NSCommandKeyMask)
155
        val.i_int |= KEY_MODIFIER_COMMAND;
156

157
    NSString * characters = [o_event charactersIgnoringModifiers];
158
    if ([characters length] > 0) {
159 160
        key = [[characters lowercaseString] characterAtIndex: 0];

161
        if (key) {
162
            /* Escape should always get you out of fullscreen */
163
            if (key == (unichar) 0x1b) {
164
                playlist_t * p_playlist = pl_Get(getIntf());
165
                 if (var_GetBool(p_playlist, "fullscreen"))
166
                     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
167
            }
168
            /* handle Lion's default key combo for fullscreen-toggle in addition to our own hotkeys */
169
            else if (key == 'f' && i_pressed_modifiers & NSControlKeyMask && i_pressed_modifiers & NSCommandKeyMask)
170
                [[VLCCoreInteraction sharedInstance] toggleFullscreen];
171
            else if (p_vout) {
172
                val.i_int |= (int)CocoaKeyToVLC(key);
173
                var_Set(p_vout->obj.libvlc, "key-pressed", val);
174
            }
175
            else
176
                msg_Dbg(getIntf(), "could not send keyevent to VLC core");
177

178 179
            return;
        }
180
    }
181
    [super keyDown: o_event];
182 183
}

184 185
- (BOOL)performKeyEquivalent:(NSEvent *)o_event
{
186
    return [[[VLCMain sharedInstance] mainWindow] performKeyEquivalent: o_event];
187 188
}

189
- (void)mouseDown:(NSEvent *)o_event
190
{
191
    if (([o_event type] == NSLeftMouseDown) && (! ([o_event modifierFlags] &  NSControlKeyMask))) {
192
        if ([o_event clickCount] == 2)
193
            [[VLCCoreInteraction sharedInstance] toggleFullscreen];
194

195 196 197
    } else if (([o_event type] == NSRightMouseDown) ||
               (([o_event type] == NSLeftMouseDown) &&
               ([o_event modifierFlags] &  NSControlKeyMask)))
198
        [NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
199 200

    [super mouseDown: o_event];
201 202 203 204
}

- (void)rightMouseDown:(NSEvent *)o_event
{
205
    if ([o_event type] == NSRightMouseDown)
206
        [NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
207 208

    [super mouseDown: o_event];
209 210 211 212
}

- (void)rightMouseUp:(NSEvent *)o_event
{
213
    if ([o_event type] == NSRightMouseUp)
214
        [NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
215 216

    [super mouseUp: o_event];
217 218 219 220
}

- (void)mouseMoved:(NSEvent *)o_event
{
221
    NSPoint ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
222
    if ([self mouse: ml inRect: [self bounds]])
223 224
        [[VLCMain sharedInstance] showFullscreenController];

225
    [super mouseMoved: o_event];
226 227
}

228 229 230 231 232 233 234 235 236
- (void)resetScrollWheelDirection
{
    /* release the scroll direction 0.8 secs after the last event */
    if (([NSDate timeIntervalSinceReferenceDate] - t_lastScrollEvent) >= 0.80)
        i_lastScrollWheelDirection = 0;
}

- (void)scrollWheel:(NSEvent *)theEvent
{
237
    intf_thread_t * p_intf = getIntf();
238 239 240
    CGFloat f_deltaX = [theEvent deltaX];
    CGFloat f_deltaY = [theEvent deltaY];

241
    if ([theEvent isDirectionInvertedFromDevice]) {
242 243 244 245 246 247 248 249 250 251 252 253
        f_deltaX = -f_deltaX;
        f_deltaY = -f_deltaY;
    }

    CGFloat f_yabsvalue = f_deltaY > 0.0f ? f_deltaY : -f_deltaY;
    CGFloat f_xabsvalue = f_deltaX > 0.0f ? f_deltaX : -f_deltaX;

    int i_yvlckey, i_xvlckey = 0;
    if (f_deltaY < 0.0f)
        i_yvlckey = KEY_MOUSEWHEELDOWN;
    else
        i_yvlckey = KEY_MOUSEWHEELUP;
254

255 256 257 258 259 260 261 262 263 264 265 266 267 268
    if (f_deltaX < 0.0f)
        i_xvlckey = KEY_MOUSEWHEELRIGHT;
    else
        i_xvlckey = KEY_MOUSEWHEELLEFT;

    /* in the following, we're forwarding either a x or a y event */
    /* Multiple key events are send depending on the intensity of the event */
    /* the opposite direction is being blocked for 0.8 secs */
    if (f_yabsvalue > 0.05) {
        if (i_lastScrollWheelDirection < 0) // last was a X
            return;

        i_lastScrollWheelDirection = 1; // Y
        for (NSUInteger i = 0; i < (int)(f_yabsvalue/4.+1.); i++)
269
            var_SetInteger(p_intf->obj.libvlc, "key-pressed", i_yvlckey);
270 271 272 273 274 275 276 277 278 279 280 281 282

        t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
        [self performSelector:@selector(resetScrollWheelDirection)
                   withObject: NULL
                   afterDelay:1.00];
        return;
    }
    if (f_xabsvalue > 0.05) {
        if (i_lastScrollWheelDirection > 0) // last was a Y
            return;

        i_lastScrollWheelDirection = -1; // X
        for (NSUInteger i = 0; i < (int)(f_xabsvalue/6.+1.); i++)
283
            var_SetInteger(p_intf->obj.libvlc, "key-pressed", i_xvlckey);
284 285 286 287 288 289 290 291

        t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
        [self performSelector:@selector(resetScrollWheelDirection)
                   withObject: NULL
                   afterDelay:1.00];
    }
}

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
#pragma mark -
#pragma mark Handling of vout related actions

- (void)setVoutThread:(vout_thread_t *)p_vout_thread
{
    assert(p_vout == NULL);
    p_vout = p_vout_thread;
    vlc_object_hold(p_vout);
}

- (vout_thread_t *)voutThread
{
    if (p_vout) {
        vlc_object_hold(p_vout);
        return p_vout;
    }

    return NULL;
}

- (void)releaseVoutThread
{
    if (p_vout) {
        vlc_object_release(p_vout);
        p_vout = NULL;
    }
}

#pragma mark -
#pragma mark Basic view behaviour and touch events handling

323 324 325 326 327
- (BOOL)mouseDownCanMoveWindow
{
    return YES;
}

Eric Petit's avatar
Eric Petit committed
328 329 330
- (BOOL)acceptsFirstResponder
{
    return YES;
331 332
}

Eric Petit's avatar
Eric Petit committed
333
- (BOOL)becomeFirstResponder
334
{
Eric Petit's avatar
Eric Petit committed
335
    return YES;
336 337
}

Eric Petit's avatar
Eric Petit committed
338
- (BOOL)resignFirstResponder
339
{
340 341
    /* while we need to be the first responder most of the time, we need to give up that status when toggling the playlist */
    return YES;
Eric Petit's avatar
Eric Petit committed
342
}
343 344 345 346 347 348

-(void)didAddSubview:(NSView *)subview
{
    [[self window] makeFirstResponder: subview];
}

349 350 351
- (void)magnifyWithEvent:(NSEvent *)event
{
    f_cumulated_magnification += [event magnification];
352 353 354 355

    // This is the result of [NSEvent standardMagnificationThreshold].
    // Unfortunately, this is a private API, currently.
    CGFloat f_threshold = 0.3;
356
    BOOL b_fullscreen = [(VLCVideoWindowCommon *)[self window] fullscreen];
357

358
    if ((f_cumulated_magnification > f_threshold && !b_fullscreen) || (f_cumulated_magnification < -f_threshold && b_fullscreen)) {
359 360 361 362 363 364 365 366 367 368
        f_cumulated_magnification = 0.0;
        [[VLCCoreInteraction sharedInstance] toggleFullscreen];
    }
}

- (void)beginGestureWithEvent:(NSEvent *)event
{
    f_cumulated_magnification = 0.0;
}

369
@end