cocoa-cb: remove pre-allocation of window, view and layer

the pre-allocation was needed because the layer allocated a opengl
context async itself and we couldn't influence that. so we had to start
the core after the context was actually allocated. furthermore a window,
view and layer hierarchy had to be created so the layer would create
a context.
now, instead of relying on the layer to create a context we do this
manually and re-use that context later when the layer wants to create
one async itself.
This commit is contained in:
Akemi
2018-06-06 17:04:40 +02:00
committed by Jan Ekström
parent 20dffe0621
commit 5865086aa8
9 changed files with 160 additions and 142 deletions

View File

@@ -31,9 +31,9 @@ class EventsView: NSView {
override var acceptsFirstResponder: Bool { return true }
init(frame frameRect: NSRect, cocoaCB ccb: CocoaCB) {
init(cocoaCB ccb: CocoaCB) {
cocoaCB = ccb
super.init(frame: frameRect)
super.init(frame: NSMakeRect(0, 0, 960, 480))
autoresizingMask = [.viewWidthSizable, .viewHeightSizable]
wantsBestResolutionOpenGLSurface = true
register(forDraggedTypes: [NSFilenamesPboardType, NSURLPboardType])
@@ -249,6 +249,7 @@ class EventsView: NSView {
}
func canHideCursor() -> Bool {
if cocoaCB.window == nil { return false }
return !hasMouseDown && containsMouseLocation() && window!.isKeyWindow
}

View File

@@ -61,7 +61,15 @@ class VideoLayer: CAOpenGLLayer {
super.init()
autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
backgroundColor = NSColor.black.cgColor
contentsScale = cocoaCB.window.backingScaleFactor
CGLCreateContext(copyCGLPixelFormat(forDisplayMask: 0), nil, &cglContext)
var i: GLint = 1
CGLSetParameter(cglContext!, kCGLCPSwapInterval, &i)
CGLSetCurrentContext(cglContext!)
mpv.initRender()
mpv.setRenderUpdateCallback(updateCallback, context: self)
mpv.setRenderControlCallback(cocoaCB.controlCallback, context: cocoaCB)
}
override init(layer: Any) {
@@ -74,12 +82,6 @@ class VideoLayer: CAOpenGLLayer {
fatalError("init(coder:) has not been implemented")
}
func setUpRender() {
mpv.initRender()
mpv.setRenderUpdateCallback(updateCallback, context: self)
mpv.setRenderControlCallback(cocoaCB.controlCallback, context: cocoaCB)
}
override func canDraw(inCGLContext ctx: CGLContextObj,
pixelFormat pf: CGLPixelFormatObj,
forLayerTime t: CFTimeInterval,
@@ -177,23 +179,15 @@ class VideoLayer: CAOpenGLLayer {
if err != kCGLNoError || pix == nil {
let errS = String(cString: CGLErrorString(err))
print("Couldn't create CGL pixel format: \(errS) (\(err.rawValue))")
mpv.sendError("Couldn't create CGL pixel format: \(errS) (\(err.rawValue))")
exit(1)
}
return pix!
}
override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj {
let ctx = super.copyCGLContext(forPixelFormat: pf)
var i: GLint = 1
CGLSetParameter(ctx, kCGLCPSwapInterval, &i)
CGLSetCurrentContext(ctx)
cglContext = ctx
if let app = NSApp as? Application {
app.initMPVCore()
}
return ctx
contentsScale = cocoaCB.window.backingScaleFactor
return cglContext!
}
let updateCallback: mpv_render_update_fn = { (ctx) in

View File

@@ -78,28 +78,23 @@ class Window: NSWindow, NSWindowDelegate {
}
}
convenience init(cocoaCB ccb: CocoaCB) {
self.init(contentRect: NSMakeRect(0, 0, 960, 480),
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered, defer: false, screen: NSScreen.main())
cocoaCB = ccb
title = "mpv"
}
convenience init(contentRect: NSRect, styleMask style: NSWindowStyleMask,
screen: NSScreen?, cocoaCB ccb: CocoaCB)
{
self.init(contentRect: contentRect, styleMask: style,
convenience init(contentRect: NSRect, screen: NSScreen?, view: NSView, cocoaCB ccb: CocoaCB) {
self.init(contentRect: contentRect,
styleMask: [.titled, .closable, .miniaturizable, .resizable],
backing: .buffered, defer: false, screen: screen)
cocoaCB = ccb
title = cocoaCB.title
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!
initTitleBar()
if let app = NSApp as? Application {
app.menuBar.register(#selector(setHalfWindowSize), for: MPM_H_SIZE)
@@ -123,14 +118,31 @@ class Window: NSWindow, NSWindowDelegate {
titleBarEffect!.blendingMode = .withinWindow
titleBarEffect!.autoresizingMask = [.viewWidthSizable, .viewMinYMargin]
setTitleBarStyle(mpv.getStringProperty("macos-title-bar-style") ?? "dark")
setTitleBarStyle(Int(mpv.macOpts!.macos_title_bar_style))
contentView!.addSubview(titleBarEffect!, positioned: .above, relativeTo: nil)
border = mpv.getBoolProperty("border")
}
func setTitleBarStyle(_ style: String) {
var effect = style
func setTitleBarStyle(_ style: Any) {
var effect: String
if style is Int {
switch style as! Int {
case 4:
effect = "auto"
case 3:
effect = "mediumlight"
case 2:
effect = "light"
case 1:
effect = "ultradark"
case 0: fallthrough
default:
effect = "dark"
}
} else {
effect = style as! String
}
if effect == "auto" {
let systemStyle = UserDefaults.standard.string(forKey: "AppleInterfaceStyle")
effect = systemStyle == nil ? "mediumlight" : "ultradark"
@@ -339,16 +351,26 @@ class Window: NSWindow, NSWindowDelegate {
}
}
func setOnTop(_ state: Bool) {
func setOnTop(_ state: Bool, _ ontopLevel: Any) {
if state {
let ontopLevel = mpv.getStringProperty("ontop-level") ?? "window"
switch ontopLevel {
case "window":
level = Int(CGWindowLevelForKey(.floatingWindow))
case "system":
level = Int(CGWindowLevelForKey(.statusWindow))+1
default:
level = Int(ontopLevel)!
if ontopLevel is Int {
switch ontopLevel as! Int {
case -1:
level = Int(CGWindowLevelForKey(.floatingWindow))
case -2:
level = Int(CGWindowLevelForKey(.statusWindow))+1
default:
level = ontopLevel as! Int
}
} else {
switch ontopLevel as! String {
case "window":
level = Int(CGWindowLevelForKey(.floatingWindow))
case "system":
level = Int(CGWindowLevelForKey(.statusWindow))+1
default:
level = Int(ontopLevel as! String)!
}
}
collectionBehavior.remove(.transient)
collectionBehavior.insert(.managed)

View File

@@ -30,6 +30,10 @@ class CocoaCB: NSObject {
var cursorVisibilityWanted: Bool = true
var isShuttingDown: Bool = false
var title: String = "mpv" {
didSet { if window != nil { window.title = title } }
}
enum State {
case uninit
case needsInit
@@ -47,31 +51,29 @@ class CocoaCB: NSObject {
let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue")
override init() {
super.init()
window = Window(cocoaCB: self)
view = EventsView(frame: window.contentView!.bounds, cocoaCB: self)
window.contentView!.addSubview(view)
convenience init(_ mpvHandle: OpaquePointer) {
self.init()
mpv = MPVHelper(mpvHandle)
layer = VideoLayer(cocoaCB: self)
view.layer = layer
view.wantsLayer = true
view.layerContentsPlacement = .scaleProportionallyToFit
}
func setMpvHandle(_ ctx: OpaquePointer) {
mpv = MPVHelper(ctx)
layer.setUpRender()
}
func preinit() {
func preinit(_ vo: UnsafeMutablePointer<vo>) {
if backendState == .uninit {
backendState = .needsInit
DispatchQueue.main.async {
self.updateICCProfile()
if let app = NSApp as? Application {
let ptr = mp_get_config_group(mpv.mpctx!, vo.pointee.global,
app.getMacOSConf())
mpv.macOpts = UnsafeMutablePointer<macos_opts>(OpaquePointer(ptr))!.pointee
}
startDisplayLink()
view = EventsView(cocoaCB: self)
view.layer = layer
view.wantsLayer = true
view.layerContentsPlacement = .scaleProportionallyToFit
startDisplayLink(vo)
initLightSensor()
addDisplayReconfigureObserver()
}
}
@@ -82,39 +84,37 @@ class CocoaCB: NSObject {
func reconfig(_ vo: UnsafeMutablePointer<vo>) {
if backendState == .needsInit {
initBackend(vo)
DispatchQueue.main.sync { self.initBackend(vo) }
} else {
layer.setVideo(true)
updateWindowSize(vo)
layer.update()
DispatchQueue.main.async {
self.layer.setVideo(true)
self.updateWindowSize(vo)
self.layer.update()
}
}
}
func initBackend(_ vo: UnsafeMutablePointer<vo>) {
let opts: mp_vo_opts = vo.pointee.opts.pointee
NSApp.setActivationPolicy(.regular)
let targetScreen = getTargetScreen(forFullscreen: false) ?? NSScreen.main()
let wr = getWindowGeometry(forScreen: targetScreen!, videoOut: vo)
let win = Window(contentRect: wr, styleMask: window.styleMask,
screen: targetScreen, cocoaCB: self)
win.title = window.title
win.setOnTop(mpv.getBoolProperty("ontop"))
win.keepAspect = mpv.getBoolProperty("keepaspect-window")
window.close()
window = win
window.contentView!.addSubview(view)
view.frame = window.contentView!.frame
window.initTitleBar()
setAppIcon()
let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main()
let wr = getWindowGeometry(forScreen: targetScreen!, videoOut: vo)
window = Window(contentRect: wr, screen: targetScreen, view: view, cocoaCB: self)
updateICCProfile()
window.setOnTop(Bool(opts.ontop), Int(opts.ontop_level))
window.keepAspect = Bool(opts.keepaspect_window)
window.title = title
window.border = Bool(opts.border)
window.isRestorable = false
window.makeMain()
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
layer.setVideo(true)
if mpv.getBoolProperty("fullscreen") {
if Bool(opts.fullscreen) {
DispatchQueue.main.async {
self.window.toggleFullScreen(nil)
}
@@ -122,13 +122,12 @@ class CocoaCB: NSObject {
window.isMovableByWindowBackground = true
}
initLightSensor()
addDisplayReconfigureObserver()
backendState = .init
}
func updateWindowSize(_ vo: UnsafeMutablePointer<vo>) {
let targetScreen = getTargetScreen(forFullscreen: false) ?? NSScreen.main()
let opts: mp_vo_opts = vo.pointee.opts.pointee
let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main()
let wr = getWindowGeometry(forScreen: targetScreen!, videoOut: vo)
if !window.isVisible {
window.makeKeyAndOrderFront(nil)
@@ -155,8 +154,11 @@ class CocoaCB: NSObject {
return kCVReturnSuccess
}
func startDisplayLink() {
let displayId = UInt32(window.screen!.deviceDescription["NSScreenNumber"] as! Int)
func startDisplayLink(_ vo: UnsafeMutablePointer<vo>) {
let opts: mp_vo_opts = vo.pointee.opts.pointee
let screen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main()
let displayId = screen!.deviceDescription["NSScreenNumber"] as! UInt32
CVDisplayLinkCreateWithActiveCGDisplays(&link)
CVDisplayLinkSetCurrentCGDisplay(link!, displayId)
if #available(macOS 10.12, *) {
@@ -324,8 +326,8 @@ class CocoaCB: NSObject {
}
func getTargetScreen(forFullscreen fs: Bool) -> NSScreen? {
let screenID = fs ? mpv.getStringProperty("fs-screen") ?? "current":
mpv.getStringProperty("screen") ?? "current"
let screenType = fs ? "fs-screen" : "screen"
let screenID = mpv.getStringProperty(screenType) ?? "current"
switch screenID {
case "current", "default", "all":
@@ -432,21 +434,17 @@ class CocoaCB: NSObject {
let titleData = data!.assumingMemoryBound(to: Int8.self)
let title = String(cString: titleData)
DispatchQueue.main.async {
ccb.window.title = String(cString: titleData)
ccb.title = String(cString: titleData)
}
return VO_TRUE
case VOCTRL_PREINIT:
ccb.preinit()
DispatchQueue.main.sync { ccb.preinit(vo!) }
return VO_TRUE
case VOCTRL_UNINIT:
DispatchQueue.main.async {
ccb.uninit()
}
DispatchQueue.main.async { ccb.uninit() }
return VO_TRUE
case VOCTRL_RECONFIG:
DispatchQueue.main.async {
ccb.reconfig(vo!)
}
ccb.reconfig(vo!)
return VO_TRUE
default:
return VO_NOTIMPL
@@ -472,7 +470,7 @@ class CocoaCB: NSObject {
func processEvent(_ event: UnsafePointer<mpv_event>) {
switch event.pointee.event_id {
case MPV_EVENT_SHUTDOWN:
if window.isAnimating {
if window != nil && window.isAnimating {
isShuttingDown = true
return
}
@@ -499,7 +497,7 @@ class CocoaCB: NSObject {
}
case "ontop":
if let data = MPVHelper.mpvFlagToBool(property.data) {
window.setOnTop(data)
window.setOnTop(data, mpv.getStringProperty("ontop-level") ?? "window")
}
case "keepaspect-window":
if let data = MPVHelper.mpvFlagToBool(property.data) {