| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| import CoreFoundation |
| |
| #if os(OSX) || os(iOS) |
| internal let kCFRunLoopEntry = CFRunLoopActivity.entry.rawValue |
| internal let kCFRunLoopBeforeTimers = CFRunLoopActivity.beforeTimers.rawValue |
| internal let kCFRunLoopBeforeSources = CFRunLoopActivity.beforeSources.rawValue |
| internal let kCFRunLoopBeforeWaiting = CFRunLoopActivity.beforeWaiting.rawValue |
| internal let kCFRunLoopAfterWaiting = CFRunLoopActivity.afterWaiting.rawValue |
| internal let kCFRunLoopExit = CFRunLoopActivity.exit.rawValue |
| internal let kCFRunLoopAllActivities = CFRunLoopActivity.allActivities.rawValue |
| #endif |
| |
| public struct RunLoopMode : RawRepresentable, Equatable, Hashable, Comparable { |
| public private(set) var rawValue: String |
| |
| public init(_ rawValue: String) { |
| self.rawValue = rawValue |
| } |
| |
| public init(rawValue: String) { |
| self.rawValue = rawValue |
| } |
| |
| public var hashValue: Int { |
| return rawValue.hashValue |
| } |
| } |
| |
| public func ==(lhs: RunLoopMode, rhs: RunLoopMode) -> Bool { |
| return lhs.rawValue == rhs.rawValue |
| } |
| |
| public func <(lhs: RunLoopMode, rhs: RunLoopMode) -> Bool { |
| return lhs.rawValue < rhs.rawValue |
| } |
| |
| |
| extension RunLoopMode { |
| public static let defaultRunLoopMode = RunLoopMode("kCFRunLoopDefaultMode") |
| public static let commonModes = RunLoopMode("kCFRunLoopCommonModes") |
| } |
| |
| internal func _NSRunLoopNew(_ cf: CFRunLoop) -> Unmanaged<AnyObject> { |
| let rl = Unmanaged<RunLoop>.passRetained(RunLoop(cfObject: cf)) |
| return unsafeBitCast(rl, to: Unmanaged<AnyObject>.self) // this retain is balanced on the other side of the CF fence |
| } |
| |
| open class RunLoop: NSObject { |
| internal var _cfRunLoop : CFRunLoop! |
| internal static var _mainRunLoop : RunLoop = { |
| return RunLoop(cfObject: CFRunLoopGetMain()) |
| }() |
| |
| internal init(cfObject : CFRunLoop) { |
| _cfRunLoop = cfObject |
| } |
| |
| open class var current: RunLoop { |
| return _CFRunLoopGet2(CFRunLoopGetCurrent()) as! RunLoop |
| } |
| |
| open class var main: RunLoop { |
| return _CFRunLoopGet2(CFRunLoopGetMain()) as! RunLoop |
| } |
| |
| open var currentMode: RunLoopMode? { |
| if let mode = CFRunLoopCopyCurrentMode(_cfRunLoop) { |
| return RunLoopMode(mode._swiftObject) |
| } else { |
| return nil |
| } |
| } |
| |
| open func getCFRunLoop() -> CFRunLoop { |
| return _cfRunLoop |
| } |
| |
| open func add(_ timer: Timer, forMode mode: RunLoopMode) { |
| CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer._cfObject, mode.rawValue._cfObject) |
| } |
| |
| open func add(_ aPort: Port, forMode mode: RunLoopMode) { |
| NSUnimplemented() |
| } |
| |
| open func remove(_ aPort: Port, forMode mode: RunLoopMode) { |
| NSUnimplemented() |
| } |
| |
| open func limitDate(forMode mode: RunLoopMode) -> Date? { |
| if _cfRunLoop !== CFRunLoopGetCurrent() { |
| return nil |
| } |
| let modeArg = mode.rawValue._cfObject |
| |
| CFRunLoopRunInMode(modeArg, -10.0, true) /* poll run loop to fire ready timers and performers, as used to be done here */ |
| if _CFRunLoopFinished(_cfRunLoop, modeArg) { |
| return nil |
| } |
| |
| let nextTimerFireAbsoluteTime = CFRunLoopGetNextTimerFireDate(CFRunLoopGetCurrent(), modeArg) |
| |
| if (nextTimerFireAbsoluteTime == 0) { |
| return Date.distantFuture |
| } |
| |
| return Date(timeIntervalSinceReferenceDate: nextTimerFireAbsoluteTime) |
| } |
| |
| open func acceptInput(forMode mode: String, before limitDate: Date) { |
| if _cfRunLoop !== CFRunLoopGetCurrent() { |
| return |
| } |
| CFRunLoopRunInMode(mode._cfObject, limitDate.timeIntervalSinceReferenceDate - CFAbsoluteTimeGetCurrent(), true) |
| } |
| |
| } |
| |
| extension RunLoop { |
| |
| public func run() { |
| while run(mode: .defaultRunLoopMode, before: Date.distantFuture) { } |
| } |
| |
| public func run(until limitDate: Date) { |
| while run(mode: .defaultRunLoopMode, before: limitDate) && limitDate.timeIntervalSinceReferenceDate > CFAbsoluteTimeGetCurrent() { } |
| } |
| |
| public func run(mode: RunLoopMode, before limitDate: Date) -> Bool { |
| if _cfRunLoop !== CFRunLoopGetCurrent() { |
| return false |
| } |
| let modeArg = mode.rawValue._cfObject |
| if _CFRunLoopFinished(_cfRunLoop, modeArg) { |
| return false |
| } |
| |
| let limitTime = limitDate.timeIntervalSinceReferenceDate |
| let ti = limitTime - CFAbsoluteTimeGetCurrent() |
| CFRunLoopRunInMode(modeArg, ti, true) |
| return true |
| } |
| |
| public func perform(inModes modes: [RunLoopMode], block: @escaping () -> Void) { |
| CFRunLoopPerformBlock(getCFRunLoop(), (modes.map { $0.rawValue._nsObject })._cfObject, block) |
| } |
| |
| public func perform(_ block: @escaping () -> Void) { |
| perform(inModes: [.defaultRunLoopMode], block: block) |
| } |
| } |