@@ -14,13 +14,14 @@ use bitflags::bitflags;
14
14
use serde:: { Deserialize , Serialize } ;
15
15
use tauri:: {
16
16
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 ,
19
19
} ;
20
20
21
21
use std:: {
22
22
collections:: { HashMap , HashSet } ,
23
- fs:: { create_dir_all, File } ,
23
+ fs:: create_dir_all,
24
+ io:: BufReader ,
24
25
sync:: { Arc , Mutex } ,
25
26
} ;
26
27
@@ -106,6 +107,7 @@ impl Default for WindowState {
106
107
struct WindowStateCache ( Arc < Mutex < HashMap < String , WindowState > > > ) ;
107
108
/// Used to prevent deadlocks from resize and position event listeners setting the cached state on restoring states
108
109
struct RestoringWindowState ( Mutex < ( ) > ) ;
110
+
109
111
pub trait AppHandleExt {
110
112
/// Saves all open windows state to disk
111
113
fn save_window_state ( & self , flags : StateFlags ) -> Result < ( ) > ;
@@ -115,33 +117,31 @@ pub trait AppHandleExt {
115
117
116
118
impl < R : Runtime > AppHandleExt for tauri:: AppHandle < R > {
117
119
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 ) ? ;
136
138
}
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 ( ( ) )
144
139
}
140
+
141
+ create_dir_all ( app_dir) ?;
142
+ std:: fs:: write ( state_path, serde_json:: to_vec_pretty ( & * state) ?) ?;
143
+
144
+ Ok ( ( ) )
145
145
}
146
146
147
147
fn filename ( & self ) -> String {
@@ -159,6 +159,7 @@ impl<R: Runtime> WindowExt for WebviewWindow<R> {
159
159
self . as_ref ( ) . window ( ) . restore_state ( flags)
160
160
}
161
161
}
162
+
162
163
impl < R : Runtime > WindowExt for Window < R > {
163
164
fn restore_state ( & self , flags : StateFlags ) -> tauri:: Result < ( ) > {
164
165
let plugin_state = self . app_handle ( ) . state :: < PluginState > ( ) ;
@@ -352,7 +353,7 @@ impl Builder {
352
353
self
353
354
}
354
355
355
- /// Sets a filter callback to exclude specific windows from being tracked.
356
+ /// Sets a filter callback to exclude specific windows from being tracked.
356
357
/// Return `true` to save the state, or `false` to skip and not save it.
357
358
pub fn with_filter < F > ( mut self , filter_callback : F ) -> Self
358
359
where
@@ -391,25 +392,8 @@ impl Builder {
391
392
cmd:: filename
392
393
] )
393
394
. 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) ) ) ) ;
413
397
app. manage ( RestoringWindowState ( Mutex :: new ( ( ) ) ) ) ;
414
398
app. manage ( PluginState {
415
399
filename,
@@ -522,6 +506,18 @@ impl Builder {
522
506
}
523
507
}
524
508
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
+
525
521
trait MonitorExt {
526
522
fn intersects ( & self , position : PhysicalPosition < i32 > , size : PhysicalSize < u32 > ) -> bool ;
527
523
}
0 commit comments