diff --git a/plugin-canvas-slint/src/editor.rs b/plugin-canvas-slint/src/editor.rs index 6b4dce9..1ac51a6 100644 --- a/plugin-canvas-slint/src/editor.rs +++ b/plugin-canvas-slint/src/editor.rs @@ -51,7 +51,7 @@ impl SlintEditor { ).unwrap(); // It's ok if this fails as it just means it has already been set - slint::platform::set_platform(Box::new(PluginCanvasPlatform)).ok(); + slint::platform::set_platform(Box::new(PluginCanvasPlatform::new())).ok(); let window = Arc::new(window); WINDOW_TO_SLINT.set(Some(window.clone())); diff --git a/plugin-canvas-slint/src/platform.rs b/plugin-canvas-slint/src/platform.rs index 8f4a739..57923b7 100644 --- a/plugin-canvas-slint/src/platform.rs +++ b/plugin-canvas-slint/src/platform.rs @@ -1,13 +1,46 @@ -use std::rc::Rc; +use std::{rc::Rc, collections::VecDeque, sync::{Arc, Mutex}}; use i_slint_core::{platform::{Platform, PlatformError}, window::WindowAdapter}; +use slint::{EventLoopError, platform::EventLoopProxy}; use crate::window_adapter::PluginCanvasWindowAdapter; -pub struct PluginCanvasPlatform; +pub(crate) type CallbackQueue = Arc>>>; + +struct PluginCanvasEventLoopProxy { + queue: CallbackQueue, +} + +impl EventLoopProxy for PluginCanvasEventLoopProxy { + fn quit_event_loop(&self) -> Result<(), EventLoopError> { + Ok(()) + } + + fn invoke_from_event_loop(&self, event: Box) -> Result<(), EventLoopError> { + self.queue.lock().unwrap().push_back(event); + Ok(()) + } +} + +pub struct PluginCanvasPlatform { + callback_queue: CallbackQueue, +} + +impl PluginCanvasPlatform { + pub fn new() -> Self { + Self { callback_queue: Arc::new(Mutex::new(VecDeque::new())) } + } +} impl Platform for PluginCanvasPlatform { fn create_window_adapter(&self) -> Result, PlatformError> { - PluginCanvasWindowAdapter::new() + PluginCanvasWindowAdapter::new(self.callback_queue.clone()) + } + + fn new_event_loop_proxy(&self) -> Option> { + // Shared with all adapters - see window_adapter.rs draw event handling. + Some(Box::new(PluginCanvasEventLoopProxy { + queue: self.callback_queue.clone(), + })) } -} +} diff --git a/plugin-canvas-slint/src/window_adapter.rs b/plugin-canvas-slint/src/window_adapter.rs index de0fc7e..50ac380 100644 --- a/plugin-canvas-slint/src/window_adapter.rs +++ b/plugin-canvas-slint/src/window_adapter.rs @@ -4,6 +4,8 @@ use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering, AtomicUsize}; use std::sync::Arc; +use crate::platform::CallbackQueue; + use cursor_icon::CursorIcon; use i_slint_core::{window::{WindowAdapter, WindowAdapterInternal}, renderer::Renderer, platform::{PlatformError, WindowEvent}}; use i_slint_renderer_skia::{SkiaRenderer, SkiaSharedContext}; @@ -35,11 +37,12 @@ pub struct PluginCanvasWindowAdapter { pending_mouse_exit: AtomicBool, modifiers: RefCell, + callback_queue: CallbackQueue, } impl PluginCanvasWindowAdapter { #[allow(clippy::new_ret_no_self)] - pub fn new() -> Result, PlatformError> { + pub fn new(callback_queue: CallbackQueue) -> Result, PlatformError> { let plugin_canvas_window = WINDOW_TO_SLINT.take().unwrap(); let window_attributes = plugin_canvas_window.attributes(); @@ -80,6 +83,7 @@ impl PluginCanvasWindowAdapter { pending_mouse_exit: Default::default(), modifiers: Default::default(), + callback_queue, } }); @@ -122,6 +126,10 @@ impl PluginCanvasWindowAdapter { let built_in_response = match event { plugin_canvas::Event::Draw => { + // Note: this may invoke callbacks from other windows as well, not just ours, because the callback queue is owned by PluginCanvasPlatform. Events are added via `slint::invoke_from_event_loop` which has no window context. + let callbacks: Vec<_> = self.callback_queue.lock().unwrap().drain(..).collect(); + for callback in callbacks { callback(); } + match self.plugin_canvas_window.poll_events() { Ok(_) => {}, Err(e) => {