patches: add Zoom completion tracking (overlay + child frame)
Zoom patch 0000 now tracks completion candidates: - Overlay: Vertico, Icomplete, Ivy (face heuristic on before-string) - Child frame: Corfu, Company-box (scan buffer text for selected face) Also fixes duplicate lastCursorRect ivar when applied with VoiceOver.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
From 8a45d478b23b3bc2a1ae039493ba90b07eb89c72 Mon Sep 17 00:00:00 2001
|
||||
From 45076d26a15ae82b489349d481f3c1a1792730a5 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 22:39:35 +0100
|
||||
Subject: [PATCH 1/9] ns: integrate with macOS Zoom for cursor tracking
|
||||
@@ -6,32 +6,46 @@ Subject: [PATCH 1/9] ns: integrate with macOS Zoom for cursor tracking
|
||||
Inform macOS Zoom of the text cursor position so the zoomed viewport
|
||||
follows keyboard focus in Emacs.
|
||||
|
||||
Basic cursor tracking:
|
||||
* src/nsterm.h (EmacsView): Add lastCursorRect, zoomCursorUpdated.
|
||||
* src/nsterm.m (ns_draw_window_cursor): Store cursor rect in
|
||||
lastCursorRect; call UAZoomChangeFocus with CG-space coordinates
|
||||
when UAZoomEnabled returns true. Set zoomCursorUpdated flag.
|
||||
(ns_update_end): Call UAZoomChangeFocus as fallback when cursor
|
||||
was not physically redrawn in this cycle (e.g., after C-x o window
|
||||
switch). Gated by zoomCursorUpdated to avoid double calls.
|
||||
was not physically redrawn (e.g. after C-x o window switch).
|
||||
Gated by zoomCursorUpdated to avoid double calls.
|
||||
|
||||
Completion candidate tracking:
|
||||
* src/nsterm.m (ns_zoom_face_is_selected): New predicate.
|
||||
Match 'current', 'selected', and 'selection' in face symbol
|
||||
names to identify the highlighted completion candidate.
|
||||
(ns_zoom_find_overlay_candidate_line): Scan overlay
|
||||
before-string/after-string for the selected candidate line.
|
||||
Handles Vertico, Icomplete, Ivy, and similar overlay frameworks.
|
||||
(ns_zoom_find_child_frame_candidate): Scan child frame buffer
|
||||
text for the selected candidate. Handles Corfu, Company-box,
|
||||
and similar child frame frameworks.
|
||||
(ns_zoom_track_completion): Called from ns_update_end after
|
||||
cursor tracking. Overrides Zoom focus to the selected
|
||||
completion candidate when one is found.
|
||||
|
||||
Coordinate conversion: EmacsView pixels (AppKit, flipped) ->
|
||||
NSWindow -> NSScreen -> CGRect with y-flip for CoreGraphics
|
||||
top-left origin. UAZoomEnabled returns false when Zoom is inactive,
|
||||
so overhead is a single function call per redisplay cycle.
|
||||
top-left origin.
|
||||
|
||||
Tested on macOS 14 with Zoom enabled: cursor tracking works across
|
||||
window splits, switches (C-x o), and normal navigation.
|
||||
window splits, switches (C-x o), and completion frameworks.
|
||||
---
|
||||
etc/NEWS | 8 +++++++
|
||||
src/nsterm.h | 6 +++++
|
||||
src/nsterm.m | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 82 insertions(+)
|
||||
etc/NEWS | 11 ++
|
||||
src/nsterm.h | 6 ++
|
||||
src/nsterm.m | 285 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 302 insertions(+)
|
||||
|
||||
diff --git a/etc/NEWS b/etc/NEWS
|
||||
index ef36df5..f10d17e 100644
|
||||
index ef36df5..80661a9 100644
|
||||
--- a/etc/NEWS
|
||||
+++ b/etc/NEWS
|
||||
@@ -82,6 +82,14 @@ other directory on your system. You can also invoke the
|
||||
@@ -82,6 +82,17 @@ other directory on your system. You can also invoke the
|
||||
|
||||
* Changes in Emacs 31.1
|
||||
|
||||
@@ -41,7 +55,10 @@ index ef36df5..f10d17e 100644
|
||||
+Follow keyboard focus), Emacs informs Zoom of the text cursor position
|
||||
+after every cursor redraw via 'UAZoomChangeFocus'. The zoomed viewport
|
||||
+automatically tracks the insertion point across window splits and
|
||||
+switches.
|
||||
+switches. Completion frameworks (Vertico, Icomplete, Ivy for overlay
|
||||
+candidates; Corfu, Company-box for child frame popups) are also
|
||||
+tracked: Zoom follows the selected candidate rather than the text
|
||||
+cursor during completion.
|
||||
+
|
||||
+++
|
||||
** 'line-spacing' now supports specifying spacing above the line.
|
||||
@@ -64,10 +81,228 @@ index 7c1ee4c..ea6e7ba 100644
|
||||
}
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 74e4ad5..cd721c8 100644
|
||||
index 74e4ad5..05ec3d1 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -1104,6 +1104,35 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
|
||||
@@ -1081,6 +1081,217 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
|
||||
}
|
||||
|
||||
|
||||
+
|
||||
+#ifdef NS_IMPL_COCOA
|
||||
+#if defined (MAC_OS_X_VERSION_MIN_REQUIRED) \
|
||||
+ && MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
||||
+
|
||||
+/* Check whether FACE (a Lisp symbol or list) has a name suggesting
|
||||
+ it marks the currently selected completion candidate. Matches
|
||||
+ vertico-current, icomplete-selected-match, ivy-current-match,
|
||||
+ company-tooltip-selection, corfu-current, and similar. */
|
||||
+static bool
|
||||
+ns_zoom_face_is_selected (Lisp_Object face)
|
||||
+{
|
||||
+ if (SYMBOLP (face) && !NILP (face))
|
||||
+ {
|
||||
+ const char *name = SSDATA (SYMBOL_NAME (face));
|
||||
+ if (strstr (name, "current")
|
||||
+ || strstr (name, "selected")
|
||||
+ || strstr (name, "selection"))
|
||||
+ return true;
|
||||
+ }
|
||||
+ /* Handle face list (face1 face2 ...). */
|
||||
+ if (CONSP (face))
|
||||
+ {
|
||||
+ Lisp_Object tail;
|
||||
+ for (tail = face; CONSP (tail); tail = XCDR (tail))
|
||||
+ if (ns_zoom_face_is_selected (XCAR (tail)))
|
||||
+ return true;
|
||||
+ }
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+/* Scan overlay before-string / after-string properties in the
|
||||
+ selected window for a completion candidate with a "selected"
|
||||
+ face. Return the 0-based visual line index of the selected
|
||||
+ candidate, or -1 if none found. */
|
||||
+static int
|
||||
+ns_zoom_find_overlay_candidate_line (struct window *w)
|
||||
+{
|
||||
+ struct buffer *b = XBUFFER (w->contents);
|
||||
+ ptrdiff_t beg = marker_position (w->start);
|
||||
+ ptrdiff_t end = ZV_S (b);
|
||||
+ Lisp_Object overlays = Foverlays_in (make_fixnum (beg),
|
||||
+ make_fixnum (end));
|
||||
+ Lisp_Object tail;
|
||||
+
|
||||
+ for (tail = overlays; CONSP (tail); tail = XCDR (tail))
|
||||
+ {
|
||||
+ Lisp_Object ov = XCAR (tail);
|
||||
+ Lisp_Object str = Foverlay_get (ov, Qbefore_string);
|
||||
+
|
||||
+ if (NILP (str))
|
||||
+ str = Foverlay_get (ov, Qafter_string);
|
||||
+ if (!STRINGP (str) || SCHARS (str) < 2)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Walk the string line by line, checking faces. */
|
||||
+ ptrdiff_t len = SCHARS (str);
|
||||
+ int line = 0;
|
||||
+ ptrdiff_t line_start = 0;
|
||||
+
|
||||
+ for (ptrdiff_t i = 0; i <= len; i++)
|
||||
+ {
|
||||
+ bool at_newline = (i == len
|
||||
+ || SREF (str, i) == '\n');
|
||||
+ if (at_newline && i > line_start)
|
||||
+ {
|
||||
+ /* Check the face at line_start. */
|
||||
+ Lisp_Object face
|
||||
+ = Fget_text_property (make_fixnum (line_start),
|
||||
+ Qface, str);
|
||||
+ if (ns_zoom_face_is_selected (face))
|
||||
+ return line;
|
||||
+ line++;
|
||||
+ line_start = i + 1;
|
||||
+ }
|
||||
+ else if (at_newline)
|
||||
+ {
|
||||
+ line++;
|
||||
+ line_start = i + 1;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+/* Scan child frames for a completion popup with a selected
|
||||
+ candidate. Return the 0-based line index, or -1 if none.
|
||||
+ Set *CHILD_FRAME to the child frame if found. */
|
||||
+static int
|
||||
+ns_zoom_find_child_frame_candidate (struct frame *f,
|
||||
+ struct frame **child_frame)
|
||||
+{
|
||||
+ Lisp_Object frames, tail;
|
||||
+
|
||||
+ FOR_EACH_FRAME (tail, frames)
|
||||
+ {
|
||||
+ struct frame *cf = XFRAME (frames);
|
||||
+ if (!FRAME_NS_P (cf) || !FRAME_LIVE_P (cf))
|
||||
+ continue;
|
||||
+ if (FRAME_PARENT_FRAME (cf) != f)
|
||||
+ continue;
|
||||
+ /* Small buffer = likely completion popup. */
|
||||
+ struct buffer *b = XBUFFER (cf->current_buffer);
|
||||
+ if (BUF_ZV (b) - BUF_BEGV (b) > 10000)
|
||||
+ continue;
|
||||
+
|
||||
+ ptrdiff_t beg = BUF_BEGV (b);
|
||||
+ ptrdiff_t zv = BUF_ZV (b);
|
||||
+ int line = 0;
|
||||
+
|
||||
+ ptrdiff_t pos = beg;
|
||||
+ while (pos < zv)
|
||||
+ {
|
||||
+ Lisp_Object face
|
||||
+ = Fget_char_property (make_fixnum (pos), Qface,
|
||||
+ cf->current_buffer);
|
||||
+ if (ns_zoom_face_is_selected (face))
|
||||
+ {
|
||||
+ *child_frame = cf;
|
||||
+ return line;
|
||||
+ }
|
||||
+ /* Advance to next line. */
|
||||
+ ptrdiff_t next = find_newline (pos, -1, zv, -1,
|
||||
+ 1, NULL, NULL, false);
|
||||
+ if (next <= pos)
|
||||
+ break;
|
||||
+ pos = next;
|
||||
+ line++;
|
||||
+ }
|
||||
+ }
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+/* Update Zoom focus based on completion candidates.
|
||||
+ Called from ns_update_end after normal cursor tracking.
|
||||
+ If a completion candidate is selected (overlay or child frame),
|
||||
+ move Zoom to that candidate instead of the text cursor. */
|
||||
+static void
|
||||
+ns_zoom_track_completion (struct frame *f, EmacsView *view)
|
||||
+{
|
||||
+ if (!UAZoomEnabled ())
|
||||
+ return;
|
||||
+
|
||||
+ struct window *w = XWINDOW (f->selected_window);
|
||||
+ int line_h = FRAME_LINE_HEIGHT (f);
|
||||
+
|
||||
+ /* 1. Check overlay completions (Vertico, Icomplete, Ivy). */
|
||||
+ int ov_line = ns_zoom_find_overlay_candidate_line (w);
|
||||
+ if (ov_line >= 0)
|
||||
+ {
|
||||
+ /* Overlay candidates typically start after the input line,
|
||||
+ so the visual offset is (ov_line + 1) * line_h from
|
||||
+ the window top. */
|
||||
+ int y_off = (ov_line + 1) * line_h;
|
||||
+ if (y_off < w->pixel_height)
|
||||
+ {
|
||||
+ NSRect r = NSMakeRect (
|
||||
+ WINDOW_TEXT_TO_FRAME_PIXEL_X (w, 0),
|
||||
+ WINDOW_TO_FRAME_PIXEL_Y (w, y_off),
|
||||
+ FRAME_COLUMN_WIDTH (f),
|
||||
+ line_h);
|
||||
+
|
||||
+ NSRect windowRect = [view convertRect:r toView:nil];
|
||||
+ NSRect screenRect
|
||||
+ = [[view window] convertRectToScreen:windowRect];
|
||||
+ CGRect cgRect = NSRectToCGRect (screenRect);
|
||||
+ CGFloat primaryH
|
||||
+ = [[[NSScreen screens] firstObject] frame].size.height;
|
||||
+ cgRect.origin.y
|
||||
+ = primaryH - cgRect.origin.y - cgRect.size.height;
|
||||
+
|
||||
+ UAZoomChangeFocus (&cgRect, &cgRect,
|
||||
+ kUAZoomFocusTypeInsertionPoint);
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* 2. Check child frame completions (Corfu, Company-box). */
|
||||
+ struct frame *cf = NULL;
|
||||
+ int cf_line = ns_zoom_find_child_frame_candidate (f, &cf);
|
||||
+ if (cf_line >= 0 && cf)
|
||||
+ {
|
||||
+ EmacsView *cv = FRAME_NS_VIEW (cf);
|
||||
+ struct window *cw
|
||||
+ = XWINDOW (cf->selected_window);
|
||||
+ int cf_line_h = FRAME_LINE_HEIGHT (cf);
|
||||
+ int y_off = cf_line * cf_line_h;
|
||||
+
|
||||
+ NSRect r = NSMakeRect (
|
||||
+ WINDOW_TEXT_TO_FRAME_PIXEL_X (cw, 0),
|
||||
+ WINDOW_TO_FRAME_PIXEL_Y (cw, y_off),
|
||||
+ FRAME_COLUMN_WIDTH (cf),
|
||||
+ cf_line_h);
|
||||
+
|
||||
+ NSRect windowRect = [cv convertRect:r toView:nil];
|
||||
+ NSRect screenRect
|
||||
+ = [[cv window] convertRectToScreen:windowRect];
|
||||
+ CGRect cgRect = NSRectToCGRect (screenRect);
|
||||
+ CGFloat primaryH
|
||||
+ = [[[NSScreen screens] firstObject] frame].size.height;
|
||||
+ cgRect.origin.y
|
||||
+ = primaryH - cgRect.origin.y - cgRect.size.height;
|
||||
+
|
||||
+ UAZoomChangeFocus (&cgRect, &cgRect,
|
||||
+ kUAZoomFocusTypeInsertionPoint);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#endif /* MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 */
|
||||
+#endif /* NS_IMPL_COCOA */
|
||||
+
|
||||
static void
|
||||
ns_update_end (struct frame *f)
|
||||
/* --------------------------------------------------------------------------
|
||||
@@ -1104,6 +1315,41 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
|
||||
|
||||
unblock_input ();
|
||||
ns_updating_frame = NULL;
|
||||
@@ -99,11 +334,17 @@ index 74e4ad5..cd721c8 100644
|
||||
+ if (view)
|
||||
+ view->zoomCursorUpdated = NO;
|
||||
+#endif
|
||||
+
|
||||
+ /* Track completion candidates for Zoom (overlay and child frame).
|
||||
+ Runs after cursor tracking so the selected candidate overrides
|
||||
+ the default cursor position. */
|
||||
+ if (view)
|
||||
+ ns_zoom_track_completion (f, view);
|
||||
+#endif /* NS_IMPL_COCOA */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3232,6 +3261,45 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
|
||||
@@ -3232,6 +3478,45 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
|
||||
/* Prevent the cursor from being drawn outside the text area. */
|
||||
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 67bf4786bb3896241bf7ab75cdada0e3da924ec5 Mon Sep 17 00:00:00 2001
|
||||
From 59ec39bdda532d02c748a7e27f9a90ba3be3c338 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 12:58:11 +0100
|
||||
Subject: [PATCH 2/9] ns: add accessibility base classes and text extraction
|
||||
@@ -188,7 +188,7 @@ index ea6e7ba..6e830de 100644
|
||||
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index cd721c8..1320a9f 100644
|
||||
index 05ec3d1..a4d0e02 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -46,6 +46,7 @@ Updated by Christian Limpach (chris@nice.ch)
|
||||
@@ -199,7 +199,7 @@ index cd721c8..1320a9f 100644
|
||||
#include "systime.h"
|
||||
#include "character.h"
|
||||
#include "xwidget.h"
|
||||
@@ -6924,6 +6925,430 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
|
||||
@@ -7141,6 +7142,430 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -630,7 +630,7 @@ index cd721c8..1320a9f 100644
|
||||
/* ==========================================================================
|
||||
|
||||
EmacsView implementation
|
||||
@@ -11380,6 +11805,28 @@ Convert an X font name (XLFD) to an NS font name.
|
||||
@@ -11597,6 +12022,28 @@ Convert an X font name (XLFD) to an NS font name.
|
||||
DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic");
|
||||
DEFSYM (Qns_handle_drag_motion, "ns-handle-drag-motion");
|
||||
|
||||
@@ -659,7 +659,7 @@ index cd721c8..1320a9f 100644
|
||||
Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
|
||||
Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
|
||||
Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier));
|
||||
@@ -11528,6 +11975,15 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with
|
||||
@@ -11745,6 +12192,15 @@ Nil means use fullscreen the old (< 10.7) way. The old way works better with
|
||||
This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
|
||||
ns_use_srgb_colorspace = YES;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 80e590420ce74bb886849d91c245d0c0bece39bf Mon Sep 17 00:00:00 2001
|
||||
From 80f6de2020c50717e2238528e6241e00017f7230 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 12:58:11 +0100
|
||||
Subject: [PATCH 3/9] ns: implement buffer accessibility element (core
|
||||
@@ -22,10 +22,10 @@ line-by-line navigation, word/character announcements.
|
||||
1 file changed, 1097 insertions(+)
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 1320a9f..ab9a287 100644
|
||||
index a4d0e02..e281073 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -7346,6 +7346,1103 @@ - (id)accessibilityTopLevelUIElement
|
||||
@@ -7563,6 +7563,1103 @@ - (id)accessibilityTopLevelUIElement
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From afadafa16eef6e8e6d01ef4f340c451132198ba8 Mon Sep 17 00:00:00 2001
|
||||
From 672223b6ced41898156aa476b8c77b27d3719e4a Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 12:58:11 +0100
|
||||
Subject: [PATCH 4/9] ns: add buffer notification dispatch and mode-line
|
||||
@@ -24,10 +24,10 @@ region selection feedback, completion popups, mode-line reading.
|
||||
1 file changed, 545 insertions(+)
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index ab9a287..330667d 100644
|
||||
index e281073..a29f039 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -8443,6 +8443,551 @@ - (NSRect)accessibilityFrame
|
||||
@@ -8660,6 +8660,551 @@ - (NSRect)accessibilityFrame
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 010ec7a6e568653e12b904c5bb812a1b3c8e52cf Mon Sep 17 00:00:00 2001
|
||||
From 64b373bebadd9b9c52c90da297173ea108c6e394 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 12:58:11 +0100
|
||||
Subject: [PATCH 5/9] ns: add interactive span elements for Tab navigation
|
||||
@@ -17,10 +17,10 @@ Tested on macOS 14. Verified: Tab-cycling through org-mode links,
|
||||
1 file changed, 286 insertions(+)
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 330667d..907ce47 100644
|
||||
index a29f039..86bb7b6 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -8988,6 +8988,292 @@ - (NSRect)accessibilityFrame
|
||||
@@ -9205,6 +9205,292 @@ - (NSRect)accessibilityFrame
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From f10036eeadf681cd87bbec7ec0581b572053c38a Mon Sep 17 00:00:00 2001
|
||||
From be594f584a94e6fccd649be029c1af30242a12ee Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 12:58:11 +0100
|
||||
Subject: [PATCH 6/9] ns: integrate accessibility with EmacsView and redisplay
|
||||
@@ -23,14 +23,14 @@ block cursor, org-mode folded headings, indirect buffers.
|
||||
Known limitations documented in patch 6 Texinfo node.
|
||||
---
|
||||
etc/NEWS | 13 ++
|
||||
src/nsterm.m | 369 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 374 insertions(+), 8 deletions(-)
|
||||
src/nsterm.m | 376 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
||||
2 files changed, 376 insertions(+), 13 deletions(-)
|
||||
|
||||
diff --git a/etc/NEWS b/etc/NEWS
|
||||
index f10d17e..f48d05b 100644
|
||||
index 80661a9..2b1f9e6 100644
|
||||
--- a/etc/NEWS
|
||||
+++ b/etc/NEWS
|
||||
@@ -4397,6 +4397,19 @@ allowing Emacs users access to speech recognition utilities.
|
||||
@@ -4400,6 +4400,19 @@ allowing Emacs users access to speech recognition utilities.
|
||||
Note: Accepting this permission allows the use of system APIs, which may
|
||||
send user data to Apple's speech recognition servers.
|
||||
|
||||
@@ -51,20 +51,28 @@ index f10d17e..f48d05b 100644
|
||||
** Re-introduced dictation, lost in Emacs v30 (macOS).
|
||||
We lost macOS dictation in v30 when migrating to NSTextInputClient.
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 907ce47..d813274 100644
|
||||
index 86bb7b6..2e8ae20 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -1133,6 +1133,9 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
|
||||
@@ -1343,13 +1343,16 @@ so the visual offset is (ov_line + 1) * line_h from
|
||||
}
|
||||
if (view)
|
||||
view->zoomCursorUpdated = NO;
|
||||
#endif
|
||||
-#endif
|
||||
|
||||
/* Track completion candidates for Zoom (overlay and child frame).
|
||||
Runs after cursor tracking so the selected candidate overrides
|
||||
the default cursor position. */
|
||||
if (view)
|
||||
ns_zoom_track_completion (f, view);
|
||||
+#endif
|
||||
+
|
||||
+ /* Post accessibility notifications after each redisplay cycle. */
|
||||
+ [view postAccessibilityUpdates];
|
||||
#endif /* NS_IMPL_COCOA */
|
||||
}
|
||||
|
||||
@@ -3263,11 +3266,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
|
||||
@@ -3480,15 +3483,12 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
|
||||
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
|
||||
|
||||
#ifdef NS_IMPL_COCOA
|
||||
@@ -73,15 +81,20 @@ index 907ce47..d813274 100644
|
||||
- element to keep the zoomed viewport centered on the cursor.
|
||||
-
|
||||
- Coordinate conversion:
|
||||
+ /* Store cursor rect and inform macOS Zoom / VoiceOver.
|
||||
+ lastCursorRect is used by:
|
||||
+ - Zoom: UAZoomChangeFocus below (unconditional when active)
|
||||
+ - VoiceOver: accessibilityBoundsForRange: fallback
|
||||
- EmacsView pixels (AppKit, flipped, top-left origin)
|
||||
- -> NSWindow (convertRect:toView:nil)
|
||||
- -> NSScreen (convertRectToScreen:)
|
||||
- -> CGRect with y-flip for CoreGraphics top-left origin. */
|
||||
+ /* Store cursor rect for Zoom and VoiceOver bounds queries.
|
||||
+ Zoom: UAZoomChangeFocus below.
|
||||
+ VoiceOver: accessibilityBoundsForRange: fallback.
|
||||
+ Coordinate conversion for Zoom:
|
||||
EmacsView pixels (AppKit, flipped, top-left origin)
|
||||
-> NSWindow (convertRect:toView:nil)
|
||||
-> NSScreen (convertRectToScreen:)
|
||||
@@ -7349,7 +7352,6 @@ - (id)accessibilityTopLevelUIElement
|
||||
+ EmacsView (AppKit, flipped) -> NSWindow -> NSScreen
|
||||
+ -> CGRect with y-flip for CoreGraphics top-left origin. */
|
||||
{
|
||||
EmacsView *view = FRAME_NS_VIEW (f);
|
||||
if (view && on_p && active_p)
|
||||
@@ -7566,7 +7566,6 @@ - (id)accessibilityTopLevelUIElement
|
||||
|
||||
|
||||
|
||||
@@ -89,7 +102,7 @@ index 907ce47..d813274 100644
|
||||
static BOOL
|
||||
ns_ax_find_completion_overlay_range (struct buffer *b, ptrdiff_t point,
|
||||
ptrdiff_t *out_start,
|
||||
@@ -8444,7 +8446,6 @@ - (NSRect)accessibilityFrame
|
||||
@@ -8661,7 +8660,6 @@ - (NSRect)accessibilityFrame
|
||||
@end
|
||||
|
||||
|
||||
@@ -97,7 +110,7 @@ index 907ce47..d813274 100644
|
||||
/* ===================================================================
|
||||
EmacsAccessibilityBuffer (Notifications) — AX event dispatch
|
||||
|
||||
@@ -8989,7 +8990,6 @@ - (NSRect)accessibilityFrame
|
||||
@@ -9206,7 +9204,6 @@ - (NSRect)accessibilityFrame
|
||||
@end
|
||||
|
||||
|
||||
@@ -105,7 +118,7 @@ index 907ce47..d813274 100644
|
||||
/* ===================================================================
|
||||
EmacsAccessibilityInteractiveSpan — helpers and implementation
|
||||
=================================================================== */
|
||||
@@ -9319,6 +9319,7 @@ - (void)dealloc
|
||||
@@ -9536,6 +9533,7 @@ - (void)dealloc
|
||||
[layer release];
|
||||
#endif
|
||||
|
||||
@@ -113,7 +126,7 @@ index 907ce47..d813274 100644
|
||||
[[self menu] release];
|
||||
[super dealloc];
|
||||
}
|
||||
@@ -10667,6 +10668,32 @@ - (void)windowDidBecomeKey /* for direct calls */
|
||||
@@ -10884,6 +10882,32 @@ - (void)windowDidBecomeKey /* for direct calls */
|
||||
XSETFRAME (event.frame_or_window, emacsframe);
|
||||
kbd_buffer_store_event (&event);
|
||||
ns_send_appdefined (-1); // Kick main loop
|
||||
@@ -146,7 +159,7 @@ index 907ce47..d813274 100644
|
||||
}
|
||||
|
||||
|
||||
@@ -11904,6 +11931,332 @@ - (int) fullscreenState
|
||||
@@ -12121,6 +12145,332 @@ - (int) fullscreenState
|
||||
return fs_state;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 40bf8a0163b876e1d8f71fa8bd3c4aaa2a28ad52 Mon Sep 17 00:00:00 2001
|
||||
From 10ae74cefffd3733b8ff60e07a2b7f0dcb4d62cb Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 12:58:11 +0100
|
||||
Subject: [PATCH 7/9] doc: add VoiceOver accessibility section to macOS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 456c6a734fb94943b1d9acfaa8c1ffd0f1321ab5 Mon Sep 17 00:00:00 2001
|
||||
From 43b0625a7b9ce634006811e814fff037af8a51cd Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 14:46:25 +0100
|
||||
Subject: [PATCH 8/9] ns: announce overlay completion candidates for VoiceOver
|
||||
@@ -61,10 +61,10 @@ index 6e830de..2102fb9 100644
|
||||
@property (nonatomic, assign) BOOL cachedMarkActive;
|
||||
@property (nonatomic, copy) NSString *cachedCompletionAnnouncement;
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index d813274..9e089f3 100644
|
||||
index 2e8ae20..b9b2a80 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -6938,11 +6938,154 @@ Accessibility virtual elements (macOS / Cocoa only)
|
||||
@@ -7152,11 +7152,154 @@ Accessibility virtual elements (macOS / Cocoa only)
|
||||
|
||||
/* ---- Helper: extract buffer text for accessibility ---- */
|
||||
|
||||
@@ -220,7 +220,7 @@ index d813274..9e089f3 100644
|
||||
static NSString *
|
||||
ns_ax_buffer_text (struct window *w, ptrdiff_t *out_start,
|
||||
ns_ax_visible_run **out_runs, NSUInteger *out_nruns)
|
||||
@@ -7013,7 +7156,7 @@ Accessibility virtual elements (macOS / Cocoa only)
|
||||
@@ -7227,7 +7370,7 @@ Accessibility virtual elements (macOS / Cocoa only)
|
||||
|
||||
/* Extract this visible run's text. Use
|
||||
Fbuffer_substring_no_properties which correctly handles the
|
||||
@@ -229,7 +229,7 @@ index d813274..9e089f3 100644
|
||||
include garbage bytes when the run spans the gap position. */
|
||||
Lisp_Object lstr = Fbuffer_substring_no_properties (
|
||||
make_fixnum (pos), make_fixnum (run_end));
|
||||
@@ -7094,7 +7237,7 @@ Mode lines using icon fonts (e.g. doom-modeline with nerd-font)
|
||||
@@ -7308,7 +7451,7 @@ Mode lines using icon fonts (e.g. doom-modeline with nerd-font)
|
||||
return NSZeroRect;
|
||||
|
||||
/* charpos_start and charpos_len are already in buffer charpos
|
||||
@@ -238,7 +238,7 @@ index d813274..9e089f3 100644
|
||||
charposForAccessibilityIndex which handles invisible text. */
|
||||
ptrdiff_t cp_start = charpos_start;
|
||||
ptrdiff_t cp_end = cp_start + charpos_len;
|
||||
@@ -7573,6 +7716,7 @@ @implementation EmacsAccessibilityBuffer
|
||||
@@ -7787,6 +7930,7 @@ @implementation EmacsAccessibilityBuffer
|
||||
@synthesize cachedOverlayModiff;
|
||||
@synthesize cachedTextStart;
|
||||
@synthesize cachedModiff;
|
||||
@@ -246,7 +246,7 @@ index d813274..9e089f3 100644
|
||||
@synthesize cachedPoint;
|
||||
@synthesize cachedMarkActive;
|
||||
@synthesize cachedCompletionAnnouncement;
|
||||
@@ -7670,7 +7814,7 @@ - (void)ensureTextCache
|
||||
@@ -7884,7 +8028,7 @@ - (void)ensureTextCache
|
||||
NSTRACE ("EmacsAccessibilityBuffer ensureTextCache");
|
||||
/* This method is only called from the main thread (AX getters
|
||||
dispatch_sync to main first). Reads of cachedText/cachedTextModiff
|
||||
@@ -255,7 +255,7 @@ index d813274..9e089f3 100644
|
||||
write section at the end needs synchronization to protect
|
||||
against concurrent reads from AX server thread. */
|
||||
eassert ([NSThread isMainThread]);
|
||||
@@ -7683,16 +7827,15 @@ - (void)ensureTextCache
|
||||
@@ -7897,16 +8041,15 @@ - (void)ensureTextCache
|
||||
return;
|
||||
|
||||
ptrdiff_t modiff = BUF_MODIFF (b);
|
||||
@@ -278,7 +278,7 @@ index d813274..9e089f3 100644
|
||||
&& cachedTextStart == BUF_BEGV (b)
|
||||
&& pt >= cachedTextStart
|
||||
&& (textLen == 0
|
||||
@@ -7709,7 +7852,6 @@ - (void)ensureTextCache
|
||||
@@ -7923,7 +8066,6 @@ - (void)ensureTextCache
|
||||
[cachedText release];
|
||||
cachedText = [text retain];
|
||||
cachedTextModiff = modiff;
|
||||
@@ -286,7 +286,7 @@ index d813274..9e089f3 100644
|
||||
cachedTextStart = start;
|
||||
|
||||
if (visibleRuns)
|
||||
@@ -7774,7 +7916,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
|
||||
@@ -7988,7 +8130,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
|
||||
@@ -295,7 +295,7 @@ index d813274..9e089f3 100644
|
||||
NSUInteger lo = 0, hi = visibleRunCount;
|
||||
while (lo < hi)
|
||||
{
|
||||
@@ -7787,7 +7929,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
|
||||
@@ -8001,7 +8143,7 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
|
||||
else
|
||||
{
|
||||
/* Found: charpos is inside this run. Compute UTF-16 delta
|
||||
@@ -304,7 +304,7 @@ index d813274..9e089f3 100644
|
||||
NSUInteger chars_in = (NSUInteger)(charpos - r->charpos);
|
||||
if (chars_in == 0 || !cachedText)
|
||||
return r->ax_start;
|
||||
@@ -7812,10 +7954,10 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
|
||||
@@ -8026,10 +8168,10 @@ - (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
|
||||
|
||||
/* Convert accessibility string index to buffer charpos.
|
||||
Safe to call from any thread: uses only cachedText (NSString) and
|
||||
@@ -317,7 +317,7 @@ index d813274..9e089f3 100644
|
||||
@synchronized (self)
|
||||
{
|
||||
if (visibleRunCount == 0)
|
||||
@@ -7849,7 +7991,7 @@ - (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
|
||||
@@ -8063,7 +8205,7 @@ - (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
@@ -326,7 +326,7 @@ index d813274..9e089f3 100644
|
||||
if (lo > 0)
|
||||
{
|
||||
ns_ax_visible_run *last = &visibleRuns[visibleRunCount - 1];
|
||||
@@ -7871,7 +8013,7 @@ - (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
|
||||
@@ -8085,7 +8227,7 @@ - (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
|
||||
deadlocking the AX server thread. This is prevented by:
|
||||
|
||||
1. validWindow checks WINDOW_LIVE_P and BUFFERP before every
|
||||
@@ -335,7 +335,7 @@ index d813274..9e089f3 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
|
||||
@@ -8225,6 +8367,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber
|
||||
@@ -8439,6 +8581,50 @@ - (NSInteger)accessibilityInsertionPointLineNumber
|
||||
return [self lineForAXIndex:point_idx];
|
||||
}
|
||||
|
||||
@@ -386,7 +386,7 @@ index d813274..9e089f3 100644
|
||||
- (NSRange)accessibilityRangeForLine:(NSInteger)line
|
||||
{
|
||||
if (![NSThread isMainThread])
|
||||
@@ -8447,7 +8633,7 @@ - (NSRect)accessibilityFrame
|
||||
@@ -8661,7 +8847,7 @@ - (NSRect)accessibilityFrame
|
||||
|
||||
|
||||
/* ===================================================================
|
||||
@@ -395,7 +395,7 @@ index d813274..9e089f3 100644
|
||||
|
||||
These methods notify VoiceOver of text and selection changes.
|
||||
Called from the redisplay cycle (postAccessibilityUpdates).
|
||||
@@ -8462,7 +8648,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point
|
||||
@@ -8676,7 +8862,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point
|
||||
if (point > self.cachedPoint
|
||||
&& point - self.cachedPoint == 1)
|
||||
{
|
||||
@@ -404,7 +404,7 @@ index d813274..9e089f3 100644
|
||||
[self invalidateTextCache];
|
||||
[self ensureTextCache];
|
||||
if (cachedText)
|
||||
@@ -8481,7 +8667,7 @@ - (void)postTextChangedNotification:(ptrdiff_t)point
|
||||
@@ -8695,7 +8881,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
|
||||
@@ -413,7 +413,7 @@ index d813274..9e089f3 100644
|
||||
self.cachedPoint = point;
|
||||
|
||||
NSDictionary *change = @{
|
||||
@@ -8814,14 +9000,72 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f
|
||||
@@ -9028,14 +9214,72 @@ - (void)postAccessibilityNotificationsForFrame:(struct frame *)f
|
||||
BOOL markActive = !NILP (BVAR (b, mark_active));
|
||||
|
||||
/* --- Text changed (edit) --- */
|
||||
@@ -488,7 +488,7 @@ index d813274..9e089f3 100644
|
||||
per the WebKit/Chromium pattern. */
|
||||
else if (point != self.cachedPoint || markActive != self.cachedMarkActive)
|
||||
{
|
||||
@@ -8991,7 +9235,7 @@ - (NSRect)accessibilityFrame
|
||||
@@ -9205,7 +9449,7 @@ - (NSRect)accessibilityFrame
|
||||
|
||||
|
||||
/* ===================================================================
|
||||
@@ -497,7 +497,7 @@ index d813274..9e089f3 100644
|
||||
=================================================================== */
|
||||
|
||||
/* Scan visible range of window W for interactive spans.
|
||||
@@ -9199,7 +9443,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
|
||||
@@ -9413,7 +9657,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
|
||||
dispatch_async (dispatch_get_main_queue (), ^{
|
||||
/* lwin is a Lisp_Object captured by value. This is GC-safe
|
||||
because Lisp_Objects are tagged integers/pointers that
|
||||
@@ -506,7 +506,7 @@ index d813274..9e089f3 100644
|
||||
Emacs. The WINDOW_LIVE_P check below guards against the
|
||||
window being deleted between capture and execution. */
|
||||
if (!WINDOWP (lwin) || NILP (Fwindow_live_p (lwin)))
|
||||
@@ -9225,7 +9469,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
|
||||
@@ -9439,7 +9683,7 @@ - (void) setAccessibilityFocused: (BOOL) focused
|
||||
|
||||
@end
|
||||
|
||||
@@ -515,7 +515,7 @@ index d813274..9e089f3 100644
|
||||
Methods are kept here (same .m file) so they access the ivars
|
||||
declared in the @interface ivar block. */
|
||||
@implementation EmacsAccessibilityBuffer (InteractiveSpans)
|
||||
@@ -11947,7 +12191,7 @@ - (int) fullscreenState
|
||||
@@ -12161,7 +12405,7 @@ - (int) fullscreenState
|
||||
|
||||
if (WINDOW_LEAF_P (w))
|
||||
{
|
||||
@@ -524,7 +524,7 @@ index d813274..9e089f3 100644
|
||||
EmacsAccessibilityBuffer *elem
|
||||
= [existing objectForKey:[NSValue valueWithPointer:w]];
|
||||
if (!elem)
|
||||
@@ -11981,7 +12225,7 @@ - (int) fullscreenState
|
||||
@@ -12195,7 +12439,7 @@ - (int) fullscreenState
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -533,7 +533,7 @@ index d813274..9e089f3 100644
|
||||
Lisp_Object child = w->contents;
|
||||
while (!NILP (child))
|
||||
{
|
||||
@@ -12093,7 +12337,7 @@ - (void)postAccessibilityUpdates
|
||||
@@ -12307,7 +12551,7 @@ - (void)postAccessibilityUpdates
|
||||
accessibilityUpdating = YES;
|
||||
|
||||
/* Detect window tree change (split, delete, new buffer). Compare
|
||||
@@ -542,7 +542,7 @@ index d813274..9e089f3 100644
|
||||
Lisp_Object curRoot = FRAME_ROOT_WINDOW (emacsframe);
|
||||
if (!EQ (curRoot, lastRootWindow))
|
||||
{
|
||||
@@ -12102,12 +12346,12 @@ - (void)postAccessibilityUpdates
|
||||
@@ -12316,12 +12560,12 @@ - (void)postAccessibilityUpdates
|
||||
}
|
||||
|
||||
/* If tree is stale, rebuild FIRST so we don't iterate freed
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 16e60a514212d8e5e541eb731db242b2bcd1bca2 Mon Sep 17 00:00:00 2001
|
||||
From 62e619d508d4ce3b3bf0f8dd959041bcd9a75350 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 16:01:29 +0100
|
||||
Subject: [PATCH 9/9] ns: announce child frame completion candidates for
|
||||
@@ -71,10 +71,10 @@ index 4825cf9..97777e2 100644
|
||||
To disable the accessibility interface entirely (for instance, to
|
||||
eliminate overhead on systems where assistive technology is not in
|
||||
diff --git a/etc/NEWS b/etc/NEWS
|
||||
index f48d05b..ec4b95e 100644
|
||||
index 2b1f9e6..8a40850 100644
|
||||
--- a/etc/NEWS
|
||||
+++ b/etc/NEWS
|
||||
@@ -4401,8 +4401,8 @@ send user data to Apple's speech recognition servers.
|
||||
@@ -4404,8 +4404,8 @@ send user data to Apple's speech recognition servers.
|
||||
** VoiceOver accessibility support on macOS.
|
||||
Emacs now exposes buffer content, cursor position, and interactive
|
||||
elements to the macOS accessibility subsystem (VoiceOver). This
|
||||
@@ -109,10 +109,10 @@ index 2102fb9..2fc4de4 100644
|
||||
@end
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 9e089f3..1a623be 100644
|
||||
index b9b2a80..dc49417 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -7082,6 +7082,112 @@ visual line index for Zoom (skip whitespace-only lines
|
||||
@@ -7296,6 +7296,112 @@ visual line index for Zoom (skip whitespace-only lines
|
||||
|
||||
return nil;
|
||||
}
|
||||
@@ -225,7 +225,7 @@ index 9e089f3..1a623be 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
|
||||
@@ -12321,6 +12427,77 @@ - (id)accessibilityFocusedUIElement
|
||||
@@ -12535,6 +12641,77 @@ - (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. */
|
||||
@@ -303,7 +303,7 @@ index 9e089f3..1a623be 100644
|
||||
- (void)postAccessibilityUpdates
|
||||
{
|
||||
NSTRACE ("[EmacsView postAccessibilityUpdates]");
|
||||
@@ -12331,11 +12508,59 @@ - (void)postAccessibilityUpdates
|
||||
@@ -12545,11 +12722,59 @@ - (void)postAccessibilityUpdates
|
||||
|
||||
/* Re-entrance guard: VoiceOver callbacks during notification posting
|
||||
can trigger redisplay, which calls ns_update_end, which calls us
|
||||
|
||||
Reference in New Issue
Block a user