diff --git a/examples/window.rs b/examples/window.rs index 61bd51bd7..35333ac0f 100644 --- a/examples/window.rs +++ b/examples/window.rs @@ -27,6 +27,7 @@ use winit::platform::macos::{OptionAsAlt, WindowAttributesExtMacOS, WindowExtMac use winit::platform::startup_notify::{ self, EventLoopExtStartupNotify, WindowAttributesExtStartupNotify, WindowExtStartupNotify, }; +use winit::platform::wayland::{EventLoopExtWayland, WaylandApplicationHandler}; #[cfg(web_platform)] use winit::platform::web::{ActiveEventLoopExtWeb, CustomCursorExtWeb, WindowAttributesExtWeb}; use winit::window::{ @@ -46,7 +47,7 @@ fn main() -> Result<(), Box> { tracing::init(); - let event_loop = EventLoop::new()?; + let mut event_loop = EventLoop::new()?; let (sender, receiver) = mpsc::channel(); // Wire the user event from another thread. @@ -67,6 +68,7 @@ fn main() -> Result<(), Box> { } let app = Application::new(&event_loop, receiver, sender); + event_loop.register_wayland_callback::(); Ok(event_loop.run_app(app)?) } @@ -371,6 +373,11 @@ impl Application { } impl ApplicationHandler for Application { + fn as_any(&mut self) -> Option<&mut dyn std::any::Any> { + println!("Called"); + Some(self) + } + fn proxy_wake_up(&mut self, event_loop: &dyn ActiveEventLoop) { while let Ok(action) = self.receiver.try_recv() { self.handle_action_from_proxy(event_loop, action) @@ -552,6 +559,12 @@ impl ApplicationHandler for Application { } } +impl WaylandApplicationHandler for Application { + fn wayland_callback(&mut self) { + println!("Wayland callback!"); + } +} + /// State of the window. struct WindowState { /// IME input. diff --git a/src/application.rs b/src/application.rs index 8b268b05d..bb3f43471 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,5 +1,7 @@ //! End user application handling. +use std::any::Any; + use crate::event::{DeviceEvent, DeviceId, StartCause, WindowEvent}; use crate::event_loop::ActiveEventLoop; use crate::window::WindowId; @@ -325,10 +327,23 @@ pub trait ApplicationHandler { fn memory_warning(&mut self, event_loop: &dyn ActiveEventLoop) { let _ = event_loop; } + + /// Get the [`ApplicationHandler`] as [`Any`]. + /// + /// This is useful for downcasting to a concrete application type. + #[inline(always)] + fn as_any(&mut self) -> Option<&mut dyn Any> { + None + } } #[deny(clippy::missing_trait_methods)] impl ApplicationHandler for &mut A { + #[inline(always)] + fn as_any(&mut self) -> Option<&mut dyn Any> { + (**self).as_any() + } + #[inline] fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) { (**self).new_events(event_loop, cause); @@ -397,6 +412,11 @@ impl ApplicationHandler for &mut A { #[deny(clippy::missing_trait_methods)] impl ApplicationHandler for Box { + #[inline(always)] + fn as_any(&mut self) -> Option<&mut dyn Any> { + (**self).as_any() + } + #[inline] fn new_events(&mut self, event_loop: &dyn ActiveEventLoop, cause: StartCause) { (**self).new_events(event_loop, cause); diff --git a/src/platform/wayland.rs b/src/platform/wayland.rs index 7b489abed..789c2fa88 100644 --- a/src/platform/wayland.rs +++ b/src/platform/wayland.rs @@ -13,6 +13,7 @@ //! * `wayland-csd-adwaita` (default). //! * `wayland-csd-adwaita-crossfont`. //! * `wayland-csd-adwaita-notitle`. +use crate::application::ApplicationHandler; use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder}; use crate::monitor::MonitorHandle; pub use crate::window::Theme; @@ -24,6 +25,10 @@ pub trait ActiveEventLoopExtWayland { fn is_wayland(&self) -> bool; } +pub trait WaylandApplicationHandler: ApplicationHandler + 'static { + fn wayland_callback(&mut self); +} + impl ActiveEventLoopExtWayland for &dyn ActiveEventLoop { #[inline] fn is_wayland(&self) -> bool { @@ -35,6 +40,8 @@ impl ActiveEventLoopExtWayland for &dyn ActiveEventLoop { pub trait EventLoopExtWayland { /// True if the [`EventLoop`] uses Wayland. fn is_wayland(&self) -> bool; + + fn register_wayland_callback(&mut self); } impl EventLoopExtWayland for EventLoop { @@ -42,6 +49,22 @@ impl EventLoopExtWayland for EventLoop { fn is_wayland(&self) -> bool { self.event_loop.is_wayland() } + + fn register_wayland_callback(&mut self) { + let event_loop = match &self.event_loop { + crate::platform_impl::EventLoop::Wayland(event_loop) => &event_loop.active_event_loop, + #[cfg(x11_platform)] + crate::platform_impl::EventLoop::X(_) => return, + }; + + event_loop.wayland_callback.set(Some(|app: &mut dyn ApplicationHandler| { + app.as_any() + .expect("as_any_mut is not implemented") + .downcast_mut::() + .unwrap() + .wayland_callback() + })); + } } /// Additional methods on [`EventLoopBuilder`] that are specific to Wayland. diff --git a/src/platform_impl/linux/wayland/event_loop/mod.rs b/src/platform_impl/linux/wayland/event_loop/mod.rs index 39a546e71..299dabfb9 100644 --- a/src/platform_impl/linux/wayland/event_loop/mod.rs +++ b/src/platform_impl/linux/wayland/event_loop/mod.rs @@ -53,7 +53,7 @@ pub struct EventLoop { connection: Connection, /// Event loop window target. - active_event_loop: ActiveEventLoop, + pub(crate) active_event_loop: ActiveEventLoop, // XXX drop after everything else, just to be safe. /// Calloop's event loop. @@ -139,6 +139,7 @@ impl EventLoop { control_flow: Cell::new(ControlFlow::default()), exit: Cell::new(None), state: RefCell::new(winit_state), + wayland_callback: Default::default(), }; let event_loop = Self { @@ -297,6 +298,10 @@ impl EventLoop { app.new_events(&self.active_event_loop, cause); + if let Some(callback) = self.active_event_loop.wayland_callback.get() { + callback(app); + } + // NB: For consistency all platforms must call `can_create_surfaces` even though Wayland // applications don't themselves have a formal surface destroy/create lifecycle. if cause == StartCause::Init { @@ -582,6 +587,8 @@ pub struct ActiveEventLoop { /// Connection to the wayland server. pub connection: Connection, + + pub wayland_callback: Cell>, } impl RootActiveEventLoop for ActiveEventLoop {