6.5 KiB
6.5 KiB
Config Struct Analysis: cargo run vs Standalone EXE
QUICK ANSWER
The config.toml modifications work in cargo run but not standalone EXE because:
- Both behave identically - neither reloads config during runtime
- The difference is file location - where config.toml is searched for
- cargo run appears to work because users restart the process frequently
- Standalone EXE appears broken because users expect live reloading
The real issue: Config is frozen at startup and never reloaded.
THE CORE PROBLEM
Configuration Loading (One-Time Only)
File: src/main.rs, Line 54
let app_config = config::load_config(); // Loaded ONCE, never again
Configuration Freezing Points
Freeze Point 1: BackgroundRenderer (src/app.rs:28-34)
let background_renderer = Some(Arc::new(BackgroundRenderer::new(
&cc.egui_ctx,
&config.appearance.background_image,
config.appearance.background_opacity, // ← COPIED
config.appearance.fallback_color, // ← COPIED
config.appearance.fallback_color_opacity, // ← COPIED
)));
- Appearance values copied into struct once
- Stored in
Arc<BackgroundRenderer>(immutable) - Never updated during application lifetime
Freeze Point 2: Config Field (src/app.rs:49)
Self {
config, // ← Stored as owned field, never mutated
// ...
}
- Config struct stored once at initialization
- Colors, text sizing, window settings frozen
- Never reloaded from disk
- Never updated at runtime
WHY CHANGES DON'T APPEAR
Background Changes (opacity, color)
- User modifies
config.toml(e.g., changesbackground_opacity) - Application still has original value in
BackgroundRenderermemory - Every frame,
render_fullscreen()uses frozen opacity value - No code to reload config or recreate
BackgroundRenderer - Change never takes effect
Color Changes
- User modifies
config.toml(e.g., changes text color) - Application still has original
Configstruct in memory - Every frame,
update()reads fromself.config - But
self.configwas never updated ctx.set_visuals()applies same frozen colors- Change never takes effect
cargo run vs Standalone: The REAL Story
cargo run Process
User runs: cargo run
├─ New process created
├─ load_config() reads config.toml from repo root (fallback path)
├─ Application starts with current config
├─ User modifies config.toml while app is running
│ └─ Change DOESN'T take effect (no reload mechanism)
├─ User exits app
├─ User runs: cargo run again
│ ├─ New process created
│ ├─ load_config() reads UPDATED config.toml
│ └─ Application shows new values ✓
└─ User thinks "config changes work in cargo run!"
Standalone EXE Process
User runs: Create-App-Secret.exe
├─ Process created
├─ load_config() looks in EXE directory
│ └─ If config.toml exists there, loads it
│ └─ Otherwise falls back to ./config.toml
├─ Application starts with current config
├─ User modifies config.toml while app is running
│ └─ Change DOESN'T take effect (no reload mechanism)
├─ User expects changes to appear
│ └─ Nothing happens ✗
├─ User closes app
├─ User runs: Create-App-Secret.exe again
│ ├─ New process created
│ ├─ load_config() reads UPDATED config.toml
│ └─ Application shows new values ✓
└─ User thinks "config changes don't work in standalone!"
The Actual Difference
| Aspect | cargo run | Standalone |
|---|---|---|
| Config loading code | Identical | Identical |
| Config freezing | Yes, identical | Yes, identical |
| Hot-reload | No | No |
| Updates on restart | Yes ✓ | Yes ✓ |
| File location | Repo root (fallback) | EXE directory |
CODE PATH: From Config Loading to Display
main.rs:54
↓
config::load_config() ← Reads config.toml from disk [ONCE]
↓
Returns Config struct
↓
main.rs:76
↓
Moved into AzureAppManager::new()
↓
app.rs:28-34: BackgroundRenderer created
└─ opacity, fallback_color COPIED from config [FROZEN]
└─ Stored in Arc<BackgroundRenderer>
↓
app.rs:49: Config stored
└─ self.config = config [FROZEN]
↓
eframe event loop (every frame ~60x/sec):
├─ app.rs:375-457: update() called
│ ├─ app.rs:380: Read colors from self.config [frozen values]
│ ├─ app.rs:467: Read text sizing from self.config [frozen values]
│ ├─ app.rs:489: Read position offset from self.config [frozen values]
│ └─ app.rs:505-507: Render background with frozen renderer
│
└─ Every frame: Same frozen values used again
(Because no code reloads or updates them)
What Would Be Needed to Fix
1. File Watching
// Add to Cargo.toml
notify = "6.0" // File system event watcher
2. Config Reload Mechanism
pub fn reload_config_from_disk() -> Config {
config::load_config() // Re-read from disk
}
3. Mutable Config Storage
// Change from:
config: Config
// To:
config: Arc<Mutex<Config>>
4. Updatable Background Renderer
// Either:
// - Store as Arc<Mutex<BackgroundRenderer>>
// - Or recreate it every frame with current config values
5. Hot Reload Trigger
if config_file_changed {
new_config = reload_config_from_disk();
update_background_renderer(&new_config);
ctx.request_repaint();
}
Summary Table
| Component | Location | Issue | Status |
|---|---|---|---|
| Config loading | main.rs:54 |
Loaded once | FROZEN |
| Config movement | main.rs:76 |
Moved via ownership | FROZEN |
| Background values | app.rs:28-34 |
Copied into struct | FROZEN |
| Config storage | app.rs:49 |
Stored as owned field | FROZEN |
| Color application | app.rs:380-444 |
Reads frozen config | EVERY FRAME |
| Background rendering | background.rs:106 |
Uses frozen values | EVERY FRAME |
| Reload mechanism | Not found | No file watching | ✗ MISSING |
Key Insight
The application architecture assumes configuration is set once at startup and never changes. This is a design choice, not a bug. The same frozen-config behavior exists in both cargo run and standalone EXE.
The perceived difference comes from:
- cargo run: Users frequently restart processes → see updated config
- Standalone EXE: Users expect live updates → see frozen config
Both are executing identical code with identical behavior.