diff --git a/src/ifs/wp_cursor_shape_device_v1.rs b/src/ifs/wp_cursor_shape_device_v1.rs index f1d4e307..b4fdec17 100644 --- a/src/ifs/wp_cursor_shape_device_v1.rs +++ b/src/ifs/wp_cursor_shape_device_v1.rs @@ -72,7 +72,33 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 { } fn set_shape(&self, req: SetShape, _slf: &Rc) -> Result<(), Self::Error> { - let cursor = match req.shape { + let cursor = KnownCursor::from_shape(req.shape, self.version) + .ok_or(WpCursorShapeDeviceV1Error::UnknownShape(req.shape))?; + let tablet_tool; + let (node_client_id, user) = match &self.cursor_user { + CursorShapeCursorUser::Seat(s) => match s.pointer_node() { + Some(n) => (n.node_client_id(), s.pointer_cursor()), + _ => return Ok(()), + }, + CursorShapeCursorUser::TabletTool(t) => match t.get() { + Some(t) => { + tablet_tool = t; + (tablet_tool.node().node_client_id(), tablet_tool.cursor()) + } + _ => return Ok(()), + }, + }; + if node_client_id != Some(self.client.id) { + return Ok(()); + } + user.set_known(cursor); + Ok(()) + } +} + +impl KnownCursor { + pub fn from_shape(shape: u32, version: Version) -> Option { + let cursor = match shape { DEFAULT => KnownCursor::Default, CONTEXT_MENU => KnownCursor::ContextMenu, HELP => KnownCursor::Help, @@ -107,29 +133,52 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 { ALL_SCROLL => KnownCursor::AllScroll, ZOOM_IN => KnownCursor::ZoomIn, ZOOM_OUT => KnownCursor::ZoomOut, - DND_ASK if self.version >= V2 => KnownCursor::DndAsk, - ALL_RESIZE if self.version >= V2 => KnownCursor::AllResize, - _ => return Err(WpCursorShapeDeviceV1Error::UnknownShape(req.shape)), + DND_ASK if version >= V2 => KnownCursor::DndAsk, + ALL_RESIZE if version >= V2 => KnownCursor::AllResize, + _ => return None, }; - let tablet_tool; - let (node_client_id, user) = match &self.cursor_user { - CursorShapeCursorUser::Seat(s) => match s.pointer_node() { - Some(n) => (n.node_client_id(), s.pointer_cursor()), - _ => return Ok(()), - }, - CursorShapeCursorUser::TabletTool(t) => match t.get() { - Some(t) => { - tablet_tool = t; - (tablet_tool.node().node_client_id(), tablet_tool.cursor()) - } - _ => return Ok(()), - }, - }; - if node_client_id != Some(self.client.id) { - return Ok(()); + Some(cursor) + } + + pub fn to_shape(self) -> u32 { + match self { + KnownCursor::Default => DEFAULT, + KnownCursor::ContextMenu => CONTEXT_MENU, + KnownCursor::Help => HELP, + KnownCursor::Pointer => POINTER, + KnownCursor::Progress => PROGRESS, + KnownCursor::Wait => WAIT, + KnownCursor::Cell => CELL, + KnownCursor::Crosshair => CROSSHAIR, + KnownCursor::Text => TEXT, + KnownCursor::VerticalText => VERTICAL_TEXT, + KnownCursor::Alias => ALIAS, + KnownCursor::Copy => COPY, + KnownCursor::Move => MOVE, + KnownCursor::NoDrop => NO_DROP, + KnownCursor::NotAllowed => NOT_ALLOWED, + KnownCursor::Grab => GRAB, + KnownCursor::Grabbing => GRABBING, + KnownCursor::EResize => E_RESIZE, + KnownCursor::NResize => N_RESIZE, + KnownCursor::NeResize => NE_RESIZE, + KnownCursor::NwResize => NW_RESIZE, + KnownCursor::SResize => S_RESIZE, + KnownCursor::SeResize => SE_RESIZE, + KnownCursor::SwResize => SW_RESIZE, + KnownCursor::WResize => W_RESIZE, + KnownCursor::EwResize => EW_RESIZE, + KnownCursor::NsResize => NS_RESIZE, + KnownCursor::NeswResize => NESW_RESIZE, + KnownCursor::NwseResize => NWSE_RESIZE, + KnownCursor::ColResize => COL_RESIZE, + KnownCursor::RowResize => ROW_RESIZE, + KnownCursor::AllScroll => ALL_SCROLL, + KnownCursor::ZoomIn => ZOOM_IN, + KnownCursor::ZoomOut => ZOOM_OUT, + KnownCursor::DndAsk => DND_ASK, + KnownCursor::AllResize => ALL_RESIZE, } - user.set_known(cursor); - Ok(()) } } diff --git a/src/wl_usr/usr_ifs.rs b/src/wl_usr/usr_ifs.rs index 8f31fc04..c2272c7c 100644 --- a/src/wl_usr/usr_ifs.rs +++ b/src/wl_usr/usr_ifs.rs @@ -15,7 +15,12 @@ pub mod usr_linux_dmabuf; pub mod usr_wl_buffer; pub mod usr_wl_callback; pub mod usr_wl_compositor; +pub mod usr_wl_data_device; +pub mod usr_wl_data_device_manager; +pub mod usr_wl_data_offer; +pub mod usr_wl_data_source; pub mod usr_wl_display; +pub mod usr_wl_keyboard; pub mod usr_wl_output; pub mod usr_wl_pointer; pub mod usr_wl_registry; @@ -25,9 +30,17 @@ pub mod usr_wl_shm_pool; pub mod usr_wl_surface; pub mod usr_wlr_layer_shell; pub mod usr_wlr_layer_surface; +pub mod usr_wp_cursor_shape_device_v1; +pub mod usr_wp_cursor_shape_manager_v1; pub mod usr_wp_fractional_scale; pub mod usr_wp_fractional_scale_manager; pub mod usr_wp_viewport; pub mod usr_wp_viewporter; +pub mod usr_xdg_surface; +pub mod usr_xdg_toplevel; +pub mod usr_xdg_wm_base; pub mod usr_zwlr_screencopy_frame; pub mod usr_zwlr_screencopy_manager; +pub mod usr_zwp_linux_buffer_params_v1; +pub mod usr_zwp_linux_dmabuf_v1; +pub mod usr_zwp_primary_selection_device_manager; diff --git a/src/wl_usr/usr_ifs/usr_wl_data_device.rs b/src/wl_usr/usr_ifs/usr_wl_data_device.rs new file mode 100644 index 00000000..7b3cb57e --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_data_device.rs @@ -0,0 +1,99 @@ +use { + crate::{ + object::Version, + utils::clonecell::CloneCell, + wire::{WlDataDeviceId, wl_data_device::*}, + wl_usr::{ + UsrCon, + usr_ifs::{usr_wl_data_offer::UsrWlDataOffer, usr_wl_data_source::UsrWlDataSource}, + usr_object::UsrObject, + }, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrWlDataDevice { + pub id: WlDataDeviceId, + pub con: Rc, + pub version: Version, + pub offer: CloneCell>>, + pub selection: CloneCell>>, +} + +impl UsrWlDataDevice { + #[expect(dead_code)] + pub fn set_selection(&self, serial: u32, source: &UsrWlDataSource) { + self.con.request(SetSelection { + self_id: self.id, + source: source.id, + serial, + }); + } +} + +impl WlDataDeviceEventHandler for UsrWlDataDevice { + type Error = Infallible; + + fn data_offer(&self, ev: DataOffer, _slf: &Rc) -> Result<(), Self::Error> { + let obj = Rc::new(UsrWlDataOffer { + id: ev.id, + con: self.con.clone(), + version: self.version, + mime_types: Default::default(), + }); + self.con.add_object(obj.clone()); + if let Some(offer) = self.offer.set(Some(obj)) { + self.con.remove_obj(&*offer); + } + Ok(()) + } + + fn enter(&self, ev: Enter, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn leave(&self, ev: Leave, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn motion(&self, ev: Motion, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn drop_(&self, ev: Drop, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn selection(&self, ev: Selection, _slf: &Rc) -> Result<(), Self::Error> { + self.selection.take(); + if let Some(offer) = self.offer.get() + && offer.id == ev.id + { + self.selection.set(Some(offer)); + } + Ok(()) + } +} + +usr_object_base! { + self = UsrWlDataDevice = WlDataDevice; + version = self.version; +} + +impl UsrObject for UsrWlDataDevice { + fn destroy(&self) { + if let Some(offer) = self.offer.take() { + self.con.remove_obj(&*offer); + } + self.con.request(Release { self_id: self.id }); + } + + fn break_loops(&self) { + self.selection.take(); + self.offer.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs b/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs new file mode 100644 index 00000000..0957a93a --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_data_device_manager.rs @@ -0,0 +1,72 @@ +use { + crate::{ + object::Version, + wire::{WlDataDeviceManagerId, wl_data_device_manager::*}, + wl_usr::{ + UsrCon, + usr_ifs::{ + usr_wl_data_device::UsrWlDataDevice, usr_wl_data_source::UsrWlDataSource, + usr_wl_seat::UsrWlSeat, + }, + usr_object::UsrObject, + }, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrWlDataDeviceManager { + pub id: WlDataDeviceManagerId, + pub con: Rc, + pub version: Version, +} + +impl UsrWlDataDeviceManager { + #[expect(dead_code)] + pub fn create_data_source(&self) -> Rc { + let obj = Rc::new(UsrWlDataSource { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + version: self.version, + }); + self.con.request(CreateDataSource { + self_id: self.id, + id: obj.id, + }); + self.con.add_object(obj.clone()); + obj + } + + #[expect(dead_code)] + pub fn get_data_device(&self, seat: &UsrWlSeat) -> Rc { + let obj = Rc::new(UsrWlDataDevice { + id: self.con.id(), + con: self.con.clone(), + version: self.version, + offer: Default::default(), + selection: Default::default(), + }); + self.con.request(GetDataDevice { + self_id: self.id, + id: obj.id, + seat: seat.id, + }); + self.con.add_object(obj.clone()); + obj + } +} + +impl WlDataDeviceManagerEventHandler for UsrWlDataDeviceManager { + type Error = Infallible; +} + +usr_object_base! { + self = UsrWlDataDeviceManager = WlDataDeviceManager; + version = self.version; +} + +impl UsrObject for UsrWlDataDeviceManager { + fn destroy(&self) { + self.con.request(Release { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_data_offer.rs b/src/wl_usr/usr_ifs/usr_wl_data_offer.rs new file mode 100644 index 00000000..4c500e36 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_data_offer.rs @@ -0,0 +1,58 @@ +use { + crate::{ + object::Version, + wire::{WlDataOfferId, wl_data_offer::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, + }, + ahash::AHashSet, + std::{cell::RefCell, convert::Infallible, rc::Rc}, + uapi::OwnedFd, +}; + +pub struct UsrWlDataOffer { + pub id: WlDataOfferId, + pub con: Rc, + pub version: Version, + pub mime_types: RefCell>, +} + +impl UsrWlDataOffer { + #[expect(dead_code)] + pub fn receive(&self, mime_type: &str, fd: &Rc) { + self.con.request(Receive { + self_id: self.id, + mime_type, + fd: fd.clone(), + }); + } +} + +impl WlDataOfferEventHandler for UsrWlDataOffer { + type Error = Infallible; + + fn offer(&self, ev: Offer<'_>, _slf: &Rc) -> Result<(), Self::Error> { + self.mime_types + .borrow_mut() + .insert(ev.mime_type.to_string()); + Ok(()) + } + + fn source_actions(&self, _ev: SourceActions, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } + + fn action(&self, _ev: Action, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } +} + +usr_object_base! { + self = UsrWlDataOffer = WlDataOffer; + version = self.version; +} + +impl UsrObject for UsrWlDataOffer { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_data_source.rs b/src/wl_usr/usr_ifs/usr_wl_data_source.rs new file mode 100644 index 00000000..e7109346 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_data_source.rs @@ -0,0 +1,82 @@ +use { + crate::{ + object::Version, + utils::clonecell::CloneCell, + wire::{WlDataSourceId, wl_data_source::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, + }, + std::{convert::Infallible, rc::Rc}, + uapi::OwnedFd, +}; + +pub struct UsrWlDataSource { + pub id: WlDataSourceId, + pub con: Rc, + pub owner: CloneCell>>, + pub version: Version, +} + +pub trait UsrWlDataSourceOwner { + fn send(&self, mime_type: &str, fd: Rc); +} + +impl UsrWlDataSource { + #[expect(dead_code)] + pub fn offer(&self, mime_type: &str) { + self.con.request(Offer { + self_id: self.id, + mime_type, + }); + } +} + +impl WlDataSourceEventHandler for UsrWlDataSource { + type Error = Infallible; + + fn target(&self, ev: Target<'_>, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn send(&self, ev: Send<'_>, _slf: &Rc) -> Result<(), Self::Error> { + if let Some(owner) = self.owner.get() { + owner.send(ev.mime_type, ev.fd); + } + Ok(()) + } + + fn cancelled(&self, ev: Cancelled, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn dnd_drop_performed(&self, ev: DndDropPerformed, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn dnd_finished(&self, ev: DndFinished, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } + + fn action(&self, ev: Action, _slf: &Rc) -> Result<(), Self::Error> { + let _ = ev; + Ok(()) + } +} + +usr_object_base! { + self = UsrWlDataSource = WlDataSource; + version = self.version; +} + +impl UsrObject for UsrWlDataSource { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_wl_keyboard.rs b/src/wl_usr/usr_ifs/usr_wl_keyboard.rs new file mode 100644 index 00000000..05e7734d --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wl_keyboard.rs @@ -0,0 +1,148 @@ +use { + crate::{ + ifs::wl_seat::wl_keyboard, + object::Version, + utils::{clonecell::CloneCell, mmap::mmap, oserror::OsError}, + wire::{WlKeyboardId, WlSurfaceId, wl_keyboard::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, + }, + kbvm::{ + Components, Keycode, ModifierMask, + lookup::{Lookup, LookupTable}, + xkb::{ + Context, + diagnostic::{Diagnostic, WriteToLog}, + }, + }, + std::{cell::RefCell, rc::Rc}, + thiserror::Error, + uapi::c, +}; + +pub struct UsrWlKeyboard { + pub id: WlKeyboardId, + pub con: Rc, + pub keyboard: RefCell>, + pub owner: CloneCell>>, + pub version: Version, +} + +pub struct Keyboard { + lookup: LookupTable, + components: Components, +} + +pub trait UsrWlKeyboardOwner { + fn focus(self: Rc, surface: WlSurfaceId, serial: u32); + fn unfocus(self: Rc); + fn modifiers(self: Rc, mods: ModifierMask); + fn down(self: Rc, lookup: Lookup<'_>, serial: u32); + fn repeat(self: Rc, lookup: Lookup<'_>, serial: u32); + fn up(self: Rc, lookup: Lookup<'_>, serial: u32); +} + +impl WlKeyboardEventHandler for UsrWlKeyboard { + type Error = UsrWlKeyboardError; + + fn keymap(&self, ev: Keymap, _slf: &Rc) -> Result<(), Self::Error> { + let map = mmap(ev.size as _, c::PROT_READ, c::MAP_PRIVATE, ev.fd.raw(), 0) + .map_err(UsrWlKeyboardError::MapKeymap)?; + let mut builder = Context::builder(); + builder.enable_default_includes(false); + builder.enable_environment(false); + let keymap = builder + .build() + .keymap_from_bytes(WriteToLog, None, unsafe { &*map.ptr }) + .map_err(UsrWlKeyboardError::ParseKeymap)?; + let lookup = keymap.to_builder().build_lookup_table(); + let keyboard = Keyboard { + lookup, + components: Default::default(), + }; + self.keyboard.replace(Some(keyboard)); + Ok(()) + } + + fn enter(&self, ev: Enter<'_>, _slf: &Rc) -> Result<(), Self::Error> { + let Some(owner) = self.owner.get() else { + return Ok(()); + }; + owner.focus(ev.surface, ev.serial); + Ok(()) + } + + fn leave(&self, _ev: Leave, _slf: &Rc) -> Result<(), Self::Error> { + let Some(owner) = self.owner.get() else { + return Ok(()); + }; + owner.unfocus(); + Ok(()) + } + + fn key(&self, ev: Key, _slf: &Rc) -> Result<(), Self::Error> { + let Some(kb) = &*self.keyboard.borrow() else { + return Ok(()); + }; + let Some(owner) = self.owner.get() else { + return Ok(()); + }; + let kc = Keycode::from_evdev(ev.key); + let lookup = kb + .lookup + .lookup(kb.components.group, kb.components.mods, kc); + if ev.state == wl_keyboard::PRESSED { + owner.down(lookup, ev.serial); + } else if ev.state == wl_keyboard::REPEATED { + owner.repeat(lookup, ev.serial); + } else if ev.state == wl_keyboard::RELEASED { + owner.up(lookup, ev.serial); + } + Ok(()) + } + + fn modifiers(&self, ev: Modifiers, _slf: &Rc) -> Result<(), Self::Error> { + let Some(kb) = &mut *self.keyboard.borrow_mut() else { + return Ok(()); + }; + kb.components.mods_pressed.0 = ev.mods_depressed; + kb.components.mods_latched.0 = ev.mods_latched; + kb.components.mods_locked.0 = ev.mods_locked; + kb.components.group_locked.0 = ev.group; + let old = kb.components.mods; + kb.components.update_effective(); + let new = kb.components.mods; + if old != new + && let Some(owner) = self.owner.get() + { + owner.modifiers(new); + } + Ok(()) + } + + fn repeat_info(&self, _ev: RepeatInfo, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } +} + +usr_object_base! { + self = UsrWlKeyboard = WlKeyboard; + version = self.version; +} + +impl UsrObject for UsrWlKeyboard { + fn destroy(&self) { + self.con.request(Release { self_id: self.id }); + } + + fn break_loops(&self) { + self.owner.take(); + } +} + +#[derive(Debug, Error)] +pub enum UsrWlKeyboardError { + #[error("Could not map the keymap")] + MapKeymap(#[source] OsError), + #[error("Could not parse the keymap")] + ParseKeymap(#[source] Diagnostic), +} diff --git a/src/wl_usr/usr_ifs/usr_wl_seat.rs b/src/wl_usr/usr_ifs/usr_wl_seat.rs index 82db0a05..d1f4ba6f 100644 --- a/src/wl_usr/usr_ifs/usr_wl_seat.rs +++ b/src/wl_usr/usr_ifs/usr_wl_seat.rs @@ -3,7 +3,11 @@ use { object::Version, utils::clonecell::CloneCell, wire::{WlSeatId, wl_seat::*}, - wl_usr::{UsrCon, usr_ifs::usr_wl_pointer::UsrWlPointer, usr_object::UsrObject}, + wl_usr::{ + UsrCon, + usr_ifs::{usr_wl_keyboard::UsrWlKeyboard, usr_wl_pointer::UsrWlPointer}, + usr_object::UsrObject, + }, }, std::{cell::Cell, convert::Infallible, rc::Rc}, }; @@ -42,6 +46,23 @@ impl UsrWlSeat { }); ptr } + + #[expect(dead_code)] + pub fn get_keyboard(&self) -> Rc { + let kb = Rc::new(UsrWlKeyboard { + id: self.con.id(), + con: self.con.clone(), + keyboard: Default::default(), + owner: Default::default(), + version: self.version, + }); + self.con.add_object(kb.clone()); + self.con.request(GetKeyboard { + self_id: self.id, + id: kb.id, + }); + kb + } } impl WlSeatEventHandler for UsrWlSeat { diff --git a/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs new file mode 100644 index 00000000..49e8c816 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_device_v1.rs @@ -0,0 +1,41 @@ +use { + crate::{ + cursor::KnownCursor, + object::Version, + wire::{WpCursorShapeDeviceV1Id, wp_cursor_shape_device_v1::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrWpCursorShapeDeviceV1 { + pub id: WpCursorShapeDeviceV1Id, + pub con: Rc, + pub version: Version, +} + +impl UsrWpCursorShapeDeviceV1 { + #[expect(dead_code)] + pub fn set_shape(&self, serial: u32, cursor: KnownCursor) { + self.con.request(SetShape { + self_id: self.id, + serial, + shape: cursor.to_shape(), + }); + } +} + +impl WpCursorShapeDeviceV1EventHandler for UsrWpCursorShapeDeviceV1 { + type Error = Infallible; +} + +usr_object_base! { + self = UsrWpCursorShapeDeviceV1 = WpCursorShapeDeviceV1; + version = self.version; +} + +impl UsrObject for UsrWpCursorShapeDeviceV1 { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs new file mode 100644 index 00000000..69c9cd55 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_wp_cursor_shape_manager_v1.rs @@ -0,0 +1,54 @@ +use { + crate::{ + object::Version, + wire::{WpCursorShapeManagerV1Id, wp_cursor_shape_manager_v1::*}, + wl_usr::{ + UsrCon, + usr_ifs::{ + usr_wl_pointer::UsrWlPointer, + usr_wp_cursor_shape_device_v1::UsrWpCursorShapeDeviceV1, + }, + usr_object::UsrObject, + }, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrWpCursorShapeManagerV1 { + pub id: WpCursorShapeManagerV1Id, + pub con: Rc, + pub version: Version, +} + +impl UsrWpCursorShapeManagerV1 { + #[expect(dead_code)] + pub fn get_pointer(&self, pointer: &UsrWlPointer) -> Rc { + let obj = Rc::new(UsrWpCursorShapeDeviceV1 { + id: self.con.id(), + con: self.con.clone(), + version: self.version, + }); + self.con.request(GetPointer { + self_id: self.id, + cursor_shape_device: obj.id, + pointer: pointer.id, + }); + self.con.add_object(obj.clone()); + obj + } +} + +impl WpCursorShapeManagerV1EventHandler for UsrWpCursorShapeManagerV1 { + type Error = Infallible; +} + +usr_object_base! { + self = UsrWpCursorShapeManagerV1 = WpCursorShapeManagerV1; + version = self.version; +} + +impl UsrObject for UsrWpCursorShapeManagerV1 { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_xdg_surface.rs b/src/wl_usr/usr_ifs/usr_xdg_surface.rs new file mode 100644 index 00000000..e706c5c2 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_xdg_surface.rs @@ -0,0 +1,70 @@ +use { + crate::{ + object::Version, + utils::clonecell::CloneCell, + wire::{XdgSurfaceId, xdg_surface::*}, + wl_usr::{UsrCon, usr_ifs::usr_xdg_toplevel::UsrXdgToplevel, usr_object::UsrObject}, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrXdgSurface { + pub id: XdgSurfaceId, + pub con: Rc, + pub owner: CloneCell>>, + pub version: Version, +} + +pub trait UsrXdgSurfaceOwner { + fn configure(&self) { + // nothing + } +} + +impl UsrXdgSurface { + #[expect(dead_code)] + pub fn get_toplevel(&self) -> Rc { + let obj = Rc::new(UsrXdgToplevel { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + version: self.version, + }); + self.con.request(GetToplevel { + self_id: self.id, + id: obj.id, + }); + self.con.add_object(obj.clone()); + obj + } +} + +impl XdgSurfaceEventHandler for UsrXdgSurface { + type Error = Infallible; + + fn configure(&self, ev: Configure, _slf: &Rc) -> Result<(), Self::Error> { + self.con.request(AckConfigure { + self_id: self.id, + serial: ev.serial, + }); + if let Some(owner) = self.owner.get() { + owner.configure(); + } + Ok(()) + } +} + +usr_object_base! { + self = UsrXdgSurface = XdgSurface; + version = self.version; +} + +impl UsrObject for UsrXdgSurface { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs b/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs new file mode 100644 index 00000000..4e4d7491 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_xdg_toplevel.rs @@ -0,0 +1,95 @@ +use { + crate::{ + object::Version, + utils::clonecell::CloneCell, + wire::{WlOutputId, XdgToplevelId, xdg_toplevel::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrXdgToplevel { + pub id: XdgToplevelId, + pub con: Rc, + pub owner: CloneCell>>, + pub version: Version, +} + +impl UsrXdgToplevel { + #[expect(dead_code)] + pub fn set_title(&self, title: &str) { + self.con.request(SetTitle { + self_id: self.id, + title, + }); + } + + #[expect(dead_code)] + pub fn set_fullscreen(&self, fullscreen: bool) { + match fullscreen { + true => { + self.con.request(SetFullscreen { + self_id: self.id, + output: WlOutputId::NONE, + }); + } + false => { + self.con.request(UnsetFullscreen { self_id: self.id }); + } + } + } +} + +pub trait UsrXdgToplevelOwner { + fn configure(&self, width: i32, height: i32) { + let _ = width; + let _ = height; + } + + fn close(&self) { + // nothing + } +} + +impl UsrXdgToplevel {} + +impl XdgToplevelEventHandler for UsrXdgToplevel { + type Error = Infallible; + + fn configure(&self, ev: Configure<'_>, _slf: &Rc) -> Result<(), Self::Error> { + if let Some(owner) = self.owner.get() { + owner.configure(ev.width, ev.height); + } + Ok(()) + } + + fn close(&self, _ev: Close, _slf: &Rc) -> Result<(), Self::Error> { + if let Some(owner) = self.owner.get() { + owner.close(); + } + Ok(()) + } + + fn configure_bounds(&self, _ev: ConfigureBounds, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } + + fn wm_capabilities(&self, _ev: WmCapabilities<'_>, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } +} + +usr_object_base! { + self = UsrXdgToplevel = XdgToplevel; + version = self.version; +} + +impl UsrObject for UsrXdgToplevel { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } + + fn break_loops(&self) { + self.owner.take(); + } +} diff --git a/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs b/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs new file mode 100644 index 00000000..b9d7faf0 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_xdg_wm_base.rs @@ -0,0 +1,60 @@ +use { + crate::{ + object::Version, + wire::{XdgWmBaseId, xdg_wm_base::*}, + wl_usr::{ + UsrCon, + usr_ifs::{usr_wl_surface::UsrWlSurface, usr_xdg_surface::UsrXdgSurface}, + usr_object::UsrObject, + }, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrXdgWmBase { + pub id: XdgWmBaseId, + pub con: Rc, + pub version: Version, +} + +impl UsrXdgWmBase { + #[expect(dead_code)] + pub fn get_xdg_surface(&self, surface: &UsrWlSurface) -> Rc { + let obj = Rc::new(UsrXdgSurface { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + version: self.version, + }); + self.con.request(GetXdgSurface { + self_id: self.id, + id: obj.id, + surface: surface.id, + }); + self.con.add_object(obj.clone()); + obj + } +} + +impl XdgWmBaseEventHandler for UsrXdgWmBase { + type Error = Infallible; + + fn ping(&self, ev: Ping, _slf: &Rc) -> Result<(), Self::Error> { + self.con.request(Pong { + self_id: self.id, + serial: ev.serial, + }); + Ok(()) + } +} + +usr_object_base! { + self = UsrXdgWmBase = XdgWmBase; + version = self.version; +} + +impl UsrObject for UsrXdgWmBase { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs b/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs new file mode 100644 index 00000000..f06a383b --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_zwp_linux_buffer_params_v1.rs @@ -0,0 +1,79 @@ +use { + crate::{ + format::Format, + object::Version, + video::Modifier, + wire::{ZwpLinuxBufferParamsV1Id, zwp_linux_buffer_params_v1::*}, + wl_usr::{UsrCon, usr_ifs::usr_wl_buffer::UsrWlBuffer, usr_object::UsrObject}, + }, + std::{convert::Infallible, rc::Rc}, + uapi::OwnedFd, +}; + +pub struct UsrZwpLinuxBufferParamsV1 { + pub id: ZwpLinuxBufferParamsV1Id, + pub con: Rc, + pub version: Version, +} + +impl UsrZwpLinuxBufferParamsV1 { + pub fn add( + &self, + fd: &Rc, + plane_idx: usize, + offset: u32, + stride: u32, + modifier: Modifier, + ) { + self.con.request(Add { + self_id: self.id, + fd: fd.clone(), + plane_idx: plane_idx as u32, + offset, + stride, + modifier, + }); + } + + pub fn create_immed(&self, width: i32, height: i32, format: &Format) -> Rc { + let obj = Rc::new(UsrWlBuffer { + id: self.con.id(), + con: self.con.clone(), + owner: Default::default(), + version: self.version, + }); + self.con.request(CreateImmed { + self_id: self.id, + buffer_id: obj.id, + width, + height, + format: format.drm, + flags: 0, + }); + self.con.add_object(obj.clone()); + obj + } +} + +impl ZwpLinuxBufferParamsV1EventHandler for UsrZwpLinuxBufferParamsV1 { + type Error = Infallible; + + fn created(&self, _ev: Created, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } + + fn failed(&self, _ev: Failed, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } +} + +usr_object_base! { + self = UsrZwpLinuxBufferParamsV1 = ZwpLinuxBufferParamsV1; + version = self.version; +} + +impl UsrObject for UsrZwpLinuxBufferParamsV1 { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs b/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs new file mode 100644 index 00000000..f2017a51 --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_zwp_linux_dmabuf_v1.rs @@ -0,0 +1,67 @@ +use { + crate::{ + object::Version, + video::dmabuf::DmaBuf, + wire::{ZwpLinuxDmabufV1Id, zwp_linux_dmabuf_v1::*}, + wl_usr::{ + UsrCon, + usr_ifs::{ + usr_wl_buffer::UsrWlBuffer, + usr_zwp_linux_buffer_params_v1::UsrZwpLinuxBufferParamsV1, + }, + usr_object::UsrObject, + }, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrZwpLinuxDmabufV1 { + pub id: ZwpLinuxDmabufV1Id, + pub con: Rc, + pub version: Version, +} + +impl UsrZwpLinuxDmabufV1 { + #[expect(dead_code)] + pub fn create_buffer(&self, buffer: &DmaBuf) -> Rc { + let params = Rc::new(UsrZwpLinuxBufferParamsV1 { + id: self.con.id(), + con: self.con.clone(), + version: self.version, + }); + self.con.request(CreateParams { + self_id: self.id, + params_id: params.id, + }); + self.con.add_object(params.clone()); + for (idx, plane) in buffer.planes.iter().enumerate() { + params.add(&plane.fd, idx, plane.offset, plane.stride, buffer.modifier); + } + let obj = params.create_immed(buffer.width, buffer.height, &buffer.format); + self.con.remove_obj(&*params); + obj + } +} + +impl ZwpLinuxDmabufV1EventHandler for UsrZwpLinuxDmabufV1 { + type Error = Infallible; + + fn format(&self, _ev: Format, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } + + fn modifier(&self, _ev: Modifier, _slf: &Rc) -> Result<(), Self::Error> { + Ok(()) + } +} + +usr_object_base! { + self = UsrZwpLinuxDmabufV1 = ZwpLinuxDmabufV1; + version = self.version; +} + +impl UsrObject for UsrZwpLinuxDmabufV1 { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +} diff --git a/src/wl_usr/usr_ifs/usr_zwp_primary_selection_device_manager.rs b/src/wl_usr/usr_ifs/usr_zwp_primary_selection_device_manager.rs new file mode 100644 index 00000000..b978ba9d --- /dev/null +++ b/src/wl_usr/usr_ifs/usr_zwp_primary_selection_device_manager.rs @@ -0,0 +1,31 @@ +use { + crate::{ + object::Version, + wire::{ZwpPrimarySelectionDeviceManagerV1Id, zwp_primary_selection_device_manager_v1::*}, + wl_usr::{UsrCon, usr_object::UsrObject}, + }, + std::{convert::Infallible, rc::Rc}, +}; + +pub struct UsrZwpPrimarySelectionDeviceManagerV1 { + pub id: ZwpPrimarySelectionDeviceManagerV1Id, + pub con: Rc, + pub version: Version, +} + +impl UsrZwpPrimarySelectionDeviceManagerV1 {} + +impl ZwpPrimarySelectionDeviceManagerV1EventHandler for UsrZwpPrimarySelectionDeviceManagerV1 { + type Error = Infallible; +} + +usr_object_base! { + self = UsrZwpPrimarySelectionDeviceManagerV1 = ZwpPrimarySelectionDeviceManagerV1; + version = self.version; +} + +impl UsrObject for UsrZwpPrimarySelectionDeviceManagerV1 { + fn destroy(&self) { + self.con.request(Destroy { self_id: self.id }) + } +}