/* * 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 MacCommon: Common { @objc var layer: MetalLayer? var timer: PreciseTimer? var swapTime: UInt64 = 0 let swapLock: NSCondition = NSCondition() @objc init(_ vo: UnsafeMutablePointer) { let newlog = mp_log_new(vo, vo.pointee.log, "mac") super.init(newlog) option = OptionHelper(vo) input = InputHelper(vo.pointee.input_ctx, option) timer = PreciseTimer(common: self) DispatchQueue.main.sync { layer = MetalLayer(common: self) initMisc(vo) } } @objc func config(_ vo: UnsafeMutablePointer) -> Bool { option?.vo = vo DispatchQueue.main.sync { let previousActiveApp = getActiveApp() initApp() let (_, _, wr) = getInitProperties(vo) guard let layer = self.layer else { log.sendError("Something went wrong, no MetalLayer was initialized") exit(1) } if window == nil { initView(vo, layer) initWindow(vo, previousActiveApp) initWindowState() } if !NSEqualSizes(window?.unfsContentFramePixel.size ?? NSZeroSize, wr.size) && option?.opts.auto_window_resize ?? true { window?.updateSize(wr.size) } if option?.opts.focus_on ?? 1 == 2 { NSApp.activate(ignoringOtherApps: true) } windowDidResize() updateICCProfile() } return true } @objc func uninit(_ vo: UnsafeMutablePointer) { window?.waitForAnimation() timer?.terminate() DispatchQueue.main.sync { window?.delegate = nil window?.close() uninitCommon() } } @objc func swapBuffer() { if option?.macOpts.macos_render_timer ?? Int32(RENDER_TIMER_CALLBACK) != RENDER_TIMER_SYSTEM { swapLock.lock() while(swapTime < 1) { swapLock.wait() } swapTime = 0 swapLock.unlock() } } override func displayLinkCallback(_ displayLink: CVDisplayLink, _ inNow: UnsafePointer, _ inOutputTime: UnsafePointer, _ flagsIn: CVOptionFlags, _ flagsOut: UnsafeMutablePointer) -> CVReturn { let frameTimer = option?.macOpts.macos_render_timer ?? Int32(RENDER_TIMER_CALLBACK) let signalSwap = { self.swapLock.lock() self.swapTime += 1 self.swapLock.signal() self.swapLock.unlock() } if frameTimer != RENDER_TIMER_SYSTEM { if let timer = self.timer, frameTimer == RENDER_TIMER_PRECISE { timer.scheduleAt(time: inOutputTime.pointee.hostTime, closure: signalSwap) return kCVReturnSuccess } signalSwap() } return kCVReturnSuccess } override func startDisplayLink(_ vo: UnsafeMutablePointer) { super.startDisplayLink(vo) timer?.updatePolicy(periodSeconds: 1 / currentFps()) } override func updateDisplaylink() { super.updateDisplaylink() timer?.updatePolicy(periodSeconds: 1 / currentFps()) } override func lightSensorUpdate() { flagEvents(VO_EVENT_AMBIENT_LIGHTING_CHANGED) } override func updateICCProfile() { flagEvents(VO_EVENT_ICC_PROFILE_CHANGED) } override func windowDidResize() { flagEvents(VO_EVENT_RESIZE | VO_EVENT_EXPOSE) } override func windowDidChangeScreenProfile() { updateICCProfile() } override func windowDidChangeBackingProperties() { layer?.contentsScale = window?.backingScaleFactor ?? 1 windowDidResize() } }