100 lines
3.9 KiB
Markdown
100 lines
3.9 KiB
Markdown
# Architecture Overview
|
|
|
|
Modus is built with Python and the [Fabric](https://github.com/Fabric-Development/fabric/)
|
|
framework (GTK/Wayland wrapper), plus custom C extensions for high-performance
|
|
Wayland interactions.
|
|
|
|
## 1. Core Application Loop
|
|
|
|
Entry point is `start.py`, delegates to `src/main.py`. `main.py` instantiates
|
|
`fabric.Application`, which manages lifecycle of floating Wayland windows:
|
|
|
|
- **Panel**: Top bar (`src/window/panel/`)
|
|
- **Dock**: macOS-style bottom dock (`src/window/dock/`)
|
|
- **Control Center**: Right-side quick settings (`src/window/controlcenter/`)
|
|
- **App Switcher**: Alt-Tab window switcher (`src/window/switcher/`)
|
|
- **Lock Screen**: Session lock (`src/window/lock.py`)
|
|
- **Spotlight Search**: Super+D search overlay (`src/window/spotlight/`)
|
|
|
|
## 2. Spotlight Search Engine
|
|
|
|
The spotlight (`src/window/spotlight/`) is a plugin-powered search overlay.
|
|
It has three layers:
|
|
|
|
### Layer 1: UI (`main.py`)
|
|
|
|
A GTK window with an entry field and scrollable result list. Renders results
|
|
from plugins. Manages keyboard navigation, viewport sizing, and result
|
|
selection. Uses a 200ms debounce on the entry field to avoid searching on
|
|
every keystroke.
|
|
|
|
### Layer 2: Search Pipeline (`core/search.py`)
|
|
|
|
On each keystroke:
|
|
|
|
1. Routes the query — if it starts with a keyword (e.g., `gg ` for Google),
|
|
the query goes exclusively to that plugin
|
|
2. Otherwise, dispatches to all `searchable` plugins in parallel via daemon
|
|
threads
|
|
3. Collects results via `GLib.idle_add` (main thread callback)
|
|
4. Merges results sorted by plugin priority then result score
|
|
5. Cancels previous in-flight searches with `threading.Event` tokens
|
|
|
|
### Layer 3: Plugin System (`core/loader.py`, `core/manager.py`, `core/registry.py`)
|
|
|
|
- **Loader**: Scans `config/plugins/` for `.py` files and package directories.
|
|
Handles per-plugin virtualenvs via `uv` for dependency isolation. Supports
|
|
deep reload (re-import from disk without restart).
|
|
- **Manager**: Orchestrates lifecycle — instantiate, enable/disable, reload,
|
|
release memory. Persists disabled plugin list to `plugins.json`.
|
|
- **Registry**: Stores plugin metadata keyed by id. Maintains keyword-to-plugin
|
|
map for fast routing.
|
|
|
|
### Data flow
|
|
|
|
```
|
|
User types → debounce (200ms) → route query
|
|
├─ keyword match → single plugin search → render
|
|
└─ global search → dispatch to threads → collect → merge → render
|
|
|
|
User selects result → action callback → (copy, launch, etc.)
|
|
User presses Escape → cancel searches → release plugin memory → hide
|
|
```
|
|
|
|
## 3. High-Performance App Switcher (AppCapture)
|
|
|
|
The App Switcher (Alt+Tab) needs live video previews of Wayland windows. Pure
|
|
Python DBus polling is too slow, so Modus uses a C-extension at
|
|
`src/window/switcher/app-capture/`.
|
|
|
|
- Uses `hyprland-toplevel-export-v1` Wayland protocol to get dmabuf/shm buffers
|
|
from Hyprland
|
|
- Compiled to `libappcapture.so`, exposed to Python via GObject Introspection
|
|
- Framerate throttled by Python using `invoke_repeater`, controlled by
|
|
`switcher_live_preview_delay_ms` in `config.toml`
|
|
|
|
## 4. Global Menu (DBus)
|
|
|
|
macOS-style menu bar in the top panel.
|
|
|
|
- Apps export menus over `com.canonical.dbusmenu` DBus
|
|
- Custom C shim (`src/window/globalmenu/libmenu_button_shim.c`) forces GTK apps to
|
|
export menus even if they weren't designed to
|
|
- Python daemon (`src/window/globalmenu/service.py`) listens for exported menus and
|
|
renders them as Fabric widgets in the panel
|
|
|
|
## 5. State Management & Services
|
|
|
|
Services in `src/services/` monitor system state asynchronously and emit
|
|
signals:
|
|
|
|
| Service | Source | What it tracks |
|
|
|---------|--------|---------------|
|
|
| `battery.py` | UPower over DBus | Battery percentage, charging state |
|
|
| `bluetooth.py` | BlueZ over DBus | Bluetooth devices |
|
|
| `brightness.py` | `brightnessctl` / `ddcutil` | Screen brightness |
|
|
| `network.py` | NetworkManager over DBus | WiFi, ethernet state |
|
|
|
|
Uses signals (`connect("changed", update_ui)`) for reactive UI — virtually 0%
|
|
CPU while idle.
|