cocoa-cb: migrate to swift 5 with swift 4 fallback

this migrates our current swift code to version 5 and 4. building is
support from 10.12.6 and xcode 9.1 onwards.

dynamic linking is the new default, since Apple removed static libs
from their new toolchains and it's the recommended way.

additionally the found macOS SDK version is printed since it's an
important information for finding possible errors now.

Fixes #6470
This commit is contained in:
der richter 2019-07-20 12:16:37 +02:00 committed by Jan Ekström
parent 0602f082cb
commit a8c2e29868
9 changed files with 143 additions and 85 deletions

View File

@ -177,9 +177,11 @@ class MPVHelper: NSObject {
sendWarning("Invalid ICC profile data.")
return
}
let iccSize = iccData.count
iccData.withUnsafeMutableBytes { (u8Ptr: UnsafeMutablePointer<UInt8>) in
let iccBstr = bstrdup(nil, bstr(start: u8Ptr, len: iccSize))
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)

View File

@ -16,9 +16,68 @@
*/
#if !HAVE_MACOS_10_14_FEATURES
let NSAppearanceNameDarkAqua = "NSAppearanceNameDarkAqua"
let NSAppearanceNameAccessibilityHighContrastAqua = "NSAppearanceNameAccessibilityAqua"
let NSAppearanceNameAccessibilityHighContrastDarkAqua = "NSAppearanceNameAccessibilityDarkAqua"
let NSAppearanceNameAccessibilityHighContrastVibrantLight = "NSAppearanceNameAccessibilityVibrantLight"
let NSAppearanceNameAccessibilityHighContrastVibrantDark = "NSAppearanceNameAccessibilityVibrantDark"
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")
}
#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<Type>(_ body: (UnsafeMutableRawBufferPointer) throws -> Type) rethrows -> Type {
let dataCount = count
return try withUnsafeMutableBytes { (ptr: UnsafeMutablePointer<UInt8>) 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<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult] {
return try self.flatMap(transform)
}
}
extension NSWindow.Level {
static func +(left: NSWindow.Level, right: Int) -> NSWindow.Level {
return NSWindow.Level(left.rawValue + right)
}
}
#endif

View File

@ -17,11 +17,15 @@
import Cocoa
extension NSDeviceDescriptionKey {
static let screenNumber = NSDeviceDescriptionKey("NSScreenNumber")
}
extension NSScreen {
public var displayID: CGDirectDisplayID {
get {
return deviceDescription["NSScreenNumber"] as? CGDirectDisplayID ?? 0
return deviceDescription[.screenNumber] as? CGDirectDisplayID ?? 0
}
}

View File

@ -32,11 +32,9 @@ class EventsView: NSView {
init(cocoaCB ccb: CocoaCB) {
cocoaCB = ccb
super.init(frame: NSMakeRect(0, 0, 960, 480))
autoresizingMask = [.viewWidthSizable, .viewHeightSizable]
autoresizingMask = [.width, .height]
wantsBestResolutionOpenGLSurface = true
register(forDraggedTypes: [ NSFilenamesPboardType,
NSURLPboardType,
NSPasteboardTypeString ])
registerForDraggedTypes([ .fileURLCompat, .URLCompat, .string ])
}
required init?(coder: NSCoder) {
@ -60,11 +58,8 @@ class EventsView: NSView {
}
override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
guard let types = sender.draggingPasteboard().types else { return [] }
if types.contains(NSFilenamesPboardType) ||
types.contains(NSURLPboardType) ||
types.contains(NSPasteboardTypeString)
{
guard let types = sender.draggingPasteboard.types else { return [] }
if types.contains(.fileURLCompat) || types.contains(.URLCompat) || types.contains(.string) {
return .copy
}
return []
@ -81,21 +76,17 @@ class EventsView: NSView {
}
override func performDragOperation(_ sender: NSDraggingInfo) -> Bool {
let pb = sender.draggingPasteboard()
guard let types = sender.draggingPasteboard().types else { return false }
if types.contains(NSFilenamesPboardType) {
if let files = pb.propertyList(forType: NSFilenamesPboardType) as? [Any] {
let pb = sender.draggingPasteboard
guard let types = pb.types else { return false }
if types.contains(.fileURLCompat) || types.contains(.URLCompat) {
if let urls = pb.readObjects(forClasses: [NSURL.self]) as? [URL] {
let files = urls.map { $0.absoluteString }
EventsResponder.sharedInstance().handleFilesArray(files)
return true
}
} else if types.contains(NSURLPboardType) {
if var url = pb.propertyList(forType: NSURLPboardType) as? [String] {
url = url.filter{ !$0.isEmpty }
EventsResponder.sharedInstance().handleFilesArray(url)
return true
}
} else if types.contains(NSPasteboardTypeString) {
guard let str = pb.string(forType: NSPasteboardTypeString) else { return false }
} 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") {
@ -220,7 +211,7 @@ class EventsView: NSView {
var delta: Double
var cmd: Int32
if fabs(event.deltaY) >= fabs(event.deltaX) {
if abs(event.deltaY) >= abs(event.deltaX) {
delta = Double(event.deltaY) * 0.1;
cmd = delta > 0 ? SWIFT_WHEEL_UP : SWIFT_WHEEL_DOWN;
} else {
@ -228,7 +219,7 @@ class EventsView: NSView {
cmd = delta > 0 ? SWIFT_WHEEL_RIGHT : SWIFT_WHEEL_LEFT;
}
mpv.putAxis(cmd, delta: fabs(delta))
mpv.putAxis(cmd, delta: abs(delta))
}
override func scrollWheel(with event: NSEvent) {
@ -244,7 +235,7 @@ class EventsView: NSView {
let deltaY = modifiers.contains(.shift) ? event.scrollingDeltaX : event.scrollingDeltaY
var mpkey: Int32
if fabs(deltaY) >= fabs(deltaX) {
if abs(deltaY) >= abs(deltaX) {
mpkey = deltaY > 0 ? SWIFT_WHEEL_UP : SWIFT_WHEEL_DOWN;
} else {
mpkey = deltaX > 0 ? SWIFT_WHEEL_RIGHT : SWIFT_WHEEL_LEFT;

View File

@ -29,7 +29,7 @@ class TitleBar: NSVisualEffectView {
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 [NSWindow.ButtonType]).compactMap { cocoaCB.window?.standardWindowButton($0) } }
}
override var material: NSVisualEffectView.Material {
@ -57,7 +57,7 @@ class TitleBar: NSVisualEffectView {
super.init(frame: f)
alphaValue = 0
blendingMode = .withinWindow
autoresizingMask = [.viewWidthSizable, .viewMinYMargin]
autoresizingMask = [.width, .minYMargin]
systemBar?.alphaValue = 0
state = .followsWindowActiveState
wantsLayer = true
@ -148,7 +148,7 @@ class TitleBar: NSVisualEffectView {
}
}
func hide() {
@objc func hide() {
guard let window = cocoaCB.window else { return }
if window.isInFullscreen && !window.isAnimating {
alphaValue = 0
@ -175,26 +175,26 @@ class TitleBar: NSVisualEffectView {
func appearanceFrom(string: String) -> NSAppearance? {
switch string {
case "1", "aqua":
return NSAppearance(named: NSAppearanceNameAqua)
return NSAppearance(named: .aqua)
case "3", "vibrantLight":
return NSAppearance(named: NSAppearanceNameVibrantLight)
return NSAppearance(named: .vibrantLight)
case "4", "vibrantDark":
return NSAppearance(named: NSAppearanceNameVibrantDark)
return NSAppearance(named: .vibrantDark)
default: break
}
if #available(macOS 10.14, *) {
switch string {
case "2", "darkAqua":
return NSAppearance(named: NSAppearanceNameDarkAqua)
return NSAppearance(named: .darkAqua)
case "5", "aquaHighContrast":
return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastAqua)
return NSAppearance(named: .accessibilityHighContrastAqua)
case "6", "darkAquaHighContrast":
return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastDarkAqua)
return NSAppearance(named: .accessibilityHighContrastDarkAqua)
case "7", "vibrantLightHighContrast":
return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastVibrantLight)
return NSAppearance(named: .accessibilityHighContrastVibrantLight)
case "8", "vibrantDarkHighContrast":
return NSAppearance(named: NSAppearanceNameAccessibilityHighContrastVibrantDark)
return NSAppearance(named: .accessibilityHighContrastVibrantDark)
case "0", "auto": fallthrough
default:
return nil

View File

@ -54,7 +54,7 @@ class Window: NSWindow, NSWindowDelegate {
override var canBecomeKey: Bool { return true }
override var canBecomeMain: Bool { return true }
override var styleMask: NSWindowStyleMask {
override var styleMask: NSWindow.StyleMask {
get { return super.styleMask }
set {
let responder = firstResponder
@ -72,7 +72,7 @@ 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 let wantedScreen = screen, screen != NSScreen.main() {
if let wantedScreen = screen, screen != NSScreen.main {
var absoluteWantedOrigin = contentRect.origin
absoluteWantedOrigin.x += wantedScreen.frame.origin.x
absoluteWantedOrigin.y += wantedScreen.frame.origin.y
@ -255,26 +255,26 @@ class Window: NSWindow, NSWindowDelegate {
}
func setOnTop(_ state: Bool, _ ontopLevel: Any) {
let stdLevel = Int(CGWindowLevelForKey(.normalWindow))
let stdLevel: NSWindow.Level = .normal
if state {
if ontopLevel is Int {
switch ontopLevel as? Int {
case .some(-1):
level = Int(CGWindowLevelForKey(.floatingWindow))
level = .floating
case .some(-2):
level = Int(CGWindowLevelForKey(.statusWindow))+1
level = .statusBar + 1
default:
level = ontopLevel as? Int ?? stdLevel
level = NSWindow.Level(ontopLevel as? Int ?? stdLevel.rawValue)
}
} else {
switch ontopLevel as? String {
case .some("window"):
level = Int(CGWindowLevelForKey(.floatingWindow))
level = .floating
case .some("system"):
level = Int(CGWindowLevelForKey(.statusWindow))+1
level = .statusBar + 1
default:
level = Int(ontopLevel as? String ?? "") ?? stdLevel
level = NSWindow.Level(Int(ontopLevel as? String ?? "") ?? stdLevel.rawValue)
}
}
collectionBehavior.remove(.transient)
@ -410,7 +410,7 @@ class Window: NSWindow, NSWindowDelegate {
return frameRect
}
guard let ts: NSScreen = tScreen ?? screen ?? NSScreen.main() else {
guard let ts: NSScreen = tScreen ?? screen ?? NSScreen.main else {
return frameRect
}
var nf: NSRect = frameRect
@ -443,9 +443,9 @@ class Window: NSWindow, NSWindowDelegate {
return nf
}
func setNormalWindowSize() { setWindowScale(1.0) }
func setHalfWindowSize() { setWindowScale(0.5) }
func setDoubleWindowSize() { setWindowScale(2.0) }
@objc func setNormalWindowSize() { setWindowScale(1.0) }
@objc func setHalfWindowSize() { setWindowScale(0.5) }
@objc func setDoubleWindowSize() { setWindowScale(2.0) }
func setWindowScale(_ scale: Double) {
mpv.commandAsync(["osd-auto", "set", "window-scale", "\(scale)"])
@ -480,7 +480,7 @@ class Window: NSWindow, NSWindowDelegate {
cocoaCB.layer?.inLiveResize = false
}
func windowShouldClose(_ sender: Any) -> Bool {
func windowShouldClose(_ sender: NSWindow) -> Bool {
cocoa_put_key(SWIFT_KEY_CLOSE_WIN)
return false
}

View File

@ -29,7 +29,7 @@ class CocoaCB: NSObject {
var cursorHidden: Bool = false
var cursorVisibilityWanted: Bool = true
var isShuttingDown: Bool = false
@objc var isShuttingDown: Bool = false
var title: String = "mpv" {
didSet { if let window = window { window.title = title } }
@ -52,7 +52,7 @@ class CocoaCB: NSObject {
let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue")
init(_ mpvHandle: OpaquePointer) {
@objc init(_ mpvHandle: OpaquePointer) {
mpv = MPVHelper(mpvHandle)
super.init()
layer = VideoLayer(cocoaCB: self)
@ -97,7 +97,7 @@ class CocoaCB: NSObject {
mpv.sendError("Something went wrong, no View was initialized")
exit(1)
}
guard let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main() else {
guard let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main else {
mpv.sendError("Something went wrong, no Screen was found")
exit(1)
}
@ -135,7 +135,7 @@ class CocoaCB: NSObject {
func updateWindowSize(_ vo: UnsafeMutablePointer<vo>) {
let opts: mp_vo_opts = vo.pointee.opts.pointee
guard let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main() else {
guard let targetScreen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main else {
mpv.sendWarning("Couldn't update Window size, no Screen available")
return
}
@ -170,7 +170,7 @@ class CocoaCB: NSObject {
let opts: mp_vo_opts = vo.pointee.opts.pointee
CVDisplayLinkCreateWithActiveCGDisplays(&link)
guard let screen = getScreenBy(id: Int(opts.screen_id)) ?? NSScreen.main(),
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")
@ -279,18 +279,19 @@ class CocoaCB: NSObject {
// the polinomial approximation for apple lmu value -> lux was empirically
// derived by firefox developers (Apple provides no documentation).
// https://bugzilla.mozilla.org/show_bug.cgi?id=793728
let power_c4 = 1 / pow(10, 27)
let power_c3 = 1 / pow(10, 19)
let power_c2 = 1 / pow(10, 12)
let power_c1 = 1 / pow(10, 5)
let power_c4: Double = 1 / pow(10, 27)
let power_c3: Double = 1 / pow(10, 19)
let power_c2: Double = 1 / pow(10, 12)
let power_c1: Double = 1 / pow(10, 5)
let term4 = -3.0 * power_c4 * pow(Decimal(v), 4)
let term3 = 2.6 * power_c3 * pow(Decimal(v), 3)
let term2 = -3.4 * power_c2 * pow(Decimal(v), 2)
let term1 = 3.9 * power_c1 * Decimal(v)
let lum = Double(v)
let term4: Double = -3.0 * power_c4 * pow(lum, 4.0)
let term3: Double = 2.6 * power_c3 * pow(lum, 3.0)
let term2: Double = -3.4 * power_c2 * pow(lum, 2.0)
let term1: Double = 3.9 * power_c1 * lum
let lux = Int(ceil( Double((term4 + term3 + term2 + term1 - 0.19) as NSNumber)))
return Int(lux > 0 ? lux : 0)
let lux = Int(ceil(term4 + term3 + term2 + term1 - 0.19))
return lux > 0 ? lux : 0
}
var lightSensorCallback: IOServiceInterestCallback = { (ctx, service, messageType, messageArgument) -> Void in
@ -370,14 +371,13 @@ class CocoaCB: NSObject {
}
func getScreenBy(id screenID: Int) -> NSScreen? {
guard let screens = NSScreen.screens() else { return nil}
if screenID >= screens.count {
if screenID >= NSScreen.screens.count {
mpv.sendInfo("Screen ID \(screenID) does not exist, falling back to current device")
return nil
} else if screenID < 0 {
return nil
}
return screens[screenID]
return NSScreen.screens[screenID]
}
func getWindowGeometry(forScreen targetScreen: NSScreen,
@ -486,7 +486,7 @@ class CocoaCB: NSObject {
var count: Int32 = 0
let screen = ccb.window != nil ? ccb.window?.screen :
ccb.getScreenBy(id: Int(opts.screen_id)) ??
NSScreen.main()
NSScreen.main
let displayName = screen?.displayName ?? "Unknown"
SWIFT_TARRAY_STRING_APPEND(nil, &array, &count, ta_xstrdup(nil, displayName))
@ -545,7 +545,7 @@ class CocoaCB: NSObject {
}
}
func processEvent(_ event: UnsafePointer<mpv_event>) {
@objc func processEvent(_ event: UnsafePointer<mpv_event>) {
switch event.pointee.event_id {
case MPV_EVENT_SHUTDOWN:
shutdown()

View File

@ -21,9 +21,9 @@ def __add_swift_flags(ctx):
verRe = re.compile("(?i)version\s?([\d.]+)")
ctx.env.SWIFT_VERSION = verRe.search(__run([ctx.env.SWIFT, '-version'])).group(1)
# the -swift-version parameter is only supported on swift 3.1 and newer
if StrictVersion(ctx.env.SWIFT_VERSION) >= StrictVersion("3.1"):
ctx.env.SWIFT_FLAGS.extend([ "-swift-version", "3" ])
# prevent possible breakages with future swift versions
if StrictVersion(ctx.env.SWIFT_VERSION) >= StrictVersion("6.0"):
ctx.env.SWIFT_FLAGS.extend([ "-swift-version", "5" ])
if ctx.is_debug_build():
ctx.env.SWIFT_FLAGS.append("-g")
@ -109,7 +109,7 @@ def __find_swift_library(ctx):
ctx.end_msg(False)
enableStatic = getattr(ctx.options, 'enable_swift-static')
if (enableStatic or enableStatic == None) and 'SWIFT_LIB_STATIC' in swift_libraries:
if (enableStatic) and 'SWIFT_LIB_STATIC' in swift_libraries:
__add_static_swift_library_linking_flags(ctx, swift_libraries['SWIFT_LIB_STATIC'])
else:
__add_dynamic_swift_library_linking_flags(ctx, swift_libraries['SWIFT_LIB_DYNAMIC'])
@ -136,7 +136,6 @@ def __find_macos_sdk(ctx):
sdk_version = __run(['xcrun', '--sdk', 'macosx', '--show-sdk-version' ])
if sdk:
ctx.end_msg(sdk)
ctx.env.MACOS_SDK = sdk
build_version = '10.10.0'
@ -161,6 +160,8 @@ def __find_macos_sdk(ctx):
ctx.env.MACOS_SDK_VERSION = build_version
else:
ctx.env.MACOS_SDK_VERSION = sdk_version
ctx.end_msg(sdk + ' (version found: ' + ctx.env.MACOS_SDK_VERSION + ')')
else:
ctx.end_msg(False)

View File

@ -129,7 +129,8 @@ build_options = [
'name': '--swift-static',
'desc': 'static Swift linking',
'deps': 'os-darwin',
'func': check_ctx_vars('SWIFT_LIB_STATIC')
'func': check_ctx_vars('SWIFT_LIB_STATIC'),
'default': 'disable'
}
]
@ -958,7 +959,7 @@ standalone_features = [
}, {
'name': '--macos-cocoa-cb',
'desc': 'macOS opengl-cb backend',
'deps': 'cocoa && swift',
'deps': 'cocoa && swift',
'func': check_true
}
]