summaryrefslogtreecommitdiffstats
path: root/video/out/cocoa
diff options
context:
space:
mode:
authorStefano Pigozzi <stefano.pigozzi@gmail.com>2013-09-03 21:18:28 +0200
committerStefano Pigozzi <stefano.pigozzi@gmail.com>2013-09-28 11:20:00 +0200
commit0ab9634eb3f3005c37a0346d9035dbc4d4abd144 (patch)
tree2bd5dbd469772067a4549fb1afafa04d223624f9 /video/out/cocoa
parent0e68ff4fad174d73c6e7ab82ead36f9209fb66a2 (diff)
downloadmpv-0ab9634eb3f3005c37a0346d9035dbc4d4abd144.tar.bz2
mpv-0ab9634eb3f3005c37a0346d9035dbc4d4abd144.tar.xz
cocoa_common: split the code, refactoring and cleanups
Split the code to several files. The GUI elements now each have they own files and private state. The original code was a mess to respect the retarded mplayer convention of having everything in a single file. This commit also seems to fix the long running bug of artifacts showing randomly when going fullscreen using nVidia GPUs.
Diffstat (limited to 'video/out/cocoa')
-rw-r--r--video/out/cocoa/additions.h27
-rw-r--r--video/out/cocoa/additions.m51
-rw-r--r--video/out/cocoa/mpvadapter.h32
-rw-r--r--video/out/cocoa/view.h30
-rw-r--r--video/out/cocoa/view.m213
-rw-r--r--video/out/cocoa/window.h34
-rw-r--r--video/out/cocoa/window.m161
7 files changed, 548 insertions, 0 deletions
diff --git a/video/out/cocoa/additions.h b/video/out/cocoa/additions.h
new file mode 100644
index 0000000000..8c237c9a40
--- /dev/null
+++ b/video/out/cocoa/additions.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface NSScreen (mpvadditions)
+- (BOOL)hasDock;
+- (BOOL)hasMenubar;
+@end
+
+@interface NSEvent (mpvadditions)
+- (int)mpvButtonNumber;
+@end
diff --git a/video/out/cocoa/additions.m b/video/out/cocoa/additions.m
new file mode 100644
index 0000000000..3caabef956
--- /dev/null
+++ b/video/out/cocoa/additions.m
@@ -0,0 +1,51 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import "additions.h"
+
+@implementation NSScreen (mpvadditions)
+- (BOOL)hasDock
+{
+ NSRect vF = [self visibleFrame];
+ NSRect f = [self frame];
+ return
+ // The visible frame's width is smaller: dock is on left or right end
+ // of this method's receiver.
+ vF.size.width < f.size.width ||
+ // The visible frame's veritical origin is bigger: dock is
+ // on the bottom of this method's receiver.
+ vF.origin.y > f.origin.y;
+
+}
+
+- (BOOL)hasMenubar
+{
+ return [self isEqual: [NSScreen screens][0]];
+}
+@end
+
+@implementation NSEvent (mpvadditions)
+- (int)mpvButtonNumber
+{
+ int buttonNumber = [self buttonNumber];
+ switch (buttonNumber) {
+ case 1: return 2;
+ case 2: return 1;
+ default: return buttonNumber;
+ }
+}
+@end
diff --git a/video/out/cocoa/mpvadapter.h b/video/out/cocoa/mpvadapter.h
new file mode 100644
index 0000000000..eafeefce9f
--- /dev/null
+++ b/video/out/cocoa/mpvadapter.h
@@ -0,0 +1,32 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import <Cocoa/Cocoa.h>
+#include "video/out/vo.h"
+
+@interface MpvCocoaAdapter : NSObject
+- (void)setNeedsResize;
+- (void)signalMouseMovement:(NSPoint)point;
+- (void)putKey:(int)mpkey withModifiers:(int)modifiers;
+- (void)putAxis:(int)mpkey delta:(float)delta;
+- (void)performAsyncResize:(NSSize)size;
+
+- (BOOL)isInFullScreenMode;
+- (NSSize)videoSize;
+- (NSScreen *)fsScreen;
+@property(nonatomic, assign) struct vo *vout;
+@end
diff --git a/video/out/cocoa/view.h b/video/out/cocoa/view.h
new file mode 100644
index 0000000000..71d58a3348
--- /dev/null
+++ b/video/out/cocoa/view.h
@@ -0,0 +1,30 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "video/out/cocoa/mpvadapter.h"
+
+@interface MpvVideoView : NSView {
+ BOOL hasMouseDown;
+}
+@property(nonatomic, retain) MpvCocoaAdapter *adapter;
+@property(nonatomic, retain) NSTrackingArea *tracker;
+- (void)setFullScreen:(BOOL)willBeFullscreen;
+- (NSRect)frameInPixels;
+- (BOOL)canHideCursor;
+- (void)signalMousePosition;
+@end
diff --git a/video/out/cocoa/view.m b/video/out/cocoa/view.m
new file mode 100644
index 0000000000..bac485b225
--- /dev/null
+++ b/video/out/cocoa/view.m
@@ -0,0 +1,213 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libavutil/common.h>
+
+#include "mpvcore/input/input.h"
+#include "mpvcore/input/keycodes.h"
+
+#include "osdep/macosx_compat.h"
+#include "video/out/cocoa_common.h"
+#import "video/out/cocoa/additions.h"
+
+#include "view.h"
+
+@implementation MpvVideoView
+@synthesize adapter = _adapter;
+@synthesize tracker = _tracker;
+
+- (void)setFullScreen:(BOOL)willBeFullscreen
+{
+ if (willBeFullscreen && ![self isInFullScreenMode]) {
+ NSApplicationPresentationOptions popts =
+ NSApplicationPresentationDefault;
+
+ if ([[self.adapter fsScreen] hasMenubar])
+ // Cocoa raises an exception when autohiding the menubar but
+ // not the dock. They probably got bored while programming the
+ // multi screen support and took some shortcuts (tested on 10.8).
+ popts |= NSApplicationPresentationAutoHideMenuBar |
+ NSApplicationPresentationAutoHideDock;
+
+ if ([[self.adapter fsScreen] hasDock])
+ popts |= NSApplicationPresentationAutoHideDock;
+
+ NSDictionary *fsopts = @{
+ NSFullScreenModeAllScreens : @NO,
+ NSFullScreenModeApplicationPresentationOptions : @(popts)
+ };
+
+ // The original "windowed" window will stay around since sending a
+ // view fullscreen wraps it in another window. This is noticeable when
+ // sending the View fullscreen to another screen. Make it go away
+ // manually.
+ [self.window orderOut:self];
+
+ [self enterFullScreenMode:[self.adapter fsScreen]
+ withOptions:fsopts];
+ }
+
+ if (!willBeFullscreen && [self isInFullScreenMode]) {
+ [self exitFullScreenModeWithOptions:nil];
+
+ // Show the "windowed" window again.
+ [self.window makeKeyAndOrderFront:self];
+ [self.window makeFirstResponder:self];
+ }
+}
+
+// mpv uses flipped coordinates, because X11 uses those. So let's just use them
+// as well without having to do any coordinate conversion of mouse positions.
+- (BOOL)isFlipped { return YES; }
+
+- (void)updateTrackingAreas
+{
+ if (self.tracker) [self removeTrackingArea:self.tracker];
+
+ NSTrackingAreaOptions trackingOptions =
+ NSTrackingEnabledDuringMouseDrag |
+ NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved |
+ NSTrackingActiveAlways;
+
+ self.tracker =
+ [[[NSTrackingArea alloc] initWithRect:[self bounds]
+ options:trackingOptions
+ owner:self
+ userInfo:nil] autorelease];
+
+ [self addTrackingArea:self.tracker];
+}
+
+- (NSPoint)mouseLocation
+{
+ NSPoint wLoc = [self.window mouseLocationOutsideOfEventStream];
+ return [self convertPoint:wLoc fromView:nil];
+}
+
+- (BOOL)containsMouseLocation
+{
+ NSRect vF = [[self.window screen] visibleFrame];
+ NSRect vFW = [self.window convertRectFromScreen:vF];
+ NSRect vFV = [self convertRect:vFW fromView:nil];
+
+ // clip bounds to current visibleFrame
+ NSRect clippedBounds = CGRectIntersection([self bounds], vFV);
+ return CGRectContainsPoint(clippedBounds, [self mouseLocation]);
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { return YES; }
+- (BOOL)acceptsFirstResponder { return YES; }
+- (BOOL)becomeFirstResponder { return YES; }
+- (BOOL)resignFirstResponder { return YES; }
+
+- (NSRect)frameInPixels
+{
+ return [self convertRectToBacking:[self frame]];
+}
+
+- (BOOL)canHideCursor
+{
+ return !self->hasMouseDown && [self containsMouseLocation];
+}
+
+- (void)mouseEntered:(NSEvent *)event
+{
+ // do nothing!
+}
+
+- (void)mouseExited:(NSEvent *)event
+{
+ [self.adapter putKey:MP_KEY_MOUSE_LEAVE withModifiers:0];
+}
+
+- (void)setFrameSize:(NSSize)size
+{
+ [super setFrameSize:size];
+ [self signalMousePosition];
+}
+
+- (void)signalMousePosition
+{
+ NSPoint p = [self convertPoint:[self mouseLocation] fromView:nil];
+ [self.adapter signalMouseMovement:p];
+}
+
+- (void)signalMouseMovement:(NSEvent *)event
+{
+ NSPoint p = [self convertPoint:[event locationInWindow] fromView:nil];
+ [self.adapter signalMouseMovement:p];
+}
+
+- (void)mouseMoved:(NSEvent *)event { [self signalMouseMovement:event]; }
+- (void)mouseDragged:(NSEvent *)event { [self signalMouseMovement:event]; }
+- (void)mouseDown:(NSEvent *)evt { [self mouseDownEvent:evt]; }
+- (void)mouseUp:(NSEvent *)evt { [self mouseUpEvent:evt]; }
+- (void)rightMouseDown:(NSEvent *)evt { [self mouseDownEvent:evt]; }
+- (void)rightMouseUp:(NSEvent *)evt { [self mouseUpEvent:evt]; }
+- (void)otherMouseDown:(NSEvent *)evt { [self mouseDownEvent:evt]; }
+- (void)otherMouseUp:(NSEvent *)evt { [self mouseUpEvent:evt]; }
+
+- (void)scrollWheel:(NSEvent *)event
+{
+ CGFloat delta;
+ int cmd;
+
+ if (FFABS([event deltaY]) >= FFABS([event deltaX])) {
+ delta = [event deltaY] * 0.1;
+ cmd = delta > 0 ? MP_AXIS_UP : MP_AXIS_DOWN;
+ delta = FFABS(delta);
+ } else {
+ delta = [event deltaX] * 0.1;
+ cmd = delta > 0 ? MP_AXIS_RIGHT : MP_AXIS_LEFT;
+ delta = FFABS(delta);
+ }
+
+ if ([event hasPreciseScrollingDeltas]) {
+ [self.adapter putAxis:cmd delta:delta];
+ } else {
+ const int modifiers = [event modifierFlags];
+ const int mpkey = delta > 0 ? MP_MOUSE_BTN3 : MP_MOUSE_BTN4;
+ [self.adapter putKey:mpkey withModifiers:modifiers];
+ }
+}
+
+- (void)mouseDownEvent:(NSEvent *)event
+{
+ [self putMouseEvent:event withState:MP_KEY_STATE_DOWN];
+
+ if ([event clickCount] > 1)
+ [self putMouseEvent:event withState:MP_KEY_STATE_UP];
+}
+
+- (void)mouseUpEvent:(NSEvent *)event
+{
+ [self putMouseEvent:event withState:MP_KEY_STATE_UP];
+}
+
+- (void)putMouseEvent:(NSEvent *)event withState:(int)state
+{
+ self->hasMouseDown = (state == MP_KEY_STATE_DOWN);
+ int mpkey = (MP_MOUSE_BTN0 + [event mpvButtonNumber]);
+ [self.adapter putKey:(mpkey | state) withModifiers:[event modifierFlags]];
+}
+
+- (void)drawRect:(NSRect)rect
+{
+ [self.adapter performAsyncResize:[self frameInPixels].size];
+ [self.adapter setNeedsResize];
+}
+@end
diff --git a/video/out/cocoa/window.h b/video/out/cocoa/window.h
new file mode 100644
index 0000000000..d6c753cc1b
--- /dev/null
+++ b/video/out/cocoa/window.h
@@ -0,0 +1,34 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import <Cocoa/Cocoa.h>
+#import "video/out/cocoa/mpvadapter.h"
+
+@interface MpvVideoWindow : NSWindow <NSWindowDelegate>
+@property(nonatomic, retain) MpvCocoaAdapter *adapter;
+- (void)setFullScreen:(BOOL)willBeFullscreen;
+- (BOOL)canBecomeKeyWindow;
+- (BOOL)canBecomeMainWindow;
+- (void)mulSize:(float)multiplier;
+- (void)setCenteredContentSize:(NSSize)newSize;
+
+- (void)queueNewVideoSize:(NSSize)newSize;
+- (void)dispatchNewVideoSize;
+
+// This really needs to use KVO
+- (void)didChangeFullScreenState;
+@end
diff --git a/video/out/cocoa/window.m b/video/out/cocoa/window.m
new file mode 100644
index 0000000000..fa51b8d82a
--- /dev/null
+++ b/video/out/cocoa/window.m
@@ -0,0 +1,161 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "mpvcore/input/keycodes.h"
+
+#include "osdep/macosx_application.h"
+#include "osdep/macosx_events.h"
+#include "osdep/macosx_compat.h"
+
+#include "video/out/cocoa/additions.h"
+#include "video/out/cocoa_common.h"
+
+#include "window.h"
+
+@implementation MpvVideoWindow {
+ NSSize _queued_video_size;
+ bool _fs_resize_scheduled;
+}
+
+@synthesize adapter = _adapter;
+- (id)initWithContentRect:(NSRect)content_rect
+ styleMask:(NSUInteger)style_mask
+ backing:(NSBackingStoreType)buffering_type
+ defer:(BOOL)flag
+{
+ if (self = [super initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:buffering_type
+ defer:flag]) {
+ [self setBackgroundColor:[NSColor blackColor]];
+ }
+ return self;
+}
+
+- (void)windowDidResize:(NSNotification *) notification
+{
+ [self.adapter setNeedsResize];
+}
+
+- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
+ [self.adapter setNeedsResize];
+}
+
+- (BOOL)isInFullScreenMode
+{
+ return (([self styleMask] & NSFullScreenWindowMask) ==
+ NSFullScreenWindowMask);
+}
+
+- (void)setFullScreen:(BOOL)willBeFullscreen
+{
+ if (willBeFullscreen && ![self isInFullScreenMode]) {
+ [self setContentResizeIncrements:NSMakeSize(1, 1)];
+ [self toggleFullScreen:nil];
+ }
+
+ if (!willBeFullscreen && [self isInFullScreenMode]) {
+ [self setContentAspectRatio:self->_queued_video_size];
+ [self toggleFullScreen:nil];
+ }
+
+}
+
+- (BOOL)canBecomeMainWindow { return YES; }
+- (BOOL)canBecomeKeyWindow { return YES; }
+- (BOOL)windowShouldClose:(id)sender
+{
+ cocoa_put_key(MP_KEY_CLOSE_WIN);
+ // We have to wait for MPlayer to handle this,
+ // otherwise we are in trouble if the
+ // MP_KEY_CLOSE_WIN handler is disabled
+ return NO;
+}
+
+- (void)normalSize { [self mulSize:1.0f]; }
+
+- (void)halfSize { [self mulSize:0.5f];}
+
+- (void)doubleSize { [self mulSize:2.0f];}
+
+- (void)mulSize:(float)multiplier
+{
+ if (![self.adapter isInFullScreenMode]) {
+ NSSize size = [self.adapter videoSize];
+ size.width *= multiplier;
+ size.height *= multiplier;
+ [self setCenteredContentSize:size];
+ }
+}
+
+- (int)titleHeight
+{
+ NSRect of = [self frame];
+ NSRect cb = [[self contentView] bounds];
+ return of.size.height - cb.size.height;
+}
+
+- (void)setCenteredContentSize:(NSSize)ns
+{
+ NSRect f = [self frame];
+ CGFloat dx = (f.size.width - ns.width) / 2;
+ CGFloat dy = (f.size.height - ns.height - [self titleHeight]) / 2;
+ NSRect nf = NSRectFromCGRect(CGRectInset(NSRectToCGRect(f), dx, dy));
+ [self setFrame:nf display:NO animate:NO];
+}
+
+- (NSRect)constrainFrameRect:(NSRect)nf toScreen:(NSScreen *)screen
+{
+ NSRect s = [[self screen] visibleFrame];
+ if (nf.origin.y + nf.size.height > s.origin.y + s.size.height)
+ nf.origin.y = s.origin.y + s.size.height - nf.size.height;
+ return nf;
+}
+
+- (void)queueNewVideoSize:(NSSize)new_size
+{
+ NSSize prev_size = self->_queued_video_size;
+ self->_queued_video_size = new_size;
+
+ if (!CGSizeEqualToSize(prev_size, new_size))
+ [self dispatchNewVideoSize];
+}
+
+- (void)dispatchNewVideoSize
+{
+ if ([self.adapter isInFullScreenMode]) {
+ self->_fs_resize_scheduled = true;
+ } else {
+ [self applyNewVideoSize];
+ }
+}
+
+- (void)applyNewVideoSize
+{
+ [self setCenteredContentSize:self->_queued_video_size];
+ [self setContentAspectRatio:self->_queued_video_size];
+}
+
+- (void)didChangeFullScreenState
+{
+ if (![self.adapter isInFullScreenMode] && self->_fs_resize_scheduled) {
+ self->_fs_resize_scheduled = false;
+ [self applyNewVideoSize];
+ }
+}
+@end
+