diff --git a/src/client/objects.rs b/src/client/objects.rs index 51a93349..d4050cb9 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -1,6 +1,5 @@ use crate::client::{Client, ClientError}; use crate::ifs::wl_buffer::WlBuffer; -use crate::ifs::wl_data_source::WlDataSource; use crate::ifs::wl_display::WlDisplay; use crate::ifs::wl_region::WlRegion; use crate::ifs::wl_registry::WlRegistry; @@ -10,7 +9,6 @@ use crate::ifs::wl_surface::xdg_surface::XdgSurface; use crate::ifs::wl_surface::WlSurface; use crate::ifs::xdg_positioner::XdgPositioner; use crate::ifs::xdg_wm_base::XdgWmBase; -use crate::ifs::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; use crate::object::{Object, ObjectId}; use crate::tree::Node; use crate::utils::clonecell::CloneCell; @@ -23,6 +21,8 @@ use ahash::AHashMap; use std::cell::{RefCell, RefMut}; use std::mem; use std::rc::Rc; +use crate::ifs::ipc::wl_data_source::WlDataSource; +use crate::ifs::ipc::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; pub struct Objects { pub display: CloneCell>>, diff --git a/src/globals.rs b/src/globals.rs index 1023a0d7..f1fcaa69 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -4,11 +4,10 @@ use crate::ifs::wl_drm::WlDrmGlobal; use crate::ifs::wl_output::WlOutputGlobal; use crate::ifs::wl_registry::WlRegistry; use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1Global; use crate::object::{Interface, ObjectId}; use crate::utils::copyhashmap::CopyHashMap; use crate::{ - NumCell, State, WlCompositorGlobal, WlDataDeviceManagerGlobal, WlShmGlobal, + NumCell, State, WlCompositorGlobal, WlShmGlobal, WlSubcompositorGlobal, XdgWmBaseGlobal, ZwpLinuxDmabufV1Global, ZxdgDecorationManagerV1Global, }; use ahash::AHashMap; @@ -17,6 +16,8 @@ use std::error::Error; use std::fmt::{Display, Formatter}; use std::rc::Rc; use thiserror::Error; +use crate::ifs::ipc::wl_data_device_manager::WlDataDeviceManagerGlobal; +use crate::ifs::ipc::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1Global; #[derive(Debug, Error)] pub enum GlobalsError { diff --git a/src/ifs/ipc/mod.rs b/src/ifs/ipc/mod.rs new file mode 100644 index 00000000..a6131d6e --- /dev/null +++ b/src/ifs/ipc/mod.rs @@ -0,0 +1,206 @@ +use std::cell::{Cell, RefCell}; +use std::ops::{Deref, DerefMut}; +use std::rc::Rc; +use ahash::AHashSet; +use thiserror::Error; +use uapi::OwnedFd; +use crate::client::{Client, ClientId, WaylandObject}; +use crate::ifs::wl_seat::WlSeatGlobal; +use crate::object::ObjectId; +use crate::utils::clonecell::CloneCell; +use crate::utils::smallmap::SmallMap; + +pub mod wl_data_device; +pub mod wl_data_device_manager; +pub mod wl_data_offer; +pub mod wl_data_source; +pub mod zwp_primary_selection_device_manager_v1; +pub mod zwp_primary_selection_device_v1; +pub mod zwp_primary_selection_offer_v1; +pub mod zwp_primary_selection_source_v1; + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum Role { + Selection, + Dnd, +} + +pub trait Vtable: Sized { + type DeviceId: Eq + Copy; + type OfferId: Copy + From; + + type Device; + type Source; + type Offer: WaylandObject; + + fn device_id(dd: &Self::Device) -> Self::DeviceId; + fn get_offer_data(offer: &Self::Offer) -> &OfferData; + fn get_source_data(src: &Self::Source) -> &SourceData; + fn for_each_device(seat: &WlSeatGlobal, client: ClientId, f: C) + where C: FnMut(&Rc); + fn create_offer(client: &Rc, data: OfferData, id: ObjectId) -> Self::Offer; + fn send_selection(dd: &Self::Device, offer: Self::OfferId); + fn send_cancelled(source: &Self::Source); + fn get_offer_id(offer: &Self::Offer) -> Self::OfferId; + fn send_offer(dd: &Self::Device, offer: &Self::Offer); + fn send_mime_type(offer: &Self::Offer, mime_type: &str); + fn unset(seat: &Rc); + fn send_send(src: &Self::Source, mime_type: &str, fd: Rc); +} + +pub struct OfferData { + device_id: T::DeviceId, + source: CloneCell>>, + client: Rc, +} + +struct Attachment { + seat: Rc, + role: Role, + offers: SmallMap, 1>, +} + +impl Attachment { + fn detach_offers(&self) { + while let Some((_, offer)) = self.offers.pop() { + T::get_offer_data(&offer).source.set(None); + } + } +} + +#[derive(Debug, Error)] +pub enum IpcError { + #[error("The data source is already attached")] + AlreadyAttached, +} + +pub struct SourceData { + attachment: RefCell>>, + disconnecting: Cell, + mime_types: RefCell>, + client: Rc +} + +impl SourceData { + fn new(client: &Rc) -> Self { + Self { + attachment: Default::default(), + disconnecting: Cell::new(false), + mime_types: Default::default(), + client: client.clone(), + } + } +} + +pub fn attach_source( + src: &T::Source, + seat: &Rc, + role: Role, +) -> Result<(), IpcError> { + let src = T::get_source_data(src); + let mut attachment = src.attachment.borrow_mut(); + if attachment.is_some() { + return Err(IpcError::AlreadyAttached); + } + *attachment = Some(Attachment { + seat: seat.clone(), + role, + offers: Default::default(), + }); + Ok(()) +} + +pub fn detach_source(src: &T::Source) { + let data = T::get_source_data(src); + if data.disconnecting.get() { + return; + } + if let Some(attachment) = data.attachment.borrow_mut().take() { + attachment.detach_offers(); + } + T::send_cancelled(src); +} + +pub fn offer_source_to(src: &Rc, client: &Rc) { + let data = T::get_source_data(src); + let mut attachment = data.attachment.borrow_mut(); + let attachment = match attachment.deref_mut() { + Some(a) => a, + _ => { + log::error!("Trying to create an offer from a unattached data source"); + return; + } + }; + attachment.detach_offers(); + T::for_each_device(&attachment.seat, client.id, |dd| { + let id = match client.new_id() { + Ok(id) => id, + Err(e) => { + client.error(e); + return; + } + }; + let offer_data = OfferData { + device_id: T::device_id(dd), + source: CloneCell::new(Some(src.clone())), + client: client.clone(), + }; + let offer = Rc::new(T::create_offer(client, offer_data, id)); + attachment.offers.insert(T::device_id(dd), offer.clone()); + let mt = data.mime_types.borrow_mut(); + T::send_offer(dd, &offer); + for mt in mt.deref() { + T::send_mime_type(&offer, mt); + } + if attachment.role == Role::Selection { + T::send_selection(dd, T::get_offer_id(&offer)); + } + client.add_server_obj(&offer); + }); +} + + +fn add_mime_type(src: &T::Source, mime_type: &str) { + let data = T::get_source_data(src); + if data + .mime_types + .borrow_mut() + .insert(mime_type.to_string()) + { + if let Some(attachment) = data.attachment.borrow_mut().deref_mut() { + for (_, offer) in &attachment.offers { + T::send_mime_type(&offer, mime_type); + let data = T::get_offer_data(&offer); + data.client.flush(); + } + } + } +} + +fn disconnect_source(src: &T::Source) { + let data = T::get_source_data(src); + data.disconnecting.set(true); + if let Some(attachment) = data.attachment.borrow_mut().take() { + attachment.detach_offers(); + T::unset(&attachment.seat); + } +} + +fn disconnect_offer(offer: &T::Offer) { + let data = T::get_offer_data(offer); + if let Some(src) = data.source.set(None) { + let src_data = T::get_source_data(&src); + if let Some(attachment) = src_data.attachment.borrow_mut().deref_mut() { + attachment.offers.remove(&data.device_id); + } + } +} + +fn receive(offer: &T::Offer, mime_type: &str, fd: Rc) { + let data = T::get_offer_data(offer); + if let Some(src) = data.source.get() { + T::send_send(&src, mime_type, fd); + let data = T::get_source_data(&src); + data.client.flush(); + } +} diff --git a/src/ifs/wl_data_device.rs b/src/ifs/ipc/wl_data_device.rs similarity index 62% rename from src/ifs/wl_data_device.rs rename to src/ifs/ipc/wl_data_device.rs index 48693669..03a43d5e 100644 --- a/src/ifs/wl_data_device.rs +++ b/src/ifs/ipc/wl_data_device.rs @@ -1,14 +1,17 @@ -use crate::client::ClientError; -use crate::ifs::wl_data_device_manager::WlDataDeviceManager; -use crate::ifs::wl_data_source::WlDataSourceError; -use crate::ifs::wl_seat::WlSeat; -use crate::object::Object; +use crate::client::{Client, ClientError, ClientId}; +use crate::ifs::ipc::wl_data_device_manager::WlDataDeviceManager; +use crate::ifs::ipc::wl_data_source::{WlDataSource}; +use crate::ifs::wl_seat::{WlSeat, WlSeatError, WlSeatGlobal}; +use crate::object::{Object, ObjectId}; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; use crate::wire::wl_data_device::*; use crate::wire::{WlDataDeviceId, WlDataOfferId}; use std::rc::Rc; use thiserror::Error; +use uapi::OwnedFd; +use crate::ifs::ipc::{OfferData, SourceData, Vtable}; +use crate::ifs::ipc::wl_data_offer::WlDataOffer; #[allow(dead_code)] const ROLE: u32 = 0; @@ -16,7 +19,7 @@ const ROLE: u32 = 0; pub struct WlDataDevice { pub id: WlDataDeviceId, pub manager: Rc, - seat: Rc, + pub seat: Rc, } impl WlDataDevice { @@ -66,6 +69,66 @@ impl WlDataDevice { } } +impl Vtable for WlDataDevice { + type DeviceId = WlDataDeviceId; + type OfferId = WlDataOfferId; + type Device = WlDataDevice; + type Source = WlDataSource; + type Offer = WlDataOffer; + + fn device_id(dd: &Self::Device) -> Self::DeviceId { + dd.id + } + + fn get_offer_data(offer: &Self::Offer) -> &OfferData { + &offer.offer_data + } + + fn get_source_data(src: &Self::Source) -> &SourceData { + &src.data + } + + fn for_each_device(seat: &WlSeatGlobal, client: ClientId, f: C) where C: FnMut(&Rc) { + seat.for_each_data_device(0, client, f); + } + + fn create_offer(client: &Rc, offer_data: OfferData, id: ObjectId) -> Self::Offer { + WlDataOffer { + id: id.into(), + client: client.clone(), + offer_data, + } + } + + fn send_selection(dd: &Self::Device, offer: Self::OfferId) { + dd.send_selection(offer); + } + + fn send_cancelled(source: &Self::Source) { + source.send_cancelled(); + } + + fn get_offer_id(offer: &Self::Offer) -> Self::OfferId { + offer.id + } + + fn send_offer(dd: &Self::Device, offer: &Self::Offer) { + dd.send_data_offer(offer.id); + } + + fn send_mime_type(offer: &Self::Offer, mime_type: &str) { + offer.send_offer(mime_type); + } + + fn unset(seat: &Rc) { + seat.unset_selection(); + } + + fn send_send(src: &Self::Source, mime_type: &str, fd: Rc) { + src.send_send(mime_type, fd); + } +} + object_base! { WlDataDevice, WlDataDeviceError; @@ -116,11 +179,11 @@ pub enum SetSelectionError { #[error(transparent)] ClientError(Box), #[error(transparent)] - WlDataSourceError(Box), + WlSeatError(Box), } efrom!(SetSelectionError, ParseFailed, MsgParserError); efrom!(SetSelectionError, ClientError); -efrom!(SetSelectionError, WlDataSourceError); +efrom!(SetSelectionError, WlSeatError); #[derive(Debug, Error)] pub enum ReleaseError { diff --git a/src/ifs/wl_data_device_manager.rs b/src/ifs/ipc/wl_data_device_manager.rs similarity index 97% rename from src/ifs/wl_data_device_manager.rs rename to src/ifs/ipc/wl_data_device_manager.rs index 5c87cd4c..a7464597 100644 --- a/src/ifs/wl_data_device_manager.rs +++ b/src/ifs/ipc/wl_data_device_manager.rs @@ -1,7 +1,7 @@ use crate::client::{Client, ClientError}; use crate::globals::{Global, GlobalName}; -use crate::ifs::wl_data_device::WlDataDevice; -use crate::ifs::wl_data_source::WlDataSource; +use crate::ifs::ipc::wl_data_device::WlDataDevice; +use crate::ifs::ipc::wl_data_source::WlDataSource; use crate::object::Object; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; diff --git a/src/ifs/wl_data_offer.rs b/src/ifs/ipc/wl_data_offer.rs similarity index 66% rename from src/ifs/wl_data_offer.rs rename to src/ifs/ipc/wl_data_offer.rs index 83edb3a7..a8e54661 100644 --- a/src/ifs/wl_data_offer.rs +++ b/src/ifs/ipc/wl_data_offer.rs @@ -1,16 +1,13 @@ use crate::client::{Client, ClientError}; -use crate::ifs::wl_data_source::WlDataSource; -use crate::ifs::wl_seat::WlSeatGlobal; use crate::object::Object; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; -use crate::utils::clonecell::CloneCell; use crate::wire::wl_data_offer::*; -use crate::wire::WlDataOfferId; -use std::mem; -use std::ops::Deref; +use crate::wire::{WlDataOfferId}; use std::rc::Rc; use thiserror::Error; +use crate::ifs::ipc::{disconnect_offer, OfferData, receive}; +use crate::ifs::ipc::wl_data_device::WlDataDevice; #[allow(dead_code)] const INVALID_FINISH: u32 = 0; @@ -21,61 +18,15 @@ const INVALID_ACTION: u32 = 2; #[allow(dead_code)] const INVALID_OFFER: u32 = 3; -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum DataOfferRole { - Selection, -} pub struct WlDataOffer { pub id: WlDataOfferId, pub client: Rc, - pub role: DataOfferRole, - pub source: CloneCell>>, + pub offer_data: OfferData, } 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(); - let mut sent_offer = false; - seat.for_each_data_device(0, client.id, |device| { - if !mem::replace(&mut sent_offer, true) { - device.send_data_offer(slf.id); - } - for mt in mt.deref() { - slf.send_offer(mt); - } - match role { - DataOfferRole::Selection => device.send_selection(id), - } - }); - client.add_server_obj(&slf); - if !sent_offer { - let _ = client.remove_obj(&*slf); - None - } else { - Some(slf) - } - } - - pub fn send_offer(self: &Rc, mime_type: &str) { + pub fn send_offer(&self, mime_type: &str) { self.client.event(Offer { self_id: self.id, mime_type, @@ -89,22 +40,13 @@ impl WlDataOffer { fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ReceiveError> { let req: Receive = self.client.parse(self, parser)?; - if let Some(src) = self.source.get() { - src.send_send(req.mime_type, req.fd); - src.client.flush(); - } + receive::(self, req.mime_type, req.fd); 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(); + disconnect_offer::(self); self.client.remove_obj(self)?; Ok(()) } @@ -136,7 +78,7 @@ impl Object for WlDataOffer { } fn break_loops(&self) { - self.disconnect(); + disconnect_offer::(self); } } diff --git a/src/ifs/ipc/wl_data_source.rs b/src/ifs/ipc/wl_data_source.rs new file mode 100644 index 00000000..2d840a82 --- /dev/null +++ b/src/ifs/ipc/wl_data_source.rs @@ -0,0 +1,123 @@ +use crate::client::{Client, ClientError}; +use crate::object::Object; +use crate::utils::buffd::MsgParser; +use crate::utils::buffd::MsgParserError; +use crate::wire::wl_data_source::*; +use crate::wire::{WlDataSourceId}; +use std::rc::Rc; +use thiserror::Error; +use uapi::OwnedFd; +use crate::ifs::ipc::{add_mime_type, disconnect_source, SourceData}; +use crate::ifs::ipc::wl_data_device::WlDataDevice; + +#[allow(dead_code)] +const INVALID_ACTION_MASK: u32 = 0; +#[allow(dead_code)] +const INVALID_SOURCE: u32 = 1; + +pub struct WlDataSource { + pub id: WlDataSourceId, + pub data: SourceData, +} + +impl WlDataSource { + pub fn new(id: WlDataSourceId, client: &Rc) -> Self { + Self { + id, + data: SourceData::new(client), + } + } + + pub fn send_cancelled(&self) { + self.data.client.event(Cancelled { self_id: self.id }) + } + + pub fn send_send(&self, mime_type: &str, fd: Rc) { + self.data.client.event(Send { + self_id: self.id, + mime_type, + fd, + }) + } + + fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), OfferError> { + let req: Offer = self.data.client.parse(self, parser)?; + add_mime_type::(self, req.mime_type); + Ok(()) + } + + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.data.client.parse(self, parser)?; + disconnect_source::(self); + self.data.client.remove_obj(self)?; + Ok(()) + } + + fn set_actions(&self, parser: MsgParser<'_, '_>) -> Result<(), SetActionsError> { + let _req: SetActions = self.data.client.parse(self, parser)?; + Ok(()) + } +} + +object_base! { + WlDataSource, WlDataSourceError; + + OFFER => offer, + DESTROY => destroy, + SET_ACTIONS => set_actions, +} + +impl Object for WlDataSource { + fn num_requests(&self) -> u32 { + SET_ACTIONS + 1 + } + + fn break_loops(&self) { + disconnect_source::(self); + } +} + +dedicated_add_obj!(WlDataSource, WlDataSourceId, wl_data_source); + +#[derive(Debug, Error)] +pub enum WlDataSourceError { + #[error(transparent)] + ClientError(Box), + #[error("Could not process `offer` request")] + OfferError(#[from] OfferError), + #[error("Could not process `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process `set_actions` request")] + SetActionsError(#[from] SetActionsError), +} +efrom!(WlDataSourceError, ClientError); + +#[derive(Debug, Error)] +pub enum OfferError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(OfferError, ParseFailed, MsgParserError); +efrom!(OfferError, ClientError); + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError); + +#[derive(Debug, Error)] +pub enum SetActionsError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(SetActionsError, ParseFailed, MsgParserError); +efrom!(SetActionsError, ClientError); diff --git a/src/ifs/zwp_primary_selection_device_manager_v1.rs b/src/ifs/ipc/zwp_primary_selection_device_manager_v1.rs similarity index 96% rename from src/ifs/zwp_primary_selection_device_manager_v1.rs rename to src/ifs/ipc/zwp_primary_selection_device_manager_v1.rs index f687932b..da51b89c 100644 --- a/src/ifs/zwp_primary_selection_device_manager_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_device_manager_v1.rs @@ -1,7 +1,5 @@ use crate::client::{Client, ClientError}; use crate::globals::{Global, GlobalName}; -use crate::ifs::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; -use crate::ifs::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; use crate::object::Object; use crate::utils::buffd::MsgParser; use crate::utils::buffd::MsgParserError; @@ -9,6 +7,8 @@ use crate::wire::zwp_primary_selection_device_manager_v1::*; use crate::wire::ZwpPrimarySelectionDeviceManagerV1Id; use std::rc::Rc; use thiserror::Error; +use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; +use crate::ifs::ipc::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; pub struct ZwpPrimarySelectionDeviceManagerV1Global { name: GlobalName, diff --git a/src/ifs/zwp_primary_selection_device_v1.rs b/src/ifs/ipc/zwp_primary_selection_device_v1.rs similarity index 58% rename from src/ifs/zwp_primary_selection_device_v1.rs rename to src/ifs/ipc/zwp_primary_selection_device_v1.rs index 895dd7da..c7fe1b99 100644 --- a/src/ifs/zwp_primary_selection_device_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_device_v1.rs @@ -1,13 +1,16 @@ -use crate::client::ClientError; -use crate::ifs::wl_seat::WlSeat; -use crate::ifs::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1; -use crate::ifs::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1Error; -use crate::object::Object; +use crate::client::{Client, ClientError, ClientId}; +use crate::ifs::wl_seat::{WlSeat, WlSeatError, WlSeatGlobal}; +use crate::object::{Object, ObjectId}; use crate::utils::buffd::{MsgParser, MsgParserError}; use crate::wire::zwp_primary_selection_device_v1::*; use crate::wire::{ZwpPrimarySelectionDeviceV1Id, ZwpPrimarySelectionOfferV1Id}; use std::rc::Rc; use thiserror::Error; +use uapi::OwnedFd; +use crate::ifs::ipc::{OfferData, SourceData, Vtable}; +use crate::ifs::ipc::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1; +use crate::ifs::ipc::zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1; +use crate::ifs::ipc::zwp_primary_selection_source_v1::{ZwpPrimarySelectionSourceV1}; pub struct ZwpPrimarySelectionDeviceV1 { pub id: ZwpPrimarySelectionDeviceV1Id, @@ -61,6 +64,66 @@ impl ZwpPrimarySelectionDeviceV1 { } } +impl Vtable for ZwpPrimarySelectionDeviceV1 { + type DeviceId = ZwpPrimarySelectionDeviceV1Id; + type OfferId = ZwpPrimarySelectionOfferV1Id; + type Device = ZwpPrimarySelectionDeviceV1; + type Source = ZwpPrimarySelectionSourceV1; + type Offer = ZwpPrimarySelectionOfferV1; + + fn device_id(dd: &Self::Device) -> Self::DeviceId { + dd.id + } + + fn get_offer_data(offer: &Self::Offer) -> &OfferData { + &offer.offer_data + } + + fn get_source_data(src: &Self::Source) -> &SourceData { + &src.data + } + + fn for_each_device(seat: &WlSeatGlobal, client: ClientId, f: C) where C: FnMut(&Rc) { + seat.for_each_primary_selection_device(0, client, f) + } + + fn create_offer(client: &Rc, offer_data: OfferData, id: ObjectId) -> Self::Offer { + ZwpPrimarySelectionOfferV1 { + id: id.into(), + client: client.clone(), + offer_data, + } + } + + fn send_selection(dd: &Self::Device, offer: Self::OfferId) { + dd.send_selection(offer); + } + + fn send_cancelled(source: &Self::Source) { + source.send_cancelled(); + } + + fn get_offer_id(offer: &Self::Offer) -> Self::OfferId { + offer.id + } + + fn send_offer(dd: &Self::Device, offer: &Self::Offer) { + dd.send_data_offer(offer.id); + } + + fn send_mime_type(offer: &Self::Offer, mime_type: &str) { + offer.send_offer(mime_type); + } + + fn unset(seat: &Rc) { + seat.unset_primary_selection(); + } + + fn send_send(src: &Self::Source, mime_type: &str, fd: Rc) { + src.send_send(mime_type, fd); + } +} + object_base! { ZwpPrimarySelectionDeviceV1, ZwpPrimarySelectionDeviceV1Error; @@ -98,11 +161,11 @@ pub enum SetSelectionError { #[error(transparent)] ClientError(Box), #[error(transparent)] - ZwpPrimarySelectionSourceV1Error(Box), + WlSeatError(Box), } efrom!(SetSelectionError, ParseFailed, MsgParserError); efrom!(SetSelectionError, ClientError); -efrom!(SetSelectionError, ZwpPrimarySelectionSourceV1Error); +efrom!(SetSelectionError, WlSeatError); #[derive(Debug, Error)] pub enum DestroyError { diff --git a/src/ifs/zwp_primary_selection_offer_v1.rs b/src/ifs/ipc/zwp_primary_selection_offer_v1.rs similarity index 55% rename from src/ifs/zwp_primary_selection_offer_v1.rs rename to src/ifs/ipc/zwp_primary_selection_offer_v1.rs index 0fb96aca..5fa98f7a 100644 --- a/src/ifs/zwp_primary_selection_offer_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_offer_v1.rs @@ -1,61 +1,21 @@ use crate::client::{Client, ClientError}; -use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; use crate::object::Object; use crate::utils::buffd::{MsgParser, MsgParserError}; -use crate::utils::clonecell::CloneCell; use crate::wire::zwp_primary_selection_offer_v1::*; use crate::wire::ZwpPrimarySelectionOfferV1Id; -use std::mem; -use std::ops::Deref; use std::rc::Rc; use thiserror::Error; +use crate::ifs::ipc::{disconnect_offer, OfferData, receive}; +use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; pub struct ZwpPrimarySelectionOfferV1 { pub id: ZwpPrimarySelectionOfferV1Id, pub client: Rc, - pub source: CloneCell>>, + pub offer_data: OfferData, } impl ZwpPrimarySelectionOfferV1 { - pub fn create( - client: &Rc, - 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(), - source: CloneCell::new(Some(src.clone())), - }); - let mt = src.mime_types.borrow_mut(); - let mut sent_offer = false; - seat.for_each_primary_selection_device(0, client.id, |device| { - if !mem::replace(&mut sent_offer, true) { - device.send_data_offer(slf.id); - } - for mt in mt.deref() { - slf.send_offer(mt); - } - device.send_selection(id); - }); - client.add_server_obj(&slf); - if !sent_offer { - let _ = client.remove_obj(&*slf); - None - } else { - Some(slf) - } - } - - pub fn send_offer(self: &Rc, mime_type: &str) { + pub fn send_offer(&self, mime_type: &str) { self.client.event(Offer { self_id: self.id, mime_type, @@ -64,22 +24,13 @@ impl ZwpPrimarySelectionOfferV1 { fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ReceiveError> { let req: Receive = self.client.parse(self, parser)?; - if let Some(src) = self.source.get() { - src.send_send(req.mime_type, req.fd); - src.client.flush(); - } + receive::(self, req.mime_type, req.fd); Ok(()) } - fn disconnect(&self) { - if let Some(src) = self.source.set(None) { - src.clear_offer(); - } - } - fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { let _req: Destroy = self.client.parse(self, parser)?; - self.disconnect(); + disconnect_offer::(self); self.client.remove_obj(self)?; Ok(()) } @@ -98,7 +49,7 @@ impl Object for ZwpPrimarySelectionOfferV1 { } fn break_loops(&self) { - self.disconnect(); + disconnect_offer::(self); } } diff --git a/src/ifs/ipc/zwp_primary_selection_source_v1.rs b/src/ifs/ipc/zwp_primary_selection_source_v1.rs new file mode 100644 index 00000000..0795e223 --- /dev/null +++ b/src/ifs/ipc/zwp_primary_selection_source_v1.rs @@ -0,0 +1,103 @@ +use crate::client::{Client, ClientError}; +use crate::object::Object; +use crate::utils::buffd::{MsgParser, MsgParserError}; +use crate::wire::zwp_primary_selection_source_v1::*; +use crate::wire::ZwpPrimarySelectionSourceV1Id; +use std::rc::Rc; +use thiserror::Error; +use uapi::OwnedFd; +use crate::ifs::ipc::{add_mime_type, disconnect_source, SourceData}; +use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; + +pub struct ZwpPrimarySelectionSourceV1 { + pub id: ZwpPrimarySelectionSourceV1Id, + pub data: SourceData, +} + +impl ZwpPrimarySelectionSourceV1 { + pub fn new(id: ZwpPrimarySelectionSourceV1Id, client: &Rc) -> Self { + Self { + id, + data: SourceData::new(client), + } + } + + pub fn send_cancelled(&self) { + self.data.client.event(Cancelled { self_id: self.id }) + } + + pub fn send_send(&self, mime_type: &str, fd: Rc) { + self.data.client.event(Send { + self_id: self.id, + mime_type, + fd, + }) + } + + fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), OfferError> { + let req: Offer = self.data.client.parse(self, parser)?; + add_mime_type::(self, req.mime_type); + Ok(()) + } + + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.data.client.parse(self, parser)?; + disconnect_source::(self); + self.data.client.remove_obj(self)?; + Ok(()) + } +} + +object_base! { + ZwpPrimarySelectionSourceV1, ZwpPrimarySelectionSourceV1Error; + + OFFER => offer, + DESTROY => destroy, +} + +impl Object for ZwpPrimarySelectionSourceV1 { + fn num_requests(&self) -> u32 { + DESTROY + 1 + } + + fn break_loops(&self) { + disconnect_source::(self); + } +} + +dedicated_add_obj!( + ZwpPrimarySelectionSourceV1, + ZwpPrimarySelectionSourceV1Id, + zwp_primary_selection_source +); + +#[derive(Debug, Error)] +pub enum ZwpPrimarySelectionSourceV1Error { + #[error(transparent)] + ClientError(Box), + #[error("Could not process `offer` request")] + OfferError(#[from] OfferError), + #[error("Could not process `destroy` request")] + DestroyError(#[from] DestroyError), +} +efrom!(ZwpPrimarySelectionSourceV1Error, ClientError); + +#[derive(Debug, Error)] +pub enum OfferError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(OfferError, ParseFailed, MsgParserError); +efrom!(OfferError, ClientError); + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseFailed(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ParseFailed, MsgParserError); +efrom!(DestroyError, ClientError); diff --git a/src/ifs/mod.rs b/src/ifs/mod.rs index 9ecdadc8..448892eb 100644 --- a/src/ifs/mod.rs +++ b/src/ifs/mod.rs @@ -3,10 +3,6 @@ pub mod org_kde_kwin_server_decoration_manager; pub mod wl_buffer; pub mod wl_callback; pub mod wl_compositor; -pub mod wl_data_device; -pub mod wl_data_device_manager; -pub mod wl_data_offer; -pub mod wl_data_source; pub mod wl_display; pub mod wl_drm; pub mod wl_output; @@ -21,9 +17,6 @@ pub mod xdg_positioner; pub mod xdg_wm_base; pub mod zwp_linux_buffer_params_v1; pub mod zwp_linux_dmabuf_v1; -pub mod zwp_primary_selection_device_manager_v1; -pub mod zwp_primary_selection_device_v1; -pub mod zwp_primary_selection_offer_v1; -pub mod zwp_primary_selection_source_v1; pub mod zxdg_decoration_manager_v1; pub mod zxdg_toplevel_decoration_v1; +pub mod ipc; diff --git a/src/ifs/wl_data_source.rs b/src/ifs/wl_data_source.rs deleted file mode 100644 index e98c22e3..00000000 --- a/src/ifs/wl_data_source.rs +++ /dev/null @@ -1,206 +0,0 @@ -use crate::client::{Client, ClientError}; -use crate::ifs::wl_data_offer::{DataOfferRole, WlDataOffer}; -use crate::ifs::wl_seat::WlSeatGlobal; -use crate::object::Object; -use crate::utils::buffd::MsgParser; -use crate::utils::buffd::MsgParserError; -use crate::utils::clonecell::{CloneCell, UnsafeCellCloneSafe}; -use crate::wire::wl_data_source::*; -use crate::wire::WlDataSourceId; -use ahash::AHashSet; -use std::cell::RefCell; -use std::rc::Rc; -use thiserror::Error; -use uapi::OwnedFd; - -#[allow(dead_code)] -const INVALID_ACTION_MASK: u32 = 0; -#[allow(dead_code)] -const INVALID_SOURCE: u32 = 1; - -#[derive(Clone)] -struct Attachment { - seat: Rc, - role: DataOfferRole, -} - -unsafe impl UnsafeCellCloneSafe for Attachment {} - -pub struct WlDataSource { - pub id: WlDataSourceId, - pub client: Rc, - pub mime_types: RefCell>, - attachment: CloneCell>, - offer: CloneCell>>, -} - -impl WlDataSource { - pub fn new(id: WlDataSourceId, client: &Rc) -> Self { - Self { - id, - client: client.clone(), - mime_types: RefCell::new(Default::default()), - attachment: Default::default(), - offer: Default::default(), - } - } - - pub fn attach( - &self, - seat: &Rc, - role: DataOfferRole, - ) -> Result<(), WlDataSourceError> { - if self.attachment.get().is_some() { - return Err(WlDataSourceError::AlreadyAttached); - } - self.attachment.set(Some(Attachment { - seat: seat.clone(), - role, - })); - Ok(()) - } - - pub fn detach(self: &Rc) { - self.attachment.set(None); - if let Some(offer) = self.offer.set(None) { - offer.source.set(None); - } - self.send_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 send_cancelled(self: &Rc) { - self.client.event(Cancelled { self_id: self.id }) - } - - pub fn send_send(&self, mime_type: &str, fd: Rc) { - self.client.event(Send { - self_id: self.id, - mime_type, - 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.send_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(()) - } - - fn set_actions(&self, parser: MsgParser<'_, '_>) -> Result<(), SetActionsError> { - let _req: SetActions = self.client.parse(self, parser)?; - Ok(()) - } -} - -object_base! { - WlDataSource, WlDataSourceError; - - OFFER => offer, - DESTROY => destroy, - SET_ACTIONS => set_actions, -} - -impl Object for WlDataSource { - fn num_requests(&self) -> u32 { - SET_ACTIONS + 1 - } - - fn break_loops(&self) { - self.disconnect(); - } -} - -dedicated_add_obj!(WlDataSource, WlDataSourceId, wl_data_source); - -#[derive(Debug, Error)] -pub enum WlDataSourceError { - #[error(transparent)] - ClientError(Box), - #[error("Could not process `offer` request")] - OfferError(#[from] OfferError), - #[error("Could not process `destroy` request")] - DestroyError(#[from] DestroyError), - #[error("Could not process `set_actions` request")] - SetActionsError(#[from] SetActionsError), - #[error("The data source is already attached")] - AlreadyAttached, -} -efrom!(WlDataSourceError, ClientError); - -#[derive(Debug, Error)] -pub enum OfferError { - #[error("Parsing failed")] - ParseFailed(#[source] Box), - #[error(transparent)] - ClientError(Box), -} -efrom!(OfferError, ParseFailed, MsgParserError); -efrom!(OfferError, ClientError); - -#[derive(Debug, Error)] -pub enum DestroyError { - #[error("Parsing failed")] - ParseFailed(#[source] Box), - #[error(transparent)] - ClientError(Box), -} -efrom!(DestroyError, ParseFailed, MsgParserError); -efrom!(DestroyError, ClientError); - -#[derive(Debug, Error)] -pub enum SetActionsError { - #[error("Parsing failed")] - ParseFailed(#[source] Box), - #[error(transparent)] - ClientError(Box), -} -efrom!(SetActionsError, ParseFailed, MsgParserError); -efrom!(SetActionsError, ClientError); diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index a653c801..4a511971 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -8,18 +8,11 @@ use crate::client::{Client, ClientError, ClientId}; use crate::cursor::{Cursor, KnownCursor}; use crate::fixed::Fixed; use crate::globals::{Global, GlobalName}; -use crate::ifs::wl_data_device::WlDataDevice; -use crate::ifs::wl_data_offer::DataOfferRole; -use crate::ifs::wl_data_source::{WlDataSource, WlDataSourceError}; use crate::ifs::wl_seat::wl_keyboard::{WlKeyboard, WlKeyboardError, REPEAT_INFO_SINCE}; use crate::ifs::wl_seat::wl_pointer::WlPointer; use crate::ifs::wl_seat::wl_touch::WlTouch; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; -use crate::ifs::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; -use crate::ifs::zwp_primary_selection_source_v1::{ - ZwpPrimarySelectionSourceV1, ZwpPrimarySelectionSourceV1Error, -}; -use crate::object::Object; +use crate::object::{Object, ObjectId}; use crate::tree::{FloatNode, FoundNode, Node}; use crate::utils::asyncevent::AsyncEvent; use crate::utils::buffd::MsgParser; @@ -30,8 +23,8 @@ use crate::utils::linkedlist::LinkedList; use crate::utils::smallmap::SmallMap; use crate::wire::wl_seat::*; use crate::wire::{ - WlDataDeviceId, WlDataOfferId, WlKeyboardId, WlPointerId, WlSeatId, - ZwpPrimarySelectionDeviceV1Id, ZwpPrimarySelectionOfferV1Id, + WlDataDeviceId, WlKeyboardId, WlPointerId, WlSeatId, + ZwpPrimarySelectionDeviceV1Id, }; use crate::xkbcommon::{XkbContext, XkbState}; use crate::{NumCell, State}; @@ -44,6 +37,12 @@ use std::io::Write; use std::rc::Rc; use thiserror::Error; use uapi::{c, OwnedFd}; +use crate::ifs::ipc; +use crate::ifs::ipc::IpcError; +use crate::ifs::ipc::wl_data_device::WlDataDevice; +use crate::ifs::ipc::wl_data_source::WlDataSource; +use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; +use crate::ifs::ipc::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1; const POINTER: u32 = 1; const KEYBOARD: u32 = 2; @@ -159,56 +158,49 @@ impl WlSeatGlobal { } } - pub fn set_selection( + fn set_selection_( self: &Rc, - selection: Option>, - ) -> Result<(), WlDataSourceError> { - if let Some(new) = &selection { - new.attach(self, DataOfferRole::Selection)?; + field: &CloneCell>>, + src: Option>, + ) -> Result<(), WlSeatError> { + if let Some(new) = &src { + ipc::attach_source::(new, self, ipc::Role::Selection)?; } - if let Some(old) = self.selection.set(selection.clone()) { - old.detach(); + if let Some(old) = field.set(src.clone()) { + ipc::detach_source::(&old); } 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| { - device.send_selection(WlDataOfferId::NONE); - }); - } + match src { + Some(src) => ipc::offer_source_to::(&src, &client), + _ => T::for_each_device(self, client.id, |device| { + T::send_selection(device, ObjectId::NONE.into()); + }), } client.flush(); } Ok(()) } + pub fn unset_selection(self: &Rc) { + let _ = self.set_selection(None); + } + + pub fn set_selection( + self: &Rc, + selection: Option>, + ) -> Result<(), WlSeatError> { + self.set_selection_::(&self.selection, selection) + } + + pub fn unset_primary_selection(self: &Rc) { + let _ = self.set_primary_selection(None); + } + pub fn set_primary_selection( self: &Rc, selection: Option>, - ) -> Result<(), ZwpPrimarySelectionSourceV1Error> { - if let Some(new) = &selection { - new.attach(self)?; - } - if let Some(old) = self.primary_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_primary_selection_device(0, client.id, |device| { - device.send_selection(ZwpPrimarySelectionOfferV1Id::NONE); - }); - } - } - client.flush(); - } - Ok(()) + ) -> Result<(), WlSeatError> { + self.set_selection_::(&self.primary_selection, selection) } pub fn set_known_cursor(&self, cursor: KnownCursor) { @@ -443,6 +435,8 @@ pub enum WlSeatError { ReleaseError(#[from] ReleaseError), #[error(transparent)] ClientError(Box), + #[error(transparent)] + IpcError(#[from] IpcError), } efrom!(WlSeatError, ClientError); diff --git a/src/ifs/wl_seat/handling.rs b/src/ifs/wl_seat/handling.rs index 33f67568..6997fb01 100644 --- a/src/ifs/wl_seat/handling.rs +++ b/src/ifs/wl_seat/handling.rs @@ -1,7 +1,6 @@ use crate::backend::{KeyState, OutputId, ScrollAxis, SeatEvent, SeatId}; -use crate::client::ClientId; +use crate::client::{Client, ClientId}; use crate::fixed::Fixed; -use crate::ifs::wl_data_device::WlDataDevice; 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::{ @@ -11,13 +10,16 @@ use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; use crate::ifs::wl_surface::xdg_surface::XdgSurface; use crate::ifs::wl_surface::WlSurface; -use crate::ifs::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; use crate::tree::{FloatNode, FoundNode, Node}; use crate::utils::smallmap::SmallMap; -use crate::wire::{WlDataOfferId, ZwpPrimarySelectionOfferV1Id}; use crate::xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP}; use std::ops::{Deref, DerefMut}; use std::rc::Rc; +use crate::ifs::ipc; +use crate::ifs::ipc::wl_data_device::WlDataDevice; +use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; +use crate::object::ObjectId; +use crate::utils::clonecell::CloneCell; #[derive(Default)] pub struct NodeSeatState { @@ -243,26 +245,17 @@ impl WlSeatGlobal { }); if old.client_id() != Some(surface.client.id) { - match self.selection.get() { - None => { - self.surface_data_device_event(0, &surface, |dd| { - dd.send_selection(WlDataOfferId::NONE) - }); - } - Some(sel) => { - sel.create_offer(&surface.client); - } - } - match self.primary_selection.get() { - None => { - self.surface_primary_selection_device_event(0, &surface, |dd| { - dd.send_selection(ZwpPrimarySelectionOfferV1Id::NONE) - }); - } - Some(sel) => { - sel.create_offer(&surface.client); - } - } + self.offer_selection::(&self.selection, &surface.client); + self.offer_selection::(&self.primary_selection, &surface.client); + } + } + + fn offer_selection(&self, field: &CloneCell>>, client: &Rc) { + match field.get() { + Some(sel) => ipc::offer_source_to::(&sel, &client), + None => T::for_each_device(self, client.id, |dd| { + T::send_selection(dd, ObjectId::NONE.into()); + }), } } @@ -358,28 +351,6 @@ impl WlSeatGlobal { client.flush(); } - fn surface_data_device_event(&self, ver: u32, surface: &WlSurface, mut f: F) - where - F: FnMut(&Rc), - { - let client = &surface.client; - self.for_each_data_device(ver, client.id, |p| { - f(p); - }); - client.flush(); - } - - fn surface_primary_selection_device_event(&self, ver: u32, surface: &WlSurface, mut f: F) - where - F: FnMut(&Rc), - { - let client = &surface.client; - self.for_each_primary_selection_device(ver, client.id, |p| { - f(p); - }); - client.flush(); - } - fn set_new_position(self: &Rc, x: Fixed, y: Fixed) { self.pos.set((x, y)); self.handle_new_position(true); diff --git a/src/ifs/zwp_primary_selection_source_v1.rs b/src/ifs/zwp_primary_selection_source_v1.rs deleted file mode 100644 index ad8c5585..00000000 --- a/src/ifs/zwp_primary_selection_source_v1.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::client::{Client, ClientError}; -use crate::ifs::wl_seat::WlSeatGlobal; -use crate::ifs::zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1; -use crate::object::Object; -use crate::utils::buffd::{MsgParser, MsgParserError}; -use crate::utils::clonecell::CloneCell; -use crate::wire::zwp_primary_selection_source_v1::*; -use crate::wire::ZwpPrimarySelectionSourceV1Id; -use ahash::AHashSet; -use std::cell::RefCell; -use std::rc::Rc; -use thiserror::Error; -use uapi::OwnedFd; - -pub struct ZwpPrimarySelectionSourceV1 { - pub id: ZwpPrimarySelectionSourceV1Id, - pub client: Rc, - pub mime_types: RefCell>, - seat: CloneCell>>, - offer: CloneCell>>, -} - -impl ZwpPrimarySelectionSourceV1 { - pub fn new(id: ZwpPrimarySelectionSourceV1Id, client: &Rc) -> Self { - Self { - id, - client: client.clone(), - mime_types: RefCell::new(Default::default()), - seat: Default::default(), - offer: Default::default(), - } - } - - pub fn attach(&self, seat: &Rc) -> Result<(), ZwpPrimarySelectionSourceV1Error> { - if self.seat.get().is_some() { - return Err(ZwpPrimarySelectionSourceV1Error::AlreadyAttached); - } - self.seat.set(Some(seat.clone())); - Ok(()) - } - - pub fn detach(self: &Rc) { - self.seat.set(None); - if let Some(offer) = self.offer.set(None) { - offer.source.set(None); - } - self.send_cancelled(); - self.client.flush(); - } - - pub fn create_offer(self: &Rc, client: &Rc) { - let seat = match self.seat.get() { - Some(a) => a, - _ => { - log::error!("Trying to create an offer from a unattached data source"); - return; - } - }; - let offer = ZwpPrimarySelectionOfferV1::create(client, self, &seat); - let old = self.offer.set(offer); - if let Some(offer) = old { - offer.source.set(None); - } - } - - pub fn clear_offer(&self) { - self.offer.take(); - } - - pub fn send_cancelled(&self) { - self.client.event(Cancelled { self_id: self.id }) - } - - pub fn send_send(&self, mime_type: &str, fd: Rc) { - self.client.event(Send { - self_id: self.id, - mime_type, - 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.send_offer(req.mime_type); - } - } - Ok(()) - } - - fn disconnect(&self) { - if let Some(offer) = self.offer.take() { - offer.source.set(None); - } - if let Some(seat) = self.seat.get() { - let _ = seat.set_primary_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(()) - } -} - -object_base! { - ZwpPrimarySelectionSourceV1, ZwpPrimarySelectionSourceV1Error; - - OFFER => offer, - DESTROY => destroy, -} - -impl Object for ZwpPrimarySelectionSourceV1 { - fn num_requests(&self) -> u32 { - DESTROY + 1 - } - - fn break_loops(&self) { - self.disconnect(); - } -} - -dedicated_add_obj!( - ZwpPrimarySelectionSourceV1, - ZwpPrimarySelectionSourceV1Id, - zwp_primary_selection_source -); - -#[derive(Debug, Error)] -pub enum ZwpPrimarySelectionSourceV1Error { - #[error(transparent)] - ClientError(Box), - #[error("Could not process `offer` request")] - OfferError(#[from] OfferError), - #[error("Could not process `destroy` request")] - DestroyError(#[from] DestroyError), - #[error("The data source is already attached")] - AlreadyAttached, -} -efrom!(ZwpPrimarySelectionSourceV1Error, ClientError); - -#[derive(Debug, Error)] -pub enum OfferError { - #[error("Parsing failed")] - ParseFailed(#[source] Box), - #[error(transparent)] - ClientError(Box), -} -efrom!(OfferError, ParseFailed, MsgParserError); -efrom!(OfferError, ClientError); - -#[derive(Debug, Error)] -pub enum DestroyError { - #[error("Parsing failed")] - ParseFailed(#[source] Box), - #[error(transparent)] - ClientError(Box), -} -efrom!(DestroyError, ParseFailed, MsgParserError); -efrom!(DestroyError, ClientError); diff --git a/src/main.rs b/src/main.rs index ee79fba4..6b396e26 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,6 @@ use crate::clientmem::ClientMemError; use crate::event_loop::EventLoopError; use crate::globals::Globals; use crate::ifs::wl_compositor::WlCompositorGlobal; -use crate::ifs::wl_data_device_manager::WlDataDeviceManagerGlobal; use crate::ifs::wl_shm::WlShmGlobal; use crate::ifs::wl_subcompositor::WlSubcompositorGlobal; use crate::ifs::wl_surface::NoneSurfaceExt; diff --git a/src/object.rs b/src/object.rs index ebf60148..86f5a6c3 100644 --- a/src/object.rs +++ b/src/object.rs @@ -10,6 +10,8 @@ pub const WL_DISPLAY_ID: WlDisplayId = WlDisplayId::from_raw(1); pub struct ObjectId(u32); impl ObjectId { + pub const NONE: Self = ObjectId(0); + pub fn from_raw(raw: u32) -> Self { Self(raw) } diff --git a/todo.md b/todo.md index 151939e8..9e560dcf 100644 --- a/todo.md +++ b/todo.md @@ -10,7 +10,6 @@ - Float moving - Highlighting active - dnd -- primary selection - presentation time - viewporter - session lock @@ -19,3 +18,4 @@ - Container resizing - clipboard +- primary selection