Skip to content

DanielLukic/cofi

Repository files navigation

COFI - C/GTK Window Switcher

COFI is a fast window switcher for X11 Linux desktops, written in C with GTK3. It provides Alt-Tab functionality with real-time fuzzy search and intelligent result ranking.

Features

  • Instant window switching with MRU (Most Recently Used) ordering
  • Multi-stage fuzzy matching with intelligent scoring:
    • Word boundary matches: "comm" → "Commodoro"
    • Initials matching: "ddl" → "Daniel Dario Lukic"
    • Subsequence matching: "th" → "Thunderbird"
  • Alt-Tab behavior - pressing Enter switches to the most recent window
  • Harpoon-style assignments - assign windows to number keys for instant access
  • Custom window naming - assign custom names to windows for better identification
  • Command mode - vim-style commands with no-space syntax for window management (:cw2, :tL, :j5)
  • Configurable tiling grid - choose between 2x2 or 3x2 grid layouts with direct tiling commands
  • Event-driven updates - real-time window list synchronization
  • System hotkeys - daemon mode with configurable XGrabKey hotkeys (Alt+Tab, Alt+`, Alt+Backspace)
  • Visual ripple feedback - smooth 60fps circle ripple highlights the target window on switch
  • Zero external dependencies - direct X11 window activation
  • Lightweight - minimal memory footprint, fast startup

Building

Dependencies

  • GTK3 development libraries
  • X11 development libraries
  • GNU Make
  • GCC

On Debian/Ubuntu:

sudo apt install libgtk-3-dev libx11-dev build-essential

Compilation

make

To build with debug output:

make debug

Usage

Run cofi daemon (starts hidden, shows on hotkey):

./cofi

Delegate to a specific mode/tab (opens existing daemon if running, otherwise starts daemon and opens that mode): All delegate flags (--command, --run, --workspaces, --harpoon, --names, --applications, --windows/-W) forward over the daemon socket to the running instance, or autostart the daemon if none is running.

./cofi --command
./cofi --windows

Autostart

Install for automatic startup at login:

# XDG autostart (desktop entry)
./scripts/install-xdg.sh

# Or systemd user service
./scripts/install-systemd.sh

Command-line Options

Command Line Options

  • --windows (-W) - Delegate to Windows tab
  • --log-level LEVEL (-l) - Set log level: trace, debug, info (default), warn, error, fatal
  • --log-file FILE (-f) - Write logs to file
  • --no-log (-n) - Disable logging
  • --align POSITION (-a) - Window position: center (default), top, top_left, top_right, left, right, bottom, bottom_left, bottom_right
  • --no-auto-close (-C) - Don't close window when focus is lost
  • --workspaces (-w) - Delegate to Workspaces tab
  • --harpoon - Delegate to Harpoon tab
  • --names - Delegate to Names tab
  • --command (-c) - Delegate to command mode (: prompt)
  • --run - Delegate to run mode (! prompt)
  • --applications - Delegate to Apps tab
  • --assign-slots - Assign workspace window slots and exit
  • --version (-v) - Show version
  • --help (-h) - Show help
  • --help-commands (-H) - Show command mode help

Configuration

COFI saves configuration to ~/.config/cofi/:

  • ~/.config/cofi/options.json - Application settings
    • close_on_focus_loss - Auto-close on focus loss (boolean)
    • align - Default window alignment
    • workspaces_per_row - Grid columns for workspace view (0 = single row)
    • tile_columns - Tiling grid columns: 2 (2x2 grid) or 3 (3x2 grid), default 2
    • digit_slot_mode - What Alt+digit does: "default" (harpoon), "per-workspace" (window slots by position), "workspaces" (switch workspace)
    • slot_overlay_duration_ms - Duration of slot number overlays in ms (default 750, 0 = disabled)
    • ripple_enabled - Show circle ripple on window activation (boolean, default true)
    • hotkey_windows - System hotkey for windows mode (default "Mod1+Tab", "" = disabled)
    • hotkey_command - System hotkey for command mode (default "Mod1+grave")
    • hotkey_workspaces - System hotkey for workspaces mode (default "Mod1+BackSpace")
  • ~/.config/cofi/harpoon.json - Window assignments
    • Slots 0-9: Ctrl+0-9 / Alt+0-9
    • Slots a-z: Ctrl+a-z / Alt+a-z (excluding h,j,k,l,u)
  • ~/.config/cofi/names.json - Custom window names
    • User-defined names that override window titles
    • Format: <custom_name> - <original_title>

Keyboard Shortcuts

Window/Workspace Navigation

  • Up/Down arrows - Navigate through windows
  • Ctrl+k/Ctrl+j - Navigate up/down (Vim-style)
  • Tab/Shift+Tab - Cycle between Windows, Workspaces, Harpoon, Names, Config, Hotkeys, and Apps tabs
  • Enter - Activate selected window/workspace
  • Escape - Cancel and close
  • Type to search - Filter windows in real-time

Custom Window Names (Names Tab)

  • Tab to Names tab (or launch with --names)
  • Ctrl+E - Edit name for selected window
  • Ctrl+D - Delete name for selected window
  • Command mode: :assign-name, :an, or :n - Assign name to selected window

Harpoon-Style Window Assignment

  • Ctrl+0-9 - Assign current window to number key (0-9)
  • Ctrl+a-z - Assign current window to letter key (a-z, see exclusions below)
  • Alt+0-9 - Switch directly to window assigned to number
  • Alt+a-z - Switch directly to window assigned to letter
  • Ctrl+key on assigned window - Remove assignment (toggle)

Excluded Keys: The following keys are reserved for navigation and cannot be used for harpoon assignments:

  • Ctrl+j - Navigate down in selection
  • Ctrl+k - Navigate up in selection
  • Ctrl+u - Clear search text (GTK default behavior)

Override Exclusions with Shift: You can override the key exclusions by holding Shift:

  • Ctrl+Shift+j/k/u - Assign these normally excluded keys as harpoon slots
  • This is safe because activation still uses Alt+key (without Shift)
  • Example: Ctrl+Shift+j assigns to slot 'j', then Alt+j activates it

This gives you 33 available harpoon slots by default (0-9 and a-i, l-t, v-z), or all 36 slots (0-9 and a-z) when using the Shift override.

Workspace Window Slots (Per-Workspace Mode)

When digit_slot_mode is "per-workspace" in options.json:

  • Alt+1-9 - Jump to the Nth window on the current workspace, ordered by screen position (left-to-right, top-to-bottom)
  • Slots auto-assign on every press — no manual step needed
  • Only visible windows are numbered (minimized, shaded, and occluded windows are excluded)
  • Numbered overlays flash briefly on each window after assignment
  • Alt+a-z - Still activates global harpoon letter slots as normal
  • :as - Manually reassign slots and auto-enable per-workspace mode

Typical workflow: Alt+Tab to open cofi, then Alt+1/2/3 to jump directly to a window.

Workspace Switching Mode

When digit_slot_mode is "workspaces" in options.json:

  • Alt+1-9 - Always switches directly to workspaces 1-9 (regardless of current tab)
  • Ctrl+1-9 - Still assigns/unassigns harpoon slots as normal

Command Mode

Press : to enter command mode for advanced window management operations. Commands can be typed with or without spaces between the command and arguments. When entered from hidden/delegated flows, command targeting is pinned by the pre-show active window ID (captured before show) and then resolved in the filtered list on command-mode entry.

Command Mode

Run Mode

Press ! to enter run mode for detached shell commands. ! is the mode indicator label; the entry itself holds raw command text (no literal ! prefix). Up/Down browse a separate session-only run history, Enter launches the trimmed command detached and closes cofi, and deleting back to empty exits run mode. Bare ! (legacy tolerated) or whitespace-only commands are ignored. :show run and --run open directly into the same run surface.

Apps Tab

The Apps tab launches installed desktop applications from XDG desktop entries via GLib/GIO.

  • Start directly with --applications
  • Switch from command mode with :show apps
  • Enter launches the selected app detached and closes cofi
  • Hidden / invalid / NoDisplay apps are excluded
  • Apps matching/ranking is local to the Apps tab, not the window-switcher MRU/fuzzy ranking
  • Ranking order: name > generic_name > keywords
  • generic_name and keywords are token-matched to avoid cross-token false positives

Available Commands

Window Management:

  • :cw [N|dir] or :change-workspace [N|dir] - Move selected window to workspace N or direction (h/j/k/l)

    Change Workspace

  • :pw or :pull-window or :p - Pull selected window to current workspace

  • :tm or :toggle-monitor - Move window to next monitor

  • :tw [OPT] or :tile-window [OPT] or :t [OPT] - Tile window

    • Options: L/R/T/B (halves), 1-4 (2x2 grid) or 1-6 (3x2 grid), F (fullscreen), C (center)
    • Direct tiling: :t[lrtbc][1-4] for quick sizing
      • Sizes: 1=25%, 2=50%, 3=66%, 4=75% (or 100% for center)
      • Examples: :tr4 (right 75%), :tl2 (left 50%), :tc1 (center 33%), :tc4 (fullscreen)

    Tiling Options

  • :maw [N|dir] or :move-all-to-workspace [N|dir] - Move all windows from current workspace to target

  • :sw or :swap-windows - Swap two windows (positions and sizes)

  • :cl or :close-window or :c - Close selected window

  • :mw or :maximize-window or :m - Toggle maximize

  • :miw or :min or :minimize-window - Toggle minimize (restore if already minimized)

  • :hm or :horizontal-maximize-window - Toggle horizontal maximize

  • :vm or :vertical-maximize-window - Toggle vertical maximize

Window Properties:

  • :sb or :skip-taskbar - Toggle skip taskbar
  • :at or :always-on-top or :aot - Toggle always on top
  • :ab or :always-below - Toggle always below
  • :ew or :every-workspace - Toggle sticky (show on all workspaces)

Navigation:

  • :jw [N|dir] or :jump-workspace [N|dir] or :j [N|dir] - Jump to workspace N or direction (h/j/k/l)

    Jump to Workspace

  • :rw [N] or :rename-workspace - Rename workspace N (current if omitted)

  • :help or :h or :? - Show command help

Window Naming:

  • :assign-name or :an or :n - Assign custom name to selected window

Configuration:

  • :set <key> <value> - Set a config option at runtime
  • :config or :cfg - Switch to the Config tab
  • :hotkeys or :hk - Show/manage hotkey bindings
  • :as or :assign-slots - Assign workspace window slots by screen position

Mouse:

  • :mouse away or :ma - Move mouse cursor away
  • :mouse show or :ms - Show mouse cursor
  • :mouse hide or :mh - Hide mouse cursor

No-Space Syntax

Commands with arguments can be typed without spaces for faster entry:

  • :cw2 - Move window to workspace 2
  • :j5 - Jump to workspace 5
  • :tL - Tile window left half
  • :t5 - Tile to grid position 5
  • :tr4 - Tile window right 75%
  • :tl1 - Tile window left 25%
  • :tc3 - Center window at 75% size
  • :jwk - Jump to workspace above (vim direction)
  • :mawl - Move all windows to workspace right

This vim-style syntax works alongside traditional space-separated commands.

Window Display

COFI shows windows in a 6-column format:

  • Slot - Harpoon slot indicator (digit/letter if assigned, blank otherwise)
  • Desktop - [0-9] for desktop number, [S] for sticky windows
  • Instance - Application instance name
  • Title - Window title (truncated to fit)
  • Class - Application class name
  • ID - Window ID in hexadecimal

The display is bottom-aligned (fzf-style) with the most recent window at the bottom.

Example

COFI Example

See how I assigned shortcuts for Thunderbird (m), and my current project (p), the terminal to that project (t), the volume control (v). Cofi makes it easy to jump to these windows directly. For example <alt-tab><alt-m> jumps to my mail. Without releasing the <alt> key.

Cofi runs as a daemon and registers Alt+Tab as a system hotkey. No WM configuration needed — just start cofi and it takes over Alt+Tab.

Advanced Features

Intelligent Search

COFI uses multi-stage matching with priority scoring:

  1. Word Boundary (highest) - Matches at word starts
  2. Initials (very high) - Matches first letters of words
  3. Subsequence (high) - Matches characters in order
  4. Fuzzy (fallback) - Complex partial matching

Harpoon Assignments

Inspired by the VIM Harpoon plugin:

  • Persistent - Assignments saved to ~/.config/cofi/harpoon.json
  • Automatic reassignment - When windows close, intelligently reassign numbers
  • Visual indicators - Assigned numbers shown in first column
  • Fuzzy reassignment - Uses partial title matching for smart reassignment

Custom Window Naming

Give windows meaningful custom names for better identification:

  • Override titles - Custom names appear as <custom_name> - <original_title>
  • Persistent storage - Names saved to ~/.config/cofi/names.json
  • Smart reassignment - When windows close, intelligently reassign names using fuzzy matching
  • Integrated search - Custom names are included in filtering and search
  • Tab interface - Dedicated Names tab for managing all custom names
  • Command support - Use :assign-name command or Names tab shortcuts

System Hotkeys

  • Daemon mode registers global hotkeys via XGrabKey on the X11 root window
  • Configurable in options.json using Modifier+KeyName format (X11 keysym names)
  • Set any hotkey to "" to disable it
  • CapsLock/NumLock insensitive
  • Retry/Exit dialog if another application holds a key binding

Event-Driven Updates

  • Real-time window list updates via X11 PropertyNotify events
  • No polling - zero CPU overhead when idle
  • Instant response to window creation/destruction

Installation

sudo make install

This installs cofi to /usr/local/bin/.

To uninstall:

sudo make uninstall

Testing

Run the test suite:

make test

Architecture

COFI uses a modular architecture with specialized components for:

  • Application lifecycle and GTK window management
  • X11 window property extraction and activation
  • Window enumeration via EWMH protocol
  • MRU (Most Recently Used) ordering and Alt-Tab logic
  • Multi-stage search with intelligent scoring
  • Display formatting and user interface
  • Event-driven updates for real-time synchronization
  • System hotkey registration via XGrabKey
  • Harpoon-style window assignments
  • Workspace switching and management

See CLAUDE.md for detailed technical documentation.

Requirements

  • X11-based Linux desktop environment
  • Window manager with EWMH support (most modern WMs)
  • GTK3 runtime libraries

License

See LICENSE for terms.

About

Vibe coded C/GTK version of the gofi window switcher

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors