diff --git a/SnowfallApp.xcodeproj/project.pbxproj b/SnowfallApp.xcodeproj/project.pbxproj index 9a10b1b..a0fa0bc 100644 --- a/SnowfallApp.xcodeproj/project.pbxproj +++ b/SnowfallApp.xcodeproj/project.pbxproj @@ -272,6 +272,7 @@ CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"SnowfallApp/Preview Content\""; + DEVELOPMENT_TEAM = 694AARYR2X; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; @@ -317,6 +318,7 @@ CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; DEVELOPMENT_ASSET_PATHS = "\"SnowfallApp/Preview Content\""; + DEVELOPMENT_TEAM = 694AARYR2X; ENABLE_APP_SANDBOX = YES; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; diff --git a/SnowfallApp/Info.plist b/SnowfallApp/Info.plist index 62d843b..85732f5 100644 --- a/SnowfallApp/Info.plist +++ b/SnowfallApp/Info.plist @@ -8,5 +8,7 @@ NSRequiresAquaSystemAppearance + LSUIElement + diff --git a/SnowfallApp/Sources/SnowfallApp.swift b/SnowfallApp/Sources/SnowfallApp.swift index 0b1fa83..e64da99 100644 --- a/SnowfallApp/Sources/SnowfallApp.swift +++ b/SnowfallApp/Sources/SnowfallApp.swift @@ -19,8 +19,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { var snowWindows: [NSWindow] = [] func applicationDidFinishLaunching(_ notification: Notification) { + NSApp.setActivationPolicy(.accessory) setupSnowWindows() NotificationCenter.default.addObserver(self, selector: #selector(setupSnowWindows), name: NSApplication.didChangeScreenParametersNotification, object: nil) + NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(handleSpaceChange), name: NSWorkspace.activeSpaceDidChangeNotification, object: nil) + NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(handleSpaceChange), name: NSWorkspace.didActivateApplicationNotification, object: nil) + updateSnowVisibility() } @objc private func setupSnowWindows() { @@ -42,6 +46,8 @@ class AppDelegate: NSObject, NSApplicationDelegate { for screen in NSScreen.screens { createSnowWindow(for: screen, in: globalRect) } + + updateSnowVisibility() } private func createSnowWindow(for screen: NSScreen, in globalRect: CGRect) { @@ -56,7 +62,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { window.hasShadow = false window.backgroundColor = .clear window.level = .screenSaver - window.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary, .ignoresCycle, .transient, .stationary] + window.collectionBehavior = [.ignoresCycle, .transient, .stationary] window.ignoresMouseEvents = true window.isReleasedWhenClosed = false window.setFrame(screenRect, display: true) @@ -65,4 +71,43 @@ class AppDelegate: NSObject, NSApplicationDelegate { snowWindows.append(window) } + + @objc private func handleSpaceChange() { + updateSnowVisibility() + } + + private func updateSnowVisibility() { + let shouldHide = isAnyFullscreenWindowPresent() + for window in snowWindows { + if shouldHide { + window.orderOut(nil) + } else { + window.orderFront(nil) + } + } + } + + private func isAnyFullscreenWindowPresent() -> Bool { + let options: CGWindowListOption = [.optionOnScreenOnly, .excludeDesktopElements] + guard let windowList = CGWindowListCopyWindowInfo(options, kCGNullWindowID) as? [[String: Any]] else { return false } + + let screenSizes = NSScreen.screens.map { $0.frame.size } + let tolerance: CGFloat = 2.0 + + for entry in windowList { + guard let layer = entry[kCGWindowLayer as String] as? Int, layer == 0, + let bounds = entry[kCGWindowBounds as String] as? [String: Any], + let width = bounds["Width"] as? CGFloat, + let height = bounds["Height"] as? CGFloat else { continue } + + for screenSize in screenSizes { + let widthClose = abs(width - screenSize.width) <= tolerance + let heightClose = abs(height - screenSize.height) <= tolerance + if widthClose && heightClose { + return true + } + } + } + return false + } }