diff --git a/src/client/error.rs b/src/client/error.rs index f91870c2..295e4292 100644 --- a/src/client/error.rs +++ b/src/client/error.rs @@ -6,7 +6,7 @@ use crate::ifs::wl_compositor::WlCompositorError; use crate::ifs::wl_data_device::WlDataDeviceError; use crate::ifs::wl_data_device_manager::WlDataDeviceManagerError; use crate::ifs::wl_data_offer::WlDataOfferError; -use crate::ifs::wl_data_source::WlDataSourceError; +use crate::ifs::wl_data_source::{WlDataSourceError, WlDataSourceId}; use crate::ifs::wl_display::WlDisplayError; use crate::ifs::wl_drm::WlDrmError; use crate::ifs::wl_output::WlOutputError; @@ -61,6 +61,8 @@ pub enum ClientError { SurfaceDoesNotExist(WlSurfaceId), #[error("There is no xdg_surface with id {0}")] XdgSurfaceDoesNotExist(XdgSurfaceId), + #[error("There is no wl_data_source with id {0}")] + WlDataSourceDoesNotExist(WlDataSourceId), #[error("There is no xdg_toplevel with id {0}")] XdgToplevelDoesNotExist(XdgToplevelId), #[error("There is no xdg_positioner with id {0}")] diff --git a/src/client/mod.rs b/src/client/mod.rs index 48713d35..2a75752a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -8,7 +8,7 @@ use crate::ifs::wl_compositor::WlCompositorObj; use crate::ifs::wl_data_device::WlDataDevice; use crate::ifs::wl_data_device_manager::WlDataDeviceManagerObj; use crate::ifs::wl_data_offer::WlDataOffer; -use crate::ifs::wl_data_source::WlDataSource; +use crate::ifs::wl_data_source::{WlDataSource, WlDataSourceId}; use crate::ifs::wl_display::WlDisplay; use crate::ifs::wl_drm::WlDrmObj; use crate::ifs::wl_output::WlOutputObj; @@ -42,6 +42,7 @@ use crate::ErrorFmt; use ahash::AHashMap; pub use error::ClientError; use std::cell::{Cell, RefCell, RefMut}; +use std::error::Error; use std::fmt::{Debug, Display, Formatter}; use std::mem; use std::rc::Rc; @@ -273,6 +274,22 @@ impl Client { Ok(res) } + pub fn error(&self, message: impl Error) { + let msg = ErrorFmt(message).to_string(); + log::error!("Client {}: A fatal error occurred: {}", self.id.0, msg,); + match self.display() { + Ok(d) => self.fatal_event(d.implementation_error(msg)), + Err(e) => { + log::error!( + "Could not retrieve display of client {}: {}", + self.id, + ErrorFmt(e), + ); + self.state.clients.kill(self.id); + } + } + } + pub fn protocol_error(&self, obj: &dyn Object, code: u32, message: String) { if let Ok(d) = self.display() { self.fatal_event(d.error(obj.id(), code, message)); @@ -343,6 +360,13 @@ impl Client { } } + pub fn get_wl_data_source(&self, id: WlDataSourceId) -> Result, ClientError> { + match self.objects.wl_data_source.get(&id) { + Some(r) => Ok(r), + _ => Err(ClientError::WlDataSourceDoesNotExist(id)), + } + } + pub fn get_xdg_toplevel(&self, id: XdgToplevelId) -> Result, ClientError> { match self.objects.xdg_toplevel.get(&id) { Some(r) => Ok(r), @@ -440,7 +464,6 @@ simple_add_obj!(WlTouch); simple_add_obj!(WlDataDeviceManagerObj); simple_add_obj!(WlDataDevice); simple_add_obj!(WlDataOffer); -simple_add_obj!(WlDataSource); simple_add_obj!(ZwpLinuxDmabufV1Obj); simple_add_obj!(ZwpLinuxBufferParamsV1); simple_add_obj!(WlDrmObj); @@ -470,3 +493,4 @@ dedicated_add_obj!(WlBuffer, buffers); dedicated_add_obj!(WlSeatObj, seats); dedicated_add_obj!(XdgPositioner, xdg_positioners); dedicated_add_obj!(XdgToplevel, xdg_toplevel); +dedicated_add_obj!(WlDataSource, wl_data_source); diff --git a/src/client/objects.rs b/src/client/objects.rs index d74ecd71..3f5d71a7 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -1,5 +1,6 @@ use crate::client::{Client, ClientError}; use crate::ifs::wl_buffer::{WlBuffer, WlBufferId}; +use crate::ifs::wl_data_source::{WlDataSource, WlDataSourceId}; use crate::ifs::wl_display::WlDisplay; use crate::ifs::wl_region::{WlRegion, WlRegionId}; use crate::ifs::wl_registry::{WlRegistry, WlRegistryId}; @@ -25,6 +26,7 @@ pub struct Objects { pub surfaces: CopyHashMap>, pub xdg_surfaces: CopyHashMap>, pub xdg_toplevel: CopyHashMap>, + pub wl_data_source: CopyHashMap>, pub xdg_positioners: CopyHashMap>, pub regions: CopyHashMap>, pub buffers: CopyHashMap>, @@ -45,6 +47,7 @@ impl Objects { surfaces: Default::default(), xdg_surfaces: Default::default(), xdg_toplevel: Default::default(), + wl_data_source: Default::default(), xdg_positioners: Default::default(), regions: Default::default(), buffers: Default::default(), @@ -141,8 +144,9 @@ impl Objects { return Err(ClientError::ServerIdOutOfBounds); } ids[pos] |= 1 << seg_offset; + } else { + client_data.event(client_data.display()?.delete_id(id)); } - client_data.event(client_data.display()?.delete_id(id)); Ok(()) } diff --git a/src/ifs/wl_data_device/mod.rs b/src/ifs/wl_data_device/mod.rs index 6e2bc562..fc1dadbc 100644 --- a/src/ifs/wl_data_device/mod.rs +++ b/src/ifs/wl_data_device/mod.rs @@ -1,9 +1,9 @@ mod types; -use crate::client::{Client, DynEventFormatter}; +use crate::client::{DynEventFormatter}; use crate::ifs::wl_data_device_manager::WlDataDeviceManagerObj; use crate::ifs::wl_data_offer::WlDataOfferId; -use crate::ifs::wl_seat::WlSeatObj; +use crate::ifs::wl_seat::{WlSeatObj}; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; use std::rc::Rc; @@ -28,7 +28,6 @@ id!(WlDataDeviceId); pub struct WlDataDevice { pub id: WlDataDeviceId, pub manager: Rc, - client: Rc, seat: Rc, } @@ -41,11 +40,17 @@ impl WlDataDevice { Self { id, manager: manager.clone(), - client: seat.client().clone(), seat: seat.clone(), } } + pub fn data_offer(self: &Rc, id: WlDataOfferId) -> DynEventFormatter { + Box::new(DataOffer { + obj: self.clone(), + id, + }) + } + pub fn selection(self: &Rc, id: WlDataOfferId) -> DynEventFormatter { Box::new(Selection { obj: self.clone(), @@ -54,19 +59,25 @@ impl WlDataDevice { } fn start_drag(&self, parser: MsgParser<'_, '_>) -> Result<(), StartDragError> { - let _req: StartDrag = self.client.parse(self, parser)?; + let _req: StartDrag = self.manager.client.parse(self, parser)?; Ok(()) } fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), SetSelectionError> { - let _req: SetSelection = self.client.parse(self, parser)?; + let req: SetSelection = self.manager.client.parse(self, parser)?; + let src = if req.source.is_none() { + None + } else { + Some(self.manager.client.get_wl_data_source(req.source)?) + }; + self.seat.global.set_selection(src)?; Ok(()) } fn release(&self, parser: MsgParser<'_, '_>) -> Result<(), ReleaseError> { - let _req: Release = self.client.parse(self, parser)?; + let _req: Release = self.manager.client.parse(self, parser)?; self.seat.remove_data_device(self); - self.client.remove_obj(self)?; + self.manager.client.remove_obj(self)?; Ok(()) } diff --git a/src/ifs/wl_data_device/types.rs b/src/ifs/wl_data_device/types.rs index 18768cf6..b5c16145 100644 --- a/src/ifs/wl_data_device/types.rs +++ b/src/ifs/wl_data_device/types.rs @@ -2,7 +2,7 @@ use crate::client::{ClientError, EventFormatter, RequestParser}; use crate::fixed::Fixed; use crate::ifs::wl_data_device::{WlDataDevice, DATA_OFFER, DROP, ENTER, LEAVE, MOTION, SELECTION}; use crate::ifs::wl_data_offer::WlDataOfferId; -use crate::ifs::wl_data_source::WlDataSourceId; +use crate::ifs::wl_data_source::{WlDataSourceError, WlDataSourceId}; use crate::ifs::wl_surface::WlSurfaceId; use crate::object::Object; use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; @@ -39,9 +39,12 @@ pub enum SetSelectionError { ParseFailed(#[source] Box), #[error(transparent)] ClientError(Box), + #[error(transparent)] + WlDataSourceError(Box), } efrom!(SetSelectionError, ParseFailed, MsgParserError); efrom!(SetSelectionError, ClientError); +efrom!(SetSelectionError, WlDataSourceError); #[derive(Debug, Error)] pub enum ReleaseError { diff --git a/src/ifs/wl_data_device_manager/mod.rs b/src/ifs/wl_data_device_manager/mod.rs index 90f91175..7ed1d9ff 100644 --- a/src/ifs/wl_data_device_manager/mod.rs +++ b/src/ifs/wl_data_device_manager/mod.rs @@ -28,8 +28,8 @@ pub struct WlDataDeviceManagerGlobal { } pub struct WlDataDeviceManagerObj { - id: WlDataDeviceManagerId, - client: Rc, + pub id: WlDataDeviceManagerId, + pub client: Rc, pub version: u32, } diff --git a/src/ifs/wl_data_offer/mod.rs b/src/ifs/wl_data_offer/mod.rs index 87c368e0..990973b7 100644 --- a/src/ifs/wl_data_offer/mod.rs +++ b/src/ifs/wl_data_offer/mod.rs @@ -1,8 +1,12 @@ mod types; -use crate::client::Client; +use crate::client::{Client, DynEventFormatter}; +use crate::ifs::wl_data_source::{WlDataSource}; +use crate::ifs::wl_seat::WlSeatGlobal; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; +use crate::utils::clonecell::CloneCell; +use std::ops::Deref; use std::rc::Rc; pub use types::*; @@ -27,24 +31,83 @@ const INVALID_OFFER: u32 = 3; id!(WlDataOfferId); +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum DataOfferRole { + Selection, +} + pub struct WlDataOffer { - id: WlDataOfferId, - client: Rc, + pub id: WlDataOfferId, + pub client: Rc, + pub role: DataOfferRole, + pub source: CloneCell>>, } impl WlDataOffer { + pub fn create( + client: &Rc, + role: DataOfferRole, + src: &Rc, + seat: &Rc, + ) -> Option> { + let id = match client.new_id() { + Ok(id) => id, + Err(e) => { + client.error(e); + return None; + } + }; + let slf = Rc::new(Self { + id, + client: client.clone(), + role, + source: CloneCell::new(Some(src.clone())), + }); + let mt = src.mime_types.borrow_mut(); + seat.for_each_data_device(0, client.id, |device| { + client.event(device.data_offer(slf.id)); + for mt in mt.deref() { + client.event(slf.offer(mt)); + } + let ev = match role { + DataOfferRole::Selection => device.selection(id), + }; + client.event(ev); + }); + client.add_server_obj(&slf); + Some(slf) + } + + pub fn offer(self: &Rc, mime_type: &str) -> DynEventFormatter { + Box::new(Offer { + obj: self.clone(), + mime_type: mime_type.to_string(), + }) + } + fn accept(&self, parser: MsgParser<'_, '_>) -> Result<(), AcceptError> { let _req: Accept = self.client.parse(self, parser)?; Ok(()) } fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ReceiveError> { - let _req: Receive = self.client.parse(self, parser)?; + let req: Receive = self.client.parse(self, parser)?; + if let Some(src) = self.source.get() { + src.client.event(src.send(req.mime_type, req.fd)); + src.client.flush(); + } Ok(()) } + fn disconnect(&self) { + if let Some(src) = self.source.set(None) { + src.destroy_offer(); + } + } + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; + self.disconnect(); self.client.remove_obj(self)?; Ok(()) } @@ -90,4 +153,8 @@ impl Object for WlDataOffer { fn num_requests(&self) -> u32 { SET_ACTIONS + 1 } + + fn break_loops(&self) { + self.disconnect(); + } } diff --git a/src/ifs/wl_data_offer/types.rs b/src/ifs/wl_data_offer/types.rs index cf487570..0ff3277b 100644 --- a/src/ifs/wl_data_offer/types.rs +++ b/src/ifs/wl_data_offer/types.rs @@ -2,7 +2,7 @@ use crate::client::{ClientError, EventFormatter, RequestParser}; use crate::ifs::wl_data_offer::{WlDataOffer, ACTION, OFFER, SOURCE_ACTIONS}; use crate::object::Object; use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; -use bstr::{BStr, BString}; +use bstr::{BStr}; use std::fmt::{Debug, Formatter}; use std::rc::Rc; use thiserror::Error; @@ -83,7 +83,7 @@ impl<'a> RequestParser<'a> for Accept<'a> { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { Ok(Self { serial: parser.uint()?, - mime_type: parser.string()?, + mime_type: parser.bstr()?, }) } } @@ -98,13 +98,13 @@ impl Debug for Accept<'_> { } pub(super) struct Receive<'a> { - pub mime_type: &'a BStr, + pub mime_type: &'a str, pub fd: OwnedFd, } impl<'a> RequestParser<'a> for Receive<'a> { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { Ok(Self { - mime_type: parser.string()?, + mime_type: parser.str()?, fd: parser.fd()?, }) } @@ -168,7 +168,7 @@ impl Debug for SetActions { pub(super) struct Offer { pub obj: Rc, - pub mime_type: BString, + pub mime_type: String, } impl EventFormatter for Offer { fn format(self: Box, fmt: &mut MsgFormatter<'_>) { diff --git a/src/ifs/wl_data_source/mod.rs b/src/ifs/wl_data_source/mod.rs index 17b44231..1b53d01d 100644 --- a/src/ifs/wl_data_source/mod.rs +++ b/src/ifs/wl_data_source/mod.rs @@ -1,9 +1,15 @@ mod types; -use crate::client::Client; +use crate::client::{Client, DynEventFormatter}; +use crate::ifs::wl_data_offer::{DataOfferRole, WlDataOffer}; +use crate::ifs::wl_seat::WlSeatGlobal; use crate::object::{Interface, Object, ObjectId}; use crate::utils::buffd::MsgParser; +use crate::utils::clonecell::{CloneCell, UnsafeCellCloneSafe}; +use ahash::AHashSet; +use std::cell::RefCell; use std::rc::Rc; +use uapi::OwnedFd; pub use types::*; const OFFER: u32 = 0; @@ -24,9 +30,20 @@ const INVALID_SOURCE: u32 = 1; id!(WlDataSourceId); +#[derive(Clone)] +struct Attachment { + seat: Rc, + role: DataOfferRole, +} + +unsafe impl UnsafeCellCloneSafe for Attachment {} + pub struct WlDataSource { - id: WlDataSourceId, - client: Rc, + pub id: WlDataSourceId, + pub client: Rc, + pub mime_types: RefCell>, + attachment: CloneCell>, + offer: CloneCell>>, } impl WlDataSource { @@ -34,16 +51,101 @@ impl WlDataSource { Self { id, client: client.clone(), + mime_types: RefCell::new(Default::default()), + attachment: Default::default(), + offer: Default::default(), } } - fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), OfferError> { - let _req: Offer = self.client.parse(self, parser)?; + pub fn attach( + &self, + seat: &Rc, + role: DataOfferRole, + ) -> Result<(), WlDataSourceError> { + let old = self.attachment.set( + Some(Attachment { + seat: seat.clone(), + role, + }), + ); + if old.is_some() { + return Err(WlDataSourceError::AlreadyAttached); + } Ok(()) } + pub fn detach(self: &Rc) { + self.attachment.set(None); + if let Some(offer) = self.offer.set(None) { + offer.source.set(None); + } + self.client.event(self.cancelled()); + self.client.flush(); + } + + pub fn create_offer(self: &Rc, client: &Rc) { + let attachment = match self.attachment.get() { + Some(a) => a, + _ => { + log::error!("Trying to create an offer from a unattached data source"); + return; + } + }; + let offer = WlDataOffer::create(client, attachment.role, self, &attachment.seat); + let old = self.offer.set(offer); + if let Some(offer) = old { + offer.source.set(None); + } + } + + pub fn destroy_offer(&self) { + self.offer.take(); + } + + pub fn cancelled(self: &Rc) -> DynEventFormatter { + Box::new(Cancelled { + obj: self.clone(), + }) + } + + pub fn send(self: &Rc, mime_type: &str, fd: OwnedFd) -> DynEventFormatter { + Box::new(Send { + obj: self.clone(), + mime_type: mime_type.to_string(), + fd: Rc::new(fd), + }) + } + + fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), OfferError> { + let req: Offer = self.client.parse(self, parser)?; + if self + .mime_types + .borrow_mut() + .insert(req.mime_type.to_string()) + { + if let Some(offer) = self.offer.get() { + offer.client.event(offer.offer(req.mime_type)); + } + } + Ok(()) + } + + fn disconnect(&self) { + if let Some(offer) = self.offer.take() { + offer.source.set(None); + } + if let Some(attachment) = self.attachment.get() { + match attachment.role { + DataOfferRole::Selection => { + let _ = attachment.seat.set_selection(None); + }, + } + } + } + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; + self.disconnect(); self.client.remove_obj(self)?; Ok(()) } @@ -82,4 +184,8 @@ impl Object for WlDataSource { fn num_requests(&self) -> u32 { SET_ACTIONS + 1 } + + fn break_loops(&self) { + self.disconnect(); + } } diff --git a/src/ifs/wl_data_source/types.rs b/src/ifs/wl_data_source/types.rs index 8e4e1ae9..c6515993 100644 --- a/src/ifs/wl_data_source/types.rs +++ b/src/ifs/wl_data_source/types.rs @@ -4,7 +4,7 @@ use crate::ifs::wl_data_source::{ }; use crate::object::Object; use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; -use bstr::{BStr, BString}; +use bstr::{BString}; use std::fmt::{Debug, Formatter}; use std::rc::Rc; use thiserror::Error; @@ -20,6 +20,8 @@ pub enum WlDataSourceError { DestroyError(#[from] DestroyError), #[error("Could not process `set_actions` request")] SetActionsError(#[from] SetActionsError), + #[error("The data source is already attached")] + AlreadyAttached, } efrom!(WlDataSourceError, ClientError); @@ -54,12 +56,12 @@ efrom!(SetActionsError, ParseFailed, MsgParserError); efrom!(SetActionsError, ClientError); pub(super) struct Offer<'a> { - pub mime_type: &'a BStr, + pub mime_type: &'a str, } impl<'a> RequestParser<'a> for Offer<'a> { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { Ok(Self { - mime_type: parser.string()?, + mime_type: parser.str()?, }) } } @@ -117,7 +119,7 @@ impl Debug for Target { pub(super) struct Send { pub obj: Rc, - pub mime_type: BString, + pub mime_type: String, pub fd: Rc, } impl EventFormatter for Send { diff --git a/src/ifs/wl_registry/types.rs b/src/ifs/wl_registry/types.rs index e8527770..26e29d0a 100644 --- a/src/ifs/wl_registry/types.rs +++ b/src/ifs/wl_registry/types.rs @@ -101,7 +101,7 @@ impl<'a> RequestParser<'a> for Bind<'a> { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { Ok(Self { name: parser.global()?, - interface: parser.string()?, + interface: parser.bstr()?, version: parser.uint()?, id: parser.object()?, }) diff --git a/src/ifs/wl_seat/handling.rs b/src/ifs/wl_seat/handling.rs index 419c81ae..9d89fe6f 100644 --- a/src/ifs/wl_seat/handling.rs +++ b/src/ifs/wl_seat/handling.rs @@ -2,7 +2,7 @@ use crate::backend::{KeyState, OutputId, ScrollAxis, SeatEvent, SeatId}; use crate::client::{ClientId, DynEventFormatter}; use crate::fixed::Fixed; use crate::ifs::wl_data_device::WlDataDevice; -use crate::ifs::wl_data_offer::WlDataOfferId; +use crate::ifs::wl_data_offer::{WlDataOfferId}; use crate::ifs::wl_seat::wl_keyboard::WlKeyboard; use crate::ifs::wl_seat::wl_pointer::{WlPointer, POINTER_FRAME_SINCE_VERSION}; use crate::ifs::wl_seat::{ @@ -241,7 +241,18 @@ impl WlSeatGlobal { k.modifiers(serial, mods_depressed, mods_latched, mods_locked, group) }); - self.surface_data_device_event(0, &surface, |dd| dd.selection(WlDataOfferId::NONE)); + if old.client_id() != Some(surface.client.id) { + match self.selection.get() { + None => { + self.surface_data_device_event(0, &surface, |dd| { + dd.selection(WlDataOfferId::NONE) + }); + } + Some(sel) => { + sel.create_offer(&surface.client); + } + } + } } fn for_each_seat(&self, ver: u32, client: ClientId, mut f: C) @@ -282,7 +293,7 @@ impl WlSeatGlobal { }) } - fn for_each_data_device(&self, ver: u32, client: ClientId, mut f: C) + pub fn for_each_data_device(&self, ver: u32, client: ClientId, mut f: C) where C: FnMut(&Rc), { diff --git a/src/ifs/wl_seat/mod.rs b/src/ifs/wl_seat/mod.rs index 02abf3d8..122fdfa0 100644 --- a/src/ifs/wl_seat/mod.rs +++ b/src/ifs/wl_seat/mod.rs @@ -10,6 +10,8 @@ use crate::cursor::{Cursor, KnownCursor}; use crate::fixed::Fixed; use crate::globals::{Global, GlobalName}; use crate::ifs::wl_data_device::{WlDataDevice, WlDataDeviceId}; +use crate::ifs::wl_data_offer::{DataOfferRole, WlDataOfferId}; +use crate::ifs::wl_data_source::{WlDataSource, WlDataSourceError}; use crate::ifs::wl_seat::wl_keyboard::{WlKeyboard, WlKeyboardId, REPEAT_INFO_SINCE}; use crate::ifs::wl_seat::wl_pointer::{WlPointer, WlPointerId}; use crate::ifs::wl_seat::wl_touch::WlTouch; @@ -95,6 +97,7 @@ pub struct WlSeatGlobal { serial: NumCell, grabber: RefCell>, tree_changed: Rc, + selection: CloneCell>>, } impl WlSeatGlobal { @@ -144,20 +147,31 @@ impl WlSeatGlobal { serial: Default::default(), grabber: RefCell::new(None), tree_changed: tree_changed.clone(), + selection: Default::default(), } } - // pub fn grab_pointer(self: &Rc, node: Rc) -> Option { - // let mut grabber = self.grabber.borrow_mut(); - // if grabber.is_some() { - // return None; - // } - // *grabber = Some(PointerGrabber { - // node, - // buttons: Default::default(), - // }); - // Some(PointerGrab { seat: self.clone() }) - // } + pub fn set_selection(self: &Rc, selection: Option>) -> Result<(), WlDataSourceError> { + if let Some(new) = &selection { + new.attach(self, DataOfferRole::Selection)?; + } + if let Some(old) = self.selection.set(selection.clone()) { + old.detach(); + } + if let Some(client) = self.keyboard_node.get().client() { + match selection { + Some(sel) => { + sel.create_offer(&client); + } + _ => { + self.for_each_data_device(0, client.id, |device| { + client.event(device.selection(WlDataOfferId::NONE)); + }); + } + } + } + Ok(()) + } pub fn set_known_cursor(&self, cursor: KnownCursor) { let cursors = match self.state.cursors.get() { @@ -292,10 +306,6 @@ impl WlSeatObj { } } - pub fn client(&self) -> &Rc { - &self.client - } - pub fn move_(&self, node: &Rc) { self.global.move_(node); } diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index af4469c4..1349834b 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -4,7 +4,7 @@ pub mod wl_subsurface; pub mod xdg_surface; use crate::backend::{KeyState, ScrollAxis, SeatId}; -use crate::client::{Client, ClientId, DynEventFormatter, RequestParser}; +use crate::client::{Client, DynEventFormatter, RequestParser}; use crate::fixed::Fixed; use crate::ifs::wl_buffer::WlBuffer; use crate::ifs::wl_callback::WlCallback; @@ -17,7 +17,9 @@ use crate::object::{Interface, Object, ObjectId}; use crate::pixman::Region; use crate::rect::Rect; use crate::render::Renderer; -use crate::tree::{Node, NodeId}; +use crate::tree::{ + Node, NodeId, +}; use crate::utils::buffd::{MsgParser, MsgParserError}; use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::LinkedList; @@ -662,7 +664,7 @@ impl Node for WlSurface { renderer.render_surface(self, x, y); } - fn client_id(&self) -> Option { - Some(self.client.id) + fn client(&self) -> Option> { + Some(self.client.clone()) } } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs index bbea0f82..18bbadab 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -1,6 +1,6 @@ mod types; -use crate::client::{ClientId, DynEventFormatter}; +use crate::client::{Client, DynEventFormatter}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; @@ -311,8 +311,8 @@ impl Node for XdgPopup { self.xdg.set_workspace(ws); } - fn client_id(&self) -> Option { - Some(self.xdg.surface.client.id) + fn client(&self) -> Option> { + Some(self.xdg.surface.client.clone()) } } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs index ebed7cff..c50d9517 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -2,7 +2,7 @@ mod types; use crate::backend::SeatId; use crate::bugs::Bugs; -use crate::client::{ClientId, DynEventFormatter}; +use crate::client::{Client, DynEventFormatter}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal}; @@ -496,8 +496,8 @@ impl Node for XdgToplevel { self.xdg.set_workspace(ws); } - fn client_id(&self) -> Option { - Some(self.xdg.surface.client.id) + fn client(&self) -> Option> { + Some(self.xdg.surface.client.clone()) } } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs index 255b38c5..71ed4308 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/types.rs @@ -219,7 +219,7 @@ pub(super) struct SetTitle<'a> { impl<'a> RequestParser<'a> for SetTitle<'a> { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { Ok(Self { - title: parser.string()?, + title: parser.bstr()?, }) } } @@ -235,7 +235,7 @@ pub(super) struct SetAppId<'a> { impl<'a> RequestParser<'a> for SetAppId<'a> { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result { Ok(Self { - app_id: parser.string()?, + app_id: parser.bstr()?, }) } } diff --git a/src/rect.rs b/src/rect.rs index bdc74088..ef7eca1d 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -1,17 +1,5 @@ use std::fmt::{Debug, Formatter}; -#[derive(Copy, Clone, Eq, PartialEq, Default)] -pub struct Point { - pub x: i32, - pub y: i32, -} - -impl Point { - pub fn translate(&self, x: i32, y: i32) -> (i32, i32) { - (x - self.x, y - self.y) - } -} - #[derive(Copy, Clone, Eq, PartialEq, Default)] pub struct Rect { x1: i32, @@ -65,13 +53,6 @@ impl Rect { } } - pub fn to_point(&self) -> Point { - Point { - x: self.x1, - y: self.y1, - } - } - pub fn new(x1: i32, y1: i32, x2: i32, y2: i32) -> Option { if x2 < x1 || y2 < y1 { return None; diff --git a/src/tree/mod.rs b/src/tree/mod.rs index c2f92a79..02325c86 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -1,5 +1,5 @@ use crate::backend::{KeyState, OutputId, ScrollAxis}; -use crate::client::ClientId; +use crate::client::{Client, ClientId}; use crate::cursor::KnownCursor; use crate::fixed::Fixed; use crate::ifs::wl_output::WlOutputGlobal; @@ -169,9 +169,13 @@ pub trait Node { let _ = ws; } - fn client_id(&self) -> Option { + fn client(&self) -> Option> { None } + + fn client_id(&self) -> Option { + self.client().map(|c| c.id) + } } pub struct FoundNode { diff --git a/src/utils/buffd/parser.rs b/src/utils/buffd/parser.rs index 305d70b2..e993ecf6 100644 --- a/src/utils/buffd/parser.rs +++ b/src/utils/buffd/parser.rs @@ -16,6 +16,8 @@ pub enum MsgParserError { MissingFd, #[error("There is trailing data after the message")] TrailingData, + #[error("String is not UTF-8")] + NonUtf8, } pub struct MsgParser<'a, 'b> { @@ -62,7 +64,7 @@ impl<'a, 'b> MsgParser<'a, 'b> { self.int().map(Fixed) } - pub fn string(&mut self) -> Result<&'b BStr, MsgParserError> { + pub fn bstr(&mut self) -> Result<&'b BStr, MsgParserError> { let len = self.uint()? as usize; if len == 0 { return Err(MsgParserError::EmptyString); @@ -77,6 +79,13 @@ impl<'a, 'b> MsgParser<'a, 'b> { Ok(s) } + pub fn str(&mut self) -> Result<&'b str, MsgParserError> { + match self.bstr()?.to_str() { + Ok(s) => Ok(s), + _ => Err(MsgParserError::NonUtf8), + } + } + pub fn fd(&mut self) -> Result { match self.buf.get_fd() { Ok(fd) => Ok(fd), diff --git a/todo.md b/todo.md index de6ced09..809b5da9 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,5 @@ -- Container resizing +# todo + - Container moving (mouse) - Container moving (kb) - Float toggle @@ -14,3 +15,7 @@ - presentation time - viewporter - session lock + +# done + +- Container resizing