From be1462d0ef4a8e6c4bea1e5d830285d02a28f7a1 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 8 Oct 2024 16:00:40 +0200 Subject: [PATCH] ipc: move data control logic out of wlr code --- src/ifs/ipc/data_control.rs | 1 + src/ifs/ipc/data_control/private.rs | 426 ++++++++++++++++++ .../zwlr_data_control_device_v1.rs | 228 ++-------- .../zwlr_data_control_offer_v1.rs | 81 +--- .../zwlr_data_control_source_v1.rs | 89 ++-- 5 files changed, 520 insertions(+), 305 deletions(-) create mode 100644 src/ifs/ipc/data_control/private.rs diff --git a/src/ifs/ipc/data_control.rs b/src/ifs/ipc/data_control.rs index 976f8a1d..20c3418d 100644 --- a/src/ifs/ipc/data_control.rs +++ b/src/ifs/ipc/data_control.rs @@ -3,6 +3,7 @@ use { std::rc::Rc, }; +mod private; pub mod zwlr_data_control_device_v1; pub mod zwlr_data_control_manager_v1; pub mod zwlr_data_control_offer_v1; diff --git a/src/ifs/ipc/data_control/private.rs b/src/ifs/ipc/data_control/private.rs new file mode 100644 index 00000000..629765f7 --- /dev/null +++ b/src/ifs/ipc/data_control/private.rs @@ -0,0 +1,426 @@ +use { + crate::{ + client::{Client, ClientError, ClientId, WaylandObject, WaylandObjectLookup}, + ifs::{ + ipc::{ + cancel_offer, cancel_offers, + data_control::{DataControlDeviceId, DynDataControlDevice}, + detach_seat, offer_source_to_data_control_device, offer_source_to_x, + x_data_device::{XClipboardIpc, XIpcDevice, XPrimarySelectionIpc}, + DataOffer, DataOfferId, DataSource, DeviceData, DynDataOffer, DynDataSource, + IpcLocation, IpcVtable, OfferData, Role, SourceData, + }, + wl_seat::WlSeatGlobal, + }, + object::{ObjectId, Version}, + }, + std::{cell::Cell, marker::PhantomData, rc::Rc}, + uapi::OwnedFd, +}; + +struct ClipboardCore(PhantomData); +struct PrimarySelectionCore(PhantomData); +struct DataControlIpcImpl(PhantomData); + +type Device = ::Device; +type Offer = ::Offer; +type Source = ::Source; +type SourceId = ::SourceId; + +pub trait DataControlIpc: Sized + 'static { + const PRIMARY_SELECTION_SINCE: Version; + + type Device: DataControlDevice; + type OfferId: From; + type Offer: DataControlOffer; + type SourceId: WaylandObjectLookup; + type Source: DataControlSource; + + fn create_offer(id: Self::OfferId, data: DataControlOfferData) -> Rc; +} + +pub struct DataControlDeviceData { + pub data_control_device_id: DataControlDeviceId, + pub client: Rc, + pub version: Version, + pub seat: Rc, + pub clipboard_data: DeviceData, + pub primary_selection_data: DeviceData, +} + +pub trait DataControlDevice: WaylandObject { + type Ipc: DataControlIpc; + + fn data(&self) -> &DataControlDeviceData; + + fn send_data_offer(&self, offer: &Rc>); + + fn send_selection(&self, offer: Option<&Rc>>); + + fn send_primary_selection(&self, offer: Option<&Rc>>); +} + +pub struct DataControlOfferData { + pub offer_id: DataOfferId, + pub client: Rc, + pub device: Rc, + pub data: OfferData, + pub location: IpcLocation, +} + +pub trait DataControlOffer: WaylandObject { + type Ipc: DataControlIpc; + + fn data(&self) -> &DataControlOfferData; + + fn send_offer(&self, mime_type: &str); +} + +pub struct DataControlSourceData { + pub data: SourceData, + pub version: Version, + pub location: Cell, + pub used: Cell, +} + +pub trait DataControlSource: WaylandObject { + type Ipc: DataControlIpc; + + fn data(&self) -> &DataControlSourceData; + + fn send_cancelled(&self); + + fn send_send(&self, mime_type: &str, fd: Rc); +} + +impl DynDataControlDevice for T { + fn id(&self) -> DataControlDeviceId { + self.data().data_control_device_id + } + + fn handle_new_source( + self: Rc, + location: IpcLocation, + source: Option>, + ) { + if location == IpcLocation::PrimarySelection + && self.data().version < T::Ipc::PRIMARY_SELECTION_SINCE + { + return; + } + match location { + IpcLocation::Clipboard => match source { + Some(src) => { + offer_source_to_data_control_device::>(src, &self); + } + _ => self.send_selection(None), + }, + IpcLocation::PrimarySelection => match source { + Some(src) => { + offer_source_to_data_control_device::>(src, &self); + } + _ => self.send_primary_selection(None), + }, + } + } +} + +type Clipboard = DataControlIpcImpl>; +type PrimarySelection = DataControlIpcImpl>; + +pub trait DataControlLocationIpc { + type Ipc: DataControlIpc; + const LOCATION: IpcLocation; + + fn loc_get_device_data(dd: &Device) -> &DeviceData>; + + fn loc_send_selection(dd: &Device, offer: Option<&Rc>>); + + fn loc_unset(seat: &Rc); +} + +impl DataControlLocationIpc for ClipboardCore { + type Ipc = T; + const LOCATION: IpcLocation = IpcLocation::Clipboard; + + fn loc_get_device_data(dd: &Device) -> &DeviceData> { + &dd.data().clipboard_data + } + + fn loc_send_selection(dd: &Device, offer: Option<&Rc>>) { + dd.send_selection(offer) + } + + fn loc_unset(seat: &Rc) { + seat.unset_selection() + } +} + +impl DataControlLocationIpc for PrimarySelectionCore { + type Ipc = T; + const LOCATION: IpcLocation = IpcLocation::PrimarySelection; + + fn loc_get_device_data(dd: &Device) -> &DeviceData> { + &dd.data().primary_selection_data + } + + fn loc_send_selection(dd: &Device, offer: Option<&Rc>>) { + dd.send_primary_selection(offer) + } + + fn loc_unset(seat: &Rc) { + seat.unset_primary_selection() + } +} + +impl IpcVtable for DataControlIpcImpl { + type Device = Device; + type Source = Source; + type Offer = Offer; + + fn get_device_data(dd: &Self::Device) -> &DeviceData { + T::loc_get_device_data(dd) + } + + fn get_device_seat(dd: &Self::Device) -> Rc { + dd.data().seat.clone() + } + + fn create_offer( + device: &Rc, + offer_data: OfferData, + ) -> Result, ClientError> { + let data = device.data(); + let offer = DataControlOfferData { + offer_id: data.client.state.data_offer_ids.next(), + client: data.client.clone(), + device: device.clone(), + data: offer_data, + location: T::LOCATION, + }; + let rc = T::Ipc::create_offer(data.client.new_id()?, offer); + data.client.add_server_obj(&rc); + Ok(rc) + } + + fn send_selection(dd: &Self::Device, offer: Option<&Rc>) { + T::loc_send_selection(dd, offer) + } + + fn send_offer(dd: &Self::Device, offer: &Rc) { + dd.send_data_offer(offer); + } + + fn unset(seat: &Rc, _role: Role) { + T::loc_unset(seat) + } + + fn device_client(dd: &Rc) -> &Rc { + &dd.data().client + } +} + +impl DataSource for T { + fn send_cancelled(&self, _seat: &Rc) { + self.send_cancelled(); + } +} + +impl DynDataSource for T { + fn source_data(&self) -> &SourceData { + &self.data().data + } + + fn send_send(&self, mime_type: &str, fd: Rc) { + self.send_send(mime_type, fd); + } + + fn offer_to_x(self: Rc, dd: &Rc) { + match self.data().location.get() { + IpcLocation::Clipboard => offer_source_to_x::(self, dd), + IpcLocation::PrimarySelection => offer_source_to_x::(self, dd), + } + } + + fn detach_seat(&self, seat: &Rc) { + detach_seat(self, seat) + } + + fn cancel_unprivileged_offers(&self) { + cancel_offers(self, false) + } +} + +impl DataOffer for T { + type Device = Device; + + fn offer_data(&self) -> &OfferData { + &self.data().data + } +} + +impl DynDataOffer for T { + fn offer_id(&self) -> DataOfferId { + self.data().offer_id + } + + fn client_id(&self) -> ClientId { + self.data().client.id + } + + fn send_offer(&self, mime_type: &str) { + self.send_offer(mime_type); + } + + fn cancel(&self) { + match self.data().location { + IpcLocation::Clipboard => cancel_offer::>(self), + IpcLocation::PrimarySelection => cancel_offer::>(self), + } + } + + fn get_seat(&self) -> Rc { + self.data().device.data().seat.clone() + } + + fn is_privileged(&self) -> bool { + true + } +} + +pub mod logic { + use { + crate::{ + client::ClientError, + ifs::{ + ipc::{ + add_data_source_mime_type, break_device_loops, break_offer_loops, + break_source_loops, + data_control::private::{ + Clipboard, DataControlDevice, DataControlOffer, DataControlSource, + PrimarySelection, Source, SourceId, + }, + destroy_data_device, destroy_data_offer, destroy_data_source, + receive_data_offer, IpcLocation, + }, + wl_seat::WlSeatError, + }, + }, + std::rc::Rc, + thiserror::Error, + uapi::OwnedFd, + }; + + pub fn data_device_break_loops(d: &D) { + break_device_loops::>(d); + break_device_loops::>(d); + d.data().seat.remove_data_control_device(d); + } + + fn use_source( + device: &D, + source: Option>, + location: IpcLocation, + ) -> Result>>, DataControlError> { + if let Some(source) = source { + let src = device.data().client.lookup(source)?; + if src.data().used.replace(true) { + return Err(DataControlError::AlreadyUsed); + } + src.data().location.set(location); + Ok(Some(src)) + } else { + Ok(None) + } + } + + pub fn device_set_selection( + d: &D, + source: Option>, + ) -> Result<(), DataControlError> { + let src = use_source(d, source, IpcLocation::Clipboard)?; + d.data().seat.set_selection(src)?; + Ok(()) + } + + pub fn device_destroy(d: &D) -> Result<(), DataControlError> { + destroy_data_device::>(d); + destroy_data_device::>(d); + d.data().seat.remove_data_control_device(d); + d.data().client.remove_obj(d)?; + Ok(()) + } + + pub fn device_set_primary_selection( + d: &D, + source: Option>, + ) -> Result<(), DataControlError> { + let src = use_source(d, source, IpcLocation::PrimarySelection)?; + d.data().seat.set_primary_selection(src)?; + Ok(()) + } + + pub fn data_source_offer( + s: &S, + mime_type: &str, + ) -> Result<(), DataControlError> { + if s.data().used.get() { + return Err(DataControlError::AlreadyUsed); + } + add_data_source_mime_type::>(s, mime_type); + Ok(()) + } + + pub fn data_source_destroy(s: &S) -> Result<(), DataControlError> { + match s.data().location.get() { + IpcLocation::Clipboard => destroy_data_source::>(s), + IpcLocation::PrimarySelection => destroy_data_source::>(s), + } + s.data().data.client.remove_obj(s)?; + Ok(()) + } + + pub fn data_source_break_loops(s: &S) { + match s.data().location.get() { + IpcLocation::Clipboard => break_source_loops::>(s), + IpcLocation::PrimarySelection => break_source_loops::>(s), + } + } + + pub fn data_offer_receive(o: &O, mime_type: &str, fd: Rc) { + match o.data().location { + IpcLocation::Clipboard => receive_data_offer::>(o, mime_type, fd), + IpcLocation::PrimarySelection => { + receive_data_offer::>(o, mime_type, fd) + } + } + } + + pub fn data_offer_destroy(o: &O) -> Result<(), DataControlError> { + match o.data().location { + IpcLocation::Clipboard => destroy_data_offer::>(o), + IpcLocation::PrimarySelection => destroy_data_offer::>(o), + } + o.data().client.remove_obj(o)?; + Ok(()) + } + + pub fn data_offer_break_loops(o: &O) { + match o.data().location { + IpcLocation::Clipboard => break_offer_loops::>(o), + IpcLocation::PrimarySelection => break_offer_loops::>(o), + } + } + + #[derive(Debug, Error)] + pub enum DataControlError { + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + WlSeatError(Box), + #[error("The source has already been used")] + AlreadyUsed, + } + efrom!(DataControlError, ClientError); + efrom!(DataControlError, WlSeatError); +} diff --git a/src/ifs/ipc/data_control/zwlr_data_control_device_v1.rs b/src/ifs/ipc/data_control/zwlr_data_control_device_v1.rs index 4ab57159..2c12aedf 100644 --- a/src/ifs/ipc/data_control/zwlr_data_control_device_v1.rs +++ b/src/ifs/ipc/data_control/zwlr_data_control_device_v1.rs @@ -1,21 +1,16 @@ use { crate::{ - client::{Client, ClientError}, + client::Client, ifs::{ - ipc::{ - break_device_loops, - data_control::{ - zwlr_data_control_device_v1::private::{ - WlrClipboardIpcCore, WlrIpcImpl, WlrPrimarySelectionIpcCore, - }, - zwlr_data_control_offer_v1::ZwlrDataControlOfferV1, - zwlr_data_control_source_v1::ZwlrDataControlSourceV1, - DataControlDeviceId, DynDataControlDevice, + ipc::data_control::{ + private::{ + logic::{self, DataControlError}, + DataControlDevice, DataControlDeviceData, DataControlIpc, DataControlOfferData, }, - destroy_data_device, offer_source_to_data_control_device, DeviceData, - DynDataSource, IpcLocation, IpcVtable, OfferData, Role, + zwlr_data_control_offer_v1::ZwlrDataControlOfferV1, + zwlr_data_control_source_v1::ZwlrDataControlSourceV1, }, - wl_seat::{WlSeatError, WlSeatGlobal}, + wl_seat::WlSeatGlobal, }, leaks::Tracker, object::{Object, Version}, @@ -32,12 +27,7 @@ pub const PRIMARY_SELECTION_SINCE: Version = Version(2); pub struct ZwlrDataControlDeviceV1 { pub id: ZwlrDataControlDeviceV1Id, - pub data_control_device_id: DataControlDeviceId, - pub client: Rc, - pub version: Version, - pub seat: Rc, - pub clipboard_data: DeviceData, - pub primary_selection_data: DeviceData, + pub data: DataControlDeviceData, pub tracker: Tracker, } @@ -50,18 +40,20 @@ impl ZwlrDataControlDeviceV1 { ) -> Self { Self { id, - data_control_device_id: client.state.data_control_device_ids.next(), - client: client.clone(), - version, - seat: seat.clone(), - clipboard_data: Default::default(), - primary_selection_data: Default::default(), + data: DataControlDeviceData { + data_control_device_id: client.state.data_control_device_ids.next(), + client: client.clone(), + version, + seat: seat.clone(), + clipboard_data: Default::default(), + primary_selection_data: Default::default(), + }, tracker: Default::default(), } } pub fn send_data_offer(&self, offer: &Rc) { - self.client.event(DataOffer { + self.data.client.event(DataOffer { self_id: self.id, id: offer.id, }) @@ -71,7 +63,7 @@ impl ZwlrDataControlDeviceV1 { let id = offer .map(|o| o.id) .unwrap_or(ZwlrDataControlOfferV1Id::NONE); - self.client.event(Selection { + self.data.client.event(Selection { self_id: self.id, id, }) @@ -81,44 +73,23 @@ impl ZwlrDataControlDeviceV1 { let id = offer .map(|o| o.id) .unwrap_or(ZwlrDataControlOfferV1Id::NONE); - self.client.event(PrimarySelection { + self.data.client.event(PrimarySelection { self_id: self.id, id, }) } - - fn use_source( - &self, - source: ZwlrDataControlSourceV1Id, - location: IpcLocation, - ) -> Result>, ZwlrDataControlDeviceV1Error> { - if source.is_none() { - Ok(None) - } else { - let src = self.client.lookup(source)?; - if src.used.replace(true) { - return Err(ZwlrDataControlDeviceV1Error::AlreadyUsed); - } - src.location.set(location); - Ok(Some(src)) - } - } } impl ZwlrDataControlDeviceV1RequestHandler for ZwlrDataControlDeviceV1 { type Error = ZwlrDataControlDeviceV1Error; fn set_selection(&self, req: SetSelection, _slf: &Rc) -> Result<(), Self::Error> { - let src = self.use_source(req.source, IpcLocation::Clipboard)?; - self.seat.set_selection(src)?; + logic::device_set_selection(self, req.source.is_some().then_some(req.source))?; Ok(()) } fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { - destroy_data_device::(self); - destroy_data_device::(self); - self.seat.remove_data_control_device(self); - self.client.remove_obj(self)?; + logic::device_destroy(self)?; Ok(()) } @@ -127,157 +98,60 @@ impl ZwlrDataControlDeviceV1RequestHandler for ZwlrDataControlDeviceV1 { req: SetPrimarySelection, _slf: &Rc, ) -> Result<(), Self::Error> { - let src = self.use_source(req.source, IpcLocation::PrimarySelection)?; - self.seat.set_primary_selection(src)?; + logic::device_set_primary_selection(self, req.source.is_some().then_some(req.source))?; Ok(()) } } -mod private { - use std::marker::PhantomData; - - pub struct WlrClipboardIpcCore; - pub struct WlrPrimarySelectionIpcCore; - pub struct WlrIpcImpl(PhantomData); -} -pub type WlrClipboardIpc = WlrIpcImpl; -pub type WlrPrimarySelectionIpc = WlrIpcImpl; - -trait WlrIpc { - const LOCATION: IpcLocation; - - fn wlr_get_device_data(dd: &ZwlrDataControlDeviceV1) -> &DeviceData; - - fn wlr_send_selection(dd: &ZwlrDataControlDeviceV1, offer: Option<&Rc>); - - fn wlr_unset(seat: &Rc); -} - -impl WlrIpc for WlrClipboardIpcCore { - const LOCATION: IpcLocation = IpcLocation::Clipboard; - - fn wlr_get_device_data(dd: &ZwlrDataControlDeviceV1) -> &DeviceData { - &dd.clipboard_data - } - - fn wlr_send_selection( - dd: &ZwlrDataControlDeviceV1, - offer: Option<&Rc>, - ) { - dd.send_selection(offer) - } - - fn wlr_unset(seat: &Rc) { - seat.unset_selection() - } -} - -impl WlrIpc for WlrPrimarySelectionIpcCore { - const LOCATION: IpcLocation = IpcLocation::PrimarySelection; +pub struct WlrDataControlIpc; - fn wlr_get_device_data(dd: &ZwlrDataControlDeviceV1) -> &DeviceData { - &dd.primary_selection_data - } - - fn wlr_send_selection( - dd: &ZwlrDataControlDeviceV1, - offer: Option<&Rc>, - ) { - dd.send_primary_selection(offer) - } - - fn wlr_unset(seat: &Rc) { - seat.unset_primary_selection() - } -} - -impl IpcVtable for WlrIpcImpl { +impl DataControlIpc for WlrDataControlIpc { + const PRIMARY_SELECTION_SINCE: Version = PRIMARY_SELECTION_SINCE; type Device = ZwlrDataControlDeviceV1; - type Source = ZwlrDataControlSourceV1; + type OfferId = ZwlrDataControlOfferV1Id; type Offer = ZwlrDataControlOfferV1; + type SourceId = ZwlrDataControlSourceV1Id; + type Source = ZwlrDataControlSourceV1; - fn get_device_data(dd: &Self::Device) -> &DeviceData { - T::wlr_get_device_data(dd) - } - - fn get_device_seat(dd: &Self::Device) -> Rc { - dd.seat.clone() - } - - fn create_offer( - device: &Rc, - offer_data: OfferData, - ) -> Result, ClientError> { + fn create_offer(id: Self::OfferId, data: DataControlOfferData) -> Rc { let rc = Rc::new(ZwlrDataControlOfferV1 { - id: device.client.new_id()?, - offer_id: device.client.state.data_offer_ids.next(), - client: device.client.clone(), - device: device.clone(), - data: offer_data, - location: T::LOCATION, + id, + data, tracker: Default::default(), }); - track!(device.client, rc); - device.client.add_server_obj(&rc); - Ok(rc) - } - - fn send_selection(dd: &Self::Device, offer: Option<&Rc>) { - T::wlr_send_selection(dd, offer) + track!(rc.data.client, rc); + rc } +} - fn send_offer(dd: &Self::Device, offer: &Rc) { - dd.send_data_offer(offer); - } +impl DataControlDevice for ZwlrDataControlDeviceV1 { + type Ipc = WlrDataControlIpc; - fn unset(seat: &Rc, _role: Role) { - T::wlr_unset(seat) + fn data(&self) -> &DataControlDeviceData { + &self.data } - fn device_client(dd: &Rc) -> &Rc { - &dd.client + fn send_data_offer(&self, offer: &Rc<::Offer>) { + self.send_data_offer(offer) } -} -impl DynDataControlDevice for ZwlrDataControlDeviceV1 { - fn id(&self) -> DataControlDeviceId { - self.data_control_device_id + fn send_selection(&self, offer: Option<&Rc<::Offer>>) { + self.send_selection(offer) } - fn handle_new_source( - self: Rc, - location: IpcLocation, - source: Option>, - ) { - match location { - IpcLocation::Clipboard => match source { - Some(src) => offer_source_to_data_control_device::(src, &self), - _ => self.send_selection(None), - }, - IpcLocation::PrimarySelection => { - if self.version >= PRIMARY_SELECTION_SINCE { - match source { - Some(src) => offer_source_to_data_control_device::( - src, &self, - ), - _ => self.send_primary_selection(None), - } - } - } - } + fn send_primary_selection(&self, offer: Option<&Rc<::Offer>>) { + self.send_primary_selection(offer) } } object_base! { self = ZwlrDataControlDeviceV1; - version = self.version; + version = self.data.version; } impl Object for ZwlrDataControlDeviceV1 { fn break_loops(&self) { - break_device_loops::(self); - break_device_loops::(self); - self.seat.remove_data_control_device(self); + logic::data_device_break_loops(self); } } @@ -286,11 +160,5 @@ simple_add_obj!(ZwlrDataControlDeviceV1); #[derive(Debug, Error)] pub enum ZwlrDataControlDeviceV1Error { #[error(transparent)] - ClientError(Box), - #[error(transparent)] - WlSeatError(Box), - #[error("The source has already been used")] - AlreadyUsed, + DataControlError(#[from] DataControlError), } -efrom!(ZwlrDataControlDeviceV1Error, ClientError); -efrom!(ZwlrDataControlDeviceV1Error, WlSeatError); diff --git a/src/ifs/ipc/data_control/zwlr_data_control_offer_v1.rs b/src/ifs/ipc/data_control/zwlr_data_control_offer_v1.rs index 7c0f9197..df9a61a8 100644 --- a/src/ifs/ipc/data_control/zwlr_data_control_offer_v1.rs +++ b/src/ifs/ipc/data_control/zwlr_data_control_offer_v1.rs @@ -1,16 +1,11 @@ use { crate::{ - client::{Client, ClientError, ClientId}, - ifs::{ - ipc::{ - break_offer_loops, cancel_offer, - data_control::zwlr_data_control_device_v1::{ - WlrClipboardIpc, WlrPrimarySelectionIpc, ZwlrDataControlDeviceV1, - }, - destroy_data_offer, receive_data_offer, DataOffer, DataOfferId, DynDataOffer, - IpcLocation, OfferData, + ifs::ipc::data_control::{ + private::{ + logic::{self, DataControlError}, + DataControlOffer, DataControlOfferData, }, - wl_seat::WlSeatGlobal, + zwlr_data_control_device_v1::WlrDataControlIpc, }, leaks::Tracker, object::Object, @@ -22,54 +17,25 @@ use { pub struct ZwlrDataControlOfferV1 { pub id: ZwlrDataControlOfferV1Id, - pub offer_id: DataOfferId, - pub client: Rc, - pub device: Rc, - pub data: OfferData, - pub location: IpcLocation, + pub data: DataControlOfferData, pub tracker: Tracker, } -impl DataOffer for ZwlrDataControlOfferV1 { - type Device = ZwlrDataControlDeviceV1; +impl DataControlOffer for ZwlrDataControlOfferV1 { + type Ipc = WlrDataControlIpc; - fn offer_data(&self) -> &OfferData { + fn data(&self) -> &DataControlOfferData { &self.data } -} - -impl DynDataOffer for ZwlrDataControlOfferV1 { - fn offer_id(&self) -> DataOfferId { - self.offer_id - } - - fn client_id(&self) -> ClientId { - self.client.id - } fn send_offer(&self, mime_type: &str) { - ZwlrDataControlOfferV1::send_offer(self, mime_type) - } - - fn cancel(&self) { - match self.location { - IpcLocation::Clipboard => cancel_offer::(self), - IpcLocation::PrimarySelection => cancel_offer::(self), - } - } - - fn get_seat(&self) -> Rc { - self.device.seat.clone() - } - - fn is_privileged(&self) -> bool { - true + self.send_offer(mime_type); } } impl ZwlrDataControlOfferV1 { pub fn send_offer(&self, mime_type: &str) { - self.client.event(Offer { + self.data.client.event(Offer { self_id: self.id, mime_type, }) @@ -80,38 +46,24 @@ impl ZwlrDataControlOfferV1RequestHandler for ZwlrDataControlOfferV1 { type Error = ZwlrDataControlOfferV1Error; fn receive(&self, req: Receive, _slf: &Rc) -> Result<(), Self::Error> { - match self.location { - IpcLocation::Clipboard => { - receive_data_offer::(self, req.mime_type, req.fd) - } - IpcLocation::PrimarySelection => { - receive_data_offer::(self, req.mime_type, req.fd) - } - } + logic::data_offer_receive(self, req.mime_type, req.fd); Ok(()) } fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { - match self.location { - IpcLocation::Clipboard => destroy_data_offer::(self), - IpcLocation::PrimarySelection => destroy_data_offer::(self), - } - self.client.remove_obj(self)?; + logic::data_offer_destroy(self)?; Ok(()) } } object_base! { self = ZwlrDataControlOfferV1; - version = self.device.version; + version = self.data.device.data.version; } impl Object for ZwlrDataControlOfferV1 { fn break_loops(&self) { - match self.location { - IpcLocation::Clipboard => break_offer_loops::(self), - IpcLocation::PrimarySelection => break_offer_loops::(self), - } + logic::data_offer_break_loops(self); } } @@ -120,6 +72,5 @@ simple_add_obj!(ZwlrDataControlOfferV1); #[derive(Debug, Error)] pub enum ZwlrDataControlOfferV1Error { #[error(transparent)] - ClientError(Box), + DataControlError(#[from] DataControlError), } -efrom!(ZwlrDataControlOfferV1Error, ClientError); diff --git a/src/ifs/ipc/data_control/zwlr_data_control_source_v1.rs b/src/ifs/ipc/data_control/zwlr_data_control_source_v1.rs index 08488bd9..2186bd9a 100644 --- a/src/ifs/ipc/data_control/zwlr_data_control_source_v1.rs +++ b/src/ifs/ipc/data_control/zwlr_data_control_source_v1.rs @@ -1,17 +1,15 @@ use { crate::{ - client::{Client, ClientError}, - ifs::{ - ipc::{ - add_data_source_mime_type, break_source_loops, cancel_offers, - data_control::zwlr_data_control_device_v1::{ - WlrClipboardIpc, WlrPrimarySelectionIpc, + client::Client, + ifs::ipc::{ + data_control::{ + private::{ + logic::{self, DataControlError}, + DataControlSource, DataControlSourceData, }, - destroy_data_source, detach_seat, offer_source_to_x, - x_data_device::{XClipboardIpc, XIpcDevice, XPrimarySelectionIpc}, - DataSource, DynDataSource, IpcLocation, SourceData, + zwlr_data_control_device_v1::WlrDataControlIpc, }, - wl_seat::WlSeatGlobal, + IpcLocation, SourceData, }, leaks::Tracker, object::{Object, Version}, @@ -24,41 +22,23 @@ use { pub struct ZwlrDataControlSourceV1 { pub id: ZwlrDataControlSourceV1Id, - pub data: SourceData, - pub version: Version, - pub location: Cell, - pub used: Cell, + pub data: DataControlSourceData, pub tracker: Tracker, } -impl DataSource for ZwlrDataControlSourceV1 { - fn send_cancelled(&self, _seat: &Rc) { - ZwlrDataControlSourceV1::send_cancelled(self); - } -} +impl DataControlSource for ZwlrDataControlSourceV1 { + type Ipc = WlrDataControlIpc; -impl DynDataSource for ZwlrDataControlSourceV1 { - fn source_data(&self) -> &SourceData { + fn data(&self) -> &DataControlSourceData { &self.data } - fn send_send(&self, mime_type: &str, fd: Rc) { - ZwlrDataControlSourceV1::send_send(&self, mime_type, fd); + fn send_cancelled(&self) { + self.send_cancelled(); } - fn offer_to_x(self: Rc, dd: &Rc) { - match self.location.get() { - IpcLocation::Clipboard => offer_source_to_x::(self, dd), - IpcLocation::PrimarySelection => offer_source_to_x::(self, dd), - } - } - - fn detach_seat(&self, seat: &Rc) { - detach_seat(self, seat) - } - - fn cancel_unprivileged_offers(&self) { - cancel_offers(self, false) + fn send_send(&self, mime_type: &str, fd: Rc) { + self.send_send(mime_type, fd); } } @@ -66,16 +46,18 @@ impl ZwlrDataControlSourceV1 { pub fn new(id: ZwlrDataControlSourceV1Id, client: &Rc, version: Version) -> Self { Self { id, + data: DataControlSourceData { + data: SourceData::new(client), + version, + location: Cell::new(IpcLocation::Clipboard), + used: Cell::new(false), + }, tracker: Default::default(), - data: SourceData::new(client), - version, - location: Cell::new(IpcLocation::Clipboard), - used: Cell::new(false), } } pub fn send_send(&self, mime_type: &str, fd: Rc) { - self.data.client.event(Send { + self.data.data.client.event(Send { self_id: self.id, mime_type, fd, @@ -83,7 +65,7 @@ impl ZwlrDataControlSourceV1 { } pub fn send_cancelled(&self) { - self.data.client.event(Cancelled { self_id: self.id }) + self.data.data.client.event(Cancelled { self_id: self.id }) } } @@ -91,34 +73,24 @@ impl ZwlrDataControlSourceV1RequestHandler for ZwlrDataControlSourceV1 { type Error = ZwlrDataControlSourceV1Error; fn offer(&self, req: Offer, _slf: &Rc) -> Result<(), Self::Error> { - if self.used.get() { - return Err(ZwlrDataControlSourceV1Error::AlreadyUsed); - } - add_data_source_mime_type::(self, req.mime_type); + logic::data_source_offer(self, req.mime_type)?; Ok(()) } fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { - match self.location.get() { - IpcLocation::Clipboard => destroy_data_source::(self), - IpcLocation::PrimarySelection => destroy_data_source::(self), - } - self.data.client.remove_obj(self)?; + logic::data_source_destroy(self)?; Ok(()) } } object_base! { self = ZwlrDataControlSourceV1; - version = self.version; + version = self.data.version; } impl Object for ZwlrDataControlSourceV1 { fn break_loops(&self) { - match self.location.get() { - IpcLocation::Clipboard => break_source_loops::(self), - IpcLocation::PrimarySelection => break_source_loops::(self), - } + logic::data_source_break_loops(self); } } @@ -131,8 +103,5 @@ dedicated_add_obj!( #[derive(Debug, Error)] pub enum ZwlrDataControlSourceV1Error { #[error(transparent)] - ClientError(Box), - #[error("The source has already been used")] - AlreadyUsed, + DataControlError(#[from] DataControlError), } -efrom!(ZwlrDataControlSourceV1Error, ClientError);