From a5ff8d391b6dcb9a6a8103bc45919e9d4d729e7e Mon Sep 17 00:00:00 2001 From: Daneel Date: Mon, 2 Mar 2026 20:57:32 +0100 Subject: [PATCH] patches: fix org fold/unfold VoiceOver refresh; revert to BUF_MODIFF REGRESSION: fold/unfold in org-mode, outline-mode and hideshow-mode did not refresh VoiceOver text because ensureTextCache used BUF_CHARS_MODIFF which is NOT bumped by (put-text-property ... 'invisible), the mechanism used by modern org-fold-core (org >= 29) and outline-mode to hide text. VoiceOver would continue reading folded content as if visible, or miss newly unfolded content entirely, because the text cache was considered valid despite the visible-text having changed. Revert ensureTextCache to BUF_MODIFF with an explanatory comment: - BUF_CHARS_MODIFF is bumped only on character insertions/deletions, not text-property changes. Fold/unfold uses text properties for visibility. - BUF_OVERLAY_MODIFF alone is also insufficient: org >= 29 uses text properties, not overlays, for folding. Also hl-line-mode bumps BUF_OVERLAY_MODIFF every post-command-hook --- same per-keystroke cost as BUF_MODIFF, with none of its correctness guarantee. - BUF_MODIFF cost is acceptable: ensureTextCache is called only when VoiceOver queries AX properties (human interaction speed, not redisplay speed). Rebuild cost is O(visible-buffer-text). Also retain C-n/C-p line-read fix from previous commit (7a0b4f6): FocusedUIElementChanged excluded for sequential isCtrlNP moves. --- ...-with-macOS-Zoom-for-cursor-tracking.patch | 2 +- ...lity-base-classes-and-text-extractio.patch | 2 +- ...fer-accessibility-element-core-proto.patch | 2 +- ...tification-dispatch-and-mode-line-el.patch | 2 +- ...ive-span-elements-for-Tab-navigation.patch | 2 +- ...essibility-with-EmacsView-and-redisp.patch | 2 +- ...r-accessibility-section-to-macOS-app.patch | 2 +- ...lay-completion-candidates-for-VoiceO.patch | 95 ++++++++++++++----- ...d-frame-completion-candidates-for-Vo.patch | 66 ++++--------- 9 files changed, 94 insertions(+), 81 deletions(-) diff --git a/patches/0000-ns-integrate-with-macOS-Zoom-for-cursor-tracking.patch b/patches/0000-ns-integrate-with-macOS-Zoom-for-cursor-tracking.patch index 8443f9f..ffdbbf4 100644 --- a/patches/0000-ns-integrate-with-macOS-Zoom-for-cursor-tracking.patch +++ b/patches/0000-ns-integrate-with-macOS-Zoom-for-cursor-tracking.patch @@ -1,4 +1,4 @@ -From 3f97f3b69fdb10c1781ded98292434525838a369 Mon Sep 17 00:00:00 2001 +From 2d2b7eb2b3039f3e581460c874a5ece52ebfdb9a Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 22:39:35 +0100 Subject: [PATCH 0/8] ns: integrate with macOS Zoom for cursor tracking diff --git a/patches/0001-ns-add-accessibility-base-classes-and-text-extractio.patch b/patches/0001-ns-add-accessibility-base-classes-and-text-extractio.patch index 965c906..3136f4d 100644 --- a/patches/0001-ns-add-accessibility-base-classes-and-text-extractio.patch +++ b/patches/0001-ns-add-accessibility-base-classes-and-text-extractio.patch @@ -1,4 +1,4 @@ -From 234da3ced54798fe9e4bafb0eae08d571a4ffcfc Mon Sep 17 00:00:00 2001 +From 01f32063667eb000b95b1514b0f78056aaa53c28 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 12:58:11 +0100 Subject: [PATCH 1/8] ns: add accessibility base classes and text extraction diff --git a/patches/0002-ns-implement-buffer-accessibility-element-core-proto.patch b/patches/0002-ns-implement-buffer-accessibility-element-core-proto.patch index a010a00..1924280 100644 --- a/patches/0002-ns-implement-buffer-accessibility-element-core-proto.patch +++ b/patches/0002-ns-implement-buffer-accessibility-element-core-proto.patch @@ -1,4 +1,4 @@ -From 5a786a29a4d4067ce7a75994136f945c49e4624e Mon Sep 17 00:00:00 2001 +From 4f4fa019e14e1cd9283b09b9b7cf20e772edc809 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 12:58:11 +0100 Subject: [PATCH 2/8] ns: implement buffer accessibility element (core diff --git a/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch b/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch index bc430ca..54d53bd 100644 --- a/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch +++ b/patches/0003-ns-add-buffer-notification-dispatch-and-mode-line-el.patch @@ -1,4 +1,4 @@ -From 1dd6de1a46d86a87640129745bb0db01618b2879 Mon Sep 17 00:00:00 2001 +From 4a77386e8210b2ad8fe1c9a0145cbde96d282c7c Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 12:58:11 +0100 Subject: [PATCH 3/8] ns: add buffer notification dispatch and mode-line diff --git a/patches/0004-ns-add-interactive-span-elements-for-Tab-navigation.patch b/patches/0004-ns-add-interactive-span-elements-for-Tab-navigation.patch index 70ccf42..79c2bbe 100644 --- a/patches/0004-ns-add-interactive-span-elements-for-Tab-navigation.patch +++ b/patches/0004-ns-add-interactive-span-elements-for-Tab-navigation.patch @@ -1,4 +1,4 @@ -From 3b8838647b39912753157d76b2aa4d8d0da0c55c Mon Sep 17 00:00:00 2001 +From f6a4baf7e19aa2b95becff1dc8be4c2fdc85a0d5 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 12:58:11 +0100 Subject: [PATCH 4/8] ns: add interactive span elements for Tab navigation diff --git a/patches/0005-ns-integrate-accessibility-with-EmacsView-and-redisp.patch b/patches/0005-ns-integrate-accessibility-with-EmacsView-and-redisp.patch index a08058d..be17a92 100644 --- a/patches/0005-ns-integrate-accessibility-with-EmacsView-and-redisp.patch +++ b/patches/0005-ns-integrate-accessibility-with-EmacsView-and-redisp.patch @@ -1,4 +1,4 @@ -From d4cda4bda0bee73c14946f20322975edd1580d46 Mon Sep 17 00:00:00 2001 +From 825798ddb922cb24cf3db72d76c6ea4e29596844 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 12:58:11 +0100 Subject: [PATCH 5/8] ns: integrate accessibility with EmacsView and redisplay diff --git a/patches/0006-doc-add-VoiceOver-accessibility-section-to-macOS-app.patch b/patches/0006-doc-add-VoiceOver-accessibility-section-to-macOS-app.patch index e4bdaab..5606374 100644 --- a/patches/0006-doc-add-VoiceOver-accessibility-section-to-macOS-app.patch +++ b/patches/0006-doc-add-VoiceOver-accessibility-section-to-macOS-app.patch @@ -1,4 +1,4 @@ -From 33ed790921c1d78dec79f803807deae65fff365e Mon Sep 17 00:00:00 2001 +From b0a0cf378168cd15d2af663100dae87ded394801 Mon Sep 17 00:00:00 2001 From: Martin Sukany Date: Sat, 28 Feb 2026 12:58:11 +0100 Subject: [PATCH 6/8] doc: add VoiceOver accessibility section to macOS diff --git a/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch b/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch index ffd6614..e6f1e5d 100644 --- a/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch +++ b/patches/0007-ns-announce-overlay-completion-candidates-for-VoiceO.patch @@ -1,4 +1,4 @@ -From 8c99359156443223d13905de4cfbca58fb3e1177 Mon Sep 17 00:00:00 2001 +From 1a3dea1876ecde2e625d3a2b8f41d688568ecbf8 Mon Sep 17 00:00:00 2001 From: Daneel Date: Mon, 2 Mar 2026 18:39:46 +0100 Subject: [PATCH 7/8] ns: announce overlay completion candidates for VoiceOver @@ -18,8 +18,8 @@ ValueChanged; keep overlay_modiff out of ensureTextCache to prevent a race where an AX query consumes the change before notification. --- src/nsterm.h | 1 + - src/nsterm.m | 318 +++++++++++++++++++++++++++++++++++++++++++++------ - 2 files changed, 283 insertions(+), 36 deletions(-) + src/nsterm.m | 348 ++++++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 307 insertions(+), 42 deletions(-) diff --git a/src/nsterm.h b/src/nsterm.h index 5746e9e9bd..21a93bc799 100644 @@ -34,7 +34,7 @@ index 5746e9e9bd..21a93bc799 100644 @property (nonatomic, assign) BOOL cachedMarkActive; @property (nonatomic, copy) NSString *cachedCompletionAnnouncement; diff --git a/src/nsterm.m b/src/nsterm.m -index a0598a73c2..3d8a5dd0fc 100644 +index a0598a73c2..8f744d1bf3 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -7263,11 +7263,154 @@ Accessibility virtual elements (macOS / Cocoa only) @@ -228,7 +228,7 @@ index a0598a73c2..3d8a5dd0fc 100644 write section at the end needs synchronization to protect against concurrent reads from AX server thread. */ eassert ([NSThread isMainThread]); -@@ -8005,24 +8149,15 @@ - (void)ensureTextCache +@@ -8005,25 +8149,34 @@ - (void)ensureTextCache if (!b) return; @@ -247,19 +247,62 @@ index a0598a73c2..3d8a5dd0fc 100644 - explicit announcements in postAccessibilityNotificationsForFrame). - Including overlay_modiff would silently update cachedOverlayModiff - and prevent the notification dispatch from detecting changes. */ - ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b); +- ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b); ++ /* Use BUF_MODIFF, not BUF_CHARS_MODIFF, for cache validity. ++ ++ Fold/unfold commands (org-mode, outline-mode, hideshow-mode) change ++ text visibility by modifying the 'invisible text property via ++ `put-text-property' or `add-text-properties'. These bump BUF_MODIFF ++ but NOT BUF_CHARS_MODIFF, because no characters are inserted or ++ deleted. Using only BUF_CHARS_MODIFF would serve stale AX text ++ across fold/unfold: VoiceOver would continue reading hidden content ++ as if it were visible, or miss newly revealed content entirely. ++ ++ BUF_MODIFF is bumped by all buffer modifications including ++ text-property changes (e.g. font-lock face assignments), causing a ++ full text-cache rebuild on each redisplay cycle. This is acceptable ++ because `ensureTextCache' is only called when VoiceOver queries ++ accessibilityValue or related AX properties --- which happens at ++ human interaction speed, not at redisplay speed. The per-rebuild ++ cost is O(visible-buffer-text). ++ ++ Do NOT use BUF_OVERLAY_MODIFF alone: org-mode >= 29 (org-fold-core) ++ uses text properties, not overlays, for folding, so ++ BUF_OVERLAY_MODIFF would miss those changes. Additionally, modes ++ like hl-line-mode bump BUF_OVERLAY_MODIFF on every ++ post-command-hook, yielding the same per-keystroke rebuild cost as ++ BUF_MODIFF, with none of its correctness guarantee. */ ++ ptrdiff_t modiff = BUF_MODIFF (b); ptrdiff_t pt = BUF_PT (b); NSUInteger textLen = cachedText ? [cachedText length] : 0; -+ /* Cache validity: track BUF_MODIFF and buffer narrowing. -+ Do NOT track BUF_OVERLAY_MODIFF here --- overlay text is not -+ included in the cached AX text (it is handled separately via -+ explicit announcements). Including overlay_modiff would -+ silently update cachedOverlayModiff and prevent the -+ notification dispatch from detecting overlay changes. */ - if (cachedText && cachedTextModiff == chars_modiff +- if (cachedText && cachedTextModiff == chars_modiff ++ if (cachedText && cachedTextModiff == modiff && cachedTextStart == BUF_BEGV (b) && pt >= cachedTextStart -@@ -8108,7 +8243,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos + && (textLen == 0 +@@ -8039,7 +8192,7 @@ included in the cached AX text (it is handled separately via + { + [cachedText release]; + cachedText = [text retain]; +- cachedTextModiff = chars_modiff; ++ cachedTextModiff = modiff; + cachedTextStart = start; + + if (visibleRuns) +@@ -8051,9 +8204,9 @@ included in the cached AX text (it is handled separately via + Walk the cached text once, recording the start offset of each + line. Uses NSString lineRangeForRange: --- O(N) in the total + text --- but this loop runs only on cache rebuild, which is +- gated on BUF_CHARS_MODIFF: actual character insertions or +- deletions. Font-lock (text property changes) does not trigger +- a rebuild, so the hot path (cursor movement, redisplay) never ++ gated on BUF_MODIFF changes. Rebuilds happen when any buffer ++ modification occurs (including fold/unfold), ensuring the line ++ index always matches the currently visible text. + enters this code. */ + if (lineStartOffsets) + xfree (lineStartOffsets); +@@ -8108,7 +8261,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos /* Binary search: runs are sorted by charpos (ascending). Find the run whose [charpos, charpos+length) range contains the target, or the nearest run after an invisible gap. O(log n) instead of @@ -268,7 +311,7 @@ index a0598a73c2..3d8a5dd0fc 100644 NSUInteger lo = 0, hi = visibleRunCount; while (lo < hi) { -@@ -8157,10 +8292,10 @@ by run length (visible window), not total buffer size. */ +@@ -8157,10 +8310,10 @@ by run length (visible window), not total buffer size. */ /* Convert accessibility string index to buffer charpos. Safe to call from any thread: uses only cachedText (NSString) and @@ -281,7 +324,7 @@ index a0598a73c2..3d8a5dd0fc 100644 @synchronized (self) { if (visibleRunCount == 0) -@@ -8202,7 +8337,7 @@ the slow path (composed character sequence walk), which is +@@ -8202,7 +8355,7 @@ the slow path (composed character sequence walk), which is return cp; } } @@ -290,7 +333,7 @@ index a0598a73c2..3d8a5dd0fc 100644 if (lo > 0) { ns_ax_visible_run *last = &visibleRuns[visibleRunCount - 1]; -@@ -8224,7 +8359,7 @@ the slow path (composed character sequence walk), which is +@@ -8224,7 +8377,7 @@ the slow path (composed character sequence walk), which is deadlocking the AX server thread. This is prevented by: 1. validWindow checks WINDOW_LIVE_P and BUFFERP before every @@ -299,7 +342,7 @@ index a0598a73c2..3d8a5dd0fc 100644 2. All dispatch_sync blocks run on the main thread where no concurrent Lisp code can modify state between checks. 3. block_input prevents timer events and process output from -@@ -8570,6 +8705,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber +@@ -8570,6 +8723,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber return [self lineForAXIndex:point_idx]; } @@ -350,7 +393,7 @@ index a0598a73c2..3d8a5dd0fc 100644 - (NSRange)accessibilityRangeForLine:(NSInteger)line { if (![NSThread isMainThread]) -@@ -8792,7 +8971,7 @@ - (NSRect)accessibilityFrame +@@ -8792,7 +8989,7 @@ - (NSRect)accessibilityFrame /* =================================================================== @@ -359,7 +402,7 @@ index a0598a73c2..3d8a5dd0fc 100644 These methods notify VoiceOver of text and selection changes. Called from the redisplay cycle (postAccessibilityUpdates). -@@ -8807,7 +8986,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point +@@ -8807,7 +9004,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point if (point > self.cachedPoint && point - self.cachedPoint == 1) { @@ -368,7 +411,7 @@ index a0598a73c2..3d8a5dd0fc 100644 [self invalidateTextCache]; [self ensureTextCache]; if (cachedText) -@@ -8826,7 +9005,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point +@@ -8826,7 +9023,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point /* Update cachedPoint here so the selection-move branch does NOT fire for point changes caused by edits. WebKit and Chromium never send both ValueChanged and SelectedTextChanged for the @@ -377,7 +420,7 @@ index a0598a73c2..3d8a5dd0fc 100644 self.cachedPoint = point; NSDictionary *change = @{ -@@ -9220,16 +9399,83 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f +@@ -9220,16 +9417,83 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f BOOL markActive = !NILP (BVAR (b, mark_active)); /* --- Text changed (edit) --- */ @@ -465,7 +508,7 @@ index a0598a73c2..3d8a5dd0fc 100644 { ptrdiff_t oldPoint = self.cachedPoint; BOOL oldMarkActive = self.cachedMarkActive; -@@ -12402,7 +12648,7 @@ - (int) fullscreenState +@@ -12402,7 +12666,7 @@ - (int) fullscreenState if (WINDOW_LEAF_P (w)) { @@ -474,7 +517,7 @@ index a0598a73c2..3d8a5dd0fc 100644 EmacsAccessibilityBuffer *elem = [existing objectForKey:[NSValue valueWithPointer:w]]; if (!elem) -@@ -12436,7 +12682,7 @@ - (int) fullscreenState +@@ -12436,7 +12700,7 @@ - (int) fullscreenState } else { @@ -483,7 +526,7 @@ index a0598a73c2..3d8a5dd0fc 100644 Lisp_Object child = w->contents; while (!NILP (child)) { -@@ -12548,7 +12794,7 @@ - (void)postAccessibilityUpdates +@@ -12548,7 +12812,7 @@ - (void)postAccessibilityUpdates accessibilityUpdating = YES; /* Detect window tree change (split, delete, new buffer). Compare @@ -492,7 +535,7 @@ index a0598a73c2..3d8a5dd0fc 100644 Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe); if (!EQ (curRoot, lastRootWindow)) { -@@ -12557,12 +12803,12 @@ - (void)postAccessibilityUpdates +@@ -12557,12 +12821,12 @@ - (void)postAccessibilityUpdates } /* If tree is stale, rebuild FIRST so we don't iterate freed diff --git a/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch b/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch index 90212b9..c154c2d 100644 --- a/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch +++ b/patches/0008-ns-announce-child-frame-completion-candidates-for-Vo.patch @@ -1,4 +1,4 @@ -From 33333f637c51c1ee2080c780fd623e67d3a85545 Mon Sep 17 00:00:00 2001 +From f26d6d8d2a9030af3296902b4e3db79fef3ed760 Mon Sep 17 00:00:00 2001 From: Daneel Date: Mon, 2 Mar 2026 18:49:13 +0100 Subject: [PATCH 8/8] ns: announce child frame completion candidates for @@ -33,8 +33,8 @@ area announcements. doc/emacs/macos.texi | 14 +- etc/NEWS | 18 +- src/nsterm.h | 20 ++ - src/nsterm.m | 456 +++++++++++++++++++++++++++++++++++++++---- - 4 files changed, 460 insertions(+), 48 deletions(-) + src/nsterm.m | 436 ++++++++++++++++++++++++++++++++++++++++--- + 4 files changed, 446 insertions(+), 42 deletions(-) diff --git a/doc/emacs/macos.texi b/doc/emacs/macos.texi index 8d4a7825d8..03a657f970 100644 @@ -149,7 +149,7 @@ index 21a93bc799..bdd40b8eb7 100644 @end diff --git a/src/nsterm.m b/src/nsterm.m -index 3d8a5dd0fc..7555ae3e95 100644 +index 8f744d1bf3..b434a7fd41 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1126,24 +1126,19 @@ Uses CFAbsoluteTimeGetCurrent() (~5 ns, a VDSO read) for timing. */ @@ -300,37 +300,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 /* Build accessibility text for window W, skipping invisible text. Populates *OUT_START with the buffer start charpos. Populates *OUT_RUNS with an array of visible runs and *OUT_NRUNS -@@ -8149,15 +8250,23 @@ - (void)ensureTextCache - if (!b) - return; - -+ /* Use BUF_CHARS_MODIFF, not BUF_MODIFF, for cache validity. -+ BUF_MODIFF is bumped by every text-property change, including -+ font-lock face applications on every redisplay. AX text contains -+ only characters, not face data, so property-only changes do not -+ affect the cached value. Rebuilding the full buffer text on -+ each font-lock pass is O(buffer-size) per redisplay --- this -+ causes progressive slowdown when scrolling through large files. -+ BUF_CHARS_MODIFF is bumped only on actual character insertions -+ and deletions, matching the semantic of "did the text change". -+ This is the pattern used by WebKit and NSTextView. -+ Do NOT add BUF_OVERLAY_MODIFF here: modes like hl-line-mode move -+ overlays on every post-command-hook, bumping BUF_OVERLAY_MODIFF and -+ causing O(buffer-size) text rebuilds per keystroke. Fold/unfold -+ changes visible characters and thereby bumps BUF_CHARS_MODIFF. */ - ptrdiff_t chars_modiff = BUF_CHARS_MODIFF (b); - ptrdiff_t pt = BUF_PT (b); - NSUInteger textLen = cachedText ? [cachedText length] : 0; -- /* Cache validity: track BUF_MODIFF and buffer narrowing. -- Do NOT track BUF_OVERLAY_MODIFF here --- overlay text is not -- included in the cached AX text (it is handled separately via -- explicit announcements). Including overlay_modiff would -- silently update cachedOverlayModiff and prevent the -- notification dispatch from detecting overlay changes. */ - if (cachedText && cachedTextModiff == chars_modiff - && cachedTextStart == BUF_BEGV (b) - && pt >= cachedTextStart -@@ -8587,6 +8696,11 @@ - (void)setAccessibilitySelectedTextRange:(NSRange)range +@@ -8605,6 +8706,11 @@ - (void)setAccessibilitySelectedTextRange:(NSRange)range [self ensureTextCache]; @@ -342,7 +312,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 specpdl_ref count = SPECPDL_INDEX (); record_unwind_current_buffer (); /* Ensure block_input is always matched by unblock_input even if -@@ -9042,15 +9156,23 @@ - (void)postFocusedCursorNotification:(ptrdiff_t)point +@@ -9060,15 +9166,23 @@ - (void)postFocusedCursorNotification:(ptrdiff_t)point = @(ns_ax_text_state_change_selection_move); moveInfo[@"AXTextSelectionDirection"] = @(direction); moveInfo[@"AXTextChangeElement"] = self; @@ -372,7 +342,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 NSAccessibilitySelectedTextChangedNotification, moveInfo); -@@ -9148,12 +9270,17 @@ user expectation ("w" jumps to next word and reads it). */ +@@ -9166,12 +9280,17 @@ user expectation ("w" jumps to next word and reads it). */ } } @@ -395,7 +365,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 if (cachedText && granularity == ns_ax_text_selection_granularity_line) { -@@ -9218,6 +9345,11 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b +@@ -9236,6 +9355,11 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b block_input (); specpdl_ref count2 = SPECPDL_INDEX (); @@ -407,7 +377,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 record_unwind_protect_void (unblock_input); record_unwind_current_buffer (); if (b != current_buffer) -@@ -9394,12 +9526,29 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f +@@ -9412,12 +9536,29 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f if (!b) return; @@ -437,7 +407,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 if (modiff != self.cachedModiff) { self.cachedModiff = modiff; -@@ -9413,6 +9562,7 @@ Text property changes (e.g. face updates from +@@ -9431,6 +9572,7 @@ Text property changes (e.g. face updates from { self.cachedCharsModiff = chars_modiff; [self postTextChangedNotification:point]; @@ -445,7 +415,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 } } -@@ -9435,8 +9585,15 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9453,8 +9595,15 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property displayed in the minibuffer. In normal editing buffers, font-lock and other modes change BUF_OVERLAY_MODIFF on every redisplay, triggering O(overlays) work per keystroke. @@ -463,7 +433,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 goto skip_overlay_scan; int selected_line = -1; -@@ -9482,7 +9639,18 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9500,7 +9649,18 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property self.cachedPoint = point; self.cachedMarkActive = markActive; @@ -483,7 +453,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 NSInteger direction = ns_ax_text_selection_direction_discontiguous; if (point > oldPoint) direction = ns_ax_text_selection_direction_next; -@@ -9716,6 +9884,13 @@ - (NSRect)accessibilityFrame +@@ -9734,6 +9894,13 @@ - (NSRect)accessibilityFrame if (vis_start >= vis_end) return @[]; @@ -497,7 +467,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 block_input (); specpdl_ref blk_count = SPECPDL_INDEX (); record_unwind_protect_void (unblock_input); -@@ -9840,6 +10015,7 @@ than O(chars). Fall back to pos+1 as safety net. */ +@@ -9858,6 +10025,7 @@ than O(chars). Fall back to pos+1 as safety net. */ pos = span_end; } @@ -505,7 +475,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 return [[spans copy] autorelease]; } -@@ -10021,6 +10197,10 @@ - (void)dealloc +@@ -10039,6 +10207,10 @@ - (void)dealloc #endif [accessibilityElements release]; @@ -516,7 +486,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 [[self menu] release]; [super dealloc]; } -@@ -11470,6 +11650,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f +@@ -11488,6 +11660,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f windowClosing = NO; processingCompose = NO; @@ -526,7 +496,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 scrollbarsNeedingUpdate = 0; fs_state = FULLSCREEN_NONE; fs_before_fs = next_maximized = -1; -@@ -12778,6 +12961,154 @@ - (id)accessibilityFocusedUIElement +@@ -12796,6 +12971,154 @@ - (id)accessibilityFocusedUIElement The existing elements carry cached state (modiff, point) from the previous redisplay cycle. Rebuilding first would create fresh elements with current values, making change detection impossible. */ @@ -681,7 +651,7 @@ index 3d8a5dd0fc..7555ae3e95 100644 - (void)postAccessibilityUpdates { NSTRACE ("[EmacsView postAccessibilityUpdates]"); -@@ -12788,11 +13119,64 @@ - (void)postAccessibilityUpdates +@@ -12806,11 +13129,64 @@ - (void)postAccessibilityUpdates /* Re-entrance guard: VoiceOver callbacks during notification posting can trigger redisplay, which calls ns_update_end, which calls us