@ -17,6 +17,8 @@ use std::{
sync ::{ Arc , Mutex } ,
sync ::{ Arc , Mutex } ,
} ;
} ;
mod cmd ;
pub const STATE_FILENAME : & str = ".window-state" ;
pub const STATE_FILENAME : & str = ".window-state" ;
#[ derive(Debug, thiserror::Error) ]
#[ derive(Debug, thiserror::Error) ]
@ -34,7 +36,7 @@ pub enum Error {
pub type Result < T > = std ::result ::Result < T , Error > ;
pub type Result < T > = std ::result ::Result < T , Error > ;
bitflags ! {
bitflags ! {
#[ derive(Clone, Copy )]
#[ derive(Clone, Copy , Debug )]
pub struct StateFlags : u32 {
pub struct StateFlags : u32 {
const SIZE = 1 < < 0 ;
const SIZE = 1 < < 0 ;
const POSITION = 1 < < 1 ;
const POSITION = 1 < < 1 ;
@ -51,7 +53,7 @@ impl Default for StateFlags {
}
}
}
}
#[ derive(Debug, Default, Deserialize, Serialize )]
#[ derive(Debug, Default, Deserialize, Serialize , PartialEq )]
struct WindowState {
struct WindowState {
width : f64 ,
width : f64 ,
height : f64 ,
height : f64 ,
@ -65,6 +67,7 @@ struct WindowState {
struct WindowStateCache ( Arc < Mutex < HashMap < String , WindowState > > > ) ;
struct WindowStateCache ( Arc < Mutex < HashMap < String , WindowState > > > ) ;
pub trait AppHandleExt {
pub trait AppHandleExt {
/// Saves all open windows state to disk
fn save_window_state ( & self , flags : StateFlags ) -> Result < ( ) > ;
fn save_window_state ( & self , flags : StateFlags ) -> Result < ( ) > ;
}
}
@ -94,6 +97,7 @@ impl<R: Runtime> AppHandleExt for tauri::AppHandle<R> {
}
}
pub trait WindowExt {
pub trait WindowExt {
/// Restores this window state from disk
fn restore_state ( & self , flags : StateFlags ) -> tauri ::Result < ( ) > ;
fn restore_state ( & self , flags : StateFlags ) -> tauri ::Result < ( ) > ;
}
}
@ -101,9 +105,15 @@ impl<R: Runtime> WindowExt for Window<R> {
fn restore_state ( & self , flags : StateFlags ) -> tauri ::Result < ( ) > {
fn restore_state ( & self , flags : StateFlags ) -> tauri ::Result < ( ) > {
let cache = self . state ::< WindowStateCache > ( ) ;
let cache = self . state ::< WindowStateCache > ( ) ;
let mut c = cache . 0. lock ( ) . unwrap ( ) ;
let mut c = cache . 0. lock ( ) . unwrap ( ) ;
let mut should_show = true ;
let mut should_show = true ;
if let Some ( state ) = c . get ( self . label ( ) ) {
if let Some ( state ) = c . get ( self . label ( ) ) {
// avoid restoring the default zeroed state
if * state = = WindowState ::default ( ) {
return Ok ( ( ) ) ;
}
if flags . contains ( StateFlags ::DECORATIONS ) {
if flags . contains ( StateFlags ::DECORATIONS ) {
self . set_decorations ( state . decorated ) ? ;
self . set_decorations ( state . decorated ) ? ;
}
}
@ -270,6 +280,10 @@ impl Builder {
pub fn build < R : Runtime > ( self ) -> TauriPlugin < R > {
pub fn build < R : Runtime > ( self ) -> TauriPlugin < R > {
let flags = self . state_flags ;
let flags = self . state_flags ;
PluginBuilder ::new ( "window-state" )
PluginBuilder ::new ( "window-state" )
. invoke_handler ( tauri ::generate_handler ! [
cmd ::save_window_state ,
cmd ::restore_state
] )
. setup ( | app | {
. setup ( | app | {
let cache : Arc < Mutex < HashMap < String , WindowState > > > = if let Some ( app_dir ) =
let cache : Arc < Mutex < HashMap < String , WindowState > > > = if let Some ( app_dir ) =
app . path_resolver ( ) . app_config_dir ( )
app . path_resolver ( ) . app_config_dir ( )
@ -305,6 +319,17 @@ impl Builder {
let label = window . label ( ) . to_string ( ) ;
let label = window . label ( ) . to_string ( ) ;
let window_clone = window . clone ( ) ;
let window_clone = window . clone ( ) ;
let flags = self . state_flags ;
let flags = self . state_flags ;
// insert a default state if this window should be tracked and
// the disk cache doesn't have a state for it
{
cache
. lock ( )
. unwrap ( )
. entry ( label . clone ( ) )
. or_insert_with ( WindowState ::default ) ;
}
window . on_window_event ( move | e | {
window . on_window_event ( move | e | {
if let WindowEvent ::CloseRequested { .. } = e {
if let WindowEvent ::CloseRequested { .. } = e {
let mut c = cache . lock ( ) . unwrap ( ) ;
let mut c = cache . lock ( ) . unwrap ( ) ;