import Foundation import os private let log = Logger(subsystem: "com.scarriffleservices.onyx", category: "OSD") /// Apples eigene Einblendung für Lautstärke, Helligkeit und Feststelltaste. /// /// Solange sie erscheint, zeigt der Mac bei jedem Lautstärkeschritt **zwei** /// Anzeigen: Apples Kasten in der Bildschirmmitte und die Live Activity unter /// der Notch. Eine davon ist eine zu viel. /// /// **Wie es geht — und warum es ohne Root geht.** `com.apple.OSDUIHelper` ist /// ein LaunchAgent in der GUI-Domäne des angemeldeten Benutzers, nicht im /// System. `launchctl bootout gui//…` hängt ihn dort aus. Die Datei selbst /// liegt unter SIP-Schutz und wird **nicht** angefasst; geändert wird nur, was /// in der eigenen Sitzung geladen ist. Siehe `docs/spikes/J-osd.md`. /// /// **Und was das kostet.** Es verschwindet nicht nur die Lautstärkeanzeige, /// sondern jede: auch Helligkeit und Feststelltaste. Deshalb steht der Schalter /// standardmäßig aus, und deshalb wird beim Beenden wieder eingehängt — sonst /// säße jemand bis zum nächsten Abmelden ganz ohne Rückmeldung da, ohne zu /// wissen, warum. public enum SystemOSD { private static let service = "com.apple.OSDUIHelper" private static var domain: String { "gui/\(getuid())/\(service)" } /// Ob der Dienst gerade ausgehängt ist. public static var isSuppressed: Bool { // `launchctl print` gibt für einen ausgehängten Dienst einen Fehler // zurück. Kein Fehler heißt: er ist da. run(["print", domain]) != 0 } /// Hängt die Einblendung aus. Wirkt bis zum nächsten Abmelden. @discardableResult public static func suppress() -> Bool { guard !isSuppressed else { return true } let status = run(["bootout", domain]) if status != 0 { log.notice("OSD-Dienst nicht aushängbar: \(status, privacy: .public)") } return status == 0 } /// Hängt sie wieder ein. /// /// Beim Beenden zu rufen. Ohne das bliebe der Mac bis zum nächsten Abmelden /// ohne jede Einblendung — auch für Helligkeit, mit der Onyx nichts zu tun /// hat. @discardableResult public static func restore() -> Bool { guard isSuppressed else { return true } let status = run(["bootstrap", "gui/\(getuid())", "/System/Library/LaunchAgents/\(service).plist"]) if status != 0 { log.notice("OSD-Dienst nicht einhängbar: \(status, privacy: .public)") } return status == 0 } private static func run(_ arguments: [String]) -> Int32 { let task = Process() task.executableURL = URL(fileURLWithPath: "/bin/launchctl") task.arguments = arguments task.standardOutput = FileHandle.nullDevice task.standardError = FileHandle.nullDevice do { try task.run() task.waitUntilExit() return task.terminationStatus } catch { log.error("launchctl nicht startbar: \(error.localizedDescription, privacy: .public)") return -1 } } }