patches: fix B1 (live window ref), B2 (matrix guard), B3 (invisibility-spec), H1 (thread safety), H4 (main thread assert)

This commit is contained in:
2026-02-27 09:57:10 +01:00
parent 081d1c01e7
commit 1245253e15

View File

@@ -1,19 +1,19 @@
From 4626c5d0688db9d878120b120cb19e12fa2f3a94 Mon Sep 17 00:00:00 2001 From 1caa0476b3109ad583715c2f8a90c943780ffcb9 Mon Sep 17 00:00:00 2001
From: Martin Sukany <martin@sukany.cz> From: Martin Sukany <martin@sukany.cz>
Date: Fri, 27 Feb 2026 09:39:39 +0100 Date: Fri, 27 Feb 2026 09:57:00 +0100
Subject: [PATCH] ns: implement VoiceOver accessibility (AXBoundsForRange, line Subject: [PATCH] ns: implement VoiceOver accessibility (AXBoundsForRange, line
nav, completions) nav, completions)
--- ---
src/nsterm.h | 71 ++ src/nsterm.h | 73 ++
src/nsterm.m | 2195 ++++++++++++++++++++++++++++++++++++++++++++++---- src/nsterm.m | 2249 +++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 2126 insertions(+), 140 deletions(-) 2 files changed, 2187 insertions(+), 135 deletions(-)
diff --git a/src/nsterm.h b/src/nsterm.h diff --git a/src/nsterm.h b/src/nsterm.h
index 7c1ee4c..22828f2 100644 index 7c1ee4c..717a838 100644
--- a/src/nsterm.h --- a/src/nsterm.h
+++ b/src/nsterm.h +++ b/src/nsterm.h
@@ -453,6 +453,62 @@ enum ns_return_frame_mode @@ -453,6 +453,64 @@ enum ns_return_frame_mode
@end @end
@@ -29,7 +29,9 @@ index 7c1ee4c..22828f2 100644
+/* Base class for virtual accessibility elements attached to EmacsView. */ +/* Base class for virtual accessibility elements attached to EmacsView. */
+@interface EmacsAccessibilityElement : NSAccessibilityElement +@interface EmacsAccessibilityElement : NSAccessibilityElement
+@property (nonatomic, unsafe_unretained) EmacsView *emacsView; +@property (nonatomic, unsafe_unretained) EmacsView *emacsView;
+@property (nonatomic, assign) struct window *emacsWindow; +/* Lisp window object — safe across GC cycles. NULL_LISP when unset. */
+@property (nonatomic, assign) Lisp_Object lispWindow;
+- (struct window *)validWindow; /* Returns live window or NULL. */
+- (NSRect)screenRectFromEmacsX:(int)x y:(int)y width:(int)w height:(int)h; +- (NSRect)screenRectFromEmacsX:(int)x y:(int)y width:(int)w height:(int)h;
+@end +@end
+ +
@@ -76,7 +78,7 @@ index 7c1ee4c..22828f2 100644
/* ========================================================================== /* ==========================================================================
The main Emacs view The main Emacs view
@@ -471,6 +527,14 @@ enum ns_return_frame_mode @@ -471,6 +529,14 @@ enum ns_return_frame_mode
#ifdef NS_IMPL_COCOA #ifdef NS_IMPL_COCOA
char *old_title; char *old_title;
BOOL maximizing_resize; BOOL maximizing_resize;
@@ -91,7 +93,7 @@ index 7c1ee4c..22828f2 100644
#endif #endif
BOOL font_panel_active; BOOL font_panel_active;
NSFont *font_panel_result; NSFont *font_panel_result;
@@ -528,6 +592,13 @@ enum ns_return_frame_mode @@ -528,6 +594,13 @@ enum ns_return_frame_mode
- (void)windowWillExitFullScreen; - (void)windowWillExitFullScreen;
- (void)windowDidExitFullScreen; - (void)windowDidExitFullScreen;
- (void)windowDidBecomeKey; - (void)windowDidBecomeKey;
@@ -106,10 +108,18 @@ index 7c1ee4c..22828f2 100644
diff --git a/src/nsterm.m b/src/nsterm.m diff --git a/src/nsterm.m b/src/nsterm.m
index 932d209..06ee636 100644 index 932d209..220dccf 100644
--- a/src/nsterm.m --- a/src/nsterm.m
+++ b/src/nsterm.m +++ b/src/nsterm.m
@@ -1104,6 +1104,11 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) @@ -46,6 +46,7 @@ Updated by Christian Limpach (chris@nice.ch)
#include "blockinput.h"
#include "sysselect.h"
#include "nsterm.h"
+#include "intervals.h"
#include "systime.h"
#include "character.h"
#include "xwidget.h"
@@ -1104,6 +1105,11 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
unblock_input (); unblock_input ();
ns_updating_frame = NULL; ns_updating_frame = NULL;
@@ -121,7 +131,7 @@ index 932d209..06ee636 100644
} }
static void static void
@@ -3232,6 +3237,37 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. @@ -3232,6 +3238,37 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
/* Prevent the cursor from being drawn outside the text area. */ /* Prevent the cursor from being drawn outside the text area. */
r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA));
@@ -159,7 +169,7 @@ index 932d209..06ee636 100644
ns_focus (f, NULL, 0); ns_focus (f, NULL, 0);
NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
@@ -6849,216 +6885,1781 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg @@ -6849,207 +6886,1829 @@ - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
/* ========================================================================== /* ==========================================================================
@@ -227,16 +237,14 @@ index 932d209..06ee636 100644
+ +
+ while (pos < zv) + while (pos < zv)
+ { + {
+ /* Check invisible property (text properties + overlays). */ + /* Check invisible property (text properties + overlays).
+ Use TEXT_PROP_MEANS_INVISIBLE which respects buffer-invisibility-spec,
+ matching the logic in xdisp.c. This correctly handles org-mode,
+ outline-mode, hideshow and any mode using spec-controlled
+ invisibility (not just `invisible t'). */
+ Lisp_Object invis = Fget_char_property (make_fixnum (pos), + Lisp_Object invis = Fget_char_property (make_fixnum (pos),
+ Qinvisible, Qnil); + Qinvisible, Qnil);
+ /* Check if invisible property means truly invisible. + if (TEXT_PROP_MEANS_INVISIBLE (invis))
+ TEXT_PROP_MEANS_INVISIBLE is defined only in xdisp.c,
+ so we replicate: EQ(invis, Qt), or invis is on the
+ buffer's invisibility-spec list. Simplified: any
+ non-nil invisible property hides the text. This matches
+ the common case (invisible t) and org-mode/dired usage. */
+ if (!NILP (invis))
+ { + {
+ /* Skip to the next position where invisible changes. */ + /* Skip to the next position where invisible changes. */
+ Lisp_Object next = Fnext_single_char_property_change ( + Lisp_Object next = Fnext_single_char_property_change (
@@ -730,8 +738,34 @@ index 932d209..06ee636 100644
+@implementation EmacsAccessibilityElement +@implementation EmacsAccessibilityElement
- return Qnil; - return Qnil;
+- (NSRect)screenRectFromEmacsX:(int)x y:(int)y width:(int)ew height:(int)eh +- (instancetype)init
+{ +{
+ self = [super init];
+ if (self)
+ self.lispWindow = Qnil;
+ return self;
}
-- (BOOL)acceptsFirstResponder
+/* Return the associated Emacs window if it is still live, else NULL.
+ Use this instead of storing a raw struct window * which can become a
+ dangling pointer after delete-window or kill-buffer. */
+- (struct window *)validWindow
{
- NSTRACE ("[EmacsView acceptsFirstResponder]");
- return YES;
+ if (NILP (self.lispWindow) || !WINDOW_LIVE_P (self.lispWindow))
+ return NULL;
+ return XWINDOW (self.lispWindow);
}
-/* Tell NS we want to accept clicks that activate the window */
-- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
+- (NSRect)screenRectFromEmacsX:(int)x y:(int)y width:(int)ew height:(int)eh
{
- NSTRACE_MSG ("First mouse event: type=%ld, clickCount=%ld",
- [theEvent type], [theEvent clickCount]);
- return ns_click_through;
+ EmacsView *view = self.emacsView; + EmacsView *view = self.emacsView;
+ if (!view || ![view window]) + if (!view || ![view window])
+ return NSZeroRect; + return NSZeroRect;
@@ -740,39 +774,25 @@ index 932d209..06ee636 100644
+ NSRect winRect = [view convertRect:r toView:nil]; + NSRect winRect = [view convertRect:r toView:nil];
+ return [[view window] convertRectToScreen:winRect]; + return [[view window] convertRectToScreen:winRect];
} }
-- (void)resetCursorRects
-- (BOOL)acceptsFirstResponder +
+- (BOOL)isAccessibilityElement +- (BOOL)isAccessibilityElement
{ {
- NSTRACE ("[EmacsView acceptsFirstResponder]");
return YES;
}
-/* Tell NS we want to accept clicks that activate the window */
-- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
+/* ---- Hierarchy plumbing (required for VoiceOver to find us) ---- */
+
+- (id)accessibilityParent
{
- NSTRACE_MSG ("First mouse event: type=%ld, clickCount=%ld",
- [theEvent type], [theEvent clickCount]);
- return ns_click_through;
+ return NSAccessibilityUnignoredAncestor (self.emacsView);
}
-- (void)resetCursorRects
-{
- NSRect visible = [self visibleRect]; - NSRect visible = [self visibleRect];
- NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe); - NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
- NSTRACE ("[EmacsView resetCursorRects]"); - NSTRACE ("[EmacsView resetCursorRects]");
- + return YES;
+}
- if (currentCursor == nil) - if (currentCursor == nil)
- currentCursor = [NSCursor arrowCursor]; - currentCursor = [NSCursor arrowCursor];
+/* ---- Hierarchy plumbing (required for VoiceOver to find us) ---- */
- if (!NSIsEmptyRect (visible)) - if (!NSIsEmptyRect (visible))
- [self addCursorRect: visible cursor: currentCursor]; - [self addCursorRect: visible cursor: currentCursor];
+- (id)accessibilityWindow +- (id)accessibilityParent
+{ +{
+ return [self.emacsView window]; + return NSAccessibilityUnignoredAncestor (self.emacsView);
+} +}
-#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 -#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
@@ -781,17 +801,19 @@ index 932d209..06ee636 100644
-#endif -#endif
- [currentCursor setOnMouseEntered: YES]; - [currentCursor setOnMouseEntered: YES];
-#endif -#endif
+- (id)accessibilityWindow
+{
+ return [self.emacsView window];
+}
+
+- (id)accessibilityTopLevelUIElement +- (id)accessibilityTopLevelUIElement
+{ +{
+ return [self.emacsView window]; + return [self.emacsView window];
} +}
+
+@end +@end
+
+
-/*****************************************************************************/
-/* Keyboard handling. */
-#define NS_KEYLOG 0
+@implementation EmacsAccessibilityBuffer +@implementation EmacsAccessibilityBuffer
+@synthesize cachedText; +@synthesize cachedText;
+@synthesize cachedTextModiff; +@synthesize cachedTextModiff;
@@ -803,8 +825,7 @@ index 932d209..06ee636 100644
+@synthesize cachedCompletionOverlayStart; +@synthesize cachedCompletionOverlayStart;
+@synthesize cachedCompletionOverlayEnd; +@synthesize cachedCompletionOverlayEnd;
+@synthesize cachedCompletionPoint; +@synthesize cachedCompletionPoint;
+
-- (void)keyDown: (NSEvent *)theEvent
+- (void)dealloc +- (void)dealloc
+{ +{
+ [cachedText release]; + [cachedText release];
@@ -830,7 +851,7 @@ index 932d209..06ee636 100644
+ +
+- (void)ensureTextCache +- (void)ensureTextCache
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return; + return;
+ +
@@ -868,7 +889,7 @@ index 932d209..06ee636 100644
+/* Convert buffer charpos to accessibility string index. */ +/* Convert buffer charpos to accessibility string index. */
+- (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos +- (NSUInteger)accessibilityIndexForCharpos:(ptrdiff_t)charpos
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ struct buffer *b = (w && WINDOW_LEAF_P (w)) ? XBUFFER (w->contents) : NULL; + struct buffer *b = (w && WINDOW_LEAF_P (w)) ? XBUFFER (w->contents) : NULL;
+ +
+ for (NSUInteger i = 0; i < visibleRunCount; i++) + for (NSUInteger i = 0; i < visibleRunCount; i++)
@@ -901,7 +922,7 @@ index 932d209..06ee636 100644
+/* Convert accessibility string index to buffer charpos. */ +/* Convert accessibility string index to buffer charpos. */
+- (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx +- (ptrdiff_t)charposForAccessibilityIndex:(NSUInteger)ax_idx
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ struct buffer *b = (w && WINDOW_LEAF_P (w)) ? XBUFFER (w->contents) : NULL; + struct buffer *b = (w && WINDOW_LEAF_P (w)) ? XBUFFER (w->contents) : NULL;
+ +
+ for (NSUInteger i = 0; i < visibleRunCount; i++) + for (NSUInteger i = 0; i < visibleRunCount; i++)
@@ -950,7 +971,7 @@ index 932d209..06ee636 100644
+ +
+- (NSString *)accessibilityRoleDescription +- (NSString *)accessibilityRoleDescription
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (w && MINI_WINDOW_P (w)) + if (w && MINI_WINDOW_P (w))
+ return @"minibuffer"; + return @"minibuffer";
+ return @"editor"; + return @"editor";
@@ -958,7 +979,7 @@ index 932d209..06ee636 100644
+ +
+- (NSString *)accessibilityLabel +- (NSString *)accessibilityLabel
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (w && WINDOW_LEAF_P (w)) + if (w && WINDOW_LEAF_P (w))
+ { + {
+ if (MINI_WINDOW_P (w)) + if (MINI_WINDOW_P (w))
@@ -977,7 +998,7 @@ index 932d209..06ee636 100644
+ +
+- (BOOL)isAccessibilityFocused +- (BOOL)isAccessibilityFocused
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w) + if (!w)
+ return NO; + return NO;
+ EmacsView *view = self.emacsView; + EmacsView *view = self.emacsView;
@@ -989,6 +1010,14 @@ index 932d209..06ee636 100644
+ +
+- (id)accessibilityValue +- (id)accessibilityValue
+{ +{
+ /* AX getters can be called from any thread by the AT subsystem.
+ Dispatch to main thread where Emacs buffer state is consistent. */
+ if (![NSThread isMainThread])
+ {
+ __block id result;
+ dispatch_sync (dispatch_get_main_queue (), ^{ result = [self accessibilityValue]; });
+ return result;
+ }
+ [self ensureTextCache]; + [self ensureTextCache];
+ return cachedText ? cachedText : @""; + return cachedText ? cachedText : @"";
+} +}
@@ -1001,7 +1030,7 @@ index 932d209..06ee636 100644
+ +
+- (NSString *)accessibilitySelectedText +- (NSString *)accessibilitySelectedText
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return @""; + return @"";
+ +
@@ -1019,7 +1048,13 @@ index 932d209..06ee636 100644
+ +
+- (NSRange)accessibilitySelectedTextRange +- (NSRange)accessibilitySelectedTextRange
+{ +{
+ struct window *w = self.emacsWindow; + if (![NSThread isMainThread])
+ {
+ __block NSRange result;
+ dispatch_sync (dispatch_get_main_queue (), ^{ result = [self accessibilitySelectedTextRange]; });
+ return result;
+ }
+ struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return NSMakeRange (0, 0); + return NSMakeRange (0, 0);
+ +
@@ -1045,7 +1080,7 @@ index 932d209..06ee636 100644
+ +
+- (void)setAccessibilitySelectedTextRange:(NSRange)range +- (void)setAccessibilitySelectedTextRange:(NSRange)range
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return; + return;
+ +
@@ -1104,7 +1139,7 @@ index 932d209..06ee636 100644
+ if (!flag) + if (!flag)
+ return; + return;
+ +
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return; + return;
+ +
@@ -1132,7 +1167,13 @@ index 932d209..06ee636 100644
+ +
+- (NSInteger)accessibilityInsertionPointLineNumber +- (NSInteger)accessibilityInsertionPointLineNumber
+{ +{
+ struct window *w = self.emacsWindow; + if (![NSThread isMainThread])
+ {
+ __block NSInteger result;
+ dispatch_sync (dispatch_get_main_queue (), ^{ result = [self accessibilityInsertionPointLineNumber]; });
+ return result;
+ }
+ struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return 0; + return 0;
+ +
@@ -1246,7 +1287,13 @@ index 932d209..06ee636 100644
+ +
+- (NSRect)accessibilityFrameForRange:(NSRange)range +- (NSRect)accessibilityFrameForRange:(NSRange)range
+{ +{
+ struct window *w = self.emacsWindow; + if (![NSThread isMainThread])
+ {
+ __block NSRect result;
+ dispatch_sync (dispatch_get_main_queue (), ^{ result = [self accessibilityFrameForRange:range]; });
+ return result;
+ }
+ struct window *w = [self validWindow];
+ EmacsView *view = self.emacsView; + EmacsView *view = self.emacsView;
+ if (!w || !view) + if (!w || !view)
+ return NSZeroRect; + return NSZeroRect;
@@ -1261,8 +1308,14 @@ index 932d209..06ee636 100644
+ +
+- (NSRange)accessibilityRangeForPosition:(NSPoint)screenPoint +- (NSRange)accessibilityRangeForPosition:(NSPoint)screenPoint
+{ +{
+ if (![NSThread isMainThread])
+ {
+ __block NSRange result;
+ dispatch_sync (dispatch_get_main_queue (), ^{ result = [self accessibilityRangeForPosition:screenPoint]; });
+ return result;
+ }
+ /* Hit test: convert screen point to buffer character index. */ + /* Hit test: convert screen point to buffer character index. */
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ EmacsView *view = self.emacsView; + EmacsView *view = self.emacsView;
+ if (!w || !view || !w->current_matrix) + if (!w || !view || !w->current_matrix)
+ return NSMakeRange (0, 0); + return NSMakeRange (0, 0);
@@ -1278,6 +1331,10 @@ index 932d209..06ee636 100644
+ if (x < 0 || y < 0 || x >= w->pixel_width || y >= w->pixel_height) + if (x < 0 || y < 0 || x >= w->pixel_width || y >= w->pixel_height)
+ return NSMakeRange (0, 0); + return NSMakeRange (0, 0);
+ +
+ /* Block input to prevent concurrent redisplay from modifying the
+ glyph matrix while we traverse it. */
+ block_input ();
+
+ /* Find the glyph row at this y coordinate. */ + /* Find the glyph row at this y coordinate. */
+ struct glyph_matrix *matrix = w->current_matrix; + struct glyph_matrix *matrix = w->current_matrix;
+ struct glyph_row *hit_row = NULL; + struct glyph_row *hit_row = NULL;
@@ -1297,7 +1354,10 @@ index 932d209..06ee636 100644
+ } + }
+ +
+ if (!hit_row) + if (!hit_row)
+ return NSMakeRange (0, 0); + {
+ unblock_input ();
+ return NSMakeRange (0, 0);
+ }
+ +
+ /* Find the glyph at this x coordinate within the row. */ + /* Find the glyph at this x coordinate within the row. */
+ struct glyph *glyph = hit_row->glyphs[TEXT_AREA]; + struct glyph *glyph = hit_row->glyphs[TEXT_AREA];
@@ -1324,6 +1384,8 @@ index 932d209..06ee636 100644
+ NSUInteger ax_idx = [self accessibilityIndexForCharpos:best_charpos]; + NSUInteger ax_idx = [self accessibilityIndexForCharpos:best_charpos];
+ if (cachedText && ax_idx > [cachedText length]) + if (cachedText && ax_idx > [cachedText length])
+ ax_idx = [cachedText length]; + ax_idx = [cachedText length];
+
+ unblock_input ();
+ return NSMakeRange (ax_idx, 1); + return NSMakeRange (ax_idx, 1);
+} +}
+ +
@@ -1338,7 +1400,7 @@ index 932d209..06ee636 100644
+ +
+- (NSRect)accessibilityFrame +- (NSRect)accessibilityFrame
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w) + if (!w)
+ return NSZeroRect; + return NSZeroRect;
+ +
@@ -1366,7 +1428,7 @@ index 932d209..06ee636 100644
+ +
+- (void)postAccessibilityNotificationsForFrame:(struct frame *)f +- (void)postAccessibilityNotificationsForFrame:(struct frame *)f
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w || !WINDOW_LEAF_P (w)) + if (!w || !WINDOW_LEAF_P (w))
+ return; + return;
+ +
@@ -1812,7 +1874,7 @@ index 932d209..06ee636 100644
+ +
+- (NSString *)accessibilityLabel +- (NSString *)accessibilityLabel
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (w && WINDOW_LEAF_P (w)) + if (w && WINDOW_LEAF_P (w))
+ { + {
+ struct buffer *b = XBUFFER (w->contents); + struct buffer *b = XBUFFER (w->contents);
@@ -1831,7 +1893,7 @@ index 932d209..06ee636 100644
+ +
+- (id)accessibilityValue +- (id)accessibilityValue
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w) + if (!w)
+ return @""; + return @"";
+ return ns_ax_mode_line_text (w); + return ns_ax_mode_line_text (w);
@@ -1839,7 +1901,7 @@ index 932d209..06ee636 100644
+ +
+- (NSRect)accessibilityFrame +- (NSRect)accessibilityFrame
+{ +{
+ struct window *w = self.emacsWindow; + struct window *w = [self validWindow];
+ if (!w || !w->current_matrix) + if (!w || !w->current_matrix)
+ return NSZeroRect; + return NSZeroRect;
+ +
@@ -2069,19 +2131,10 @@ index 932d209..06ee636 100644
+#endif +#endif
+ [currentCursor setOnMouseEntered: YES]; + [currentCursor setOnMouseEntered: YES];
+#endif +#endif
+} }
+
+
+ @@ -8237,6 +9896,28 @@ - (void)windowDidBecomeKey /* for direct calls */
+/*****************************************************************************/
+/* Keyboard handling. */
+#define NS_KEYLOG 0
+
+- (void)keyDown: (NSEvent *)theEvent
{
Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
int code;
@@ -8237,6 +9838,28 @@ - (void)windowDidBecomeKey /* for direct calls */
XSETFRAME (event.frame_or_window, emacsframe); XSETFRAME (event.frame_or_window, emacsframe);
kbd_buffer_store_event (&event); kbd_buffer_store_event (&event);
ns_send_appdefined (-1); // Kick main loop ns_send_appdefined (-1); // Kick main loop
@@ -2110,7 +2163,7 @@ index 932d209..06ee636 100644
} }
@@ -9474,6 +11097,298 @@ - (int) fullscreenState @@ -9474,6 +11155,304 @@ - (int) fullscreenState
return fs_state; return fs_state;
} }
@@ -2147,7 +2200,7 @@ index 932d209..06ee636 100644
+ { + {
+ [elem retain]; + [elem retain];
+ } + }
+ elem.emacsWindow = w; + elem.lispWindow = window;
+ [elements addObject:elem]; + [elements addObject:elem];
+ [elem release]; + [elem release];
+ +
@@ -2157,7 +2210,7 @@ index 932d209..06ee636 100644
+ EmacsAccessibilityModeLine *ml + EmacsAccessibilityModeLine *ml
+ = [[EmacsAccessibilityModeLine alloc] init]; + = [[EmacsAccessibilityModeLine alloc] init];
+ ml.emacsView = view; + ml.emacsView = view;
+ ml.emacsWindow = w; + ml.lispWindow = window;
+ [elements addObject:ml]; + [elements addObject:ml];
+ [ml release]; + [ml release];
+ } + }
@@ -2186,10 +2239,10 @@ index 932d209..06ee636 100644
+ for (EmacsAccessibilityElement *elem in accessibilityElements) + for (EmacsAccessibilityElement *elem in accessibilityElements)
+ { + {
+ if ([elem isKindOfClass:[EmacsAccessibilityBuffer class]] + if ([elem isKindOfClass:[EmacsAccessibilityBuffer class]]
+ && elem.emacsWindow) + && !NILP (elem.lispWindow))
+ [existing setObject:elem + [existing setObject:elem
+ forKey:[NSValue valueWithPointer: + forKey:[NSValue valueWithPointer:
+ elem.emacsWindow]]; + XWINDOW (elem.lispWindow)]];
+ } + }
+ } + }
+ +
@@ -2248,7 +2301,7 @@ index 932d209..06ee636 100644
+ for (EmacsAccessibilityElement *elem in accessibilityElements) + for (EmacsAccessibilityElement *elem in accessibilityElements)
+ { + {
+ if ([elem isKindOfClass:[EmacsAccessibilityBuffer class]] + if ([elem isKindOfClass:[EmacsAccessibilityBuffer class]]
+ && elem.emacsWindow == sel) + && EQ (elem.lispWindow, emacsframe->selected_window))
+ return elem; + return elem;
+ } + }
+ return self; + return self;
@@ -2262,6 +2315,9 @@ index 932d209..06ee636 100644
+ elements with current values, making change detection impossible. */ + elements with current values, making change detection impossible. */
+- (void)postAccessibilityUpdates +- (void)postAccessibilityUpdates
+{ +{
+ NSCAssert ([NSThread isMainThread],
+ @"postAccessibilityUpdates must be called on the main thread");
+
+ if (!emacsframe) + if (!emacsframe)
+ return; + return;
+ +
@@ -2271,6 +2327,7 @@ index 932d209..06ee636 100644
+ if (accessibilityUpdating) + if (accessibilityUpdating)
+ return; + return;
+ accessibilityUpdating = YES; + accessibilityUpdating = YES;
+ @try {
+ +
+ /* Detect window tree change (split, delete, new buffer). Compare + /* Detect window tree change (split, delete, new buffer). Compare
+ FRAME_ROOT_WINDOW — if it changed, the tree structure changed. */ + FRAME_ROOT_WINDOW — if it changed, the tree structure changed. */
@@ -2308,7 +2365,7 @@ index 932d209..06ee636 100644
+ { + {
+ if ([elem isKindOfClass:[EmacsAccessibilityBuffer class]]) + if ([elem isKindOfClass:[EmacsAccessibilityBuffer class]])
+ { + {
+ struct window *w = elem.emacsWindow; + struct window *w = [elem validWindow];
+ if (w && WINDOW_LEAF_P (w) + if (w && WINDOW_LEAF_P (w)
+ && BUFFERP (w->contents) && XBUFFER (w->contents)) + && BUFFERP (w->contents) && XBUFFER (w->contents))
+ [(EmacsAccessibilityBuffer *) elem + [(EmacsAccessibilityBuffer *) elem
@@ -2338,7 +2395,9 @@ index 932d209..06ee636 100644
+ NSAccessibilityFocusedUIElementChangedNotification); + NSAccessibilityFocusedUIElementChangedNotification);
+ } + }
+ +
+ accessibilityUpdating = NO; + } @finally {
+ accessibilityUpdating = NO;
+ }
+} +}
+ +
+/* ---- Cursor position for Zoom (via accessibilityBoundsForRange:) ---- +/* ---- Cursor position for Zoom (via accessibilityBoundsForRange:) ----