Fix window hover detection; add redaction tool

Window detection was broken by wrong CG-to-AppKit coordinate conversion
of the cursor and highlight rects — both now go through the same
cgToAppKit mapping. The draw toolbar gains a Pen/Redact toggle: redact
drags cover content with a solid black bar (participates in undo/redo
and export like pen strokes).

💘 Generated with Crush

Assisted-by: Crush:deepseek-v4-flash-0731
This commit is contained in:
2026-09-09 10:39:26 +08:00
parent b998ea210e
commit 5f137f89bf
3 changed files with 89 additions and 51 deletions
+11 -15
View File
@@ -97,24 +97,19 @@ final class OverlayView: NSView {
private func windowFrame(at point: NSPoint) -> NSRect? {
guard let window = window else { return nil }
let screenPoint = window.convertToScreen(NSRect(origin: point, size: .zero))
// CGWindowList bounds use a TOP-LEFT origin; convert the cursor point.
guard let mainScreen = NSScreen.screens.first else { return nil }
let topLeftPoint = NSPoint(
x: screenPoint.origin.x,
y: mainScreen.frame.height - screenPoint.origin.y
)
// Pick the frontmost (list order) window containing the point
// convertToScreen gives AppKit-global coordinates; convert tracked
// CG frames to the same space and pick the frontmost containing it.
let screenPoint = window.convertToScreen(NSRect(origin: point, size: .zero)).origin
for (_, frame) in trackedWindows {
if frame.contains(topLeftPoint) {
if Self.cgToAppKit(rect: frame).contains(screenPoint) {
return frame
}
}
return nil
}
/// Convert a CGWindowList (top-left origin) frame into AppKit screen
/// coordinates (bottom-left origin) for capture.
/// Convert a CGWindowList (top-left origin, CG global space) frame into
/// AppKit screen coordinates (bottom-left origin) for capture.
private static func cgToAppKit(rect: NSRect) -> NSRect {
guard let mainScreen = NSScreen.screens.first else { return rect }
let y = mainScreen.frame.height - rect.origin.y - rect.height
@@ -189,12 +184,13 @@ final class OverlayView: NSView {
// Highlight the hovered window (rounded, like the real window corners)
if let frame = hoveredWindowFrame {
// Convert CGWindowList (top-left) frame to view (bottom-left) space
guard let window = window, let mainScreen = NSScreen.screens.first else { return }
// Convert the CG frame to AppKit-global, then to this view's space.
guard let window = window else { return }
let screenFrame = window.convertToScreen(NSRect(origin: .zero, size: bounds.size))
let appKitFrame = Self.cgToAppKit(rect: frame)
let viewFrame = NSRect(
x: frame.origin.x - screenFrame.origin.x,
y: mainScreen.frame.height - frame.origin.y - frame.height - screenFrame.origin.y,
x: appKitFrame.origin.x - screenFrame.origin.x,
y: appKitFrame.origin.y - screenFrame.origin.y,
width: frame.width,
height: frame.height
)