Compare commits

...
2 Commits
Author SHA1 Message Date
TZGyn 69e1a7fccb Show overlays only after activation completes
The local probe confirmed activation is asynchronous on macOS 26:
isActive flips on a later runloop tick, so overlays shown in the same
tick as activate() belong to a still-inactive app and misses clicks.
Delay overlay creation by a tick and log the activation state at show
time.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-0731
2026-09-09 11:51:13 +08:00
TZGyn e22bcb99c4 Make overlay panels activating so clicks are received
The session log showed active=false after every activation attempt on
macOS 26: cooperative activation is denied for LSUIElement apps, and an
inactive app's panels let clicks fall through to the windows below.
Remove .nonactivatingPanel so showing the overlay activates the app
(previous app focus is restored after capture as before).

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-0731
2026-09-09 11:46:45 +08:00
2 changed files with 20 additions and 16 deletions
+18 -14
View File
@@ -61,22 +61,26 @@ final class CaptureController: NSObject {
} }
isSelecting = true isSelecting = true
previousApp = NSWorkspace.shared.frontmostApplication previousApp = NSWorkspace.shared.frontmostApplication
// Force activation: cooperative NSApp.activate() can silently fail for // Activation is ASYNC: isActive only flips on a later runloop tick
// LSUIElement apps, leaving the app inactive — then clicks on the // (verified on macOS 26). Show overlays only once active, otherwise
// overlays pass through to the windows below. // the first click can pass through to the windows below.
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
CaptureController.log("begin: creating overlays for \(NSScreen.screens.count) screens") CaptureController.log("begin: activate issued, active=\(NSApp.isActive)")
overlays = NSScreen.screens.map { screen in DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) { [weak self] in
OverlayWindow( guard let self, self.isSelecting else { return }
screen: screen, CaptureController.log("begin: active=\(NSApp.isActive) — showing overlays")
onComplete: { [weak self] rect in self?.finishSelection(rect) }, self.overlays = NSScreen.screens.map { screen in
onCancel: { [weak self] in self?.cancelSelection() }, OverlayWindow(
onWindowPick: { [weak self] rect in self?.finishWindowPick(rect) } screen: screen,
) onComplete: { [weak self] rect in self?.finishSelection(rect) },
onCancel: { [weak self] in self?.cancelSelection() },
onWindowPick: { [weak self] rect in self?.finishWindowPick(rect) }
)
}
self.overlays.forEach { $0.makeKeyAndOrderFront(nil) }
self.overlayIDs = self.overlays.map { $0.windowNumber }
CaptureController.log("begin: \(self.overlays.count) overlays, ids=\(self.overlayIDs), active=\(NSApp.isActive)")
} }
overlays.forEach { $0.makeKeyAndOrderFront(nil) }
overlayIDs = overlays.map { $0.windowNumber }
CaptureController.log("begin: \(overlays.count) overlays, ids=\(overlayIDs), active=\(NSApp.isActive)")
} }
/// A window was picked from hover — capture it with rounded corners. /// A window was picked from hover — capture it with rounded corners.
+2 -2
View File
@@ -108,9 +108,9 @@ cat > "$APP/Contents/Info.plist" <<'PLIST'
<key>CFBundleIconFile</key> <key>CFBundleIconFile</key>
<string>Icon</string> <string>Icon</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.6.2</string> <string>1.6.4</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>62</string> <string>64</string>
<key>LSUIElement</key> <key>LSUIElement</key>
<true/> <true/>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>