musealpha / src-tauri /src /browser /layout.rs
asdf98's picture
fix: child webview positioning use logical CSS coords and offscreen parking
a5ca9aa verified
use tauri::{AppHandle, LogicalPosition, LogicalSize, Manager};
use super::tab_manager::{tab_label, ViewportLayout};
use crate::state::AppState;
const OFFSCREEN_X: f64 = -32000.0;
const OFFSCREEN_Y: f64 = -32000.0;
pub fn bounds(layout: &ViewportLayout) -> (f64, f64, f64, f64) {
(
layout.x.max(0.0),
layout.y.max(0.0),
layout.width.max(1.0),
layout.height.max(1.0),
)
}
/// Child webviews added with `window.add_child` are positioned in the parent
/// window client-area logical coordinate space. DOM getBoundingClientRect()
/// from the main webview also reports CSS/logical pixels relative to that same
/// client area (because our main webview fills the undecorated window).
///
/// So: use LogicalPosition/LogicalSize directly. Do NOT multiply by DPI here.
/// Passing PhysicalPosition can push the child webview out of the intended
/// panel on scaled displays and was the main reason it appeared invisible.
pub fn show_tab(app: &AppHandle, tab_id: &str, layout: &ViewportLayout) -> Result<(), String> {
let label = tab_label(app, tab_id)?;
let (x, y, w, h) = bounds(layout);
if let Some(webview) = app.get_webview(&label) {
// Bounds first, then visible/focus. Idempotent and cross-platform.
webview.set_position(LogicalPosition::new(x, y)).map_err(|e| e.to_string())?;
webview.set_size(LogicalSize::new(w, h)).map_err(|e| e.to_string())?;
let _ = webview.show();
let _ = webview.set_focus();
}
Ok(())
}
/// Park offscreen instead of relying on hide/show lifecycle. This keeps WebView2
/// initialized and avoids stale rendering after panel close/open.
pub fn hide_tab(app: &AppHandle, tab_id: &str) -> Result<(), String> {
let label = tab_label(app, tab_id)?;
if let Some(webview) = app.get_webview(&label) {
webview.set_position(LogicalPosition::new(OFFSCREEN_X, OFFSCREEN_Y)).map_err(|e| e.to_string())?;
webview.set_size(LogicalSize::new(1.0, 1.0)).map_err(|e| e.to_string())?;
// Do not call hide(); parking is more reliable with child WebView2.
}
Ok(())
}
pub fn resize_active(app: &AppHandle, layout: &ViewportLayout) -> Result<(), String> {
let active = {
let state = app.state::<AppState>();
let tabs = state.tabs.lock().map_err(|_| "lock")?;
tabs.active.clone()
};
if let Some(active_id) = active {
show_tab(app, &active_id, layout)?;
}
Ok(())
}