@@ -120,9 +120,12 @@ pub struct EditorApp {
120120 pub ( crate ) batch_output_dir : Option < PathBuf > ,
121121
122122 // Window state tracking
123- // Window state tracking
124- pub ( crate ) last_known_maximized : bool ,
125- pub ( crate ) startup_frame_count : usize ,
123+ /// True only for the very first update() call — used for the first-frame maximize trick
124+ pub ( crate ) first_frame : bool ,
125+ /// Whether the window should start maximized (from saved settings)
126+ pub ( crate ) start_maximized : bool ,
127+ /// Current maximized state, updated every frame from the OS viewport
128+ pub ( crate ) is_maximized : bool ,
126129}
127130
128131impl EditorApp {
@@ -200,8 +203,9 @@ impl EditorApp {
200203 batch_files : Vec :: new ( ) ,
201204 batch_keyfile : None ,
202205 batch_output_dir : None ,
203- last_known_maximized : settings. start_maximized ,
204- startup_frame_count : 0 ,
206+ first_frame : true ,
207+ start_maximized : settings. start_maximized ,
208+ is_maximized : false ,
205209 last_autosave_time : None ,
206210 last_copy_time : None ,
207211
@@ -232,56 +236,64 @@ impl eframe::App for EditorApp {
232236 // Update window title dynamically
233237 self . update_window_title ( ctx) ;
234238
235- // Track window state (maximized, position, size)
236- // Wait for a few frames to let the OS apply the initial window state
237- if self . startup_frame_count <= 30 {
238- self . startup_frame_count += 1 ;
239+ // ── Window state tracking ──────────────────────────────────────────
240+ // Read the OS-reported maximized state every frame.
241+ // This correctly tracks when the user clicks the Windows maximize/restore button.
242+ self . is_maximized = ctx. input ( |i| i. viewport ( ) . maximized . unwrap_or ( false ) ) ;
243+
244+ // First-frame maximize trick: with_maximized(true) in ViewportBuilder has a
245+ // race condition on Windows 10/11. Instead we send a ViewportCommand on the
246+ // very first frame, which fires after the window is fully created.
247+ if self . first_frame {
248+ self . first_frame = false ;
249+ if self . start_maximized {
250+ ctx. send_viewport_cmd ( egui:: ViewportCommand :: Maximized ( true ) ) ;
251+ }
239252 }
240-
241- if self . startup_frame_count > 30 {
242- ctx. input ( |i| {
243- let is_maximized = i. viewport ( ) . maximized . unwrap_or ( false ) ;
244-
245- // Only save changes to avoid disk spam
253+
254+ // Persist window geometry changes — only save when something actually changed
255+ {
246256 let mut changed = false ;
247257
248- if is_maximized != self . last_known_maximized {
249- self . settings . start_maximized = is_maximized ;
250- self . last_known_maximized = is_maximized;
258+ // Track maximize state changes
259+ if self . is_maximized != self . settings . start_maximized {
260+ self . settings . start_maximized = self . is_maximized ;
251261 changed = true ;
252262 }
253263
254- // If not maximized, save position and size
255- if !is_maximized {
256- if let Some ( rect) = i. viewport ( ) . outer_rect {
257- // Save position if valid (not negative coordinates that might be off-screen/minimized)
258- if rect. min . x >= 0.0 && rect. min . y >= 0.0 {
259- if ( self . settings . window_pos_x - rect. min . x ) . abs ( ) > 1.0 {
260- self . settings . window_pos_x = rect. min . x ;
264+ // When NOT maximized, save position and size so we preserve the last
265+ // known non-maximized geometry. Never overwrite these while maximized,
266+ // because the maximized rect covers the whole screen and would clobber
267+ // the user's preferred restored-window position/size.
268+ if !self . is_maximized {
269+ ctx. input ( |i| {
270+ if let Some ( rect) = i. viewport ( ) . outer_rect {
271+ // Only save valid positions (negative coords = off-screen/minimized)
272+ if rect. min . x >= 0.0 && rect. min . y >= 0.0 {
273+ if ( self . settings . window_pos_x - rect. min . x ) . abs ( ) > 1.0 {
274+ self . settings . window_pos_x = rect. min . x ;
275+ changed = true ;
276+ }
277+ if ( self . settings . window_pos_y - rect. min . y ) . abs ( ) > 1.0 {
278+ self . settings . window_pos_y = rect. min . y ;
279+ changed = true ;
280+ }
281+ }
282+ if ( self . settings . window_width - rect. width ( ) ) . abs ( ) > 1.0 {
283+ self . settings . window_width = rect. width ( ) ;
261284 changed = true ;
262- }
263- if ( self . settings . window_pos_y - rect. min . y ) . abs ( ) > 1.0 {
264- self . settings . window_pos_y = rect. min . y ;
285+ }
286+ if ( self . settings . window_height - rect. height ( ) ) . abs ( ) > 1.0 {
287+ self . settings . window_height = rect. height ( ) ;
265288 changed = true ;
266- }
267- }
268-
269- // Save size
270- if ( self . settings . window_width - rect. width ( ) ) . abs ( ) > 1.0 {
271- self . settings . window_width = rect. width ( ) ;
272- changed = true ;
273- }
274- if ( self . settings . window_height - rect. height ( ) ) . abs ( ) > 1.0 {
275- self . settings . window_height = rect. height ( ) ;
276- changed = true ;
289+ }
277290 }
278- }
291+ } ) ;
279292 }
280293
281294 if changed {
282295 let _ = self . settings . save ( ) ;
283296 }
284- } ) ;
285297 }
286298
287299 // Perform auto-save check
0 commit comments