summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkemi <der.richter@gmx.de>2018-02-12 12:28:19 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-02-12 04:49:15 -0800
commitc5e4538bc4b63f02bf89f62aa25a37b9eb0c0316 (patch)
tree443f47ce1d584bb5fbf4fa30918e7c17cb800016
parent235eb60671c899d55b1174043940763b250fa3b8 (diff)
downloadmpv-c5e4538bc4b63f02bf89f62aa25a37b9eb0c0316.tar.bz2
mpv-c5e4538bc4b63f02bf89f62aa25a37b9eb0c0316.tar.xz
cocoa-cb: initial implementation via opengl-cb API
this is meant to replace the old and not properly working vo_gpu/opengl cocoa backend in the future. the problems are various shortcomings of Apple's opengl implementation and buggy behaviour in certain circumstances that couldn't be properly worked around. there are also certain regressions on newer macOS versions from 10.11 onwards. - awful opengl performance with a none layer backed context - huge amount of dropped frames with an early context flush - flickering of system elements like the dock or volume indicator - double buffering not properly working with a none layer backed context - bad performance in fullscreen because of system optimisations all the problems were caused by using a normal opengl context, that seems somewhat abandoned by apple, and are fixed by using a layer backed opengl context instead. problems that couldn't be fixed could be properly worked around. this has all features our old backend has sans the wid embedding, the possibility to disable the automatic GPU switching and taking screenshots of the window content. the first was deemed unnecessary by me for now, since i just use the libmpv API that others can use anyway. second is technically not possible atm because we have to pre-allocate our opengl context at a time the config isn't read yet, so we can't get the needed property. third one is a bit tricky because of deadlocking and it needed to be in sync, hopefully i can work around that in the future. this also has at least one additional feature or eye-candy. a properly working fullscreen animation with the native fs. also since this is a direct port of the old backend of the parts that could be used, though with adaptions and improvements, this looks a lot cleaner and easier to understand. some credit goes to @pigoz for the initial swift build support which i could improve upon. Fixes: #5478, #5393, #5152, #5151, #4615, #4476, #3978, #3746, #3739, #2392, #2217
-rw-r--r--DOCS/interface-changes.rst2
-rw-r--r--DOCS/man/options.rst2
-rw-r--r--DOCS/man/vo.rst4
-rw-r--r--osdep/macOS_mpv_helper.swift255
-rw-r--r--osdep/macOS_swift_bridge.h54
-rw-r--r--osdep/macosx_application.m80
-rw-r--r--osdep/macosx_application_objc.h6
-rw-r--r--osdep/macosx_events.m21
-rw-r--r--osdep/macosx_menubar.m18
-rw-r--r--player/client.c24
-rw-r--r--player/client.h10
-rw-r--r--video/out/cocoa-cb/events_view.swift266
-rw-r--r--video/out/cocoa-cb/video_layer.swift210
-rw-r--r--video/out/cocoa-cb/window.swift456
-rw-r--r--video/out/cocoa_cb_common.swift485
-rw-r--r--video/out/opengl/context_cocoa.c2
-rw-r--r--video/out/vo.h5
-rw-r--r--video/out/vo_opengl_cb.c88
-rw-r--r--waftools/checks/custom.py14
-rw-r--r--waftools/detections/compiler_swift.py71
-rw-r--r--waftools/generators/sources.py11
-rw-r--r--wscript15
-rw-r--r--wscript_build.py37
23 files changed, 2054 insertions, 82 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index da47ef6ba8..ba1a25c273 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -70,6 +70,8 @@ Interface changes
pad must be connected either to another filter, or to a video/audio track
or video/audio output). If they are disconnected at runtime, the stream
will probably stall.
+ - deprecate the OpenGL cocoa backend, option choice --gpu-context=cocoa
+ when used with --gpu-api=opengl (use --vo=opengl-cb)
--- mpv 0.28.0 ---
- rename --hwdec=mediacodec option to mediacodec-copy, to reflect
conventions followed by other hardware video decoding APIs
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index 9f0c672919..c12453ae5f 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -4876,7 +4876,7 @@ The following video options are currently all specific to ``--vo=gpu`` and
auto
auto-select (default)
cocoa
- Cocoa/OS X
+ Cocoa/OS X (deprecated, use --vo=opengl-cb instead)
win
Win32/WGL
winvk
diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst
index 20e406dd4e..d5a4ef9b26 100644
--- a/DOCS/man/vo.rst
+++ b/DOCS/man/vo.rst
@@ -429,7 +429,9 @@ Available video output drivers are:
Specify the directory to save the image files to (default: ``./``).
``opengl-cb``
- For use with libmpv direct OpenGL embedding; useless in any other contexts.
+ For use with libmpv direct OpenGL embedding. As a special case, on OS X it
+ is used like a normal VO within mpv (cocoa-cb). Otherwise useless in any
+ other contexts.
(See ``<mpv/opengl_cb.h>``.)
This also supports many of the options the ``gpu`` VO has.
diff --git a/osdep/macOS_mpv_helper.swift b/osdep/macOS_mpv_helper.swift
new file mode 100644
index 0000000000..39be9cc8c7
--- /dev/null
+++ b/osdep/macOS_mpv_helper.swift
@@ -0,0 +1,255 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import Cocoa
+import OpenGL.GL
+import OpenGL.GL3
+
+class MPVHelper: NSObject {
+
+ var mpvHandle: OpaquePointer?
+ var mpvGLCBContext: OpaquePointer?
+ var mpvLog: OpaquePointer?
+ var inputContext: OpaquePointer?
+ var mpctx: UnsafeMutablePointer<MPContext>?
+
+ init(_ mpv: OpaquePointer) {
+ super.init()
+ mpvHandle = mpv
+ mpvLog = mp_log_new(UnsafeMutablePointer<MPContext>(mpvHandle),
+ mp_client_get_log(mpvHandle), "cocoacb")
+ mpctx = UnsafeMutablePointer<MPContext>(mp_client_get_core(mpvHandle))
+ inputContext = mpctx!.pointee.input
+
+ mpv_observe_property(mpvHandle, 0, "ontop", MPV_FORMAT_FLAG)
+ mpv_observe_property(mpvHandle, 0, "border", MPV_FORMAT_FLAG)
+ mpv_observe_property(mpvHandle, 0, "keepaspect-window", MPV_FORMAT_FLAG)
+ }
+
+ func setGLCB() {
+ if mpvHandle == nil {
+ sendError("No mpv handle available.")
+ exit(1)
+ }
+ mpvGLCBContext = OpaquePointer(mp_get_sub_api2(mpvHandle, MPV_SUB_API_OPENGL_CB, false))
+ if mpvGLCBContext == nil {
+ sendError("libmpv does not have the opengl-cb sub-API.")
+ exit(1)
+ }
+ }
+
+ func initGLCB() {
+ if mpvGLCBContext == nil {
+ setGLCB()
+ }
+ if mpv_opengl_cb_init_gl(mpvGLCBContext, nil, getProcAddress, nil) < 0 {
+ sendError("GL init has failed.")
+ exit(1)
+ }
+ }
+
+ let getProcAddress: mpv_opengl_cb_get_proc_address_fn = {
+ (ctx: UnsafeMutableRawPointer?, name: UnsafePointer<Int8>?) -> UnsafeMutableRawPointer? in
+ let symbol: CFString = CFStringCreateWithCString(
+ kCFAllocatorDefault, name, kCFStringEncodingASCII)
+ let indentifier = CFBundleGetBundleWithIdentifier("com.apple.opengl" as CFString)
+ let addr = CFBundleGetFunctionPointerForName(indentifier, symbol)
+
+ if symbol as String == "glFlush" {
+ return glDummyPtr()
+ }
+
+ return addr
+ }
+
+ func setGLCBUpdateCallback(_ callback: @escaping mpv_opengl_cb_update_fn, context object: AnyObject) {
+ if mpvGLCBContext == nil {
+ sendWarning("Init mpv opengl-cb first.")
+ } else {
+ mpv_opengl_cb_set_update_callback(mpvGLCBContext, callback, MPVHelper.bridge(obj: object))
+ }
+ }
+
+ func setGLCBControlCallback(_ callback: @escaping mpv_opengl_cb_control_fn, context object: AnyObject) {
+ if mpvGLCBContext == nil {
+ sendWarning("Init mpv opengl-cb first.")
+ } else {
+ mp_client_set_control_callback(mpvGLCBContext, callback, MPVHelper.bridge(obj: object))
+ }
+ }
+
+ func reportGLCBFlip() {
+ if mpvGLCBContext == nil { return }
+ mpv_opengl_cb_report_flip(mpvGLCBContext, 0)
+ }
+
+ func drawGLCB(_ surface: NSSize) {
+ if mpvGLCBContext != nil {
+ var i: GLint = 0
+ glGetIntegerv(GLenum(GL_DRAW_FRAMEBUFFER_BINDING), &i)
+
+ mpv_opengl_cb_draw(mpvGLCBContext, i, Int32(surface.width), Int32(-surface.height))
+ } else {
+ glClearColor(0, 0, 0, 1)
+ glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
+ }
+ }
+
+ func setGLCBICCProfile(_ profile: NSColorSpace) {
+ if mpvGLCBContext == nil { return }
+ var iccData = profile.iccProfileData
+ iccData!.withUnsafeMutableBytes { (u8Ptr: UnsafeMutablePointer<UInt8>) in
+ let icc = bstrdup(nil, bstr(start: u8Ptr, len: iccData!.count))
+ mp_client_set_icc_profile(mpvGLCBContext, icc)
+ }
+ }
+
+ func setGLCBLux(_ lux: Int) {
+ if mpvGLCBContext == nil { return }
+ mp_client_set_ambient_lux(mpvGLCBContext, Int32(lux))
+ }
+
+ func command(_ cmd: String) {
+ if mpvHandle == nil { return }
+ mpv_command_string(mpvHandle, cmd)
+ }
+
+ func commandAsync(_ cmd: [String?], id: UInt64 = 1) {
+ if mpvHandle == nil { return }
+ var mCmd = cmd
+ mCmd.append(nil)
+ var cargs = mCmd.map { $0.flatMap { UnsafePointer<Int8>(strdup($0)) } }
+ mpv_command_async(mpvHandle, id, &cargs)
+ for ptr in cargs { free(UnsafeMutablePointer(mutating: ptr)) }
+ }
+
+ func getBoolProperty(_ name: String) -> Bool {
+ if mpvHandle == nil { return false }
+ var value = Int32()
+ mpv_get_property(mpvHandle, name, MPV_FORMAT_FLAG, &value)
+ return value > 0
+ }
+
+ func getIntProperty(_ name: String) -> Int {
+ if mpvHandle == nil { return 0 }
+ var value = Int64()
+ mpv_get_property(mpvHandle, name, MPV_FORMAT_INT64, &value)
+ return Int(value)
+ }
+
+ func getStringProperty(_ name: String) -> String? {
+ if mpvHandle == nil { return nil }
+ let value = mpv_get_property_string(mpvHandle, name)
+ let str = value == nil ? nil : String(cString: value!)
+ mpv_free(value)
+ return str
+ }
+
+ func canBeDraggedAt(_ pos: NSPoint) -> Bool {
+ if inputContext == nil { return false }
+ let canDrag = !mp_input_test_dragging(inputContext!, Int32(pos.x), Int32(pos.y))
+ return canDrag
+ }
+
+ func setMousePosition(_ pos: NSPoint) {
+ if inputContext == nil { return }
+ mp_input_set_mouse_pos(inputContext!, Int32(pos.x), Int32(pos.y))
+ }
+
+ func putAxis(_ mpkey: Int32, delta: Double) {
+ if inputContext == nil { return }
+ mp_input_put_wheel(inputContext!, mpkey, delta)
+ }
+
+ func sendVerbose(_ msg: String) {
+ send(message: msg, type: MSGL_V)
+ }
+
+ func sendInfo(_ msg: String) {
+ send(message: msg, type: MSGL_INFO)
+ }
+
+ func sendWarning(_ msg: String) {
+ send(message: msg, type: MSGL_WARN)
+ }
+
+ func sendError(_ msg: String) {
+ send(message: msg, type: MSGL_ERR)
+ }
+
+ func send(message msg: String, type t: Int) {
+ if mpvLog == nil {
+ sendFallback(message: msg, type: t)
+ } else {
+ let args: [CVarArg] = [ (msg as NSString).utf8String! ]
+ mp_msg_va(mpvLog, Int32(t), "%s\n", getVaList(args))
+ }
+ }
+
+ func sendFallback(message msg: String, type t: Int) {
+ var level = "\u{001B}"
+ switch t {
+ case MSGL_V:
+ level += "[0;30m[VERBOSE]"
+ case MSGL_INFO:
+ level += "[0;30m[INFO]"
+ case MSGL_WARN:
+ level += "[0;33m"
+ case MSGL_ERR:
+ level += "[0;31m"
+ default:
+ level += "[0;30m"
+ }
+
+ print("\(level)[osx/cocoacb] \(msg)\u{001B}[0;30m")
+ }
+
+ func deinitGLCB() {
+ mpv_opengl_cb_set_update_callback(mpvGLCBContext, nil, nil)
+ mp_client_set_control_callback(mpvGLCBContext, nil, nil)
+ mpv_opengl_cb_uninit_gl(mpvGLCBContext)
+ mpvGLCBContext = nil
+ }
+
+ func deinitMPV() {
+ mpvHandle = nil
+ mpvLog = nil
+ inputContext = nil
+ mpctx = nil
+ }
+
+ // (__bridge void*)
+ class func bridge<T: AnyObject>(obj: T) -> UnsafeMutableRawPointer {
+ return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque())
+ }
+
+ // (__bridge T*)
+ class func bridge<T: AnyObject>(ptr: UnsafeRawPointer) -> T {
+ return Unmanaged<T>.fromOpaque(ptr).takeUnretainedValue()
+ }
+
+ // *(char **) MPV_FORMAT_STRING on mpv_event_property
+ class func mpvStringArrayToString(_ obj: UnsafeMutableRawPointer) -> String? {
+ let cstr = UnsafeMutablePointer<UnsafeMutablePointer<Int8>>(OpaquePointer(obj))
+ return String(cString: cstr[0])
+ }
+
+ // MPV_FORMAT_FLAG
+ class func mpvFlagToBool(_ obj: UnsafeMutableRawPointer) -> Bool? {
+ return UnsafePointer<Bool>(OpaquePointer(obj))?.pointee
+ }
+}
diff --git a/osdep/macOS_swift_bridge.h b/osdep/macOS_swift_bridge.h
new file mode 100644
index 0000000000..d662dbcf4e
--- /dev/null
+++ b/osdep/macOS_swift_bridge.h
@@ -0,0 +1,54 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// including IOKit here again doesn't make sense, but otherwise the swift
+// compiler doesn't include the needed header in our generated header file
+#import <IOKit/pwr_mgt/IOPMLib.h>
+
+#include "player/client.h"
+#include "libmpv/opengl_cb.h"
+
+#include "player/core.h"
+#include "input/input.h"
+#include "video/out/win_state.h"
+
+#include "osdep/macosx_application_objc.h"
+#include "osdep/macosx_events_objc.h"
+
+
+// complex macros won't get imported to Swift so we have to reassign them
+static int SWIFT_MBTN_LEFT = MP_MBTN_LEFT;
+static int SWIFT_MBTN_MID = MP_MBTN_MID;
+static int SWIFT_MBTN_RIGHT = MP_MBTN_RIGHT;
+static int SWIFT_WHEEL_UP = MP_WHEEL_UP;
+static int SWIFT_WHEEL_DOWN = MP_WHEEL_DOWN;
+static int SWIFT_WHEEL_LEFT = MP_WHEEL_LEFT;
+static int SWIFT_WHEEL_RIGHT = MP_WHEEL_RIGHT;
+static int SWIFT_MBTN_BACK = MP_MBTN_BACK;
+static int SWIFT_MBTN_FORWARD = MP_MBTN_FORWARD;
+static int SWIFT_MBTN9 = MP_MBTN9;
+
+static int SWIFT_KEY_CLOSE_WIN = MP_KEY_CLOSE_WIN;
+static int SWIFT_KEY_MOUSE_LEAVE = MP_KEY_MOUSE_LEAVE;
+static int SWIFT_KEY_MOUSE_ENTER = MP_KEY_MOUSE_ENTER;
+static int SWIFT_KEY_STATE_DOWN = MP_KEY_STATE_DOWN;
+static int SWIFT_KEY_STATE_UP = MP_KEY_STATE_UP;
+
+// dummy function to override glFlush()
+static void glDummy() {}
+static void *glDummyPtr(void) __attribute__((unused));
+static void *glDummyPtr() { return &glDummy; }
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m
index d070401621..a65910ec9e 100644
--- a/osdep/macosx_application.m
+++ b/osdep/macosx_application.m
@@ -33,6 +33,9 @@
#if HAVE_MACOS_TOUCHBAR
#import "osdep/macosx_touchbar.h"
#endif
+#if HAVE_MACOS_COCOA_CB
+#include "osdep/macOS_swift.h"
+#endif
#define MPV_PROTOCOL @"mpv://"
@@ -40,7 +43,13 @@
// running in libmpv mode, and cocoa_main() was never called.
static bool application_instantiated;
+struct playback_thread_ctx {
+ int *argc;
+ char ***argv;
+};
+
static pthread_t playback_thread_id;
+static struct playback_thread_ctx thread_ctx = {0};
@interface Application ()
{
@@ -60,9 +69,22 @@ static void terminate_cocoa_application(void)
[NSApp terminate:NSApp];
}
+static void *playback_thread(void *ctx_obj)
+{
+ mpthread_set_name("playback core (OSX)");
+ @autoreleasepool {
+ struct playback_thread_ctx *ctx = (struct playback_thread_ctx*) ctx_obj;
+ int r = mpv_main(*ctx->argc, *ctx->argv);
+ terminate_cocoa_application();
+ // normally never reached - unless the cocoa mainloop hasn't started yet
+ exit(r);
+ }
+}
+
@implementation Application
@synthesize menuBar = _menu_bar;
@synthesize openCount = _open_count;
+@synthesize cocoaCB = _cocoa_cb;
- (void)sendEvent:(NSEvent *)event
{
@@ -96,6 +118,24 @@ static void terminate_cocoa_application(void)
[super dealloc];
}
+- (void)initMPVCore
+{
+ pthread_create(&playback_thread_id, NULL, playback_thread, &thread_ctx);
+ [[EventsResponder sharedInstance] waitForInputContext];
+}
+
+static const char macosx_icon[] =
+#include "osdep/macosx_icon.inc"
+;
+
+- (NSImage *)getMPVIcon
+{
+ NSData *icon_data = [NSData dataWithBytesNoCopy:(void *)macosx_icon
+ length:sizeof(macosx_icon)
+ freeWhenDone:NO];
+ return [[NSImage alloc] initWithData:icon_data];
+}
+
#if HAVE_MACOS_TOUCHBAR
- (NSTouchBar *)makeTouchBar
{
@@ -117,6 +157,16 @@ static void terminate_cocoa_application(void)
if ([self respondsToSelector:@selector(touchBar)])
[(TouchBar *)self.touchBar processEvent:event];
#endif
+ if (_cocoa_cb) {
+ [_cocoa_cb processEvent:event];
+ }
+}
+
+- (void)setMpvHandle:(struct mpv_handle *)ctx
+{
+ if (_cocoa_cb) {
+ [_cocoa_cb setMpvHandle:ctx];
+ }
}
- (void)queueCommand:(char *)cmd
@@ -182,11 +232,6 @@ static void terminate_cocoa_application(void)
}
@end
-struct playback_thread_ctx {
- int *argc;
- char ***argv;
-};
-
static void cocoa_run_runloop(void)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@@ -194,18 +239,6 @@ static void cocoa_run_runloop(void)
[pool drain];
}
-static void *playback_thread(void *ctx_obj)
-{
- mpthread_set_name("playback core (OSX)");
- @autoreleasepool {
- struct playback_thread_ctx *ctx = (struct playback_thread_ctx*) ctx_obj;
- int r = mpv_main(*ctx->argc, *ctx->argv);
- terminate_cocoa_application();
- // normally never reached - unless the cocoa mainloop hasn't started yet
- exit(r);
- }
-}
-
void cocoa_register_menu_item_action(MPMenuKey key, void* action)
{
if (application_instantiated)
@@ -218,6 +251,10 @@ static void init_cocoa_application(bool regular)
[NSApp setDelegate:NSApp];
[NSApp setMenuBar:[[MenuBar alloc] init]];
+#if HAVE_MACOS_COCOA_CB
+ [NSApp setCocoaCB:[[CocoaCB alloc] init]];
+#endif
+
// Will be set to Regular from cocoa_common during UI creation so that we
// don't create an icon when playing audio only files.
[NSApp setActivationPolicy: regular ?
@@ -279,9 +316,8 @@ int cocoa_main(int argc, char *argv[])
application_instantiated = true;
[[EventsResponder sharedInstance] setIsApplication:YES];
- struct playback_thread_ctx ctx = {0};
- ctx.argc = &argc;
- ctx.argv = &argv;
+ thread_ctx.argc = &argc;
+ thread_ctx.argv = &argv;
if (bundle_started_from_finder(argv)) {
setup_bundle(&argc, argv);
@@ -294,8 +330,8 @@ int cocoa_main(int argc, char *argv[])
init_cocoa_application(false);
}
- pthread_create(&playback_thread_id, NULL, playback_thread, &ctx);
- [[EventsResponder sharedInstance] waitForInputContext];
+ if (![NSApp cocoaCB])
+ [NSApp initMPVCore];
cocoa_run_runloop();
// This should never be reached: cocoa_run_runloop blocks until the
diff --git a/osdep/macosx_application_objc.h b/osdep/macosx_application_objc.h
index c12a8b8c64..22e6f7e525 100644
--- a/osdep/macosx_application_objc.h
+++ b/osdep/macosx_application_objc.h
@@ -19,15 +19,21 @@
#include "osdep/macosx_application.h"
#import "osdep/macosx_menubar_objc.h"
+@class CocoaCB;
struct mpv_event;
+struct mpv_handle;
@interface Application : NSApplication
+- (NSImage *)getMPVIcon;
- (void)processEvent:(struct mpv_event *)event;
- (void)queueCommand:(char *)cmd;
- (void)stopMPV:(char *)cmd;
- (void)openFiles:(NSArray *)filenames;
+- (void)setMpvHandle:(struct mpv_handle *)ctx;
+- (void)initMPVCore;
@property(nonatomic, retain) MenuBar *menuBar;
@property(nonatomic, assign) size_t openCount;
+@property(nonatomic, retain) CocoaCB *cocoaCB;
@end
diff --git a/osdep/macosx_events.m b/osdep/macosx_events.m
index a23bd56278..fef7e95053 100644
--- a/osdep/macosx_events.m
+++ b/osdep/macosx_events.m
@@ -39,6 +39,10 @@
#include "config.h"
+#if HAVE_MACOS_COCOA_CB
+#include "osdep/macOS_swift.h"
+#endif
+
@interface EventsResponder ()
{
struct input_ctx *_inputContext;
@@ -304,7 +308,10 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx)
- (BOOL)setMpvHandle:(struct mpv_handle *)ctx
{
if (_is_application) {
- dispatch_sync(dispatch_get_main_queue(), ^{ _ctx = ctx; });
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ _ctx = ctx;
+ [NSApp setMpvHandle:ctx];
+ });
return YES;
} else {
mpv_detach_destroy(ctx);
@@ -326,17 +333,21 @@ void cocoa_set_mpv_handle(struct mpv_handle *ctx)
-(void)processEvent:(struct mpv_event *)event
{
+ if(_is_application) {
+ [NSApp processEvent:event];
+ }
+
switch (event->event_id) {
case MPV_EVENT_SHUTDOWN: {
+ #if HAVE_MACOS_COCOA_CB
+ if ([(Application *)NSApp cocoaCB].isShuttingDown)
+ return;
+ #endif
mpv_detach_destroy(_ctx);
_ctx = nil;
break;
}
}
-
- if(_is_application) {
- [NSApp processEvent:event];
- }
}
- (void)startAppleRemote
diff --git a/osdep/macosx_menubar.m b/osdep/macosx_menubar.m
index 92bd3fa991..931079a552 100644
--- a/osdep/macosx_menubar.m
+++ b/osdep/macosx_menubar.m
@@ -646,7 +646,7 @@
{
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
@"mpv", @"ApplicationName",
- [self getMPVIcon], @"ApplicationIcon",
+ [(Application *)NSApp getMPVIcon], @"ApplicationIcon",
[NSString stringWithUTF8String:mpv_copyright], @"Copyright",
[NSString stringWithUTF8String:mpv_version], @"ApplicationVersion",
nil];
@@ -709,7 +709,7 @@
[alert setMessageText:@"Open URL"];
[alert addButtonWithTitle:@"Ok"];
[alert addButtonWithTitle:@"Cancel"];
- [alert setIcon:[self getMPVIcon]];
+ [alert setIcon:[(Application *)NSApp getMPVIcon]];
NSTextField *input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 24)];
[input setPlaceholderString:@"URL"];
@@ -737,25 +737,13 @@
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]];
}
-static const char macosx_icon[] =
-#include "osdep/macosx_icon.inc"
-;
-
-- (NSImage *)getMPVIcon
-{
- NSData *icon_data = [NSData dataWithBytesNoCopy:(void *)macosx_icon
- length:sizeof(macosx_icon)
- freeWhenDone:NO];
- return [[NSImage alloc] initWithData:icon_data];
-}
-
- (void)alertWithTitle:(NSString *)title andText:(NSString *)text
{
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:title];
[alert setInformativeText:text];
[alert addButtonWithTitle:@"Ok"];
- [alert setIcon:[self getMPVIcon]];
+ [alert setIcon:[(Application *)NSApp getMPVIcon]];
[alert runModal];
}
diff --git a/player/client.c b/player/client.c
index 618dbc4165..1df7e659d8 100644
--- a/player/client.c
+++ b/player/client.c
@@ -1726,6 +1726,17 @@ int mpv_opengl_cb_uninit_gl(mpv_opengl_cb_context *ctx)
{
return MPV_ERROR_NOT_IMPLEMENTED;
}
+void mp_client_set_control_callback(struct mpv_opengl_cb_context *ctx,
+ mpv_opengl_cb_control_fn callback,
+ void *callback_ctx)
+{
+}
+void mp_client_set_icc_profile(struct mpv_opengl_cb_context *ctx, bstr icc_data)
+{
+}
+void mp_client_set_ambient_lux(struct mpv_opengl_cb_context *ctx, int lux)
+{
+}
#endif
int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4])
@@ -1733,22 +1744,29 @@ int mpv_opengl_cb_render(mpv_opengl_cb_context *ctx, int fbo, int vp[4])
return mpv_opengl_cb_draw(ctx, fbo, vp[2], vp[3]);
}
-void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api)
+void *mp_get_sub_api2(mpv_handle *ctx, mpv_sub_api sub_api, bool lock)
{
if (!ctx->mpctx->initialized)
return NULL;
void *res = NULL;
- lock_core(ctx);
+ if (lock)
+ lock_core(ctx);
switch (sub_api) {
case MPV_SUB_API_OPENGL_CB:
res = opengl_cb_get_context(ctx);
break;
default:;
}
- unlock_core(ctx);
+ if (lock)
+ unlock_core(ctx);
return res;
}
+void *mpv_get_sub_api(mpv_handle *ctx, mpv_sub_api sub_api)
+{
+ return mp_get_sub_api2(ctx, sub_api, true);
+}
+
struct mp_custom_protocol {
char *protocol;
void *user_data;
diff --git a/player/client.h b/player/client.h
index 67b287b67f..042934cde3 100644
--- a/player/client.h
+++ b/player/client.h
@@ -6,6 +6,7 @@
#include "libmpv/client.h"
#include "libmpv/stream_cb.h"
+#include "misc/bstr.h"
struct MPContext;
struct mpv_handle;
@@ -34,6 +35,7 @@ struct mpv_handle *mp_new_client(struct mp_client_api *clients, const char *name
struct mp_log *mp_client_get_log(struct mpv_handle *ctx);
struct MPContext *mp_client_get_core(struct mpv_handle *ctx);
struct MPContext *mp_client_api_get_core(struct mp_client_api *api);
+void *mp_get_sub_api2(mpv_handle *ctx, mpv_sub_api sub_api, bool lock);
// m_option.c
void *node_get_alloc(struct mpv_node *node);
@@ -49,4 +51,12 @@ void kill_video(struct mp_client_api *client_api);
bool mp_streamcb_lookup(struct mpv_global *g, const char *protocol,
void **out_user_data, mpv_stream_cb_open_ro_fn *out_fn);
+typedef int (*mpv_opengl_cb_control_fn)(void *cb_ctx, int *events, uint32_t request, void *data);
+
+void mp_client_set_control_callback(struct mpv_opengl_cb_context *ctx,
+ mpv_opengl_cb_control_fn callback,
+ void *callback_ctx);
+void mp_client_set_icc_profile(struct mpv_opengl_cb_context *ctx, bstr icc_data);
+void mp_client_set_ambient_lux(struct mpv_opengl_cb_context *ctx, int lux);
+
#endif
diff --git a/video/out/cocoa-cb/events_view.swift b/video/out/cocoa-cb/events_view.swift
new file mode 100644
index 0000000000..4cb154c64a
--- /dev/null
+++ b/video/out/cocoa-cb/events_view.swift
@@ -0,0 +1,266 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import Cocoa
+
+class EventsView: NSView {
+
+ weak var cocoaCB: CocoaCB!
+ var mpv: MPVHelper! {
+ get { return cocoaCB == nil ? nil : cocoaCB.mpv }
+ }
+
+ var tracker: NSTrackingArea?
+ var hasMouseDown: Bool = false
+
+ override var isFlipped: Bool { return true }
+ override var acceptsFirstResponder: Bool { return true }
+
+
+ init(frame frameRect: NSRect, cocoaCB ccb: CocoaCB) {
+ cocoaCB = ccb
+ super.init(frame: frameRect)
+ autoresizingMask = [.viewWidthSizable, .viewHeightSizable]
+ wantsBestResolutionOpenGLSurface = true
+ register(forDraggedTypes: [NSFilenamesPboardType, NSURLPboardType])
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ override func updateTrackingAreas() {
+ if tracker != nil {
+ removeTrackingArea(tracker!)
+ }
+
+ if mpv != nil && !mpv.getBoolProperty("input-cursor") {
+ return
+ }
+
+ tracker = NSTrackingArea(rect: self.bounds,
+ options: [.activeAlways, .mouseEnteredAndExited, .mouseMoved, .enabledDuringMouseDrag],
+ owner: self, userInfo: nil)
+ addTrackingArea(tracker!)
+
+ if contains