From 40066d2e6b4c1fa6a692f59f46ea4cee05848517 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 26 Aug 2024 11:11:48 -0700 Subject: [PATCH 1/2] WIP winit: Call `create_window` in `resumed`; not deprecated way `EventLoop::create_window()` is removed in winit git, so it seems we'll need to change this eventually. This isn't that hard to update in Smithay, but in the compositor it's a bit awkward to not have a window / EGL context / renderer until an event is sent from the backend... --- src/backend/winit/mod.rs | 281 ++++++++++++++++++++++----------------- 1 file changed, 158 insertions(+), 123 deletions(-) diff --git a/src/backend/winit/mod.rs b/src/backend/winit/mod.rs index 03302cacd01e..02c2f56110f0 100644 --- a/src/backend/winit/mod.rs +++ b/src/backend/winit/mod.rs @@ -19,6 +19,7 @@ //! two traits for the winit backend. use std::io::Error as IoError; +use std::marker::PhantomData; use std::rc::Rc; use std::sync::Arc; use std::time::Duration; @@ -63,7 +64,7 @@ use super::renderer::Renderer; /// Create a new [`WinitGraphicsBackend`], which implements the /// [`Renderer`] trait and a corresponding [`WinitEventLoop`]. -pub fn init() -> Result<(WinitGraphicsBackend, WinitEventLoop), Error> +pub fn init() -> Result, Error> where R: From + Bind>, crate::backend::SwapBuffersError: From<::Error>, @@ -79,9 +80,7 @@ where /// Create a new [`WinitGraphicsBackend`], which implements the [`Renderer`] /// trait, from a given [`WindowAttributes`] struct and a corresponding /// [`WinitEventLoop`]. -pub fn init_from_attributes( - attributes: WindowAttributes, -) -> Result<(WinitGraphicsBackend, WinitEventLoop), Error> +pub fn init_from_attributes(attributes: WindowAttributes) -> Result, Error> where R: From + Bind>, crate::backend::SwapBuffersError: From<::Error>, @@ -104,7 +103,7 @@ where pub fn init_from_attributes_with_gl_attr( attributes: WindowAttributes, gl_attributes: GlAttributes, -) -> Result<(WinitGraphicsBackend, WinitEventLoop), Error> +) -> Result, Error> where R: From + Bind>, crate::backend::SwapBuffersError: From<::Error>, @@ -115,106 +114,24 @@ where let event_loop = EventLoop::builder().build().map_err(Error::EventLoopCreation)?; - // TODO: Create window in `resumed`? - #[allow(deprecated)] - let window = Arc::new( - event_loop - .create_window(attributes) - .map_err(Error::WindowCreation)?, - ); - - span.record("window", Into::::into(window.id())); - debug!("Window created"); - - let (display, context, surface, is_x11) = { - let display = unsafe { EGLDisplay::new(window.clone())? }; - - let context = - EGLContext::new_with_config(&display, gl_attributes, PixelFormatRequirements::_10_bit()) - .or_else(|_| { - EGLContext::new_with_config(&display, gl_attributes, PixelFormatRequirements::_8_bit()) - })?; - - let (surface, is_x11) = match window.window_handle().map(|handle| handle.as_raw()) { - Ok(RawWindowHandle::Wayland(handle)) => { - debug!("Winit backend: Wayland"); - let size = window.inner_size(); - let surface = unsafe { - wegl::WlEglSurface::new_from_raw( - handle.surface.as_ptr() as *mut _, - size.width as i32, - size.height as i32, - ) - } - .map_err(|err| Error::Surface(err.into()))?; - unsafe { - ( - EGLSurface::new( - &display, - context.pixel_format().unwrap(), - context.config_id(), - surface, - ) - .map_err(EGLError::CreationFailed)?, - false, - ) - } - } - Ok(RawWindowHandle::Xlib(handle)) => { - debug!("Winit backend: X11"); - unsafe { - ( - EGLSurface::new( - &display, - context.pixel_format().unwrap(), - context.config_id(), - native::XlibWindow(handle.window), - ) - .map_err(EGLError::CreationFailed)?, - true, - ) - } - } - _ => panic!("only running on Wayland or with Xlib is supported"), - }; - - let _ = context.unbind(); - (display, context, surface, is_x11) - }; - - let egl = Rc::new(surface); - let renderer = unsafe { GlesRenderer::new(context)?.into() }; - let damage_tracking = display.supports_damage(); - drop(_guard); event_loop.set_control_flow(winit::event_loop::ControlFlow::Poll); let event_loop = Generic::new(event_loop, Interest::READ, calloop::Mode::Level); - Ok(( - WinitGraphicsBackend { - window: window.clone(), - span: span.clone(), - _display: display, - egl_surface: egl, - damage_tracking, - bind_size: None, - renderer, - }, - WinitEventLoop { - inner: WinitEventLoopInner { - scale_factor: window.scale_factor(), - clock: Clock::::new(), - key_counter: 0, - window, - is_x11, - }, - fake_token: None, - event_loop, - pending_events: Vec::new(), + Ok(WinitEventLoop { + inner: WinitEventLoopInner { + clock: Clock::::new(), + key_counter: 0, + window: None, + attributes, + gl_attributes, span, }, - )) + fake_token: None, + event_loop, + pending_events: Vec::new(), + }) } /// Errors thrown by the `winit` backends @@ -359,11 +276,12 @@ where #[derive(Debug)] struct WinitEventLoopInner { - window: Arc, + window: Option>, clock: Clock, key_counter: u32, - is_x11: bool, - scale_factor: f64, + attributes: WindowAttributes, + gl_attributes: GlAttributes, + span: tracing::Span, } /// Abstracted event loop of a [`WinitWindow`]. @@ -372,15 +290,17 @@ struct WinitEventLoopInner { /// [`dispatch_new_events`](WinitEventLoop::dispatch_new_events) periodically to receive any /// events. #[derive(Debug)] -pub struct WinitEventLoop { +pub struct WinitEventLoop { inner: WinitEventLoopInner, fake_token: Option, - pending_events: Vec, + pending_events: Vec>, event_loop: Generic>, - span: tracing::Span, } -impl WinitEventLoop { +impl WinitEventLoop +where + R: From, +{ /// Processes new events of the underlying event loop and calls the provided callback. /// /// You need to periodically call this function to keep the underlying event loop and @@ -392,11 +312,11 @@ impl WinitEventLoop { /// /// The linked [`WinitGraphicsBackend`] will error with a lost context and should /// not be used anymore as well. - #[instrument(level = "trace", parent = &self.span, skip_all)] + #[instrument(level = "trace", parent = &self.inner.span, skip_all)] #[profiling::function] pub fn dispatch_new_events(&mut self, callback: F) -> PumpStatus where - F: FnMut(WinitEvent), + F: FnMut(WinitEvent), { // SAFETY: we don't drop event loop ourselves. let event_loop = unsafe { self.event_loop.get_mut() }; @@ -406,30 +326,141 @@ impl WinitEventLoop { &mut WinitEventLoopApp { inner: &mut self.inner, callback, + _renderer: PhantomData, }, ) } } -struct WinitEventLoopApp<'a, F: FnMut(WinitEvent)> { +struct WinitEventLoopApp<'a, R, F: FnMut(WinitEvent)> { inner: &'a mut WinitEventLoopInner, callback: F, + _renderer: PhantomData, } -impl<'a, F: FnMut(WinitEvent)> WinitEventLoopApp<'a, F> { +impl<'a, R, F: FnMut(WinitEvent)> WinitEventLoopApp<'a, R, F> +where + R: From, +{ fn timestamp(&self) -> u64 { self.inner.clock.now().as_micros() } + + pub fn create_window(&mut self, event_loop: &ActiveEventLoop) -> Result, Error> { + let span = info_span!("backend_winit", window = tracing::field::Empty); + let _guard = span.enter(); + info!("Initializing a winit backend"); + + let window = Arc::new( + event_loop + .create_window(self.inner.attributes.clone()) + .map_err(Error::WindowCreation)?, + ); + + span.record("window", Into::::into(window.id())); + debug!("Window created"); + + let (display, context, surface) = { + let display = unsafe { EGLDisplay::new(window.clone())? }; + + let context = EGLContext::new_with_config( + &display, + self.inner.gl_attributes, + PixelFormatRequirements::_10_bit(), + ) + .or_else(|_| { + EGLContext::new_with_config( + &display, + self.inner.gl_attributes, + PixelFormatRequirements::_8_bit(), + ) + })?; + + let surface = match window.window_handle().map(|handle| handle.as_raw()) { + Ok(RawWindowHandle::Wayland(handle)) => { + debug!("Winit backend: Wayland"); + let size = window.inner_size(); + let surface = unsafe { + wegl::WlEglSurface::new_from_raw( + handle.surface.as_ptr() as *mut _, + size.width as i32, + size.height as i32, + ) + } + .map_err(|err| Error::Surface(err.into()))?; + unsafe { + EGLSurface::new( + &display, + context.pixel_format().unwrap(), + context.config_id(), + surface, + ) + .map_err(EGLError::CreationFailed)? + } + } + Ok(RawWindowHandle::Xlib(handle)) => { + debug!("Winit backend: X11"); + unsafe { + EGLSurface::new( + &display, + context.pixel_format().unwrap(), + context.config_id(), + native::XlibWindow(handle.window), + ) + .map_err(EGLError::CreationFailed)? + } + } + _ => panic!("only running on Wayland or with Xlib is supported"), + }; + + let _ = context.unbind(); + (display, context, surface) + }; + + let egl = Rc::new(surface); + let renderer = unsafe { GlesRenderer::new(context)?.into() }; + let damage_tracking = display.supports_damage(); + + drop(_guard); + + self.inner.window = Some(window.clone()); + + Ok(WinitGraphicsBackend { + window, + span: span.clone(), + _display: display, + egl_surface: egl, + damage_tracking, + bind_size: None, + renderer, + }) + } } -impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { - fn resumed(&mut self, _event_loop: &ActiveEventLoop) { +impl<'a, R, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, R, F> +where + R: From, +{ + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let window = self.create_window(event_loop).unwrap(); + (self.callback)(WinitEvent::WindowCreated(window)); + (self.callback)(WinitEvent::Input(InputEvent::DeviceAdded { device: WinitVirtualDevice, })); } + fn suspended(&mut self, _event_loop: &ActiveEventLoop) { + (self.callback)(WinitEvent::Input(InputEvent::DeviceRemoved { + device: WinitVirtualDevice, + })); + } + fn window_event(&mut self, _event_loop: &ActiveEventLoop, _window_id: WindowId, event: WindowEvent) { + let Some(window) = self.inner.window.as_ref() else { + return; + }; + match event { WindowEvent::Resized(size) => { trace!("Resizing window to {size:?}"); @@ -437,7 +468,7 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { (self.callback)(WinitEvent::Resized { size: (w, h).into(), - scale_factor: self.inner.scale_factor, + scale_factor: window.scale_factor(), }); } WindowEvent::ScaleFactorChanged { @@ -445,11 +476,10 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { .. } => { trace!("Scale factor changed to {new_scale_factor}"); - self.inner.scale_factor = new_scale_factor; - let (w, h): (i32, i32) = self.inner.window.inner_size().into(); + let (w, h): (i32, i32) = window.inner_size().into(); (self.callback)(WinitEvent::Resized { size: (w, h).into(), - scale_factor: self.inner.scale_factor, + scale_factor: new_scale_factor, }); } WindowEvent::RedrawRequested => { @@ -483,7 +513,7 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { (self.callback)(WinitEvent::Input(event)); } WindowEvent::CursorMoved { position, .. } => { - let size = self.inner.window.inner_size(); + let size = window.inner_size(); let x = position.x / size.width as f64; let y = position.y / size.height as f64; let event = InputEvent::PointerMotionAbsolute { @@ -510,7 +540,7 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { time: self.timestamp(), button, state, - is_x11: self.inner.is_x11, + is_x11: matches!(window.window_handle().unwrap().as_raw(), RawWindowHandle::Xlib(_)), }, }; (self.callback)(WinitEvent::Input(event)); @@ -521,7 +551,7 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { id, .. }) => { - let size = self.inner.window.inner_size(); + let size = window.inner_size(); let x = location.x / size.width as f64; let y = location.y / size.width as f64; let event = InputEvent::TouchDown { @@ -541,7 +571,7 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { id, .. }) => { - let size = self.inner.window.inner_size(); + let size = window.inner_size(); let x = location.x / size.width as f64; let y = location.y / size.width as f64; let event = InputEvent::TouchMotion { @@ -562,7 +592,7 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { id, .. }) => { - let size = self.inner.window.inner_size(); + let size = window.inner_size(); let x = location.x / size.width as f64; let y = location.y / size.width as f64; let event = InputEvent::TouchMotion { @@ -621,8 +651,11 @@ impl<'a, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, F> { } } -impl EventSource for WinitEventLoop { - type Event = WinitEvent; +impl EventSource for WinitEventLoop +where + R: From, +{ + type Event = WinitEvent; type Metadata = (); type Ret = (); type Error = IoError; @@ -689,7 +722,9 @@ impl EventSource for WinitEventLoop { /// Specific events generated by Winit #[derive(Debug)] -pub enum WinitEvent { +pub enum WinitEvent { + WindowCreated(WinitGraphicsBackend), + /// The window has been resized Resized { /// The new physical size (in pixels) From d92a9eee19b327500dcfec1151d41ac46a776f38 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Mon, 26 Aug 2024 11:28:24 -0700 Subject: [PATCH 2/2] WIP winit git I wanted to see how the changes in Winit git would work here. So of course this depends on that being released. Depends on https://github.com/Smithay/smithay/pull/1514. It doesn't seem to pose a particular challenge beyond that. Updating compositors for that change will be needed to test this... --- Cargo.toml | 2 +- anvil/src/winit.rs | 171 ++++++++++++++++++++------------------ src/backend/egl/native.rs | 2 +- src/backend/winit/mod.rs | 80 ++++++++++++------ 4 files changed, 147 insertions(+), 108 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 20584075f4d7..45264305acc9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ wayland-protocols-misc = { version = "0.3.1", features = ["server"], optional = wayland-server = { version = "0.31.0", optional = true } wayland-sys = { version = "0.31", optional = true } wayland-backend = { version = "0.3.5", optional = true } -winit = { version = "0.30.0", default-features = false, features = ["wayland", "wayland-dlopen", "x11", "rwh_06"], optional = true } +winit = { git = "https://github.com/rust-windowing/winit", default-features = false, features = ["wayland", "wayland-dlopen", "x11", "rwh_06"], optional = true } x11rb = { version = "0.13.0", optional = true } xkbcommon = { version = "0.8.0", features = ["wayland"]} scan_fmt = { version = "0.2.3", default-features = false } diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 67ee9612255e..5ad11d27fc3f 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -98,92 +98,13 @@ pub fn run_winit() { let mut display_handle = display.handle(); #[cfg_attr(not(feature = "egl"), allow(unused_mut))] - let (mut backend, mut winit) = match winit::init::() { + let mut winit = match winit::init::() { Ok(ret) => ret, Err(err) => { error!("Failed to initialize Winit backend: {}", err); return; } }; - let size = backend.window_size(); - - let mode = Mode { - size, - refresh: 60_000, - }; - let output = Output::new( - OUTPUT_NAME.to_string(), - PhysicalProperties { - size: (0, 0).into(), - subpixel: Subpixel::Unknown, - make: "Smithay".into(), - model: "Winit".into(), - }, - ); - let _global = output.create_global::>(&display.handle()); - output.change_current_state(Some(mode), Some(Transform::Flipped180), None, Some((0, 0).into())); - output.set_preferred(mode); - - #[cfg(feature = "debug")] - let fps_image = - image::ImageReader::with_format(std::io::Cursor::new(FPS_NUMBERS_PNG), image::ImageFormat::Png) - .decode() - .unwrap(); - #[cfg(feature = "debug")] - let fps_texture = backend - .renderer() - .import_memory( - &fps_image.to_rgba8(), - Fourcc::Abgr8888, - (fps_image.width() as i32, fps_image.height() as i32).into(), - false, - ) - .expect("Unable to upload FPS texture"); - #[cfg(feature = "debug")] - let mut fps_element = FpsElement::new(fps_texture); - - let render_node = EGLDevice::device_for_display(backend.renderer().egl_context().display()) - .and_then(|device| device.try_get_render_node()); - - let dmabuf_default_feedback = match render_node { - Ok(Some(node)) => { - let dmabuf_formats = backend.renderer().dmabuf_formats(); - let dmabuf_default_feedback = DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats) - .build() - .unwrap(); - Some(dmabuf_default_feedback) - } - Ok(None) => { - warn!("failed to query render node, dmabuf will use v3"); - None - } - Err(err) => { - warn!(?err, "failed to egl device for display, dmabuf will use v3"); - None - } - }; - - // if we failed to build dmabuf feedback we fall back to dmabuf v3 - // Note: egl on Mesa requires either v4 or wl_drm (initialized with bind_wl_display) - let dmabuf_state = if let Some(default_feedback) = dmabuf_default_feedback { - let mut dmabuf_state = DmabufState::new(); - let dmabuf_global = dmabuf_state.create_global_with_default_feedback::>( - &display.handle(), - &default_feedback, - ); - (dmabuf_state, dmabuf_global, Some(default_feedback)) - } else { - let dmabuf_formats = backend.renderer().dmabuf_formats(); - let mut dmabuf_state = DmabufState::new(); - let dmabuf_global = - dmabuf_state.create_global::>(&display.handle(), dmabuf_formats); - (dmabuf_state, dmabuf_global, None) - }; - - #[cfg(feature = "egl")] - if backend.renderer().bind_wl_display(&display.handle()).is_ok() { - info!("EGL hardware-acceleration enabled"); - }; let data = { let damage_tracker = OutputDamageTracker::from_output(&output); @@ -212,6 +133,96 @@ pub fn run_winit() { while state.running.load(Ordering::SeqCst) { let status = winit.dispatch_new_events(|event| match event { + WinitEvent::WindowCreated(backend) => { + let size = backend.window_size(); + + let mode = Mode { + size, + refresh: 60_000, + }; + let output = Output::new( + OUTPUT_NAME.to_string(), + PhysicalProperties { + size: (0, 0).into(), + subpixel: Subpixel::Unknown, + make: "Smithay".into(), + model: "Winit".into(), + }, + ); + let _global = output.create_global::>(&display.handle()); + output.change_current_state( + Some(mode), + Some(Transform::Flipped180), + None, + Some((0, 0).into()), + ); + output.set_preferred(mode); + + #[cfg(feature = "debug")] + let fps_image = image::ImageReader::with_format( + std::io::Cursor::new(FPS_NUMBERS_PNG), + image::ImageFormat::Png, + ) + .decode() + .unwrap(); + #[cfg(feature = "debug")] + let fps_texture = backend + .renderer() + .import_memory( + &fps_image.to_rgba8(), + Fourcc::Abgr8888, + (fps_image.width() as i32, fps_image.height() as i32).into(), + false, + ) + .expect("Unable to upload FPS texture"); + #[cfg(feature = "debug")] + let mut fps_element = FpsElement::new(fps_texture); + + let render_node = EGLDevice::device_for_display(backend.renderer().egl_context().display()) + .and_then(|device| device.try_get_render_node()); + + let dmabuf_default_feedback = match render_node { + Ok(Some(node)) => { + let dmabuf_formats = backend.renderer().dmabuf_formats(); + let dmabuf_default_feedback = + DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats) + .build() + .unwrap(); + Some(dmabuf_default_feedback) + } + Ok(None) => { + warn!("failed to query render node, dmabuf will use v3"); + None + } + Err(err) => { + warn!(?err, "failed to egl device for display, dmabuf will use v3"); + None + } + }; + + // if we failed to build dmabuf feedback we fall back to dmabuf v3 + // Note: egl on Mesa requires either v4 or wl_drm (initialized with bind_wl_display) + let dmabuf_state = if let Some(default_feedback) = dmabuf_default_feedback { + let mut dmabuf_state = DmabufState::new(); + let dmabuf_global = dmabuf_state + .create_global_with_default_feedback::>( + &display.handle(), + &default_feedback, + ); + (dmabuf_state, dmabuf_global, Some(default_feedback)) + } else { + let dmabuf_formats = backend.renderer().dmabuf_formats(); + let mut dmabuf_state = DmabufState::new(); + let dmabuf_global = dmabuf_state + .create_global::>(&display.handle(), dmabuf_formats); + (dmabuf_state, dmabuf_global, None) + }; + + #[cfg(feature = "egl")] + if backend.renderer().bind_wl_display(&display.handle()).is_ok() { + info!("EGL hardware-acceleration enabled"); + }; + } WinitEvent::Resized { size, .. } => { // We only have one output let output = state.space.outputs().next().unwrap().clone(); diff --git a/src/backend/egl/native.rs b/src/backend/egl/native.rs index 6c2e32259ca6..00372f12972a 100644 --- a/src/backend/egl/native.rs +++ b/src/backend/egl/native.rs @@ -160,7 +160,7 @@ impl EGLNativeDisplay for GbmDevice { } #[cfg(feature = "backend_winit")] -impl EGLNativeDisplay for Arc { +impl EGLNativeDisplay for Arc { fn supported_platforms(&self) -> Vec> { use winit::raw_window_handle::{self, HasDisplayHandle}; diff --git a/src/backend/winit/mod.rs b/src/backend/winit/mod.rs index 02c2f56110f0..97c6735ef5c8 100644 --- a/src/backend/winit/mod.rs +++ b/src/backend/winit/mod.rs @@ -18,6 +18,7 @@ //! The other types in this module are the instances of the associated types of these //! two traits for the winit backend. +use std::collections::HashMap; use std::io::Error as IoError; use std::marker::PhantomData; use std::rc::Rc; @@ -34,7 +35,7 @@ use winit::raw_window_handle::{HasWindowHandle, RawWindowHandle}; use winit::{ application::ApplicationHandler, dpi::LogicalSize, - event::{ElementState, Touch, TouchPhase, WindowEvent}, + event::{ElementState, FingerId, Touch, TouchPhase, WindowEvent}, event_loop::{ActiveEventLoop, EventLoop}, platform::pump_events::EventLoopExtPumpEvents, window::{Window as WinitWindow, WindowAttributes, WindowId}, @@ -70,7 +71,7 @@ where crate::backend::SwapBuffersError: From<::Error>, { init_from_attributes( - WinitWindow::default_attributes() + ::default_attributes() .with_inner_size(LogicalSize::new(1280.0, 800.0)) .with_title("Smithay") .with_visible(true), @@ -100,6 +101,7 @@ where /// trait, from a given [`WindowAttributes`] struct, as well as given /// [`GlAttributes`] for further customization of the rendering pipeline and a /// corresponding [`WinitEventLoop`]. +/// corresponding [`WinitEventLoop`]. pub fn init_from_attributes_with_gl_attr( attributes: WindowAttributes, gl_attributes: GlAttributes, @@ -127,6 +129,7 @@ where attributes, gl_attributes, span, + finger_ids: HashMap::new(), }, fake_token: None, event_loop, @@ -158,13 +161,13 @@ pub enum Error { } /// Window with an active EGL Context created by `winit`. -#[derive(Debug)] +//#[derive(Debug)] pub struct WinitGraphicsBackend { renderer: R, // The display isn't used past this point but must be kept alive. _display: EGLDisplay, egl_surface: Rc, - window: Arc, + window: Arc, damage_tracking: bool, bind_size: Option>, span: tracing::Span, @@ -187,8 +190,8 @@ where } /// Reference to the underlying window - pub fn window(&self) -> &WinitWindow { - &self.window + pub fn window(&self) -> &dyn WinitWindow { + self.window.as_ref() } /// Access the underlying renderer @@ -274,14 +277,15 @@ where } } -#[derive(Debug)] +//#[derive(Debug)] struct WinitEventLoopInner { - window: Option>, + window: Option>, clock: Clock, key_counter: u32, attributes: WindowAttributes, gl_attributes: GlAttributes, span: tracing::Span, + finger_ids: HashMap, } /// Abstracted event loop of a [`WinitWindow`]. @@ -289,12 +293,12 @@ struct WinitEventLoopInner { /// You can register it into `calloop` or call /// [`dispatch_new_events`](WinitEventLoop::dispatch_new_events) periodically to receive any /// events. -#[derive(Debug)] +//#[derive(Debug)] pub struct WinitEventLoop { inner: WinitEventLoopInner, fake_token: Option, pending_events: Vec>, - event_loop: Generic>, + event_loop: Generic, } impl WinitEventLoop @@ -346,12 +350,15 @@ where self.inner.clock.now().as_micros() } - pub fn create_window(&mut self, event_loop: &ActiveEventLoop) -> Result, Error> { + pub fn create_window( + &mut self, + event_loop: &dyn ActiveEventLoop, + ) -> Result, Error> { let span = info_span!("backend_winit", window = tracing::field::Empty); let _guard = span.enter(); info!("Initializing a winit backend"); - let window = Arc::new( + let window = Arc::::from( event_loop .create_window(self.inner.attributes.clone()) .map_err(Error::WindowCreation)?, @@ -435,13 +442,28 @@ where renderer, }) } + + fn finger_id(&mut self, id: FingerId) -> u64 { + match self.inner.finger_ids.get(&id) { + Some(id) => *id, + None => { + for i in 0.. { + if self.inner.finger_ids.values().any(|x| *x == i) { + self.inner.finger_ids.insert(id, i); + return i; + } + } + unreachable!() + } + } + } } impl<'a, R, F: FnMut(WinitEvent)> ApplicationHandler for WinitEventLoopApp<'a, R, F> where R: From, { - fn resumed(&mut self, event_loop: &ActiveEventLoop) { + fn resumed(&mut self, event_loop: &dyn ActiveEventLoop) { let window = self.create_window(event_loop).unwrap(); (self.callback)(WinitEvent::WindowCreated(window)); @@ -450,13 +472,13 @@ where })); } - fn suspended(&mut self, _event_loop: &ActiveEventLoop) { + fn suspended(&mut self, _event_loop: &dyn ActiveEventLoop) { (self.callback)(WinitEvent::Input(InputEvent::DeviceRemoved { device: WinitVirtualDevice, })); } - 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) { let Some(window) = self.inner.window.as_ref() else { return; }; @@ -548,7 +570,7 @@ where WindowEvent::Touch(Touch { phase: TouchPhase::Started, location, - id, + finger_id, .. }) => { let size = window.inner_size(); @@ -559,7 +581,7 @@ where time: self.timestamp(), global_position: location, position: RelativePosition::new(x, y), - id, + id: self.finger_id(finger_id), }, }; @@ -568,7 +590,7 @@ where WindowEvent::Touch(Touch { phase: TouchPhase::Moved, location, - id, + finger_id, .. }) => { let size = window.inner_size(); @@ -579,7 +601,7 @@ where time: self.timestamp(), position: RelativePosition::new(x, y), global_position: location, - id, + id: self.finger_id(finger_id), }, }; @@ -589,7 +611,7 @@ where WindowEvent::Touch(Touch { phase: TouchPhase::Ended, location, - id, + finger_id, .. }) => { let size = window.inner_size(); @@ -600,7 +622,7 @@ where time: self.timestamp(), position: RelativePosition::new(x, y), global_position: location, - id, + id: self.finger_id(finger_id), }, }; (self.callback)(WinitEvent::Input(event)); @@ -608,30 +630,32 @@ where let event = InputEvent::TouchUp { event: WinitTouchEndedEvent { time: self.timestamp(), - id, + id: self.finger_id(finger_id), }, }; + self.inner.finger_ids.remove(&finger_id); (self.callback)(WinitEvent::Input(event)); } WindowEvent::Touch(Touch { phase: TouchPhase::Cancelled, - id, + finger_id, .. }) => { let event = InputEvent::TouchCancel { event: WinitTouchCancelledEvent { time: self.timestamp(), - id, + id: self.finger_id(finger_id), }, }; + self.inner.finger_ids.remove(&finger_id); + (self.callback)(WinitEvent::Input(event)); } WindowEvent::DroppedFile(_) | WindowEvent::Destroyed | WindowEvent::CursorEntered { .. } - | WindowEvent::AxisMotion { .. } | WindowEvent::CursorLeft { .. } | WindowEvent::ModifiersChanged(_) | WindowEvent::KeyboardInput { .. } @@ -649,6 +673,10 @@ where | WindowEvent::ActivationTokenDone { .. } => (), } } + + fn can_create_surfaces(&mut self, _: &dyn ActiveEventLoop) { + todo!() + } } impl EventSource for WinitEventLoop @@ -721,7 +749,7 @@ where } /// Specific events generated by Winit -#[derive(Debug)] +// #[derive(Debug)] pub enum WinitEvent { WindowCreated(WinitGraphicsBackend),