You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
11 KiB
369 lines
11 KiB
/*****************************************************************************
|
|
* VLCVoutView.m: MacOS X video output module
|
|
*****************************************************************************
|
|
* Copyright (C) 2002-2014 VLC authors and VideoLAN
|
|
* $Id$
|
|
*
|
|
* Authors: Derk-Jan Hartman <hartman at videolan dot org>
|
|
* Eric Petit <titer@m0k.org>
|
|
* Benjamin Pracht <bigben at videolan dot org>
|
|
* Pierre d'Herbemont <pdherbemont # videolan org>
|
|
* Felix Paul Kühne <fkuehne at videolan dot org>
|
|
* David Fuhrmann <david dot fuhrmann at googlemail dot com>
|
|
*
|
|
* 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.
|
|
*
|
|
* 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
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* Preamble
|
|
*****************************************************************************/
|
|
#import <stdlib.h> /* free() */
|
|
|
|
#import "CompatibilityFixes.h"
|
|
#import "intf.h"
|
|
#import "VLCVoutView.h"
|
|
#import "VLCCoreInteraction.h"
|
|
#import "VLCMainMenu.h"
|
|
|
|
#import <QuartzCore/QuartzCore.h>
|
|
|
|
#import <vlc_keys.h>
|
|
|
|
|
|
/*****************************************************************************
|
|
* VLCVoutView implementation
|
|
*****************************************************************************/
|
|
@interface VLCVoutView()
|
|
{
|
|
NSInteger i_lastScrollWheelDirection;
|
|
NSTimeInterval t_lastScrollEvent;
|
|
|
|
CGFloat f_cumulated_magnification;
|
|
|
|
vout_thread_t *p_vout;
|
|
}
|
|
@end
|
|
|
|
@implementation VLCVoutView
|
|
|
|
#pragma mark -
|
|
#pragma mark drag & drop support
|
|
|
|
- (void)dealloc
|
|
{
|
|
if (p_vout)
|
|
vlc_object_release(p_vout);
|
|
|
|
[self unregisterDraggedTypes];
|
|
}
|
|
|
|
-(id)initWithFrame:(NSRect)frameRect
|
|
{
|
|
if (self = [super initWithFrame:frameRect]) {
|
|
[self registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
|
|
}
|
|
|
|
i_lastScrollWheelDirection = 0;
|
|
f_cumulated_magnification = 0.0;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (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];
|
|
}
|
|
|
|
- (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
|
|
{
|
|
BOOL b_returned = [[VLCCoreInteraction sharedInstance] performDragOperation:sender];
|
|
|
|
[self setNeedsDisplay:YES];
|
|
return b_returned;
|
|
}
|
|
|
|
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
|
|
{
|
|
[self setNeedsDisplay:YES];
|
|
}
|
|
|
|
#pragma mark -
|
|
#pragma mark vout actions
|
|
|
|
- (void)keyDown:(NSEvent *)o_event
|
|
{
|
|
unichar key = 0;
|
|
vlc_value_t val;
|
|
unsigned int i_pressed_modifiers = 0;
|
|
val.i_int = 0;
|
|
|
|
i_pressed_modifiers = [o_event modifierFlags];
|
|
|
|
if (i_pressed_modifiers & NSShiftKeyMask)
|
|
val.i_int |= KEY_MODIFIER_SHIFT;
|
|
if (i_pressed_modifiers & NSControlKeyMask)
|
|
val.i_int |= KEY_MODIFIER_CTRL;
|
|
if (i_pressed_modifiers & NSAlternateKeyMask)
|
|
val.i_int |= KEY_MODIFIER_ALT;
|
|
if (i_pressed_modifiers & NSCommandKeyMask)
|
|
val.i_int |= KEY_MODIFIER_COMMAND;
|
|
|
|
NSString * characters = [o_event charactersIgnoringModifiers];
|
|
if ([characters length] > 0) {
|
|
key = [[characters lowercaseString] characterAtIndex: 0];
|
|
|
|
if (key) {
|
|
/* Escape should always get you out of fullscreen */
|
|
if (key == (unichar) 0x1b) {
|
|
playlist_t * p_playlist = pl_Get(getIntf());
|
|
if (var_GetBool(p_playlist, "fullscreen"))
|
|
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
|
|
}
|
|
/* handle Lion's default key combo for fullscreen-toggle in addition to our own hotkeys */
|
|
else if (key == 'f' && i_pressed_modifiers & NSControlKeyMask && i_pressed_modifiers & NSCommandKeyMask)
|
|
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
|
|
else if (p_vout) {
|
|
val.i_int |= (int)CocoaKeyToVLC(key);
|
|
var_Set(p_vout->obj.libvlc, "key-pressed", val);
|
|
}
|
|
else
|
|
msg_Dbg(getIntf(), "could not send keyevent to VLC core");
|
|
|
|
return;
|
|
}
|
|
}
|
|
[super keyDown: o_event];
|
|
}
|
|
|
|
- (BOOL)performKeyEquivalent:(NSEvent *)o_event
|
|
{
|
|
return [[[VLCMain sharedInstance] mainWindow] performKeyEquivalent: o_event];
|
|
}
|
|
|
|
- (void)mouseDown:(NSEvent *)o_event
|
|
{
|
|
if (([o_event type] == NSLeftMouseDown) && (! ([o_event modifierFlags] & NSControlKeyMask))) {
|
|
if ([o_event clickCount] == 2)
|
|
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
|
|
|
|
} else if (([o_event type] == NSRightMouseDown) ||
|
|
(([o_event type] == NSLeftMouseDown) &&
|
|
([o_event modifierFlags] & NSControlKeyMask)))
|
|
[NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
|
|
|
|
[super mouseDown: o_event];
|
|
}
|
|
|
|
- (void)rightMouseDown:(NSEvent *)o_event
|
|
{
|
|
if ([o_event type] == NSRightMouseDown)
|
|
[NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
|
|
|
|
[super mouseDown: o_event];
|
|
}
|
|
|
|
- (void)rightMouseUp:(NSEvent *)o_event
|
|
{
|
|
if ([o_event type] == NSRightMouseUp)
|
|
[NSMenu popUpContextMenu: [[[VLCMain sharedInstance] mainMenu] voutMenu] withEvent: o_event forView: self];
|
|
|
|
[super mouseUp: o_event];
|
|
}
|
|
|
|
- (void)mouseMoved:(NSEvent *)o_event
|
|
{
|
|
NSPoint ml = [self convertPoint: [o_event locationInWindow] fromView: nil];
|
|
if ([self mouse: ml inRect: [self bounds]])
|
|
[[VLCMain sharedInstance] showFullscreenController];
|
|
|
|
[super mouseMoved: o_event];
|
|
}
|
|
|
|
- (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
|
|
{
|
|
intf_thread_t * p_intf = getIntf();
|
|
CGFloat f_deltaX = [theEvent deltaX];
|
|
CGFloat f_deltaY = [theEvent deltaY];
|
|
|
|
if ([theEvent isDirectionInvertedFromDevice]) {
|
|
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;
|
|
|
|
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++)
|
|
var_SetInteger(p_intf->obj.libvlc, "key-pressed", i_yvlckey);
|
|
|
|
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++)
|
|
var_SetInteger(p_intf->obj.libvlc, "key-pressed", i_xvlckey);
|
|
|
|
t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
|
|
[self performSelector:@selector(resetScrollWheelDirection)
|
|
withObject: NULL
|
|
afterDelay:1.00];
|
|
}
|
|
}
|
|
|
|
#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
|
|
|
|
- (BOOL)mouseDownCanMoveWindow
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)acceptsFirstResponder
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)becomeFirstResponder
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)resignFirstResponder
|
|
{
|
|
/* 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;
|
|
}
|
|
|
|
-(void)didAddSubview:(NSView *)subview
|
|
{
|
|
[[self window] makeFirstResponder: subview];
|
|
}
|
|
|
|
- (void)magnifyWithEvent:(NSEvent *)event
|
|
{
|
|
f_cumulated_magnification += [event magnification];
|
|
|
|
// This is the result of [NSEvent standardMagnificationThreshold].
|
|
// Unfortunately, this is a private API, currently.
|
|
CGFloat f_threshold = 0.3;
|
|
BOOL b_fullscreen = [(VLCVideoWindowCommon *)[self window] fullscreen];
|
|
|
|
if ((f_cumulated_magnification > f_threshold && !b_fullscreen) || (f_cumulated_magnification < -f_threshold && b_fullscreen)) {
|
|
f_cumulated_magnification = 0.0;
|
|
[[VLCCoreInteraction sharedInstance] toggleFullscreen];
|
|
}
|
|
}
|
|
|
|
- (void)beginGestureWithEvent:(NSEvent *)event
|
|
{
|
|
f_cumulated_magnification = 0.0;
|
|
}
|
|
|
|
@end
|
|
|