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 3680f62..be5bfe9 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 0ef896396709b9b0a832d07476dfc7ded2eca9fc Mon Sep 17 00:00:00 2001 +From e27ae42313eb5cb5cab14de348f83db216a17a53 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 294ee64..bf127a2 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 195c2d4ccc1d607984468fa7f9a8e41005463f04 Mon Sep 17 00:00:00 2001 +From 9650910e7ac6e423ea9beaa75033d12693b93c89 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 6cdd3c5..57200b2 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 96ab29ec0bd830c6ba81632c8ccfedb4fdec85d2 Mon Sep 17 00:00:00 2001 +From 9ac52a3f3e57628bd06516bc439b8ec388207098 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 36746f8..e004b27 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 23f2a62922e7fe9a4075b5e2074bde292434f882 Mon Sep 17 00:00:00 2001 +From 361aecfc858d712943921435454d9a7235d145ed 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 0981609..5d3c78a 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 04edba6e94622176c9869ba2564cd4fda4d2edd8 Mon Sep 17 00:00:00 2001 +From a0ea23e5b05e7ab6048d6dd3e9e05aae00dc6939 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 bfb6c9e..307626f 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 c3afdca23634547cb961efd8368e09393ade2690 Mon Sep 17 00:00:00 2001 +From ca511140b95caf299ab1b24b7a22de03a2e5b543 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 6b0370a..704314c 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 312ef33147100f5486aa42b70d44ee9e143fd6ce Mon Sep 17 00:00:00 2001 +From 2cfc623598b666515fe3cf05ee8c578601e0e587 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 8509c1a..b199aed 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 a264f3ec7acb0f736e79bd692bd79c11b0f16c2e Mon Sep 17 00:00:00 2001 +From 239d804cf216a05a2b62aeeda7ab2cc5795c158b 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 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 59e2adf..8a4144b 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 089ff332d52b9595e774b654a9259c65450cdaa2 Mon Sep 17 00:00:00 2001 +From 235fb607dfe06a242044218a2ed0ea82fed4f82f 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 | 493 ++++++++++++++++++++++++++++++++++++++----- - 4 files changed, 475 insertions(+), 70 deletions(-) + src/nsterm.m | 504 +++++++++++++++++++++++++++++++++++++------ + 4 files changed, 482 insertions(+), 74 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 8f744d1bf3..20a50281db 100644 +index 8f744d1bf3..1f3b2ad78a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1126,24 +1126,19 @@ Uses CFAbsoluteTimeGetCurrent() (~5 ns, a VDSO read) for timing. */ @@ -339,29 +339,43 @@ index 8f744d1bf3..20a50281db 100644 specpdl_ref count = SPECPDL_INDEX (); record_unwind_current_buffer (); /* Ensure block_input is always matched by unblock_input even if -@@ -9060,15 +9166,23 @@ - (void)postFocusedCursorNotification:(ptrdiff_t)point +@@ -9053,22 +9159,33 @@ - (void)postFocusedCursorNotification:(ptrdiff_t)point + && granularity + == ns_ax_text_selection_granularity_character); + +- /* Always post SelectedTextChanged to interrupt VoiceOver reading +- and update cursor tracking / braille displays. */ ++ /* Post SelectedTextChanged to interrupt VoiceOver reading and ++ update cursor tracking / braille displays. ++ For sequential moves (direction = next/previous): include ++ direction + granularity so VoiceOver reads the destination line ++ or word without additional state queries. ++ For discontiguous jumps (teleports, multi-line leaps): omit ++ direction and granularity and let VoiceOver determine what to read ++ from its own navigation state. This matches the pre-review ++ behaviour and ensures VoiceOver reads the full destination line ++ even when the jump skips blank or invisible lines (e.g. org-agenda ++ items separated by blank lines, where adjacency detection cannot ++ classify the move as singleLineMove). */ + NSMutableDictionary *moveInfo = [NSMutableDictionary dictionary]; + moveInfo[@"AXTextStateChangeType"] = @(ns_ax_text_state_change_selection_move); - moveInfo[@"AXTextSelectionDirection"] = @(direction); +- moveInfo[@"AXTextSelectionDirection"] = @(direction); moveInfo[@"AXTextChangeElement"] = self; - /* Omit granularity for character moves so VoiceOver does not - derive its own speech (it would read the wrong character - for block-cursor mode). Include it for word/line/ - selection so VoiceOver reads the appropriate text. */ - if (!isCharMove) -+ /* Include granularity for sequential moves so VoiceOver reads the -+ appropriate unit. Omit for character moves (announced explicitly -+ below) and for discontiguous jumps (destination line announced -+ explicitly; omitting granularity lets VoiceOver use its default -+ behaviour and re-anchor its browse cursor). */ -+ if (!isCharMove -+ && direction != ns_ax_text_selection_direction_discontiguous) - moveInfo[@"AXTextSelectionGranularity"] = @(granularity); +- moveInfo[@"AXTextSelectionGranularity"] = @(granularity); ++ BOOL isDiscontiguous ++ = (direction == ns_ax_text_selection_direction_discontiguous); ++ if (!isDiscontiguous && !isCharMove) ++ { ++ moveInfo[@"AXTextSelectionDirection"] = @(direction); ++ moveInfo[@"AXTextSelectionGranularity"] = @(granularity); ++ } -+ /* Post SelectedTextChanged from the parent EmacsView (an NSView) -+ rather than from self (a custom NSObject element). VoiceOver -+ processes text-change notifications more reliably from view-based -+ elements. Include UIElementsKey so VoiceOver knows which child -+ element's selectedTextRange to re-query. */ + moveInfo[NSAccessibilityUIElementsKey] = @[self]; ns_ax_post_notification_with_info ( - self, @@ -369,7 +383,7 @@ index 8f744d1bf3..20a50281db 100644 NSAccessibilitySelectedTextChangedNotification, moveInfo); -@@ -9166,12 +9280,17 @@ user expectation ("w" jumps to next word and reads it). */ +@@ -9166,12 +9283,17 @@ user expectation ("w" jumps to next word and reads it). */ } } @@ -392,7 +406,7 @@ index 8f744d1bf3..20a50281db 100644 if (cachedText && granularity == ns_ax_text_selection_granularity_line) { -@@ -9236,6 +9355,11 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b +@@ -9236,6 +9358,11 @@ - (void)postCompletionAnnouncementForBuffer:(struct buffer *)b block_input (); specpdl_ref count2 = SPECPDL_INDEX (); @@ -404,7 +418,7 @@ index 8f744d1bf3..20a50281db 100644 record_unwind_protect_void (unblock_input); record_unwind_current_buffer (); if (b != current_buffer) -@@ -9412,12 +9536,29 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f +@@ -9412,12 +9539,29 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f if (!b) return; @@ -434,7 +448,7 @@ index 8f744d1bf3..20a50281db 100644 if (modiff != self.cachedModiff) { self.cachedModiff = modiff; -@@ -9431,6 +9572,7 @@ Text property changes (e.g. face updates from +@@ -9431,6 +9575,7 @@ Text property changes (e.g. face updates from { self.cachedCharsModiff = chars_modiff; [self postTextChangedNotification:point]; @@ -442,7 +456,7 @@ index 8f744d1bf3..20a50281db 100644 } } -@@ -9453,8 +9595,15 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9453,8 +9598,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. @@ -460,7 +474,7 @@ index 8f744d1bf3..20a50281db 100644 goto skip_overlay_scan; int selected_line = -1; -@@ -9500,7 +9649,18 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9500,7 +9652,18 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property self.cachedPoint = point; self.cachedMarkActive = markActive; @@ -480,7 +494,7 @@ index 8f744d1bf3..20a50281db 100644 NSInteger direction = ns_ax_text_selection_direction_discontiguous; if (point > oldPoint) direction = ns_ax_text_selection_direction_next; -@@ -9512,6 +9672,7 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9512,6 +9675,7 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property /* --- Granularity detection --- */ NSInteger granularity = ns_ax_text_selection_granularity_unknown; @@ -488,7 +502,7 @@ index 8f744d1bf3..20a50281db 100644 [self ensureTextCache]; if (cachedText && oldPoint > 0) { -@@ -9526,7 +9687,18 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9526,7 +9690,18 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property NSRange newLine = [cachedText lineRangeForRange: NSMakeRange (newIdx, 0)]; if (oldLine.location != newLine.location) @@ -508,7 +522,7 @@ index 8f744d1bf3..20a50281db 100644 else { NSUInteger dist = (newIdx > oldIdx -@@ -9548,34 +9720,23 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property +@@ -9548,34 +9723,23 @@ frameworks like Vertico bump BOTH BUF_MODIFF (via text property granularity = ns_ax_text_selection_granularity_line; } @@ -556,7 +570,7 @@ index 8f744d1bf3..20a50281db 100644 { NSWindow *win = [self.emacsView window]; if (win) -@@ -9734,6 +9895,13 @@ - (NSRect)accessibilityFrame +@@ -9734,6 +9898,13 @@ - (NSRect)accessibilityFrame if (vis_start >= vis_end) return @[]; @@ -570,7 +584,7 @@ index 8f744d1bf3..20a50281db 100644 block_input (); specpdl_ref blk_count = SPECPDL_INDEX (); record_unwind_protect_void (unblock_input); -@@ -9858,6 +10026,7 @@ than O(chars). Fall back to pos+1 as safety net. */ +@@ -9858,6 +10029,7 @@ than O(chars). Fall back to pos+1 as safety net. */ pos = span_end; } @@ -578,7 +592,7 @@ index 8f744d1bf3..20a50281db 100644 return [[spans copy] autorelease]; } -@@ -10039,6 +10208,10 @@ - (void)dealloc +@@ -10039,6 +10211,10 @@ - (void)dealloc #endif [accessibilityElements release]; @@ -589,7 +603,7 @@ index 8f744d1bf3..20a50281db 100644 [[self menu] release]; [super dealloc]; } -@@ -11488,6 +11661,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f +@@ -11488,6 +11664,9 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f windowClosing = NO; processingCompose = NO; @@ -599,7 +613,7 @@ index 8f744d1bf3..20a50281db 100644 scrollbarsNeedingUpdate = 0; fs_state = FULLSCREEN_NONE; fs_before_fs = next_maximized = -1; -@@ -12796,6 +12972,154 @@ - (id)accessibilityFocusedUIElement +@@ -12796,6 +12975,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. */ @@ -754,7 +768,7 @@ index 8f744d1bf3..20a50281db 100644 - (void)postAccessibilityUpdates { NSTRACE ("[EmacsView postAccessibilityUpdates]"); -@@ -12806,11 +13130,64 @@ - (void)postAccessibilityUpdates +@@ -12806,11 +13133,64 @@ - (void)postAccessibilityUpdates /* Re-entrance guard: VoiceOver callbacks during notification posting can trigger redisplay, which calls ns_update_end, which calls us