fix(gui): hide the window until elevation is resolved, not after
The window used to be visible from launch, so the unprivileged instance's normal window would show, flash while pkexec/osascript asked for the admin password, and only then get replaced by the elevated relaunch's window once it killed this one ~1.2s later — the same mechanism Sabiá already uses under the hood, but with Sabiá's window visible throughout too; Guará's heavier initial UI made the unprivileged flash far more noticeable. tauri.conf.json now starts the window with "visible": false. main.rs shows it explicitly in exactly one of three cases: already elevated (or non-unix, where the OS-level UAC manifest already elevated the process before it started), the relaunch failed and the user needs to see the warning, or this is the already-elevated relaunched instance itself. Only one window is ever shown to the user now. Also fixes a latent bug this surfaced: do_relaunch_elevated only emitted "elevate-failed" from the child-process-exited-nonzero path. If it fails earlier (pkexec/osascript missing, exe path unresolved, log file unwritable) it returns Err directly without emitting anything — with the window now starting hidden, that would have left it hidden forever with no feedback. The setup() closure now emits the same event on that early-Err path too. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
This commit is contained in:
1 parent
803346469b
commit
5ecf40056f
2 files changed
+38
-9
No files matched your search
@@ -247,6 +247,7 @@ fn main() {
|
|||||||
std::thread::spawn(move || responder.respond(serve_file(&eng, &request)));
|
std::thread::spawn(move || responder.respond(serve_file(&eng, &request)));
|
||||||
})
|
})
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
|
use tauri::{Listener, Manager};
|
||||||
// When launched elevated by the unprivileged instance, terminate the old process.
|
// When launched elevated by the unprivileged instance, terminate the old process.
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
if let Some(pid) = std::env::var("GUARA_REPLACE_PID")
|
if let Some(pid) = std::env::var("GUARA_REPLACE_PID")
|
||||||
@@ -264,15 +265,42 @@ fn main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reading raw disks requires root: request elevation as soon as the app launches,
|
// The window starts hidden (tauri.conf.json: "visible": false) so the
|
||||||
// without waiting for the user to look for a button. If authorization fails,
|
// unprivileged instance never flashes on screen before being replaced.
|
||||||
// the window stays open and the UI displays a warning.
|
// Reading raw disks requires root: request elevation as soon as the app
|
||||||
|
// launches, without waiting for the user to look for a button, and only
|
||||||
|
// show a window once we know which one it is — the elevated relaunch's,
|
||||||
|
// or this same one if elevation turned out not to be needed/possible.
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
if unsafe { libc::geteuid() != 0 } && std::env::var("GUARA_REPLACE_PID").is_err() {
|
{
|
||||||
let handle = app.handle().clone();
|
if unsafe { libc::geteuid() != 0 } && std::env::var("GUARA_REPLACE_PID").is_err() {
|
||||||
std::thread::spawn(move || {
|
use tauri::Emitter;
|
||||||
let _ = do_relaunch_elevated(handle);
|
let handle = app.handle().clone();
|
||||||
});
|
let handle_for_failure = app.handle().clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
// do_relaunch_elevated only emits "elevate-failed" itself once the
|
||||||
|
// child process has actually spawned and later exits non-zero. If it
|
||||||
|
// fails earlier (pkexec/osascript missing, exe path unresolved, log
|
||||||
|
// file unwritable), it returns Err directly without emitting anything
|
||||||
|
// — emit it here too, or the hidden window would never reappear.
|
||||||
|
if let Err(e) = do_relaunch_elevated(handle) {
|
||||||
|
let _ = handle_for_failure.emit("elevate-failed", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Whichever path emits it, make sure the window comes back so the
|
||||||
|
// user sees the warning instead of a silently stuck, invisible app.
|
||||||
|
if let Some(win) = app.get_webview_window("main") {
|
||||||
|
app.handle().listen("elevate-failed", move |_| {
|
||||||
|
let _ = win.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if let Some(win) = app.get_webview_window("main") {
|
||||||
|
let _ = win.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||||
|
if let Some(win) = app.get_webview_window("main") {
|
||||||
|
let _ = win.show();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
"height": 780,
|
"height": 780,
|
||||||
"minWidth": 420,
|
"minWidth": 420,
|
||||||
"minHeight": 560,
|
"minHeight": 560,
|
||||||
"resizable": true
|
"resizable": true,
|
||||||
|
"visible": false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
|
|||||||
Reference in new issue
Block a user