Safe mode: one run with only the shell working (the app menu, --safe-mode, Shift at launch on Windows)
Host: `safe.rs` is a flag in this process's memory, never written to disk, so the next normal start is back to the owner's setup. While it is on a site tab gets the tab bridge and nothing of the app's page layers: its document-start scripts are `SiteHooks::safe_init_scripts` (default: the bridge alone) instead of `init_scripts`; `site_page_loaded`, `tab_placed` and `tab_background` are not called; `page_scripts` is empty; `eval_in_site_tabs` does nothing. So no page runtime, plugins, theme, custom CSS, feature flags, fixes, hotfix data or words reach a page: the site runs as in a browser, and only the shell is the app's. It starts from the launch argument `--safe-mode` (for when the interface itself is broken), from Shift held while the app starts (Windows), or from the shell: `safe_mode_get` / `safe_mode_set {on}` (shell-only), where a switch rebuilds every tab webview (profiles marked stale, `tabs-rebuild` asks the shell for its layout) so document-start scripts change too. Tests: the argument, the flag, and that app.rs and host.rs gate every layer.
Frame: the app menu's "Restart in safe mode…" says what it does before anything reloads; while on, the titlebar shows an amber "Safe mode | Leave" chip (one click leaves) and the row reads "Leave safe mode"; the chrome drops its theme (and pane themes) and takes it back on leaving, without touching the first-frame cache. `features.safeMode` (on by default).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d24b1d2234
commit
ca46210e53
19 changed files with 342 additions and 20 deletions
|
|
@ -48,6 +48,10 @@ pub fn tab_webview<R: Runtime>(app: &AppHandle<R>, id: &str) -> Option<Webview<R
|
|||
|
||||
/// Evaluates `script` in every tab that is on the site right now.
|
||||
pub fn eval_in_site_tabs<R: Runtime>(app: &AppHandle<R>, site: &SiteSpec, script: &str) {
|
||||
// Safe mode: site pages run none of the app's layers, so nothing is pushed into them either.
|
||||
if crate::safe::active() {
|
||||
return;
|
||||
}
|
||||
for (label, webview) in app.webviews() {
|
||||
if policy::tab_id(&label).is_some() && webview.url().is_ok_and(|url| site.is_origin(&url)) {
|
||||
let _ = webview.eval(script);
|
||||
|
|
@ -89,6 +93,21 @@ pub fn tab_action<R: Runtime>(app: &AppHandle<R>, id: &str, action: &str) -> Res
|
|||
result.map_err(|error| format!("TAB: {error}"))
|
||||
}
|
||||
|
||||
/// Whether Shift is held right now (asked once while the app starts: safe mode). Windows only;
|
||||
/// elsewhere the launch argument is the way in.
|
||||
pub fn shift_held() -> bool {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use windows::Win32::UI::Input::KeyboardAndMouse::{GetAsyncKeyState, VK_SHIFT};
|
||||
// SAFETY: a plain Win32 key-state read. The high bit means the key is down.
|
||||
unsafe { GetAsyncKeyState(i32::from(VK_SHIFT.0)) < 0 }
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// The remembered page zoom per tab ([`crate::zoom`], app data `zoom.json`), read once.
|
||||
fn zooms<R: Runtime>(app: &AppHandle<R>) -> std::sync::MutexGuard<'static, crate::zoom::ZoomMap> {
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue