Merge remote-tracking branch 'refs/remotes/origin/master'

This commit is contained in:
Martin Sukany
2026-02-26 18:25:13 +01:00

View File

@@ -1,19 +1,19 @@
From 5fb855925912142401db0c732fff2014d21c3362 Mon Sep 17 00:00:00 2001
From f88649b2e09520d4c6e7ebc041e9e1a6e7ed616b Mon Sep 17 00:00:00 2001
From: Daneel <daneel@sukany.cz>
Date: Thu, 26 Feb 2026 18:06:10 +0100
Date: Thu, 26 Feb 2026 18:24:58 +0100
Subject: [PATCH] ns: implement AXBoundsForRange and VoiceOver interaction
fixes
---
nsterm.h | 70 ++
nsterm.m | 2090 +++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 1997 insertions(+), 163 deletions(-)
nsterm.h | 71 ++
nsterm.m | 2126 ++++++++++++++++++++++++++++++++++++++++++++++++++----
2 files changed, 2051 insertions(+), 146 deletions(-)
diff --git a/src/nsterm.h b/src/nsterm.h
index 7c1ee4c..97da979 100644
index 7c1ee4c..22828f2 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -453,6 +453,61 @@ enum ns_return_frame_mode
@@ -453,6 +453,62 @@ enum ns_return_frame_mode
@end
@@ -60,6 +60,7 @@ index 7c1ee4c..97da979 100644
+@property (nonatomic, copy) NSString *cachedCompletionAnnouncement;
+@property (nonatomic, assign) ptrdiff_t cachedCompletionOverlayStart;
+@property (nonatomic, assign) ptrdiff_t cachedCompletionOverlayEnd;
+@property (nonatomic, assign) ptrdiff_t cachedCompletionPoint;
+- (void)invalidateTextCache;
+- (void)postAccessibilityNotificationsForFrame:(struct frame *)f;
+- (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx;
@@ -75,7 +76,7 @@ index 7c1ee4c..97da979 100644
/* ==========================================================================
The main Emacs view
@@ -471,6 +526,14 @@ enum ns_return_frame_mode
@@ -471,6 +527,14 @@ enum ns_return_frame_mode
#ifdef NS_IMPL_COCOA
char *old_title;
BOOL maximizing_resize;
@@ -90,7 +91,7 @@ index 7c1ee4c..97da979 100644
#endif
BOOL font_panel_active;
NSFont *font_panel_result;
@@ -528,6 +591,13 @@ enum ns_return_frame_mode
@@ -528,6 +592,13 @@ enum ns_return_frame_mode
- (void)windowWillExitFullScreen;
- (void)windowDidExitFullScreen;
- (void)windowDidBecomeKey;
@@ -105,7 +106,7 @@ index 7c1ee4c..97da979 100644
diff --git a/src/nsterm.m b/src/nsterm.m
index 932d209..e7af9a3 100644
index 932d209..add827f 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -1104,6 +1104,11 @@ ns_update_end (struct frame *f)
@@ -158,7 +159,7 @@ index 932d209..e7af9a3 100644
ns_focus (f, NULL, 0);
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
@@ -6849,240 +6885,1646 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
@@ -6849,220 +6885,1696 @@ ns_create_font_panel_buttons (id target, SEL select, SEL cancel_action)
/* ==========================================================================
@@ -173,93 +174,57 @@ index 932d209..e7af9a3 100644
+/* ---- Helper: extract buffer text for accessibility ---- */
-- (void)windowDidEndLiveResize:(NSNotification *)notification
-{
- [self updateFramePosition];
-}
+/* Maximum characters exposed via accessibilityValue. */
+#define NS_AX_TEXT_CAP 100000
-/* Needed to inform when window closed from lisp. */
-- (void) setWindowClosing: (BOOL)closing
-{
- NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
+
+/* 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
+ with the count. Caller must free *OUT_RUNS with xfree(). */
- windowClosing = closing;
-}
+
+static NSString *
+ns_ax_buffer_text (struct window *w, ptrdiff_t *out_start,
+ ns_ax_visible_run **out_runs, NSUInteger *out_nruns)
+{
{
- [self updateFramePosition];
+ *out_runs = NULL;
+ *out_nruns = 0;
+
+ if (!w || !WINDOW_LEAF_P (w))
+ {
+ *out_start = 0;
+ return @"";
+ }
-- (void)dealloc
-{
- NSTRACE ("[EmacsView dealloc]");
+
+ struct buffer *b = XBUFFER (w->contents);
+ if (!b)
+ {
+ *out_start = 0;
+ return @"";
+ }
- /* Clear the view resize notification. */
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:NSViewFrameDidChangeNotification
- object:nil];
+
+ ptrdiff_t begv = BUF_BEGV (b);
+ ptrdiff_t zv = BUF_ZV (b);
- if (fs_state == FULLSCREEN_BOTH)
- [nonfs_window release];
+
+ *out_start = begv;
-#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
- /* Release layer and menu */
- EmacsLayer *layer = (EmacsLayer *)[self layer];
- [layer release];
-#endif
+
+ if (zv <= begv)
+ return @"";
- [[self menu] release];
- [super dealloc];
-}
+
+ struct buffer *oldb = current_buffer;
+ if (b != current_buffer)
+ set_buffer_internal_1 (b);
+
+ /* First pass: count visible runs to allocate the mapping array. */
+ NSUInteger run_capacity = 64;
+ ns_ax_visible_run *runs = xmalloc (run_capacity
+ * sizeof (ns_ax_visible_run));
+ NSUInteger nruns = 0;
+ NSUInteger ax_offset = 0;
-/* Called on font panel selection. */
-- (void) changeFont: (id) sender
-{
- struct font *font = FRAME_OUTPUT_DATA (emacsframe)->font;
- NSFont *nsfont;
+
+ NSMutableString *result = [NSMutableString string];
+ ptrdiff_t pos = begv;
-#ifdef NS_IMPL_GNUSTEP
- nsfont = ((struct nsfont_info *) font)->nsfont;
-#else
- nsfont = (NSFont *) macfont_get_nsctfont (font);
-#endif
+
+ while (pos < zv)
+ {
+ /* Check invisible property (text properties + overlays). */
@@ -279,16 +244,12 @@ index 932d209..e7af9a3 100644
+ pos = FIXNUMP (next) ? XFIXNUM (next) : zv;
+ continue;
+ }
- if (!font_panel_active)
- return;
+
+ /* Find end of this visible run: where invisible property changes. */
+ Lisp_Object next = Fnext_single_char_property_change (
+ make_fixnum (pos), Qinvisible, Qnil, make_fixnum (zv));
+ ptrdiff_t run_end = FIXNUMP (next) ? XFIXNUM (next) : zv;
- if (font_panel_result)
- [font_panel_result release];
+
+ /* Cap total text at NS_AX_TEXT_CAP. */
+ ptrdiff_t run_len = run_end - pos;
+ if (ax_offset + (NSUInteger) run_len > NS_AX_TEXT_CAP)
@@ -319,54 +280,41 @@ index 932d209..e7af9a3 100644
+ runs[nruns].ax_start = ax_offset;
+ runs[nruns].ax_length = ns_len;
+ nruns++;
- font_panel_result = (NSFont *) [sender convertFont: nsfont];
+
+ ax_offset += ns_len;
+ pos = run_end;
+ }
- if (font_panel_result)
- [font_panel_result retain];
+
+ if (b != oldb)
+ set_buffer_internal_1 (oldb);
-#ifndef NS_IMPL_COCOA
- font_panel_active = NO;
- [NSApp stop: self];
-#endif
+
+ *out_runs = runs;
+ *out_nruns = nruns;
+ return result;
}
-#ifdef NS_IMPL_COCOA
-- (void) noteUserSelectedFont
-/* Needed to inform when window closed from lisp. */
-- (void) setWindowClosing: (BOOL)closing
+
+/* ---- Helper: extract mode line text from glyph rows ---- */
+
+static NSString *
+ns_ax_mode_line_text (struct window *w)
{
- font_panel_active = NO;
- NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
+ if (!w || !w->current_matrix)
+ return @"";
- /* If no font was previously selected, use the currently selected
- font. */
- windowClosing = closing;
+ struct glyph_matrix *matrix = w->current_matrix;
+ NSMutableString *text = [NSMutableString string];
- if (!font_panel_result && FRAME_FONT (emacsframe))
+
+ for (int i = 0; i < matrix->nrows; i++)
{
- font_panel_result
- = macfont_get_nsctfont (FRAME_FONT (emacsframe));
+ {
+ struct glyph_row *row = matrix->rows + i;
+ if (!row->enabled_p || !row->mode_line_p)
+ continue;
- if (font_panel_result)
- [font_panel_result retain];
+
+ struct glyph *g = row->glyphs[TEXT_AREA];
+ struct glyph *end = g + row->used[TEXT_AREA];
+ for (; g < end; g++)
@@ -378,36 +326,42 @@ index 932d209..e7af9a3 100644
+ length:1]];
+ }
+ }
}
-
- [NSApp stop: self];
+ }
+ return text;
}
-- (void) noteUserCancelledSelection
+
-- (void)dealloc
+/* ---- Helper: screen rect for a character range via glyph matrix ---- */
+
+static NSRect
+ns_ax_frame_for_range (struct window *w, EmacsView *view,
+ ptrdiff_t text_start, NSRange range)
{
- font_panel_active = NO;
- NSTRACE ("[EmacsView dealloc]");
+ if (!w || !w->current_matrix || !view)
+ return NSZeroRect;
- if (font_panel_result)
- [font_panel_result release];
- font_panel_result = nil;
- /* Clear the view resize notification. */
- [[NSNotificationCenter defaultCenter]
- removeObserver:self
- name:NSViewFrameDidChangeNotification
- object:nil];
+ /* Convert range indices back to buffer charpos. */
+ ptrdiff_t cp_start = text_start + (ptrdiff_t) range.location;
+ ptrdiff_t cp_end = cp_start + (ptrdiff_t) range.length;
- [NSApp stop: self];
- if (fs_state == FULLSCREEN_BOTH)
- [nonfs_window release];
+ struct glyph_matrix *matrix = w->current_matrix;
+ NSRect result = NSZeroRect;
+ BOOL found = NO;
+
-#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
- /* Release layer and menu */
- EmacsLayer *layer = (EmacsLayer *)[self layer];
- [layer release];
-#endif
+ for (int i = 0; i < matrix->nrows; i++)
+ {
+ struct glyph_row *row = matrix->rows + i;
@@ -415,7 +369,9 @@ index 932d209..e7af9a3 100644
+ continue;
+ if (!row->displays_text_p && !row->ends_at_zv_p)
+ continue;
+
- [[self menu] release];
- [super dealloc];
+ ptrdiff_t row_start = MATRIX_ROW_START_CHARPOS (row);
+ ptrdiff_t row_end = MATRIX_ROW_END_CHARPOS (row);
+
@@ -459,9 +415,7 @@ index 932d209..e7af9a3 100644
+ NSRect winRect = [view convertRect:result toView:nil];
+ return [[view window] convertRectToScreen:winRect];
}
-#endif
-- (Lisp_Object) showFontPanel
+/* AX enum numeric compatibility for NSAccessibility notifications.
+ Values match WebKit AXObjectCacheMac fallback enums
+ (AXTextStateChangeType / AXTextEditType / AXTextSelectionDirection /
@@ -470,86 +424,75 @@ index 932d209..e7af9a3 100644
+ ns_ax_text_state_change_unknown = 0,
+ ns_ax_text_state_change_edit = 1,
+ ns_ax_text_state_change_selection_move = 2,
+
+ ns_ax_text_edit_type_typing = 3,
+
+ ns_ax_text_selection_direction_unknown = 0,
+ ns_ax_text_selection_direction_previous = 3,
+ ns_ax_text_selection_direction_next = 4,
+ ns_ax_text_selection_direction_discontiguous = 5,
+
+ ns_ax_text_selection_granularity_unknown = 0,
+ ns_ax_text_selection_granularity_character = 1,
+ ns_ax_text_selection_granularity_line = 3,
+};
+
+static NSUInteger
+ns_ax_utf16_length_for_buffer_range (struct buffer *b, ptrdiff_t start,
+ ptrdiff_t end)
{
- id fm = [NSFontManager sharedFontManager];
-/* Called on font panel selection. */
-- (void) changeFont: (id) sender
-{
- struct font *font = FRAME_OUTPUT_DATA (emacsframe)->font;
- NSFont *nsfont, *result;
- struct timespec timeout;
-#ifdef NS_IMPL_COCOA
- NSView *buttons;
- BOOL canceled;
-#endif
+ if (!b || end <= start)
+ return 0;
- NSFont *nsfont;
+ ns_ax_text_edit_type_typing = 3,
-#ifdef NS_IMPL_GNUSTEP
- nsfont = ((struct nsfont_info *) font)->nsfont;
-#else
- nsfont = (NSFont *) macfont_get_nsctfont (font);
-#endif
+ ns_ax_text_selection_direction_unknown = 0,
+ ns_ax_text_selection_direction_previous = 3,
+ ns_ax_text_selection_direction_next = 4,
+ ns_ax_text_selection_direction_discontiguous = 5,
- if (!font_panel_active)
- return;
+ ns_ax_text_selection_granularity_unknown = 0,
+ ns_ax_text_selection_granularity_character = 1,
+ ns_ax_text_selection_granularity_line = 3,
+};
- if (font_panel_result)
- [font_panel_result release];
+static NSUInteger
+ns_ax_utf16_length_for_buffer_range (struct buffer *b, ptrdiff_t start,
+ ptrdiff_t end)
+{
+ if (!b || end <= start)
+ return 0;
- font_panel_result = (NSFont *) [sender convertFont: nsfont];
+ struct buffer *oldb = current_buffer;
+ if (b != current_buffer)
+ set_buffer_internal_1 (b);
-#ifdef NS_IMPL_COCOA
- buttons
- = ns_create_font_panel_buttons (self,
- @selector (noteUserSelectedFont),
- @selector (noteUserCancelledSelection));
- [[fm fontPanel: YES] setAccessoryView: buttons];
- [buttons release];
-#endif
- if (font_panel_result)
- [font_panel_result retain];
+ Lisp_Object lstr = Fbuffer_substring_no_properties (make_fixnum (start),
+ make_fixnum (end));
+ NSString *nsstr = [NSString stringWithLispString:lstr];
+ NSUInteger len = [nsstr length];
- [fm setSelectedFont: nsfont isMultiple: NO];
- [fm orderFrontFontPanel: NSApp];
-#ifndef NS_IMPL_COCOA
- font_panel_active = NO;
- [NSApp stop: self];
-#endif
+ if (b != oldb)
+ set_buffer_internal_1 (oldb);
- font_panel_active = YES;
- timeout = make_timespec (0, 100000000);
+
+ return len;
+}
}
- block_input ();
- while (font_panel_active
-#ifdef NS_IMPL_COCOA
- && (canceled = [[fm fontPanel: YES] isVisible])
-#else
- && [[fm fontPanel: YES] isVisible]
-#endif
- )
- ns_select_1 (0, NULL, NULL, NULL, &timeout, NULL, YES);
- unblock_input ();
-- (void) noteUserSelectedFont
+static BOOL
+ns_ax_find_completion_overlay_range (struct buffer *b, ptrdiff_t point,
+ ptrdiff_t *out_start,
+ ptrdiff_t *out_end)
+{
{
- font_panel_active = NO;
+ if (!b || !out_start || !out_end)
+ return NO;
- if (font_panel_result)
- [font_panel_result autorelease];
- /* If no font was previously selected, use the currently selected
- font. */
+ Lisp_Object faceSym = intern ("completions-highlight");
+ ptrdiff_t begv = BUF_BEGV (b);
+ ptrdiff_t zv = BUF_ZV (b);
@@ -558,10 +501,50 @@ index 932d209..e7af9a3 100644
+ ptrdiff_t best_dist = PTRDIFF_MAX;
+ BOOL found = NO;
-#ifdef NS_IMPL_COCOA
- if (!canceled)
- font_panel_result = nil;
-#endif
- if (!font_panel_result && FRAME_FONT (emacsframe))
+ /* Fast path: look at point and immediate neighbors first. */
+ ptrdiff_t probes[3] = { point, point - 1, point + 1 };
+ for (int i = 0; i < 3 && !found; i++)
{
- font_panel_result
- = macfont_get_nsctfont (FRAME_FONT (emacsframe));
+ ptrdiff_t p = probes[i];
+ if (p < begv || p > zv)
+ continue;
- if (font_panel_result)
- [font_panel_result retain];
+ Lisp_Object overlays = Foverlays_at (make_fixnum (p), Qnil);
+ Lisp_Object tail;
+ for (tail = overlays; CONSP (tail); tail = XCDR (tail))
+ {
+ Lisp_Object ov = XCAR (tail);
+ Lisp_Object face = Foverlay_get (ov, Qface);
+ if (!(EQ (face, faceSym)
+ || (CONSP (face) && !NILP (Fmemq (faceSym, face)))))
+ continue;
+
+ ptrdiff_t ov_start = OVERLAY_START (ov);
+ ptrdiff_t ov_end = OVERLAY_END (ov);
+ if (ov_end <= ov_start)
+ continue;
+
+ best_start = ov_start;
+ best_end = ov_end;
+ best_dist = 0;
+ found = YES;
+ break;
+ }
}
- [NSApp stop: self];
-}
-
-- (void) noteUserCancelledSelection
-{
- font_panel_active = NO;
+ if (!found)
+ {
+ for (ptrdiff_t scan = begv; scan < zv; scan++)
+ {
+ Lisp_Object overlays = Foverlays_at (make_fixnum (scan), Qnil);
@@ -596,32 +579,130 @@ index 932d209..e7af9a3 100644
+ }
+ }
+ }
+ }
- result = font_panel_result;
- if (font_panel_result)
- [font_panel_result release];
- font_panel_result = nil;
+ if (!found)
+ return NO;
- [[fm fontPanel: YES] setIsVisible: NO];
- font_panel_active = NO;
- [NSApp stop: self];
+ *out_start = best_start;
+ *out_end = best_end;
+ return YES;
}
-#endif
-- (Lisp_Object) showFontPanel
+static NSString *
+ns_ax_completion_text_for_span (EmacsAccessibilityBuffer *elem,
+ struct buffer *b,
+ ptrdiff_t start,
+ ptrdiff_t end,
+ NSString *cachedText)
{
- id fm = [NSFontManager sharedFontManager];
- struct font *font = FRAME_OUTPUT_DATA (emacsframe)->font;
- NSFont *nsfont, *result;
- struct timespec timeout;
-#ifdef NS_IMPL_COCOA
- NSView *buttons;
- BOOL canceled;
-#endif
-
-#ifdef NS_IMPL_GNUSTEP
- nsfont = ((struct nsfont_info *) font)->nsfont;
-#else
- nsfont = (NSFont *) macfont_get_nsctfont (font);
-#endif
+ if (!elem || !b || !cachedText || end <= start)
+ return nil;
-#ifdef NS_IMPL_COCOA
- buttons
- = ns_create_font_panel_buttons (self,
- @selector (noteUserSelectedFont),
- @selector (noteUserCancelledSelection));
- [[fm fontPanel: YES] setAccessoryView: buttons];
- [buttons release];
-#endif
+ NSString *text = nil;
+ struct buffer *oldb = current_buffer;
+ if (b != current_buffer)
+ set_buffer_internal_1 (b);
- [fm setSelectedFont: nsfont isMultiple: NO];
- [fm orderFrontFontPanel: NSApp];
+ /* Prefer canonical completion candidate string from text property. */
+ ptrdiff_t probes[2] = { start, end - 1 };
+ for (int i = 0; i < 2 && !text; i++)
+ {
+ ptrdiff_t p = probes[i];
+ Lisp_Object cstr = Fget_char_property (make_fixnum (p),
+ intern ("completion--string"),
+ Qnil);
+ if (STRINGP (cstr))
+ text = [NSString stringWithLispString:cstr];
+ }
- font_panel_active = YES;
- timeout = make_timespec (0, 100000000);
+ if (!text)
+ {
+ NSUInteger ax_s = [elem accessibilityIndexForCharpos:start];
+ NSUInteger ax_e = [elem accessibilityIndexForCharpos:end];
+ if (ax_e > ax_s && ax_e <= [cachedText length])
+ text = [cachedText substringWithRange:NSMakeRange (ax_s, ax_e - ax_s)];
+ }
- block_input ();
- while (font_panel_active
-#ifdef NS_IMPL_COCOA
- && (canceled = [[fm fontPanel: YES] isVisible])
-#else
- && [[fm fontPanel: YES] isVisible]
-#endif
- )
- ns_select_1 (0, NULL, NULL, NULL, &timeout, NULL, YES);
- unblock_input ();
+ if (b != oldb)
+ set_buffer_internal_1 (oldb);
- if (font_panel_result)
- [font_panel_result autorelease];
+ if (text)
+ {
+ text = [text stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if ([text length] == 0)
+ text = nil;
+ }
-#ifdef NS_IMPL_COCOA
- if (!canceled)
- font_panel_result = nil;
-#endif
+ return text;
+}
- result = font_panel_result;
- font_panel_result = nil;
- [[fm fontPanel: YES] setIsVisible: NO];
- font_panel_active = NO;
+@implementation EmacsAccessibilityElement
- if (result)
- return ns_font_desc_to_font_spec ([result fontDescriptor],
- result);
- return Qnil;
+@implementation EmacsAccessibilityElement
+
+- (NSRect)screenRectFromEmacsX:(int)x y:(int)y width:(int)ew height:(int)eh
+{
+ EmacsView *view = self.emacsView;
+ if (!view || ![view window])
+ return NSZeroRect;
+
- return Qnil;
+ NSRect r = NSMakeRect (x, y, ew, eh);
+ NSRect winRect = [view convertRect:r toView:nil];
+ return [[view window] convertRectToScreen:winRect];
@@ -684,6 +765,7 @@ index 932d209..e7af9a3 100644
+@synthesize cachedCompletionAnnouncement;
+@synthesize cachedCompletionOverlayStart;
+@synthesize cachedCompletionOverlayEnd;
+@synthesize cachedCompletionPoint;
+- (void)dealloc
+{
@@ -705,8 +787,6 @@ index 932d209..e7af9a3 100644
- Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
- int code;
- unsigned fnKeysym = 0;
- static NSMutableArray *nsEvArray;
- unsigned int flags = [theEvent modifierFlags];
+ [cachedText release];
+ cachedText = nil;
+ if (visibleRuns)
@@ -716,21 +796,17 @@ index 932d209..e7af9a3 100644
+ }
+ visibleRunCount = 0;
+}
- NSTRACE ("[EmacsView keyDown:]");
+
+- (void)ensureTextCache
+{
+ struct window *w = self.emacsWindow;
+ if (!w || !WINDOW_LEAF_P (w))
+ return;
- /* Rhapsody and macOS give up and down events for the arrow keys. */
- if ([theEvent type] != NSEventTypeKeyDown)
+
+ struct buffer *b = XBUFFER (w->contents);
+ if (!b)
return;
- if (!emacs_event)
+ return;
+
+ ptrdiff_t modiff = BUF_MODIFF (b);
+ ptrdiff_t pt = BUF_PT (b);
+ NSUInteger textLen = cachedText ? [cachedText length] : 0;
@@ -738,16 +814,8 @@ index 932d209..e7af9a3 100644
+ && pt >= cachedTextStart
+ && (textLen == 0
+ || [self accessibilityIndexForCharpos:pt] <= textLen))
return;
- if (![[self window] isKeyWindow]
- && [[theEvent window] isKindOfClass: [EmacsWindow class]]
- /* We must avoid an infinite loop here. */
- && (EmacsView *)[[theEvent window] delegate] != self)
- {
- /* XXX: There is an occasional condition in which, when Emacs display
- updates a different frame from the current one, and temporarily
- selects it, then processes some interrupt-driven input
+ return;
+
+ ptrdiff_t start;
+ ns_ax_visible_run *runs = NULL;
+ NSUInteger nruns = 0;
@@ -1470,18 +1538,10 @@ index 932d209..e7af9a3 100644
+ ptrdiff_t ov_end = OVERLAY_END (ov);
+ if (ov_end > ov_start)
+ {
+ NSUInteger ax_idx = [self accessibilityIndexForCharpos:
+ ov_start];
+ if (ax_idx <= [cachedText length])
+ {
+ NSInteger lineNum = [self accessibilityLineForIndex:ax_idx];
+ NSRange lineRange = [self accessibilityRangeForLine:lineNum];
+ if (lineRange.location != NSNotFound
+ && lineRange.length > 0
+ && lineRange.location + lineRange.length
+ <= [cachedText length])
+ announceText = [cachedText substringWithRange:lineRange];
+ }
+ announceText = ns_ax_completion_text_for_span (self, b,
+ ov_start,
+ ov_end,
+ cachedText);
+ currentOverlayStart = ov_start;
+ currentOverlayEnd = ov_end;
+ }
@@ -1498,17 +1558,10 @@ index 932d209..e7af9a3 100644
+ ptrdiff_t ov_end = 0;
+ if (ns_ax_find_completion_overlay_range (b, point, &ov_start, &ov_end))
+ {
+ NSUInteger ax_idx = [self accessibilityIndexForCharpos:ov_start];
+ if (ax_idx <= [cachedText length])
+ {
+ NSInteger lineNum = [self accessibilityLineForIndex:ax_idx];
+ NSRange lineRange = [self accessibilityRangeForLine:lineNum];
+ if (lineRange.location != NSNotFound
+ && lineRange.length > 0
+ && lineRange.location + lineRange.length
+ <= [cachedText length])
+ announceText = [cachedText substringWithRange:lineRange];
+ }
+ announceText = ns_ax_completion_text_for_span (self, b,
+ ov_start,
+ ov_end,
+ cachedText);
+ currentOverlayStart = ov_start;
+ currentOverlayEnd = ov_end;
+ }
@@ -1545,7 +1598,8 @@ index 932d209..e7af9a3 100644
+ BOOL overlayChanged =
+ (currentOverlayStart != self.cachedCompletionOverlayStart
+ || currentOverlayEnd != self.cachedCompletionOverlayEnd);
+ if (textChanged || overlayChanged)
+ BOOL pointChanged = (point != self.cachedCompletionPoint);
+ if (textChanged || overlayChanged || pointChanged)
+ {
+ NSDictionary *annInfo = @{
+ NSAccessibilityAnnouncementKey: announceText,
@@ -1560,12 +1614,14 @@ index 932d209..e7af9a3 100644
+ self.cachedCompletionAnnouncement = announceText;
+ self.cachedCompletionOverlayStart = currentOverlayStart;
+ self.cachedCompletionOverlayEnd = currentOverlayEnd;
+ self.cachedCompletionPoint = point;
+ }
+ else
+ {
+ self.cachedCompletionAnnouncement = nil;
+ self.cachedCompletionOverlayStart = 0;
+ self.cachedCompletionOverlayEnd = 0;
+ self.cachedCompletionPoint = 0;
+ }
+ }
+ else
@@ -1573,6 +1629,7 @@ index 932d209..e7af9a3 100644
+ self.cachedCompletionAnnouncement = nil;
+ self.cachedCompletionOverlayStart = 0;
+ self.cachedCompletionOverlayEnd = 0;
+ self.cachedCompletionPoint = 0;
+ }
+ }
+
@@ -1584,6 +1641,7 @@ index 932d209..e7af9a3 100644
+ self.cachedCompletionAnnouncement = nil;
+ self.cachedCompletionOverlayStart = 0;
+ self.cachedCompletionOverlayEnd = 0;
+ self.cachedCompletionPoint = 0;
+ }
+ else
+ {
@@ -1601,18 +1659,10 @@ index 932d209..e7af9a3 100644
+ &currentOverlayStart,
+ &currentOverlayEnd))
+ {
+ NSUInteger ax_idx = [self accessibilityIndexForCharpos:
+ currentOverlayStart];
+ if (ax_idx <= [cachedText length])
+ {
+ NSInteger lineNum = [self accessibilityLineForIndex:ax_idx];
+ NSRange lineRange = [self accessibilityRangeForLine:lineNum];
+ if (lineRange.location != NSNotFound
+ && lineRange.length > 0
+ && lineRange.location + lineRange.length
+ <= [cachedText length])
+ announceText = [cachedText substringWithRange:lineRange];
+ }
+ announceText = ns_ax_completion_text_for_span (self, b,
+ currentOverlayStart,
+ currentOverlayEnd,
+ cachedText);
+ }
+
+ if (b != oldb2)
@@ -1629,7 +1679,8 @@ index 932d209..e7af9a3 100644
+ BOOL overlayChanged =
+ (currentOverlayStart != self.cachedCompletionOverlayStart
+ || currentOverlayEnd != self.cachedCompletionOverlayEnd);
+ if (textChanged || overlayChanged)
+ BOOL pointChanged = (point != self.cachedCompletionPoint);
+ if (textChanged || overlayChanged || pointChanged)
+ {
+ NSDictionary *annInfo = @{
+ NSAccessibilityAnnouncementKey: announceText,
@@ -1644,12 +1695,14 @@ index 932d209..e7af9a3 100644
+ self.cachedCompletionAnnouncement = announceText;
+ self.cachedCompletionOverlayStart = currentOverlayStart;
+ self.cachedCompletionOverlayEnd = currentOverlayEnd;
+ self.cachedCompletionPoint = point;
+ }
+ else
+ {
+ self.cachedCompletionAnnouncement = nil;
+ self.cachedCompletionOverlayStart = 0;
+ self.cachedCompletionOverlayEnd = 0;
+ self.cachedCompletionPoint = 0;
+ }
+ }
+ else
@@ -1657,6 +1710,7 @@ index 932d209..e7af9a3 100644
+ self.cachedCompletionAnnouncement = nil;
+ self.cachedCompletionOverlayStart = 0;
+ self.cachedCompletionOverlayEnd = 0;
+ self.cachedCompletionPoint = 0;
+ }
+ }
+ }
@@ -1945,30 +1999,10 @@ index 932d209..e7af9a3 100644
+ Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
+ int code;
+ unsigned fnKeysym = 0;
+ static NSMutableArray *nsEvArray;
+ unsigned int flags = [theEvent modifierFlags];
+
+ NSTRACE ("[EmacsView keyDown:]");
+
+ /* Rhapsody and macOS give up and down events for the arrow keys. */
+ if ([theEvent type] != NSEventTypeKeyDown)
+ return;
+
+ if (!emacs_event)
+ return;
+
+ if (![[self window] isKeyWindow]
+ && [[theEvent window] isKindOfClass: [EmacsWindow class]]
+ /* We must avoid an infinite loop here. */
+ && (EmacsView *)[[theEvent window] delegate] != self)
+ {
+ /* XXX: There is an occasional condition in which, when Emacs display
+ updates a different frame from the current one, and temporarily
+ selects it, then processes some interrupt-driven input
(dispnew.c:3878), OS will send the event to the correct NSWindow, but
for some reason that window has its first responder set to the NSView
most recently updated (I guess), which is not the correct one. */
@@ -8237,6 +9679,28 @@ ns_in_echo_area (void)
static NSMutableArray *nsEvArray;
unsigned int flags = [theEvent modifierFlags];
@@ -8237,6 +9749,28 @@ ns_in_echo_area (void)
XSETFRAME (event.frame_or_window, emacsframe);
kbd_buffer_store_event (&event);
ns_send_appdefined (-1); // Kick main loop
@@ -1997,7 +2031,7 @@ index 932d209..e7af9a3 100644
}
@@ -9474,6 +10938,298 @@ ns_in_echo_area (void)
@@ -9474,6 +11008,298 @@ ns_in_echo_area (void)
return fs_state;
}
@@ -2296,7 +2330,7 @@ index 932d209..e7af9a3 100644
@end /* EmacsView */
@@ -9941,6 +11697,14 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
@@ -9941,6 +11767,14 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
return [super accessibilityAttributeValue:attribute];
}