Initial import
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
# Architecture — MangoTune
|
||||
|
||||
## Rust Edition & MSRV
|
||||
|
||||
- Rust edition: **2021**
|
||||
- Minimum Supported Rust Version: **1.75.0**
|
||||
- Build target: `x86_64-unknown-linux-gnu` (primary), `aarch64-unknown-linux-gnu` (secondary)
|
||||
|
||||
## Cargo.toml Dependencies
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "mangotune"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["MangoTune Contributors"]
|
||||
description = "A modern MangoHud configurator for Linux"
|
||||
license = "GPL-3.0"
|
||||
repository = "https://github.com/your-org/mangotune"
|
||||
|
||||
[[bin]]
|
||||
name = "mangotune"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
# GUI
|
||||
gtk4 = { version = "0.9", features = ["v4_12"] }
|
||||
libadwaita = { version = "0.7", features = ["v1_5"] }
|
||||
glib = "0.20"
|
||||
gio = "0.20"
|
||||
|
||||
# Async runtime (for subprocess management, file watching)
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "process", "fs", "sync", "time"] }
|
||||
|
||||
# Serialization (for GSettings schema, internal state)
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
||||
# Config file parsing
|
||||
indexmap = "2" # preserve insertion order in parsed configs
|
||||
|
||||
# Error handling
|
||||
anyhow = "1"
|
||||
thiserror = "1"
|
||||
|
||||
# Filesystem watching (live reload when config changes externally)
|
||||
notify = "6"
|
||||
|
||||
# XDG base directory resolution
|
||||
xdg = "2"
|
||||
|
||||
# Regex (for config line parsing)
|
||||
regex = "1"
|
||||
once_cell = "1"
|
||||
|
||||
# Process detection (checking if gamemode is running, etc.)
|
||||
sysinfo = "0.31"
|
||||
|
||||
# Logging/tracing
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
||||
[build-dependencies]
|
||||
# For compiling GSettings schema and other build-time assets
|
||||
glib-build-tools = "0.20"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3"
|
||||
assert_fs = "1"
|
||||
```
|
||||
|
||||
## System Dependencies (must be present at build time)
|
||||
|
||||
| Package | Ubuntu/Debian | Fedora/RHEL | Arch |
|
||||
|--------------------------|---------------------------|---------------------------------|----------------|
|
||||
| GTK4 dev headers | `libgtk-4-dev` | `gtk4-devel` | `gtk4` |
|
||||
| libadwaita dev headers | `libadwaita-1-dev` | `libadwaita-devel` | `libadwaita` |
|
||||
| GLib dev headers | `libglib2.0-dev` | `glib2-devel` | `glib2` |
|
||||
| pkg-config | `pkg-config` | `pkgconf` | `pkgconf` |
|
||||
|
||||
Runtime (optional, detected at launch):
|
||||
- `mangohud` — the actual overlay
|
||||
- `vkcube` — from `vulkan-tools` package
|
||||
- `glxgears` — from `mesa-utils` package
|
||||
- `gamemoded` — from `gamemode` package
|
||||
- `gamemodectl` — from `gamemode` package
|
||||
|
||||
## Module Dependency Graph
|
||||
|
||||
```
|
||||
main.rs
|
||||
└── app.rs (GtkApplication)
|
||||
└── window.rs (AdwApplicationWindow)
|
||||
├── ui/pages/*.rs ← all pages
|
||||
│ ├── config/resolver.rs ← discovers config stack
|
||||
│ ├── config/validator.rs ← validates on every change
|
||||
│ ├── config/parser.rs ← reads/writes files
|
||||
│ └── config/schema.rs ← option definitions
|
||||
├── ui/widgets/*.rs ← reusable widgets
|
||||
├── system/detect.rs ← run at startup
|
||||
├── system/paths.rs ← XDG resolution
|
||||
├── launcher/runner.rs ← test process management
|
||||
└── integrations/*.rs ← GameMode/Steam/Lutris/Heroic
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
```
|
||||
Startup:
|
||||
system::detect::run()
|
||||
→ SystemInfo { mangohud_version, gpu_vendor, display_server, available_tools }
|
||||
|
||||
config::resolver::discover()
|
||||
→ Vec<ConfigLayer> { path, source_type, priority, exists }
|
||||
|
||||
For each ConfigLayer:
|
||||
config::parser::read(path)
|
||||
→ RawConfig { lines: Vec<ConfigLine> }
|
||||
|
||||
config::schema::annotate(raw)
|
||||
→ AnnotatedConfig { options: IndexMap<key, ConfigEntry> }
|
||||
|
||||
User edits a field:
|
||||
ui::widgets::* emits change signal
|
||||
→ config::validator::check(key, value, &schema)
|
||||
→ ValidationResult::Ok | ValidationResult::Error(msg) | ValidationResult::Warning(msg)
|
||||
|
||||
If Ok: update in-memory AnnotatedConfig
|
||||
check for dependency side-effects
|
||||
update cascade_view to show which layer owns the value
|
||||
enable Save button if no errors anywhere
|
||||
|
||||
Save:
|
||||
config::validator::check_all(&config) ← full pass before any write
|
||||
→ if any Error: abort, show error summary toast
|
||||
→ if all Ok: config::parser::write(path, config)
|
||||
preserving all comment lines unchanged
|
||||
```
|
||||
|
||||
## Threading Model
|
||||
|
||||
- **Main thread**: GTK4 event loop only. No blocking calls.
|
||||
- **Tokio thread pool**: file I/O, subprocess spawning, filesystem watcher.
|
||||
- Communication: `glib::MainContext::channel()` for sending results back to GTK main thread.
|
||||
- Never call GTK functions from tokio threads.
|
||||
|
||||
## GSettings Schema
|
||||
|
||||
Used for persisting app preferences (window size, last-opened config path, theme preference).
|
||||
NOT used for MangoHud config itself — that is always written directly to .conf files.
|
||||
|
||||
Schema ID: `com.mangotune.MangoTune`
|
||||
Keys:
|
||||
- `last-config-path` (string)
|
||||
- `window-width` (int, default 1200)
|
||||
- `window-height` (int, default 780)
|
||||
- `active-page` (string, default "performance")
|
||||
- `show-raw-editor` (bool, default false)
|
||||
|
||||
## Error Handling Strategy
|
||||
|
||||
- All I/O operations return `anyhow::Result`.
|
||||
- UI layer converts errors to `AdwToast` notifications (non-blocking).
|
||||
- Critical startup errors (GTK init failure) use `eprintln!` + `process::exit(1)`.
|
||||
- Validation errors are `thiserror` enums, displayed inline, never panicked on.
|
||||
- Never use `.unwrap()` or `.expect()` in production paths. Use `?` or match.
|
||||
|
||||
## Config File Format Notes
|
||||
|
||||
MangoHud .conf files follow these rules (the parser must handle all of them):
|
||||
1. Lines starting with `#` are comments — preserve verbatim.
|
||||
2. Empty lines — preserve verbatim.
|
||||
3. `key=value` — option with value.
|
||||
4. `key` alone (no `=`) — boolean flag, presence = enabled.
|
||||
5. `# key` — commented-out option (disabled).
|
||||
6. `# key=value` — commented-out option with default value shown.
|
||||
7. Inline comments after values are NOT standard and should be treated as part of value.
|
||||
8. Duplicate keys: last occurrence wins (MangoHud behavior).
|
||||
9. Encoding: UTF-8.
|
||||
|
||||
The parser must distinguish between:
|
||||
- An option that is absent from the file (use MangoHud's compiled default)
|
||||
- An option explicitly set to 0 or empty (user explicitly disabled)
|
||||
- An option present as a bare key (user enabled a flag)
|
||||
Reference in New Issue
Block a user