1
0
Fork 0
forked from wry/wry

wl_usr: add additional interfaces

This commit is contained in:
Julian Orth 2026-02-22 00:11:31 +01:00
parent 56290d5547
commit ce30901093
16 changed files with 1062 additions and 23 deletions

View file

@ -72,7 +72,33 @@ impl WpCursorShapeDeviceV1RequestHandler for WpCursorShapeDeviceV1 {
}
fn set_shape(&self, req: SetShape, _slf: &Rc<Self>) -> 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<Self> {
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(())
}
}

View file

@ -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;

View file

@ -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<UsrCon>,
pub version: Version,
pub offer: CloneCell<Option<Rc<UsrWlDataOffer>>>,
pub selection: CloneCell<Option<Rc<UsrWlDataOffer>>>,
}
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<Self>) -> 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<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn leave(&self, ev: Leave, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn motion(&self, ev: Motion, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn drop_(&self, ev: Drop, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn selection(&self, ev: Selection, _slf: &Rc<Self>) -> 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();
}
}

View file

@ -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<UsrCon>,
pub version: Version,
}
impl UsrWlDataDeviceManager {
#[expect(dead_code)]
pub fn create_data_source(&self) -> Rc<UsrWlDataSource> {
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<UsrWlDataDevice> {
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 });
}
}

View file

@ -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<UsrCon>,
pub version: Version,
pub mime_types: RefCell<AHashSet<String>>,
}
impl UsrWlDataOffer {
#[expect(dead_code)]
pub fn receive(&self, mime_type: &str, fd: &Rc<OwnedFd>) {
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<Self>) -> Result<(), Self::Error> {
self.mime_types
.borrow_mut()
.insert(ev.mime_type.to_string());
Ok(())
}
fn source_actions(&self, _ev: SourceActions, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn action(&self, _ev: Action, _slf: &Rc<Self>) -> 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 });
}
}

View file

@ -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<UsrCon>,
pub owner: CloneCell<Option<Rc<dyn UsrWlDataSourceOwner>>>,
pub version: Version,
}
pub trait UsrWlDataSourceOwner {
fn send(&self, mime_type: &str, fd: Rc<OwnedFd>);
}
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<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn send(&self, ev: Send<'_>, _slf: &Rc<Self>) -> 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<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn dnd_drop_performed(&self, ev: DndDropPerformed, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn dnd_finished(&self, ev: DndFinished, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let _ = ev;
Ok(())
}
fn action(&self, ev: Action, _slf: &Rc<Self>) -> 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();
}
}

View file

@ -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<UsrCon>,
pub keyboard: RefCell<Option<Keyboard>>,
pub owner: CloneCell<Option<Rc<dyn UsrWlKeyboardOwner>>>,
pub version: Version,
}
pub struct Keyboard {
lookup: LookupTable,
components: Components,
}
pub trait UsrWlKeyboardOwner {
fn focus(self: Rc<Self>, surface: WlSurfaceId, serial: u32);
fn unfocus(self: Rc<Self>);
fn modifiers(self: Rc<Self>, mods: ModifierMask);
fn down(self: Rc<Self>, lookup: Lookup<'_>, serial: u32);
fn repeat(self: Rc<Self>, lookup: Lookup<'_>, serial: u32);
fn up(self: Rc<Self>, lookup: Lookup<'_>, serial: u32);
}
impl WlKeyboardEventHandler for UsrWlKeyboard {
type Error = UsrWlKeyboardError;
fn keymap(&self, ev: Keymap, _slf: &Rc<Self>) -> 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<Self>) -> 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<Self>) -> Result<(), Self::Error> {
let Some(owner) = self.owner.get() else {
return Ok(());
};
owner.unfocus();
Ok(())
}
fn key(&self, ev: Key, _slf: &Rc<Self>) -> 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<Self>) -> 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<Self>) -> 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),
}

View file

@ -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<UsrWlKeyboard> {
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 {

View file

@ -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<UsrCon>,
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 })
}
}

View file

@ -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<UsrCon>,
pub version: Version,
}
impl UsrWpCursorShapeManagerV1 {
#[expect(dead_code)]
pub fn get_pointer(&self, pointer: &UsrWlPointer) -> Rc<UsrWpCursorShapeDeviceV1> {
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 })
}
}

View file

@ -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<UsrCon>,
pub owner: CloneCell<Option<Rc<dyn UsrXdgSurfaceOwner>>>,
pub version: Version,
}
pub trait UsrXdgSurfaceOwner {
fn configure(&self) {
// nothing
}
}
impl UsrXdgSurface {
#[expect(dead_code)]
pub fn get_toplevel(&self) -> Rc<UsrXdgToplevel> {
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<Self>) -> 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();
}
}

View file

@ -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<UsrCon>,
pub owner: CloneCell<Option<Rc<dyn UsrXdgToplevelOwner>>>,
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<Self>) -> Result<(), Self::Error> {
if let Some(owner) = self.owner.get() {
owner.configure(ev.width, ev.height);
}
Ok(())
}
fn close(&self, _ev: Close, _slf: &Rc<Self>) -> Result<(), Self::Error> {
if let Some(owner) = self.owner.get() {
owner.close();
}
Ok(())
}
fn configure_bounds(&self, _ev: ConfigureBounds, _slf: &Rc<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn wm_capabilities(&self, _ev: WmCapabilities<'_>, _slf: &Rc<Self>) -> 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();
}
}

View file

@ -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<UsrCon>,
pub version: Version,
}
impl UsrXdgWmBase {
#[expect(dead_code)]
pub fn get_xdg_surface(&self, surface: &UsrWlSurface) -> Rc<UsrXdgSurface> {
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<Self>) -> 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 })
}
}

View file

@ -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<UsrCon>,
pub version: Version,
}
impl UsrZwpLinuxBufferParamsV1 {
pub fn add(
&self,
fd: &Rc<OwnedFd>,
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<UsrWlBuffer> {
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<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn failed(&self, _ev: Failed, _slf: &Rc<Self>) -> 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 })
}
}

View file

@ -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<UsrCon>,
pub version: Version,
}
impl UsrZwpLinuxDmabufV1 {
#[expect(dead_code)]
pub fn create_buffer(&self, buffer: &DmaBuf) -> Rc<UsrWlBuffer> {
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<Self>) -> Result<(), Self::Error> {
Ok(())
}
fn modifier(&self, _ev: Modifier, _slf: &Rc<Self>) -> 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 })
}
}

View file

@ -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<UsrCon>,
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 })
}
}