Desktop: Switch to the latest unreleased version of Winit (#3177)

* Use unstable winit

* Improve

* Remove unnecessary heap indirection
This commit is contained in:
Timon
2025-09-17 05:16:11 -07:00
committed by Dennis Kobert
parent 4662cbbbc1
commit 3fe7c477e9
14 changed files with 567 additions and 527 deletions

View File

@@ -26,7 +26,7 @@ graphite-desktop-wrapper = { path = "wrapper" }
graphite-desktop-embedded-resources = { path = "embedded-resources", optional = true }
wgpu = { workspace = true }
winit = { workspace = true, features = ["serde"] }
winit = { workspace = true, features = [ "serde" ] }
thiserror = { workspace = true }
futures = { workspace = true }
cef = { workspace = true }
@@ -34,7 +34,7 @@ cef-dll-sys = { workspace = true }
tracing-subscriber = { workspace = true }
tracing = { workspace = true }
dirs = { workspace = true }
ron = { workspace = true}
ron = { workspace = true }
bytemuck = { workspace = true }
glam = { workspace = true }
vello = { workspace = true }

View File

@@ -1,39 +1,37 @@
use crate::CustomEvent;
use crate::cef::WindowSize;
use crate::consts::{APP_NAME, CEF_MESSAGE_LOOP_MAX_ITERATIONS};
use crate::persist::PersistentData;
use crate::render::GraphicsState;
use graphite_desktop_wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, Platform};
use graphite_desktop_wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
use rfd::AsyncFileDialog;
use std::sync::Arc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::Sender;
use std::sync::mpsc::SyncSender;
use std::thread;
use std::time::Duration;
use std::time::Instant;
use winit::application::ApplicationHandler;
use winit::dpi::PhysicalSize;
use winit::event::WindowEvent;
use winit::event_loop::ActiveEventLoop;
use winit::event_loop::ControlFlow;
use winit::event_loop::EventLoopProxy;
use winit::window::Window;
use winit::window::WindowId;
use crate::cef;
use crate::consts::CEF_MESSAGE_LOOP_MAX_ITERATIONS;
use crate::event::{AppEvent, AppEventScheduler};
use crate::native_window;
use crate::persist::PersistentData;
use crate::render::GraphicsState;
use graphite_desktop_wrapper::messages::{DesktopFrontendMessage, DesktopWrapperMessage, Platform};
use graphite_desktop_wrapper::{DesktopWrapper, NodeGraphExecutionResult, WgpuContext, serialize_frontend_messages};
pub(crate) struct WinitApp {
pub(crate) struct App {
cef_context: Box<dyn cef::CefContext>,
window: Option<Arc<Window>>,
window: Option<Arc<dyn Window>>,
native_window: native_window::NativeWindowHandle,
cef_schedule: Option<Instant>,
window_size_sender: Sender<WindowSize>,
cef_window_size_sender: Sender<cef::WindowSize>,
graphics_state: Option<GraphicsState>,
wgpu_context: WgpuContext,
event_loop_proxy: EventLoopProxy<CustomEvent>,
app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler,
desktop_wrapper: DesktopWrapper,
last_ui_update: Instant,
avg_frame_time: f32,
@@ -43,14 +41,20 @@ pub(crate) struct WinitApp {
persistent_data: PersistentData,
}
impl WinitApp {
pub(crate) fn new(cef_context: Box<dyn cef::CefContext>, window_size_sender: Sender<WindowSize>, wgpu_context: WgpuContext, event_loop_proxy: EventLoopProxy<CustomEvent>) -> Self {
let rendering_loop_proxy = event_loop_proxy.clone();
impl App {
pub(crate) fn new(
cef_context: Box<dyn cef::CefContext>,
window_size_sender: Sender<cef::WindowSize>,
wgpu_context: WgpuContext,
app_event_receiver: Receiver<AppEvent>,
app_event_scheduler: AppEventScheduler,
) -> Self {
let rendering_app_event_scheduler = app_event_scheduler.clone();
let (start_render_sender, start_render_receiver) = std::sync::mpsc::sync_channel(1);
std::thread::spawn(move || {
loop {
let result = futures::executor::block_on(DesktopWrapper::execute_node_graph());
let _ = rendering_loop_proxy.send_event(CustomEvent::NodeGraphExecutionResult(result));
rendering_app_event_scheduler.schedule(AppEvent::NodeGraphExecutionResult(result));
let _ = start_render_receiver.recv();
}
});
@@ -63,9 +67,10 @@ impl WinitApp {
window: None,
cef_schedule: Some(Instant::now()),
graphics_state: None,
window_size_sender,
cef_window_size_sender: window_size_sender,
wgpu_context,
event_loop_proxy,
app_event_receiver,
app_event_scheduler,
desktop_wrapper: DesktopWrapper::new(),
last_ui_update: Instant::now(),
avg_frame_time: 0.,
@@ -87,7 +92,7 @@ impl WinitApp {
self.send_or_queue_web_message(bytes);
}
DesktopFrontendMessage::OpenFileDialog { title, filters, context } => {
let event_loop_proxy = self.event_loop_proxy.clone();
let app_event_scheduler = self.app_event_scheduler.clone();
let _ = thread::spawn(move || {
let mut dialog = AsyncFileDialog::new().set_title(title);
for filter in filters {
@@ -100,7 +105,7 @@ impl WinitApp {
&& let Ok(content) = std::fs::read(&path)
{
let message = DesktopWrapperMessage::OpenFileDialogResult { path, content, context };
let _ = event_loop_proxy.send_event(CustomEvent::DesktopWrapperMessage(message));
app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
}
});
}
@@ -111,7 +116,7 @@ impl WinitApp {
filters,
context,
} => {
let event_loop_proxy = self.event_loop_proxy.clone();
let app_event_scheduler = self.app_event_scheduler.clone();
let _ = thread::spawn(move || {
let mut dialog = AsyncFileDialog::new().set_title(title).set_file_name(default_filename);
if let Some(folder) = default_folder {
@@ -125,7 +130,7 @@ impl WinitApp {
if let Some(path) = futures::executor::block_on(show_dialog) {
let message = DesktopWrapperMessage::SaveFileDialogResult { path, context };
let _ = event_loop_proxy.send_event(CustomEvent::DesktopWrapperMessage(message));
app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
}
});
}
@@ -145,7 +150,7 @@ impl WinitApp {
if let Some(graphics_state) = &mut self.graphics_state
&& let Some(window) = &self.window
{
let window_size = window.inner_size();
let window_size = window.surface_size();
let viewport_offset_x = x / window_size.width as f32;
let viewport_offset_y = y / window_size.height as f32;
@@ -173,7 +178,7 @@ impl WinitApp {
}
}
DesktopFrontendMessage::CloseWindow => {
let _ = self.event_loop_proxy.send_event(CustomEvent::CloseWindow);
self.app_event_scheduler.schedule(AppEvent::CloseWindow);
}
DesktopFrontendMessage::PersistenceWriteDocument { id, document } => {
self.persistent_data.write_document(id, document);
@@ -252,43 +257,67 @@ impl WinitApp {
self.web_communication_startup_buffer.push(message);
}
}
}
impl ApplicationHandler<CustomEvent> for WinitApp {
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
// Set a timeout in case we miss any cef schedule requests
let timeout = Instant::now() + Duration::from_millis(10);
let wait_until = timeout.min(self.cef_schedule.unwrap_or(timeout));
if let Some(schedule) = self.cef_schedule
&& schedule < Instant::now()
{
self.cef_schedule = None;
// Poll cef message loop multiple times to avoid message loop starvation
for _ in 0..CEF_MESSAGE_LOOP_MAX_ITERATIONS {
self.cef_context.work();
fn user_event(&mut self, event_loop: &dyn ActiveEventLoop, event: AppEvent) {
match event {
AppEvent::WebCommunicationInitialized => {
self.web_communication_initialized = true;
for message in self.web_communication_startup_buffer.drain(..) {
self.cef_context.send_web_message(message);
}
}
AppEvent::DesktopWrapperMessage(message) => self.dispatch_desktop_wrapper_message(message),
AppEvent::NodeGraphExecutionResult(result) => match result {
NodeGraphExecutionResult::HasRun(texture) => {
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::PollNodeGraphEvaluation);
if let Some(texture) = texture
&& let Some(graphics_state) = self.graphics_state.as_mut()
&& let Some(window) = self.window.as_ref()
{
graphics_state.bind_viewport_texture(texture);
window.request_redraw();
}
}
NodeGraphExecutionResult::NotRun => {}
},
AppEvent::UiUpdate(texture) => {
if let Some(graphics_state) = self.graphics_state.as_mut() {
graphics_state.resize(texture.width(), texture.height());
graphics_state.bind_ui_texture(texture);
let elapsed = self.last_ui_update.elapsed().as_secs_f32();
self.last_ui_update = Instant::now();
if elapsed < 0.5 {
self.avg_frame_time = (self.avg_frame_time * 3. + elapsed) / 4.;
}
}
if let Some(window) = &self.window {
window.request_redraw();
}
}
AppEvent::ScheduleBrowserWork(instant) => {
if instant <= Instant::now() {
self.cef_context.work();
} else {
self.cef_schedule = Some(instant);
}
}
AppEvent::CloseWindow => {
// TODO: Implement graceful shutdown
tracing::info!("Exiting main event loop");
event_loop.exit();
}
}
if let Some(window) = &self.window.as_ref() {
window.request_redraw();
}
event_loop.set_control_flow(ControlFlow::WaitUntil(wait_until));
}
}
impl ApplicationHandler for App {
fn can_create_surfaces(&mut self, event_loop: &dyn ActiveEventLoop) {
let window_attributes = self.native_window.build(event_loop);
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
let mut window = Window::default_attributes()
.with_title(APP_NAME)
.with_min_inner_size(winit::dpi::LogicalSize::new(400, 300))
.with_inner_size(winit::dpi::LogicalSize::new(1200, 800))
.with_resizable(true);
let window: Arc<dyn Window> = Arc::from(event_loop.create_window(window_attributes).unwrap());
window = self.native_window.build(window, event_loop);
self.native_window.setup(window.as_ref());
let window = event_loop.create_window(window).unwrap();
self.native_window.setup(&window);
let window = Arc::new(window);
let graphics_state = GraphicsState::new(window.clone(), self.wgpu_context.clone());
self.window = Some(window);
@@ -307,67 +336,21 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::UpdatePlatform(platform));
}
fn user_event(&mut self, event_loop: &ActiveEventLoop, event: CustomEvent) {
match event {
CustomEvent::WebCommunicationInitialized => {
self.web_communication_initialized = true;
for message in self.web_communication_startup_buffer.drain(..) {
self.cef_context.send_web_message(message);
}
}
CustomEvent::DesktopWrapperMessage(message) => self.dispatch_desktop_wrapper_message(message),
CustomEvent::NodeGraphExecutionResult(result) => match result {
NodeGraphExecutionResult::HasRun(texture) => {
self.dispatch_desktop_wrapper_message(DesktopWrapperMessage::PollNodeGraphEvaluation);
if let Some(texture) = texture
&& let Some(graphics_state) = self.graphics_state.as_mut()
&& let Some(window) = self.window.as_ref()
{
graphics_state.bind_viewport_texture(texture);
window.request_redraw();
}
}
NodeGraphExecutionResult::NotRun => {}
},
CustomEvent::UiUpdate(texture) => {
if let Some(graphics_state) = self.graphics_state.as_mut() {
graphics_state.resize(texture.width(), texture.height());
graphics_state.bind_ui_texture(texture);
let elapsed = self.last_ui_update.elapsed().as_secs_f32();
self.last_ui_update = Instant::now();
if elapsed < 0.5 {
self.avg_frame_time = (self.avg_frame_time * 3. + elapsed) / 4.;
}
}
if let Some(window) = &self.window {
window.request_redraw();
}
}
CustomEvent::ScheduleBrowserWork(instant) => {
if instant <= Instant::now() {
self.cef_context.work();
} else {
self.cef_schedule = Some(instant);
}
}
CustomEvent::CloseWindow => {
// TODO: Implement graceful shutdown
tracing::info!("Exiting main event loop");
event_loop.exit();
}
fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) {
while let Ok(event) = self.app_event_receiver.try_recv() {
self.user_event(event_loop, event);
}
}
fn window_event(&mut self, event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {
fn window_event(&mut self, event_loop: &dyn ActiveEventLoop, _window_id: WindowId, event: WindowEvent) {
self.cef_context.handle_window_event(&event);
match event {
WindowEvent::CloseRequested => {
let _ = self.event_loop_proxy.send_event(CustomEvent::CloseWindow);
self.app_event_scheduler.schedule(AppEvent::CloseWindow);
}
WindowEvent::Resized(PhysicalSize { width, height }) => {
let _ = self.window_size_sender.send(WindowSize::new(width as usize, height as usize));
WindowEvent::SurfaceResized(size) => {
let _ = self.cef_window_size_sender.send(size.into());
self.cef_context.notify_of_resize();
}
WindowEvent::RedrawRequested => {
@@ -387,18 +370,19 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
let _ = self.start_render_sender.try_send(());
}
}
// Currently not supported on wayland see https://github.com/rust-windowing/winit/issues/1881
WindowEvent::DroppedFile(path) => {
match std::fs::read(&path) {
Ok(content) => {
let message = DesktopWrapperMessage::OpenFile { path, content };
let _ = self.event_loop_proxy.send_event(CustomEvent::DesktopWrapperMessage(message));
}
Err(e) => {
tracing::error!("Failed to read dropped file {}: {}", path.display(), e);
return;
}
};
WindowEvent::DragDropped { paths, .. } => {
for path in paths {
match std::fs::read(&path) {
Ok(content) => {
let message = DesktopWrapperMessage::OpenFile { path, content };
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(message));
}
Err(e) => {
tracing::error!("Failed to read dropped file {}: {}", path.display(), e);
return;
}
};
}
}
_ => {}
}
@@ -406,4 +390,24 @@ impl ApplicationHandler<CustomEvent> for WinitApp {
// Notify cef of possible input events
self.cef_context.work();
}
fn about_to_wait(&mut self, event_loop: &dyn ActiveEventLoop) {
// Set a timeout in case we miss any cef schedule requests
let timeout = Instant::now() + Duration::from_millis(10);
let wait_until = timeout.min(self.cef_schedule.unwrap_or(timeout));
if let Some(schedule) = self.cef_schedule
&& schedule < Instant::now()
{
self.cef_schedule = None;
// Poll cef message loop multiple times to avoid message loop starvation
for _ in 0..CEF_MESSAGE_LOOP_MAX_ITERATIONS {
self.cef_context.work();
}
}
if let Some(window) = &self.window.as_ref() {
window.request_redraw();
}
event_loop.set_control_flow(ControlFlow::WaitUntil(wait_until));
}
}

View File

@@ -10,10 +10,9 @@
//! - **Windows**: D3D11 shared textures via either Vulkan or D3D12 interop (`accelerated_paint_d3d11` feature)
//! - **macOS**: IOSurface via Metal/Vulkan interop (`accelerated_paint_iosurface` feature)
//!
//!
//! The system gracefully falls back to CPU textures when hardware acceleration is unavailable.
use crate::CustomEvent;
use crate::event::{AppEvent, AppEventScheduler};
use crate::render::FrameBufferRef;
use graphite_desktop_wrapper::{WgpuContext, deserialize_editor_message};
use std::fs::File;
@@ -38,7 +37,6 @@ mod texture_import;
use texture_import::SharedTextureHandle;
pub(crate) use context::{CefContext, CefContextBuilder, InitError};
use winit::event_loop::EventLoopProxy;
pub(crate) trait CefEventHandler: Clone + Send + Sync + 'static {
fn window_size(&self) -> WindowSize;
@@ -58,12 +56,16 @@ pub(crate) struct WindowSize {
pub(crate) width: usize,
pub(crate) height: usize,
}
impl WindowSize {
pub(crate) fn new(width: usize, height: usize) -> Self {
Self { width, height }
}
}
impl From<winit::dpi::PhysicalSize<u32>> for WindowSize {
fn from(size: winit::dpi::PhysicalSize<u32>) -> Self {
Self::new(size.width as usize, size.height as usize)
}
}
#[derive(Clone)]
pub(crate) struct Resource {
@@ -88,29 +90,17 @@ impl Read for ResourceReader {
#[derive(Clone)]
pub(crate) struct CefHandler {
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
event_loop_proxy: EventLoopProxy<CustomEvent>,
wgpu_context: WgpuContext,
app_event_scheduler: AppEventScheduler,
window_size_receiver: Arc<Mutex<WindowSizeReceiver>>,
}
struct WindowSizeReceiver {
receiver: Receiver<WindowSize>,
window_size: WindowSize,
}
impl WindowSizeReceiver {
fn new(window_size_receiver: Receiver<WindowSize>) -> Self {
Self {
window_size: WindowSize { width: 1, height: 1 },
receiver: window_size_receiver,
}
}
}
impl CefHandler {
pub(crate) fn new(window_size_receiver: Receiver<WindowSize>, event_loop_proxy: EventLoopProxy<CustomEvent>, wgpu_context: WgpuContext) -> Self {
pub(crate) fn new(wgpu_context: WgpuContext, app_event_scheduler: AppEventScheduler, window_size_receiver: Receiver<WindowSize>) -> Self {
Self {
window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))),
event_loop_proxy,
wgpu_context,
app_event_scheduler,
window_size_receiver: Arc::new(Mutex::new(WindowSizeReceiver::new(window_size_receiver))),
}
}
}
@@ -164,14 +154,14 @@ impl CefEventHandler for CefHandler {
},
);
let _ = self.event_loop_proxy.send_event(CustomEvent::UiUpdate(texture));
self.app_event_scheduler.schedule(AppEvent::UiUpdate(texture));
}
#[cfg(feature = "accelerated_paint")]
fn draw_gpu(&self, shared_texture: SharedTextureHandle) {
match shared_texture.import_texture(&self.wgpu_context.device) {
Ok(texture) => {
let _ = self.event_loop_proxy.send_event(CustomEvent::UiUpdate(texture));
self.app_event_scheduler.schedule(AppEvent::UiUpdate(texture));
}
Err(e) => {
tracing::error!("Failed to import shared texture: {}", e);
@@ -235,11 +225,11 @@ impl CefEventHandler for CefHandler {
}
fn schedule_cef_message_loop_work(&self, scheduled_time: std::time::Instant) {
let _ = self.event_loop_proxy.send_event(CustomEvent::ScheduleBrowserWork(scheduled_time));
self.app_event_scheduler.schedule(AppEvent::ScheduleBrowserWork(scheduled_time));
}
fn initialized_web_communication(&self) {
let _ = self.event_loop_proxy.send_event(CustomEvent::WebCommunicationInitialized);
self.app_event_scheduler.schedule(AppEvent::WebCommunicationInitialized);
}
fn receive_web_message(&self, message: &[u8]) {
@@ -247,6 +237,19 @@ impl CefEventHandler for CefHandler {
tracing::error!("Failed to deserialize web message");
return;
};
let _ = self.event_loop_proxy.send_event(CustomEvent::DesktopWrapperMessage(desktop_wrapper_message));
self.app_event_scheduler.schedule(AppEvent::DesktopWrapperMessage(desktop_wrapper_message));
}
}
struct WindowSizeReceiver {
window_size: WindowSize,
receiver: Receiver<WindowSize>,
}
impl WindowSizeReceiver {
fn new(window_size_receiver: Receiver<WindowSize>) -> Self {
Self {
window_size: WindowSize { width: 1, height: 1 },
receiver: window_size_receiver,
}
}
}

View File

@@ -2,7 +2,7 @@ use cef::sys::{cef_event_flags_t, cef_key_event_type_t, cef_mouse_button_type_t}
use cef::{Browser, ImplBrowser, ImplBrowserHost, KeyEvent, KeyEventType, MouseEvent};
use std::time::Instant;
use winit::dpi::PhysicalPosition;
use winit::event::{ElementState, MouseButton, MouseScrollDelta, WindowEvent};
use winit::event::{ButtonSource, ElementState, MouseButton, MouseScrollDelta, WindowEvent};
mod keymap;
use keymap::{ToNativeKeycode, ToVKBits};
@@ -11,7 +11,7 @@ use super::consts::{MULTICLICK_ALLOWED_TRAVEL, MULTICLICK_TIMEOUT, SCROLL_LINE_H
pub(crate) fn handle_window_event(browser: &Browser, input_state: &mut InputState, event: &WindowEvent) {
match event {
WindowEvent::CursorMoved { position, .. } => {
WindowEvent::PointerMoved { position, .. } => {
input_state.cursor_move(position);
let Some(host) = browser.host() else {
@@ -19,13 +19,20 @@ pub(crate) fn handle_window_event(browser: &Browser, input_state: &mut InputStat
};
host.send_mouse_move_event(Some(&input_state.into()), 0);
}
WindowEvent::MouseInput { state, button, .. } => {
let cef_click_count = input_state.mouse_input(button, state).into();
WindowEvent::PointerButton { state, button, .. } => {
let mouse_button = match button {
ButtonSource::Mouse(mouse_button) => mouse_button,
_ => {
return; // TODO: Handle touch input
}
};
let cef_click_count = input_state.mouse_input(mouse_button, state).into();
let cef_mouse_up = match state {
ElementState::Pressed => 0,
ElementState::Released => 1,
};
let cef_button = match button {
let cef_button = match mouse_button {
MouseButton::Left => cef::MouseButtonType::from(cef_mouse_button_type_t::MBT_LEFT),
MouseButton::Right => cef::MouseButtonType::from(cef_mouse_button_type_t::MBT_RIGHT),
MouseButton::Middle => cef::MouseButtonType::from(cef_mouse_button_type_t::MBT_MIDDLE),
@@ -59,7 +66,6 @@ pub(crate) fn handle_window_event(browser: &Browser, input_state: &mut InputStat
winit::keyboard::Key::Named(named_key) => (
Some(named_key),
match named_key {
winit::keyboard::NamedKey::Space => Some(' '),
winit::keyboard::NamedKey::Enter => Some('\u{000d}'),
_ => None,
},
@@ -312,7 +318,7 @@ impl CefModifiers {
if input_state.modifiers.alt_key() {
inner |= cef_event_flags_t::EVENTFLAG_ALT_DOWN as u32;
}
if input_state.modifiers.super_key() {
if input_state.modifiers.meta_key() {
inner |= cef_event_flags_t::EVENTFLAG_COMMAND_DOWN as u32;
}

View File

@@ -47,10 +47,8 @@ impl ToVKBits for winit::keyboard::NamedKey {
(0x91, ScrollLock),
(0x10, Shift),
(0x5B, Meta),
(0x5C, Super),
(0x0D, Enter),
(0x09, Tab),
(0x20, Space),
(0x28, ArrowDown),
(0x25, ArrowLeft),
(0x27, ArrowRight),
@@ -253,6 +251,7 @@ impl ToVKBits for char {
(0xDE, '"'),
(0xBF, '/'),
(0xBF, '?'),
(0x20, ' '),
)
}
}

34
desktop/src/event.rs Normal file
View File

@@ -0,0 +1,34 @@
use graphite_desktop_wrapper::NodeGraphExecutionResult;
use graphite_desktop_wrapper::messages::DesktopWrapperMessage;
pub(crate) enum AppEvent {
UiUpdate(wgpu::Texture),
ScheduleBrowserWork(std::time::Instant),
WebCommunicationInitialized,
DesktopWrapperMessage(DesktopWrapperMessage),
NodeGraphExecutionResult(NodeGraphExecutionResult),
CloseWindow,
}
#[derive(Clone)]
pub(crate) struct AppEventScheduler {
pub(crate) proxy: winit::event_loop::EventLoopProxy,
pub(crate) sender: std::sync::mpsc::Sender<AppEvent>,
}
impl AppEventScheduler {
pub(crate) fn schedule(&self, event: AppEvent) {
let _ = self.sender.send(event);
self.proxy.wake_up();
}
}
pub(crate) trait CreateAppEventSchedulerEventLoopExt {
fn create_app_event_scheduler(&self, sender: std::sync::mpsc::Sender<AppEvent>) -> AppEventScheduler;
}
impl CreateAppEventSchedulerEventLoopExt for winit::event_loop::EventLoop {
fn create_app_event_scheduler(&self, sender: std::sync::mpsc::Sender<AppEvent>) -> AppEventScheduler {
AppEventScheduler { proxy: self.create_proxy(), sender }
}
}

View File

@@ -1,35 +1,22 @@
use std::process::exit;
use std::time::Instant;
use cef::CefHandler;
use tracing_subscriber::EnvFilter;
use winit::event_loop::EventLoop;
use graphite_desktop_wrapper::WgpuContext;
pub(crate) mod consts;
mod app;
mod cef;
mod dirs;
mod event;
mod native_window;
mod persist;
mod render;
mod app;
use app::WinitApp;
mod dirs;
mod persist;
use graphite_desktop_wrapper::messages::DesktopWrapperMessage;
use graphite_desktop_wrapper::{NodeGraphExecutionResult, WgpuContext};
pub(crate) enum CustomEvent {
UiUpdate(wgpu::Texture),
ScheduleBrowserWork(Instant),
WebCommunicationInitialized,
DesktopWrapperMessage(DesktopWrapperMessage),
NodeGraphExecutionResult(NodeGraphExecutionResult),
CloseWindow,
}
use app::App;
use cef::CefHandler;
use event::CreateAppEventSchedulerEventLoopExt;
fn main() {
tracing_subscriber::fmt().with_env_filter(EnvFilter::from_default_env()).init();
@@ -46,13 +33,18 @@ fn main() {
let wgpu_context = futures::executor::block_on(WgpuContext::new()).unwrap();
let event_loop = EventLoop::<CustomEvent>::with_user_event().build().unwrap();
let event_loop = EventLoop::new().unwrap();
let (app_event_sender, app_event_receiver) = std::sync::mpsc::channel();
let app_event_scheduler = event_loop.create_app_event_scheduler(app_event_sender);
let (window_size_sender, window_size_receiver) = std::sync::mpsc::channel();
let cef_handler = cef::CefHandler::new(window_size_receiver, event_loop.create_proxy(), wgpu_context.clone());
let cef_handler = cef::CefHandler::new(wgpu_context.clone(), app_event_scheduler.clone(), window_size_receiver);
let cef_context = match cef_context_builder.initialize(cef_handler) {
Ok(c) => c,
Ok(c) => {
tracing::info!("CEF initialized successfully");
c
}
Err(cef::InitError::AlreadyRunning) => {
tracing::error!("Another instance is already running, Exiting.");
exit(0);
@@ -71,9 +63,7 @@ fn main() {
}
};
tracing::info!("CEF initialized successfully");
let mut app = App::new(Box::new(cef_context), window_size_sender, wgpu_context, app_event_receiver, app_event_scheduler);
let mut winit_app = WinitApp::new(Box::new(cef_context), window_size_sender, wgpu_context, event_loop.create_proxy());
event_loop.run_app(&mut winit_app).unwrap();
event_loop.run_app(&mut app).unwrap();
}

View File

@@ -1,6 +1,8 @@
use winit::event_loop::ActiveEventLoop;
use winit::window::{Window, WindowAttributes};
use crate::consts::APP_NAME;
#[cfg(target_os = "windows")]
mod windows;
@@ -17,25 +19,31 @@ impl Default for NativeWindowHandle {
}
impl NativeWindowHandle {
#[allow(unused_variables)]
pub(super) fn build(&mut self, window: WindowAttributes, event_loop: &ActiveEventLoop) -> WindowAttributes {
pub(super) fn build(&mut self, event_loop: &dyn ActiveEventLoop) -> WindowAttributes {
let mut window = WindowAttributes::default()
.with_title(APP_NAME)
.with_min_surface_size(winit::dpi::LogicalSize::new(400, 300))
.with_surface_size(winit::dpi::LogicalSize::new(1200, 800))
.with_resizable(true);
#[cfg(target_os = "linux")]
{
use crate::consts::{APP_ID, APP_NAME};
use winit::platform::wayland::ActiveEventLoopExtWayland;
if event_loop.is_wayland() {
winit::platform::wayland::WindowAttributesExtWayland::with_name(window, APP_ID, "")
use winit::platform::wayland::WindowAttributesWayland;
use winit::platform::x11::WindowAttributesX11;
window = if event_loop.is_wayland() {
let wayland_window = WindowAttributesWayland::default().with_name(APP_ID, "");
window.with_platform_attributes(Box::new(wayland_window))
} else {
winit::platform::x11::WindowAttributesExtX11::with_name(window, APP_ID, APP_NAME)
let x11_window = WindowAttributesX11::default().with_name(APP_ID, APP_NAME);
window.with_platform_attributes(Box::new(x11_window))
}
}
#[cfg(not(target_os = "linux"))]
{
window
}
window
}
#[allow(unused_variables)]
pub(crate) fn setup(&mut self, window: &Window) {
pub(crate) fn setup(&mut self, window: &dyn Window) {
#[cfg(target_os = "windows")]
{
*self = NativeWindowHandle::Windows(windows::WindowsNativeWindowHandle::new(window));

View File

@@ -23,7 +23,7 @@ pub(super) struct WindowsNativeWindowHandle {
inner: WindowsNativeWindowHandleInner,
}
impl WindowsNativeWindowHandle {
pub(super) fn new(window: &Window) -> Self {
pub(super) fn new(window: &dyn Window) -> Self {
let inner = WindowsNativeWindowHandleInner::new(window);
WindowsNativeWindowHandle { inner }
}
@@ -41,7 +41,7 @@ struct WindowsNativeWindowHandleInner {
prev_window_message_handler: isize,
}
impl WindowsNativeWindowHandleInner {
fn new(window: &Window) -> WindowsNativeWindowHandleInner {
fn new(window: &dyn Window) -> WindowsNativeWindowHandleInner {
// Extract Win32 HWND from winit.
let hwnd = match window.window_handle().expect("No window handle").as_raw() {
RawWindowHandle::Win32(h) => HWND(h.hwnd.get() as *mut std::ffi::c_void),

View File

@@ -24,8 +24,8 @@ pub(crate) struct GraphicsState {
}
impl GraphicsState {
pub(crate) fn new(window: Arc<Window>, context: WgpuContext) -> Self {
let size = window.inner_size();
pub(crate) fn new(window: Arc<dyn Window>, context: WgpuContext) -> Self {
let size = window.surface_size();
let surface = context.instance.create_surface(window).unwrap();
@@ -232,7 +232,7 @@ impl GraphicsState {
self.bind_overlays_texture(texture);
}
pub(crate) fn render(&mut self, window: &Window) -> Result<(), wgpu::SurfaceError> {
pub(crate) fn render(&mut self, window: &dyn Window) -> Result<(), wgpu::SurfaceError> {
if let Some(scene) = self.overlays_scene.take() {
self.render_overlays(scene);
}