1- use crate :: CustomEvent ;
2- use crate :: cef:: WindowSize ;
3- use crate :: consts:: { APP_NAME , CEF_MESSAGE_LOOP_MAX_ITERATIONS } ;
4- use crate :: persist:: PersistentData ;
5- use crate :: render:: GraphicsState ;
6- use graphite_desktop_wrapper:: messages:: { DesktopFrontendMessage , DesktopWrapperMessage , Platform } ;
7- use graphite_desktop_wrapper:: { DesktopWrapper , NodeGraphExecutionResult , WgpuContext , serialize_frontend_messages} ;
8-
91use rfd:: AsyncFileDialog ;
102use std:: sync:: Arc ;
3+ use std:: sync:: mpsc:: Receiver ;
114use std:: sync:: mpsc:: Sender ;
125use std:: sync:: mpsc:: SyncSender ;
136use std:: thread;
147use std:: time:: Duration ;
158use std:: time:: Instant ;
169use winit:: application:: ApplicationHandler ;
17- use winit:: dpi:: PhysicalSize ;
1810use winit:: event:: WindowEvent ;
1911use winit:: event_loop:: ActiveEventLoop ;
2012use winit:: event_loop:: ControlFlow ;
21- use winit:: event_loop:: EventLoopProxy ;
2213use winit:: window:: Window ;
2314use winit:: window:: WindowId ;
2415
2516use crate :: cef;
17+ use crate :: consts:: CEF_MESSAGE_LOOP_MAX_ITERATIONS ;
18+ use crate :: event:: { AppEvent , AppEventScheduler } ;
2619use crate :: native_window;
20+ use crate :: persist:: PersistentData ;
21+ use crate :: render:: GraphicsState ;
22+ use graphite_desktop_wrapper:: messages:: { DesktopFrontendMessage , DesktopWrapperMessage , Platform } ;
23+ use graphite_desktop_wrapper:: { DesktopWrapper , NodeGraphExecutionResult , WgpuContext , serialize_frontend_messages} ;
2724
28- pub ( crate ) struct WinitApp {
25+ pub ( crate ) struct App {
2926 cef_context : Box < dyn cef:: CefContext > ,
30- window : Option < Arc < Window > > ,
27+ window : Option < Arc < dyn Window > > ,
3128 native_window : native_window:: NativeWindowHandle ,
3229 cef_schedule : Option < Instant > ,
33- window_size_sender : Sender < WindowSize > ,
30+ cef_window_size_sender : Sender < cef :: WindowSize > ,
3431 graphics_state : Option < GraphicsState > ,
3532 wgpu_context : WgpuContext ,
36- event_loop_proxy : EventLoopProxy < CustomEvent > ,
33+ app_event_receiver : Receiver < AppEvent > ,
34+ app_event_scheduler : AppEventScheduler ,
3735 desktop_wrapper : DesktopWrapper ,
3836 last_ui_update : Instant ,
3937 avg_frame_time : f32 ,
@@ -43,14 +41,20 @@ pub(crate) struct WinitApp {
4341 persistent_data : PersistentData ,
4442}
4543
46- impl WinitApp {
47- pub ( crate ) fn new ( cef_context : Box < dyn cef:: CefContext > , window_size_sender : Sender < WindowSize > , wgpu_context : WgpuContext , event_loop_proxy : EventLoopProxy < CustomEvent > ) -> Self {
48- let rendering_loop_proxy = event_loop_proxy. clone ( ) ;
44+ impl App {
45+ pub ( crate ) fn new (
46+ cef_context : Box < dyn cef:: CefContext > ,
47+ window_size_sender : Sender < cef:: WindowSize > ,
48+ wgpu_context : WgpuContext ,
49+ app_event_receiver : Receiver < AppEvent > ,
50+ app_event_scheduler : AppEventScheduler ,
51+ ) -> Self {
52+ let rendering_app_event_scheduler = app_event_scheduler. clone ( ) ;
4953 let ( start_render_sender, start_render_receiver) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
5054 std:: thread:: spawn ( move || {
5155 loop {
5256 let result = futures:: executor:: block_on ( DesktopWrapper :: execute_node_graph ( ) ) ;
53- let _ = rendering_loop_proxy . send_event ( CustomEvent :: NodeGraphExecutionResult ( result) ) ;
57+ rendering_app_event_scheduler . schedule ( AppEvent :: NodeGraphExecutionResult ( result) ) ;
5458 let _ = start_render_receiver. recv ( ) ;
5559 }
5660 } ) ;
@@ -63,9 +67,10 @@ impl WinitApp {
6367 window : None ,
6468 cef_schedule : Some ( Instant :: now ( ) ) ,
6569 graphics_state : None ,
66- window_size_sender,
70+ cef_window_size_sender : window_size_sender,
6771 wgpu_context,
68- event_loop_proxy,
72+ app_event_receiver,
73+ app_event_scheduler,
6974 desktop_wrapper : DesktopWrapper :: new ( ) ,
7075 last_ui_update : Instant :: now ( ) ,
7176 avg_frame_time : 0. ,
@@ -87,7 +92,7 @@ impl WinitApp {
8792 self . send_or_queue_web_message ( bytes) ;
8893 }
8994 DesktopFrontendMessage :: OpenFileDialog { title, filters, context } => {
90- let event_loop_proxy = self . event_loop_proxy . clone ( ) ;
95+ let app_event_scheduler = self . app_event_scheduler . clone ( ) ;
9196 let _ = thread:: spawn ( move || {
9297 let mut dialog = AsyncFileDialog :: new ( ) . set_title ( title) ;
9398 for filter in filters {
@@ -100,7 +105,7 @@ impl WinitApp {
100105 && let Ok ( content) = std:: fs:: read ( & path)
101106 {
102107 let message = DesktopWrapperMessage :: OpenFileDialogResult { path, content, context } ;
103- let _ = event_loop_proxy . send_event ( CustomEvent :: DesktopWrapperMessage ( message) ) ;
108+ app_event_scheduler . schedule ( AppEvent :: DesktopWrapperMessage ( message) ) ;
104109 }
105110 } ) ;
106111 }
@@ -111,7 +116,7 @@ impl WinitApp {
111116 filters,
112117 context,
113118 } => {
114- let event_loop_proxy = self . event_loop_proxy . clone ( ) ;
119+ let app_event_scheduler = self . app_event_scheduler . clone ( ) ;
115120 let _ = thread:: spawn ( move || {
116121 let mut dialog = AsyncFileDialog :: new ( ) . set_title ( title) . set_file_name ( default_filename) ;
117122 if let Some ( folder) = default_folder {
@@ -125,7 +130,7 @@ impl WinitApp {
125130
126131 if let Some ( path) = futures:: executor:: block_on ( show_dialog) {
127132 let message = DesktopWrapperMessage :: SaveFileDialogResult { path, context } ;
128- let _ = event_loop_proxy . send_event ( CustomEvent :: DesktopWrapperMessage ( message) ) ;
133+ app_event_scheduler . schedule ( AppEvent :: DesktopWrapperMessage ( message) ) ;
129134 }
130135 } ) ;
131136 }
@@ -145,7 +150,7 @@ impl WinitApp {
145150 if let Some ( graphics_state) = & mut self . graphics_state
146151 && let Some ( window) = & self . window
147152 {
148- let window_size = window. inner_size ( ) ;
153+ let window_size = window. surface_size ( ) ;
149154
150155 let viewport_offset_x = x / window_size. width as f32 ;
151156 let viewport_offset_y = y / window_size. height as f32 ;
@@ -173,7 +178,7 @@ impl WinitApp {
173178 }
174179 }
175180 DesktopFrontendMessage :: CloseWindow => {
176- let _ = self . event_loop_proxy . send_event ( CustomEvent :: CloseWindow ) ;
181+ self . app_event_scheduler . schedule ( AppEvent :: CloseWindow ) ;
177182 }
178183 DesktopFrontendMessage :: PersistenceWriteDocument { id, document } => {
179184 self . persistent_data . write_document ( id, document) ;
@@ -252,71 +257,17 @@ impl WinitApp {
252257 self . web_communication_startup_buffer . push ( message) ;
253258 }
254259 }
255- }
256-
257- impl ApplicationHandler < CustomEvent > for WinitApp {
258- fn about_to_wait ( & mut self , event_loop : & ActiveEventLoop ) {
259- // Set a timeout in case we miss any cef schedule requests
260- let timeout = Instant :: now ( ) + Duration :: from_millis ( 10 ) ;
261- let wait_until = timeout. min ( self . cef_schedule . unwrap_or ( timeout) ) ;
262- if let Some ( schedule) = self . cef_schedule
263- && schedule < Instant :: now ( )
264- {
265- self . cef_schedule = None ;
266- // Poll cef message loop multiple times to avoid message loop starvation
267- for _ in 0 ..CEF_MESSAGE_LOOP_MAX_ITERATIONS {
268- self . cef_context . work ( ) ;
269- }
270- }
271- if let Some ( window) = & self . window . as_ref ( ) {
272- window. request_redraw ( ) ;
273- }
274-
275- event_loop. set_control_flow ( ControlFlow :: WaitUntil ( wait_until) ) ;
276- }
277-
278- fn resumed ( & mut self , event_loop : & ActiveEventLoop ) {
279- let mut window = Window :: default_attributes ( )
280- . with_title ( APP_NAME )
281- . with_min_inner_size ( winit:: dpi:: LogicalSize :: new ( 400 , 300 ) )
282- . with_inner_size ( winit:: dpi:: LogicalSize :: new ( 1200 , 800 ) )
283- . with_resizable ( true ) ;
284-
285- window = self . native_window . build ( window, event_loop) ;
286-
287- let window = event_loop. create_window ( window) . unwrap ( ) ;
288-
289- self . native_window . setup ( & window) ;
290-
291- let window = Arc :: new ( window) ;
292- let graphics_state = GraphicsState :: new ( window. clone ( ) , self . wgpu_context . clone ( ) ) ;
293-
294- self . window = Some ( window) ;
295- self . graphics_state = Some ( graphics_state) ;
296-
297- tracing:: info!( "Winit window created and ready" ) ;
298-
299- self . desktop_wrapper . init ( self . wgpu_context . clone ( ) ) ;
300-
301- #[ cfg( target_os = "windows" ) ]
302- let platform = Platform :: Windows ;
303- #[ cfg( target_os = "macos" ) ]
304- let platform = Platform :: Mac ;
305- #[ cfg( target_os = "linux" ) ]
306- let platform = Platform :: Linux ;
307- self . dispatch_desktop_wrapper_message ( DesktopWrapperMessage :: UpdatePlatform ( platform) ) ;
308- }
309260
310- fn user_event ( & mut self , event_loop : & ActiveEventLoop , event : CustomEvent ) {
261+ fn user_event ( & mut self , event_loop : & dyn ActiveEventLoop , event : AppEvent ) {
311262 match event {
312- CustomEvent :: WebCommunicationInitialized => {
263+ AppEvent :: WebCommunicationInitialized => {
313264 self . web_communication_initialized = true ;
314265 for message in self . web_communication_startup_buffer . drain ( ..) {
315266 self . cef_context . send_web_message ( message) ;
316267 }
317268 }
318- CustomEvent :: DesktopWrapperMessage ( message) => self . dispatch_desktop_wrapper_message ( message) ,
319- CustomEvent :: NodeGraphExecutionResult ( result) => match result {
269+ AppEvent :: DesktopWrapperMessage ( message) => self . dispatch_desktop_wrapper_message ( message) ,
270+ AppEvent :: NodeGraphExecutionResult ( result) => match result {
320271 NodeGraphExecutionResult :: HasRun ( texture) => {
321272 self . dispatch_desktop_wrapper_message ( DesktopWrapperMessage :: PollNodeGraphEvaluation ) ;
322273 if let Some ( texture) = texture
@@ -329,7 +280,7 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
329280 }
330281 NodeGraphExecutionResult :: NotRun => { }
331282 } ,
332- CustomEvent :: UiUpdate ( texture) => {
283+ AppEvent :: UiUpdate ( texture) => {
333284 if let Some ( graphics_state) = self . graphics_state . as_mut ( ) {
334285 graphics_state. resize ( texture. width ( ) , texture. height ( ) ) ;
335286 graphics_state. bind_ui_texture ( texture) ;
@@ -343,31 +294,63 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
343294 window. request_redraw ( ) ;
344295 }
345296 }
346- CustomEvent :: ScheduleBrowserWork ( instant) => {
297+ AppEvent :: ScheduleBrowserWork ( instant) => {
347298 if instant <= Instant :: now ( ) {
348299 self . cef_context . work ( ) ;
349300 } else {
350301 self . cef_schedule = Some ( instant) ;
351302 }
352303 }
353- CustomEvent :: CloseWindow => {
304+ AppEvent :: CloseWindow => {
354305 // TODO: Implement graceful shutdown
355306
356307 tracing:: info!( "Exiting main event loop" ) ;
357308 event_loop. exit ( ) ;
358309 }
359310 }
360311 }
312+ }
313+ impl ApplicationHandler for App {
314+ fn can_create_surfaces ( & mut self , event_loop : & dyn ActiveEventLoop ) {
315+ let window_attributes = self . native_window . build ( event_loop) ;
316+
317+ let window: Arc < dyn Window > = Arc :: from ( event_loop. create_window ( window_attributes) . unwrap ( ) ) ;
361318
362- fn window_event ( & mut self , event_loop : & ActiveEventLoop , _window_id : WindowId , event : WindowEvent ) {
319+ self . native_window . setup ( window. as_ref ( ) ) ;
320+
321+ let graphics_state = GraphicsState :: new ( window. clone ( ) , self . wgpu_context . clone ( ) ) ;
322+
323+ self . window = Some ( window) ;
324+ self . graphics_state = Some ( graphics_state) ;
325+
326+ tracing:: info!( "Winit window created and ready" ) ;
327+
328+ self . desktop_wrapper . init ( self . wgpu_context . clone ( ) ) ;
329+
330+ #[ cfg( target_os = "windows" ) ]
331+ let platform = Platform :: Windows ;
332+ #[ cfg( target_os = "macos" ) ]
333+ let platform = Platform :: Mac ;
334+ #[ cfg( target_os = "linux" ) ]
335+ let platform = Platform :: Linux ;
336+ self . dispatch_desktop_wrapper_message ( DesktopWrapperMessage :: UpdatePlatform ( platform) ) ;
337+ }
338+
339+ fn proxy_wake_up ( & mut self , event_loop : & dyn ActiveEventLoop ) {
340+ while let Ok ( event) = self . app_event_receiver . try_recv ( ) {
341+ self . user_event ( event_loop, event) ;
342+ }
343+ }
344+
345+ fn window_event ( & mut self , event_loop : & dyn ActiveEventLoop , _window_id : WindowId , event : WindowEvent ) {
363346 self . cef_context . handle_window_event ( & event) ;
364347
365348 match event {
366349 WindowEvent :: CloseRequested => {
367- let _ = self . event_loop_proxy . send_event ( CustomEvent :: CloseWindow ) ;
350+ self . app_event_scheduler . schedule ( AppEvent :: CloseWindow ) ;
368351 }
369- WindowEvent :: Resized ( PhysicalSize { width , height } ) => {
370- let _ = self . window_size_sender . send ( WindowSize :: new ( width as usize , height as usize ) ) ;
352+ WindowEvent :: SurfaceResized ( size ) => {
353+ let _ = self . cef_window_size_sender . send ( size . into ( ) ) ;
371354 self . cef_context . notify_of_resize ( ) ;
372355 }
373356 WindowEvent :: RedrawRequested => {
@@ -387,23 +370,44 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
387370 let _ = self . start_render_sender . try_send ( ( ) ) ;
388371 }
389372 }
390- // Currently not supported on wayland see https://github.com/rust-windowing/winit/issues/1881
391- WindowEvent :: DroppedFile ( path) => {
392- match std:: fs:: read ( & path) {
393- Ok ( content) => {
394- let message = DesktopWrapperMessage :: OpenFile { path, content } ;
395- let _ = self . event_loop_proxy . send_event ( CustomEvent :: DesktopWrapperMessage ( message) ) ;
396- }
397- Err ( e) => {
398- tracing:: error!( "Failed to read dropped file {}: {}" , path. display( ) , e) ;
399- return ;
400- }
401- } ;
373+ WindowEvent :: DragDropped { paths, .. } => {
374+ for path in paths {
375+ match std:: fs:: read ( & path) {
376+ Ok ( content) => {
377+ let message = DesktopWrapperMessage :: OpenFile { path, content } ;
378+ self . app_event_scheduler . schedule ( AppEvent :: DesktopWrapperMessage ( message) ) ;
379+ }
380+ Err ( e) => {
381+ tracing:: error!( "Failed to read dropped file {}: {}" , path. display( ) , e) ;
382+ return ;
383+ }
384+ } ;
385+ }
402386 }
403387 _ => { }
404388 }
405389
406390 // Notify cef of possible input events
407391 self . cef_context . work ( ) ;
408392 }
393+
394+ fn about_to_wait ( & mut self , event_loop : & dyn ActiveEventLoop ) {
395+ // Set a timeout in case we miss any cef schedule requests
396+ let timeout = Instant :: now ( ) + Duration :: from_millis ( 10 ) ;
397+ let wait_until = timeout. min ( self . cef_schedule . unwrap_or ( timeout) ) ;
398+ if let Some ( schedule) = self . cef_schedule
399+ && schedule < Instant :: now ( )
400+ {
401+ self . cef_schedule = None ;
402+ // Poll cef message loop multiple times to avoid message loop starvation
403+ for _ in 0 ..CEF_MESSAGE_LOOP_MAX_ITERATIONS {
404+ self . cef_context . work ( ) ;
405+ }
406+ }
407+ if let Some ( window) = & self . window . as_ref ( ) {
408+ window. request_redraw ( ) ;
409+ }
410+
411+ event_loop. set_control_flow ( ControlFlow :: WaitUntil ( wait_until) ) ;
412+ }
409413}
0 commit comments