From 6d0f0546ee851f4106438c5b92c8d1d152937ea7 Mon Sep 17 00:00:00 2001 From: der richter Date: Sun, 29 Sep 2019 18:35:12 +0200 Subject: cocoa-cb: remove get_property_* usages and split up mpv helper all the get_property_* usages were removed because in some circumstances they can lead to deadlocks. they were replaced by accessing the vo and mp_vo_opts structs directly, like on other vos. additionally the mpv helper was split into a mpv and libmpv helper, to differentiate between private and public APIs and for future changes like a macOS vulkan context for vo=gpu. --- osdep/macOS_mpv_helper.swift | 338 ----------------------------------- osdep/macOS_swift_compat.swift | 97 ---------- osdep/macOS_swift_extensions.swift | 75 -------- osdep/macos/libmpv_helper.swift | 251 ++++++++++++++++++++++++++ osdep/macos/log_helper.swift | 48 +++++ osdep/macos/mpv_helper.swift | 78 ++++++++ osdep/macos/swift_compat.swift | 97 ++++++++++ osdep/macos/swift_extensions.swift | 82 +++++++++ video/out/cocoa-cb/events_view.swift | 31 ++-- video/out/cocoa-cb/title_bar.swift | 10 +- video/out/cocoa-cb/video_layer.swift | 53 +++--- video/out/cocoa-cb/window.swift | 48 ++--- video/out/cocoa_cb_common.swift | 114 ++++++------ wscript | 2 +- wscript_build.py | 8 +- 15 files changed, 685 insertions(+), 647 deletions(-) delete mode 100644 osdep/macOS_mpv_helper.swift delete mode 100644 osdep/macOS_swift_compat.swift delete mode 100644 osdep/macOS_swift_extensions.swift create mode 100644 osdep/macos/libmpv_helper.swift create mode 100644 osdep/macos/log_helper.swift create mode 100644 osdep/macos/mpv_helper.swift create mode 100644 osdep/macos/swift_compat.swift create mode 100644 osdep/macos/swift_extensions.swift diff --git a/osdep/macOS_mpv_helper.swift b/osdep/macOS_mpv_helper.swift deleted file mode 100644 index 3494c60cfd..0000000000 --- a/osdep/macOS_mpv_helper.swift +++ /dev/null @@ -1,338 +0,0 @@ -/* - * 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 . - */ - -import Cocoa -import OpenGL.GL -import OpenGL.GL3 - -let glDummy: @convention(c) () -> Void = {} - -extension Bool { - init(_ num: Int32) { - self.init(num > 0) - } -} - -class MPVHelper: NSObject { - - var mpvHandle: OpaquePointer? - var mpvRenderContext: OpaquePointer? - var mpvLog: OpaquePointer? - var inputContext: OpaquePointer? - var mpctx: UnsafeMutablePointer? - var vo: UnsafeMutablePointer? - var macOpts: macos_opts? - var fbo: GLint = 1 - let deinitLock = NSLock() - - init(_ mpv: OpaquePointer) { - super.init() - mpvHandle = mpv - mpvLog = mp_log_new(UnsafeMutablePointer(mpvHandle), - mp_client_get_log(mpvHandle), "cocoacb") - guard let mpctx = UnsafeMutablePointer(mp_client_get_core(mpvHandle)) else { - sendError("No MPContext available") - exit(1) - } - - self.mpctx = mpctx - inputContext = mpctx.pointee.input - guard let app = NSApp as? Application, - let ptr = mp_get_config_group(mpctx, - mp_client_get_global(mpvHandle), - app.getMacOSConf()) else - { - sendError("macOS config group couldn't be retrieved'") - exit(1) - } - macOpts = UnsafeMutablePointer(OpaquePointer(ptr)).pointee - - 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) - mpv_observe_property(mpvHandle, 0, "macos-title-bar-style", MPV_FORMAT_STRING) - mpv_observe_property(mpvHandle, 0, "macos-title-bar-appearance", MPV_FORMAT_STRING) - mpv_observe_property(mpvHandle, 0, "macos-title-bar-material", MPV_FORMAT_STRING) - mpv_observe_property(mpvHandle, 0, "macos-title-bar-color", MPV_FORMAT_STRING) - } - - func initRender() { - var advanced: CInt = 1 - let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String) - var pAddress = mpv_opengl_init_params(get_proc_address: getProcAddress, - get_proc_address_ctx: nil, - extra_exts: nil) - var params: [mpv_render_param] = [ - mpv_render_param(type: MPV_RENDER_PARAM_API_TYPE, data: api), - mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, data: &pAddress), - mpv_render_param(type: MPV_RENDER_PARAM_ADVANCED_CONTROL, data: &advanced), - mpv_render_param() - ] - - if (mpv_render_context_create(&mpvRenderContext, mpvHandle, ¶ms) < 0) - { - sendError("Render context init has failed.") - exit(1) - } - } - - let getProcAddress: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer?) - -> UnsafeMutableRawPointer?) = - { - (ctx: UnsafeMutableRawPointer?, name: UnsafePointer?) - -> 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 unsafeBitCast(glDummy, to: UnsafeMutableRawPointer.self) - } - - return addr - } - - func setRenderUpdateCallback(_ callback: @escaping mpv_render_update_fn, context object: AnyObject) { - if mpvRenderContext == nil { - sendWarning("Init mpv render context first.") - } else { - mpv_render_context_set_update_callback(mpvRenderContext, callback, MPVHelper.bridge(obj: object)) - } - } - - func setRenderControlCallback(_ callback: @escaping mp_render_cb_control_fn, context object: AnyObject) { - if mpvRenderContext == nil { - sendWarning("Init mpv render context first.") - } else { - mp_render_context_set_control_callback(mpvRenderContext, callback, MPVHelper.bridge(obj: object)) - } - } - - func reportRenderFlip() { - if mpvRenderContext == nil { return } - mpv_render_context_report_swap(mpvRenderContext) - } - - func isRenderUpdateFrame() -> Bool { - deinitLock.lock() - if mpvRenderContext == nil { - deinitLock.unlock() - return false - } - let flags: UInt64 = mpv_render_context_update(mpvRenderContext) - deinitLock.unlock() - return flags & UInt64(MPV_RENDER_UPDATE_FRAME.rawValue) > 0 - } - - func drawRender(_ surface: NSSize, _ depth: GLint, _ ctx: CGLContextObj, skip: Bool = false) { - deinitLock.lock() - if mpvRenderContext != nil { - var i: GLint = 0 - var flip: CInt = 1 - var skip: CInt = skip ? 1 : 0 - var ditherDepth = depth - glGetIntegerv(GLenum(GL_DRAW_FRAMEBUFFER_BINDING), &i) - // CAOpenGLLayer has ownership of FBO zero yet can return it to us, - // so only utilize a newly received FBO ID if it is nonzero. - fbo = i != 0 ? i : fbo - - var data = mpv_opengl_fbo(fbo: Int32(fbo), - w: Int32(surface.width), - h: Int32(surface.height), - internal_format: 0) - var params: [mpv_render_param] = [ - mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_FBO, data: &data), - mpv_render_param(type: MPV_RENDER_PARAM_FLIP_Y, data: &flip), - mpv_render_param(type: MPV_RENDER_PARAM_DEPTH, data: &ditherDepth), - mpv_render_param(type: MPV_RENDER_PARAM_SKIP_RENDERING, data: &skip), - mpv_render_param() - ] - mpv_render_context_render(mpvRenderContext, ¶ms); - } else { - glClearColor(0, 0, 0, 1) - glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) - } - - if !skip { CGLFlushDrawable(ctx) } - - deinitLock.unlock() - } - - func setRenderICCProfile(_ profile: NSColorSpace) { - if mpvRenderContext == nil { return } - guard var iccData = profile.iccProfileData else { - sendWarning("Invalid ICC profile data.") - return - } - iccData.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) in - guard let baseAddress = ptr.baseAddress, ptr.count > 0 else { return } - - let u8Ptr = baseAddress.assumingMemoryBound(to: UInt8.self) - let iccBstr = bstrdup(nil, bstr(start: u8Ptr, len: ptr.count)) - var icc = mpv_byte_array(data: iccBstr.start, size: iccBstr.len) - let params = mpv_render_param(type: MPV_RENDER_PARAM_ICC_PROFILE, data: &icc) - mpv_render_context_set_parameter(mpvRenderContext, params) - } - } - - func setRenderLux(_ lux: Int) { - if mpvRenderContext == nil { return } - var light = lux - let params = mpv_render_param(type: MPV_RENDER_PARAM_AMBIENT_LIGHT, data: &light) - mpv_render_context_set_parameter(mpvRenderContext, params) - } - - 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(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? { - guard let mpv = mpvHandle, - let value = mpv_get_property_string(mpv, name) else - { - return nil - } - - let str = String(cString: value) - mpv_free(value) - return str - } - - func canBeDraggedAt(_ pos: NSPoint) -> Bool { - guard let input = inputContext else { return false } - let canDrag = !mp_input_test_dragging(input, Int32(pos.x), Int32(pos.y)) - return canDrag - } - - func setMousePosition(_ pos: NSPoint) { - guard let input = inputContext else { return } - mp_input_set_mouse_pos(input, Int32(pos.x), Int32(pos.y)) - } - - func putAxis(_ mpkey: Int32, delta: Double) { - guard let input = inputContext else { return } - mp_input_put_wheel(input, 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 ?? "NO MESSAGE"] - 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 deinitRender() { - mpv_render_context_set_update_callback(mpvRenderContext, nil, nil) - mp_render_context_set_control_callback(mpvRenderContext, nil, nil) - deinitLock.lock() - mpv_render_context_free(mpvRenderContext) - mpvRenderContext = nil - deinitLock.unlock() - } - - func deinitMPV(_ destroy: Bool = false) { - if destroy { - mpv_destroy(mpvHandle) - } - mpvHandle = nil - mpvLog = nil - inputContext = nil - mpctx = nil - } - - // (__bridge void*) - class func bridge(obj: T) -> UnsafeMutableRawPointer { - return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque()) - } - - // (__bridge T*) - class func bridge(ptr: UnsafeRawPointer) -> T { - return Unmanaged.fromOpaque(ptr).takeUnretainedValue() - } - - // *(char **) MPV_FORMAT_STRING on mpv_event_property - class func mpvStringArrayToString(_ obj: UnsafeMutableRawPointer) -> String? { - let cstr = UnsafeMutablePointer>(OpaquePointer(obj)) - return String(cString: cstr[0]) - } - - // MPV_FORMAT_FLAG - class func mpvFlagToBool(_ obj: UnsafeMutableRawPointer) -> Bool? { - return UnsafePointer(OpaquePointer(obj))?.pointee - } -} diff --git a/osdep/macOS_swift_compat.swift b/osdep/macOS_swift_compat.swift deleted file mode 100644 index c14aa08282..0000000000 --- a/osdep/macOS_swift_compat.swift +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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 . - */ - -#if !HAVE_MACOS_10_14_FEATURES -extension NSAppearance.Name { - static let darkAqua: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameDarkAqua") - static let accessibilityHighContrastAqua: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityAqua") - static let accessibilityHighContrastDarkAqua: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityDarkAqua") - static let accessibilityHighContrastVibrantLight: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityVibrantLight") - static let accessibilityHighContrastVibrantDark: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityVibrantDark") -} - -@available(OSX 10.12, *) -extension String { - static let RGBA16Float: String = kCAContentsFormatRGBA16Float - static let RGBA8Uint: String = kCAContentsFormatRGBA8Uint - static let gray8Uint: String = kCAContentsFormatGray8Uint -} -#endif - -extension NSPasteboard.PasteboardType { - - static let fileURLCompat: NSPasteboard.PasteboardType = { - if #available(OSX 10.13, *) { - return .fileURL - } else { - return NSPasteboard.PasteboardType(kUTTypeURL as String) - } - } () - - static let URLCompat: NSPasteboard.PasteboardType = { - if #available(OSX 10.13, *) { - return .URL - } else { - return NSPasteboard.PasteboardType(kUTTypeFileURL as String) - } - } () -} - -#if !swift(>=5.0) -extension Data { - - mutating func withUnsafeMutableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> Type) rethrows -> Type { - let dataCount = count - return try withUnsafeMutableBytes { (ptr: UnsafeMutablePointer) throws -> Type in - try body(UnsafeMutableRawBufferPointer(start: ptr, count: dataCount)) - } - } -} -#endif - -#if !swift(>=4.2) -extension NSDraggingInfo { - - var draggingPasteboard: NSPasteboard { - get { return draggingPasteboard() } - } -} -#endif - -#if !swift(>=4.1) -extension Array { - - func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] { - return try self.flatMap(transform) - } -} - -extension Array where Element == [CGLPixelFormatAttribute] { - - func contains(_ obj: [CGLPixelFormatAttribute]) -> Bool { - return self.contains(where:{ $0 == obj }) - } -} - -extension NSWindow.Level { - - static func +(left: NSWindow.Level, right: Int) -> NSWindow.Level { - return NSWindow.Level(left.rawValue + right) - } -} -#endif - diff --git a/osdep/macOS_swift_extensions.swift b/osdep/macOS_swift_extensions.swift deleted file mode 100644 index 1e30cf4df7..0000000000 --- a/osdep/macOS_swift_extensions.swift +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 . - */ - -import Cocoa - -extension NSDeviceDescriptionKey { - static let screenNumber = NSDeviceDescriptionKey("NSScreenNumber") -} - -extension NSScreen { - - public var displayID: CGDirectDisplayID { - get { - return deviceDescription[.screenNumber] as? CGDirectDisplayID ?? 0 - } - } - - public var displayName: String? { - get { - var name: String? = nil - var object: io_object_t - var iter = io_iterator_t() - let matching = IOServiceMatching("IODisplayConnect") - let result = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iter) - - if result != KERN_SUCCESS || iter == 0 { return nil } - - repeat { - object = IOIteratorNext(iter) - if let info = IODisplayCreateInfoDictionary(object, IOOptionBits(kIODisplayOnlyPreferredName)).takeRetainedValue() as? [String:AnyObject], - (info[kDisplayVendorID] as? UInt32 == CGDisplayVendorNumber(displayID) && - info[kDisplayProductID] as? UInt32 == CGDisplayModelNumber(displayID) && - info[kDisplaySerialNumber] as? UInt32 ?? 0 == CGDisplaySerialNumber(displayID)) - { - if let productNames = info["DisplayProductName"] as? [String:String], - let productName = productNames.first?.value - { - name = productName - break - } - } - } while object != 0 - - IOObjectRelease(iter) - return name - } - } -} - -extension NSColor { - - convenience init(hex: String) { - let int = Int(hex.dropFirst(), radix: 16) ?? 0 - let alpha = CGFloat((int >> 24) & 0x000000FF)/255 - let red = CGFloat((int >> 16) & 0x000000FF)/255 - let green = CGFloat((int >> 8) & 0x000000FF)/255 - let blue = CGFloat((int) & 0x000000FF)/255 - - self.init(calibratedRed: red, green: green, blue: blue, alpha: alpha) - } -} diff --git a/osdep/macos/libmpv_helper.swift b/osdep/macos/libmpv_helper.swift new file mode 100644 index 0000000000..bf069efc6b --- /dev/null +++ b/osdep/macos/libmpv_helper.swift @@ -0,0 +1,251 @@ +/* + * 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 . + */ + +import Cocoa +import OpenGL.GL +import OpenGL.GL3 + +let glDummy: @convention(c) () -> Void = {} + +class LibmpvHelper: LogHelper { + + var mpvHandle: OpaquePointer? + var mpvRenderContext: OpaquePointer? + var macOpts: macos_opts = macos_opts() + var fbo: GLint = 1 + let deinitLock = NSLock() + + init(_ mpv: OpaquePointer, _ name: String) { + let newlog = mp_log_new(UnsafeMutablePointer(mpv), mp_client_get_log(mpv), name) + super.init(newlog) + mpvHandle = mpv + + guard let mpctx = UnsafeMutablePointer(mp_client_get_core(mpvHandle)) else { + sendError("No MPContext available") + exit(1) + } + guard let app = NSApp as? Application, + let ptr = mp_get_config_group(mpctx, + mp_client_get_global(mpvHandle), + app.getMacOSConf()) else + { + sendError("macOS config group couldn't be retrieved'") + exit(1) + } + macOpts = UnsafeMutablePointer(OpaquePointer(ptr)).pointee + } + + func initRender() { + var advanced: CInt = 1 + let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String) + var pAddress = mpv_opengl_init_params(get_proc_address: getProcAddress, + get_proc_address_ctx: nil, + extra_exts: nil) + var params: [mpv_render_param] = [ + mpv_render_param(type: MPV_RENDER_PARAM_API_TYPE, data: api), + mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, data: &pAddress), + mpv_render_param(type: MPV_RENDER_PARAM_ADVANCED_CONTROL, data: &advanced), + mpv_render_param() + ] + + if (mpv_render_context_create(&mpvRenderContext, mpvHandle, ¶ms) < 0) + { + sendError("Render context init has failed.") + exit(1) + } + } + + let getProcAddress: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer?) + -> UnsafeMutableRawPointer?) = + { + (ctx: UnsafeMutableRawPointer?, name: UnsafePointer?) + -> 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 unsafeBitCast(glDummy, to: UnsafeMutableRawPointer.self) + } + + return addr + } + + func setRenderUpdateCallback(_ callback: @escaping mpv_render_update_fn, context object: AnyObject) { + if mpvRenderContext == nil { + sendWarning("Init mpv render context first.") + } else { + mpv_render_context_set_update_callback(mpvRenderContext, callback, MPVHelper.bridge(obj: object)) + } + } + + func setRenderControlCallback(_ callback: @escaping mp_render_cb_control_fn, context object: AnyObject) { + if mpvRenderContext == nil { + sendWarning("Init mpv render context first.") + } else { + mp_render_context_set_control_callback(mpvRenderContext, callback, MPVHelper.bridge(obj: object)) + } + } + + func reportRenderFlip() { + if mpvRenderContext == nil { return } + mpv_render_context_report_swap(mpvRenderContext) + } + + func isRenderUpdateFrame() -> Bool { + deinitLock.lock() + if mpvRenderContext == nil { + deinitLock.unlock() + return false + } + let flags: UInt64 = mpv_render_context_update(mpvRenderContext) + deinitLock.unlock() + return flags & UInt64(MPV_RENDER_UPDATE_FRAME.rawValue) > 0 + } + + func drawRender(_ surface: NSSize, _ depth: GLint, _ ctx: CGLContextObj, skip: Bool = false) { + deinitLock.lock() + if mpvRenderContext != nil { + var i: GLint = 0 + var flip: CInt = 1 + var skip: CInt = skip ? 1 : 0 + var ditherDepth = depth + glGetIntegerv(GLenum(GL_DRAW_FRAMEBUFFER_BINDING), &i) + // CAOpenGLLayer has ownership of FBO zero yet can return it to us, + // so only utilize a newly received FBO ID if it is nonzero. + fbo = i != 0 ? i : fbo + + var data = mpv_opengl_fbo(fbo: Int32(fbo), + w: Int32(surface.width), + h: Int32(surface.height), + internal_format: 0) + var params: [mpv_render_param] = [ + mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_FBO, data: &data), + mpv_render_param(type: MPV_RENDER_PARAM_FLIP_Y, data: &flip), + mpv_render_param(type: MPV_RENDER_PARAM_DEPTH, data: &ditherDepth), + mpv_render_param(type: MPV_RENDER_PARAM_SKIP_RENDERING, data: &skip), + mpv_render_param() + ] + mpv_render_context_render(mpvRenderContext, ¶ms); + } else { + glClearColor(0, 0, 0, 1) + glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) + } + + if !skip { CGLFlushDrawable(ctx) } + + deinitLock.unlock() + } + + func setRenderICCProfile(_ profile: NSColorSpace) { + if mpvRenderContext == nil { return } + guard var iccData = profile.iccProfileData else { + sendWarning("Invalid ICC profile data.") + return + } + iccData.withUnsafeMutableBytes { (ptr: UnsafeMutableRawBufferPointer) in + guard let baseAddress = ptr.baseAddress, ptr.count > 0 else { return } + + let u8Ptr = baseAddress.assumingMemoryBound(to: UInt8.self) + let iccBstr = bstrdup(nil, bstr(start: u8Ptr, len: ptr.count)) + var icc = mpv_byte_array(data: iccBstr.start, size: iccBstr.len) + let params = mpv_render_param(type: MPV_RENDER_PARAM_ICC_PROFILE, data: &icc) + mpv_render_context_set_parameter(mpvRenderContext, params) + } + } + + func setRenderLux(_ lux: Int) { + if mpvRenderContext == nil { return } + var light = lux + let params = mpv_render_param(type: MPV_RENDER_PARAM_AMBIENT_LIGHT, data: &light) + mpv_render_context_set_parameter(mpvRenderContext, params) + } + + func commandAsync(_ cmd: [String?], id: UInt64 = 1) { + if mpvHandle == nil { return } + var mCmd = cmd + mCmd.append(nil) + var cargs = mCmd.map { $0.flatMap { UnsafePointer(strdup($0)) } } + mpv_command_async(mpvHandle, id, &cargs) + for ptr in cargs { free(UnsafeMutablePointer(mutating: ptr)) } + } + + func observeString(_ property: String) { + mpv_observe_property(mpvHandle, 0, property, MPV_FORMAT_STRING) + } + + func observeFlag(_ property: String) { + mpv_observe_property(mpvHandle, 0, property, MPV_FORMAT_FLAG) + } + + // Unsafe function when called while using the render API + func command(_ cmd: String) { + if mpvHandle == nil { return } + mpv_command_string(mpvHandle, cmd) + } + + 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? { + guard let mpv = mpvHandle else { return nil } + guard let value = mpv_get_property_string(mpv, name) else { return nil } + let str = String(cString: value) + mpv_free(value) + return str + } + + func deinitRender() { + mpv_render_context_set_update_callback(mpvRenderContext, nil, nil) + mp_render_context_set_control_callback(mpvRenderContext, nil, nil) + deinitLock.lock() + mpv_render_context_free(mpvRenderContext) + mpvRenderContext = nil + deinitLock.unlock() + } + + func deinitMPV(_ destroy: Bool = false) { + if destroy { + mpv_destroy(mpvHandle) + } + mpvHandle = nil + log = nil + } + + // *(char **) MPV_FORMAT_STRING on mpv_event_property + class func mpvStringArrayToString(_ obj: UnsafeMutableRawPointer) -> String? { + let cstr = UnsafeMutablePointer>(OpaquePointer(obj)) + return String(cString: cstr[0]) + } + + // MPV_FORMAT_FLAG + class func mpvFlagToBool(_ obj: UnsafeMutableRawPointer) -> Bool? { + return UnsafePointer(OpaquePointer(obj))?.pointee + } +} diff --git a/osdep/macos/log_helper.swift b/osdep/macos/log_helper.swift new file mode 100644 index 0000000000..6d834c0631 --- /dev/null +++ b/osdep/macos/log_helper.swift @@ -0,0 +1,48 @@ +/* + * 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 . + */ + +import Cocoa + +class LogHelper: NSObject { + + var log: OpaquePointer? + + init(_ log: OpaquePointer?) { + self.log = log + } + + 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) { + let args: [CVarArg] = [ (msg as NSString).utf8String ?? "NO MESSAGE"] + mp_msg_va(log, Int32(t), "%s\n", getVaList(args)) + } +} diff --git a/osdep/macos/mpv_helper.swift b/osdep/macos/mpv_helper.swift new file mode 100644 index 0000000000..ce1fb5ffec --- /dev/null +++ b/osdep/macos/mpv_helper.swift @@ -0,0 +1,78 @@ +/* + * 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 . + */ + +import Cocoa + +class MPVHelper: LogHelper { + + var vo: UnsafeMutablePointer + var vout: vo { get { return vo.pointee } } + var opts: mp_vo_opts { get { return vout.opts.pointee } } + var input: OpaquePointer { get { return vout.input_ctx } } + var macOpts: macos_opts = macos_opts() + + init(_ vo: UnsafeMutablePointer, _ name: String) { + self.vo = vo + let newlog = mp_log_new(vo, vo.pointee.log, name) + + super.init(newlog) + + guard let app = NSApp as? Application, + let ptr = mp_get_config_group(vo, + vo.pointee.global, + app.getMacOSConf()) else + { + sendError("macOS config group couldn't be retrieved'") + exit(1) + } + macOpts = UnsafeMutablePointer(OpaquePointer(ptr)).pointee + } + + func canBeDraggedAt(_ pos: NSPoint) -> Bool { + let canDrag = !mp_input_test_dragging(input, Int32(pos.x), Int32(pos.y)) + return canDrag + } + + func mouseEnabled() -> Bool { + return mp_input_mouse_enabled(input) + } + + func setMousePosition(_ pos: NSPoint) { + mp_input_set_mouse_pos(input, Int32(pos.x), Int32(pos.y)) + } + + func putAxis(_ mpkey: Int32, delta: Double) { + mp_input_put_wheel(input, mpkey, delta) + } + + func command(_ cmd: String) { + let cCmd = UnsafePointer(strdup(cmd)) + let mpvCmd = mp_input_parse_cmd(input, bstr0(cCmd), "") + mp_input_queue_cmd(input, mpvCmd) + free(UnsafeMutablePointer(mutating: cCmd)) + } + + // (__bridge void*) + class func bridge(obj: T) -> UnsafeMutableRawPointer { + return UnsafeMutableRawPointer(Unmanaged.passUnretained(obj).toOpaque()) + } + + // (__bridge T*) + class func bridge(ptr: UnsafeRawPointer) -> T { + return Unmanaged.fromOpaque(ptr).takeUnretainedValue() + } +} diff --git a/osdep/macos/swift_compat.swift b/osdep/macos/swift_compat.swift new file mode 100644 index 0000000000..c14aa08282 --- /dev/null +++ b/osdep/macos/swift_compat.swift @@ -0,0 +1,97 @@ +/* + * 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 . + */ + +#if !HAVE_MACOS_10_14_FEATURES +extension NSAppearance.Name { + static let darkAqua: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameDarkAqua") + static let accessibilityHighContrastAqua: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityAqua") + static let accessibilityHighContrastDarkAqua: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityDarkAqua") + static let accessibilityHighContrastVibrantLight: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityVibrantLight") + static let accessibilityHighContrastVibrantDark: NSAppearance.Name = NSAppearance.Name(rawValue: "NSAppearanceNameAccessibilityVibrantDark") +} + +@available(OSX 10.12, *) +extension String { + static let RGBA16Float: String = kCAContentsFormatRGBA16Float + static let RGBA8Uint: String = kCAContentsFormatRGBA8Uint + static let gray8Uint: String = kCAContentsFormatGray8Uint +} +#endif + +extension NSPasteboard.PasteboardType { + + static let fileURLCompat: NSPasteboard.PasteboardType = { + if #available(OSX 10.13, *) { + return .fileURL + } else { + return NSPasteboard.PasteboardType(kUTTypeURL as String) + } + } () + + static let URLCompat: NSPasteboard.PasteboardType = { + if #available(OSX 10.13, *) { + return .URL + } else { + return NSPasteboard.PasteboardType(kUTTypeFileURL as String) + } + } () +} + +#if !swift(>=5.0) +extension Data { + + mutating func withUnsafeMutableBytes(_ body: (UnsafeMutableRawBufferPointer) throws -> Type) rethrows -> Type { + let dataCount = count + return try withUnsafeMutableBytes { (ptr: UnsafeMutablePointer) throws -> Type in + try body(UnsafeMutableRawBufferPointer(start: ptr, count: dataCount)) + } + } +} +#endif + +#if !swift(>=4.2) +extension NSDraggingInfo { + + var draggingPasteboard: NSPasteboard { + get { return draggingPasteboard() } + } +} +#endif + +#if !swift(>=4.1) +extension Array { + + func compactMap(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] { + return try self.flatMap(transform) + } +} + +extension Array where Element == [CGLPixelFormatAttribute] { + + func contains(_ obj: [CGLPixelFormatAttribute]) -> Bool { + return self.contains(where:{ $0 == obj }) + } +} + +extension NSWindow.Level { + + static func +(left: NSWindow.Level, right: Int) -> NSWindow.Level { + return NSWindow.Level(left.rawValue + right) + } +} +#endif + diff --git a/osdep/macos/swift_extensions.swift b/osdep/macos/swift_extensions.swift new file mode 100644 index 0000000000..c48ad6e798 --- /dev/null +++ b/osdep/macos/swift_extensions.swift @@ -0,0 +1,82 @@ +/* + * 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 . + */ + +import Cocoa + +extension NSDeviceDescriptionKey { + static let screenNumber = NSDeviceDescriptionKey("NSScreenNumber") +} + +extension NSScreen { + + public var displayID: CGDirectDisplayID { + get { + return deviceDescription[.screenNumber] as? CGDirectDisplayID ?? 0 + } + } + + public var displayName: String? { + get { + var name: String? = nil + var object: io_object_t + var iter = io_iterator_t() + let matching = IOServiceMatching("IODisplayConnect") + let result = IOServiceGetMatchingServices(kIOMasterPortDefault, matching, &iter) + + if result != KERN_SUCCESS || iter == 0 { return nil } + + repeat { + object = IOIteratorNext(iter) + if let info = IODisplayCreateInfoDictionary(object, IOOptionBits(kIODisplayOnlyPreferredName)).takeRetainedValue() as? [String:AnyObject], + (info[kDisplayVendorID] as? UInt32 == CGDisplayVendorNumber(displayID) && + info[kDisplayProductID] as? UInt32 == CGDisplayModelNumber(displayID) && + info[kDisplaySerialNumber] as? UInt32 ?? 0 == CGDisplaySerialNumber(displayID)) + { + if let productNames = info["DisplayProductName"] as? [String:String], + let productName = productNames.first?.value + { + name = productName + break + } + } + } while object != 0 + + IOObjectRelease(iter) + return name + } + } +} + +extension NSColor { + + convenience init(hex: String) { + let int = Int(hex.dropFirst(), radix: 16) ?? 0 + let alpha = CGFloat((int >> 24) & 0x000000FF)/255 + let red = CGFloat((int >> 16) & 0x000000FF)/255 + let green = CGFloat((int >> 8) & 0x000000FF)/255 + let blue = CGFloat((int) & 0x000000FF)/255 + + self.init(calibratedRed: red, green: green, blue: blue, alpha: alpha) + } +} + +extension Bool { + + init(_ int32: Int32) { + self.init(int32 != 0) + } +} diff --git a/video/out/cocoa-cb/events_view.swift b/video/out/cocoa-cb/events_view.swift index 59441d9793..31533bbb98 100644 --- a/video/out/cocoa-cb/events_view.swift +++ b/video/out/cocoa-cb/events_view.swift @@ -19,8 +19,8 @@ import Cocoa class EventsView: NSView { - weak var cocoaCB: CocoaCB! - var mpv: MPVHelper { get { return cocoaCB.mpv } } + unowned var cocoaCB: CocoaCB + var mpv: MPVHelper? { get { return cocoaCB.mpv } } var tracker: NSTrackingArea? var hasMouseDown: Bool = false @@ -117,64 +117,64 @@ class EventsView: NSView { } override func mouseEntered(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_ENTER, 0) } } override func mouseExited(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0) } cocoaCB.titleBar?.hide() } override func mouseMoved(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseMovement(event) } cocoaCB.titleBar?.show() } override func mouseDragged(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseMovement(event) } } override func mouseDown(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseDown(event) } } override func mouseUp(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseUp(event) } cocoaCB.window?.isMoving = false } override func rightMouseDown(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseDown(event) } } override func rightMouseUp(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseUp(event) } } override func otherMouseDown(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseDown(event) } } override func otherMouseUp(with event: NSEvent) { - if mpv.getBoolProperty("input-cursor") { + if mpv?.mouseEnabled() ?? true { signalMouseUp(event) } } @@ -203,7 +203,7 @@ class EventsView: NSView { cocoaCB.window?.updateMovableBackground(point) if !(cocoaCB.window?.isMoving ?? false) { - mpv.setMousePosition(point) + mpv?.setMousePosition(point) } } @@ -219,11 +219,11 @@ class EventsView: NSView { cmd = delta > 0 ? SWIFT_WHEEL_RIGHT : SWIFT_WHEEL_LEFT; } - mpv.putAxis(cmd, delta: abs(delta)) + mpv?.putAxis(cmd, delta: abs(delta)) } override func scrollWheel(with event: NSEvent) { - if !mpv.getBoolProperty("input-cursor") { + if !(mpv?.mouseEnabled() ?? true) { return } @@ -246,7 +246,6 @@ class EventsView: NSView { } func containsMouseLocation() -> Bool { - if cocoaCB == nil { return false } var topMargin: CGFloat = 0.0 let menuBarHeight = NSApp.mainMenu?.menuBarHeight ?? 23.0 diff --git a/video/out/cocoa-cb/title_bar.swift b/video/out/cocoa-cb/title_bar.swift index 41d04a19ad..20812e9029 100644 --- a/video/out/cocoa-cb/title_bar.swift +++ b/video/out/cocoa-cb/title_bar.swift @@ -19,8 +19,8 @@ import Cocoa class TitleBar: NSVisualEffectView { - weak var cocoaCB: CocoaCB! - var mpv: MPVHelper { get { return cocoaCB.mpv } } + unowned var cocoaCB: CocoaCB + var libmpv: LibmpvHelper { get { return cocoaCB.libmpv } } var systemBar: NSView? { get { return cocoaCB.window?.standardWindowButton(.closeButton)?.superview } @@ -67,9 +67,9 @@ class TitleBar: NSVisualEffectView { window.contentView?.addSubview(self, positioned: .above, relativeTo: nil) window.titlebarAppearsTransparent = true window.styleMask.insert(.fullSizeContentView) - set(appearance: Int(mpv.macOpts?.macos_title_bar_appearance ?? 0)) - set(material: Int(mpv.macOpts?.macos_title_bar_material ?? 0)) - set(color: mpv.macOpts?.macos_title_bar_color ?? "#00000000") + set(appearance: Int(libmpv.macOpts.macos_title_bar_appearance)) + set(material: Int(libmpv.macOpts.macos_title_bar_material)) + set(color: libmpv.macOpts.macos_title_bar_color) } required init?(coder: NSCoder) { diff --git a/video/out/cocoa-cb/video_layer.swift b/video/out/cocoa-cb/video_layer.swift index 95727ee01f..90a37ae0c5 100644 --- a/video/out/cocoa-cb/video_layer.swift +++ b/video/out/cocoa-cb/video_layer.swift @@ -66,8 +66,8 @@ let attributeLookUp: [UInt32:String] = [ class VideoLayer: CAOpenGLLayer { - weak var cocoaCB: CocoaCB! - var mpv: MPVHelper { get { return cocoaCB.mpv } } + unowned var cocoaCB: CocoaCB + var libmpv: LibmpvHelper { get { return cocoaCB.libmpv } } let displayLock = NSLock() let cglContext: CGLContextObj @@ -101,8 +101,8 @@ class VideoLayer: CAOpenGLLayer { init(cocoaCB ccb: CocoaCB) { cocoaCB = ccb - (cglPixelFormat, bufferDepth) = VideoLayer.createPixelFormat(ccb.mpv) - cglContext = VideoLayer.createContext(ccb.mpv, cglPixelFormat) + (cglPixelFormat, bufferDepth) = VideoLayer.createPixelFormat(ccb.libmpv) + cglContext = VideoLayer.createContext(ccb.libmpv, cglPixelFormat) super.init() autoresizingMask = [.layerWidthSizable, .layerHeightSizable] backgroundColor = NSColor.black.cgColor @@ -115,9 +115,9 @@ class VideoLayer: CAOpenGLLayer { CGLSetParameter(cglContext, kCGLCPSwapInterval, &i) CGLSetCurrentContext(cglContext) - mpv.initRender() - mpv.setRenderUpdateCallback(updateCallback, context: self) - mpv.setRenderControlCallback(cocoaCB.controlCallback, context: cocoaCB) + libmpv.initRender() + libmpv.setRenderUpdateCallback(updateCallback, context: self) + libmpv.setRenderControlCallback(cocoaCB.controlCallback, context: cocoaCB) } //necessary for when the layer containing window changes the screen @@ -144,7 +144,7 @@ class VideoLayer: CAOpenGLLayer { isAsynchronous = false } return cocoaCB.backendState == .initialized && - (forceDraw || mpv.isRenderUpdateFrame()) + (forceDraw || libmpv.isRenderUpdateFrame()) } override func draw(inCGLContext ctx: CGLContextObj, @@ -163,7 +163,7 @@ class VideoLayer: CAOpenGLLayer { } updateSurfaceSize() - mpv.drawRender(surfaceSize, bufferDepth, ctx) + libmpv.drawRender(surfaceSize, bufferDepth, ctx) if needsICCUpdate { needsICCUpdate = false @@ -218,8 +218,8 @@ class VideoLayer: CAOpenGLLayer { CATransaction.flush() if isUpdate && needsFlip { CGLSetCurrentContext(cglContext) - if mpv.isRenderUpdateFrame() { - mpv.drawRender(NSZeroSize, bufferDepth, cglContext, skip: true) + if libmpv.isRenderUpdateFrame() { + libmpv.drawRender(NSZeroSize, bufferDepth, cglContext, skip: true) } } displayLock.unlock() @@ -235,29 +235,29 @@ class VideoLayer: CAOpenGLLayer { } } - class func createPixelFormat(_ mpv: MPVHelper) -> (CGLPixelFormatObj, GLint) { + class func createPixelFormat(_ libmpv: LibmpvHelper) -> (CGLPixelFormatObj, GLint) { var pix: CGLPixelFormatObj? var depth: GLint = 8 var err: CGLError = CGLError(rawValue: 0) - let swRender = mpv.macOpts?.cocoa_cb_sw_renderer ?? -1 + let swRender = libmpv.macOpts.cocoa_cb_sw_renderer if swRender != 1 { - (pix, depth, err) = VideoLayer.findPixelFormat(mpv) + (pix, depth, err) = VideoLayer.findPixelFormat(libmpv) } if (err != kCGLNoError || pix == nil) && swRender != 0 { - (pix, depth, err) = VideoLayer.findPixelFormat(mpv, software: true) + (pix, depth, err) = VideoLayer.findPixelFormat(libmpv, software: true) } guard let pixelFormat = pix, err == kCGLNoError else { - mpv.sendError("Couldn't create any CGL pixel format") + libmpv.sendError("Couldn't create any CGL pixel format") exit(1) } return (pixelFormat, depth) } - class func findPixelFormat(_ mpv: MPVHelper, software: Bool = false) -> (CGLPixelFormatObj?, GLint, CGLError) { + class func findPixelFormat(_ libmpv: LibmpvHelper, software: Bool = false) -> (CGLPixelFormatObj?, GLint, CGLError) { var pix: CGLPixelFormatObj? var err: CGLError = CGLError(rawValue: 0) var npix: GLint = 0 @@ -267,7 +267,7 @@ class VideoLayer: CAOpenGLLayer { glBase.insert(CGLPixelFormatAttribute(ver.rawValue), at: 1) var glFormat = [glBase] - if (mpv.macOpts?.cocoa_cb_10bit_context == 1) { + if (libmpv.macOpts.cocoa_cb_10bit_context == 1) { glFormat += [glFormat10Bit] } glFormat += glFormatOptional @@ -283,7 +283,7 @@ class VideoLayer: CAOpenGLLayer { return attributeLookUp[value.rawValue] ?? String(value.rawValue) }) - mpv.sendVerbose("Created CGL pixel format with attributes: " + + libmpv.sendVerbose("Created CGL pixel format with attributes: " + "\(attArray.joined(separator: ", "))") return (pix, glFormat.contains(glFormat10Bit) ? 16 : 8, err) } @@ -291,24 +291,23 @@ class VideoLayer: CAOpenGLLayer { } let errS = String(cString: CGLErrorString(err)) - mpv.sendWarning("Couldn't create a " + - "\(software ? "software" : "hardware accelerated") " + - "CGL pixel format: \(errS) (\(err.rawValue))") - - if software == false && (mpv.macOpts?.cocoa_cb_sw_renderer ?? -1) == -1 { - mpv.sendWarning("Falling back to software renderer") + libmpv.sendWarning("Couldn't create a " + + "\(software ? "software" : "hardware accelerated") " + + "CGL pixel format: \(errS) (\(err.rawValue))") + if software == false && libmpv.macOpts.cocoa_cb_sw_renderer == -1 { + libmpv.sendWarning("Falling back to software renderer") } return (pix, 8, err) } - class func createContext(_ mpv: MPVHelper, _ pixelFormat: CGLPixelFormatObj) -> CGLContextObj { + class func createContext(_ libmpv: LibmpvHelper, _ pixelFormat: CGLPixelFormatObj) -> CGLContextObj { var context: CGLContextObj? let error = CGLCreateContext(pixelFormat, nil, &context) guard let cglContext = context, error == kCGLNoError else { let errS = String(cString: CGLErrorString(error)) - mpv.sendError("Couldn't create a CGLContext: " + errS) + libmpv.sendError("Couldn't create a CGLContext: " + errS) exit(1) } diff --git a/video/out/cocoa-cb/window.swift b/video/out/cocoa-cb/window.swift index 2f87711d22..1ac0e2bc78 100644 --- a/video/out/cocoa-cb/window.swift +++ b/video/out/cocoa-cb/window.swift @@ -20,7 +20,8 @@ import Cocoa class Window: NSWindow, NSWindowDelegate { weak var cocoaCB: CocoaCB! = nil - var mpv: MPVHelper { get { return cocoaCB.mpv } } + var mpv: MPVHelper? { get { return cocoaCB.mpv } } + var libmpv: LibmpvHelper { get { return cocoaCB.libmpv } } var targetScreen: NSScreen? var previousScreen: NSScreen? @@ -134,7 +135,7 @@ class Window: NSWindow, NSWindowDelegate { setFrame(frame, display: true) } - if mpv.getBoolProperty("native-fs") { + if Bool(mpv?.opts.native_fs ?? 1) { super.toggleFullScreen(sender) } else { if !isInFullscreen { @@ -245,48 +246,35 @@ class Window: NSWindow, NSWindowDelegate { cocoaCB.layer?.update() } - func getFsAnimationDuration(_ def: Double) -> Double{ - let duration = mpv.getStringProperty("macos-fs-animation-duration") ?? "default" - if duration == "default" { + func getFsAnimationDuration(_ def: Double) -> Double { + let duration = libmpv.macOpts.macos_fs_animation_duration + if duration < 0 { return def } else { - return (Double(duration) ?? 0.2)/1000 + return Double(duration)/1000 } } - func setOnTop(_ state: Bool, _ ontopLevel: Any) { - let stdLevel: NSWindow.Level = .normal - + func setOnTop(_ state: Bool, _ ontopLevel: Int) { if state { - if ontopLevel is Int { - switch ontopLevel as? Int { - case .some(-1): - level = .floating - case .some(-2): - level = .statusBar + 1 - default: - level = NSWindow.Level(ontopLevel as? Int ?? stdLevel.rawValue) - } - } else { - switch ontopLevel as? String { - case .some("window"): - level = .floating - case .some("system"): - level = .statusBar + 1 - default: - level = NSWindow.Level(Int(ontopLevel as? String ?? "") ?? stdLevel.rawValue) - } + switch ontopLevel { + case -1: + level = .floating + case -2: + level = .statusBar + 1 + default: + level = NSWindow.Level(ontopLevel) } collectionBehavior.remove(.transient) collectionBehavior.insert(.managed) } else { - level = stdLevel + level = .normal } } func updateMovableBackground(_ pos: NSPoint) { if !isInFullscreen { - isMovableByWindowBackground = mpv.canBeDraggedAt(pos) + isMovableByWindowBackground = mpv?.canBeDraggedAt(pos) ?? true } else { isMovableByWindowBackground = false } @@ -448,7 +436,7 @@ class Window: NSWindow, NSWindowDelegate { @objc func setDoubleWindowSize() { setWindowScale(2.0) } func setWindowScale(_ scale: Double) { - mpv.commandAsync(["osd-auto", "set", "window-scale", "\(scale)"]) + mpv?.command("set window-scale \(scale)") } func windowDidChangeScreen(_ notification: Notification) { diff --git a/video/out/cocoa_cb_common.swift b/video/out/cocoa_cb_common.swift index b08f102964..504f0dfad6 100644 --- a/video/out/cocoa_cb_common.swift +++ b/video/out/cocoa_cb_common.swift @@ -20,7 +20,8 @@ import IOKit.pwr_mgt class CocoaCB: NSObject { - var mpv: MPVHelper + var mpv: MPVHelper? + var libmpv: LibmpvHelper var window: Window? var titleBar: TitleBar? var view: EventsView? @@ -53,15 +54,24 @@ class CocoaCB: NSObject { let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue") @objc init(_ mpvHandle: OpaquePointer) { - mpv = MPVHelper(mpvHandle) + libmpv = LibmpvHelper(mpvHandle, "cocoacb") super.init() layer = VideoLayer(cocoaCB: self) + + libmpv.observeFlag("ontop") + libmpv.observeFlag("border") + libmpv.observeFlag("keepaspect-window") + libmpv.observeString("macos-title-bar-style") + libmpv.observeString("macos-title-bar-appearance") + libmpv.observeString("macos-title-bar-material") + libmpv.observeString("macos-title-bar-color") } func preinit(_ vo: UnsafeMutablePointer) { if backendState == .uninitialized { backendState = .needsInit + mpv = MPVHelper(vo, "cocoacb") view = EventsView(cocoaCB: self) view?.layer = layer view?.wantsLayer = true @@ -77,7 +87,7 @@ class CocoaCB: NSObject { } func reconfig(_ vo: UnsafeMutablePointer) { - mpv.vo = vo + mpv?.vo = vo if backendState == .needsInit { DispatchQueue.main.sync { self.initBackend(vo) } } else { @@ -94,18 +104,18 @@ class CocoaCB: NSObject { setAppIcon() guard let view = self.view else { - mpv.sendError("Something went wrong, no View was initialized") + libmpv.sendError("Something went wrong, no View was initialized") exit(1) } guard let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main else { - mpv.sendError("Something went wrong, no Screen was found") + libmpv.sendError("Something went wrong, no Screen was found") exit(1) } let wr = getWindowGeometry(forScreen: targetScreen, videoOut: vo) window = Window(contentRect: wr, screen: targetScreen, view: view, cocoaCB: self) guard let window = self.window else { - mpv.sendError("Something went wrong, no Window was initialized") + libmpv.sendError("Something went wrong, no Window was initialized") exit(1) } @@ -136,7 +146,7 @@ class CocoaCB: NSObject { func updateWindowSize(_ vo: UnsafeMutablePointer) { let opts: mp_vo_opts = vo.pointee.opts.pointee guard let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main else { - mpv.sendWarning("Couldn't update Window size, no Screen available") + libmpv.sendWarning("Couldn't update Window size, no Screen available") return } @@ -162,7 +172,7 @@ class CocoaCB: NSObject { flagsOut: UnsafeMutablePointer, displayLinkContext: UnsafeMutableRawPointer?) -> CVReturn in let ccb = unsafeBitCast(displayLinkContext, to: CocoaCB.self) - ccb.mpv.reportRenderFlip() + ccb.libmpv.reportRenderFlip() return kCVReturnSuccess } @@ -173,14 +183,14 @@ class CocoaCB: NSObject { guard let screen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main, let link = self.link else { - mpv.sendWarning("Couldn't start DisplayLink, no Screen or DisplayLink available") + libmpv.sendWarning("Couldn't start DisplayLink, no Screen or DisplayLink available") return } CVDisplayLinkSetCurrentCGDisplay(link, screen.displayID) if #available(macOS 10.12, *) { CVDisplayLinkSetOutputHandler(link) { link, now, out, inFlags, outFlags -> CVReturn in - self.mpv.reportRenderFlip() + self.libmpv.reportRenderFlip() return kCVReturnSuccess } } else { @@ -197,7 +207,7 @@ class CocoaCB: NSObject { func updateDisplaylink() { guard let screen = window?.screen, let link = self.link else { - mpv.sendWarning("Couldn't update DisplayLink, no Screen or DisplayLink available") + libmpv.sendWarning("Couldn't update DisplayLink, no Screen or DisplayLink available") return } @@ -220,17 +230,17 @@ class CocoaCB: NSObject { } if fabs(actualFps - nominalFps) > 0.1 { - mpv.sendVerbose("Falling back to nominal display refresh rate: \(nominalFps)") + libmpv.sendVerbose("Falling back to nominal display refresh rate: \(nominalFps)") return nominalFps } else { return actualFps } } } else { - mpv.sendWarning("No DisplayLink available") + libmpv.sendWarning("No DisplayLink available") } - mpv.sendWarning("Falling back to standard display refresh rate: 60Hz") + libmpv.sendWarning("Falling back to standard display refresh rate: 60Hz") return 60.0 } @@ -265,11 +275,11 @@ class CocoaCB: NSObject { func updateICCProfile() { guard let colorSpace = window?.screen?.colorSpace else { - mpv.sendWarning("Couldn't update ICC Profile, no color space available") + libmpv.sendWarning("Couldn't update ICC Profile, no color space available") return } - mpv.setRenderICCProfile(colorSpace) + libmpv.setRenderICCProfile(colorSpace) if #available(macOS 10.11, *) { layer?.colorspace = colorSpace.cgColorSpace } @@ -305,7 +315,7 @@ class CocoaCB: NSObject { var mean = (values[0] + values[1]) / 2 if ccb.lastLmu != mean { ccb.lastLmu = mean - ccb.mpv.setRenderLux(ccb.lmuToLux(ccb.lastLmu)) + ccb.libmpv.setRenderLux(ccb.lmuToLux(ccb.lastLmu)) } } } @@ -313,7 +323,7 @@ class CocoaCB: NSObject { func initLightSensor() { let srv = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController")) if srv == IO_OBJECT_NULL { - mpv.sendVerbose("Can't find an ambient light sensor") + libmpv.sendVerbose("Can't find an ambient light sensor") return } @@ -325,7 +335,7 @@ class CocoaCB: NSObject { IOObjectRelease(srv) if kr != KERN_SUCCESS { - mpv.sendVerbose("Can't start ambient light sensor connection") + libmpv.sendVerbose("Can't start ambient light sensor connection") return } lightSensorCallback(MPVHelper.bridge(obj: self), 0, 0, nil) @@ -344,7 +354,7 @@ class CocoaCB: NSObject { let displayID = ccb.window?.screen?.displayID ?? display if displayID == display { - ccb.mpv.sendVerbose("Detected display mode change, updating screen refresh rate"); + ccb.libmpv.sendVerbose("Detected display mode change, updating screen refresh rate"); ccb.flagEvents(VO_EVENT_WIN_STATE) }