teardown scene window when unused
This commit is contained in:
@@ -80,7 +80,8 @@ pub fn apply_macos_decoration_window_policy(app_handle: &AppHandle, window_label
|
||||
pub const WINDOW_LABEL: &str = "scene";
|
||||
|
||||
fn track_scene_hitboxes(app_handle: AppHandle, window: tauri::WebviewWindow) {
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let tracked_window = window.clone();
|
||||
let task = tauri::async_runtime::spawn(async move {
|
||||
let mut ignores_cursor = true;
|
||||
let mut interval = tokio::time::interval(crate::cursor::SYSTEM_CURSOR_POLL_INTERVAL);
|
||||
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||
@@ -101,14 +102,14 @@ fn track_scene_hitboxes(app_handle: AppHandle, window: tauri::WebviewWindow) {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let window_position = match window.outer_position() {
|
||||
let window_position = match tracked_window.outer_position() {
|
||||
Ok(position) => position,
|
||||
Err(error) => {
|
||||
eprintln!("Failed to read scene position for hit-testing: {error}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let scale_factor = match window.scale_factor() {
|
||||
let scale_factor = match tracked_window.scale_factor() {
|
||||
Ok(scale_factor) => scale_factor,
|
||||
Err(error) => {
|
||||
eprintln!("Failed to read scene scale factor for hit-testing: {error}");
|
||||
@@ -126,7 +127,7 @@ fn track_scene_hitboxes(app_handle: AppHandle, window: tauri::WebviewWindow) {
|
||||
};
|
||||
|
||||
if should_ignore != ignores_cursor {
|
||||
match window.set_ignore_cursor_events(should_ignore) {
|
||||
match tracked_window.set_ignore_cursor_events(should_ignore) {
|
||||
Ok(()) => ignores_cursor = should_ignore,
|
||||
Err(error) => {
|
||||
eprintln!("Failed to update scene cursor event policy: {error}")
|
||||
@@ -135,6 +136,11 @@ fn track_scene_hitboxes(app_handle: AppHandle, window: tauri::WebviewWindow) {
|
||||
}
|
||||
}
|
||||
});
|
||||
window.on_window_event(move |event| {
|
||||
if matches!(event, tauri::WindowEvent::Destroyed) {
|
||||
task.abort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn overlay_fullscreen(
|
||||
@@ -156,9 +162,8 @@ pub fn overlay_fullscreen(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn open_window(app_handle: &AppHandle) -> Result<tauri::WebviewWindow, String> {
|
||||
fn open_window(app_handle: &AppHandle) -> Result<tauri::WebviewWindow, String> {
|
||||
if let Some(window) = app_handle.get_webview_window(WINDOW_LABEL) {
|
||||
window.show().map_err(|e| e.to_string())?;
|
||||
return Ok(window);
|
||||
};
|
||||
|
||||
@@ -181,26 +186,77 @@ pub fn open_window(app_handle: &AppHandle) -> Result<tauri::WebviewWindow, Strin
|
||||
.skip_taskbar(true)
|
||||
.shadow(false)
|
||||
.accept_first_mouse(true)
|
||||
.visible(true)
|
||||
.visible(false)
|
||||
.focused(false);
|
||||
|
||||
let window = builder.build().map_err(|e: tauri::Error| e.to_string())?;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
window.open_devtools();
|
||||
let configure = || -> Result<(), tauri::Error> {
|
||||
overlay_fullscreen(app_handle, &window)?;
|
||||
window.set_ignore_cursor_events(true)?;
|
||||
window.show()?;
|
||||
Ok(())
|
||||
};
|
||||
if let Err(error) = configure() {
|
||||
let _ = window.destroy();
|
||||
return Err(error.to_string());
|
||||
}
|
||||
apply_macos_decoration_window_policy(app_handle, WINDOW_LABEL.to_string());
|
||||
track_scene_hitboxes(app_handle.clone(), window.clone());
|
||||
|
||||
Ok(window)
|
||||
}
|
||||
|
||||
/// Serializes native create/destroy requests, including destruction acknowledgement.
|
||||
#[derive(Default)]
|
||||
struct SceneWindow(tokio::sync::Mutex<()>);
|
||||
|
||||
pub(crate) fn is_initialized(handle: &AppHandle) -> bool {
|
||||
handle.try_state::<SceneWindow>().is_some()
|
||||
}
|
||||
|
||||
/// Creates a fully configured scene, or destroys its webview and stops hit-testing.
|
||||
pub(crate) async fn reconcile_window(handle: &AppHandle, open: bool) -> Result<(), String> {
|
||||
let state = handle
|
||||
.try_state::<SceneWindow>()
|
||||
.ok_or("scene UI has not started")?;
|
||||
let _guard = state.0.lock().await;
|
||||
if open {
|
||||
if handle.get_webview_window(WINDOW_LABEL).is_none() {
|
||||
handle
|
||||
.state::<SceneHitboxes>()
|
||||
.0
|
||||
.write()
|
||||
.map_err(|error| error.to_string())?
|
||||
.clear();
|
||||
open_window(&handle)?;
|
||||
}
|
||||
} else if let Some(window) = handle.get_webview_window(WINDOW_LABEL) {
|
||||
let (sender, receiver) = tokio::sync::oneshot::channel();
|
||||
let sender = std::sync::Mutex::new(Some(sender));
|
||||
window.on_window_event(move |event| {
|
||||
if matches!(event, tauri::WindowEvent::Destroyed)
|
||||
&& let Some(sender) = sender.lock().unwrap().take()
|
||||
{
|
||||
let _ = sender.send(());
|
||||
}
|
||||
});
|
||||
window.destroy().map_err(|error| error.to_string())?;
|
||||
receiver.await.map_err(|error| error.to_string())?;
|
||||
handle
|
||||
.state::<SceneHitboxes>()
|
||||
.0
|
||||
.write()
|
||||
.map_err(|error| error.to_string())?
|
||||
.clear();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn init(app_handle: &AppHandle) {
|
||||
app_handle.manage(SceneHitboxes::default());
|
||||
let window = open_window(app_handle).expect("Scene window should be opened successfully");
|
||||
overlay_fullscreen(app_handle, &window).expect("Scene window should be fullscreened");
|
||||
apply_macos_decoration_window_policy(app_handle, WINDOW_LABEL.to_string());
|
||||
window
|
||||
.set_ignore_cursor_events(true)
|
||||
.expect("Scene window needs to ignore cursor events");
|
||||
track_scene_hitboxes(app_handle.clone(), window);
|
||||
// The existing puppet tick opens the scene only after publishing its snapshot.
|
||||
app_handle.manage(SceneWindow::default());
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user