diff --git a/Cargo.lock b/Cargo.lock index 25fbfb6..5ea3fc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,9 +299,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "calloop" -version = "0.12.2" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aadd183e815348c0649051b1c43418643208f8ed13c8a84da7215b4e1cf42714" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ "bitflags 2.4.0", "log", @@ -591,7 +591,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.8.0", + "libloading 0.7.4", ] [[package]] @@ -2025,7 +2025,7 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/smithay/smithay.git#91e61f13501f21d66803efac947bfafed43080c5" +source = "git+https://github.com/smithay/smithay.git#8287457195cf6a495331f65f5e0119f931ff7e79" dependencies = [ "appendlist", "bitflags 2.4.0", @@ -2627,9 +2627,9 @@ dependencies = [ [[package]] name = "wayland-protocols" -version = "0.31.0" +version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e253d7107ba913923dc253967f35e8561a3c65f914543e46843c88ddd729e21c" +checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ "bitflags 2.4.0", "wayland-backend", diff --git a/src/nodes/items/panel.rs b/src/nodes/items/panel.rs index e31edbd..8d519da 100644 --- a/src/nodes/items/panel.rs +++ b/src/nodes/items/panel.rs @@ -177,6 +177,7 @@ pub struct PanelItemInitData { pub trait Backend: Send + Sync + 'static { fn start_data(&self) -> Result; + fn surface_alive(&self, surface: &SurfaceID) -> bool; fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc); @@ -542,6 +543,9 @@ impl Backend for PanelItem { fn start_data(&self) -> Result { self.backend.start_data() } + fn surface_alive(&self, surface: &SurfaceID) -> bool { + self.backend.surface_alive(surface) + } fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc) { self.backend.apply_surface_material(surface, model_part) diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index ea6fc7c..361d511 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -20,7 +20,6 @@ pub mod xwayland_rootless; use self::xwayland_rootless::XWaylandState; use self::{state::WaylandState, surface::CORE_SURFACES}; -use crate::wayland::seat::SeatData; use crate::{core::task, wayland::state::ClientState}; use color_eyre::eyre::{ensure, Result}; use global_counter::primitive::exact::CounterU32; @@ -179,10 +178,9 @@ impl Wayland { id: OnceCell::new(), compositor_state: Default::default(), display: Arc::downgrade(&display), - seat: SeatData::new(&dh1) + seat: state.lock().seat.clone(), }); - let client = dh2.insert_client(stream.into_std()?, client_state.clone())?; - let _ = client_state.seat.client.set(client.id()); + let _client = dh2.insert_client(stream.into_std()?, client_state.clone())?; } e = dispatch_poll_listener.readable() => { // Dispatch let mut guard = e?; diff --git a/src/wayland/seat.rs b/src/wayland/seat.rs index 6f255c9..7b02b05 100644 --- a/src/wayland/seat.rs +++ b/src/wayland/seat.rs @@ -1,606 +1,277 @@ -use super::{ - state::{ClientState, WaylandState}, - surface::CoreSurface, - SERIAL_COUNTER, -}; +use super::{state::WaylandState, surface::CoreSurface}; use crate::{ core::task, - nodes::items::panel::{Backend, Geometry, PanelItem}, + nodes::{ + data::KEYMAPS, + items::panel::{Backend, Geometry, PanelItem}, + }, }; -use color_eyre::eyre::{bail, eyre, Result}; use mint::Vector2; -use nanoid::nanoid; -use once_cell::sync::OnceCell; use parking_lot::Mutex; -use rand::{seq::IteratorRandom, thread_rng}; -use rustc_hash::{FxHashMap, FxHashSet}; +use rustc_hash::FxHashMap; use smithay::{ - input::keyboard::{KeymapFile, ModifiersState}, - reexports::wayland_server::{ - backend::{ClientId, GlobalId, ObjectId}, - protocol::{ - wl_keyboard::{self, KeyState, WlKeyboard}, - wl_pointer::{self, Axis, ButtonState, WlPointer}, - wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE}, - wl_surface::WlSurface, - wl_touch::{self, WlTouch}, - }, - Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak as WlWeak, + backend::input::{AxisRelativeDirection, ButtonState, KeyState}, + delegate_seat, + input::{ + keyboard::{FilterResult, LedState}, + pointer::{AxisFrame, ButtonEvent, CursorImageStatus, MotionEvent}, + touch::{self, DownEvent, UpEvent}, + Seat, SeatHandler, }, + reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak as WlWeak}, + utils::SERIAL_COUNTER, wayland::compositor, }; -use std::{ - collections::VecDeque, - sync::Arc, - time::{Duration, Instant}, -}; +use std::sync::{Arc, Weak}; use tokio::sync::watch; -use tracing::{debug, warn}; -use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keycode, Keymap}; + +impl SeatHandler for WaylandState { + type PointerFocus = WlSurface; + type KeyboardFocus = WlSurface; + type TouchFocus = WlSurface; + + fn seat_state(&mut self) -> &mut smithay::input::SeatState { + &mut self.seat_state + } + fn focus_changed(&mut self, _seat: &Seat, _focused: Option<&Self::KeyboardFocus>) {} + fn cursor_image(&mut self, _seat: &Seat, image: CursorImageStatus) { + self.seat.cursor_info_tx.send_modify(|c| match image { + CursorImageStatus::Hidden => c.surface = None, + CursorImageStatus::Surface(surface) => { + CoreSurface::add_to(self.display_handle.clone(), &surface, || (), |_| ()); + compositor::with_states(&surface, |data| { + if let Some(core_surface) = data.data_map.get::>() { + core_surface.set_material_offset(1); + } + }); + c.surface = Some(surface.downgrade()) + } + _ => (), + }); + } + fn led_state_changed(&mut self, _seat: &Seat, _led_state: LedState) {} +} +delegate_seat!(WaylandState); pub fn handle_cursor( panel_item: &Arc>, - mut cursor: watch::Receiver>, + mut cursor: watch::Receiver, ) { let panel_item_weak = Arc::downgrade(panel_item); let _ = task::new(|| "cursor handler", async move { while cursor.changed().await.is_ok() { - let Some(panel_item) = panel_item_weak.upgrade() else {continue}; + let Some(panel_item) = panel_item_weak.upgrade() else { + continue; + }; let cursor_info = cursor.borrow(); - panel_item.set_cursor(cursor_info.as_ref().and_then(CursorInfo::cursor_data)); + panel_item.set_cursor(cursor_info.cursor_data()); } }); } - -pub struct KeyboardInfo { - keymap_string: String, - keymap: KeymapFile, - state: xkb::State, - mods: ModifiersState, - keys: FxHashSet, -} -impl KeyboardInfo { - pub fn new(keymap_string: String, keymap: &Keymap) -> Self { - KeyboardInfo { - keymap_string, - state: xkb::State::new(keymap), - keymap: KeymapFile::new(keymap), - mods: ModifiersState::default(), - keys: FxHashSet::default(), - } - } - pub fn process(&mut self, key: u32, pressed: bool, keyboard: &WlKeyboard) -> Result { - let xkb_key_state = if pressed { - xkb::KeyDirection::Down - } else { - xkb::KeyDirection::Up - }; - let state_components = self.state.update_key(Keycode::new(key + 8), xkb_key_state); - if state_components != 0 { - self.mods.update_with(&self.state); - keyboard.modifiers( - 0, - self.mods.serialized.depressed, - self.mods.serialized.latched, - self.mods.serialized.locked, - 0, - ); - } - // if pressed { - // println!("Key {key} is being pressed with {state_components} modifiers"); - // } else { - // println!("Key {key} is being released with {state_components} modifiers"); - // } - - let wl_key_state = if pressed { - KeyState::Pressed - } else { - KeyState::Released - }; - keyboard.key(SERIAL_COUNTER.inc(), 0, key, wl_key_state); - match wl_key_state { - KeyState::Pressed => { - self.keys.insert(key); - } - KeyState::Released => { - self.keys.remove(&key); - } - _ => unimplemented!(), - } - Ok(self.keys.len()) - } -} -unsafe impl Send for KeyboardInfo {} - -#[derive(Debug, Clone, Copy)] -pub enum PointerEvent { - Motion(Vector2), - Button { - button: u32, - state: u32, - }, - Scroll { - axis_continuous: Option>, - axis_discrete: Option>, - }, -} -#[derive(Debug, Clone)] -pub enum KeyboardEvent { - Keymap, - Key { key: u32, state: bool }, -} - -const POINTER_EVENT_TIMEOUT: Duration = Duration::from_millis(50); -struct SurfaceInfo { - wl_surface: WlWeak, - cursor_sender: watch::Sender>, - pointer_queue: VecDeque, - pointer_latest_event: Instant, - keyboard_queue: VecDeque, - keyboard_info: Option, +pub struct CursorInfo { + pub surface: Option>, + pub hotspot_x: i32, + pub hotspot_y: i32, } -impl SurfaceInfo { - fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender>) -> Self { - SurfaceInfo { - wl_surface: wl_surface.downgrade(), - cursor_sender, - pointer_queue: VecDeque::new(), - pointer_latest_event: Instant::now(), - keyboard_queue: VecDeque::new(), - keyboard_info: None, - } - } - fn flush(&self) { - if let Some(client) = self.wl_surface.upgrade().ok().and_then(|s| s.client()) { - if let Some(client_data) = client.get_data::() { - client_data.flush(); - } - } - } - fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool { - let Ok(focus) = self.wl_surface.upgrade() else { return false; }; - let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; }; - let Some(focus_size) = core_surface.size() else { return false; }; - - if !self.pointer_queue.is_empty() { - self.pointer_latest_event = Instant::now(); - } - while let Some(event) = self.pointer_queue.pop_front() { - match (locked, event) { - (false, PointerEvent::Motion(pos)) => { - pointer.enter( - SERIAL_COUNTER.inc(), - &focus, - (pos.x as f64).clamp(0.0, focus_size.x as f64), - (pos.y as f64).clamp(0.0, focus_size.y as f64), - ); - locked = true; - } - (true, PointerEvent::Motion(pos)) => { - pointer.motion( - 0, - (pos.x as f64).clamp(0.0, focus_size.x as f64), - (pos.y as f64).clamp(0.0, focus_size.y as f64), - ); - if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { - pointer.frame(); - } - } - (true, PointerEvent::Button { button, state }) => { - pointer.button( - 0, - 0, - button, - match state { - 0 => ButtonState::Released, - 1 => ButtonState::Pressed, - _ => continue, - }, - ); - if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { - pointer.frame(); - } - } - ( - true, - PointerEvent::Scroll { - axis_continuous, - axis_discrete, - }, - ) => { - if let Some(axis_continuous) = axis_continuous { - pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x as f64); - pointer.axis(0, Axis::VerticalScroll, -axis_continuous.y as f64); - } - if pointer.version() >= wl_pointer::EVT_AXIS_DISCRETE_SINCE { - if let Some(axis_discrete) = axis_discrete { - pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32); - pointer.axis_discrete(Axis::VerticalScroll, -axis_discrete.y as i32); - } - } - if pointer.version() >= wl_pointer::EVT_AXIS_STOP_SINCE - && axis_discrete.is_none() - && axis_continuous.is_none() - { - pointer.axis_stop(0, Axis::HorizontalScroll); - pointer.axis_stop(0, Axis::VerticalScroll); - } - if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { - pointer.frame(); - } - } - (locked, event) => { - warn!(locked, ?event, "Invalid pointer event!"); - } - } - } - if self.pointer_latest_event.elapsed() > POINTER_EVENT_TIMEOUT { - pointer.leave(SERIAL_COUNTER.inc(), &focus); - locked = false; - } - self.flush(); - - locked - } - fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool { - let Ok(focus) = self.wl_surface.upgrade() else { return false; }; - let Some(info) = self.keyboard_info.as_mut() else { return true; }; - - if !locked { - keyboard.enter(0, &focus, vec![]); - if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE { - keyboard.repeat_info(0, 0); - } - locked = info.keymap.send(keyboard).is_ok(); - } - while let Some(event) = self.keyboard_queue.pop_front() { - debug!(locked, ?event, "Process keyboard event"); - match (locked, event) { - (true, KeyboardEvent::Keymap) => { - let _ = info.keymap.send(keyboard); - } - (true, KeyboardEvent::Key { key, state }) => { - if let Ok(key_count) = info.process(key, state, keyboard) { - if key_count == 0 { - keyboard.leave(SERIAL_COUNTER.inc(), &focus); - return false; - } - } - } - (locked, event) => { - warn!(locked, ?event, "Invalid keyboard event!"); - } - } - } - self.flush(); - locked +impl CursorInfo { + pub fn cursor_data(&self) -> Option { + let cursor_size = + CoreSurface::from_wl_surface(&self.surface.as_ref()?.upgrade().ok()?)?.size()?; + Some(Geometry { + origin: [self.hotspot_x, self.hotspot_y].into(), + size: cursor_size, + }) } } -pub struct SeatData { - pub client: OnceCell, - global_id: OnceCell, - surfaces: Mutex>, - pointer: OnceCell<(WlPointer, Mutex)>, - keyboard: OnceCell<(WlKeyboard, Mutex)>, - touch: OnceCell, - touches: Mutex>, +pub struct SeatWrapper { + wayland_state: Weak>, + cursor_info_tx: watch::Sender, + pub cursor_info_rx: watch::Receiver, + seat: Seat, + touches: Mutex>>, } -impl SeatData { - pub fn new(dh: &DisplayHandle) -> Arc { - let seat_data = Arc::new(SeatData { - client: OnceCell::new(), - global_id: OnceCell::new(), - surfaces: Mutex::new(FxHashMap::default()), - pointer: OnceCell::new(), - keyboard: OnceCell::new(), - touch: OnceCell::new(), - touches: Mutex::new(FxHashMap::default()), +impl SeatWrapper { + pub fn new(wayland_state: Weak>, seat: Seat) -> Self { + let (cursor_info_tx, cursor_info_rx) = watch::channel(CursorInfo { + surface: None, + hotspot_x: 0, + hotspot_y: 0, }); - - let _ = seat_data - .global_id - .set(dh.create_global::(7, seat_data.clone())); - - seat_data - } - - pub fn set_keymap(&self, keymap_str: String, surfaces: Vec) -> Result<()> { - let context = xkb::Context::new(0); - let keymap = - Keymap::new_from_string(&context, keymap_str.clone(), XKB_KEYMAP_FORMAT_TEXT_V1, 0) - .ok_or_else(|| eyre!("Keymap is not valid"))?; - let mut panels = self.surfaces.lock(); - let Some((_, focus)) = self.keyboard.get() else {bail!("Could not get keyboard")}; - for surface in surfaces { - let Some(surface_info) = panels.get_mut(&surface.id()) else {continue}; - if let Some(keyboard_info) = &mut surface_info.keyboard_info { - if &keyboard_info.keymap_string == &keymap_str { - continue; - } - } - surface_info - .keyboard_info - .replace(KeyboardInfo::new(keymap_str.clone(), &keymap)); - - if *focus.lock() == surface.id() { - surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap); - } + SeatWrapper { + wayland_state, + cursor_info_tx, + cursor_info_rx, + seat, + touches: Mutex::new(FxHashMap::default()), } - Ok(()) } - - pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) { - let mut surfaces = self.surfaces.lock(); - let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return}; - surface_info.pointer_queue.push_back(event); - drop(surfaces); - self.handle_pointer_events(); - } - pub fn keyboard_event(&self, surface: &WlSurface, event: KeyboardEvent) { - let mut surfaces = self.surfaces.lock(); - let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return}; - surface_info.keyboard_queue.push_back(event); - drop(surfaces); - self.handle_keyboard_events(); + pub fn pointer_motion(&self, surface: WlSurface, position: Vector2) { + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let Some(pointer) = self.seat.get_pointer() else { + return; + }; + pointer.motion( + &mut state.lock(), + Some((surface, (0, 0).into())), + &MotionEvent { + location: (position.x as f64, position.y as f64).into(), + serial: SERIAL_COUNTER.next_serial(), + time: 0, + }, + ); } - - fn handle_pointer_events(&self) { - let mut surfaces = self.surfaces.lock(); - let Some((pointer, pointer_focus)) = self.pointer.get() else {return}; - let mut pointer_focus = pointer_focus.lock(); - - loop { - let locked = !pointer_focus.is_null(); - // Pick a pointer to focus on if there is none - if pointer_focus.is_null() { - *pointer_focus = surfaces - .iter() - .filter(|(_k, v)| !v.pointer_queue.is_empty()) - .map(|(k, _v)| k) - .choose(&mut thread_rng()) - .cloned() - .unwrap_or(ObjectId::null()); - } - if pointer_focus.is_null() { - // If there's still none, guess we're done with pointer events for the time being - break; - } - let Some(surface_info) = surfaces.get_mut(&pointer_focus) else {break}; - if surface_info.handle_pointer_events(pointer, locked) { - // We haven't gotten to a point where we can switch the focus - break; - } else { - *pointer_focus = ObjectId::null(); - } - } + pub fn pointer_button(&self, button: u32, pressed: bool) { + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let Some(pointer) = self.seat.get_pointer() else { + return; + }; + pointer.button( + &mut state.lock(), + &ButtonEvent { + button, + state: if pressed { + ButtonState::Pressed + } else { + ButtonState::Released + }, + serial: SERIAL_COUNTER.next_serial(), + time: 0, + }, + ); } - fn handle_keyboard_events(&self) { - let mut surfaces = self.surfaces.lock(); - let Some((keyboard, keyboard_focus)) = self.keyboard.get() else {return}; - let mut keyboard_focus = keyboard_focus.lock(); - loop { - let locked = !keyboard_focus.is_null(); - // Pick a keyboard to focus on if there is none - if keyboard_focus.is_null() { - *keyboard_focus = surfaces - .iter() - .filter(|(_k, v)| v.keyboard_info.is_some()) - .filter(|(_k, v)| !v.keyboard_queue.is_empty()) - .map(|(k, _v)| k) - .choose(&mut thread_rng()) - .cloned() - .unwrap_or(ObjectId::null()); - } - // If there's still none, guess we're done with keyboard events for the time being - let Some(surface_info) = surfaces.get_mut(&keyboard_focus) else {break}; - if surface_info.handle_keyboard_events(keyboard, locked) { - // We haven't gotten to a point where we can switch the focus - break; - } else { - *keyboard_focus = ObjectId::null(); - } - } + pub fn pointer_scroll( + &self, + scroll_distance: Option>, + scroll_steps: Option>, + ) { + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let mut state = state.lock(); + let Some(pointer) = self.seat.get_pointer() else { + return; + }; + pointer.axis( + &mut state, + AxisFrame { + source: None, + relative_direction: ( + AxisRelativeDirection::Identical, + AxisRelativeDirection::Identical, + ), + time: 0, + axis: scroll_distance + .map(|d| (d.x as f64, d.y as f64)) + .unwrap_or((0.0, 0.0)), + v120: scroll_steps.map(|d| ((d.x * 120.0) as i32, (d.y * 120.0) as i32)), + stop: (false, false), + }, + ) } - pub fn new_surface(&self, surface: &WlSurface) -> watch::Receiver> { - let (tx, rx) = watch::channel(None); - self.surfaces - .lock() - .insert(surface.id(), SurfaceInfo::new(surface, tx)); + pub fn keyboard_keys(&self, surface: WlSurface, keymap_id: &str, keys: Vec) { + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let Some(keyboard) = self.seat.get_keyboard() else { + return; + }; + let keymaps = KEYMAPS.lock(); + let Some(keymap) = keymaps.get(keymap_id).cloned() else { + return; + }; - rx - } - pub fn drop_surface(&self, surface: &WlSurface) { - self.surfaces.lock().remove(&surface.id()); - if let Some((_, pointer_focus)) = self.pointer.get() { - let mut pointer_focus = pointer_focus.lock(); - if *pointer_focus == surface.id() { - *pointer_focus = ObjectId::null(); - } + keyboard.set_focus( + &mut state.lock(), + Some(surface), + SERIAL_COUNTER.next_serial(), + ); + if keyboard + .set_keymap_from_string(&mut state.lock(), keymap) + .is_err() + { + return; } - if let Some((_, keyboard_focus)) = self.keyboard.get() { - let mut keyboard_focus = keyboard_focus.lock(); - if *keyboard_focus == surface.id() { - *keyboard_focus = ObjectId::null(); - } + for key in keys { + keyboard.input( + &mut state.lock(), + key.abs() as u32, + if key > 0 { + KeyState::Pressed + } else { + KeyState::Released + }, + SERIAL_COUNTER.next_serial(), + 0, + |_, _, _| FilterResult::Forward::<()>, + ); } - self.touches.lock().remove(&surface.id()); } - pub fn touch_down(&self, surface: &WlSurface, id: u32, position: Vector2) { - let Some(touch) = self.touch.get() else {return}; + pub fn touch_down(&self, surface: WlSurface, id: u32, position: Vector2) { + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let Some(touch) = self.seat.get_touch() else { + return; + }; touch.down( - SERIAL_COUNTER.inc(), - 0, - surface, - id as i32, - position.x as f64, - position.y as f64, + &mut state.lock(), + Some((surface, (0, 0).into())), + &DownEvent { + slot: Some(id).into(), + location: (position.x as f64, position.y as f64).into(), + serial: SERIAL_COUNTER.next_serial(), + time: 0, + }, ); - self.touches.lock().insert(surface.id(), id); + touch.frame(&mut state.lock()); } pub fn touch_move(&self, id: u32, position: Vector2) { - let Some(touch) = self.touch.get() else {return}; - touch.motion(0, id as i32, position.x as f64, position.y as f64); + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let Some(surface) = self.touches.lock().get(&id).and_then(|c| c.upgrade().ok()) else { + return; + }; + let Some(touch) = self.seat.get_touch() else { + return; + }; + touch.motion( + &mut state.lock(), + Some((surface, (0, 0).into())), + &touch::MotionEvent { + slot: Some(id).into(), + location: (position.x as f64, position.y as f64).into(), + time: 0, + }, + ); + touch.frame(&mut state.lock()); } pub fn touch_up(&self, id: u32) { - let Some(touch) = self.touch.get() else {return}; - touch.up(SERIAL_COUNTER.inc(), 0, id as i32); - let mut touches = self.touches.lock(); - touches.retain(|_, tid| *tid != id); + let Some(state) = self.wayland_state.upgrade() else { + return; + }; + let Some(touch) = self.seat.get_touch() else { + return; + }; + touch.up( + &mut state.lock(), + &UpEvent { + slot: Some(id).into(), + serial: SERIAL_COUNTER.next_serial(), + time: 0, + }, + ); } pub fn reset_touches(&self) { - let Some(touch) = self.touch.get() else {return}; - for (_, touch_id) in self.touches.lock().drain() { - touch.up(SERIAL_COUNTER.inc(), 0, touch_id as i32); - } - } -} - -pub struct CursorInfo { - pub surface: WlWeak, - pub hotspot_x: i32, - pub hotspot_y: i32, -} -impl CursorInfo { - pub fn cursor_data(&self) -> Option { - let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?; - Some(Geometry { - origin: [self.hotspot_x, self.hotspot_y].into(), - size: cursor_size, - }) - } -} - -impl GlobalDispatch, WaylandState> for WaylandState { - fn bind( - _state: &mut WaylandState, - _handle: &DisplayHandle, - _client: &Client, - resource: New, - data: &Arc, - data_init: &mut DataInit<'_, WaylandState>, - ) { - let resource = data_init.init(resource, data.clone()); - - if resource.version() >= EVT_NAME_SINCE { - resource.name(nanoid!()); - } - - resource.capabilities(Capability::Pointer | Capability::Keyboard | Capability::Touch); - } - - fn can_view(client: Client, data: &Arc) -> bool { - let Some(seat_client) = data.client.get().cloned() else {return false}; - client.id() == seat_client - } -} - -impl Dispatch, WaylandState> for WaylandState { - fn request( - _state: &mut WaylandState, - _client: &Client, - _resource: &WlSeat, - request: wl_seat::Request, - data: &Arc, - _dh: &DisplayHandle, - data_init: &mut DataInit<'_, WaylandState>, - ) { - match request { - wl_seat::Request::GetPointer { id } => { - let pointer = data_init.init(id, data.clone()); - let _ = data.pointer.set((pointer, Mutex::new(ObjectId::null()))); - } - wl_seat::Request::GetKeyboard { id } => { - let keyboard = data_init.init(id, data.clone()); - if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE { - keyboard.repeat_info(0, 0); - } - let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null()))); - } - wl_seat::Request::GetTouch { id } => { - let _ = data.touch.set(data_init.init(id, data.clone())); - } - wl_seat::Request::Release => (), - _ => unreachable!(), - } - } -} - -impl Dispatch, WaylandState> for WaylandState { - fn request( - _state: &mut WaylandState, - _client: &Client, - _resource: &WlPointer, - request: wl_pointer::Request, - seat_data: &Arc, - dh: &DisplayHandle, - _data_init: &mut DataInit<'_, WaylandState>, - ) { - match request { - wl_pointer::Request::SetCursor { - serial: _, - surface, - hotspot_x, - hotspot_y, - } => { - if let Some(surface) = surface.as_ref() { - CoreSurface::add_to(dh.clone(), surface, || (), |_| ()); - compositor::with_states(surface, |data| { - if let Some(core_surface) = data.data_map.get::>() { - core_surface.set_material_offset(1); - } - }) - } - - let Some((_, focus)) = seat_data.pointer.get() else {return}; - let focus = focus.lock(); - let surfaces = seat_data.surfaces.lock(); - let Some(surface_info) = surfaces.get(&focus) else {return}; - let cursor_info = surface.map(|surface| CursorInfo { - surface: surface.downgrade(), - hotspot_x, - hotspot_y, - }); - let _ = surface_info.cursor_sender.send_replace(cursor_info); - } - wl_pointer::Request::Release => (), - _ => unreachable!(), - } - } -} - -impl Dispatch, WaylandState> for WaylandState { - fn request( - _state: &mut WaylandState, - _client: &Client, - _resource: &WlKeyboard, - request: ::Request, - _data: &Arc, - _dh: &DisplayHandle, - _data_init: &mut DataInit<'_, WaylandState>, - ) { - match request { - wl_keyboard::Request::Release => (), - _ => unreachable!(), - } - } -} - -impl Dispatch, WaylandState> for WaylandState { - fn request( - _state: &mut WaylandState, - _client: &Client, - _resource: &WlTouch, - request: ::Request, - _data: &Arc, - _dh: &DisplayHandle, - _data_init: &mut DataInit<'_, WaylandState>, - ) { - match request { - wl_touch::Request::Release => (), - _ => unreachable!(), + for id in self.touches.lock().keys() { + self.touch_up(*id) } } } diff --git a/src/wayland/seat_old.rs b/src/wayland/seat_old.rs new file mode 100644 index 0000000..6f255c9 --- /dev/null +++ b/src/wayland/seat_old.rs @@ -0,0 +1,606 @@ +use super::{ + state::{ClientState, WaylandState}, + surface::CoreSurface, + SERIAL_COUNTER, +}; +use crate::{ + core::task, + nodes::items::panel::{Backend, Geometry, PanelItem}, +}; +use color_eyre::eyre::{bail, eyre, Result}; +use mint::Vector2; +use nanoid::nanoid; +use once_cell::sync::OnceCell; +use parking_lot::Mutex; +use rand::{seq::IteratorRandom, thread_rng}; +use rustc_hash::{FxHashMap, FxHashSet}; +use smithay::{ + input::keyboard::{KeymapFile, ModifiersState}, + reexports::wayland_server::{ + backend::{ClientId, GlobalId, ObjectId}, + protocol::{ + wl_keyboard::{self, KeyState, WlKeyboard}, + wl_pointer::{self, Axis, ButtonState, WlPointer}, + wl_seat::{self, Capability, WlSeat, EVT_NAME_SINCE}, + wl_surface::WlSurface, + wl_touch::{self, WlTouch}, + }, + Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak as WlWeak, + }, + wayland::compositor, +}; +use std::{ + collections::VecDeque, + sync::Arc, + time::{Duration, Instant}, +}; +use tokio::sync::watch; +use tracing::{debug, warn}; +use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keycode, Keymap}; + +pub fn handle_cursor( + panel_item: &Arc>, + mut cursor: watch::Receiver>, +) { + let panel_item_weak = Arc::downgrade(panel_item); + let _ = task::new(|| "cursor handler", async move { + while cursor.changed().await.is_ok() { + let Some(panel_item) = panel_item_weak.upgrade() else {continue}; + let cursor_info = cursor.borrow(); + panel_item.set_cursor(cursor_info.as_ref().and_then(CursorInfo::cursor_data)); + } + }); +} + +pub struct KeyboardInfo { + keymap_string: String, + keymap: KeymapFile, + state: xkb::State, + mods: ModifiersState, + keys: FxHashSet, +} +impl KeyboardInfo { + pub fn new(keymap_string: String, keymap: &Keymap) -> Self { + KeyboardInfo { + keymap_string, + state: xkb::State::new(keymap), + keymap: KeymapFile::new(keymap), + mods: ModifiersState::default(), + keys: FxHashSet::default(), + } + } + pub fn process(&mut self, key: u32, pressed: bool, keyboard: &WlKeyboard) -> Result { + let xkb_key_state = if pressed { + xkb::KeyDirection::Down + } else { + xkb::KeyDirection::Up + }; + let state_components = self.state.update_key(Keycode::new(key + 8), xkb_key_state); + if state_components != 0 { + self.mods.update_with(&self.state); + keyboard.modifiers( + 0, + self.mods.serialized.depressed, + self.mods.serialized.latched, + self.mods.serialized.locked, + 0, + ); + } + // if pressed { + // println!("Key {key} is being pressed with {state_components} modifiers"); + // } else { + // println!("Key {key} is being released with {state_components} modifiers"); + // } + + let wl_key_state = if pressed { + KeyState::Pressed + } else { + KeyState::Released + }; + keyboard.key(SERIAL_COUNTER.inc(), 0, key, wl_key_state); + match wl_key_state { + KeyState::Pressed => { + self.keys.insert(key); + } + KeyState::Released => { + self.keys.remove(&key); + } + _ => unimplemented!(), + } + Ok(self.keys.len()) + } +} +unsafe impl Send for KeyboardInfo {} + +#[derive(Debug, Clone, Copy)] +pub enum PointerEvent { + Motion(Vector2), + Button { + button: u32, + state: u32, + }, + Scroll { + axis_continuous: Option>, + axis_discrete: Option>, + }, +} +#[derive(Debug, Clone)] +pub enum KeyboardEvent { + Keymap, + Key { key: u32, state: bool }, +} + +const POINTER_EVENT_TIMEOUT: Duration = Duration::from_millis(50); +struct SurfaceInfo { + wl_surface: WlWeak, + cursor_sender: watch::Sender>, + pointer_queue: VecDeque, + pointer_latest_event: Instant, + keyboard_queue: VecDeque, + keyboard_info: Option, +} +impl SurfaceInfo { + fn new(wl_surface: &WlSurface, cursor_sender: watch::Sender>) -> Self { + SurfaceInfo { + wl_surface: wl_surface.downgrade(), + cursor_sender, + pointer_queue: VecDeque::new(), + pointer_latest_event: Instant::now(), + keyboard_queue: VecDeque::new(), + keyboard_info: None, + } + } + fn flush(&self) { + if let Some(client) = self.wl_surface.upgrade().ok().and_then(|s| s.client()) { + if let Some(client_data) = client.get_data::() { + client_data.flush(); + } + } + } + fn handle_pointer_events(&mut self, pointer: &WlPointer, mut locked: bool) -> bool { + let Ok(focus) = self.wl_surface.upgrade() else { return false; }; + let Some(core_surface) = CoreSurface::from_wl_surface(&focus) else { return false; }; + let Some(focus_size) = core_surface.size() else { return false; }; + + if !self.pointer_queue.is_empty() { + self.pointer_latest_event = Instant::now(); + } + while let Some(event) = self.pointer_queue.pop_front() { + match (locked, event) { + (false, PointerEvent::Motion(pos)) => { + pointer.enter( + SERIAL_COUNTER.inc(), + &focus, + (pos.x as f64).clamp(0.0, focus_size.x as f64), + (pos.y as f64).clamp(0.0, focus_size.y as f64), + ); + locked = true; + } + (true, PointerEvent::Motion(pos)) => { + pointer.motion( + 0, + (pos.x as f64).clamp(0.0, focus_size.x as f64), + (pos.y as f64).clamp(0.0, focus_size.y as f64), + ); + if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { + pointer.frame(); + } + } + (true, PointerEvent::Button { button, state }) => { + pointer.button( + 0, + 0, + button, + match state { + 0 => ButtonState::Released, + 1 => ButtonState::Pressed, + _ => continue, + }, + ); + if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { + pointer.frame(); + } + } + ( + true, + PointerEvent::Scroll { + axis_continuous, + axis_discrete, + }, + ) => { + if let Some(axis_continuous) = axis_continuous { + pointer.axis(0, Axis::HorizontalScroll, axis_continuous.x as f64); + pointer.axis(0, Axis::VerticalScroll, -axis_continuous.y as f64); + } + if pointer.version() >= wl_pointer::EVT_AXIS_DISCRETE_SINCE { + if let Some(axis_discrete) = axis_discrete { + pointer.axis_discrete(Axis::HorizontalScroll, axis_discrete.x as i32); + pointer.axis_discrete(Axis::VerticalScroll, -axis_discrete.y as i32); + } + } + if pointer.version() >= wl_pointer::EVT_AXIS_STOP_SINCE + && axis_discrete.is_none() + && axis_continuous.is_none() + { + pointer.axis_stop(0, Axis::HorizontalScroll); + pointer.axis_stop(0, Axis::VerticalScroll); + } + if pointer.version() >= wl_pointer::EVT_FRAME_SINCE { + pointer.frame(); + } + } + (locked, event) => { + warn!(locked, ?event, "Invalid pointer event!"); + } + } + } + if self.pointer_latest_event.elapsed() > POINTER_EVENT_TIMEOUT { + pointer.leave(SERIAL_COUNTER.inc(), &focus); + locked = false; + } + self.flush(); + + locked + } + fn handle_keyboard_events(&mut self, keyboard: &WlKeyboard, mut locked: bool) -> bool { + let Ok(focus) = self.wl_surface.upgrade() else { return false; }; + let Some(info) = self.keyboard_info.as_mut() else { return true; }; + + if !locked { + keyboard.enter(0, &focus, vec![]); + if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE { + keyboard.repeat_info(0, 0); + } + locked = info.keymap.send(keyboard).is_ok(); + } + while let Some(event) = self.keyboard_queue.pop_front() { + debug!(locked, ?event, "Process keyboard event"); + match (locked, event) { + (true, KeyboardEvent::Keymap) => { + let _ = info.keymap.send(keyboard); + } + (true, KeyboardEvent::Key { key, state }) => { + if let Ok(key_count) = info.process(key, state, keyboard) { + if key_count == 0 { + keyboard.leave(SERIAL_COUNTER.inc(), &focus); + return false; + } + } + } + (locked, event) => { + warn!(locked, ?event, "Invalid keyboard event!"); + } + } + } + self.flush(); + locked + } +} + +pub struct SeatData { + pub client: OnceCell, + global_id: OnceCell, + surfaces: Mutex>, + pointer: OnceCell<(WlPointer, Mutex)>, + keyboard: OnceCell<(WlKeyboard, Mutex)>, + touch: OnceCell, + touches: Mutex>, +} +impl SeatData { + pub fn new(dh: &DisplayHandle) -> Arc { + let seat_data = Arc::new(SeatData { + client: OnceCell::new(), + global_id: OnceCell::new(), + surfaces: Mutex::new(FxHashMap::default()), + pointer: OnceCell::new(), + keyboard: OnceCell::new(), + touch: OnceCell::new(), + touches: Mutex::new(FxHashMap::default()), + }); + + let _ = seat_data + .global_id + .set(dh.create_global::(7, seat_data.clone())); + + seat_data + } + + pub fn set_keymap(&self, keymap_str: String, surfaces: Vec) -> Result<()> { + let context = xkb::Context::new(0); + let keymap = + Keymap::new_from_string(&context, keymap_str.clone(), XKB_KEYMAP_FORMAT_TEXT_V1, 0) + .ok_or_else(|| eyre!("Keymap is not valid"))?; + let mut panels = self.surfaces.lock(); + let Some((_, focus)) = self.keyboard.get() else {bail!("Could not get keyboard")}; + for surface in surfaces { + let Some(surface_info) = panels.get_mut(&surface.id()) else {continue}; + if let Some(keyboard_info) = &mut surface_info.keyboard_info { + if &keyboard_info.keymap_string == &keymap_str { + continue; + } + } + surface_info + .keyboard_info + .replace(KeyboardInfo::new(keymap_str.clone(), &keymap)); + + if *focus.lock() == surface.id() { + surface_info.keyboard_queue.push_back(KeyboardEvent::Keymap); + } + } + Ok(()) + } + + pub fn pointer_event(&self, surface: &WlSurface, event: PointerEvent) { + let mut surfaces = self.surfaces.lock(); + let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return}; + surface_info.pointer_queue.push_back(event); + drop(surfaces); + self.handle_pointer_events(); + } + pub fn keyboard_event(&self, surface: &WlSurface, event: KeyboardEvent) { + let mut surfaces = self.surfaces.lock(); + let Some(surface_info) = surfaces.get_mut(&surface.id()) else {return}; + surface_info.keyboard_queue.push_back(event); + drop(surfaces); + self.handle_keyboard_events(); + } + + fn handle_pointer_events(&self) { + let mut surfaces = self.surfaces.lock(); + let Some((pointer, pointer_focus)) = self.pointer.get() else {return}; + let mut pointer_focus = pointer_focus.lock(); + + loop { + let locked = !pointer_focus.is_null(); + // Pick a pointer to focus on if there is none + if pointer_focus.is_null() { + *pointer_focus = surfaces + .iter() + .filter(|(_k, v)| !v.pointer_queue.is_empty()) + .map(|(k, _v)| k) + .choose(&mut thread_rng()) + .cloned() + .unwrap_or(ObjectId::null()); + } + if pointer_focus.is_null() { + // If there's still none, guess we're done with pointer events for the time being + break; + } + let Some(surface_info) = surfaces.get_mut(&pointer_focus) else {break}; + if surface_info.handle_pointer_events(pointer, locked) { + // We haven't gotten to a point where we can switch the focus + break; + } else { + *pointer_focus = ObjectId::null(); + } + } + } + fn handle_keyboard_events(&self) { + let mut surfaces = self.surfaces.lock(); + let Some((keyboard, keyboard_focus)) = self.keyboard.get() else {return}; + let mut keyboard_focus = keyboard_focus.lock(); + loop { + let locked = !keyboard_focus.is_null(); + // Pick a keyboard to focus on if there is none + if keyboard_focus.is_null() { + *keyboard_focus = surfaces + .iter() + .filter(|(_k, v)| v.keyboard_info.is_some()) + .filter(|(_k, v)| !v.keyboard_queue.is_empty()) + .map(|(k, _v)| k) + .choose(&mut thread_rng()) + .cloned() + .unwrap_or(ObjectId::null()); + } + // If there's still none, guess we're done with keyboard events for the time being + let Some(surface_info) = surfaces.get_mut(&keyboard_focus) else {break}; + if surface_info.handle_keyboard_events(keyboard, locked) { + // We haven't gotten to a point where we can switch the focus + break; + } else { + *keyboard_focus = ObjectId::null(); + } + } + } + + pub fn new_surface(&self, surface: &WlSurface) -> watch::Receiver> { + let (tx, rx) = watch::channel(None); + self.surfaces + .lock() + .insert(surface.id(), SurfaceInfo::new(surface, tx)); + + rx + } + pub fn drop_surface(&self, surface: &WlSurface) { + self.surfaces.lock().remove(&surface.id()); + if let Some((_, pointer_focus)) = self.pointer.get() { + let mut pointer_focus = pointer_focus.lock(); + if *pointer_focus == surface.id() { + *pointer_focus = ObjectId::null(); + } + } + if let Some((_, keyboard_focus)) = self.keyboard.get() { + let mut keyboard_focus = keyboard_focus.lock(); + if *keyboard_focus == surface.id() { + *keyboard_focus = ObjectId::null(); + } + } + self.touches.lock().remove(&surface.id()); + } + + pub fn touch_down(&self, surface: &WlSurface, id: u32, position: Vector2) { + let Some(touch) = self.touch.get() else {return}; + touch.down( + SERIAL_COUNTER.inc(), + 0, + surface, + id as i32, + position.x as f64, + position.y as f64, + ); + self.touches.lock().insert(surface.id(), id); + } + pub fn touch_move(&self, id: u32, position: Vector2) { + let Some(touch) = self.touch.get() else {return}; + touch.motion(0, id as i32, position.x as f64, position.y as f64); + } + pub fn touch_up(&self, id: u32) { + let Some(touch) = self.touch.get() else {return}; + touch.up(SERIAL_COUNTER.inc(), 0, id as i32); + let mut touches = self.touches.lock(); + touches.retain(|_, tid| *tid != id); + } + pub fn reset_touches(&self) { + let Some(touch) = self.touch.get() else {return}; + for (_, touch_id) in self.touches.lock().drain() { + touch.up(SERIAL_COUNTER.inc(), 0, touch_id as i32); + } + } +} + +pub struct CursorInfo { + pub surface: WlWeak, + pub hotspot_x: i32, + pub hotspot_y: i32, +} +impl CursorInfo { + pub fn cursor_data(&self) -> Option { + let cursor_size = CoreSurface::from_wl_surface(&self.surface.upgrade().ok()?)?.size()?; + Some(Geometry { + origin: [self.hotspot_x, self.hotspot_y].into(), + size: cursor_size, + }) + } +} + +impl GlobalDispatch, WaylandState> for WaylandState { + fn bind( + _state: &mut WaylandState, + _handle: &DisplayHandle, + _client: &Client, + resource: New, + data: &Arc, + data_init: &mut DataInit<'_, WaylandState>, + ) { + let resource = data_init.init(resource, data.clone()); + + if resource.version() >= EVT_NAME_SINCE { + resource.name(nanoid!()); + } + + resource.capabilities(Capability::Pointer | Capability::Keyboard | Capability::Touch); + } + + fn can_view(client: Client, data: &Arc) -> bool { + let Some(seat_client) = data.client.get().cloned() else {return false}; + client.id() == seat_client + } +} + +impl Dispatch, WaylandState> for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &WlSeat, + request: wl_seat::Request, + data: &Arc, + _dh: &DisplayHandle, + data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + wl_seat::Request::GetPointer { id } => { + let pointer = data_init.init(id, data.clone()); + let _ = data.pointer.set((pointer, Mutex::new(ObjectId::null()))); + } + wl_seat::Request::GetKeyboard { id } => { + let keyboard = data_init.init(id, data.clone()); + if keyboard.version() >= wl_keyboard::EVT_REPEAT_INFO_SINCE { + keyboard.repeat_info(0, 0); + } + let _ = data.keyboard.set((keyboard, Mutex::new(ObjectId::null()))); + } + wl_seat::Request::GetTouch { id } => { + let _ = data.touch.set(data_init.init(id, data.clone())); + } + wl_seat::Request::Release => (), + _ => unreachable!(), + } + } +} + +impl Dispatch, WaylandState> for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &WlPointer, + request: wl_pointer::Request, + seat_data: &Arc, + dh: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + wl_pointer::Request::SetCursor { + serial: _, + surface, + hotspot_x, + hotspot_y, + } => { + if let Some(surface) = surface.as_ref() { + CoreSurface::add_to(dh.clone(), surface, || (), |_| ()); + compositor::with_states(surface, |data| { + if let Some(core_surface) = data.data_map.get::>() { + core_surface.set_material_offset(1); + } + }) + } + + let Some((_, focus)) = seat_data.pointer.get() else {return}; + let focus = focus.lock(); + let surfaces = seat_data.surfaces.lock(); + let Some(surface_info) = surfaces.get(&focus) else {return}; + let cursor_info = surface.map(|surface| CursorInfo { + surface: surface.downgrade(), + hotspot_x, + hotspot_y, + }); + let _ = surface_info.cursor_sender.send_replace(cursor_info); + } + wl_pointer::Request::Release => (), + _ => unreachable!(), + } + } +} + +impl Dispatch, WaylandState> for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &WlKeyboard, + request: ::Request, + _data: &Arc, + _dh: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + wl_keyboard::Request::Release => (), + _ => unreachable!(), + } + } +} + +impl Dispatch, WaylandState> for WaylandState { + fn request( + _state: &mut WaylandState, + _client: &Client, + _resource: &WlTouch, + request: ::Request, + _data: &Arc, + _dh: &DisplayHandle, + _data_init: &mut DataInit<'_, WaylandState>, + ) { + match request { + wl_touch::Request::Release => (), + _ => unreachable!(), + } + } +} diff --git a/src/wayland/state.rs b/src/wayland/state.rs index e24f70d..77a8a31 100644 --- a/src/wayland/state.rs +++ b/src/wayland/state.rs @@ -1,5 +1,5 @@ -use super::DisplayWrapper; -use crate::wayland::{drm::wl_drm::WlDrm, seat::SeatData}; +use super::{seat::SeatWrapper, DisplayWrapper}; +use crate::wayland::drm::wl_drm::WlDrm; use once_cell::sync::OnceCell; use parking_lot::Mutex; use smithay::{ @@ -9,6 +9,7 @@ use smithay::{ renderer::gles::GlesRenderer, }, delegate_dmabuf, delegate_output, delegate_shm, + input::{keyboard::XkbConfig, SeatState}, output::{Mode, Output, Scale, Subpixel}, reexports::{ wayland_protocols::xdg::{ @@ -45,7 +46,7 @@ pub struct ClientState { pub id: OnceCell, pub compositor_state: CompositorClientState, pub display: Weak, - pub seat: Arc, + pub seat: Arc, } impl ClientState { pub fn flush(&self) { @@ -80,6 +81,8 @@ pub struct WaylandState { dmabuf_state: (DmabufState, DmabufGlobal, Option), pub drm_formats: Vec, pub dmabuf_tx: UnboundedSender<(Dmabuf, Option)>, + pub seat_state: SeatState, + pub seat: Arc, pub output: Output, } @@ -133,6 +136,12 @@ impl WaylandState { (dmabuf_state, dmabuf_global, None) }; + let mut seat_state = SeatState::new(); + let mut seat = seat_state.new_wl_seat(&display_handle, "seat0"); + seat.add_pointer(); + seat.add_keyboard(XkbConfig::default(), 200, 25).unwrap(); + seat.add_touch(); + let output = Output::new( "1x".to_owned(), smithay::output::PhysicalProperties { @@ -173,6 +182,8 @@ impl WaylandState { drm_formats, dmabuf_state, dmabuf_tx, + seat_state, + seat: Arc::new(SeatWrapper::new(weak.clone(), seat)), output, }) }) diff --git a/src/wayland/xdg_shell/backend.rs b/src/wayland/xdg_shell/backend.rs index cd324d7..c4ed0dc 100644 --- a/src/wayland/xdg_shell/backend.rs +++ b/src/wayland/xdg_shell/backend.rs @@ -1,16 +1,10 @@ use super::{popup::PopupData, surface::XdgSurfaceData, ToplevelData}; use crate::{ nodes::{ - data::KEYMAPS, drawable::model::ModelPart, items::panel::{Backend, ChildInfo, PanelItem, PanelItemInitData, SurfaceID}, }, - wayland::{ - seat::{CursorInfo, KeyboardEvent, PointerEvent, SeatData}, - state::ClientState, - surface::CoreSurface, - utils, SERIAL_COUNTER, - }, + wayland::{seat::SeatWrapper, state::ClientState, surface::CoreSurface, utils, SERIAL_COUNTER}, }; use color_eyre::eyre::{eyre, Result}; use mint::Vector2; @@ -18,10 +12,9 @@ use parking_lot::Mutex; use rustc_hash::FxHashMap; use smithay::reexports::{ wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel, - wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak}, + wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak as WlWeak}, }; use std::sync::Arc; -use tokio::sync::watch; use tracing::debug; pub struct XdgToplevelState { @@ -30,22 +23,18 @@ pub struct XdgToplevelState { } pub struct XdgBackend { - toplevel: Weak, - toplevel_wl_surface: Weak, + toplevel: WlWeak, + toplevel_wl_surface: WlWeak, pub toplevel_state: Mutex, - popups: Mutex>>, - pub cursor: watch::Receiver>, - pub seat: Arc, - pointer_grab: Mutex>, - keyboard_grab: Mutex>, + popups: Mutex>>, + pub seat: Arc, } impl XdgBackend { pub fn create( toplevel_wl_surface: WlSurface, toplevel: XdgToplevel, - seat: Arc, + seat: Arc, ) -> Self { - let cursor = seat.new_surface(&toplevel_wl_surface); XdgBackend { toplevel: toplevel.downgrade(), toplevel_wl_surface: toplevel_wl_surface.downgrade(), @@ -54,15 +43,19 @@ impl XdgBackend { activated: false, }), popups: Mutex::new(FxHashMap::default()), - cursor, seat, - pointer_grab: Mutex::new(None), - keyboard_grab: Mutex::new(None), } } fn wl_surface_from_id(&self, id: &SurfaceID) -> Option { match id { - SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(), + SurfaceID::Cursor => self + .seat + .cursor_info_rx + .borrow() + .surface + .clone()? + .upgrade() + .ok(), SurfaceID::Toplevel => self.toplevel_wl_surface(), SurfaceID::Child(popup) => { let popups = self.popups.lock(); @@ -146,13 +139,6 @@ impl XdgBackend { } pub fn drop_popup(&self, panel_item: &PanelItem, uid: &str) { panel_item.drop_child(uid); - let Some(popup) = self.popups.lock().remove(uid) else { - return; - }; - let Some(wl_surface) = popup.upgrade().ok() else { - return; - }; - self.seat.drop_surface(&wl_surface); } fn child_data(&self) -> FxHashMap { @@ -193,17 +179,21 @@ impl Backend for XdgBackend { .clone() .ok_or_else(|| eyre!("Could not get toplevel"))?; - let pointer_grab = self.pointer_grab.lock().clone(); - let keyboard_grab = self.keyboard_grab.lock().clone(); - Ok(PanelItemInitData { - cursor: self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()), + cursor: (*self.seat.cursor_info_rx.borrow()).cursor_data(), toplevel: toplevel_data.into(), children: self.child_data(), - pointer_grab, - keyboard_grab, + pointer_grab: None, + keyboard_grab: None, }) } + fn surface_alive(&self, surface: &SurfaceID) -> bool { + match surface { + SurfaceID::Cursor => true, + SurfaceID::Toplevel => true, + SurfaceID::Child(c) => self.popups.lock().contains_key(c), + } + } fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc) { let Some(wl_surface) = self.wl_surface_from_id(&surface) else { @@ -237,66 +227,32 @@ impl Backend for XdgBackend { let Some(surface) = self.wl_surface_from_id(surface) else { return; }; - self.seat - .pointer_event(&surface, PointerEvent::Motion(position)); + self.seat.pointer_motion(surface, 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_button(&self, _surface: &SurfaceID, button: u32, pressed: bool) { + self.seat.pointer_button(button, pressed) } fn pointer_scroll( &self, - surface: &SurfaceID, + _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, - }, - ) + self.seat.pointer_scroll(scroll_distance, scroll_steps) } 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, - }, - ); - } + self.seat.keyboard_keys(surface, keymap_id, keys) } 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) + self.seat.touch_down(surface, id, position) } fn touch_move(&self, id: u32, position: Vector2) { self.seat.touch_move(id, position) diff --git a/src/wayland/xdg_shell/surface.rs b/src/wayland/xdg_shell/surface.rs index 6cfde1c..937c2d5 100644 --- a/src/wayland/xdg_shell/surface.rs +++ b/src/wayland/xdg_shell/surface.rs @@ -14,7 +14,7 @@ use parking_lot::Mutex; use smithay::reexports::{ wayland_protocols::xdg::shell::server::{ xdg_surface::{self, XdgSurface}, - xdg_toplevel::{XdgToplevel, EVT_WM_CAPABILITIES_SINCE}, + xdg_toplevel::{WmCapabilities, XdgToplevel, EVT_WM_CAPABILITIES_SINCE}, }, wayland_server::{ protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, Resource, @@ -58,7 +58,13 @@ impl Dispatch, WaylandState> for WaylandState { debug!(?toplevel, ?xdg_surface, "Create XDG toplevel"); if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE { - toplevel.wm_capabilities(vec![3]); + toplevel.wm_capabilities( + vec![WmCapabilities::Maximize, WmCapabilities::Fullscreen] + .into_iter() + .map(u32::from) + .flat_map(u32::to_ne_bytes) + .collect(), + ); } toplevel.configure( 0, @@ -69,7 +75,7 @@ impl Dispatch, WaylandState> for WaylandState { .flat_map(u32::to_ne_bytes) .collect() } else { - vec![] + vec![1].into_iter().flat_map(u32::to_ne_bytes).collect() }, ); xdg_surface.configure(SERIAL_COUNTER.inc()); @@ -100,7 +106,10 @@ impl Dispatch, WaylandState> for WaylandState { ); utils::insert_data(&wl_surface, Arc::downgrade(&panel_item)); utils::insert_data_raw(&wl_surface, node); - handle_cursor(&panel_item, panel_item.backend.cursor.clone()); + handle_cursor( + &panel_item, + panel_item.backend.seat.cursor_info_rx.clone(), + ); } }, { @@ -172,10 +181,7 @@ impl Dispatch, WaylandState> for WaylandState { &panel_item, positioner, ); - handle_cursor( - &panel_item, - panel_item.backend.seat.new_surface(&wl_surface), - ); + handle_cursor(&panel_item, panel_item.backend.seat.cursor_info_rx.clone()); let xdg_popup = data_init.init(id, wl_surface.downgrade()); utils::insert_data(&wl_surface, SurfaceID::Child(uid)); utils::insert_data(&wl_surface, Arc::downgrade(&panel_item)); diff --git a/src/wayland/xdg_shell/toplevel.rs b/src/wayland/xdg_shell/toplevel.rs index f816e31..e196f98 100644 --- a/src/wayland/xdg_shell/toplevel.rs +++ b/src/wayland/xdg_shell/toplevel.rs @@ -95,7 +95,7 @@ impl Drop for ToplevelData { impl Dispatch, WaylandState> for WaylandState { fn request( - _state: &mut WaylandState, + state: &mut WaylandState, _client: &Client, xdg_toplevel: &XdgToplevel, request: xdg_toplevel::Request, @@ -230,7 +230,6 @@ impl Dispatch, WaylandState> for WaylandState { error!("Couldn't get the panel item"); return; }; - panel_item.backend.seat.drop_surface(&wl_surface); panel_item.drop_toplevel(); } _ => {}