@@ -1317,6 +1317,39 @@ final class OverlayProbeDelegate: NSObject, NSApplicationDelegate {
13171317 check7 ( source. marqueeLadder ( in: degenerate) . isEmpty,
13181318 " zero-area frame -> [] (a click is not a marquee) " )
13191319
1320+ // 7g — NOTHING from AnnotKit's own overlay can enter the candidate set.
1321+ // Sharper for a marquee than for a click: a drag rect by construction
1322+ // spans screen the overlay is drawn across, and overlay elements are
1323+ // genuinely identified and genuinely meaningful, so the rule cannot
1324+ // reject them — a large overlay surface would WIN pass 1 on area and
1325+ // bind the user's note to our own UI. The walk is rooted at the HOST
1326+ // window (the overlay is filtered out of `kAXWindows` by identifier
1327+ // BEFORE the root is picked, never by "key" or "frontmost"), so the
1328+ // overlay's descendants are out of reach by construction. This asserts
1329+ // that construction against the live tree instead of trusting it.
1330+ let app = AXUIElementCreateApplication ( ProcessInfo . processInfo. processIdentifier)
1331+ AXUIElementSetAttributeValue ( app, " AXEnhancedUserInterface " as CFString , kCFBooleanTrue)
1332+ let rawWindows = AX . windows ( app)
1333+ let overlayPanel = rawWindows. first { AX . string ( $0, kAXIdentifierAttribute) == overlayWindowIdentifier }
1334+ check7 ( overlayPanel != nil , " the overlay panel IS a live AX window during the drag (a real shadowing risk) " )
1335+ if let overlayPanel {
1336+ let panelFrame = AX . frame ( overlayPanel)
1337+ // Without this the whole sub-phase would be vacuous: an overlay that
1338+ // does not cover the drag region proves nothing about one that does.
1339+ check7 ( panelFrame. contains ( card. frame) ,
1340+ " sanity: the expanded overlay SPANS the drag region (the card is drawn beneath it) " )
1341+ let overlayIDs = Set ( self . axCollectIDs ( in: overlayPanel, depth: 0 ) )
1342+ let hostWindow = rawWindows. first { AX . string ( $0, kAXTitleAttribute) == " AnnotKit Harness W7 (marquee) " }
1343+ let panelIsAXChildOfHost = hostWindow. map { host in
1344+ AX . children ( host) . contains { CFEqual ( $0, overlayPanel) }
1345+ } ?? false
1346+ print ( " overlay panel \( fmt ( panelFrame) ) carries \( overlayIDs. count) identified element(s); " +
1347+ " exposed as an AX CHILD of the host window: \( panelIsAXChildOfHost) " )
1348+ let everyResult = cardLadder + sectionLadder + buttonLadder + insideLadder
1349+ check7 ( !everyResult. contains { overlayIDs. contains ( $0. id) } ,
1350+ " no marquee result — target or rung — is an element from AnnotKit's own overlay subtree " )
1351+ }
1352+
13201353 self . marqueeController? . unmount ( )
13211354 window. orderOut ( nil )
13221355 self . finish ( )
@@ -1332,6 +1365,19 @@ final class OverlayProbeDelegate: NSObject, NSApplicationDelegate {
13321365 return nil
13331366 }
13341367
1368+ /// Every non-empty AX identifier in `element`'s subtree, including its own —
1369+ /// the set of ids a walk that strayed into the overlay would surface.
1370+ func axCollectIDs( in element: AXUIElement , depth: Int ) -> [ String ] {
1371+ guard depth < 32 else { return [ ] }
1372+ var out : [ String ] = [ ]
1373+ let id = AX . string ( element, kAXIdentifierAttribute)
1374+ if !id. isEmpty { out. append ( id) }
1375+ for child in AX . children ( element) {
1376+ out. append ( contentsOf: axCollectIDs ( in: child, depth: depth + 1 ) )
1377+ }
1378+ return out
1379+ }
1380+
13351381 /// Recursive raw-AX search for elements matching one of `subroles`.
13361382 func axFindAll( in element: AXUIElement , subroles: Set < String > , depth: Int ) -> [ AXUIElement ] {
13371383 guard depth < 12 else { return [ ] }
0 commit comments