213 lines
8.0 KiB
Plaintext
213 lines
8.0 KiB
Plaintext
================================================================================
|
|
DETAILED ANALYSIS: Config Struct Usage - cargo run vs Standalone EXE
|
|
================================================================================
|
|
|
|
EXECUTIVE SUMMARY
|
|
================================================================================
|
|
|
|
Config modifications don't work in either cargo run OR standalone EXE after
|
|
startup. They only appear to work in cargo run because each run is a NEW
|
|
process that reloads the config file from disk.
|
|
|
|
ROOT CAUSE: One-time initialization with frozen values, no reload mechanism.
|
|
|
|
KEY FINDINGS:
|
|
1. config.toml is loaded ONCE in main.rs:54
|
|
2. Config values COPIED into BackgroundRenderer (immutable Arc)
|
|
3. Config STORED in AzureAppManager (never updated)
|
|
4. Every frame reads SAME frozen values
|
|
5. ZERO reload/hot-update mechanism exists
|
|
6. Working directory only affects WHERE file is looked for, not HOW changes propagate
|
|
|
|
================================================================================
|
|
1. CONFIG LOADING - src/main.rs Lines 35-80
|
|
================================================================================
|
|
|
|
#[tokio::main]
|
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
// LINE 54: LOADED ONCE
|
|
let app_config = config::load_config();
|
|
|
|
// LINES 60-64: VALUES APPLIED TO EFRAME
|
|
let viewport_builder = egui::ViewportBuilder::default()
|
|
.with_inner_size([app_config.window.width, app_config.window.height])
|
|
.with_min_inner_size([app_config.window.min_width, app_config.window.min_height])
|
|
.with_transparent(app_config.window.use_transparency)
|
|
.with_icon(icon_data);
|
|
|
|
// LINES 73-77: MOVED INTO MANAGER (ownership transferred, never accessed in main again)
|
|
eframe::run_native(
|
|
"Create App Secret",
|
|
options,
|
|
Box::new(move |cc| Ok(Box::new(AzureAppManager::new(cc, auth, app_config)))),
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
CRITICAL: The 'move' keyword transfers ownership to the closure. After this
|
|
point, no other code in main can access app_config.
|
|
|
|
================================================================================
|
|
2. CONFIG FILE PATH RESOLUTION - src/config/window_config.rs Lines 232-295
|
|
================================================================================
|
|
|
|
pub fn load_config() -> Config {
|
|
let config_path = if let Ok(exe_path) = std::env::current_exe() {
|
|
exe_path
|
|
.parent()
|
|
.map(|p| p.join("config.toml"))
|
|
.unwrap_or_else(|| Path::new("./config.toml").to_path_buf())
|
|
} else {
|
|
Path::new("./config.toml").to_path_buf()
|
|
};
|
|
|
|
if config_path.exists() {
|
|
// Load and parse TOML
|
|
} else {
|
|
// Create defaults
|
|
}
|
|
|
|
Config::default() // Fallback
|
|
}
|
|
|
|
CARGO RUN PATH:
|
|
current_exe() = C:\...\I-SecretUpdate\target\debug\create-app-secret.exe
|
|
parent = C:\...\I-SecretUpdate\target\debug\
|
|
looks for C:\...\I-SecretUpdate\target\debug\config.toml ❌ NOT FOUND
|
|
falls back to ./config.toml
|
|
resolves to C:\...\I-SecretUpdate\config.toml ✓ FOUND
|
|
|
|
STANDALONE EXE PATH:
|
|
current_exe() = C:\wherever\user\puts\Create-App-Secret.exe
|
|
parent = C:\wherever\user\puts\
|
|
looks for C:\wherever\user\puts\config.toml ✓ OR ❌
|
|
if not found, falls back to ./config.toml
|
|
|
|
KEY POINT: Both use identical code and path resolution logic. The file
|
|
location is the ONLY difference, not how changes are handled.
|
|
|
|
================================================================================
|
|
3. FIRST INITIALIZATION - FREEZE POINT 1 & 2 - src/app.rs Lines 20-52
|
|
================================================================================
|
|
|
|
pub struct AzureAppManager {
|
|
state: AppState,
|
|
auth: Arc<AzureAuthenticator>,
|
|
graph_client: GraphApiClient,
|
|
keyvault_client: KeyVaultClient,
|
|
vault_discovery: VaultDiscovery,
|
|
config: Config, // ← FREEZE POINT 2: Stored, never mutated
|
|
position_applied: bool,
|
|
}
|
|
|
|
impl AzureAppManager {
|
|
pub fn new(cc: &eframe::CreationContext<'_>,
|
|
auth: Arc<AzureAuthenticator>,
|
|
config: Config) -> Self {
|
|
|
|
let mut state = AppState::new();
|
|
|
|
// FREEZE POINT 1: Create BackgroundRenderer with COPIED config values
|
|
let background_renderer = Some(Arc::new(BackgroundRenderer::new(
|
|
&cc.egui_ctx,
|
|
&config.appearance.background_image,
|
|
config.appearance.background_opacity, // ← COPIED HERE
|
|
config.appearance.fallback_color, // ← COPIED HERE
|
|
config.appearance.fallback_color_opacity, // ← COPIED HERE
|
|
)));
|
|
state.background_renderer = background_renderer;
|
|
|
|
Self {
|
|
state,
|
|
auth,
|
|
graph_client,
|
|
keyvault_client,
|
|
vault_discovery,
|
|
config, // ← FREEZE POINT 2: Stored as owned, never updated
|
|
position_applied: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
WHAT GETS FROZEN:
|
|
|
|
FREEZE POINT 1 (BackgroundRenderer):
|
|
- opacity value COPIED
|
|
- fallback_color value COPIED
|
|
- fallback_color_opacity value COPIED
|
|
- These are stored in Arc<BackgroundRenderer> (immutable)
|
|
- Used every frame via render_fullscreen()
|
|
- NEVER RECALCULATED OR UPDATED
|
|
|
|
FREEZE POINT 2 (Config Field):
|
|
- Entire Config struct stored
|
|
- Not mutable reference, not Arc<Mutex<>>
|
|
- Owned field that cannot be changed
|
|
- Read every frame in update()
|
|
- NEVER RELOADED FROM DISK
|
|
|
|
================================================================================
|
|
4. BACKGROUND RENDERING - EVERY FRAME - src/ui/background.rs Lines 106-152
|
|
================================================================================
|
|
|
|
pub fn render_fullscreen(&self, ctx: &Context) {
|
|
let screen_rect = ctx.screen_rect();
|
|
let painter = ctx.layer_painter(egui::LayerId::background());
|
|
|
|
// Render with FROZEN fallback_color_opacity
|
|
let fallback_with_opacity = Color32::from_rgba_unmultiplied(
|
|
self.fallback_color.r(),
|
|
self.fallback_color.g(),
|
|
self.fallback_color.b(),
|
|
(self.fallback_color_opacity * 255.0) as u8, // ← FROZEN VALUE
|
|
);
|
|
painter.rect_filled(screen_rect, 0.0, fallback_with_opacity);
|
|
|
|
if let Some(texture) = &self.texture {
|
|
// Render with FROZEN opacity
|
|
let tint = Color32::from_rgba_unmultiplied(
|
|
255, 255, 255,
|
|
(self.opacity * 255.0) as u8 // ← FROZEN VALUE
|
|
);
|
|
painter.image(texture.id(), screen_rect, uv_rect, tint);
|
|
}
|
|
}
|
|
|
|
CALLED EVERY FRAME FROM: src/app.rs Line 506
|
|
|
|
if let Some(bg) = &self.state.background_renderer {
|
|
bg.render_fullscreen(ctx); // Uses same frozen values
|
|
}
|
|
|
|
RESULT: Background renders with identical opacity and colors every frame.
|
|
User modifies config.toml, but application still renders with original values.
|
|
|
|
================================================================================
|
|
5. COLOR APPLICATION - EVERY FRAME - src/app.rs Lines 375-457
|
|
================================================================================
|
|
|
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
|
let mut visuals = egui::Visuals::dark();
|
|
|
|
// LINE 380: READ FROM FROZEN CONFIG
|
|
let colors = self.config.colors.as_ref();
|
|
|
|
if let Some(color_config) = colors {
|
|
let slider = &color_config.slider;
|
|
let text = &color_config.text;
|
|
|
|
// Apply colors
|
|
visuals.widgets.noninteractive.fg_stroke.color =
|
|
egui::Color32::from_rgb(text.normal[0], text.normal[1], text.normal[2]);
|
|
visuals.widgets.inactive.fg_stroke.color =
|
|
egui::Color32::from_rgb(text.inactive[0], text.inactive[1], text.inactive[2]);
|
|
visuals.widgets.hovered.fg_stroke.color =
|
|
egui::Color32::from_rgb(text.hover[0], text.hover[1], text.hover[2]);
|
|
// ... more color applications ...
|
|
|
|
// Apply slider colors
|
|
visuals.widgets.noninteractive.bg_fill =
|
|
egui::Color32::from_rgb(slider.inactive[0], slider.inactive[1], slider.inactive[2]);
|
|
// ... more slider col
|