@@ -23,9 +23,9 @@ use crate::persist;
2323use crate :: preferences;
2424use crate :: render:: { RenderError , RenderState } ;
2525use crate :: spawner:: TokioSpawner ;
26- use crate :: ui:: { InputEvent , UiCommand , UiInstance } ;
26+ use crate :: ui:: { Acceleration , InputEvent , UiCommand , UiConfig , UiInstance } ;
2727use crate :: window:: Window ;
28- use crate :: wrapper:: messages:: { DesktopFrontendMessage , DesktopWrapperMessage , IngestAction , Preferences } ;
28+ use crate :: wrapper:: messages:: { DesktopFrontendMessage , DesktopWrapperMessage , IngestAction } ;
2929use crate :: wrapper:: { DesktopWrapper , FolderStore , MmapResourceStorage , WgpuContext , WgpuExecutor , serialize_frontend_messages} ;
3030
3131pub ( crate ) struct App {
@@ -40,18 +40,16 @@ pub(crate) struct App {
4040 pending_dnd_fetch : Option < AsyncRequestSerial > ,
4141 pending_clipboard_fetch : Option < AsyncRequestSerial > ,
4242 input_state : InputState ,
43- ui_scale : f64 ,
4443 app_event_receiver : Receiver < AppEvent > ,
4544 app_event_scheduler : AppEventScheduler ,
4645 desktop_wrapper : DesktopWrapper ,
4746 ui : UiInstance ,
4847 ui_frame_received : bool ,
4948 start_render_sender : SyncSender < ( ) > ,
50- web_communication_initialized : bool ,
49+ ui_initialized : Option < Instant > ,
5150 web_communication_startup_buffer : Vec < Vec < u8 > > ,
52- preferences : Preferences ,
51+ preferences : preferences :: DesktopPreferences ,
5352 launch_documents : Option < Vec < PathBuf > > ,
54- startup_time : Option < Instant > ,
5553 exiting : Arc < AtomicBool > ,
5654 exit_reason : ExitReason ,
5755}
@@ -66,7 +64,7 @@ impl App {
6664 wgpu_context : WgpuContext ,
6765 app_event_receiver : Receiver < AppEvent > ,
6866 app_event_scheduler : AppEventScheduler ,
69- preferences : Preferences ,
67+ preferences : preferences :: DesktopPreferences ,
7068 launch_documents : Vec < PathBuf > ,
7169 ) -> Self {
7270 let ctrlc_app_event_scheduler = app_event_scheduler. clone ( ) ;
@@ -96,7 +94,6 @@ impl App {
9694 let runtime_wake = move || {
9795 let _ = runtime_wake_sender. try_send ( ( ) ) ;
9896 } ;
99- // The node graph and the window's overlays render through this one executor, sharing its renderer and texture cache
10097 let wgpu_executor = WgpuExecutor :: with_context ( wgpu_context) . expect ( "Failed to create WgpuExecutor" ) ;
10198 let ( desktop_wrapper, mut node_runtime) = DesktopWrapper :: new (
10299 rand:: rng ( ) . random ( ) ,
@@ -133,18 +130,16 @@ impl App {
133130 pending_dnd_fetch : None ,
134131 pending_clipboard_fetch : None ,
135132 input_state : InputState :: new ( ) ,
136- ui_scale : 1. ,
137133 app_event_receiver,
138134 app_event_scheduler,
139135 desktop_wrapper,
140136 ui,
141137 ui_frame_received : false ,
142138 start_render_sender,
143- web_communication_initialized : false ,
139+ ui_initialized : None ,
144140 web_communication_startup_buffer : Vec :: new ( ) ,
145141 preferences,
146142 launch_documents : Some ( launch_documents) ,
147- startup_time : None ,
148143 exiting,
149144 exit_reason : ExitReason :: Shutdown ,
150145 }
@@ -166,6 +161,22 @@ impl App {
166161 self . app_event_scheduler . schedule ( AppEvent :: Exit ) ;
167162 }
168163
164+ fn restart_ui ( & mut self ) {
165+ let acceleration = self . preferences . acceleration ;
166+ if let Err ( error) = self . ui . restart ( UiConfig { acceleration } ) {
167+ tracing:: error!( "Failed to restart the UI: {error}" ) ;
168+ self . exit ( Some ( ExitReason :: Shutdown ) ) ;
169+ return ;
170+ }
171+ self . ui_initialized = None ;
172+
173+ self . window_size = PhysicalSize { width : 0 , height : 0 } ;
174+ self . window_scale = 1. ;
175+ self . window_maximized = false ;
176+ self . window_fullscreen = false ;
177+ self . resize ( ) ;
178+ }
179+
169180 fn resize ( & mut self ) {
170181 let Some ( window) = & self . window else {
171182 tracing:: error!( "Resize failed due to missing window" ) ;
@@ -186,7 +197,7 @@ impl App {
186197 }
187198
188199 let size = window. surface_size ( ) ;
189- let scale = window. scale_factor ( ) * self . ui_scale ;
200+ let scale = window. scale_factor ( ) * self . preferences . ui_scale ;
190201 let is_new_size = size != self . window_size ;
191202 let is_new_scale = scale != self . window_scale ;
192203
@@ -309,13 +320,9 @@ impl App {
309320 DesktopFrontendMessage :: WindowUpdateDirectInput { enabled } => {
310321 self . input_state . set_direct_input ( enabled) ;
311322 }
312- DesktopFrontendMessage :: UpdateUIScale { scale } => {
313- self . ui_scale = scale;
314- self . resize ( ) ;
315- }
316323 DesktopFrontendMessage :: UpdateOverlays ( scene) => {
317324 if let Some ( render_state) = & mut self . render_state {
318- render_state. set_overlays_scene ( scene) ;
325+ render_state. set_overlays_scene ( * scene) ;
319326 }
320327 if let Some ( window) = & self . window {
321328 window. request_redraw ( ) ;
@@ -327,8 +334,26 @@ impl App {
327334 DesktopFrontendMessage :: PersistenceReadState => {
328335 responses. push ( DesktopWrapperMessage :: LoadPersistedState { state : persist:: read_state ( ) } ) ;
329336 }
330- DesktopFrontendMessage :: PersistenceWritePreferences { preferences } => {
337+ DesktopFrontendMessage :: PersistenceUpdatePreferences { preferences } => {
338+ let old_preferences = self . preferences . clone ( ) ;
339+ self . preferences = preferences:: DesktopPreferences :: from ( & preferences) ;
340+
331341 preferences:: write ( preferences) ;
342+
343+ if old_preferences. present_mode != self . preferences . present_mode
344+ && let Some ( render_state) = & mut self . render_state
345+ {
346+ render_state. set_present_mode ( self . preferences . present_mode ) ;
347+ }
348+
349+ if old_preferences. ui_scale != self . preferences . ui_scale {
350+ self . resize ( ) ;
351+ }
352+
353+ if old_preferences. acceleration != self . preferences . acceleration {
354+ tracing:: info!( "UI acceleration preference changed, restarting UI" ) ;
355+ self . restart_ui ( ) ;
356+ }
332357 }
333358 DesktopFrontendMessage :: PersistenceLoadPreferences => {
334359 let preferences = preferences:: read ( ) ;
@@ -337,7 +362,6 @@ impl App {
337362 }
338363 DesktopFrontendMessage :: OpenLaunchDocuments => {
339364 let Some ( launch_documents) = std:: mem:: take ( & mut self . launch_documents ) else {
340- tracing:: error!( "OpenLaunchDocuments should only be sent once" ) ;
341365 return ;
342366 } ;
343367 self . app_event_scheduler . schedule ( AppEvent :: OpenFiles ( launch_documents) ) ;
@@ -434,7 +458,7 @@ impl App {
434458 }
435459
436460 fn send_or_queue_web_message ( & mut self , message : Vec < u8 > ) {
437- if self . web_communication_initialized {
461+ if self . ui_initialized . is_some ( ) {
438462 self . ui . send ( UiCommand :: Message ( message) ) ;
439463 } else {
440464 self . web_communication_startup_buffer . push ( message) ;
@@ -444,7 +468,8 @@ impl App {
444468 fn user_event ( & mut self , event_loop : & dyn ActiveEventLoop , event : AppEvent ) {
445469 match event {
446470 AppEvent :: WebCommunicationInitialized => {
447- self . web_communication_initialized = true ;
471+ self . ui_initialized = Some ( Instant :: now ( ) ) ;
472+ self . ui_frame_received = false ;
448473 for message in self . web_communication_startup_buffer . drain ( ..) {
449474 self . ui . send ( UiCommand :: Message ( message) ) ;
450475 }
@@ -505,6 +530,10 @@ impl App {
505530 tracing:: info!( "Exiting main event loop" ) ;
506531 event_loop. exit ( ) ;
507532 }
533+ AppEvent :: UiCrashed if self . ui_initialized . is_some ( ) => {
534+ tracing:: error!( "UI process crashed, restarting it." ) ;
535+ self . restart_ui ( ) ;
536+ }
508537 AppEvent :: UiCrashed => {
509538 tracing:: error!( "UI process crashed, exiting." ) ;
510539 self . exit ( Some ( ExitReason :: Shutdown ) ) ;
@@ -548,21 +577,17 @@ impl ApplicationHandler for App {
548577 let window = Window :: new ( event_loop, self . app_event_scheduler . clone ( ) ) ;
549578 self . window = Some ( window) ;
550579
551- #[ cfg( not( target_os = "macos" ) ) ]
552- let present_mode = None ;
553- #[ cfg( target_os = "macos" ) ]
554- let present_mode = if !self . preferences . vsync { Some ( wgpu:: PresentMode :: Immediate ) } else { None } ;
555-
556- let render_state = RenderState :: new ( self . window . as_ref ( ) . unwrap ( ) , self . wgpu_executor . clone ( ) , present_mode) ;
580+ let mut render_state = RenderState :: new ( self . window . as_ref ( ) . unwrap ( ) , self . wgpu_executor . clone ( ) ) ;
581+ if self . preferences . present_mode . is_some ( ) {
582+ render_state. set_present_mode ( self . preferences . present_mode ) ;
583+ }
557584 self . render_state = Some ( render_state) ;
558585
559586 if let Some ( window) = & self . window . as_ref ( ) {
560587 window. show ( ) ;
561588 }
562589
563590 self . resize ( ) ;
564-
565- self . startup_time = Some ( Instant :: now ( ) ) ;
566591 }
567592
568593 fn proxy_wake_up ( & mut self , event_loop : & dyn ActiveEventLoop ) {
@@ -625,13 +650,14 @@ impl ApplicationHandler for App {
625650 }
626651
627652 if !self . ui_frame_received
628- && !self . preferences . disable_ui_acceleration
629- && self . web_communication_initialized
630- && let Some ( startup_time) = self . startup_time
631- && startup_time. elapsed ( ) > Duration :: from_secs ( 3 )
653+ && self . preferences . acceleration != Acceleration :: Disabled
654+ && let Some ( initialized) = self . ui_initialized
655+ && initialized. elapsed ( ) > Duration :: from_secs ( 3 )
632656 {
633- tracing:: error!( "UI acceleration not working, exiting." ) ;
634- self . exit ( Some ( ExitReason :: UiAccelerationFailure ) ) ;
657+ tracing:: error!( "UI acceleration not working, disabling it." ) ;
658+ let mut preferences = preferences:: read ( ) ;
659+ preferences. disable_ui_acceleration = true ;
660+ self . dispatch_desktop_wrapper_message ( DesktopWrapperMessage :: LoadPreferences { preferences } ) ;
635661 }
636662 }
637663 WindowEvent :: DragEntered { id, .. } => {
@@ -733,5 +759,4 @@ impl ApplicationHandler for App {
733759pub ( crate ) enum ExitReason {
734760 Shutdown ,
735761 Restart ,
736- UiAccelerationFailure ,
737762}
0 commit comments