https://github.com/grepsedawk/i3wm-osx
https://github.com/grepsedawk/i3wm-osx
Last synced: 14 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/grepsedawk/i3wm-osx
- Owner: grepsedawk
- Created: 2026-05-07T15:25:19.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-07T16:57:34.000Z (about 2 months ago)
- Last Synced: 2026-05-07T17:38:11.855Z (about 2 months ago)
- Language: Swift
- Size: 43 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# i3wm-osx
A tiling window manager for macOS that reads i3 config files and behaves like i3wm.
## Install via Homebrew
```bash
brew tap grepsedawk/tap
brew install i3wm-osx
mkdir -p ~/.config/i3wm-osx
cp "$(brew --prefix)/etc/i3wm-osx/config.example" ~/.config/i3wm-osx/config
brew services start i3wm-osx # autostart on login
# or one-shot: open "$(brew --prefix)/opt/i3wm-osx/i3wm-osx.app"
```
This installs a prebuilt, signed `.app` bundle at `$(brew --prefix)/opt/i3wm-osx/`.
The signing identity is stable across releases, so Accessibility / Input
Monitoring grants survive `brew upgrade`. First launch needs those permissions
granted to the bundle — see [Permissions](#permissions).
> ⚠️ Apple Silicon only for now (`depends_on arch: :arm64`). Intel users
> need the [manual build](#manual-build).
>
> ⚠️ Gatekeeper will warn "unidentified developer" on first launch (the cert
> is self-signed, not from Apple). Right-click the bundle in Finder → Open,
> then click Open in the dialog. Subsequent launches go through silently.
## Status
**Early prototype.** Targets the [grepsedawk i3 config](https://github.com/grepsedawk/.dotfiles/blob/master/.i3/config) as its compatibility benchmark.
What works:
- Tree-based tiling (splith, splitv, tabbed, stacking) with i3 layout semantics
- Numbered workspaces with `workspace_auto_back_and_forth`
- Multi-monitor "outputs"
- i3 config parser: `set $var`, `bindsym`, `exec[_always]`, `for_window`, `mode`, gaps, colors, `floating_modifier`, bar block
- i3 command parser/executor for: `focus`, `move`, `split`, `layout`, `workspace`, `kill`, `exec`, `fullscreen`, `floating`, `gaps`, `mode`, `resize`, `reload`, `restart`, `exit`
- Global hotkeys via `CGEventTap` (Mod4 → Command, Mod1 → Option)
- i3 IPC over UNIX socket with `i3-msg` companion CLI (`RUN_COMMAND`, `GET_WORKSPACES`, `GET_OUTPUTS`, `GET_TREE`, `GET_VERSION`)
- Status bar across the top of every monitor with workspace pills + status command output (Dracula theme)
- Floating windows toggle, smart gaps, inner/outer gaps
What doesn't work yet:
- Scratchpad
- Marks / `[con_mark=…]` criteria
- Stacking layout titlebars are minimal
- Window borders (we set `default_border none`, which matches the target config)
- `move scratchpad`, `sticky`, `urgent` hint
## Manual build
```bash
# 1. One-time: create a self-signed code-signing identity so macOS TCC
# remembers your Accessibility / Input Monitoring grant across rebuilds.
# Without this, every `swift build` changes the binary's cdhash and macOS
# re-prompts you to grant access. macOS will ask for your login keychain
# password during this step.
./setup-signing.sh
# 2. Build & package as a proper .app so TCC has a stable identity to grant.
./build-app.sh # produces build/i3wm-osx.app
# 3. Drop a config file (i3 syntax). This file is intentionally separate
# from ~/.i3/config — modifier defaults, available exec commands, and
# special keys differ on macOS.
mkdir -p ~/.config/i3wm-osx
cp examples/config-macos ~/.config/i3wm-osx/config
```
## Permissions
On first launch, macOS pops a dialog asking for **Accessibility** access — click "Open System Settings" and toggle i3wm-osx on. Then do the same for **Input Monitoring** (needed for global hotkeys). The daemon polls every 2s and re-bootstraps as soon as both are granted, so you don't need to restart it.
If you previously granted Accessibility to your terminal (Alacritty, iTerm, Terminal, etc.) by mistake, **remove that entry** — TCC won't auto-clean it, and a wrongly-granted terminal will make the prompt name *that* app every time you launch from a shell.
## Running
```bash
# Brew install:
open "$(brew --prefix)/opt/i3wm-osx/i3wm-osx.app"
# Manual build:
open build/i3wm-osx.app
# or with stderr visible:
build/i3wm-osx.app/Contents/MacOS/i3wm-osx
```
The first thing the daemon prints to stderr is a diagnostic block telling you what's working:
```
[i3wm-osx] Accessibility trust: GRANTED
[i3wm-osx] screens: 2 — Built-in Retina Display, Studio Display
[i3wm-osx] scanned: 17 windows across 2 output(s)
[i3wm-osx] hotkey tap: INSTALLED
[i3wm-osx] bar windows: 2
[i3wm-osx] IPC listening on /tmp/i3wm-osx-alex.sock
```
If trust is DENIED and you grant it after launch, the daemon polls every 2 seconds and re-bootstraps automatically — you don't need to restart it.
## Notes on the config
i3 conventions are preserved as written:
| i3 keyword | macOS modifier (default) |
|------------------|-----------------------------------------------|
| `Mod4` / `super` | ⌥ Option (override via `I3WM_OSX_MOD4=command`) |
| `Mod1` | ⌥ Option (override via `I3WM_OSX_MOD1=command`) |
| `cmd` / `command`| ⌘ Command |
| `option` / `alt` | ⌥ Option |
| `Control` | ⌃ Control |
| `Shift` | ⇧ Shift |
Valid override values: `command`, `option`, `control`, `shift`. Set via env var when launching, e.g. `I3WM_OSX_MOD4=command open build/i3wm-osx.app`.
Linux-only commands like `pactl`, `rofi`, `xmodmap` will simply fail to exec; replace them with macOS equivalents in your config (e.g. `osascript`, `choose`, etc.).
## Scripts
- `setup-signing.sh` — one-time. Mints a self-signed code-signing identity so the `.app` keeps a stable cdhash across rebuilds. Without it, every rebuild invalidates your TCC grants.
- `build-app.sh` — main build path. Compiles via SwiftPM, assembles `build/i3wm-osx.app`, codesigns with the identity from `setup-signing.sh` (or ad-hoc with a warning).
- `scripts/dev-run.sh` — dev convenience. `swift build -c release` + execs the bare binary against `~/.i3/config` (or the bundled example). Skips the `.app` bundle, so it does **not** get TCC permissions — useful only when iterating on code that doesn't need AX.
- `scripts/macos-tune-animations.sh on|off` — disables (or restores) macOS-wide window/Dock animations so workspace switches feel like i3 on Linux. Affects every app, not just i3wm-osx.
## Releases
- `.github/workflows/release.yml` — on `v*` tag push, builds `.app` on macOS-14 (arm64), signs with the `i3wm-osx-ci` cert imported from `MACOS_CERT_BASE64` / `MACOS_CERT_PASSWORD` GH secrets, tarballs with the bundled config example, attaches to the GH release. The Homebrew formula at [grepsedawk/homebrew-tap](https://github.com/grepsedawk/homebrew-tap) installs that prebuilt artifact — same cdhash for every user, so TCC grants persist across `brew upgrade`.
## Architecture
- `App.swift` — top-level coordinator
- `AX.swift` / `Window.swift` — Accessibility API wrappers
- `Tree.swift` — i3-style container tree with layout computation
- `WindowManager.swift` — observes new windows, places them in the tree, applies layouts
- `Workspace.swift` — workspaces and outputs (monitors)
- `Config.swift` — i3 config parser
- `Commands.swift` — i3 command parser and executor
- `Hotkey.swift` — CGEventTap-based global hotkey daemon
- `IPC.swift` — i3 IPC server
- `Bar.swift` — top-of-screen status bar