From d0cd1f103bca0b2859530b88818ff11a92c4c295 Mon Sep 17 00:00:00 2001 From: Daneel Date: Wed, 25 Feb 2026 20:10:12 +0100 Subject: [PATCH] v7 patch: fix Zoom snapping to old window on C-x o Guard accessibility notifications with on_p && active_p so they only fire when drawing the cursor in the selected window. Without this, ns_draw_window_cursor is called for both old and new windows during redisplay, and UAZoomChangeFocus fires for the old window last. --- ...oundsForRange-for-macOS-Zoom-cursor-.patch | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch b/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch index 186d749..8197cd2 100644 --- a/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch +++ b/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch @@ -1,5 +1,5 @@ From: Martin Sukany -Date: Tue, 25 Feb 2026 19:20:00 +0100 +Date: Tue, 25 Feb 2026 20:10:00 +0100 Subject: [PATCH] ns: implement macOS Zoom cursor tracking and VoiceOver support via UAZoomChangeFocus + NSAccessibility @@ -19,12 +19,10 @@ Add cursor tracking and screen reader support for macOS accessibility: movement), FocusedUIElementChanged (window focus). Ref: https://developer.apple.com/documentation/appkit/nsaccessibilityprotocol -accessibilityFrame returns the view's frame (standard behavior) so -VoiceOver draws its focus ring around the text area. Cursor position -is exposed via accessibilityBoundsForRange: only. - -Both mechanisms are needed: UAZoomChangeFocus serves Zoom; NSAccessibility -serves VoiceOver. Same dual pattern used by iTerm2. +Accessibility notifications are only posted when drawing the cursor in +the active (selected) window (on_p && active_p guard). Without this, +C-x o (other-window) triggers UAZoomChangeFocus for the old window +last, snapping Zoom back to it. --- diff --git a/src/nsterm.h b/src/nsterm.h index 7c1ee4c..6c1ff34 100644 @@ -41,10 +39,10 @@ index 7c1ee4c..6c1ff34 100644 /* AppKit-side interface. */ diff --git a/src/nsterm.m b/src/nsterm.m -index 932d209..2576c96 100644 +index 932d209..e6b1699 100644 --- a/src/nsterm.m +++ b/src/nsterm.m -@@ -3232,6 +3232,72 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. +@@ -3232,6 +3232,77 @@ 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)); @@ -75,7 +73,12 @@ index 932d209..2576c96 100644 + serves macOS Zoom's "Follow keyboard focus" feature. */ + { + EmacsView *view = FRAME_NS_VIEW (f); -+ if (view) ++ /* Only notify AT when drawing the cursor in the active ++ (selected) window. ns_draw_window_cursor is called for ++ all windows during redisplay (to draw or erase cursors); ++ without this guard, C-x o triggers UAZoomChangeFocus for ++ the old window last, snapping Zoom back to it. */ ++ if (view && on_p && active_p) + { + /* Store cursor rect for accessibilityBoundsForRange: queries. */ + view->lastAccessibilityCursorRect = r; @@ -117,7 +120,7 @@ index 932d209..2576c96 100644 ns_focus (f, NULL, 0); NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; -@@ -8237,6 +8303,15 @@ - (void)windowDidBecomeKey /* for direct calls */ +@@ -8237,6 +8308,15 @@ - (void)windowDidBecomeKey /* for direct calls */ XSETFRAME (event.frame_or_window, emacsframe); kbd_buffer_store_event (&event); ns_send_appdefined (-1); // Kick main loop @@ -133,7 +136,7 @@ index 932d209..2576c96 100644 } -@@ -9474,6 +9549,310 @@ - (int) fullscreenState +@@ -9474,6 +9554,310 @@ - (int) fullscreenState return fs_state; }