diff --git a/winit/src/platform_specific/mod.rs b/winit/src/platform_specific/mod.rs index 070452f89c..5490bfac77 100644 --- a/winit/src/platform_specific/mod.rs +++ b/winit/src/platform_specific/mod.rs @@ -79,31 +79,11 @@ impl PlatformSpecific { }; use wayland_backend::client::ObjectId; - let Some(backend) = self.wayland.display_handle() - else { - log::error!("No display handle"); + let Some(conn) = self.wayland.conn() else { + log::error!("No Wayland conn"); return; }; - // TODO use existing conn - let conn = match backend.as_raw() { - raw_window_handle::RawDisplayHandle::Wayland( - wayland_display_handle, - ) => { - let backend = unsafe { - Backend::from_foreign_display( - wayland_display_handle.display.as_ptr().cast(), - ) - }; - cctk::sctk::reexports::client::Connection::from_backend( - backend, - ) - } - _ => { - return; - } - }; - let Ok(raw) = window.window_handle() else { log::error!("Invalid window handle {id:?}"); return; @@ -140,13 +120,20 @@ impl PlatformSpecific { } } - pub(crate) fn create_surface(&mut self, width: u32, height: u32, data: &[u8]) -> Option> { + pub(crate) fn create_surface(&mut self) -> Option> { #[cfg(all(feature = "wayland", target_os = "linux"))] { - return self.wayland.create_surface(width, height, data); + return self.wayland.create_surface(); } None } + + pub(crate) fn update_surface_shm(&mut self, surface: &dyn HasWindowHandle, width: u32, height: u32, data: &[u8]) { + #[cfg(all(feature = "wayland", target_os = "linux"))] + { + return self.wayland.update_surface_shm(surface, width, height, data); + } + } } pub type UserInterfaces<'a, P> = HashMap< @@ -195,4 +182,4 @@ pub(crate) fn handle_event<'a, P, C>( ); } } -} \ No newline at end of file +} diff --git a/winit/src/platform_specific/wayland/mod.rs b/winit/src/platform_specific/wayland/mod.rs index 6404c63f07..cf862b4a3c 100644 --- a/winit/src/platform_specific/wayland/mod.rs +++ b/winit/src/platform_specific/wayland/mod.rs @@ -18,11 +18,12 @@ use iced_graphics::Compositor; use iced_runtime::core::window; use iced_runtime::Debug; use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; +use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle}; use sctk_event::SctkEvent; use std::{collections::HashMap, sync::Arc}; use subsurface_widget::{SubsurfaceInstance, SubsurfaceState}; use wayland_backend::client::ObjectId; -use wayland_client::Proxy; +use wayland_client::{Connection, Proxy}; use winit::event_loop::OwnedDisplayHandle; use winit::window::CursorIcon; @@ -62,6 +63,7 @@ pub(crate) struct WaylandSpecific { proxy: Option, sender: Option>, display_handle: Option, + conn: Option, modifiers: Modifiers, surface_ids: HashMap, destroyed_surface_ids: HashMap, @@ -77,6 +79,28 @@ impl PlatformSpecific { display: OwnedDisplayHandle, ) -> Self { self.wayland.winit_event_sender = Some(tx); + self.wayland.conn = match display.raw_display_handle() { + Ok(raw_window_handle::RawDisplayHandle::Wayland( + wayland_display_handle, + )) => { + let backend = unsafe { + wayland_backend::client::Backend::from_foreign_display( + wayland_display_handle.display.as_ptr().cast(), + ) + }; + Some(Connection::from_backend( + backend, + )) + } + Ok(_) => { + log::error!("Non-Wayland display handle"); + None + } + Err(_) => { + log::error!("No display handle"); + None + } + }; self.wayland.display_handle = Some(display); self.wayland.proxy = Some(raw); // TODO remove this @@ -114,8 +138,8 @@ impl PlatformSpecific { } impl WaylandSpecific { - pub(crate) fn display_handle(&self) -> Option { - self.display_handle.as_ref()?.display_handle().ok() + pub(crate) fn conn(&self) -> Option<&Connection> { + self.conn.as_ref() } pub(crate) fn handle_event<'a, P, C>( @@ -141,6 +165,7 @@ impl WaylandSpecific { proxy, sender, display_handle, + conn, surface_ids, destroyed_surface_ids, modifiers, @@ -205,22 +230,30 @@ impl WaylandSpecific { surface_subsurfaces, &subsurfaces, ); - - // Yeah, this is necessary for subsurfaces. should use unsync? - wl_surface.commit(); // XXX for drag surface } - // WIP cfg raw-window-handle - pub(crate) fn create_surface(&mut self, width: u32, height: u32, data: &[u8]) -> Option> { + pub(crate) fn create_surface(&mut self) -> Option> { if let Some(subsurface_state) = self.subsurface_state.as_mut() { - let wl_surface = subsurface_state.create_surface(width, height, data); + let wl_surface = subsurface_state.create_surface(); Some(Box::new(Window(wl_surface))) } else { None } } + + pub(crate) fn update_surface_shm(&mut self, window: &dyn HasWindowHandle, width: u32, height: u32, data: &[u8]) { + if let Some(subsurface_state) = self.subsurface_state.as_mut() { + if let RawWindowHandle::Wayland(window) = window.window_handle().unwrap().as_raw() { + let id = unsafe { ObjectId::from_ptr(WlSurface::interface(), window.surface.as_ptr().cast()).unwrap() }; + let surface = WlSurface::from_id(self.conn.as_ref().unwrap(), id).unwrap(); + subsurface_state.update_surface_shm(&surface, width, height, data); + } + } + } } + struct Window(WlSurface); + impl HasWindowHandle for Window { fn window_handle(&self) -> Result, raw_window_handle::HandleError> { Ok(unsafe { @@ -232,6 +265,7 @@ impl HasWindowHandle for Window { }) } } + impl Drop for Window { fn drop(&mut self) { self.0.destroy(); diff --git a/winit/src/platform_specific/wayland/subsurface_widget.rs b/winit/src/platform_specific/wayland/subsurface_widget.rs index 4e174d0a4e..5cde0e96bb 100644 --- a/winit/src/platform_specific/wayland/subsurface_widget.rs +++ b/winit/src/platform_specific/wayland/subsurface_widget.rs @@ -371,19 +371,20 @@ pub struct SubsurfaceState { } impl SubsurfaceState { - pub fn create_surface(&self, width: u32, height: u32, data: &[u8]) -> WlSurface { + pub fn create_surface(&self) -> WlSurface { + self + .wl_compositor + .create_surface(&self.qh, SurfaceData::new(None, 1)) + } + + pub fn update_surface_shm(&self, surface: &WlSurface, width: u32, height: u32, data: &[u8]) { let shm = ShmGlobal(&self.wl_shm); let mut pool = SlotPool::new(width as usize * height as usize * 4, &shm).unwrap(); let (buffer, canvas) = pool.create_buffer(width as i32, height as i32, width as i32 * 4, wl_shm::Format::Argb8888).unwrap(); canvas[0..width as usize * height as usize * 4].copy_from_slice(data); - - let surface = self - .wl_compositor - .create_surface(&self.qh, SurfaceData::new(None, 1)); surface.damage_buffer(0, 0, width as i32, height as i32); buffer.attach_to(&surface); surface.commit(); - surface } fn create_subsurface(&self, parent: &WlSurface) -> SubsurfaceInstance { diff --git a/winit/src/program.rs b/winit/src/program.rs index 2192eb9744..f3b1ae9db7 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -978,11 +978,12 @@ async fn run_instance<'a, P, C>( pix.swap(0, 2); } // update subsurfaces - if let Some(surface) = platform_specific_handler.create_surface(viewport.physical_width(), viewport.physical_height(), &bytes) { + if let Some(surface) = platform_specific_handler.create_surface() { // TODO Remove id let id = window::Id::unique(); platform_specific_handler .update_subsurfaces(id, &surface); + platform_specific_handler.update_surface_shm(&surface, viewport.physical_width(), viewport.physical_height(), &bytes); let surface = Arc::new(surface); dnd_surface = Some(surface.clone()); Icon::Surface(dnd::DndSurface(surface))