forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDisplayLink.swift
More file actions
64 lines (56 loc) · 1.83 KB
/
DisplayLink.swift
File metadata and controls
64 lines (56 loc) · 1.83 KB
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
import Foundation
import QuartzCore
public actor DisplayLink {
private var displayLink: CVDisplayLink!
private static var _shared = DisplayLink()
static var shared: DisplayLink? {
if let _shared { return _shared }
_shared = DisplayLink()
return _shared
}
private var continuations: [UUID: AsyncStream<Void>.Continuation] = [:]
public static func createStream() -> AsyncStream<Void> {
.init { continuation in
Task {
let id = UUID()
await DisplayLink.shared?.addContinuation(continuation, id: id)
continuation.onTermination = { _ in
Task {
await DisplayLink.shared?.removeContinuation(id: id)
}
}
}
}
}
private init?() {
_ = CVDisplayLinkCreateWithCGDisplay(CGMainDisplayID(), &displayLink)
guard displayLink != nil else { return nil }
CVDisplayLinkSetOutputHandler(displayLink) { [weak self] _, _, _, _, _ in
guard let self else { return kCVReturnSuccess }
Task { await self.notifyContinuations() }
return kCVReturnSuccess
}
}
deinit {
for continuation in continuations {
continuation.value.finish()
}
}
func addContinuation(_ continuation: AsyncStream<Void>.Continuation, id: UUID) {
continuations[id] = continuation
if !continuations.isEmpty {
CVDisplayLinkStart(displayLink)
}
}
func removeContinuation(id: UUID) {
continuations[id] = nil
if continuations.isEmpty {
CVDisplayLinkStop(displayLink)
}
}
private func notifyContinuations() {
for continuation in continuations {
continuation.value.yield()
}
}
}