Skip to content

Commit 22af820

Browse files
Desktop: Switch to the latest unreleased version of Winit (#3177)
* Use unstable winit * Improve * Remove unnecessary heap indirection
1 parent 4662cbb commit 22af820

File tree

14 files changed

+545
-505
lines changed

14 files changed

+545
-505
lines changed

Cargo.lock

Lines changed: 313 additions & 317 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ web-sys = { version = "=0.3.77", features = [
132132
"HtmlImageElement",
133133
"ImageBitmapRenderingContext",
134134
] }
135-
winit = { version = "0.30", features = ["wayland", "rwh_06"] }
135+
winit = { git = "https://github.com/rust-windowing/winit.git", rev = "66283a79bddd034c45fb0e72c84fa5cd4e5f82fb", default-features = false }
136136
url = "2.5"
137137
tokio = { version = "1.29", features = ["fs", "macros", "io-std", "rt"] }
138138
vello = { git = "https://github.com/linebender/vello.git", rev = "87cc5bee6d3a34d15017dbbb58634ddc7f33ff9b" } # TODO switch back to stable when a release is made

desktop/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ graphite-desktop-wrapper = { path = "wrapper" }
2626
graphite-desktop-embedded-resources = { path = "embedded-resources", optional = true }
2727

2828
wgpu = { workspace = true }
29-
winit = { workspace = true, features = ["serde"] }
29+
winit = { workspace = true, features = [ "wayland", "wayland-dlopen","wayland-csd-adwaita", "wayland-csd-adwaita-notitle", "x11", "serde" ] }
3030
thiserror = { workspace = true }
3131
futures = { workspace = true }
3232
cef = { workspace = true }
3333
cef-dll-sys = { workspace = true }
3434
tracing-subscriber = { workspace = true }
3535
tracing = { workspace = true }
3636
dirs = { workspace = true }
37-
ron = { workspace = true}
37+
ron = { workspace = true }
3838
bytemuck = { workspace = true }
3939
glam = { workspace = true }
4040
vello = { workspace = true }

desktop/src/app.rs

Lines changed: 107 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,37 @@
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-
91
use rfd::AsyncFileDialog;
102
use std::sync::Arc;
3+
use std::sync::mpsc::Receiver;
114
use std::sync::mpsc::Sender;
125
use std::sync::mpsc::SyncSender;
136
use std::thread;
147
use std::time::Duration;
158
use std::time::Instant;
169
use winit::application::ApplicationHandler;
17-
use winit::dpi::PhysicalSize;
1810
use winit::event::WindowEvent;
1911
use winit::event_loop::ActiveEventLoop;
2012
use winit::event_loop::ControlFlow;
21-
use winit::event_loop::EventLoopProxy;
2213
use winit::window::Window;
2314
use winit::window::WindowId;
2415

2516
use crate::cef;
17+
use crate::consts::CEF_MESSAGE_LOOP_MAX_ITERATIONS;
18+
use crate::event::{AppEvent, AppEventScheduler};
2619
use 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

Comments
 (0)