diff --git a/boringNotch/XPCHelperClient/XPCHelperClient.swift b/boringNotch/XPCHelperClient/XPCHelperClient.swift index e3ad4b0fc..1c9bce831 100644 --- a/boringNotch/XPCHelperClient/XPCHelperClient.swift +++ b/boringNotch/XPCHelperClient/XPCHelperClient.swift @@ -2,9 +2,14 @@ import Foundation import Cocoa import AsyncXPCConnection +@MainActor final class XPCHelperClient: NSObject { nonisolated static let shared = XPCHelperClient() + nonisolated private override init() { + super.init() + } + private let serviceName = "theboringteam.boringnotch.BoringNotchXPCHelper" private var remoteService: RemoteXPCService? @@ -14,14 +19,8 @@ final class XPCHelperClient: NSObject { private var lunarListener: BoringNotchXPCHelperLunarListener? private var hasLunarListener: Bool = false - deinit { - connection?.invalidate() - stopMonitoringAccessibilityAuthorization() - } - // MARK: - Connection Management (Main Actor Isolated) - @MainActor private func ensureRemoteService(needsListener: Bool = false) -> RemoteXPCService { if let existing = remoteService, (!needsListener || hasLunarListener) { return existing @@ -72,7 +71,6 @@ final class XPCHelperClient: NSObject { return service } - @MainActor private func getRemoteService() -> RemoteXPCService? { remoteService } @@ -88,7 +86,6 @@ final class XPCHelperClient: NSObject { return interface } - @MainActor private func notifyAuthorizationChange(_ granted: Bool) { guard lastKnownAuthorization != granted else { return } lastKnownAuthorization = granted @@ -100,10 +97,10 @@ final class XPCHelperClient: NSObject { } // MARK: - Monitoring - nonisolated func startMonitoringAccessibilityAuthorization(every interval: TimeInterval = 3.0) { + func startMonitoringAccessibilityAuthorization(every interval: TimeInterval = 3.0) { // Ensure only one monitor exists stopMonitoringAccessibilityAuthorization() - monitoringTask = Task.detached { [weak self] in + monitoringTask = Task { [weak self] in guard let self = self else { return } while !Task.isCancelled { // Call the helper method periodically which will notify on change @@ -115,7 +112,7 @@ final class XPCHelperClient: NSObject { } } - nonisolated func stopMonitoringAccessibilityAuthorization() { + func stopMonitoringAccessibilityAuthorization() { monitoringTask?.cancel() monitoringTask = nil } @@ -127,49 +124,41 @@ final class XPCHelperClient: NSObject { // MARK: - Accessibility + // Fire-and-forget: callers invoke this from non-isolated contexts, and the work + // itself hops onto the main actor. nonisolated func requestAccessibilityAuthorization() { - Task { - let service = await MainActor.run { - ensureRemoteService() - } + Task { @MainActor in + let service = ensureRemoteService() try? await service.withService { service in service.requestAccessibilityAuthorization() } } } - nonisolated func isAccessibilityAuthorized() async -> Bool { + func isAccessibilityAuthorized() async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() let result: Bool = try await service.withContinuation { service, continuation in service.isAccessibilityAuthorized { authorized in continuation.resume(returning: authorized) } } - await MainActor.run { - notifyAuthorizationChange(result) - } + notifyAuthorizationChange(result) return result } catch { return false } } - nonisolated func ensureAccessibilityAuthorization(promptIfNeeded: Bool) async -> Bool { + func ensureAccessibilityAuthorization(promptIfNeeded: Bool) async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() let result: Bool = try await service.withContinuation { service, continuation in service.ensureAccessibilityAuthorization(promptIfNeeded) { authorized in continuation.resume(returning: authorized) } } - await MainActor.run { - notifyAuthorizationChange(result) - } + notifyAuthorizationChange(result) return result } catch { return false @@ -178,11 +167,9 @@ final class XPCHelperClient: NSObject { // MARK: - Keyboard Brightness - nonisolated func isKeyboardBrightnessAvailable() async -> Bool { + func isKeyboardBrightnessAvailable() async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.isKeyboardBrightnessAvailable { available in continuation.resume(returning: available) @@ -193,11 +180,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func currentKeyboardBrightness() async -> Float? { + func currentKeyboardBrightness() async -> Float? { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() let result: NSNumber? = try await service.withContinuation { service, continuation in service.currentKeyboardBrightness { value in continuation.resume(returning: value) @@ -209,11 +194,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func setKeyboardBrightness(_ value: Float) async -> Bool { + func setKeyboardBrightness(_ value: Float) async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.setKeyboardBrightness(value) { success in continuation.resume(returning: success) @@ -226,11 +209,9 @@ final class XPCHelperClient: NSObject { // MARK: - Screen Brightness - nonisolated func isScreenBrightnessAvailable() async -> Bool { + func isScreenBrightnessAvailable() async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.isScreenBrightnessAvailable { available in continuation.resume(returning: available) @@ -241,11 +222,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func currentScreenBrightness() async -> Float? { + func currentScreenBrightness() async -> Float? { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() let result: NSNumber? = try await service.withContinuation { service, continuation in service.currentScreenBrightness { value in continuation.resume(returning: value) @@ -257,11 +236,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func displayIDForBrightness() async -> CGDirectDisplayID? { + func displayIDForBrightness() async -> CGDirectDisplayID? { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() let result: NSNumber? = try await service.withContinuation { service, continuation in service.displayIDForBrightness(with: { value in continuation.resume(returning: value) @@ -274,11 +251,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func setScreenBrightness(_ value: Float) async -> Bool { + func setScreenBrightness(_ value: Float) async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.setScreenBrightness(value) { success in continuation.resume(returning: success) @@ -288,11 +263,9 @@ final class XPCHelperClient: NSObject { return false } } - nonisolated func adjustScreenBrightness(by value: Float) async -> Bool { + func adjustScreenBrightness(by value: Float) async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.adjustScreenBrightness(by: value) { success in continuation.resume(returning: success) @@ -305,11 +278,9 @@ final class XPCHelperClient: NSObject { // MARK: - Lunar Events - nonisolated func isLunarAvailable() async -> Bool { + func isLunarAvailable() async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.isLunarAvailable { available in continuation.resume(returning: available) @@ -320,14 +291,10 @@ final class XPCHelperClient: NSObject { } } - nonisolated func startLunarEventStream(listener: BoringNotchXPCHelperLunarListener) async -> Bool { - await MainActor.run { - lunarListener = listener - } + func startLunarEventStream(listener: BoringNotchXPCHelperLunarListener) async -> Bool { + lunarListener = listener do { - let service = await MainActor.run { - ensureRemoteService(needsListener: true) - } + let service = ensureRemoteService(needsListener: true) return try await service.withContinuation { service, continuation in service.startLunarEventStream { started in continuation.resume(returning: started) @@ -338,11 +305,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func stopLunarEventStream() async { + func stopLunarEventStream() async { do { - let service = await MainActor.run { - ensureRemoteService(needsListener: true) - } + let service = ensureRemoteService(needsListener: true) try await service.withService { service in service.stopLunarEventStream() } @@ -351,11 +316,9 @@ final class XPCHelperClient: NSObject { } } - nonisolated func setLunarOSDHidden(_ hide: Bool) async -> Bool { + func setLunarOSDHidden(_ hide: Bool) async -> Bool { do { - let service = await MainActor.run { - ensureRemoteService() - } + let service = ensureRemoteService() return try await service.withContinuation { service, continuation in service.setLunarOSDHidden(hide) { ok in continuation.resume(returning: ok)