From 90f60c9178e56cfd22fcc30ac2a56a666e09a603 Mon Sep 17 00:00:00 2001 From: Nova Date: Thu, 4 Apr 2024 23:55:49 -0400 Subject: [PATCH] refactor(wayland/xwayland_rootless): use tokio --- Cargo.lock | 2 +- Cargo.toml | 5 +- src/wayland/compositor.rs | 4 +- src/wayland/mod.rs | 15 +- src/wayland/xwayland_rootless.rs | 443 ++----------------------------- 5 files changed, 36 insertions(+), 433 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cf948d6..8aaa4c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2025,7 +2025,7 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/smithay/smithay.git#8287457195cf6a495331f65f5e0119f931ff7e79" +source = "git+https://github.com/colinmarc/smithay.git#d176935e3223bea6ae48946219bc55d12ebbba54" dependencies = [ "appendlist", "bitflags 2.4.0", diff --git a/Cargo.toml b/Cargo.toml index 9433e42..179243f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,8 +74,9 @@ fxtypemap = "0.2.0" toml = "0.8.10" [dependencies.smithay] -# git = "https://github.com/technobaboo/smithay.git" # Until we get stereokit to understand OES samplers and external textures -git = "https://github.com/smithay/smithay.git" # Until we get stereokit to understand OES samplers and external textures +# git = "https://github.com/technobaboo/smithay.git" +git = "https://github.com/colinmarc/smithay.git" +# git = "https://github.com/smithay/smithay.git" # path = "../smithay" default-features = false features = [ diff --git a/src/wayland/compositor.rs b/src/wayland/compositor.rs index e153f36..b047d5c 100644 --- a/src/wayland/compositor.rs +++ b/src/wayland/compositor.rs @@ -2,7 +2,7 @@ use crate::wayland::surface::CoreSurface; use super::state::{ClientState, WaylandState}; use portable_atomic::{AtomicU32, Ordering}; -#[cfg(feature = "xwayland")] +#[cfg(feature = "xwayland_rootless")] use smithay::xwayland::XWaylandClientData; use smithay::{ delegate_compositor, @@ -41,7 +41,7 @@ impl CompositorHandler for WaylandState { if let Some(client_state) = client.get_data::() { &client_state.compositor_state } else { - #[cfg(feature = "xwayland")] + #[cfg(feature = "xwayland_rootless")] if let Some(xwayland_client_data) = client.get_data::() { return &xwayland_client_data.compositor_state; } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index d653405..ff37bf4 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -17,7 +17,7 @@ use crate::wayland::xwayland_rootful::start_xwayland; #[cfg(feature = "xwayland_rootless")] pub mod xwayland_rootless; #[cfg(feature = "xwayland_rootless")] -use self::xwayland_rootless::XWaylandState; +use crate::wayland::xwayland_rootless::start_xwayland; use self::{state::WaylandState, surface::CORE_SURFACES}; use crate::{core::task, wayland::state::ClientState}; @@ -101,7 +101,7 @@ pub struct Wayland { #[cfg(feature = "xwayland_rootful")] pub x_lock: X11Lock, #[cfg(feature = "xwayland_rootless")] - pub xwayland_state: XWaylandState, + xwayland_join_handle: JoinHandle>, } impl Wayland { pub fn new() -> Result { @@ -120,9 +120,7 @@ impl Wayland { let (dmabuf_tx, dmabuf_rx) = mpsc::unbounded_channel(); let display = Arc::new(DisplayWrapper(Mutex::new(display), display_handle.clone())); - #[cfg(feature = "xwayland_rootless")] - let xwayland_state = XWaylandState::create(&display_handle)?; - let wayland_state = WaylandState::new(display_handle, &renderer, dmabuf_tx); + let wayland_state = WaylandState::new(display_handle.clone(), &renderer, dmabuf_tx); let output = wayland_state.lock().output.clone(); let socket = ListeningSocket::bind_auto("wayland", 0..33)?; @@ -138,6 +136,9 @@ impl Wayland { info!(socket_name, "Wayland active"); let join_handle = Wayland::start_loop(display.clone(), socket, wayland_state)?; + #[cfg(feature = "xwayland_rootless")] + let xwayland_join_handle = task::new(|| "xwayland", start_xwayland(display_handle))?; + Ok(Wayland { display, socket_name, @@ -148,7 +149,7 @@ impl Wayland { #[cfg(feature = "xwayland_rootful")] x_lock: x_display, #[cfg(feature = "xwayland_rootless")] - xwayland_state, + xwayland_join_handle, }) } @@ -226,5 +227,7 @@ impl Wayland { impl Drop for Wayland { fn drop(&mut self) { self.join_handle.abort(); + #[cfg(feature = "xwayland_rootless")] + self.xwayland_join_handle.abort(); } } diff --git a/src/wayland/xwayland_rootless.rs b/src/wayland/xwayland_rootless.rs index 28316ae..00e6a54 100644 --- a/src/wayland/xwayland_rootless.rs +++ b/src/wayland/xwayland_rootless.rs @@ -1,430 +1,29 @@ -use super::{ - seat::{KeyboardEvent, PointerEvent, SeatData}, - X_DISPLAY, -}; -use crate::{ - nodes::{ - data::KEYMAPS, - drawable::model::ModelPart, - items::panel::{Backend, Geometry, PanelItem, PanelItemInitData, SurfaceID, ToplevelInfo}, - }, - wayland::surface::CoreSurface, -}; use color_eyre::eyre::Result; -use mint::Vector2; -use once_cell::sync::OnceCell; -use parking_lot::Mutex; -use rustc_hash::FxHashMap; -use smithay::{ - reexports::{ - calloop::{EventLoop, LoopSignal}, - wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource}, - x11rb::protocol::xproto::Window, - }, - utils::{Logical, Rectangle}, - wayland::compositor, - xwayland::{ - xwm::{Reorder, ResizeEdge, XwmId}, - X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler, - }, -}; -use std::{ffi::OsStr, iter::empty, sync::Arc, time::Duration}; -use tokio::sync::oneshot; -use tracing::debug; +use smithay::{reexports::wayland_server::DisplayHandle, xwayland::XWayland}; +use std::{process::Stdio, time::Duration}; +use tokio::io::unix::AsyncFd; -pub struct XWaylandState { - pub display: u32, - event_loop_signal: LoopSignal, -} -impl XWaylandState { - pub fn create(dh: &DisplayHandle) -> Result { - let dh = dh.clone(); - - let (tx, rx) = oneshot::channel(); - - std::thread::spawn(move || { - let mut event_loop: EventLoop = EventLoop::try_new()?; - let (xwayland, connection) = XWayland::new(&dh); - let handle = event_loop.handle(); - event_loop - .handle() - .insert_source(connection, { - let dh = dh.clone(); - move |event, _, handler| match event { - XWaylandEvent::Ready { - connection, - client, - client_fd: _, - display: _, - } => { - handler.seat.client.set(client.id()).unwrap(); - handler - .wm - .set( - X11Wm::start_wm(handle.clone(), dh.clone(), connection, client) - .unwrap(), - ) - .unwrap(); - } - XWaylandEvent::Exited => (), - } - }) - .map_err(|e| e.error)?; - - let display = xwayland.start( - event_loop.handle(), - None, - empty::<(&OsStr, &OsStr)>(), - true, - |_| (), - )?; - let _ = tx.send(XWaylandState { - display, - event_loop_signal: event_loop.get_signal(), - }); - let mut handler = XWaylandHandler { - wm: OnceCell::new(), - seat: SeatData::new(&dh), - wayland_display_handle: dh, - }; - event_loop.run(Duration::from_millis(100), &mut handler, |_| ()) - }); - - let state = rx.blocking_recv()?; - let _ = X_DISPLAY.set(state.display); - - Ok(state) - } -} -impl Drop for XWaylandState { - fn drop(&mut self) { - self.event_loop_signal.stop(); - } -} - -struct XWaylandHandler { - wayland_display_handle: DisplayHandle, - wm: OnceCell, - seat: Arc, -} -impl XWaylandHandler { - fn panel_item(&self, window: &X11Surface) -> Option>> { - compositor::with_states(&window.wl_surface()?, |s| { - s.data_map.get::>>().cloned() - }) - } -} - -impl XwmHandler for XWaylandHandler { - fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm { - self.wm.get_mut().unwrap() - } - - fn new_window(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "New X window"); - } - - fn new_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "New X override redirect window"); - } - - fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "X map window request"); - window.set_mapped(true).unwrap(); - } - fn map_window_notify(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "X map window notify"); - - let _ = window.set_maximized(true); - - let dh = self.wayland_display_handle.clone(); - let seat = self.seat.clone(); - CoreSurface::add_to( - self.wayland_display_handle.clone(), - &window.wl_surface().unwrap(), - { - let window = window.clone(); - move || { - let Some(wl_surface) = window.wl_surface() else { - return; - }; - let seat = seat.clone(); - window.user_data().insert_if_missing_threadsafe(|| { - let panel_item = PanelItem::create( - Box::new(X11Backend { - toplevel_parent: None, - toplevel: window.clone(), - seat, - _pointer_grab: Mutex::new(None), - _keyboard_grab: Mutex::new(None), - }), - wl_surface - .client() - .and_then(|c| c.get_credentials(&dh).ok()) - .map(|c| c.pid), - ); - panel_item - }); - } - }, - move |_| { - let Some(panel_item) = window.user_data().get::>>() - else { - return; - }; - panel_item.toplevel_size_changed( - [ - window.geometry().size.w as u32, - window.geometry().size.h as u32, - ] - .into(), - ); - }, - ); - } - fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "X map override redirect window"); - } - - fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "Unmap X window"); - if let Some(panel_item) = window.user_data().get::>>() { - panel_item.drop_toplevel(); - } - } - fn destroyed_window(&mut self, _xwm: XwmId, window: X11Surface) { - debug!(?window, "Destroy X window"); - } - - fn configure_request( - &mut self, - _xwm: XwmId, - window: X11Surface, - x: Option, - y: Option, - w: Option, - h: Option, - reorder: Option, - ) { - debug!(?window, x, y, w, h, ?reorder, "Configure X window"); - } - - fn configure_notify( - &mut self, - _xwm: XwmId, - window: X11Surface, - geometry: Rectangle, - above: Option, - ) { - debug!(?window, ?geometry, above, "Configure X window"); - } - - fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) { - let Some(panel_item) = self.panel_item(&window) else { - return; - }; - debug!(?window, button, "X window requests move"); - panel_item.toplevel_move_request(); - } - fn resize_request( - &mut self, - _xwm: XwmId, - window: X11Surface, - button: u32, - resize_edge: ResizeEdge, - ) { - let Some(panel_item) = self.panel_item(&window) else { - return; - }; - debug!(?window, button, ?resize_edge, "X window requests resize"); - let (up, down, left, right) = match resize_edge { - ResizeEdge::Top => (true, false, false, false), - ResizeEdge::Bottom => (false, true, false, false), - ResizeEdge::Left => (false, false, true, false), - ResizeEdge::TopLeft => (true, false, true, false), - ResizeEdge::BottomLeft => (false, true, true, false), - ResizeEdge::Right => (false, false, false, true), - ResizeEdge::TopRight => (true, false, false, true), - ResizeEdge::BottomRight => (false, true, false, true), - // _ => (false, false, false, false), - }; - panel_item.toplevel_resize_request(up, down, left, right) - } - - fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) { - let _ = window.set_fullscreen(true); - let Some(panel_item) = self.panel_item(&window) else { - return; - }; - panel_item.toplevel_fullscreen_active(true); - } - fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) { - let _ = window.set_fullscreen(false); - let Some(panel_item) = self.panel_item(&window) else { - return; - }; - panel_item.toplevel_fullscreen_active(true); - } -} - -pub struct X11Backend { - pub toplevel_parent: Option, - pub toplevel: X11Surface, - pub seat: Arc, - _pointer_grab: Mutex>, - _keyboard_grab: Mutex>, -} -impl X11Backend { - fn wl_surface_from_id(&self, id: &SurfaceID) -> Option { - match id { - SurfaceID::Cursor => None, - SurfaceID::Toplevel => self.toplevel.wl_surface(), - SurfaceID::Child(_) => None, - } - } - - // fn flush_client(&self) { - // let Some(client) = self.toplevel.wl_surface().and_then(|s| s.client()) else {return}; - // if let Some(client_state) = client.get_data::() { - // client_state.flush(); - // } - // } -} -impl Backend for X11Backend { - fn start_data(&self) -> Result { - Ok(PanelItemInitData { - cursor: None, - toplevel: ToplevelInfo { - parent: None, - title: Some(self.toplevel.title()), - app_id: Some(self.toplevel.instance()), - size: [ - self.toplevel.geometry().size.w as u32, - self.toplevel.geometry().size.h as u32, - ] - .into(), - min_size: self - .toplevel - .min_size() - .map(|s| [s.w as u32, s.h as u32].into()), - max_size: self - .toplevel - .max_size() - .map(|s| [s.w as u32, s.h as u32].into()), - logical_rectangle: Geometry { - origin: [0, 0].into(), - size: [ - self.toplevel.geometry().size.w as u32, - self.toplevel.geometry().size.h as u32, - ] - .into(), - }, - }, - children: FxHashMap::default(), - pointer_grab: self._pointer_grab.lock().clone(), - keyboard_grab: self._keyboard_grab.lock().clone(), - }) - } - fn close_toplevel(&self) { - let _ = self.toplevel.close(); - } - - fn auto_size_toplevel(&self) { - let _ = self.toplevel.configure(None); - } - fn set_toplevel_size(&self, size: Vector2) { - let _ = self.toplevel.configure(Some(Rectangle { - loc: self.toplevel.geometry().loc, - size: (size.x as i32, size.y as i32).into(), - })); - } - fn set_toplevel_focused_visuals(&self, focused: bool) { - let _ = self.toplevel.set_activated(focused); - } +use super::X_DISPLAY; - fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc) { - let Some(wl_surface) = self.wl_surface_from_id(&surface) else { - return; - }; - let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else { - return; - }; +pub async fn start_xwayland(dh: DisplayHandle) -> Result<()> { + let (mut xwayland, client) = XWayland::spawn( + &dh, + None, + std::iter::empty::<(String, String)>(), + true, + Stdio::null(), + Stdio::null(), + |_| (), + )?; - core_surface.apply_material(model_part); - } + // just wait until it's readable + drop(AsyncFd::new(xwayland.poll_fd())?.readable().await?); + let wm_socket = xwayland.take_socket()?.unwrap(); - fn pointer_motion(&self, surface: &SurfaceID, position: Vector2) { - let Some(surface) = self.wl_surface_from_id(surface) else { - return; - }; - self.seat - .pointer_event(&surface, PointerEvent::Motion(position)); - } - fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool) { - let Some(surface) = self.wl_surface_from_id(surface) else { - return; - }; - self.seat.pointer_event( - &surface, - PointerEvent::Button { - button, - state: if pressed { 1 } else { 0 }, - }, - ) - } - fn pointer_scroll( - &self, - surface: &SurfaceID, - scroll_distance: Option>, - scroll_steps: Option>, - ) { - let Some(surface) = self.wl_surface_from_id(surface) else { - return; - }; - self.seat.pointer_event( - &surface, - PointerEvent::Scroll { - axis_continuous: scroll_distance, - axis_discrete: scroll_steps, - }, - ) - } + let _ = X_DISPLAY.set(xwayland.display_number()); - fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec) { - let Some(surface) = self.wl_surface_from_id(surface) else { - return; - }; - let keymaps = KEYMAPS.lock(); - let Some(keymap) = keymaps.get(keymap_id).cloned() else { - return; - }; - if self.seat.set_keymap(keymap, vec![surface.clone()]).is_err() { - return; - } - for key in keys { - self.seat.keyboard_event( - &surface, - KeyboardEvent::Key { - key: key.abs() as u32, - state: key < 0, - }, - ); - } - } + println!("yippeee x is available at :{}", xwayland.display_number()); - fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2) { - let Some(surface) = self.wl_surface_from_id(surface) else { - return; - }; - self.seat.touch_down(&surface, id, position) - } - fn touch_move(&self, id: u32, position: Vector2) { - self.seat.touch_move(id, position) - } - fn touch_up(&self, id: u32) { - self.seat.touch_up(id) - } - fn reset_touches(&self) { - self.seat.reset_touches() - } + tokio::time::sleep(Duration::from_secs(100000000000)).await; + Ok(()) }