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
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
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.
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.
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.
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
UAZoomChangeFocus (documented Apple API) + NSAccessibility.
References to official Apple documentation in comments.
Pattern matches iTerm2 implementation.
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.
- Start time prompt: empty = all-day, HH:MM = timed
- End prompt: HH:MM (same day), YYYY-MM-DD (multi-day), YYYY-MM-DD HH:MM
- All formats match what ox-icalendar/org-caldav export correctly
- Set org-icalendar-timezone to Europe/Prague
- Set org-icalendar-with-timestamps to active
- New capture template 'c' creates SCHEDULED entry on selected date
- calfw-org-capture-template set for calfw integration
- Events go to calendar_outbox.org (synced via org-caldav twoway)
- Keybinding: a = add event, RET = open agenda day
- biblio-crossref-lookup doesn't exist; use biblio-lookup (universal)
- biblio-doi: require biblio before biblio-doi (load order fix)
- my/bib-insert-manual: template for 8 entry types with cursor at KEY
- All commands lazy-load biblio via (require 'biblio)
- SPC B s = universal search (prompts for backend: CrossRef/arXiv/DBLP)
- SPC B m = manual entry template
- SPC B D = import by DOI
- setq! for citar-bibliography (Doom custom setter, fixes void variable)
- my/bib-new: create new .bib for a project
- my/bib-import-doi: import reference by DOI
- Per-project: .dir-locals.el or #+BIBLIOGRAPHY: in org header
- SPC B prefix (not SPC b which is buffer)
Reverted to cf4b486 (last known working state), then added:
1. org-caldav-save-directory explicitly set to ~/org/
State files: .org-caldav-<md5hash>.el (one per calendar URL+ID).
Delete them to reset sync state.
2. defadvice around org-caldav-update-events-in-org: condition-case
catches any error (nil fields, retrieval failures) so sync state
is saved and remaining calendars continue.
Removed: Fix#1 (@encoding), Fix#3 (set-sequence-number), @google.com
UID ignore logic — all 775 @google.com events were deleted from server
(backup at daneel:~/caldav-backup-2026-02-25.tar.gz).