diff options
-rw-r--r-- | osdep/macOS_mpv_helper.swift | 46 | ||||
-rw-r--r-- | osdep/macOS_swift_extensions.swift | 16 | ||||
-rw-r--r-- | video/out/cocoa-cb/events_view.swift | 40 | ||||
-rw-r--r-- | video/out/cocoa-cb/title_bar.swift | 62 | ||||
-rw-r--r-- | video/out/cocoa-cb/video_layer.swift | 207 | ||||
-rw-r--r-- | video/out/cocoa-cb/window.swift | 128 | ||||
-rw-r--r-- | video/out/cocoa_cb_common.swift | 283 |
7 files changed, 448 insertions, 334 deletions
diff --git a/osdep/macOS_mpv_helper.swift b/osdep/macOS_mpv_helper.swift index fe747db08c..35435835de 100644 --- a/osdep/macOS_mpv_helper.swift +++ b/osdep/macOS_mpv_helper.swift @@ -44,14 +44,22 @@ class MPVHelper: NSObject { mpvHandle = mpv mpvLog = mp_log_new(UnsafeMutablePointer<MPContext>(mpvHandle), mp_client_get_log(mpvHandle), "cocoacb") - mpctx = UnsafeMutablePointer<MPContext>(mp_client_get_core(mpvHandle)) - inputContext = mpctx!.pointee.input + guard let mpctx = UnsafeMutablePointer<MPContext>(mp_client_get_core(mpvHandle)) else { + sendError("No MPContext available") + exit(1) + } - if let app = NSApp as? Application { - let ptr = mp_get_config_group(mpctx!, mp_client_get_global(mpvHandle), - app.getMacOSConf()) - macOpts = UnsafeMutablePointer<macos_opts>(OpaquePointer(ptr))!.pointee + 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<macos_opts>(OpaquePointer(ptr)).pointee mpv_observe_property(mpvHandle, 0, "ontop", MPV_FORMAT_FLAG) mpv_observe_property(mpvHandle, 0, "border", MPV_FORMAT_FLAG) @@ -83,7 +91,7 @@ class MPVHelper: NSObject { } let getProcAddress: (@convention(c) (UnsafeMutableRawPointer?, UnsafePointer<Int8>?) - -> UnsafeMutableRawPointer?)! = + -> UnsafeMutableRawPointer?) = { (ctx: UnsafeMutableRawPointer?, name: UnsafePointer<Int8>?) -> UnsafeMutableRawPointer? in @@ -214,27 +222,31 @@ class MPVHelper: NSObject { } func getStringProperty(_ name: String) -> String? { - if mpvHandle == nil { return nil } - let value = mpv_get_property_string(mpvHandle, name) - let str = value == nil ? nil : String(cString: value!) + 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 { - if inputContext == nil { return false } - let canDrag = !mp_input_test_dragging(inputContext!, Int32(pos.x), Int32(pos.y)) + 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) { - if inputContext == nil { return } - mp_input_set_mouse_pos(inputContext!, Int32(pos.x), Int32(pos.y)) + guard let input = inputContext else { return } + mp_input_set_mouse_pos(input, Int32(pos.x), Int32(pos.y)) } func putAxis(_ mpkey: Int32, delta: Double) { - if inputContext == nil { return } - mp_input_put_wheel(inputContext!, mpkey, delta) + guard let input = inputContext else { return } + mp_input_put_wheel(input, mpkey, delta) } func sendVerbose(_ msg: String) { @@ -257,7 +269,7 @@ class MPVHelper: NSObject { if mpvLog == nil { sendFallback(message: msg, type: t) } else { - let args: [CVarArg] = [ (msg as NSString).utf8String! ] + let args: [CVarArg] = [ (msg as NSString).utf8String ?? "NO MESSAGE"] mp_msg_va(mpvLog, Int32(t), "%s\n", getVaList(args)) } } diff --git a/osdep/macOS_swift_extensions.swift b/osdep/macOS_swift_extensions.swift index cc7438fd8c..7929d48f9a 100644 --- a/osdep/macOS_swift_extensions.swift +++ b/osdep/macOS_swift_extensions.swift @@ -21,7 +21,7 @@ extension NSScreen { public var displayID: CGDirectDisplayID { get { - return deviceDescription["NSScreenNumber"] as! CGDirectDisplayID + return deviceDescription["NSScreenNumber"] as? CGDirectDisplayID ?? 0 } } @@ -37,8 +37,8 @@ extension NSScreen { repeat { object = IOIteratorNext(iter) - let info = IODisplayCreateInfoDictionary(object, IOOptionBits(kIODisplayOnlyPreferredName)).takeRetainedValue() as! [String:AnyObject] - if (info[kDisplayVendorID] as? UInt32 == CGDisplayVendorNumber(displayID) && + 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)) { @@ -60,11 +60,11 @@ extension NSScreen { extension NSColor { convenience init(hex: String) { - let int = Int(hex.dropFirst(), radix: 16) - 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 + 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/video/out/cocoa-cb/events_view.swift b/video/out/cocoa-cb/events_view.swift index b9de12ca26..9c30e32ca0 100644 --- a/video/out/cocoa-cb/events_view.swift +++ b/video/out/cocoa-cb/events_view.swift @@ -20,9 +20,7 @@ import Cocoa class EventsView: NSView { weak var cocoaCB: CocoaCB! - var mpv: MPVHelper! { - get { return cocoaCB == nil ? nil : cocoaCB.mpv } - } + var mpv: MPVHelper { get { return cocoaCB.mpv } } var tracker: NSTrackingArea? var hasMouseDown: Bool = false @@ -46,13 +44,14 @@ class EventsView: NSView { } override func updateTrackingAreas() { - if tracker != nil { - removeTrackingArea(tracker!) + if let tracker = self.tracker { + removeTrackingArea(tracker) } tracker = NSTrackingArea(rect: bounds, options: [.activeAlways, .mouseEnteredAndExited, .mouseMoved, .enabledDuringMouseDrag], owner: self, userInfo: nil) + // here tracker is guaranteed to be none-nil addTrackingArea(tracker!) if containsMouseLocation() { @@ -72,6 +71,7 @@ class EventsView: NSView { } func isURL(_ str: String) -> Bool { + // force unwrapping is fine here, regex is guarnteed to be valid let regex = try! NSRegularExpression(pattern: "^(https?|ftp)://[^\\s/$.?#].[^\\s]*$", options: .caseInsensitive) let isURL = regex.numberOfMatches(in: str, @@ -135,14 +135,14 @@ class EventsView: NSView { if mpv.getBoolProperty("input-cursor") { cocoa_put_key_with_modifiers(SWIFT_KEY_MOUSE_LEAVE, 0) } - cocoaCB.titleBar.hide() + cocoaCB.titleBar?.hide() } override func mouseMoved(with event: NSEvent) { - if mpv != nil && mpv.getBoolProperty("input-cursor") { + if mpv.getBoolProperty("input-cursor") { signalMouseMovement(event) } - cocoaCB.titleBar.show() + cocoaCB.titleBar?.show() } override func mouseDragged(with event: NSEvent) { @@ -161,7 +161,7 @@ class EventsView: NSView { if mpv.getBoolProperty("input-cursor") { signalMouseUp(event) } - cocoaCB.window.isMoving = false + cocoaCB.window?.isMoving = false } override func rightMouseDown(with event: NSEvent) { @@ -210,8 +210,8 @@ class EventsView: NSView { point = convertToBacking(point) point.y = -point.y - cocoaCB.window.updateMovableBackground(point) - if !cocoaCB.window.isMoving { + cocoaCB.window?.updateMovableBackground(point) + if !(cocoaCB.window?.isMoving ?? false) { mpv.setMousePosition(point) } } @@ -257,21 +257,23 @@ class EventsView: NSView { func containsMouseLocation() -> Bool { if cocoaCB == nil { return false } var topMargin: CGFloat = 0.0 - let menuBarHeight = NSApp.mainMenu!.menuBarHeight + let menuBarHeight = NSApp.mainMenu?.menuBarHeight ?? 23.0 + + guard let window = cocoaCB.window else { return false } + guard var vF = window.screen?.frame else { return false } - if cocoaCB.window.isInFullscreen && (menuBarHeight > 0) { + if window.isInFullscreen && (menuBarHeight > 0) { topMargin = TitleBar.height + 1 + menuBarHeight } - guard var vF = window?.screen?.frame else { return false } vF.size.height -= topMargin - let vFW = window!.convertFromScreen(vF) + let vFW = window.convertFromScreen(vF) let vFV = convert(vFW, from: nil) - let pt = convert(window!.mouseLocationOutsideOfEventStream, from: nil) + let pt = convert(window.mouseLocationOutsideOfEventStream, from: nil) var clippedBounds = bounds.intersection(vFV) - if !cocoaCB.window.isInFullscreen { + if !window.isInFullscreen { clippedBounds.origin.y += TitleBar.height clippedBounds.size.height -= TitleBar.height } @@ -279,8 +281,8 @@ class EventsView: NSView { } func canHideCursor() -> Bool { - if cocoaCB.window == nil { return false } - return !hasMouseDown && containsMouseLocation() && window!.isKeyWindow + guard let window = cocoaCB.window else { return false } + return !hasMouseDown && containsMouseLocation() && window.isKeyWindow } func getMpvButton(_ event: NSEvent) -> Int32 { diff --git a/video/out/cocoa-cb/title_bar.swift b/video/out/cocoa-cb/title_bar.swift index 8a7bf30f02..596a13ba7b 100644 --- a/video/out/cocoa-cb/title_bar.swift +++ b/video/out/cocoa-cb/title_bar.swift @@ -19,19 +19,17 @@ import Cocoa class TitleBar: NSVisualEffectView { - weak var cocoaCB: CocoaCB! = nil - var mpv: MPVHelper! { - get { return cocoaCB == nil ? nil : cocoaCB.mpv } - } + weak var cocoaCB: CocoaCB! + var mpv: MPVHelper { get { return cocoaCB.mpv } } - var systemBar: NSView { - get { return (cocoaCB.window.standardWindowButton(.closeButton)?.superview)! } + var systemBar: NSView? { + get { return cocoaCB.window?.standardWindowButton(.closeButton)?.superview } } static var height: CGFloat { get { return NSWindow.frameRect(forContentRect: CGRect.zero, styleMask: .titled).size.height } } var buttons: [NSButton] { - get { return ([.closeButton, .miniaturizeButton, .zoomButton] as [NSWindowButton]).flatMap { cocoaCB.window.standardWindowButton($0) } } + get { return ([.closeButton, .miniaturizeButton, .zoomButton] as [NSWindowButton]).flatMap { cocoaCB.window?.standardWindowButton($0) } } } override var material: NSVisualEffectView.Material { @@ -52,24 +50,28 @@ class TitleBar: NSVisualEffectView { } } - convenience init(frame: NSRect, window: NSWindow, cocoaCB ccb: CocoaCB) { + init(frame: NSRect, window: NSWindow, cocoaCB ccb: CocoaCB) { let f = NSMakeRect(0, frame.size.height - TitleBar.height, frame.size.width, TitleBar.height) - self.init(frame: f) cocoaCB = ccb + super.init(frame: f) alphaValue = 0 blendingMode = .withinWindow autoresizingMask = [.viewWidthSizable, .viewMinYMargin] - systemBar.alphaValue = 0 + systemBar?.alphaValue = 0 state = .followsWindowActiveState wantsLayer = true - window.contentView!.addSubview(self, positioned: .above, relativeTo: nil) + window.contentView?.addSubview(self, positioned: .above, relativeTo: nil) window.titlebarAppearsTransparent = true window.styleMask.insert(.fullSizeContentView) - set(appearance: Int(mpv.macOpts!.macos_title_bar_appearance)) - set(material: Int(mpv.macOpts!.macos_title_bar_material)) - set(color: mpv.macOpts!.macos_title_bar_color) + 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") + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") } // catch these events so they are not propagated to the underlying view @@ -87,34 +89,34 @@ class TitleBar: NSVisualEffectView { } if action == "Minimize" { - cocoaCB.window.miniaturize(self) + window?.miniaturize(self) } else if action == "Maximize" { - cocoaCB.window.zoom(self) + window?.zoom(self) } } } func set(appearance: Any) { if appearance is Int { - window!.appearance = appearanceFrom(string: String(appearance as! Int)) + window?.appearance = appearanceFrom(string: String(appearance as? Int ?? 0)) } else { - window!.appearance = appearanceFrom(string: appearance as! String) + window?.appearance = appearanceFrom(string: appearance as? String ?? "auto") } } func set(material: Any) { if material is Int { - self.material = materialFrom(string: String(material as! Int)) + self.material = materialFrom(string: String(material as? Int ?? 0)) } else { - self.material = materialFrom(string: material as! String) + self.material = materialFrom(string: material as? String ?? "titlebar") } } func set(color: Any) { if color is String { - layer?.backgroundColor = NSColor(hex: color as! String).cgColor + layer?.backgroundColor = NSColor(hex: color as? String ?? "#00000000").cgColor } else { - let col = color as! m_color + let col = color as? m_color ?? m_color(r: 0, g: 0, b: 0, a: 0) let red = CGFloat(col.r)/255 let green = CGFloat(col.g)/255 let blue = CGFloat(col.b)/255 @@ -125,20 +127,21 @@ class TitleBar: NSVisualEffectView { } func show() { - if (!cocoaCB.window.border && !cocoaCB.window.isInFullscreen) { return } - let loc = cocoaCB.view.convert(cocoaCB.window.mouseLocationOutsideOfEventStream, from: nil) + guard let window = cocoaCB.window else { return } + if !window.border && !window.isInFullscreen { return } + let loc = cocoaCB.view?.convert(window.mouseLocationOutsideOfEventStream, from: nil) buttons.forEach { $0.isHidden = false } NSAnimationContext.runAnimationGroup({ (context) -> Void in context.duration = 0.20 - systemBar.animator().alphaValue = 1 - if !cocoaCB.window.isInFullscreen && !cocoaCB.window.isAnimating { + systemBar?.animator().alphaValue = 1 + if !window.isInFullscreen && !window.isAnimating { animator().alphaValue = 1 isHidden = false } }, completionHandler: nil ) - if loc.y > TitleBar.height { + if loc?.y ?? 0 > TitleBar.height { hideDelayed() } else { NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(hide), object: nil) @@ -146,14 +149,15 @@ class TitleBar: NSVisualEffectView { } func hide() { - if cocoaCB.window.isInFullscreen && !cocoaCB.window.isAnimating { + guard let window = cocoaCB.window else { return } + if window.isInFullscreen && !window.isAnimating { alphaValue = 0 isHidden = true return } NSAnimationContext.runAnimationGroup({ (context) -> Void in context.duration = 0.20 - systemBar.animator().alphaValue = 0 + systemBar?.animator().alphaValue = 0 animator().alphaValue = 0 }, completionHandler: { self.buttons.forEach { $0.isHidden = true } diff --git a/video/out/cocoa-cb/video_layer.swift b/video/out/cocoa-cb/video_layer.swift index 5de57b9e00..895d9faf29 100644 --- a/video/out/cocoa-cb/video_layer.swift +++ b/video/out/cocoa-cb/video_layer.swift @@ -19,63 +19,61 @@ import Cocoa import OpenGL.GL import OpenGL.GL3 +let glVersions: [CGLOpenGLProfile] = [ + kCGLOGLPVersion_3_2_Core, + kCGLOGLPVersion_Legacy +] + +let glFormatBase: [CGLPixelFormatAttribute] = [ + kCGLPFAOpenGLProfile, + kCGLPFAAccelerated, + kCGLPFADoubleBuffer +] + +let glFormatSoftwareBase: [CGLPixelFormatAttribute] = [ + kCGLPFAOpenGLProfile, + kCGLPFARendererID, + CGLPixelFormatAttribute(UInt32(kCGLRendererGenericFloatID)), + kCGLPFADoubleBuffer +] + +let glFormatOptional: [CGLPixelFormatAttribute] = [ + kCGLPFABackingStore, + kCGLPFAAllowOfflineRenderers, + kCGLPFASupportsAutomaticGraphicsSwitching +] + +let attributeLookUp: [UInt32:String] = [ + kCGLOGLPVersion_3_2_Core.rawValue: "kCGLOGLPVersion_3_2_Core", + kCGLOGLPVersion_Legacy.rawValue: "kCGLOGLPVersion_Legacy", + kCGLPFAOpenGLProfile.rawValue: "kCGLPFAOpenGLProfile", + UInt32(kCGLRendererGenericFloatID): "kCGLRendererGenericFloatID", + kCGLPFARendererID.rawValue: "kCGLPFARendererID", + kCGLPFAAccelerated.rawValue: "kCGLPFAAccelerated", + kCGLPFADoubleBuffer.rawValue: "kCGLPFADoubleBuffer", + kCGLPFABackingStore.rawValue: "kCGLPFABackingStore", + kCGLPFAAllowOfflineRenderers.rawValue: "kCGLPFAAllowOfflineRenderers", + kCGLPFASupportsAutomaticGraphicsSwitching.rawValue: "kCGLPFASupportsAutomaticGraphicsSwitching", +] + class VideoLayer: CAOpenGLLayer { weak var cocoaCB: CocoaCB! - var mpv: MPVHelper! { - get { return cocoaCB == nil ? nil : cocoaCB.mpv } - } + var mpv: MPVHelper { get { return cocoaCB.mpv } } let videoLock = NSLock() let displayLock = NSLock() + let cglContext: CGLContextObj + let cglPixelFormat: CGLPixelFormatObj var needsFlip: Bool = false var forceDraw: Bool = false - var cglContext: CGLContextObj? = nil - var cglPixelFormat: CGLPixelFormatObj? = nil - var surfaceSize: NSSize? + var surfaceSize: NSSize = NSSize(width: 0, height: 0) enum Draw: Int { case normal = 1, atomic, atomicEnd } var draw: Draw = .normal let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue.draw") - let glVersions: [CGLOpenGLProfile] = [ - kCGLOGLPVersion_3_2_Core, - kCGLOGLPVersion_Legacy - ] - - let glFormatBase: [CGLPixelFormatAttribute] = [ - kCGLPFAOpenGLProfile, - kCGLPFAAccelerated, - kCGLPFADoubleBuffer - ] - - let glFormatSoftwareBase: [CGLPixelFormatAttribute] = [ - kCGLPFAOpenGLProfile, - kCGLPFARendererID, - CGLPixelFormatAttribute(UInt32(kCGLRendererGenericFloatID)), - kCGLPFADoubleBuffer - ] - - let glFormatOptional: [CGLPixelFormatAttribute] = [ - kCGLPFABackingStore, - kCGLPFAAllowOfflineRenderers, - kCGLPFASupportsAutomaticGraphicsSwitching - ] - - let attributeLookUp: [UInt32:String] = [ - kCGLOGLPVersion_3_2_Core.rawValue: "kCGLOGLPVersion_3_2_Core", - kCGLOGLPVersion_Legacy.rawValue: "kCGLOGLPVersion_Legacy", - kCGLPFAOpenGLProfile.rawValue: "kCGLPFAOpenGLProfile", - UInt32(kCGLRendererGenericFloatID): "kCGLRendererGenericFloatID", - kCGLPFARendererID.rawValue: "kCGLPFARendererID", - kCGLPFAAccelerated.rawValue: "kCGLPFAAccelerated", - kCGLPFADoubleBuffer.rawValue: "kCGLPFADoubleBuffer", - kCGLPFABackingStore.rawValue: "kCGLPFABackingStore", - kCGLPFAAllowOfflineRenderers.rawValue: "kCGLPFAAllowOfflineRenderers", - kCGLPFASupportsAutomaticGraphicsSwitching.rawValue: "kCGLPFASupportsAutomaticGraphicsSwitching", - ] - var needsICCUpdate: Bool = false { didSet { if needsICCUpdate == true { @@ -95,24 +93,30 @@ class VideoLayer: CAOpenGLLayer { init(cocoaCB ccb: CocoaCB) { cocoaCB = ccb + cglPixelFormat = VideoLayer.createPixelFormat(ccb.mpv) + cglContext = VideoLayer.createContext(ccb.mpv, cglPixelFormat) super.init() autoresizingMask = [.layerWidthSizable, .layerHeightSizable] backgroundColor = NSColor.black.cgColor - cglPixelFormat = copyCGLPixelFormat(forDisplayMask: 0) - CGLCreateContext(cglPixelFormat!, nil, &cglContext) var i: GLint = 1 - CGLSetParameter(cglContext!, kCGLCPSwapInterval, &i) - CGLSetCurrentContext(cglContext!) + CGLSetParameter(cglContext, kCGLCPSwapInterval, &i) + CGLSetCurrentContext(cglContext) mpv.initRender() mpv.setRenderUpdateCallback(updateCallback, context: self) mpv.setRenderControlCallback(cocoaCB.controlCallback, context: cocoaCB) } + //necessary for when the layer containing window changes the screen override init(layer: Any) { - let oldLayer = layer as! VideoLayer + guard let oldLayer = layer as? VideoLayer else { + fatalError("init(layer: Any) passed an invalid layer") + } cocoaCB = oldLayer.cocoaCB + surfaceSize = oldLayer.surfaceSize + cglPixelFormat = oldLayer.cglPixelFormat + cglContext = oldLayer.cglContext super.init() } @@ -127,7 +131,7 @@ class VideoLayer: CAOpenGLLayer { if inLiveResize == false { isAsynchronous = false } - return mpv != nil && cocoaCB.backendState == .initialized && + return cocoaCB.backendState == .initialized && (forceDraw || mpv.isRenderUpdateFrame()) } @@ -147,7 +151,7 @@ class VideoLayer: CAOpenGLLayer { } updateSurfaceSize() - mpv.drawRender(surfaceSize!, ctx) + mpv.drawRender(surfaceSize, ctx) if needsICCUpdate { needsICCUpdate = false @@ -158,12 +162,12 @@ class VideoLayer: CAOpenGLLayer { func updateSurfaceSize() { var dims: [GLint] = [0, 0, 0, 0] glGetIntegerv(GLenum(GL_VIEWPORT), &dims) - surfaceSize = NSMakeSize(CGFloat(dims[2]), CGFloat(dims[3])) + surfaceSize = NSSize(width: CGFloat(dims[2]), height: CGFloat(dims[3])) - if NSEqualSizes(surfaceSize!, NSZeroSize) { + if NSEqualSizes(surfaceSize, NSZeroSize) { surfaceSize = bounds.size - surfaceSize!.width *= contentsScale - surfaceSize!.height *= contentsScale + surfaceSize.width *= contentsScale + surfaceSize.height *= contentsScale } } @@ -182,28 +186,65 @@ class VideoLayer: CAOpenGLLayer { } override func copyCGLPixelFormat(forDisplayMask mask: UInt32) -> CGLPixelFormatObj { - if cglPixelFormat != nil { return cglPixelFormat! } + return cglPixelFormat + } + + override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj { + contentsScale = cocoaCB.window?.backingScaleFactor ?? 1.0 + return cglContext + } + + let updateCallback: mpv_render_update_fn = { (ctx) in + let layer: VideoLayer = unsafeBitCast(ctx, to: VideoLayer.self) + layer.update() + } + + override func display() { + displayLock.lock() + let isUpdate = needsFlip + super.display() + CATransaction.flush() + if isUpdate && needsFlip { + CGLSetCurrentContext(cglContext) + if mpv.isRenderUpdateFrame() { + mpv.drawRender(NSZeroSize, cglContext, skip: true) + } + } + displayLock.unlock() + } + + func update(force: Bool = false) { + if force { forceDraw = true } + queue.async { + if self.forceDraw || !self.inLiveResize { + self.needsFlip = true + self.display() + } + } + } + class func createPixelFormat(_ mpv: MPVHelper) -> CGLPixelFormatObj { var pix: CGLPixelFormatObj? var err: CGLError = CGLError(rawValue: 0) + let swRender = mpv.macOpts?.cocoa_cb_sw_renderer ?? -1 - if mpv.macOpts!.cocoa_cb_sw_renderer != 1 { - (pix, err) = createPixelFormat() + if swRender != 1 { + (pix, err) = VideoLayer.findPixelFormat(mpv) } - if (err != kCGLNoError || pix == nil) && mpv.macOpts!.cocoa_cb_sw_renderer != 0 { - (pix, err) = createPixelFormat(software: true) + if (err != kCGLNoError || pix == nil) && swRender != 0 { + (pix, err) = VideoLayer.findPixelFormat(mpv, software: true) } - if err != kCGLNoError || pix == nil { + guard let pixelFormat = pix, err == kCGLNoError else { mpv.sendError("Couldn't create any CGL pixel format") exit(1) } - return pix! + return pixelFormat } - func createPixelFormat(software: Bool = false) -> (CGLPixelFormatObj?, CGLError) { + class func findPixelFormat(_ mpv: MPVHelper, software: Bool = false) -> (CGLPixelFormatObj?, CGLError) { var pix: CGLPixelFormatObj? var err: CGLError = CGLError(rawValue: 0) var npix: GLint = 0 @@ -221,7 +262,7 @@ class VideoLayer: CAOpenGLLayer { glFormat.remove(at: index) } else { let attArray = glFormat.map({ (value: _CGLPixelFormatAttribute) -> String in - return attributeLookUp[value.rawValue]! + return attributeLookUp[value.rawValue] ?? "unknown attribute" }) mpv.sendVerbose("Created CGL pixel format with attributes: " + @@ -236,45 +277,23 @@ class VideoLayer: CAOpenGLLayer { "\(software ? "software" : "hardware accelerated") " + "CGL pixel format: \(errS) (\(err.rawValue))") - if software == false && mpv.macOpts!.cocoa_cb_sw_renderer == -1 { + if software == false && (mpv.macOpts?.cocoa_cb_sw_renderer ?? -1) == -1 { mpv.sendWarning("Falling back to software renderer") } return (pix, err) } - override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj { - contentsScale = cocoaCB.window.backingScaleFactor - return cglContext! - } + class func createContext(_ mpv: MPVHelper, _ pixelFormat: CGLPixelFormatObj) -> CGLContextObj { + var context: CGLContextObj? + let error = CGLCreateContext(pixelFormat, nil, &context) - let updateCallback: mpv_render_update_fn = { (ctx) in - let layer: VideoLayer = MPVHelper.bridge(ptr: ctx!) - layer.update() - } - - override func display() { - displayLock.lock() - let isUpdate = needsFlip - super.display() - CATransaction.flush() - if isUpdate && needsFlip { - CGLSetCurrentContext(cglContext!) - if mpv.isRenderUpdateFrame() { - mpv.drawRender(NSZeroSize, cglContext!, skip: true) - } + guard let cglContext = context, error == kCGLNoError else { + let errS = String(cString: CGLErrorString(error)) + mpv.sendError("Couldn't create a CGLContext: " + errS) + exit(1) } - displayLock.unlock() - } - func update(force: Bool = false) { - if force { forceDraw = true } - queue.async { - if self.forceDraw || !self.inLiveResize { - self.needsFlip = true - self.display() - } - } + return cglContext } - } diff --git a/video/out/cocoa-cb/window.swift b/video/out/cocoa-cb/window.swift index b3ccd9d94b..35d9b1bd91 100644 --- a/video/out/cocoa-cb/window.swift +++ b/video/out/cocoa-cb/window.swift @@ -20,9 +20,7 @@ import Cocoa class Window: NSWindow, NSWindowDelegate { weak var cocoaCB: CocoaCB! = nil - var mpv: MPVHelper! { - get { return cocoaCB == nil ? nil : cocoaCB.mpv } - } + var mpv: MPVHelper { get { return cocoaCB.mpv } } var targetScreen: NSScreen? var previousScreen: NSScreen? @@ -37,12 +35,12 @@ class Window: NSWindow, NSWindowDelegate { var keepAspect: Bool = true { didSet { - if !isInFullscreen { - unfsContentFrame = convertToScreen(contentView!.frame) + if let contentViewFrame = contentView?.frame, !isInFullscreen { + unfsContentFrame = convertToScreen(contentViewFrame) } if keepAspect { - contentAspectRatio = unfsContentFrame!.size + contentAspectRatio = unfsContentFrame?.size ?? contentAspectRatio } else { resizeIncrements = NSSize(width: 1.0, height: 1.0) } @@ -50,7 +48,7 @@ class Window: NSWindow, NSWindowDelegate { } var border: Bool = true { - didSet { if !border { cocoaCB.titleBar.hide() } } + didSet { if !border { cocoaCB.titleBar?.hide() } } } override var canBecomeKey: Bool { return true } @@ -74,10 +72,10 @@ class Window: NSWindow, NSWindowDelegate { // workaround for an AppKit bug where the NSWindow can't be placed on a // none Main screen NSScreen outside the Main screen's frame bounds - if screen != NSScreen.main() { + if let wantedScreen = screen, screen != NSScreen.main() { var absoluteWantedOrigin = contentRect.origin - absoluteWantedOrigin.x += screen!.frame.origin.x - absoluteWantedOrigin.y += screen!.frame.origin.y + absoluteWantedOrigin.x += wantedScreen.frame.origin.x + absoluteWantedOrigin.y += wantedScreen.frame.origin.y if !NSEqualPoints(absoluteWantedOrigin, self.frame.origin) { self.setFrameOrigin(absoluteWantedOrigin) @@ -89,13 +87,16 @@ class Window: NSWindow, NSWindowDelegate { minSize = NSMakeSize(160, 90) collectionBehavior = .fullScreenPrimary delegate = self - contentView!.addSubview(view) - view.frame = contentView!.frame - unfsContentFrame = convertToScreen(contentView!.frame) - targetScreen = screen! - currentScreen = screen! - unfScreen = screen! + if let cView = contentView { + cView.addSubview(view) + view.frame = cView.frame + unfsContentFrame = convertToScreen(cView.frame) + } + + targetScreen = screen + currentScreen = screen + unfScreen = screen if let app = NSApp as? Application { app.menuBar.register(#selector(setHalfWindowSize), for: MPM_H_SIZE) @@ -123,13 +124,13 @@ class Window: NSWindow, NSWindowDelegate { previousScreen = screen } - if !isInFullscreen { - unfsContentFrame = convertToScreen(contentView!.frame) + if let contentViewFrame = contentView?.frame, !isInFullscreen { + unfsContentFrame = convertToScreen(contentViewFrame) unfScreen = screen } // move window to target screen when going to fullscreen - if !isInFullscreen && (targetScreen != screen) { - let frame = calculateWindowPosition(for: targetScreen!, withoutBounds: false) + if let tScreen = targetScreen, !isInFullscreen && (tScreen != screen) { + let frame = calculateWindowPosition(for: tScreen, withoutBounds: false) setFrame(frame, display: true) } @@ -154,19 +155,21 @@ class Window: NSWindow, NSWindowDelegate { } func window(_ window: NSWindow, startCustomAnimationToEnterFullScreenWithDuration duration: TimeInterval) { - cocoaCB.view.layerContentsPlacement = .scaleProportionallyToFit - cocoaCB.titleBar.hide() + guard let tScreen = targetScreen else { return } + cocoaCB.view?.layerContentsPlacement = .scaleProportionallyToFit + cocoaCB.titleBar?.hide() NSAnimationContext.runAnimationGroup({ (context) -> Void in context.duration = getFsAnimationDuration(duration - 0.05) - window.animator().setFrame(targetScreen!.frame, display: true) + window.animator().setFrame(tScreen.frame, display: true) }, completionHandler: { }) } func window(_ window: NSWindow, startCustomAnimationToExitFullScreenWithDuration duration: TimeInterval) { - let newFrame = calculateWindowPosition(for: targetScreen!, withoutBounds: targetScreen == screen) - let intermediateFrame = aspectFit(rect: newFrame, in: screen!.frame) - cocoaCB.view.layerContentsPlacement = .scaleProportionallyToFill - cocoaCB.titleBar.hide() + guard let tScreen = targetScreen, let currentScreen = screen else { return } + let newFrame = calculateWindowPosition(for: tScreen, withoutBounds: tScreen == screen) + let intermediateFrame = aspectFit(rect: newFrame, in: currentScreen.frame) + cocoaCB.view?.layerContentsPlacement = .scaleProportionallyToFill + cocoaCB.titleBar?.hide() styleMask.remove(.fullScreen) setFrame(intermediateFrame, display: true) @@ -181,27 +184,29 @@ class Window: NSWindow, NSWindowDelegate { cocoaCB.flagEvents(VO_EVENT_FULLSCREEN_STATE) cocoaCB.updateCusorVisibility() endAnimation(frame) - cocoaCB.titleBar.show() + cocoaCB.titleBar?.show() } func windowDidExitFullScreen(_ notification: Notification) { + guard let tScreen = targetScreen else { return } isInFullscreen = false cocoaCB.flagEvents(VO_EVENT_FULLSCREEN_STATE) - endAnimation(calculateWindowPosition(for: targetScreen!, withoutBounds: targetScreen == screen)) - cocoaCB.view.layerContentsPlacement = .scaleProportionallyToFit + endAnimation(calculateWindowPosition(for: tScreen, withoutBounds: targetScreen == screen)) + cocoaCB.view?.layerContentsPlacement = .scaleProportionallyToFit } func windowDidFailToEnterFullScreen(_ window: NSWindow) { - let newFrame = calculateWindowPosition(for: targetScreen!, withoutBounds: targetScreen == screen) + guard let tScreen = targetScreen else { return } + let newFrame = calculateWindowPosition(for: tScreen, withoutBounds: targetS |