Skip to content

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.

The launch flag opts the window into the quick-terminal shape:

Terminal window
tmnl --quick-terminal

What changes:

  • Window docks at quick_terminal_position (default top). Other options: bottom / left / right. The position controls both the window’s anchor edge and its size — top / bottom are half-height strips spanning the screen width; left / right are 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_fullscreen is ignored (it doesn’t make sense for a docked strip).
~/.config/tmnl/config.toml
quick_terminal_position = "top" # top | bottom | left | right

The 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.

quick_terminal_hotkey registers a system-wide chord that wakes the window from any focused app:

~/.config/tmnl/config.toml
quick_terminal_hotkey = "cmd+shift+t"

Examples that all work:

quick_terminal_hotkey = "cmd+shift+t" # macOS-style
quick_terminal_hotkey = "ctrl+alt+t" # Linux-style
quick_terminal_hotkey = "super+space" # Wayland-style
quick_terminal_hotkey = "alt+grave" # ` key

The chord syntax accepts:

  • Modifierscmd / command / super are 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 keys f1-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.

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.

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.

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.

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.

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.

  • 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_platform submodule), src/macos_hotkey.rs (the Carbon path), and the quick-terminal window-state machinery in src/app.rs (quick_terminal_mode field + the hide-on-blur + position logic).