Architecture

How the DropTerm codebase is laid out: two crates, one module inventory, a handful of load-bearing seams, and where the reasoning behind each lives.

Two crates, one workspace

Module inventory

The recurring split is pure model vs wiring: pure modules hold plain data and functions, free of iced types, unit-testable headless; wiring modules own the runtime halves that need a compositor. Unit tests live inline in #[cfg(test)] sibling modules (src/*/tests.rs).

Module Role
main.rs CLI entry: clap verbs (--is-visible, the ToggleAction subcommands), TERM env setup, the single-instance handoff
app.rs The cosmic::Application: the message enum, update/view, config subscription - the composition root
app/spawn.rs Spawn resolution: shell/cmd/profile decisions and the cwd chains (plain_spawn_cwd, live_preset_cwd)
app/surface_lifecycle.rs Show/hide/slide-out/destroy lifecycle of the layer surface
app/tab_actions.rs Context-menu picks and inline renames funneled into app messages
app/remote.rs The CLI verbs handled inside the running instance
config.rs The 43-key on-disk config (DropTermConfig): enums, clamping, shell resolution
context_menu.rs The terminal context-menu model - rows, labels, item→terminal::Action mapping (pure; picks land in the same path keybinds use)
dbus_state.rs The read-only served state: Visible and TabCount on the …CosmicExtDropterm.V1 interface
drawer_handle.rs The settings drawer’s drag-resize handle
geometry.rs Pure geometry math plus the single apply_geometry surface path every reshape goes through
grab_bar.rs The surface-height drag bar
keybinds.rs The default chord map plus the per-action custom_key_binds overlay (pure)
notify.rs Bell → freedesktop desktop notification (direct D-Bus; COSMIC has no Notification portal)
profile.rs The profile model and its pure resolution seams (profile ?? global, per field)
session.rs Session persistence: versioned RON schema, capture/restore planning, corrupt-file quarantine, atomic save (pure file layer)
settings.rs The settings drawer: the write contract, the control→key map, five pages, the profile manager form, the keybind editor
slide.rs The 130 ms slide: draw-time translation/clip inside a fixed surface - no layer-shell traffic while animating
status_bar.rs The 28 px status band: pure segment model plus widget
surface.rs Layer-shell surface creation - a measuring pass stretches to the output, then reshapes in place
tab_bar.rs The tab strip widget: buttons, +, gear, drag reorder, inline rename, per-tab menu, pins, borders
tabs.rs The pure tab model: insert/close/reorder/cycle, title fallback
terminal/ The engine and widget adapted from cosmic-term: engine.rs (PTY + alacritty_terminal grid + cosmic-text), widget.rs (TerminalBox), mouse_reporter.rs, theme_source.rs (the 12-scheme registry with per-scheme license provenance)
applet/ The applet crate: the panel button (state-driven opacity, tooltip), the D-Bus watches, the click decision

main.rs and lib.rs also carry the pedantic-lint table just clippy enforces - standing: owner-approved exceptions and transient: worklist entries that self-clean as their lint class is cleared.

The load-bearing seams

Testing posture

Where the why lives

Module doc-comments carry the local reasoning (dated rulings, gotchas); the feature-level reasoning - peer surveys, recommendations, rejected alternatives - lives in the research records, indexed by the decision log.