diff options
Diffstat (limited to 'video/out/mac')
-rw-r--r-- | video/out/mac/common.swift | 228 | ||||
-rw-r--r-- | video/out/mac/gl_layer.swift | 32 | ||||
-rw-r--r-- | video/out/mac/metal_layer.swift | 12 | ||||
-rw-r--r-- | video/out/mac/title_bar.swift | 16 | ||||
-rw-r--r-- | video/out/mac/view.swift | 152 | ||||
-rw-r--r-- | video/out/mac/window.swift | 83 |
6 files changed, 222 insertions, 301 deletions
diff --git a/video/out/mac/common.swift b/video/out/mac/common.swift index aac7050..594a4b8 100644 --- a/video/out/mac/common.swift +++ b/video/out/mac/common.swift @@ -19,11 +19,13 @@ import Cocoa import IOKit.pwr_mgt class Common: NSObject { - var mpv: MPVHelper? + var option: OptionHelper + var input: InputHelper? var log: LogHelper + var vo: UnsafeMutablePointer<vo>? let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue") - var window: Window? + @objc var window: Window? var view: View? var titleBar: TitleBar? @@ -46,39 +48,26 @@ class Common: NSObject { didSet { if let window = window { window.title = title } } } - init(_ mpLog: OpaquePointer?) { - log = LogHelper(mpLog) + init(_ option: OptionHelper, _ log: LogHelper) { + self.option = option + self.log = log } func initMisc(_ vo: UnsafeMutablePointer<vo>) { - guard let mpv = mpv else { - log.sendError("Something went wrong, no MPVHelper was initialized") - exit(1) - } - startDisplayLink(vo) initLightSensor() addDisplayReconfigureObserver() addAppNotifications() - mpv.setMacOptionCallback(macOptsWakeupCallback, context: self) + option.setMacOptionCallback(macOptsWakeupCallback, context: self) } func initApp() { - guard let mpv = mpv else { - log.sendError("Something went wrong, no MPVHelper was initialized") - exit(1) - } - var policy: NSApplication.ActivationPolicy = .regular - switch mpv.macOpts.macos_app_activation_policy { - case 0: - policy = .regular - case 1: - policy = .accessory - case 2: - policy = .prohibited - default: - break + switch option.mac.macos_app_activation_policy { + case 0: policy = .regular + case 1: policy = .accessory + case 2: policy = .prohibited + default: break } NSApp.setActivationPolicy(policy) @@ -86,63 +75,67 @@ class Common: NSObject { } func initWindow(_ vo: UnsafeMutablePointer<vo>, _ previousActiveApp: NSRunningApplication?) { - let (mpv, targetScreen, wr) = getInitProperties(vo) + let (targetScreen, wr) = getInitProperties(vo) guard let view = self.view else { - log.sendError("Something went wrong, no View was initialized") + log.error("Something went wrong, no View was initialized") exit(1) } window = Window(contentRect: wr, screen: targetScreen, view: view, common: self) guard let window = self.window else { - log.sendError("Something went wrong, no Window was initialized") + log.error("Something went wrong, no Window was initialized") exit(1) } - window.setOnTop(Bool(mpv.opts.ontop), Int(mpv.opts.ontop_level)) - window.setOnAllWorkspaces(Bool(mpv.opts.all_workspaces)) - window.keepAspect = Bool(mpv.opts.keepaspect_window) + window.setOnTop(Bool(option.vo.ontop), Int(option.vo.ontop_level)) + window.setOnAllWorkspaces(Bool(option.vo.all_workspaces)) + window.keepAspect = Bool(option.vo.keepaspect_window) window.title = title - window.border = Bool(mpv.opts.border) + window.border = Bool(option.vo.border) titleBar = TitleBar(frame: wr, window: window, common: self) - let minimized = Bool(mpv.opts.window_minimized) + let maximized = Bool(option.vo.window_maximized) + let minimized = Bool(option.vo.window_minimized) window.isRestorable = false window.isReleasedWhenClosed = false - window.setMaximized(minimized ? false : Bool(mpv.opts.window_maximized)) + window.setMaximized((minimized || !maximized) ? window.isZoomed : maximized) window.setMinimized(minimized) window.makeMain() window.makeKey() + view.layer?.contentsScale = window.backingScaleFactor + if !minimized { window.orderFront(nil) } - NSApp.activate(ignoringOtherApps: mpv.opts.focus_on_open) + NSApp.activate(ignoringOtherApps: option.vo.focus_on >= 1) // workaround for macOS 10.15 to refocus the previous App - if (!mpv.opts.focus_on_open) { - previousActiveApp?.activate(options: .activateAllWindows) + if option.vo.focus_on == 0 { + previousActiveApp?.activate() } } func initView(_ vo: UnsafeMutablePointer<vo>, _ layer: CALayer) { - let (_, _, wr) = getInitProperties(vo) + let (_, wr) = getInitProperties(vo) view = View(frame: wr, common: self) guard let view = self.view else { - log.sendError("Something went wrong, no View was initialized") + log.error("Something went wrong, no View was initialized") exit(1) } view.layer = layer view.wantsLayer = true view.layerContentsPlacement = .scaleProportionallyToFit + layer.delegate = view } func initWindowState() { - if mpv?.opts.fullscreen ?? false { + if option.vo.fullscreen { DispatchQueue.main.async { self.window?.toggleFullScreen(nil) } @@ -179,7 +172,7 @@ class Common: NSObject { guard let screen = getTargetScreen(forFullscreen: false) ?? NSScreen.main, let link = self.link else { - log.sendWarning("Couldn't start DisplayLink, no MPVHelper, Screen or DisplayLink available") + log.warning("Couldn't start DisplayLink, no Screen or DisplayLink available") return } @@ -198,7 +191,7 @@ class Common: NSObject { func updateDisplaylink() { guard let screen = window?.screen, let link = self.link else { - log.sendWarning("Couldn't update DisplayLink, no Screen or DisplayLink available") + log.warning("Couldn't update DisplayLink, no Screen or DisplayLink available") return } @@ -221,17 +214,17 @@ class Common: NSObject { } if fabs(actualFps - nominalFps) > 0.1 { - log.sendVerbose("Falling back to nominal display refresh rate: \(nominalFps)") + log.verbose("Falling back to nominal display refresh rate: \(nominalFps)") return nominalFps } else { return actualFps } } } else { - log.sendWarning("No DisplayLink available") + log.warning("No DisplayLink available") } - log.sendWarning("Falling back to standard display refresh rate: 60Hz") + log.warning("Falling back to standard display refresh rate: 60Hz") return 60.0 } @@ -285,28 +278,28 @@ class Common: NSObject { } func lightSensorUpdate() { - log.sendWarning("lightSensorUpdate not implemented") + log.warning("lightSensorUpdate not implemented") } func initLightSensor() { let srv = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleLMUController")) if srv == IO_OBJECT_NULL { - log.sendVerbose("Can't find an ambient light sensor") + log.verbose("Can't find an ambient light sensor") return } lightSensorIOPort = IONotificationPortCreate(kIOMasterPortDefault) IONotificationPortSetDispatchQueue(lightSensorIOPort, queue) var n = io_object_t() - IOServiceAddInterestNotification(lightSensorIOPort, srv, kIOGeneralInterest, lightSensorCallback, MPVHelper.bridge(obj: self), &n) + IOServiceAddInterestNotification(lightSensorIOPort, srv, kIOGeneralInterest, lightSensorCallback, TypeHelper.bridge(obj: self), &n) let kr = IOServiceOpen(srv, mach_task_self_, 0, &lightSensor) IOObjectRelease(srv) if kr != KERN_SUCCESS { - log.sendVerbose("Can't start ambient light sensor connection") + log.verbose("Can't start ambient light sensor connection") return } - lightSensorCallback(MPVHelper.bridge(obj: self), 0, 0, nil) + lightSensorCallback(TypeHelper.bridge(obj: self), 0, 0, nil) } func uninitLightSensor() { @@ -322,18 +315,18 @@ class Common: NSObject { let displayID = com.window?.screen?.displayID ?? display if displayID == display { - com.log.sendVerbose("Detected display mode change, updating screen refresh rate") + com.log.verbose("Detected display mode change, updating screen refresh rate") com.flagEvents(VO_EVENT_WIN_STATE) } } } func addDisplayReconfigureObserver() { - CGDisplayRegisterReconfigurationCallback(reconfigureCallback, MPVHelper.bridge(obj: self)) + CGDisplayRegisterReconfigurationCallback(reconfigureCallback, TypeHelper.bridge(obj: self)) } func removeDisplayReconfigureObserver() { - CGDisplayRemoveReconfigurationCallback(reconfigureCallback, MPVHelper.bridge(obj: self)) + CGDisplayRemoveReconfigurationCallback(reconfigureCallback, TypeHelper.bridge(obj: self)) } func addAppNotifications() { @@ -365,10 +358,8 @@ class Common: NSObject { } func setAppIcon() { - if let app = NSApp as? Application, - ProcessInfo.processInfo.environment["MPVBUNDLE"] != "true" - { - NSApp.applicationIconImage = app.getMPVIcon() + if ProcessInfo.processInfo.environment["MPVBUNDLE"] != "true" { + NSApp.applicationIconImage = AppHub.shared.getIcon() } } @@ -381,12 +372,12 @@ class Common: NSObject { } func updateICCProfile() { - log.sendWarning("updateICCProfile not implemented") + log.warning("updateICCProfile not implemented") } func getScreenBy(id screenID: Int) -> NSScreen? { if screenID >= NSScreen.screens.count { - log.sendInfo("Screen ID \(screenID) does not exist, falling back to current device") + log.info("Screen ID \(screenID) does not exist, falling back to current device") return nil } else if screenID < 0 { return nil @@ -404,14 +395,9 @@ class Common: NSObject { } func getTargetScreen(forFullscreen fs: Bool) -> NSScreen? { - guard let mpv = mpv else { - log.sendWarning("Unexpected nil value in getTargetScreen") - return nil - } - - let screenID = fs ? mpv.opts.fsscreen_id : mpv.opts.screen_id + let screenID = fs ? option.vo.fsscreen_id : option.vo.screen_id var name: String? - if let screenName = fs ? mpv.opts.fsscreen_name : mpv.opts.screen_name { + if let screenName = fs ? option.vo.fsscreen_name : option.vo.screen_name { name = String(cString: screenName) } return getScreenBy(id: Int(screenID)) ?? getScreenBy(name: name) @@ -426,7 +412,7 @@ class Common: NSObject { func getWindowGeometry(forScreen screen: NSScreen, videoOut vo: UnsafeMutablePointer<vo>) -> NSRect { let r = screen.convertRectToBacking(screen.frame) - let targetFrame = (mpv?.macOpts.macos_geometry_calculation ?? Int32(FRAME_VISIBLE)) == FRAME_VISIBLE + let targetFrame = option.mac.macos_geometry_calculation == FRAME_VISIBLE ? screen.visibleFrame : screen.frame let rv = screen.convertRectToBacking(targetFrame) @@ -453,19 +439,15 @@ class Common: NSObject { return screen.convertRectFromBacking(NSMakeRect(x, y, width, height)) } - func getInitProperties(_ vo: UnsafeMutablePointer<vo>) -> (MPVHelper, NSScreen, NSRect) { - guard let mpv = mpv else { - log.sendError("Something went wrong, no MPVHelper was initialized") - exit(1) - } + func getInitProperties(_ vo: UnsafeMutablePointer<vo>) -> (NSScreen, NSRect) { guard let targetScreen = getTargetScreen(forFullscreen: false) ?? NSScreen.main else { - log.sendError("Something went wrong, no Screen was found") + log.error("Something went wrong, no Screen was found") exit(1) } let wr = getWindowGeometry(forScreen: targetScreen, videoOut: vo) - return (mpv, targetScreen, wr) + return (targetScreen, wr) } // call before initApp, because on macOS +10.15 it changes the active App @@ -478,11 +460,11 @@ class Common: NSObject { events |= ev eventsLock.unlock() - guard let vout = mpv?.vo else { - log.sendWarning("vo nil in flagEvents") + guard let vo = vo else { + log.warning("vo nil in flagEvents") return } - vo_wakeup(vout) + vo_wakeup(vo) } func checkEvents() -> Int { @@ -510,47 +492,54 @@ class Common: NSObject { request: UInt32, data: UnsafeMutableRawPointer?) -> Int32 { - guard let mpv = mpv else { - log.sendWarning("Unexpected nil value in Control Callback") - return VO_FALSE - } - switch mp_voctrl(request) { case VOCTRL_CHECK_EVENTS: events.pointee |= Int32(checkEvents()) return VO_TRUE case VOCTRL_VO_OPTS_CHANGED: var opt: UnsafeMutableRawPointer? - while mpv.nextChangedOption(property: &opt) { + while option.nextChangedOption(property: &opt) { switch opt { - case MPVHelper.getPointer(&mpv.optsPtr.pointee.border): + case TypeHelper.toPointer(&option.voPtr.pointee.border): DispatchQueue.main.async { - self.window?.border = Bool(mpv.opts.border) + self.window?.border = Bool(self.option.vo.border) } - case MPVHelper.getPointer(&mpv.optsPtr.pointee.fullscreen): + case TypeHelper.toPointer(&option.voPtr.pointee.fullscreen): DispatchQueue.main.async { self.window?.toggleFullScreen(nil) } - case MPVHelper.getPointer(&mpv.optsPtr.pointee.ontop): fallthrough - case MPVHelper.getPointer(&mpv.optsPtr.pointee.ontop_level): + case TypeHelper.toPointer(&option.voPtr.pointee.ontop): fallthrough + case TypeHelper.toPointer(&option.voPtr.pointee.ontop_level): + DispatchQueue.main.async { + self.window?.setOnTop(Bool(self.option.vo.ontop), Int(self.option.vo.ontop_level)) + } + case TypeHelper.toPointer(&option.voPtr.pointee.all_workspaces): DispatchQueue.main.async { - self.window?.setOnTop(Bool(mpv.opts.ontop), Int(mpv.opts.ontop_level)) + self.window?.setOnAllWorkspaces(Bool(self.option.vo.all_workspaces)) } - case MPVHelper.getPointer(&mpv.optsPtr.pointee.all_workspaces): + case TypeHelper.toPointer(&option.voPtr.pointee.keepaspect_window): DispatchQueue.main.async { - self.window?.setOnAllWorkspaces(Bool(mpv.opts.all_workspaces)) + self.window?.keepAspect = Bool(self.option.vo.keepaspect_window) } - case MPVHelper.getPointer(&mpv.optsPtr.pointee.keepaspect_window): + case TypeHelper.toPointer(&option.voPtr.pointee.window_minimized): DispatchQueue.main.async { - self.window?.keepAspect = Bool(mpv.opts.keepaspect_window) + self.window?.setMinimized(Bool(self.option.vo.window_minimized)) } - case MPVHelper.getPointer(&mpv.optsPtr.pointee.window_minimized): + case TypeHelper.toPointer(&option.voPtr.pointee.window_maximized): DispatchQueue.main.async { - self.window?.setMinimized(Bool(mpv.opts.window_minimized)) + self.window?.setMaximized(Bool(self.option.vo.window_maximized)) } - case MPVHelper.getPointer(&mpv.optsPtr.pointee.window_maximized): + case TypeHelper.toPointer(&option.voPtr.pointee.cursor_passthrough): DispatchQueue.main.async { - self.window?.setMaximized(Bool(mpv.opts.window_maximized)) + self.window?.ignoresMouseEvents = self.option.vo.cursor_passthrough + } + case TypeHelper.toPointer(&option.voPtr.pointee.geometry): fallthrough + case TypeHelper.toPointer(&option.voPtr.pointee.autofit): fallthrough + case TypeHelper.toPointer(&option.voPtr.pointee.autofit_smaller): fallthrough + case TypeHelper.toPointer(&option.voPtr.pointee.autofit_larger): + DispatchQueue.main.async { + let (_, wr) = self.getInitProperties(vo) + self.window?.updateFrame(wr) } default: break @@ -561,6 +550,13 @@ class Common: NSObject { let fps = data!.assumingMemoryBound(to: CDouble.self) fps.pointee = currentFps() return VO_TRUE + case VOCTRL_GET_WINDOW_ID: + guard let window = window else { + return VO_NOTAVAIL + } + let wid = data!.assumingMemoryBound(to: Int64.self) + wid.pointee = unsafeBitCast(window, to: Int64.self) + return VO_TRUE case VOCTRL_GET_HIDPI_SCALE: let scaleFactor = data!.assumingMemoryBound(to: CDouble.self) let screen = getCurrentScreen() @@ -584,7 +580,7 @@ class Common: NSObject { case VOCTRL_GET_ICC_PROFILE: let screen = getCurrentScreen() guard var iccData = screen?.colorSpace?.iccProfileData else { - log.sendWarning("No Screen available to retrieve ICC profile") + log.warning("No Screen available to retrieve ICC profile") return VO_TRUE } @@ -605,10 +601,8 @@ class Common: NSObject { case VOCTRL_GET_UNFS_WINDOW_SIZE: let sizeData = data!.assumingMemoryBound(to: Int32.self) let size = UnsafeMutableBufferPointer(start: sizeData, count: 2) - var rect = window?.unfsContentFrame ?? NSRect(x: 0, y: 0, width: 1280, height: 720) - if let screen = window?.currentScreen, !Bool(mpv.opts.hidpi_window_scale) { - rect = screen.convertRectToBacking(rect) - } + let rect = (Bool(option.vo.hidpi_window_scale) ? window?.unfsContentFrame + : window?.unfsContentFramePixel) ?? NSRect(x: 0, y: 0, width: 1280, height: 720) size[0] = Int32(rect.size.width) size[1] = Int32(rect.size.height) @@ -618,7 +612,7 @@ class Common: NSObject { let size = UnsafeBufferPointer(start: sizeData, count: 2) var rect = NSMakeRect(0, 0, CGFloat(size[0]), CGFloat(size[1])) DispatchQueue.main.async { - if let screen = self.window?.currentScreen, !Bool(self.mpv?.opts.hidpi_window_scale ?? true) { + if let screen = self.window?.currentScreen, !Bool(self.option.vo.hidpi_window_scale) { rect = screen.convertRectFromBacking(rect) } self.window?.updateSize(rect.size) @@ -630,13 +624,13 @@ class Common: NSObject { var count: Int32 = 0 let displayName = getCurrentScreen()?.localizedName ?? "Unknown" - SWIFT_TARRAY_STRING_APPEND(nil, &array, &count, ta_xstrdup(nil, displayName)) - SWIFT_TARRAY_STRING_APPEND(nil, &array, &count, nil) + app_bridge_tarray_append(nil, &array, &count, ta_xstrdup(nil, displayName)) + app_bridge_tarray_append(nil, &array, &count, nil) dnames.pointee = array return VO_TRUE case VOCTRL_GET_DISPLAY_RES: guard let screen = getCurrentScreen() else { - log.sendWarning("No Screen available to retrieve frame") + log.warning("No Screen available to retrieve frame") return VO_NOTAVAIL } let sizeData = data!.assumingMemoryBound(to: Int32.self) @@ -650,10 +644,9 @@ class Common: NSObject { focus.pointee = NSApp.isActive return VO_TRUE case VOCTRL_UPDATE_WINDOW_TITLE: - let titleData = data!.assumingMemoryBound(to: Int8.self) + let title = String(cString: data!.assumingMemoryBound(to: CChar.self)) DispatchQueue.main.async { - let title = NSString(utf8String: titleData) as String? - self.title = title ?? "Unknown Title" + self.title = title } return VO_TRUE default: @@ -669,20 +662,15 @@ class Common: NSObject { } func macOptsUpdate() { - guard let mpv = mpv else { - log.sendWarning("Unexpected nil value in mac opts update") - return - } - var opt: UnsafeMutableRawPointer? - while mpv.nextChangedMacOption(property: &opt) { + while option.nextChangedMacOption(property: &opt) { switch opt { - case MPVHelper.getPointer(&mpv.macOptsPtr.pointee.macos_title_bar_appearance): - titleBar?.set(appearance: Int(mpv.macOpts.macos_title_bar_appearance)) - case MPVHelper.getPointer(&mpv.macOptsPtr.pointee.macos_title_bar_material): - titleBar?.set(material: Int(mpv.macOpts.macos_title_bar_material)) - case MPVHelper.getPointer(&mpv.macOptsPtr.pointee.macos_title_bar_color): - titleBar?.set(color: mpv.macOpts.macos_title_bar_color) + case TypeHelper.toPointer(&option.macPtr.pointee.macos_title_bar_appearance): + titleBar?.set(appearance: Int(option.mac.macos_title_bar_appearance)) + case TypeHelper.toPointer(&option.macPtr.pointee.macos_title_bar_material): + titleBar?.set(material: Int(option.mac.macos_title_bar_material)) + case TypeHelper.toPointer(&option.macPtr.pointee.macos_title_bar_color): + titleBar?.set(color: option.mac.macos_title_bar_color) default: break } diff --git a/video/out/mac/gl_layer.swift b/video/out/mac/gl_layer.swift index dd96af7..38320bc 100644 --- a/video/out/mac/gl_layer.swift +++ b/video/out/mac/gl_layer.swift @@ -82,8 +82,6 @@ class GLLayer: CAOpenGLLayer { enum Draw: Int { case normal = 1, atomic, atomicEnd } var draw: Draw = .normal - let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue.draw") - var needsICCUpdate: Bool = false { didSet { if needsICCUpdate == true { @@ -199,6 +197,14 @@ class GLLayer: CAOpenGLLayer { } } + func lockCglContext() { + CGLLockContext(cglContext) + } + + func unlockCglContext() { + CGLUnlockContext(cglContext) + } + override func copyCGLPixelFormat(forDisplayMask mask: UInt32) -> CGLPixelFormatObj { return cglPixelFormat } @@ -219,17 +225,19 @@ class GLLayer: CAOpenGLLayer { super.display() CATransaction.flush() if isUpdate && needsFlip { + lockCglContext() CGLSetCurrentContext(cglContext) if libmpv.isRenderUpdateFrame() { libmpv.drawRender(NSZeroSize, bufferDepth, cglContext, skip: true) } + unlockCglContext() } displayLock.unlock() } func update(force: Bool = false) { if force { forceDraw = true } - queue.async { + DispatchQueue.main.async { if self.forceDraw || !self.inLiveResize { self.needsFlip = true self.display() @@ -241,7 +249,7 @@ class GLLayer: CAOpenGLLayer { var pix: CGLPixelFormatObj? var depth: GLint = 8 var err: CGLError = CGLError(rawValue: 0) - let swRender = ccb.libmpv.macOpts.cocoa_cb_sw_renderer + let swRender = ccb.option.mac.cocoa_cb_sw_renderer if swRender != 1 { (pix, depth, err) = GLLayer.findPixelFormat(ccb) @@ -252,7 +260,7 @@ class GLLayer: CAOpenGLLayer { } guard let pixelFormat = pix, err == kCGLNoError else { - ccb.log.sendError("Couldn't create any CGL pixel format") + ccb.log.error("Couldn't create any CGL pixel format") exit(1) } @@ -269,12 +277,12 @@ class GLLayer: CAOpenGLLayer { glBase.insert(CGLPixelFormatAttribute(ver.rawValue), at: 1) var glFormat = [glBase] - if ccb.libmpv.macOpts.cocoa_cb_10bit_context { + if ccb.option.mac.cocoa_cb_10bit_context { glFormat += [glFormat10Bit] } glFormat += glFormatOptional - if !ccb.libmpv.macOpts.macos_force_dedicated_gpu { + if !ccb.option.mac.macos_force_dedicated_gpu { glFormat += [glFormatAutoGPU] } @@ -289,7 +297,7 @@ class GLLayer: CAOpenGLLayer { return attributeLookUp[value.rawValue] ?? String(value.rawValue) }) - ccb.log.sendVerbose("Created CGL pixel format with attributes: " + + ccb.log.verbose("Created CGL pixel format with attributes: " + "\(attArray.joined(separator: ", "))") return (pix, glFormat.contains(glFormat10Bit) ? 16 : 8, err) } @@ -297,11 +305,11 @@ class GLLayer: CAOpenGLLayer { } let errS = String(cString: CGLErrorString(err)) - ccb.log.sendWarning("Couldn't create a " + + ccb.log.warning("Couldn't create a " + "\(software ? "software" : "hardware accelerated") " + "CGL pixel format: \(errS) (\(err.rawValue))") - if software == false && ccb.libmpv.macOpts.cocoa_cb_sw_renderer == -1 { - ccb.log.sendWarning("Falling back to software renderer") + if software == false && ccb.option.mac.cocoa_cb_sw_renderer == -1 { + ccb.log.warning("Falling back to software renderer") } return (pix, 8, err) @@ -313,7 +321,7 @@ class GLLayer: CAOpenGLLayer { guard let cglContext = context, error == kCGLNoError else { let errS = String(cString: CGLErrorString(error)) - ccb.log.sendError("Couldn't create a CGLContext: " + errS) + ccb.log.error("Couldn't create a CGLContext: " + errS) exit(1) } diff --git a/video/out/mac/metal_layer.swift b/video/out/mac/metal_layer.swift index 7cea87c..7fc419a 100644 --- a/video/out/mac/metal_layer.swift +++ b/video/out/mac/metal_layer.swift @@ -16,10 +16,22 @@ */ import Cocoa +import QuartzCore class MetalLayer: CAMetalLayer { unowned var common: MacCommon + // workaround for a MoltenVK workaround that sets the drawableSize to 1x1 to forcefully complete + // the presentation, this causes flicker and the drawableSize possibly staying at 1x1 + override var drawableSize: CGSize { + get { return super.drawableSize } + set { + if Int(newValue.width) > 1 && Int(newValue.height) > 1 { + super.drawableSize = newValue + } + } + } + init(common com: MacCommon) { common = com super.init() diff --git a/video/out/mac/title_bar.swift b/video/out/mac/title_bar.swift index 764c1ff..b274100 100644 --- a/video/out/mac/title_bar.swift +++ b/video/out/mac/title_bar.swift @@ -19,7 +19,7 @@ import Cocoa class TitleBar: NSVisualEffectView { unowned var common: Common - var mpv: MPVHelper? { get { return common.mpv } } + var option: OptionHelper { get { return common.option } } var systemBar: NSView? { get { return common.window?.standardWindowButton(.closeButton)?.superview } @@ -64,9 +64,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(option.mac.macos_title_bar_appearance)) + set(material: Int(option.mac.macos_title_bar_material)) + set(color: option.mac.macos_title_bar_color) } required init?(coder: NSCoder) { @@ -195,10 +195,6 @@ class TitleBar: NSVisualEffectView { default: return nil } - - - let style = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") - return appearanceFrom(string: style == nil ? "aqua" : "vibrantDark") } func materialFrom(string: String) -> NSVisualEffectView.Material { @@ -221,9 +217,7 @@ class TitleBar: NSVisualEffectView { case "15", "light": return .light case "16", "mediumLight": return .mediumLight case "17", "ultraDark": return .ultraDark - default: break + default: return .titlebar } - - return .titlebar } } diff --git a/video/out/mac/view.swift b/video/out/mac/view.swift index c4776c3..047a523 100644 --- a/video/out/mac/view.swift +++ b/video/out/mac/view.swift @@ -17,9 +17,9 @@ import Cocoa -class View: NSView { +class View: NSView, CALayerDelegate { unowned var common: Common - var mpv: MPVHelper? { get { return common.mpv } } + var input: InputHelper? { get { return common.input } } var tracker: NSTrackingArea? var hasMouseDown: Bool = false @@ -52,7 +52,7 @@ class View: NSView { addTrackingArea(tracker!) if containsMouseLocation() { - cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0) + input?.put(key: SWIFT_KEY_MOUSE_LEAVE) } } @@ -77,30 +77,24 @@ class View: NSView { override func performDragOperation(_ sender: NSDraggingInfo) -> Bool { let pb = sender.draggingPasteboard guard let types = pb.types else { return false } + var files: [String] = [] if types.contains(.fileURL) || types.contains(.URL) { - if let urls = pb.readObjects(forClasses: [NSURL.self]) as? [URL] { - let files = urls.map { $0.absoluteString } - EventsResponder.sharedInstance().handleFilesArray(files) - return true - } + guard let urls = pb.readObjects(forClasses: [NSURL.self]) as? [URL] else { return false } + files = urls.map { $0.absoluteString } } else if types.contains(.string) { guard let str = pb.string(forType: .string) else { return false } - var filesArray: [String] = [] - - for val in str.components(separatedBy: "\n") { - let url = val.trimmingCharacters(in: .whitespacesAndNewlines) + files = str.components(separatedBy: "\n").compactMap { + let url = $0.trimmingCharacters(in: .whitespacesAndNewlines) let path = (url as NSString).expandingTildeInPath - if isURL(url) { - filesArray.append(url) - } else if path.starts(with: "/") { - filesArray.append(path) - } + if isURL(url) { return url } + if path.starts(with: "/") { return path } + return nil } - EventsResponder.sharedInstance().handleFilesArray(filesArray) - return true } - return false + if files.isEmpty { return false } + input?.open(files: files) + return true } override func acceptsFirstMouse(for event: NSEvent?) -> Bool { @@ -116,94 +110,66 @@ class View: NSView { } override func mouseEntered(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_ENTER, 0) + if input?.mouseEnabled() ?? true { + input?.put(key: SWIFT_KEY_MOUSE_ENTER) } common.updateCursorVisibility() } override func mouseExited(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0) + if input?.mouseEnabled() ?? true { + input?.put(key: SWIFT_KEY_MOUSE_LEAVE) } common.titleBar?.hide() common.setCursorVisibility(true) } override func mouseMoved(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseMovement(event) - } + signalMouseMovement(event) common.titleBar?.show() } override func mouseDragged(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseMovement(event) - } + signalMouseMovement(event) } override func mouseDown(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseDown(event) - } + hasMouseDown = event.clickCount <= 1 + input?.processMouse(event: event) } override func mouseUp(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseUp(event) - } + hasMouseDown = false common.window?.isMoving = false + input?.processMouse(event: event) } override func rightMouseDown(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseDown(event) - } + hasMouseDown = event.clickCount <= 1 + input?.processMouse(event: event) } override func rightMouseUp(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseUp(event) - } + hasMouseDown = false + input?.processMouse(event: event) } override func otherMouseDown(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseDown(event) - } + hasMouseDown = event.clickCount <= 1 + input?.processMouse(event: event) } override func otherMouseUp(with event: NSEvent) { - if mpv?.mouseEnabled() ?? true { - signalMouseUp(event) - } + hasMouseDown = false + input?.processMouse(event: event) } override func magnify(with event: NSEvent) { - event.phase == .ended ? - common.windowDidEndLiveResize() : common.windowWillStartLiveResize() - + common.window?.isAnimating = event.phase != .ended + event.phase == .ended ? common.windowDidEndLiveResize() : common.windowWillStartLiveResize() common.window?.addWindowScale(Double(event.magnification)) } - func signalMouseDown(_ event: NSEvent) { - signalMouseEvent(event, MP_KEY_STATE_DOWN) - if event.clickCount > 1 { - signalMouseEvent(event, MP_KEY_STATE_UP) - } - } - - func signalMouseUp(_ event: NSEvent) { - signalMouseEvent(event, MP_KEY_STATE_UP) - } - - func signalMouseEvent(_ event: NSEvent, _ state: UInt32) { - hasMouseDown = state == MP_KEY_STATE_DOWN - let mpkey = getMpvButton(event) - cocoa_put_key_with_modifiers((mpkey | Int32(state)), Int32(event.modifierFlags.rawValue)) - } - func signalMouseMovement(_ event: NSEvent) { var point = convert(event.locationInWindow, from: nil) point = convertToBacking(point) @@ -211,46 +177,12 @@ class View: NSView { common.window?.updateMovableBackground(point) if !(common.window?.isMoving ?? false) { - mpv?.setMousePosition(point) - } - } - - func preciseScroll(_ event: NSEvent) { - var delta: Double - var cmd: Int32 - - if abs(event.deltaY) >= abs(event.deltaX) { - delta = Double(event.deltaY) * 0.1 - cmd = delta > 0 ? SWIFT_WHEEL_UP : SWIFT_WHEEL_DOWN - } else { - delta = Double(event.deltaX) * 0.1 - cmd = delta > 0 ? SWIFT_WHEEL_LEFT : SWIFT_WHEEL_RIGHT + input?.setMouse(position: point) } - - mpv?.putAxis(cmd, delta: abs(delta)) } override func scrollWheel(with event: NSEvent) { - if !(mpv?.mouseEnabled() ?? true) { - return - } - - if event.hasPreciseScrollingDeltas { - preciseScroll(event) - } else { - let modifiers = event.modifierFlags - let deltaX = modifiers.contains(.shift) ? event.scrollingDeltaY : event.scrollingDeltaX - let deltaY = modifiers.contains(.shift) ? event.scrollingDeltaX : event.scrollingDeltaY - var mpkey: Int32 - - if abs(deltaY) >= abs(deltaX) { - mpkey = deltaY > 0 ? SWIFT_WHEEL_UP : SWIFT_WHEEL_DOWN - } else { - mpkey = deltaX > 0 ? SWIFT_WHEEL_LEFT : SWIFT_WHEEL_RIGHT - } - - cocoa_put_key_with_modifiers(mpkey, Int32(modifiers.rawValue)) - } + input?.processWheel(event: event) } func containsMouseLocation() -> Bool { @@ -282,16 +214,4 @@ class View: NSView { guard let window = common.window else { return false } return !hasMouseDown && containsMouseLocation() && window.isKeyWindow } - - func getMpvButton(_ event: NSEvent) -> Int32 { - let buttonNumber = event.buttonNumber - switch (buttonNumber) { - case 0: return SWIFT_MBTN_LEFT - case 1: return SWIFT_MBTN_RIGHT - case 2: return SWIFT_MBTN_MID - case 3: return SWIFT_MBTN_BACK - case 4: return SWIFT_MBTN_FORWARD - default: return SWIFT_MBTN9 + Int32(buttonNumber - 5) - } - } } diff --git a/video/out/mac/window.swift b/video/out/mac/window.swift index 7b1a858..c5a711e 100644 --- a/video/out/mac/window.swift +++ b/video/out/mac/window.swift @@ -19,14 +19,15 @@ import Cocoa class Window: NSWindow, NSWindowDelegate { weak var common: Common! = nil - var mpv: MPVHelper? { get { return common.mpv } } + var option: OptionHelper { get { return common.option } } + var input: InputHelper? { get { return common.input } } var targetScreen: NSScreen? var previousScreen: NSScreen? var currentScreen: NSScreen? var unfScreen: NSScreen? - var unfsContentFrame: NSRect? + var unfsContentFrame: NSRect = NSRect(x: 0, y: 0, width: 160, height: 90) var isInFullscreen: Bool = false var isMoving: Bool = false var previousStyleMask: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable] @@ -34,8 +35,8 @@ class Window: NSWindow, NSWindowDelegate { var isAnimating: Bool = false let animationLock: NSCondition = NSCondition() - var unfsContentFramePixel: NSRect { get { return convertToBacking(unfsContentFrame ?? NSRect(x: 0, y: 0, width: 160, height: 90)) } } - var framePixel: NSRect { get { return convertToBacking(frame) } } + var unfsContentFramePixel: NSRect { get { return convertToBacking(unfsContentFrame) } } + @objc var framePixel: NSRect { get { return convertToBacking(frame) } } var keepAspect: Bool = true { didSet { @@ -44,7 +45,7 @@ class Window: NSWindow, NSWindowDelegate { } if keepAspect { - contentAspectRatio = unfsContentFrame?.size ?? contentAspectRatio + contentAspectRatio = unfsContentFrame.size } else { resizeIncrements = NSSize(width: 1.0, height: 1.0) } @@ -91,7 +92,9 @@ class Window: NSWindow, NSWindowDelegate { title = com.title minSize = NSMakeSize(160, 90) collectionBehavior = .fullScreenPrimary + ignoresMouseEvents = option.vo.cursor_passthrough delegate = self + unfsContentFrame = contentRect if let cView = contentView { cView.addSubview(view) @@ -103,13 +106,11 @@ class Window: NSWindow, NSWindowDelegate { currentScreen = screen unfScreen = screen - if let app = NSApp as? Application { - app.menuBar.register(#selector(setHalfWindowSize), for: MPM_H_SIZE) - app.menuBar.register(#selector(setNormalWindowSize), for: MPM_N_SIZE) - app.menuBar.register(#selector(setDoubleWindowSize), for: MPM_D_SIZE) - app.menuBar.register(#selector(performMiniaturize(_:)), for: MPM_MINIMIZE) - app.menuBar.register(#selector(performZoom(_:)), for: MPM_ZOOM) - } + AppHub.shared.menu?.register(#selector(setHalfWindowSize), key: .itemHalfSize) + AppHub.shared.menu?.register(#selector(setNormalWindowSize), key: .itemNormalSize) + AppHub.shared.menu?.register(#selector(setDoubleWindowSize), key: .itemDoubleSize) + AppHub.shared.menu?.register(#selector(performMiniaturize(_:)), key: .itemMinimize) + AppHub.shared.menu?.register(#selector(performZoom(_:)), key: .itemZoom) } override func toggleFullScreen(_ sender: Any?) { @@ -141,7 +142,7 @@ class Window: NSWindow, NSWindowDelegate { setFrame(frame, display: true) } - if Bool(mpv?.opts.native_fs ?? true) { + if Bool(option.vo.native_fs) { super.toggleFullScreen(sender) } else { if !isInFullscreen { @@ -192,7 +193,7 @@ class Window: NSWindow, NSWindowDelegate { func windowDidEnterFullScreen(_ notification: Notification) { isInFullscreen = true - mpv?.setOption(fullscreen: isInFullscreen) + option.setOption(fullscreen: isInFullscreen) common.updateCursorVisibility() endAnimation(frame) common.titleBar?.show() @@ -201,7 +202,7 @@ class Window: NSWindow, NSWindowDelegate { func windowDidExitFullScreen(_ notification: Notification) { guard let tScreen = targetScreen else { return } isInFullscreen = false - mpv?.setOption(fullscreen: isInFullscreen) + option.setOption(fullscreen: isInFullscreen) endAnimation(calculateWindowPosition(for: tScreen, withoutBounds: targetScreen == screen)) common.view?.layerContentsPlacement = .scaleProportionallyToFit } @@ -249,7 +250,7 @@ class Window: NSWindow, NSWindowDelegate { setFrame(targetFrame, display: true) endAnimation() isInFullscreen = true - mpv?.setOption(fullscreen: isInFullscreen) + option.setOption(fullscreen: isInFullscreen) common.windowSetToFullScreen() } @@ -268,7 +269,7 @@ class Window: NSWindow, NSWindowDelegate { setFrame(newFrame, display: true) endAnimation() isInFullscreen = false - mpv?.setOption(fullscreen: isInFullscreen) + option.setOption(fullscreen: isInFullscreen) common.windowSetToWindow() } @@ -281,7 +282,7 @@ class Window: NSWindow, NSWindowDelegate { } func getFsAnimationDuration(_ def: Double) -> Double { - let duration = mpv?.macOpts.macos_fs_animation_duration ?? -1 + let duration = option.mac.macos_fs_animation_duration if duration < 0 { return def } else { @@ -334,7 +335,7 @@ class Window: NSWindow, NSWindowDelegate { func updateMovableBackground(_ pos: NSPoint) { if !isInFullscreen { - isMovableByWindowBackground = mpv?.canBeDraggedAt(pos) ?? true + isMovableByWindowBackground = input?.draggable(at: pos) ?? true } else { isMovableByWindowBackground = false } @@ -342,35 +343,31 @@ class Window: NSWindow, NSWindowDelegate { func updateFrame(_ rect: NSRect) { if rect != frame { - let cRect = frameRect(forContentRect: rect) unfsContentFrame = rect - setFrame(cRect, display: true) - common.windowDidUpdateFrame() + if !isInFullscreen { + let cRect = frameRect(forContentRect: rect) + setFrame(cRect, display: true) + common.windowDidUpdateFrame() + } } } func updateSize(_ size: NSSize) { if let currentSize = contentView?.frame.size, size != currentSize { let newContentFrame = centeredContentSize(for: frame, size: size) - if !isInFullscreen { - updateFrame(newContentFrame) - } else { - unfsContentFrame = newContentFrame - } + updateFrame(newContentFrame) } } override func setFrame(_ frameRect: NSRect, display flag: Bool) { if frameRect.width < minSize.width || frameRect.height < minSize.height { - common.log.sendVerbose("tried to set too small window size: \(frameRect.size)") + common.log.verbose("tried to set too small window size: \(frameRect.size)") return } super.setFrame(frameRect, display: flag) - if let size = unfsContentFrame?.size, keepAspect { - contentAspectRatio = size - } + if keepAspect { contentAspectRatio = unfsContentFrame.size } } func centeredContentSize(for rect: NSRect, size sz: NSSize) -> NSRect { @@ -391,10 +388,9 @@ class Window: NSWindow, NSWindowDelegate { } func calculateWindowPosition(for tScreen: NSScreen, withoutBounds: Bool) -> NSRect { - guard let contentFrame = unfsContentFrame, let screen = unfScreen else { - return frame - } - var newFrame = frameRect(forContentRect: contentFrame) + guard let screen = unfScreen else { return frame } + + var newFrame = frameRect(forContentRect: unfsContentFrame) let targetFrame = tScreen.frame let targetVisibleFrame = tScreen.visibleFrame let unfsScreenFrame = screen.frame @@ -504,12 +500,12 @@ class Window: NSWindow, NSWindowDelegate { @objc func setDoubleWindowSize() { setWindowScale(2.0) } func setWindowScale(_ scale: Double) { - mpv?.command("set window-scale \(scale)") + input?.command("set window-scale \(scale)") } func addWindowScale(_ scale: Double) { if !isInFullscreen { - mpv?.command("add window-scale \(scale)") + input?.command("add current-window-scale \(scale)") } } @@ -542,7 +538,7 @@ class Window: NSWindow, NSWindowDelegate { func windowDidEndLiveResize(_ notification: Notification) { common.windowDidEndLiveResize() - mpv?.setOption(maximized: isZoomed) + option.setOption(maximized: isZoomed) if let contentViewFrame = contentView?.frame, !isAnimating && !isInFullscreen @@ -552,20 +548,23 @@ class Window: NSWindow, NSWindowDelegate { } func windowDidResize(_ notification: Notification) { + if let contentViewFrame = contentView?.frame, !isAnimating && !isInFullscreen && !inLiveResize { + unfsContentFrame = convertToScreen(contentViewFrame) + } common.windowDidResize() } func windowShouldClose(_ sender: NSWindow) -> Bool { - cocoa_put_key(MP_KEY_CLOSE_WIN) + input?.put(key: MP_KEY_CLOSE_WIN) return false } func windowDidMiniaturize(_ notification: Notification) { - mpv?.setOption(minimized: true) + option.setOption(minimized: true) } func windowDidDeminiaturize(_ notification: Notification) { - mpv?.setOption(minimized: false) + option.setOption(minimized: false) } func windowDidResignKey(_ notification: Notification) { @@ -588,6 +587,6 @@ class Window: NSWindow, NSWindowDelegate { } func windowDidMove(_ notification: Notification) { - mpv?.setOption(maximized: isZoomed) + option.setOption(maximized: isZoomed) } } |