From f4bcb96906f0afd2c0d59e55edb1827e5d91dd23 Mon Sep 17 00:00:00 2001 From: Hariharan Mudaliar Date: Sat, 6 Sep 2025 19:43:40 +0530 Subject: [PATCH] BugFix: Multiple object creation --- DynamicIsland/DynamicIslandApp.swift | 5 ++ .../Notch/DynamicIslandHeader.swift | 2 +- .../components/Notch/NotchShelfView.swift | 2 +- .../components/Shelf/DropItemView.swift | 2 +- DynamicIsland/helpers/SystemHUDDebugger.swift | 83 +++++++++++++++++++ .../managers/SystemChangesObserver.swift | 29 ++++--- DynamicIsland/managers/SystemHUDManager.swift | 52 +++++++++--- DynamicIsland/managers/SystemOSDManager.swift | 68 +++++++++++++-- 8 files changed, 206 insertions(+), 37 deletions(-) create mode 100644 DynamicIsland/helpers/SystemHUDDebugger.swift diff --git a/DynamicIsland/DynamicIslandApp.swift b/DynamicIsland/DynamicIslandApp.swift index 19fa7cd..e016eef 100644 --- a/DynamicIsland/DynamicIslandApp.swift +++ b/DynamicIsland/DynamicIslandApp.swift @@ -112,9 +112,14 @@ class AppDelegate: NSObject, NSApplicationDelegate { // Cancel any pending window size updates windowSizeUpdateWorkItem?.cancel() + print("๐Ÿšช Application terminating - ensuring system HUD is restored...") + // Re-enable system HUD on app termination SystemOSDManager.enableSystemHUD() + // Give it time to complete + usleep(500000) // 500ms + NotificationCenter.default.removeObserver(self) } diff --git a/DynamicIsland/components/Notch/DynamicIslandHeader.swift b/DynamicIsland/components/Notch/DynamicIslandHeader.swift index 449d8b4..2e6fea2 100644 --- a/DynamicIsland/components/Notch/DynamicIslandHeader.swift +++ b/DynamicIsland/components/Notch/DynamicIslandHeader.swift @@ -14,7 +14,7 @@ struct DynamicIslandHeader: View { @ObservedObject var batteryModel = BatteryStatusViewModel.shared @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared @ObservedObject var clipboardManager = ClipboardManager.shared - @StateObject var tvm = TrayDrop.shared + @ObservedObject var tvm = TrayDrop.shared @State private var showClipboardPopover = false @State private var showColorPickerPopover = false diff --git a/DynamicIsland/components/Notch/NotchShelfView.swift b/DynamicIsland/components/Notch/NotchShelfView.swift index 5ec7528..aa925b9 100644 --- a/DynamicIsland/components/Notch/NotchShelfView.swift +++ b/DynamicIsland/components/Notch/NotchShelfView.swift @@ -3,7 +3,7 @@ import SwiftUI struct NotchShelfView: View { @EnvironmentObject var vm: DynamicIslandViewModel - @StateObject var tvm = TrayDrop.shared + @ObservedObject var tvm = TrayDrop.shared var body: some View { HStack { diff --git a/DynamicIsland/components/Shelf/DropItemView.swift b/DynamicIsland/components/Shelf/DropItemView.swift index 131d70c..3c8eb50 100644 --- a/DynamicIsland/components/Shelf/DropItemView.swift +++ b/DynamicIsland/components/Shelf/DropItemView.swift @@ -13,7 +13,7 @@ struct DropItemView: View { let item: TrayDrop.DropItem @EnvironmentObject var vm: DynamicIslandViewModel @ObservedObject var coordinator = DynamicIslandViewCoordinator.shared - @StateObject var tvm = TrayDrop.shared + @ObservedObject var tvm = TrayDrop.shared @State var hover = false diff --git a/DynamicIsland/helpers/SystemHUDDebugger.swift b/DynamicIsland/helpers/SystemHUDDebugger.swift new file mode 100644 index 0000000..bf93cd5 --- /dev/null +++ b/DynamicIsland/helpers/SystemHUDDebugger.swift @@ -0,0 +1,83 @@ +// +// SystemHUDDebugger.swift +// DynamicIsland +// +// Debug utility for System HUD functionality +// Created by GitHub Copilot on 06/09/25. +// + +import Foundation + +class SystemHUDDebugger { + + /// Test system HUD functionality and print status + public static func testSystemHUD() { + print("\n๐Ÿ” === System HUD Debug Report ===") + + // Check current OSDUIHelper status + let isRunning = SystemOSDManager.isOSDUIHelperRunning() + print("๐Ÿ“Š OSDUIHelper Status: \(isRunning ? "โœ… Running" : "โŒ Not running")") + + // Test disable + print("๐Ÿ”‡ Testing disable...") + SystemOSDManager.disableSystemHUD() + + // Wait and check + usleep(500000) + let isRunningAfterDisable = SystemOSDManager.isOSDUIHelperRunning() + print("๐Ÿ“Š After disable: \(isRunningAfterDisable ? "โœ… Running (stopped)" : "โŒ Not running")") + + // Test enable + print("๐Ÿ”Š Testing re-enable...") + SystemOSDManager.enableSystemHUD() + + // Wait and check + usleep(1000000) + let isRunningAfterEnable = SystemOSDManager.isOSDUIHelperRunning() + print("๐Ÿ“Š After re-enable: \(isRunningAfterEnable ? "โœ… Running" : "โŒ Not running")") + + print("๐Ÿ” === End Debug Report ===\n") + + if !isRunningAfterEnable { + print("โš ๏ธ WARNING: System HUD may not be working properly!") + print("๐Ÿ’ก Try pressing volume keys to test system HUD functionality") + } + } + + /// Force restart OSDUIHelper using multiple methods + public static func forceRestartOSDUIHelper() { + print("๐Ÿ”„ Force restarting OSDUIHelper...") + + // Method 1: Kill and kickstart + SystemOSDManager.enableSystemHUD() + + // Method 2: Try launchctl bootstrap (more aggressive) + do { + let bootstrap = Process() + bootstrap.executableURL = URL(fileURLWithPath: "/bin/launchctl") + bootstrap.arguments = ["bootstrap", "gui/\(getuid())", "/System/Library/LaunchAgents/com.apple.OSDUIHelper.plist"] + try bootstrap.run() + bootstrap.waitUntilExit() + print("โœ… Bootstrap method completed") + } catch { + print("โŒ Bootstrap method failed: \(error)") + } + + // Method 3: Try direct service restart + do { + let restart = Process() + restart.executableURL = URL(fileURLWithPath: "/bin/launchctl") + restart.arguments = ["restart", "gui/\(getuid())/com.apple.OSDUIHelper"] + try restart.run() + restart.waitUntilExit() + print("โœ… Restart method completed") + } catch { + print("โŒ Restart method failed: \(error)") + } + + // Check final status + usleep(1000000) + let finalStatus = SystemOSDManager.isOSDUIHelperRunning() + print("๐Ÿ“Š Final OSDUIHelper status: \(finalStatus ? "โœ… Running" : "โŒ Not running")") + } +} \ No newline at end of file diff --git a/DynamicIsland/managers/SystemChangesObserver.swift b/DynamicIsland/managers/SystemChangesObserver.swift index 1156a0e..1da8eed 100644 --- a/DynamicIsland/managers/SystemChangesObserver.swift +++ b/DynamicIsland/managers/SystemChangesObserver.swift @@ -10,16 +10,13 @@ import Cocoa import Foundation import Defaults -class SystemChangesObserver: ObservableObject { +class SystemChangesObserver { private var oldVolume: Float private var oldMuted: Bool private var oldBrightness: Float = 0 private weak var coordinator: DynamicIslandViewCoordinator? - - @Default(.enableSystemHUD) var enableSystemHUD - @Default(.enableVolumeHUD) var enableVolumeHUD - @Default(.enableBrightnessHUD) var enableBrightnessHUD + private var timer: Timer? init(coordinator: DynamicIslandViewCoordinator) { self.coordinator = coordinator @@ -34,18 +31,18 @@ class SystemChangesObserver: ObservableObject { } func startObserving() { - guard enableSystemHUD else { return } + guard Defaults[.enableSystemHUD] else { return } createObservers() createTimerForContinuousChangesCheck(with: 0.2) } private func createTimerForContinuousChangesCheck(with seconds: TimeInterval) { - let timer = Timer( + timer = Timer( timeInterval: seconds, target: self, selector: #selector(checkChanges), userInfo: nil, repeats: true) let mainLoop = RunLoop.main - mainLoop.add(timer, forMode: .common) + mainLoop.add(timer!, forMode: .common) } private func createObservers() { @@ -63,7 +60,7 @@ class SystemChangesObserver: ObservableObject { } @objc func showVolumeHUD() { - guard enableSystemHUD && enableVolumeHUD else { return } + guard Defaults[.enableSystemHUD] && Defaults[.enableVolumeHUD] else { return } if oldVolume == 0.0 || oldVolume == 1.0 { sendVolumeNotification(value: oldVolume) @@ -72,7 +69,7 @@ class SystemChangesObserver: ObservableObject { } @objc func showBrightnessHUD() { - guard enableSystemHUD && enableBrightnessHUD else { return } + guard Defaults[.enableSystemHUD] && Defaults[.enableBrightnessHUD] else { return } if oldBrightness == 0.0 || oldBrightness == 1.0 { sendBrightnessNotification(value: oldBrightness) @@ -81,7 +78,7 @@ class SystemChangesObserver: ObservableObject { } @objc func checkChanges() { - guard enableSystemHUD else { return } + guard Defaults[.enableSystemHUD] else { return } checkBrightnessChanges() checkVolumeChanges() @@ -93,7 +90,7 @@ class SystemChangesObserver: ObservableObject { } private func checkVolumeChanges() { - guard enableVolumeHUD else { return } + guard Defaults[.enableVolumeHUD] else { return } let newVolume = SystemVolumeManager.getOutputVolume() let newMuted = SystemVolumeManager.isMuted() @@ -110,7 +107,7 @@ class SystemChangesObserver: ObservableObject { } private func checkBrightnessChanges() { - guard enableBrightnessHUD else { return } + guard Defaults[.enableBrightnessHUD] else { return } if NSScreen.screens.count == 0 { return @@ -148,6 +145,12 @@ class SystemChangesObserver: ObservableObject { } deinit { + stopObserving() + } + + func stopObserving() { + timer?.invalidate() + timer = nil NotificationCenter.default.removeObserver(self) } } \ No newline at end of file diff --git a/DynamicIsland/managers/SystemHUDManager.swift b/DynamicIsland/managers/SystemHUDManager.swift index 220665a..13965a1 100644 --- a/DynamicIsland/managers/SystemHUDManager.swift +++ b/DynamicIsland/managers/SystemHUDManager.swift @@ -7,31 +7,38 @@ import Foundation import Defaults +import Combine -class SystemHUDManager: ObservableObject { +class SystemHUDManager { static let shared = SystemHUDManager() private var changesObserver: SystemChangesObserver? private weak var coordinator: DynamicIslandViewCoordinator? - @Default(.enableSystemHUD) var enableSystemHUD { - didSet { - Task { @MainActor in - if enableSystemHUD { - await startSystemHUD() - } else { - await stopSystemHUD() - } - } - } + private init() { + // Set up observer for settings changes + setupSettingsObserver() } - private init() {} + private func setupSettingsObserver() { + // Use Defaults publisher instead of @Default property wrapper + Defaults.publisher(.enableSystemHUD, options: []).sink { [weak self] change in + Task { @MainActor in + if change.newValue { + await self?.startSystemHUD() + } else { + await self?.stopSystemHUD() + } + } + }.store(in: &cancellables) + } + + private var cancellables = Set() func setup(coordinator: DynamicIslandViewCoordinator) { self.coordinator = coordinator - if enableSystemHUD { + if Defaults[.enableSystemHUD] { Task { @MainActor in await startSystemHUD() } @@ -56,6 +63,7 @@ class SystemHUDManager: ObservableObject { @MainActor private func stopSystemHUD() async { + changesObserver?.stopObserving() changesObserver = nil // Re-enable system HUD @@ -65,18 +73,36 @@ class SystemHUDManager: ObservableObject { } private func disableSystemHUD() { + print("๐Ÿ”‡ Disabling system HUD (OSDUIHelper running: \(SystemOSDManager.isOSDUIHelperRunning()))") // Disable the system HUD using SystemOSDManager SystemOSDManager.disableSystemHUD() } private func enableOriginalSystemHUD() { + print("๐Ÿ”Š Re-enabling system HUD (OSDUIHelper running: \(SystemOSDManager.isOSDUIHelperRunning()))") // Re-enable the system HUD using SystemOSDManager SystemOSDManager.enableSystemHUD() + + // Verify it's working after a short delay + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + let isRunning = SystemOSDManager.isOSDUIHelperRunning() + print("๐Ÿ” OSDUIHelper status after re-enable: \(isRunning ? "โœ… Running" : "โŒ Not running")") + } } deinit { + print("๐Ÿงน SystemHUDManager deinitializing - ensuring system HUD is restored") + cancellables.removeAll() Task { @MainActor in await stopSystemHUD() } + // Also call the emergency restore as backup + SystemHUDDebugger.forceRestartOSDUIHelper() + } + + /// Emergency restore function - call this if system HUD is not working + public static func emergencyRestoreSystemHUD() { + print("๐Ÿšจ Emergency system HUD restore initiated") + SystemHUDDebugger.forceRestartOSDUIHelper() } } \ No newline at end of file diff --git a/DynamicIsland/managers/SystemOSDManager.swift b/DynamicIsland/managers/SystemOSDManager.swift index 319b75e..fb2e369 100644 --- a/DynamicIsland/managers/SystemOSDManager.swift +++ b/DynamicIsland/managers/SystemOSDManager.swift @@ -14,13 +14,41 @@ class SystemOSDManager { /// Re-enables the system HUD by restarting OSDUIHelper public static func enableSystemHUD() { do { - let task = Process() - task.executableURL = URL(fileURLWithPath: "/usr/bin/killall") - task.arguments = ["-9", "OSDUIHelper"] - try task.run() - print("System HUD re-enabled") + // First, stop any existing OSDUIHelper process + let stopTask = Process() + stopTask.executableURL = URL(fileURLWithPath: "/usr/bin/killall") + stopTask.arguments = ["-9", "OSDUIHelper"] + try stopTask.run() + stopTask.waitUntilExit() + + // Small delay to ensure process is fully stopped + usleep(200000) // 200ms + + // Then kickstart it again to ensure it's running properly + let kickstart = Process() + kickstart.executableURL = URL(fileURLWithPath: "/bin/launchctl") + kickstart.arguments = ["kickstart", "gui/\(getuid())/com.apple.OSDUIHelper"] + try kickstart.run() + kickstart.waitUntilExit() + + // Additional delay to ensure service is fully started + usleep(300000) // 300ms + + print("โœ… System HUD re-enabled") } catch { - NSLog("Error while trying to re-enable OSDUIHelper. \(error)") + NSLog("โŒ Error while trying to re-enable OSDUIHelper: \(error)") + + // Fallback: Try to restart the service using launchctl load + do { + let fallbackTask = Process() + fallbackTask.executableURL = URL(fileURLWithPath: "/bin/launchctl") + fallbackTask.arguments = ["load", "-w", "/System/Library/LaunchAgents/com.apple.OSDUIHelper.plist"] + try fallbackTask.run() + fallbackTask.waitUntilExit() + print("โœ… System HUD re-enabled via fallback method") + } catch { + NSLog("โŒ Fallback method also failed: \(error)") + } } } @@ -39,9 +67,33 @@ class SystemOSDManager { task.executableURL = URL(fileURLWithPath: "/usr/bin/killall") task.arguments = ["-STOP", "OSDUIHelper"] try task.run() - print("System HUD disabled") + task.waitUntilExit() + + print("โœ… System HUD disabled") } catch { - NSLog("Error while trying to hide OSDUIHelper. Please create an issue on GitHub. Error: \(error)") + NSLog("โŒ Error while trying to hide OSDUIHelper: \(error)") + } + } + + /// Check if OSDUIHelper is currently running + public static func isOSDUIHelperRunning() -> Bool { + let task = Process() + task.executableURL = URL(fileURLWithPath: "/usr/bin/pgrep") + task.arguments = ["OSDUIHelper"] + + let pipe = Pipe() + task.standardOutput = pipe + + do { + try task.run() + task.waitUntilExit() + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + let output = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) + + return task.terminationStatus == 0 && !output!.isEmpty + } catch { + return false } } } \ No newline at end of file