patches: fix B1 (live window ref), B2 (matrix guard), B3 (invisibility-spec), H1 (thread safety), H4 (main thread assert)
This commit is contained in:
@@ -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)
|
||||||
|
+ {
|
||||||
|
+ unblock_input ();
|
||||||
+ return NSMakeRange (0, 0);
|
+ 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,8 +2395,10 @@ index 932d209..06ee636 100644
|
|||||||
+ NSAccessibilityFocusedUIElementChangedNotification);
|
+ NSAccessibilityFocusedUIElementChangedNotification);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ } @finally {
|
||||||
+ accessibilityUpdating = NO;
|
+ accessibilityUpdating = NO;
|
||||||
+ }
|
+ }
|
||||||
|
+}
|
||||||
+
|
+
|
||||||
+/* ---- Cursor position for Zoom (via accessibilityBoundsForRange:) ----
|
+/* ---- Cursor position for Zoom (via accessibilityBoundsForRange:) ----
|
||||||
+
|
+
|
||||||
|
|||||||
Reference in New Issue
Block a user