Skip to content

v2.0.0 — refocused, and built to stay fast

Choose a tag to compare

@github-actions github-actions released this 20 Aug 18:48
· 18 commits to main since this release

ThreeFingerSwitcher 2.0 — refocused, and built to stay fast

2.0 is a breaking release. The on-device AI stack (Gemma/MLX, the AI command band + canvas, background agents, the notch timeline, voice/computer-use), the Files band, and the iPhone↔Mac device link (QR pairing, the local-network clipboard/file bridge, the Hub Devices page) are removed. The app is refocused on what it does best: the three-finger window switcher, the four-finger launcher (with context bands and clipboard history), Dock window previews, and per-app / per-site keyboard language. The full-featured 1.x app stays available on the v1.0.0 release and the v1 branch.

The app no longer gets slower the longer it runs

A long-standing complaint — CPU creeping up over hours, switcher previews refreshing slower, the gesture trigger developing a "needs to wake up" lag — was traced to a family of independent accumulation bugs plus a scheduling posture that let a busy Mac starve the app. All fixed:

  • One trackpad listener, ever. The vendored multitouch framework's own sleep/wake handler double-started trackpad devices, orphaning one running listener per sleep/wake cycle — after N wakes every touch frame was processed N+1 times. The framework's handlers are now neutralized; the app owns sleep/wake.
  • No more stacked preview sweeps, leaked observers, or hidden animation clocks (closing the welcome wizard used to leave a 20 Hz animation ticking forever). Thumbnail caches are LRU and pruned to live windows.
  • A busy Mac can't starve it anymore. The process opts out of App Nap (system sleep unaffected), bounds every Accessibility round-trip to 0.5 s (the OS default is 6 s per call, answered by the other app's main thread), and re-arms its event taps out-of-band if macOS disables them under load.
  • Nothing forks, hits disk, or walks a whole payload on the gesture path. With Space-row switching on, every switcher open used to spawn a /usr/bin/defaults subprocess on the main thread. Clipboard capture no longer hashes the whole payload or fully decodes every image. Launcher icons, blob-backed clipboard previews, Stage Manager state, and the browser's address field are memoized.

Idle CPU should read ~0% indefinitely. If it doesn't, that's a bug — please report it.

Crash and stuck-state fixes

  • Opening the Hub once and closing it could crash every subsequent switcher commit (CGWindowID conversion on the closed window's number).
  • A misbehaving app's Accessibility server could crash the switcher (unguarded type casts on cross-process data).
  • Sleeping the Mac with three fingers on the trackpad could leave the app swallowing every scroll event in every app until quit.
  • Closing Mission Control any way but the app's own gesture left it posting a stray Escape into your app on every later commit.
  • Double-firing a launcher item could open two windows; rapid Space switches could focus the wrong Space's window; a de-minimize could steal focus back from a newer selection.
  • Taps now re-arm automatically when Accessibility is granted mid-session.

Install

Download the DMG below, drag ThreeFingerSwitcher to Applications, launch it, and follow the First Touch wizard. The DMG is Developer-ID-signed and notarized. Upgrading from 1.x in place keeps your permissions and settings.

For developers

The investigation, rejected alternatives, and deferred follow-ups are documented in openspec/changes/fix-progressive-cpu-degradation/; the load-bearing-but-odd-looking pieces are listed in CLAUDE.md → "Progressive-degradation guardrails". 783 unit tests.