#+TITLE: Emacs macOS Build — UAZoom Accessibility Patch #+AUTHOR: Martin Sukaný #+DATE: 2026-02-23 #+STARTUP: overview * Emacs macOS Build s macOS Zoom Accessibility Návod na buildování GNU Emacs pro macOS s patchem pro =UAZoomChangeFocus=, který opravuje sledování kurzoru v macOS Zoom "Follow keyboard focus". ** Kontext macOS Zoom "Follow keyboard focus" ve vanilla GNU Emacs nefunguje. Root cause: Emacs nemá implementovanou NSAccessibility pro vlastní NSView a hlavně nevolá =UAZoomChangeFocus()= z =HIServices/UniversalAccess.h=. Patch je v repozitáři [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]] v =patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch=. ** Prerekvizity #+begin_src sh # Xcode Command Line Tools xcode-select --install # Homebrew závislosti brew install autoconf libgmp texinfo pkg-config gnutls libxml2 \ jansson tree-sitter librsvg imagemagick # Volitelné ale doporučené brew install libgccjit # native compilation #+end_src ** Stažení zdrojů #+begin_src sh git clone https://github.com/emacs-mirror/emacs.git cd emacs # Doporučená stable větev (aktuálně emacs-30) git checkout emacs-30 #+end_src ** Aplikace accessibility patche #+begin_src sh # Stáhni patch z martin/emacs-doom git clone https://git.apps.sukany.cz/martin/emacs-doom.git /tmp/emacs-doom-config # Aplikuj patch git am /tmp/emacs-doom-config/patches/0001-ns-implement-AXBoundsForRange-for-macOS-Zoom-cursor-.patch # Ověř aplikaci grep "UAZoomChangeFocus" src/nsterm.m | head -3 #+end_src Patch implementuje: - =UAZoomChangeFocus()= — přímé volání Zoom API po každém pohybu kurzoru - =NSAccessibilitySelectedTextChangedNotification= — standardní AX notifikace - =NSAccessibilityFocusedUIElementChangedNotification= — notifikace při focusu - =accessibilityBoundsForRange:= — nová NSAccessibilityProtocol API - =AXBoundsForRange= — starší fallback API - =NSAccessibilityTextAreaRole= — správná role pro Emacs view ** Konfigurace a Build #+begin_src sh ./autogen.sh ./configure \ --with-ns \ --with-tree-sitter \ --with-gnutls \ --with-xml2 \ --with-json \ --with-imagemagick \ --with-rsvg \ --with-mailutils \ --without-x \ --without-dbus \ CFLAGS="-O2 -g3" # Build — -j počet CPU jader make -j$(sysctl -n hw.ncpu) # Vytvoří nextstep/Emacs.app make install #+end_src *** Volitelně: s native compilation (rychlejší Emacs) #+begin_src sh ./configure \ --with-ns \ --with-native-compilation=aot \ --with-tree-sitter \ --with-gnutls \ --with-xml2 \ --with-json \ --without-x \ CFLAGS="-O2 -g3" #+end_src ** Instalace #+begin_src sh # Přesuň Emacs.app do /Applications cp -r nextstep/Emacs.app /Applications/Emacs.app # Vytvoř wrapper script (NE symlink — Emacs nenajde data přes symlink) sudo tee /usr/local/bin/emacs << 'EOF' #!/bin/sh exec /Applications/Emacs.app/Contents/MacOS/Emacs "$@" EOF sudo chmod +x /usr/local/bin/emacs # Ověření emacs --version #+end_src *** Proč wrapper script, ne symlink Symlink (/usr/local/bin/emacs → .../Emacs.app/Contents/MacOS/Emacs) nefunguje správně. Emacs počítá cesty k Lisp souborům z =argv[0]=, ne přes resolved symlink. Výsledkem jsou chyby: #+begin_example Warning: arch-dependent data dir 'Contents/MacOS/libexec/': No such file or directory Warning: Lisp directory 'Contents/Resources/lisp': No such file or directory #+end_example Wrapper script předává správnou cestu. ** macOS Accessibility nastavení Po každém novém buildu (nový binary) je potřeba znovu udělit permission: 1. System Settings → Privacy & Security → Accessibility 2. Přidat nové =/Applications/Emacs.app= 3. Zapnout toggle Bez tohoto kroku =UAZoomChangeFocus()= neovlivní Zoom viewport. ** Doom Emacs sync #+begin_src sh # Po instalaci ~/.emacs.d/bin/doom sync # Pokud doom hledá emacs v jiné cestě which emacs # musí vrátit /usr/local/bin/emacs emacs --version #+end_src ** Ověření Zoom funkcionality 1. System Settings → Accessibility → Zoom → zapnout "Use keyboard shortcut to zoom" 2. Zoom mode: Full Screen nebo Split Screen 3. Advanced → Zoom follows: =Keyboard focus= 4. Otevři Emacs, začni psát 5. Zoom viewport by měl sledovat kurzor ** Časté problémy | Problém | Příčina | Řešení | |---|---|---| | doom sync: "emacs not found" | Wrapper script chybí nebo není v PATH | Viz sekce Instalace | | Zoom nesleduje kurzor | Accessibility permission chybí | Přidat Emacs.app znovu do Privacy & Security | | Zoom nesleduje kurzor | Patch nebyl aplikován | Ověřit: =grep UAZoomChangeFocus src/nsterm.m= | | Build selže na nsterm.m | Chybí Xcode CLT nebo závislosti | =xcode-select --install= + brew install | | "Contents/MacOS/libexec not found" | Symlink místo wrapper scriptu | Nahradit wrapper scriptem | ** Reference - Patch repo: [[https://git.apps.sukany.cz/martin/emacs-doom][martin/emacs-doom]] - Ghostty issue (stejný problém): https://github.com/nicowillis/Ghostty/issues/4053 - iTerm2 implementace: =PTYTextView.m:refreshAccessibility= - Chromium implementace: =render_widget_host_view_mac.mm:OnSelectionBoundsChanged=