patches: restructure per reviewer feedback
Major changes: 1. Zoom separated into standalone patch 0000 - UAZoomChangeFocus in ns_draw_window_cursor - Fallback in ns_update_end for window-switch tracking - No overlayZoomActive (source of split/switch/move bug) 2. VoiceOver patches 0001-0008 are now Zoom-free - All UAZoom*, overlayZoom*, kUAZoomFocus references removed - lastAccessibilityCursorRect kept for VoiceOver bounds queries - Commit messages cleaned of Zoom references 3. README.txt and TESTING.txt rewritten for new structure Addresses reviewer (Stéphane Marks) feedback: - Keep Zoom patch separate from VoiceOver work - Design discussion needed for non-Zoom patches - Performance: ns-accessibility-enabled=nil for zero overhead
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
From 402d2959cc569ebe740f07687c37283323fce314 Mon Sep 17 00:00:00 2001
|
||||
From: Martin Sukany <martin@sukany.cz>
|
||||
Date: Sat, 28 Feb 2026 22:08:55 +0100
|
||||
Subject: [PATCH] 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.
|
||||
|
||||
* src/nsterm.h (EmacsView): Add lastZoomCursorRect ivar.
|
||||
* src/nsterm.m (ns_draw_window_cursor): Store cursor rect in
|
||||
lastZoomCursorRect; call UAZoomChangeFocus with CG-space
|
||||
coordinates when UAZoomEnabled returns true.
|
||||
(ns_update_end): Call UAZoomChangeFocus as fallback after each
|
||||
redisplay cycle to ensure Zoom tracks cursor across window
|
||||
switches (C-x o) where the physical cursor may not be redrawn.
|
||||
|
||||
Coordinate conversion: EmacsView pixels (AppKit, flipped) ->
|
||||
NSWindow -> NSScreen -> CGRect with y-flip for CoreGraphics
|
||||
top-left origin. UAZoomChangeFocus is available since macOS 10.4
|
||||
(ApplicationServices umbrella framework).
|
||||
|
||||
Tested on macOS 14 with Zoom enabled: cursor tracking works across
|
||||
window splits, switches, and normal navigation.
|
||||
---
|
||||
etc/NEWS | 8 ++++++
|
||||
src/nsterm.h | 4 +++
|
||||
src/nsterm.m | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 82 insertions(+)
|
||||
|
||||
diff --git a/etc/NEWS b/etc/NEWS
|
||||
index ef36df5..e80e124 100644
|
||||
--- a/etc/NEWS
|
||||
+++ b/etc/NEWS
|
||||
@@ -82,6 +82,14 @@ other directory on your system. You can also invoke the
|
||||
|
||||
* Changes in Emacs 31.1
|
||||
|
||||
++++
|
||||
+** The macOS NS port now integrates with macOS Zoom.
|
||||
+When macOS Zoom is enabled (System Settings -> Accessibility -> Zoom ->
|
||||
+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.
|
||||
+
|
||||
+++
|
||||
** 'line-spacing' now supports specifying spacing above the line.
|
||||
Previously, only spacing below the line could be specified. The user
|
||||
diff --git a/src/nsterm.h b/src/nsterm.h
|
||||
index 7c1ee4c..f2755e4 100644
|
||||
--- a/src/nsterm.h
|
||||
+++ b/src/nsterm.h
|
||||
@@ -484,6 +484,10 @@ enum ns_return_frame_mode
|
||||
@public
|
||||
struct frame *emacsframe;
|
||||
int scrollbarsNeedingUpdate;
|
||||
+#ifdef NS_IMPL_COCOA
|
||||
+ /* Cached cursor rect for macOS Zoom integration. */
|
||||
+ NSRect lastZoomCursorRect;
|
||||
+#endif
|
||||
NSRect ns_userRect;
|
||||
}
|
||||
|
||||
diff --git a/src/nsterm.m b/src/nsterm.m
|
||||
index 74e4ad5..eb1649b 100644
|
||||
--- a/src/nsterm.m
|
||||
+++ b/src/nsterm.m
|
||||
@@ -1104,6 +1104,34 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
|
||||
|
||||
unblock_input ();
|
||||
ns_updating_frame = NULL;
|
||||
+
|
||||
+#ifdef NS_IMPL_COCOA
|
||||
+ /* Zoom fallback: ensure Zoom tracks the cursor after window
|
||||
+ switches (C-x o) and other operations where the physical cursor
|
||||
+ may not be redrawn but the focused window changed. This uses
|
||||
+ lastZoomCursorRect which was set by ns_draw_window_cursor
|
||||
+ during the current or a previous redisplay cycle. */
|
||||
+#if defined (MAC_OS_X_VERSION_MIN_REQUIRED) \
|
||||
+ && MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
||||
+ if (view && UAZoomEnabled ()
|
||||
+ && !NSIsEmptyRect (view->lastZoomCursorRect))
|
||||
+ {
|
||||
+ NSRect r = view->lastZoomCursorRect;
|
||||
+ 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);
|
||||
+ }
|
||||
+#endif /* MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 */
|
||||
+#endif /* NS_IMPL_COCOA */
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3232,6 +3260,48 @@ 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));
|
||||
|
||||
+#ifdef NS_IMPL_COCOA
|
||||
+ /* Accessibility: store cursor rect for macOS Zoom integration.
|
||||
+ Zoom (System Settings -> Accessibility -> Zoom) tracks a focus
|
||||
+ element to keep the zoomed viewport centered on the cursor.
|
||||
+ UAZoomChangeFocus() informs Zoom of the cursor position after
|
||||
+ every physical cursor redraw.
|
||||
+
|
||||
+ The coordinate conversion chain:
|
||||
+ EmacsView pixels (AppKit, flipped, origin at top-left)
|
||||
+ -> NSWindow coordinates (convertRect:toView:nil)
|
||||
+ -> NSScreen coordinates (convertRectToScreen:)
|
||||
+ -> CGRect (NSRectToCGRect, same values)
|
||||
+ -> CG y-flip (CoreGraphics uses top-left origin on
|
||||
+ the primary screen; AppKit uses bottom-left). */
|
||||
+ {
|
||||
+ EmacsView *view = FRAME_NS_VIEW (f);
|
||||
+ if (view && on_p && active_p)
|
||||
+ {
|
||||
+ view->lastZoomCursorRect = r;
|
||||
+
|
||||
+#if defined (MAC_OS_X_VERSION_MIN_REQUIRED) \
|
||||
+ && MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
|
||||
+ if (UAZoomEnabled ())
|
||||
+ {
|
||||
+ 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);
|
||||
+ }
|
||||
+#endif /* MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 */
|
||||
+ }
|
||||
+ }
|
||||
+#endif /* NS_IMPL_COCOA */
|
||||
+
|
||||
ns_focus (f, NULL, 0);
|
||||
|
||||
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
|
||||
--
|
||||
2.43.0
|
||||
|
||||
Reference in New Issue
Block a user