Compare commits

...
1 Commits
Author SHA1 Message Date
TZGyn 265571d7e2 Reject window captures that composite extra windows
ScreenCaptureKit's desktopIndependentWindow filter can include owned
child windows (e.g. an app dialog plus its parent), producing a capture
much larger than the picked window. Detect the overflow by comparing the
returned image size against the window's frame and fall back to the
screen crop with rounded mask. Hover changes are logged with the picked
window id and tracked count for diagnosis.

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-0731
2026-09-09 14:55:40 +08:00
2 changed files with 22 additions and 5 deletions
+20 -3
View File
@@ -287,6 +287,11 @@ final class CaptureController: NSObject {
let window = topmostWindowContaining(appKitPoint) let window = topmostWindowContaining(appKitPoint)
if window?.frame != hoverFrame { if window?.frame != hoverFrame {
hoverWindow = window hoverWindow = window
if let w = window {
CaptureController.log("hover: picked id=\(w.id) frame=\(w.frame) (tracked=\(trackedWindows.count))")
} else {
CaptureController.log("hover: none (tracked=\(trackedWindows.count))")
}
renderOverlays() renderOverlays()
} }
return event return event
@@ -463,9 +468,21 @@ final class ScreenCapture {
contentFilter: SCContentFilter(desktopIndependentWindow: scWindow), contentFilter: SCContentFilter(desktopIndependentWindow: scWindow),
configuration: windowConfig configuration: windowConfig
) { ) {
CaptureController.log("capture: WINDOW id=\(windowID) image=\(windowImage.width)x\(windowImage.height) (native alpha corners)") let expectedW = CGFloat(scWindow.frame.width) * backingScale
completion(windowImage) let expectedH = CGFloat(scWindow.frame.height) * backingScale
return let overflow = max(
CGFloat(windowImage.width) / max(expectedW, 1),
CGFloat(windowImage.height) / max(expectedH, 1)
)
if overflow > 1.35 {
// SCKit composited extra windows (owned popups etc.)
// — reject and use the screen crop instead.
CaptureController.log("capture: WINDOW id=\(windowID) overflow=\(overflow) (\(windowImage.width)x\(windowImage.height) vs \(Int(expectedW))x\(Int(expectedH))) — rejecting, using crop+mask")
} else {
CaptureController.log("capture: WINDOW id=\(windowID) image=\(windowImage.width)x\(windowImage.height) (native alpha corners)")
completion(windowImage)
return
}
} }
CaptureController.log("capture: window filter failed for id=\(windowID) — falling back to crop+mask") CaptureController.log("capture: window filter failed for id=\(windowID) — falling back to crop+mask")
} }
+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.8.0</string> <string>1.8.1</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>80</string> <string>81</string>
<key>LSUIElement</key> <key>LSUIElement</key>
<true/> <true/>
<key>NSHighResolutionCapable</key> <key>NSHighResolutionCapable</key>