From bb3cc6d3f3202e9337b0f29ebc25325edfc247ae Mon Sep 17 00:00:00 2001 From: Jorgen Bruntveit Date: Wed, 11 Nov 2026 13:16:54 +0100 Subject: [PATCH] Rejoin all Spaces when the pointer turns on When a full-screen Space closes while the pointer is off, macOS keeps the hidden overlay and toolbar on the current Space only, so the hand no longer shows in other full-screen apps until TinyHand restarts. --- Sources/TinyHand/AppKitHelpers.swift | 14 ++++++++++++++ Sources/TinyHand/OverlayController.swift | 2 ++ Sources/TinyHand/Toolbar.swift | 5 +++++ 3 files changed, 21 insertions(+) diff --git a/Sources/TinyHand/AppKitHelpers.swift b/Sources/TinyHand/AppKitHelpers.swift index 8dc3030..74a5425 100644 --- a/Sources/TinyHand/AppKitHelpers.swift +++ b/Sources/TinyHand/AppKitHelpers.swift @@ -1,5 +1,19 @@ import AppKit +extension NSWindow { + /// When a full-screen Space closes, macOS keeps a hidden window that can join all + /// Spaces only on the current Space, and showing it again does not undo that. + /// Removing the behavior, committing it, and adding it back restores every Space. + func rejoinAllSpaces() { + guard collectionBehavior.contains(.canJoinAllSpaces) else { + return + } + collectionBehavior.remove(.canJoinAllSpaces) + CATransaction.flush() + collectionBehavior.insert(.canJoinAllSpaces) + } +} + extension NSView { func removeFocusRings() { focusRingType = .none diff --git a/Sources/TinyHand/OverlayController.swift b/Sources/TinyHand/OverlayController.swift index b0eae63..e0d2630 100644 --- a/Sources/TinyHand/OverlayController.swift +++ b/Sources/TinyHand/OverlayController.swift @@ -413,6 +413,8 @@ final class OverlayController { tapSound.warm() CursorHider.hide() + window.rejoinAllSpaces() + toolbar.rejoinAllSpaces() tick() window.orderFrontRegardless() diff --git a/Sources/TinyHand/Toolbar.swift b/Sources/TinyHand/Toolbar.swift index 95086a0..b4f32da 100644 --- a/Sources/TinyHand/Toolbar.swift +++ b/Sources/TinyHand/Toolbar.swift @@ -379,6 +379,11 @@ final class Toolbar { panel.setFrameOrigin(CGPoint(x: screen.frame.midX - f.width / 2, y: screen.visibleFrame.minY + 14)) } + func rejoinAllSpaces() { + panel.rejoinAllSpaces() + tray.rejoinAllSpaces() + } + func show() { panel.orderFrontRegardless() panel.invalidateShadow()