Commit Graph

423 Commits

Author SHA1 Message Date
31e452ed5c v15.5: VoiceOver cursor tracking — setAccessibilitySelectedTextRange, interaction mode, completions announcement
1. setAccessibilitySelectedTextRange: — enables bidirectional cursor
   sync. Converts AX index to buffer charpos, moves point via
   SET_PT_BOTH. VoiceOver can now place cursor in text interaction mode.

2. setAccessibilityFocused: — handles VO+Shift+Down interaction entry.
   Ensures NS window focus, posts SelectedTextChanged so VoiceOver
   reads current line.

3. Completions announcement — when point changes in a non-focused
   buffer (e.g. *Completions* during Tab), posts
   AnnouncementRequestedNotification with the current line text.
   VoiceOver speaks the selected completion while minibuffer keeps focus.
2026-02-26 15:16:44 +01:00
Martin Sukany
68eb568810 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 14:54:07 +01:00
f961f46b9a v15.4: comprehensive VoiceOver fix — 9 bugs from 4-reviewer audit
P0 fixes (critical):
- accessibilityRangeForLine: include trailing newline — fixes
  zero-length ranges for empty lines causing 'end of text'
- accessibilityVisibleCharacterRange: return full buffer range —
  VoiceOver was treating visible window boundary as end of text
- ensureTextCache: invalidate when point moves outside cached region
  (stale cachedTextStart after scrolling without editing)
- ns_ax_frame_for_range: use row->height not visible_height, clip
  to text area — fixes VoiceOver cursor bleeding into adjacent lines

P1 fixes (important):
- Post SelectedTextChanged after FocusedUIElementChanged on focus
  acquisition (windowDidBecomeKey) and window switch (C-x o)
- Post LayoutChangedNotification after tree rebuild
- accessibilityRangeForIndex: rangeOfComposedCharacterSequenceAtIndex
  for emoji/combining marks
- Buffer accessibilityFrame excludes mode line height
- New elements init cachedPoint/cachedModiff=-1 to force first
  notification

Reviewed by: architect + 3 reviewers (text, notifications, frames)
2026-02-26 14:53:47 +01:00
Martin Sukany
a2c9911171 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 14:32:25 +01:00
fd523f501f v15.3: fix VoiceOver cursor not following during typing
Root cause (confirmed via WebKit/Chromium source): ValueChanged (edit)
and SelectedTextChanged (cursor move) are MUTUALLY EXCLUSIVE — apps
must never send both for the same user action. VoiceOver enters
'typing mode' on Edit notifications and suppresses/ignores concurrent
SelectionMove notifications, causing the cursor to appear stuck.

Fix: (1) Update cachedPoint inside the modiff branch so the
selection-move check doesn't trigger for edit-caused point changes.
(2) Change 'if' to 'else if' for explicit mutual exclusion.

Source: WebKit AXObjectCacheMac.mm — postTextStateChangePlatformNotification
vs postTextSelectionChangePlatformNotification are separate code paths
that never fire for the same event.
2026-02-26 14:32:19 +01:00
Martin Sukany
cd53ce26cc Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 14:13:03 +01:00
9d963a6ab1 v15.2: fix all AXTextStateChange enum values (off-by-one from Unknown=0)
Root cause: Apple's AXTextStateChange enums start with Unknown=0,
shifting all named constants by +1 vs our values. WebKit source
(AXObjectCacheMac.mm) confirms:
- kAXTextStateChangeTypeEdit = 1 (was 0)
- kAXTextStateChangeTypeSelectionMove = 2 (was 1)
- kAXTextSelectionDirectionPrevious = 3 (was 2)
- kAXTextSelectionDirectionNext = 4 (was 3)
- kAXTextSelectionDirectionDiscontiguous = 5 (was 4)
- kAXTextSelectionGranularityCharacter = 1 (was 0)
- kAXTextSelectionGranularityLine = 3 (was 2)

Typing echo worked by coincidence (kAXTextEditTypeTyping=3 unchanged).
SelectionMove=1 mapped to Edit, so VoiceOver ignored cursor movement.

Completions two-line reading is expected (columnar buffer layout).
2026-02-26 14:11:16 +01:00
Martin Sukany
5ded624f7b Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 13:51:11 +01:00
cd48418a3c v15.1: fix freeze on window split, C-n/C-p cursor tracking, new window detection
- Re-entrance guard (accessibilityUpdating) prevents infinite recursion
  when VoiceOver callbacks trigger redisplay during notification posting
- Detect window tree change via FRAME_ROOT_WINDOW comparison; rebuild
  tree BEFORE iterating elements (prevents accessing freed windows)
- Validate window+buffer pointers before posting notifications
- Dynamic direction (Previous/Next/Discontiguous) and granularity
  (Character/Line) in SelectedTextChanged notifications based on
  actual point movement — fixes C-n/C-p not moving VoiceOver cursor
- New windows (completions, splits) detected via lastRootWindow change
2026-02-26 13:43:34 +01:00
Martin Sukany
6d185c880a Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 13:27:31 +01:00
64c40f4867 v15: fix w->start_charpos -> marker_position(w->start), remove unused line_start 2026-02-26 13:27:15 +01:00
Martin Sukany
05fc543958 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 13:22:44 +01:00
0dbcde3acb v15: fix missing @synthesize in patch (re-staged from working tree) 2026-02-26 13:21:49 +01:00
Martin Sukany
5b12e8c435 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 12:58:04 +01:00
b7c750ff71 v15: regenerate patch from git diff (fix corrupt hunk headers) 2026-02-26 12:57:44 +01:00
Martin Sukany
be642808cc Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 12:56:54 +01:00
046ea8cf7e v15: add @synthesize for MRC ivar access (no underscore prefix) 2026-02-26 12:56:23 +01:00
Martin Sukany
fd03f2e7c4 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 12:51:36 +01:00
0570ee6717 v15: fix patch paths (src/nsterm.*), replace into original patch file 2026-02-26 12:51:02 +01:00
Martin Sukany
bfe29f8da8 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 12:49:37 +01:00
bc3731112f v15: buffer-relative accessibility rewrite (patch file)
Complete rewrite from glyph-based (v14) to buffer-relative design:
- ns_ax_buffer_text() with BUF_BEGV/ZV/PT, 100KB cap
- EmacsAccessibilityBuffer (AXTextArea per window)
- EmacsAccessibilityModeLine (AXStaticText per mode line)
- Enum fix: Edit=0, SelectionMove=1
- Text cache by BUF_MODIFF
- Tree rebuild on window config change only
- Minibuffer included
- Zoom code preserved (UAZoomChangeFocus)
- 1142 lines (nsterm.h +47, nsterm.m +1017)
2026-02-26 12:47:33 +01:00
Martin Sukany
6724922592 Merge remote-tracking branch 'refs/remotes/origin/master' 2026-02-26 11:58:23 +01:00
8849a726a3 ns: fix VoiceOver cursor sync — 8 changes from pipeline review
Changes applied (from vo-cursor pipeline review, 7 workers):

1. (Change 8) Add ns_ax_index_for_charpos helper, refactor
   ns_ax_index_for_point as thin wrapper — shared coordinate
   mapping for all accessibility attribute methods.

2. (Change 1) Remove Site A notifications from ns_draw_window_cursor.
   Eliminates duplicate VoiceOver notifications (Site A + Site B both
   fired for same events). Zoom cursor tracking (UAZoomChangeFocus)
   preserved.

3. (Change 7) Remove redundant bare ValueChanged before rich
   userInfo version in postAccessibilityUpdatesForWindow:.

4. (Change 2) Fix typing echo character extraction to use glyph-based
   index (ns_ax_index_for_point) instead of buffer-relative
   (pt - BUF_BEGV - 1).

5. (Change 3) Add AXTextStateChangeType:@2 (SelectionMove) userInfo
   to SelectedTextChanged notification for cursor movement —
   enables VoiceOver line-by-line reading on arrow keys.

6. (Change 4) Fix accessibilityRangeForPosition: to return
   glyph-based index via ns_ax_index_for_charpos instead of
   buffer-relative (charpos - BUF_BEGV).

7. (Change 5) Fix accessibilitySelectedTextRange mark branch to use
   ns_ax_index_for_charpos for both endpoints instead of mixing
   glyph-based point with buffer-relative mark.

8. Remove 10 redundant text methods from EmacsView (Group role
   should not expose text attributes — eliminates coordinate
   system divergence with EmacsAccessibilityBuffer).

9. Fix MRC leak: release EmacsAccessibilityBuffer after addObject:
   in ns_ax_collect_windows.

10. Remove dead lastAccessibilityModiff ivar (was only used by
    removed Site A).

Enum values verified from WebKit AXTextStateChangeIntent.h:
  AXTextStateChangeTypeEdit = 1
  AXTextStateChangeTypeSelectionMove = 2
  AXTextEditTypeTyping = 3
2026-02-26 11:58:03 +01:00
e40d502d43 ns: fix VoiceOver cursor sync — 8 changes from pipeline review
Changes applied (from vo-cursor pipeline review, 7 workers):

1. (Change 8) Add ns_ax_index_for_charpos helper, refactor
   ns_ax_index_for_point as thin wrapper — shared coordinate
   mapping for all accessibility attribute methods.

2. (Change 1) Remove Site A notifications from ns_draw_window_cursor.
   Eliminates duplicate VoiceOver notifications (Site A + Site B both
   fired for same events). Zoom cursor tracking (UAZoomChangeFocus)
   preserved.

3. (Change 7) Remove redundant bare ValueChanged before rich
   userInfo version in postAccessibilityUpdatesForWindow:.

4. (Change 2) Fix typing echo character extraction to use glyph-based
   index (ns_ax_index_for_point) instead of buffer-relative
   (pt - BUF_BEGV - 1).

5. (Change 3) Add AXTextStateChangeType:@2 (SelectionMove) userInfo
   to SelectedTextChanged notification for cursor movement —
   enables VoiceOver line-by-line reading on arrow keys.

6. (Change 4) Fix accessibilityRangeForPosition: to return
   glyph-based index via ns_ax_index_for_charpos instead of
   buffer-relative (charpos - BUF_BEGV).

7. (Change 5) Fix accessibilitySelectedTextRange mark branch to use
   ns_ax_index_for_charpos for both endpoints instead of mixing
   glyph-based point with buffer-relative mark.

8. Remove 10 redundant text methods from EmacsView (Group role
   should not expose text attributes — eliminates coordinate
   system divergence with EmacsAccessibilityBuffer).

9. Fix MRC leak: release EmacsAccessibilityBuffer after addObject:
   in ns_ax_collect_windows.

10. Remove dead lastAccessibilityModiff ivar (was only used by
    removed Site A).

Enum values verified from WebKit AXTextStateChangeIntent.h:
  AXTextStateChangeTypeEdit = 1
  AXTextStateChangeTypeSelectionMove = 2
  AXTextEditTypeTyping = 3
2026-02-26 11:44:13 +01:00
946b138a0a v14.1: post notifications on focused virtual element, not EmacsView
Root cause of typing echo + cursor movement failure:
VoiceOver tracks the focused element (EmacsAccessibilityBuffer, AXTextArea).
Notifications from EmacsView (AXGroup) were ignored because VoiceOver
doesn't monitor non-focused elements for text changes.

Fix: ns_draw_window_cursor now calls [view accessibilityFocusedUIElement]
to find the right EmacsAccessibilityBuffer, and posts ValueChanged +
SelectedTextChanged on IT instead of on the view.

Also: postAccessibilityUpdatesForWindow now uses [self accessibilityStringForRange:]
instead of [view accessibilityStringForRange:] for typing echo text.
2026-02-26 10:47:12 +01:00
8fbdb2406d v14: fix VoiceOver virtual tree plumbing (based on Chromium analysis)
Root cause: VoiceOver ignored our virtual elements because they were
missing critical hierarchy metadata.  Chromium's AXPlatformNodeCocoa
(also an NSAccessibilityElement subclass) works because it provides
all of these.  Fixes based on VS Code/Chromium analysis:

1. Add accessibilityWindow + accessibilityTopLevelUIElement on base class
   (EmacsAccessibilityElement) — VoiceOver needs these to associate
   notifications with a window context
2. Add accessibilityParent on base class — unbroken chain to EmacsView
3. Add isAccessibilityFocused on EmacsAccessibilityBuffer — returns YES
   for active buffer
4. Post FocusedUIElementChangedNotification in windowDidBecomeKey —
   tells VoiceOver to start tracking the virtual element on app focus
5. Remove duplicate isAccessibilityFocused, deduplicate accessibilityParent
6. Keep all v13.3 features: Zoom, typing echo, full text protocol
2026-02-26 10:20:03 +01:00
ce31b94bb9 revert to v9 patch - virtual tree broke VoiceOver text interaction
v13 virtual element tree (EmacsAccessibilityBuffer) broke:
- typing echo (VoiceOver ignores notifications from virtual elements)
- buffer reading (AXGroup role on EmacsView confused VoiceOver)
- text navigation (dual text protocol = conflicting responses)

Reverting to v9 which has confirmed working:
- Zoom cursor tracking (UAZoomChangeFocus)
- typing echo (rich ValueChanged on EmacsView)
- buffer reading (accessibilityValue on AXTextArea)

Window detection (the only v13 improvement) not worth the regression.
2026-02-26 09:30:49 +01:00
ebf611bf19 v13.3: restore typing echo + add full text protocol on EmacsView
Key changes:
- Typing echo notifications back in ns_draw_window_cursor (on EmacsView,
  synchronous with cursor draw — this is how v9 did it and it worked)
- Rich userInfo: AXTextEditType=3, AXTextChangeValues with actual char
- SelectedTextChangedNotification on every cursor draw
- Full text protocol on EmacsView: accessibilityNumberOfCharacters,
  accessibilitySelectedText, accessibilityInsertionPointLineNumber,
  accessibilityVisibleCharacterRange, accessibilityLineForIndex:,
  accessibilityRangeForLine:, accessibilityAttributedStringForRange:
- accessibilityAttributedStringForRange: on EmacsAccessibilityBuffer too
- Virtual tree kept for VoiceOver window/buffer detection
2026-02-26 09:23:39 +01:00
f41fe14772 v13.2: fix protected ivar access (@public for lastAccessibilityCursorRect) 2026-02-26 09:09:09 +01:00
46265bdaa6 v13.2 patch: restore Zoom cursor tracking + fix MRC + fix typing echo
- Restore UAZoomChangeFocus() in ns_draw_window_cursor (was missing in v13)
- Restore accessibilityBoundsForRange: on EmacsView (Zoom queries the view)
- Restore legacy parameterized attribute APIs (Zoom uses these)
- Add lastAccessibilityCursorRect ivar for cursor position tracking
- Fix typing echo: AXTextEditType=3 (not 0), add AXTextChangeValues array
- Keep virtual element tree (EmacsAccessibilityBuffer) for VoiceOver
- MRC fixes: retain/release for accessibilityElements array
2026-02-26 09:03:10 +01:00
e5bfce500f v13 patch: fix MRC retain/release for accessibilityElements array
- arrayWithCapacity: returns autorelease object, must retain for ivar
- Release old array before reassigning in rebuildAccessibilityTree
- Release in EmacsView dealloc
- Fixes crash: _NSPasteboardTypeCache countByEnumeratingWithState (dangling pointer)
2026-02-26 08:52:46 +01:00
e152900004 v13 patch: fix MRC weak property error (unsafe_unretained) 2026-02-26 08:46:34 +01:00
60afee0aec v13 patch: VoiceOver virtual accessibility tree
Complete rewrite of accessibility support. Instead of flat AXTextArea
on EmacsView, implements proper tree with virtual elements:

  EmacsWindow (AXWindow)
  └── EmacsView (AXGroup)
      ├── EmacsAccessibilityBuffer (AXTextArea) — window 1
      ├── EmacsAccessibilityBuffer (AXTextArea) — window 2
      └── ...

Each EmacsAccessibilityBuffer maps to one Emacs window and exposes:
- Buffer text via glyph row iteration (accurate, handles overlays)
- Visual line navigation (glyph_row vpos)
- Cursor tracking with glyph charpos mapping
- Hit testing (accessibilityRangeForPosition:)
- Selection range with active mark
- Screen geometry via pixel coordinate conversion
- Rich typing echo (kAXTextEditTypeTyping userInfo)
- UAZoomChangeFocus for Zoom

Dynamic tree rebuilt on each redisplay cycle from FRAME_ROOT_WINDOW.
Notifications on correct virtual elements (not container view).

3 review cycles (scores: 62 → 68 → 82), plus manual fixes for
hit testing and selection range.
2026-02-25 23:26:59 +01:00
f5ecc44871 revert to v9 patch while deep accessibility rewrite in progress
v10-v12 made VoiceOver worse. Reverting to v9 (Zoom works, typing echo works).
Full accessibility tree implementation in progress.
2026-02-25 22:41:28 +01:00
2c78f04089 v12 patch: visual line numbering for VoiceOver (3 iterations)
Root cause: all accessibility line methods used count_lines (logical/
newline-counting), but VoiceOver compares line numbers before/after
cursor movement. Wrapped lines had same logical line number, so VO
fell back to reading single characters instead of full lines.

Fix: replaced count_lines/find_newline_no_quit with compute_motion/
vmotion (visual screen lines) in all three methods. Matches iTerm2's
approach of returning screen rows.

Changes from v11:
- accessibilityInsertionPointLineNumber: compute_motion visual lines
- accessibilityLineForIndex: compute_motion visual lines
- accessibilityRangeForLine: vmotion for line start/end
- SelectedRowsChanged only on visual line change (new ivar tracking)
- accessibilityLabel returns buffer name for window switch
- No double ValueChanged on edits (content_changed flag)
- Trailing newline stripped from line ranges
- compute_motion width=-1 for consistency with vmotion

3 pipeline iterations, scores: 78 → 92 → 95
2026-02-25 22:13:28 +01:00
2f1fbd30d2 v11 patch: fix VoiceOver cursor movement (iTerm2 pattern)
Key insight from iTerm2 analysis: VoiceOver does NOT need rich userInfo
on SelectedTextChanged for cursor movement. Bare notifications + correct
protocol methods (accessibilityStringForRange:, accessibilityLineForIndex:,
accessibilityRangeForLine:) are sufficient. Rich userInfo with wrong values
was likely causing VoiceOver to silently discard notifications.

Changes from v10:
- SelectedTextChanged: bare notification (removed rich userInfo)
- Added SelectedRowsChanged + SelectedColumnsChanged (iTerm2 triple pattern)
- Added bare ValueChanged on every cursor draw (not just edits)
- Fixed current_buffer safety: BUF_BYTE_ADDRESS, set_buffer_internal_1
- Added accessibilityRangeForIndex:, accessibilitySelectedTextRanges,
  isAccessibilityFocused, accessibilityLabel
2026-02-25 21:42:20 +01:00
54183cc8eb v10 patch: rich SelectedTextChanged for VoiceOver cursor movement
Key changes from v9:
- SelectedTextChanged now includes rich userInfo:
  direction (Next/Previous/Discontiguous) and
  granularity (Character/Word/Line) inferred from
  old vs new cursor position comparison
- Track lastAccessibilityCursorPos + lastAccessibilityCursorLine
  ivars for position delta detection
- accessibilityInsertionPointLineNumber: buffer lines (count_lines)
  instead of visual vpos
- accessibilityLineForIndex: buffer lines via count_lines
- accessibilityRangeForLine: buffer lines via find_newline_no_quit
- Skip notification on unchanged position (avoids VO repeating)
- Word granularity heuristic: same line, >1 char delta
2026-02-25 21:14:08 +01:00
01ea5d1f0a v9 patch: fix macOS 26 SDK compilation error
Replace extern NSString* declarations with raw string literals
(@"AXTextStateChangeType" etc.) to avoid redeclaration type conflict
with NSAccessibilityConstants.h on macOS 26 Tahoe SDK where these
symbols were added to public headers.
2026-02-25 20:49:12 +01:00
5529418b48 v8 patch: full VoiceOver support with typing echo + reviewer fixes
New in v8:
- Rich typing echo via NSAccessibilityPostNotificationWithUserInfo
  with kAXTextEditTypeTyping userInfo (WebKit pattern)
- BUF_MODIFF tracking: content edit -> ValueChanged, cursor move -> SelectedTextChanged only
- Parameterized text navigation: lineForIndex, rangeForLine, frameForRange,
  attributedStringForRange, rangeForPosition (stub)

Reviewer fixes applied:
- Fix multibyte byte_range cap (use buf_charpos_to_bytepos, not hardcoded 10000)
- Fix legacy BoundsForRange to use actual parameter instead of NSMakeRange(0,0)
- Move extern NSString* declarations to file scope

Review score: 82 -> fixes applied.
2026-02-25 20:37:14 +01:00
d0cd1f103b 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.
2026-02-25 20:10:12 +01:00
15a7c927f4 v6 patch: fix VoiceOver double cursor + add typing echo
Fixes:
1. accessibilityFrame now returns view frame (not cursor rect) - fixes
   VoiceOver drawing duplicate cursor overlay
2. Added NSAccessibilityValueChangedNotification - enables VoiceOver
   typing echo (character-by-character feedback when typing)
3. Cursor position exposed only via accessibilityBoundsForRange:

Full VoiceOver text protocol retained (accessibilityValue,
accessibilitySelectedText, accessibilityStringForRange:, etc).
2026-02-25 19:01:25 +01:00
4e34114fc8 v5 patch: full VoiceOver support + Zoom cursor tracking
Added full NSAccessibility text protocol for VoiceOver:
- accessibilityValue (buffer text, capped at 10k chars)
- accessibilitySelectedText (active region)
- accessibilitySelectedTextRange (cursor position)
- accessibilityInsertionPointLineNumber
- accessibilityVisibleCharacterRange
- accessibilityStringForRange:
- accessibilityAttributeValue: delegating to modern methods
Plus legacy parameterized attributes (StringForRange, BoundsForRange).

UAZoomChangeFocus retained for Zoom 'Follow keyboard focus'.
2026-02-25 18:45:48 +01:00
2a58436f32 v4 patch: dual UAZoomChangeFocus + NSAccessibility, with Apple doc refs
UAZoomChangeFocus is Apple's documented API for Zoom focus control.
NSAccessibility serves VoiceOver and other AT tools.
Both are needed - same approach as iTerm2.
References Apple developer documentation URLs in comments.
2026-02-25 18:20:55 +01:00
d7aae4b7d1 v4 patch: UAZoomChangeFocus (Apple documented) + NSAccessibility, with doc refs
Based on verified research:
- UAZoomChangeFocus IS officially documented by Apple (UniversalAccess.h)
- iTerm2 uses UAZoomChangeFocus for Zoom tracking (PTYTextView.m)
- NSAccessibility alone insufficient for Zoom custom view tracking
- Added Apple documentation URLs in code comments
2026-02-25 18:17:53 +01:00
6933d8f9c0 v4 patch: dual mechanism with Apple doc references
UAZoomChangeFocus (documented Apple API) + NSAccessibility.
References to official Apple documentation in comments.
Pattern matches iTerm2 implementation.
2026-02-25 18:11:05 +01:00
f3b8ff661c v3 patch: NSAccessibility-only, drop UAZoomChangeFocus per reviewer feedback 2026-02-25 17:50:04 +01:00
Martin Sukany
8a8e71764d update 2026-02-25 17:09:08 +01:00
a234ded3db Rewrite Zoom a11y patch: NSAccessibility primary, UAZoomChangeFocus supplementary
Key changes:
- Add accessibilityFrame on EmacsView returning cursor screen rect
  (the standard mechanism used by Terminal.app, iTerm2, Firefox)
- Guard UAZoomChangeFocus with bundleIdentifier check (bare binaries
  are silently ignored by the window server)
- Extensive English comments explaining both mechanisms
- Deduplicate legacy parameterized attribute via accessibilityBoundsForRange:

Root cause of Stéphane's failure: UAZoomChangeFocus communicates via the
window server which identifies apps by CFBundleIdentifier. Bare binaries
(src/emacs, symlinks) have no bundle ID and are ignored. NSAccessibility
notifications + accessibilityFrame work for ALL launch methods.
2026-02-25 17:02:40 +01:00
2313fd52c9 calfw capture: use format-time-string for day-of-week (Emacs 31 compat) 2026-02-25 16:00:36 +01:00
02ad895dd6 calfw capture: use nth for date extraction (avoid calendar-extract dependency) 2026-02-25 15:58:55 +01:00