refactor: modernize Cast discovery and app activation
This commit is contained in:
@@ -7,6 +7,10 @@ import ObjectiveC
|
||||
@_cdecl("terebi_app_main")
|
||||
@MainActor
|
||||
public func checkAppStartup() {
|
||||
if let index = CommandLine.arguments.firstIndex(of: "--check-startup-error") {
|
||||
StartupErrorCheck.run(result: URL(fileURLWithPath: CommandLine.arguments[index + 1]))
|
||||
return
|
||||
}
|
||||
if let index = CommandLine.arguments.firstIndex(of: "--check-overlay-hover") {
|
||||
OverlayHoverCheck.run(result: URL(fileURLWithPath: CommandLine.arguments[index + 1]))
|
||||
return
|
||||
@@ -30,6 +34,49 @@ public func checkAppStartup() {
|
||||
AppStartupCheck.run()
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private enum StartupErrorCheck {
|
||||
static var timer: Timer?
|
||||
|
||||
static func run(result: URL) {
|
||||
let deadline = ContinuousClock.now.advanced(by: .seconds(15))
|
||||
let observer = Timer(timeInterval: 0.05, repeats: true) { _ in
|
||||
MainActor.assumeIsolated {
|
||||
guard let window = NSApp.modalWindow, let content = window.contentView else {
|
||||
precondition(ContinuousClock.now < deadline, "Startup failure must present a native modal alert")
|
||||
return
|
||||
}
|
||||
@MainActor
|
||||
func descendants(_ view: NSView) -> [NSView] {
|
||||
[view] + view.subviews.flatMap { descendants($0) }
|
||||
}
|
||||
let views = descendants(content)
|
||||
let text = views.compactMap { ($0 as? NSTextField)?.stringValue }.filter { !$0.isEmpty }
|
||||
let button = views.compactMap { $0 as? NSButton }.first { $0.title == "OK" || $0.title == "Quit" }
|
||||
let focused = NSApp.isActive && window.isKeyWindow
|
||||
guard focused || ContinuousClock.now >= deadline else { return }
|
||||
let report: [String: Any] = [
|
||||
"passed": focused && window.isVisible && button?.isEnabled == true,
|
||||
"active": NSApp.isActive, "keyWindow": window.isKeyWindow,
|
||||
"visible": window.isVisible, "text": text,
|
||||
]
|
||||
do {
|
||||
try JSONSerialization.data(withJSONObject: report).write(to: result, options: .atomic)
|
||||
} catch {
|
||||
fatalError("Could not report native startup alert: \(error)")
|
||||
}
|
||||
timer?.invalidate()
|
||||
guard let button else { fatalError("Startup alert must have a dismissal button") }
|
||||
button.performClick(nil)
|
||||
}
|
||||
}
|
||||
timer = observer
|
||||
RunLoop.main.add(observer, forMode: .modalPanel)
|
||||
terebiAppMain()
|
||||
fatalError("Invalid startup input must not start the player")
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private enum OverlayHoverCheck {
|
||||
static var timer: Timer?
|
||||
|
||||
Reference in New Issue
Block a user