forked from swiftlang/swift-corelibs-foundation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathNSRunLoop.swift
156 lines (123 loc) · 5.02 KB
/
NSRunLoop.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 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 {
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 static 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)
}
}