refactor: modernize Cast discovery and app activation

This commit is contained in:
2026-10-22 09:16:19 +02:00
parent f1893a5a5f
commit 419ac8d677
8 changed files with 279 additions and 67 deletions
+47
View File
@@ -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?