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),