@@ -14,13 +14,14 @@ use bitflags::bitflags;
1414use serde:: { Deserialize , Serialize } ;
1515use tauri:: {
1616 plugin:: { Builder as PluginBuilder , TauriPlugin } ,
17- Manager , Monitor , PhysicalPosition , PhysicalSize , RunEvent , Runtime , WebviewWindow , Window ,
18- WindowEvent ,
17+ AppHandle , Manager , Monitor , PhysicalPosition , PhysicalSize , RunEvent , Runtime , WebviewWindow ,
18+ Window , WindowEvent ,
1919} ;
2020
2121use std:: {
2222 collections:: { HashMap , HashSet } ,
23- fs:: { create_dir_all, File } ,
23+ fs:: create_dir_all,
24+ io:: BufReader ,
2425 sync:: { Arc , Mutex } ,
2526} ;
2627
@@ -106,6 +107,7 @@ impl Default for WindowState {
106107struct WindowStateCache ( Arc < Mutex < HashMap < String , WindowState > > > ) ;
107108/// Used to prevent deadlocks from resize and position event listeners setting the cached state on restoring states
108109struct RestoringWindowState ( Mutex < ( ) > ) ;
110+
109111pub trait AppHandleExt {
110112 /// Saves all open windows state to disk
111113 fn save_window_state ( & self , flags : StateFlags ) -> Result < ( ) > ;
@@ -115,33 +117,31 @@ pub trait AppHandleExt {
115117
116118impl < R : Runtime > AppHandleExt for tauri:: AppHandle < R > {
117119 fn save_window_state ( & self , flags : StateFlags ) -> Result < ( ) > {
118- if let Ok ( app_dir) = self . path ( ) . app_config_dir ( ) {
119- let plugin_state = self . state :: < PluginState > ( ) ;
120- let state_path = app_dir. join ( & plugin_state. filename ) ;
121- let windows = self . webview_windows ( ) ;
122- let cache = self . state :: < WindowStateCache > ( ) ;
123- let mut state = cache. 0 . lock ( ) . unwrap ( ) ;
124-
125- for ( label, s) in state. iter_mut ( ) {
126- let window = match & plugin_state. map_label {
127- Some ( map ) => windows
128- . iter ( )
129- . find_map ( |( l, window) | ( map ( l) == label) . then_some ( window) ) ,
130- None => windows . get ( label ) ,
131- } ;
132-
133- if let Some ( window ) = window {
134- window. update_state ( s , flags ) ? ;
135- }
120+ let app_dir = self . path ( ) . app_config_dir ( ) ? ;
121+ let plugin_state = self . state :: < PluginState > ( ) ;
122+ let state_path = app_dir. join ( & plugin_state. filename ) ;
123+ let windows = self . webview_windows ( ) ;
124+ let cache = self . state :: < WindowStateCache > ( ) ;
125+ let mut state = cache. 0 . lock ( ) . unwrap ( ) ;
126+
127+ for ( label, s) in state. iter_mut ( ) {
128+ let window = if let Some ( map ) = & plugin_state. map_label {
129+ windows
130+ . iter ( )
131+ . find_map ( |( l, window) | ( map ( l) == label) . then_some ( window) )
132+ } else {
133+ windows . get ( label )
134+ } ;
135+
136+ if let Some ( window ) = window {
137+ window . update_state ( s , flags ) ? ;
136138 }
137-
138- create_dir_all ( & app_dir)
139- . map_err ( Error :: Io )
140- . and_then ( |_| File :: create ( state_path) . map_err ( Into :: into) )
141- . and_then ( |mut f| serde_json:: to_writer_pretty ( & mut f, & * state) . map_err ( Into :: into) )
142- } else {
143- Ok ( ( ) )
144139 }
140+
141+ create_dir_all ( app_dir) ?;
142+ std:: fs:: write ( state_path, serde_json:: to_vec_pretty ( & * state) ?) ?;
143+
144+ Ok ( ( ) )
145145 }
146146
147147 fn filename ( & self ) -> String {
@@ -159,6 +159,7 @@ impl<R: Runtime> WindowExt for WebviewWindow<R> {
159159 self . as_ref ( ) . window ( ) . restore_state ( flags)
160160 }
161161}
162+
162163impl < R : Runtime > WindowExt for Window < R > {
163164 fn restore_state ( & self , flags : StateFlags ) -> tauri:: Result < ( ) > {
164165 let plugin_state = self . app_handle ( ) . state :: < PluginState > ( ) ;
@@ -352,7 +353,7 @@ impl Builder {
352353 self
353354 }
354355
355- /// Sets a filter callback to exclude specific windows from being tracked.
356+ /// Sets a filter callback to exclude specific windows from being tracked.
356357 /// Return `true` to save the state, or `false` to skip and not save it.
357358 pub fn with_filter < F > ( mut self , filter_callback : F ) -> Self
358359 where
@@ -391,25 +392,8 @@ impl Builder {
391392 cmd:: filename
392393 ] )
393394 . setup ( |app, _api| {
394- let cache: Arc < Mutex < HashMap < String , WindowState > > > =
395- if let Ok ( app_dir) = app. path ( ) . app_config_dir ( ) {
396- let state_path = app_dir. join ( & filename) ;
397- if state_path. exists ( ) {
398- Arc :: new ( Mutex :: new (
399- std:: fs:: read ( state_path)
400- . map_err ( Error :: from)
401- . and_then ( |state| {
402- serde_json:: from_slice ( & state) . map_err ( Into :: into)
403- } )
404- . unwrap_or_default ( ) ,
405- ) )
406- } else {
407- Default :: default ( )
408- }
409- } else {
410- Default :: default ( )
411- } ;
412- app. manage ( WindowStateCache ( cache) ) ;
395+ let cache = load_saved_window_states ( app, & filename) . unwrap_or_default ( ) ;
396+ app. manage ( WindowStateCache ( Arc :: new ( Mutex :: new ( cache) ) ) ) ;
413397 app. manage ( RestoringWindowState ( Mutex :: new ( ( ) ) ) ) ;
414398 app. manage ( PluginState {
415399 filename,
@@ -522,6 +506,18 @@ impl Builder {
522506 }
523507}
524508
509+ fn load_saved_window_states < R : Runtime > (
510+ app : & AppHandle < R > ,
511+ filename : & String ,
512+ ) -> Result < HashMap < String , WindowState > > {
513+ let app_dir = app. path ( ) . app_config_dir ( ) ?;
514+ let state_path = app_dir. join ( filename) ;
515+ let file = std:: fs:: File :: open ( state_path) ?;
516+ let reader = BufReader :: new ( file) ;
517+ let states = serde_json:: from_reader ( reader) ?;
518+ Ok ( states)
519+ }
520+
525521trait MonitorExt {
526522 fn intersects ( & self , position : PhysicalPosition < i32 > , size : PhysicalSize < u32 > ) -> bool ;
527523}
0 commit comments