Quick-terminal mode
A “quick terminal” is a tmnl window that docks at one screen edge, hides when blurred, and toggles in / out from anywhere on the system via a registered global hotkey. The pattern is Yakuake’s; iTerm’s Hotkey Window; Ghostty’s quick-terminal. tmnl ships its own variant with the same shape — a chord registered system-wide that pops a half-height strip across the top (or bottom / left / right) of the active screen.
This page covers the two pieces: the --quick-terminal launch mode
that controls window placement and the hide-on-blur behavior, and the
cross-platform global hotkey facade that wires a config chord to
an OS-level grab without giving up macOS’s permission-less Carbon
path on the platform that already had it.
Launching in quick-terminal mode
Section titled “Launching in quick-terminal mode”The launch flag opts the window into the quick-terminal shape:
tmnl --quick-terminalWhat changes:
- Window docks at
quick_terminal_position(defaulttop). Other options:bottom/left/right. The position controls both the window’s anchor edge and its size —top/bottomare half-height strips spanning the screen width;left/rightare full-height strips at one-third the screen width. - Window hides on blur instead of staying around. Clicking out of the window minimizes it; the next hotkey press brings it back.
start_fullscreenis ignored (it doesn’t make sense for a docked strip).
quick_terminal_position = "top" # top | bottom | left | rightThe position knob mirrors Ghostty’s quick-terminal-position so a
config copy-pasted between the two does the right thing.
You typically don’t launch tmnl with --quick-terminal from the
shell — that defeats the purpose. The pattern is to launch tmnl in
the background (e.g. at login via your DE’s autostart, or via a
launchd agent on macOS) and let the hotkey toggle it visible.
The global hotkey
Section titled “The global hotkey”quick_terminal_hotkey registers a system-wide chord that wakes the
window from any focused app:
quick_terminal_hotkey = "cmd+shift+t"Examples that all work:
quick_terminal_hotkey = "cmd+shift+t" # macOS-stylequick_terminal_hotkey = "ctrl+alt+t" # Linux-stylequick_terminal_hotkey = "super+space" # Wayland-stylequick_terminal_hotkey = "alt+grave" # ` keyThe chord syntax accepts:
- Modifiers —
cmd/command/superare aliases (Super on Linux/Windows, Command on macOS).ctrl/control.alt/option.shift. - Keys — single chars (
t,1), named keys (space,tab,enter,escape,grave, function keysf1-f12, arrow keys, etc).
When tmnl is built / launched on the wrong platform for a chord
(e.g. cmd+shift+t on Linux), the chord still parses — cmd is
just an alias for super there — so config files are portable
between platforms without surgery.
Cross-platform — the facade
Section titled “Cross-platform — the facade”The global hotkey is the one feature where “cross-platform” can’t
mean “one implementation”; the OS-level chord registration is too
different on each platform. tmnl’s global_hotkey module is a thin
facade that picks the right implementation per platform:
| Platform | Implementation | Permissions needed |
| --- | --- | --- |
| macOS | Carbon RegisterEventHotKey (via macos_hotkey) | none |
| Linux (X11 / Xwayland) | global-hotkey crate (Tauri’s, well-tested) | none |
| Linux (pure Wayland) | unsupported — see Wayland note below | n/a |
| Windows | global-hotkey crate via the WinAPI hot-key path | none |
The macOS path is deliberately kept on Carbon: it doesn’t need an
accessibility permission grant, doesn’t pull in any non-Apple
transitive deps for macOS users, and was already shipping. The
Linux / Windows paths use the global-hotkey crate from the Tauri
project. Both surfaces export the same install_hotkey(spec) -> bool
function; the call site in App::resumed is identical across
platforms.
Wayland note
Section titled “Wayland note”global-hotkey’s Wayland support is X11-only today — it works on
pure X11 sessions and on Xwayland, but not on a pure Wayland
session. The cause is upstream: Wayland’s design intentionally
doesn’t expose a “grab a chord from any app” primitive (each
compositor handles bindings itself, and the
WlrForeignToplevelManagement protocol doesn’t cover keys), so
every cross-platform library hits the same wall.
If tmnl can’t install the hotkey, the install path catches the
underlying panic via std::panic::catch_unwind, logs a warning, and
returns false. The rest of tmnl runs normally — only the hotkey
is unwired. The catch matters because the underlying crate’s
manager-init can panic during display-server probing on systems
without an X11 fallback; without the catch, that panic would take
the whole app down.
Workaround: on a pure Wayland session, bind the hotkey at the
compositor level — sway via bindsym, hyprland via bind=,
KDE Plasma via System Settings → Shortcuts — and have it run
tmnl --quick-terminal (or the activate command, once tmnl
exposes one). The compositor owns the grab, tmnl just handles the
window.
Settings reload semantics
Section titled “Settings reload semantics”The hotkey state is held in a OnceLock<Mutex<...>> inside the
facade. A second install_hotkey call (e.g. after editing the
config and the Settings overlay re-mirrors) swaps the
registration — drops the previous chord, installs the new one,
returns. So changing your config and saving picks up the new
chord immediately without a tmnl restart.
A worker thread named global-hotkey-poll polls the underlying
crate’s event channel every 50 ms and flips a one-shot
HOTKEY_FIRED atomic on every press. The App tick reads + clears
that atomic and triggers the show / focus dance. No allocations
per event; the thread sleeps when nothing’s queued.
What happens on hotkey press
Section titled “What happens on hotkey press”The atomic flip wakes the next App tick. If the window is hidden, tmnl re-shows + focuses it at the configured edge. If it’s already visible (e.g. the user pressed the chord while already inside tmnl), the press is a no-op — the chord doesn’t toggle when the window already has focus, to avoid losing in-flight input.
The hide-on-blur side is the other half of the toggle. Clicking
back into your previous app, or Cmd+Tab-ing away, fires
WindowEvent::Focused(false). In quick-terminal mode that causes
tmnl to minimize the window rather than just unfocus it. The
next chord press re-shows.
Why a facade and not the crate directly
Section titled “Why a facade and not the crate directly”The facade module’s job is to keep the macOS path off the
global-hotkey crate. Adding a transitive dep just for macOS
support would pull in Tauri’s Wayland / X11 probing libraries for
users who’ll never need them, slow the cargo build, and add a path
where Apple users could hit a crash that doesn’t apply to their
platform. The Carbon path is well-shipped and adds zero deps.
On Linux + Windows the calculus flips: the OS APIs there are
unpleasant to call directly, the global-hotkey crate already
abstracts over both, and a Tauri-maintained crate is the same
implementation those users are already running on their desktop
elsewhere.
Where to go next
Section titled “Where to go next”- Tabs, splits, and panes — what the panes inside the quick-terminal window look like (same as any other tmnl window — the docking is the only change).
- Multi-window — quick-terminal mode is a per-launch flag, so multiple quick-terminals can coexist with regular tmnl windows.
docs/linux.md— Linux-specific install notes; documents the X11-only state of the hotkey support today plus what’s planned next.- FEATURES.md — the shipped-feature inventory.
- The implementation lives in
src/global_hotkey.rs(the facade +cross_platformsubmodule),src/macos_hotkey.rs(the Carbon path), and the quick-terminal window-state machinery insrc/app.rs(quick_terminal_modefield + the hide-on-blur + position logic).