1
0
Fork 0
forked from wry/wry

ipc: implement ext-data-control

This commit is contained in:
Julian Orth 2024-10-08 16:07:31 +02:00
parent be1462d0ef
commit 4abbe94995
13 changed files with 575 additions and 3 deletions

View file

@ -3,6 +3,10 @@ use {
std::rc::Rc,
};
pub mod ext_data_control_device_v1;
pub mod ext_data_control_manager_v1;
pub mod ext_data_control_offer_v1;
pub mod ext_data_control_source_v1;
mod private;
pub mod zwlr_data_control_device_v1;
pub mod zwlr_data_control_manager_v1;

View file

@ -0,0 +1,158 @@
use {
crate::{
client::Client,
ifs::{
ipc::data_control::{
ext_data_control_offer_v1::ExtDataControlOfferV1,
ext_data_control_source_v1::ExtDataControlSourceV1,
private::{
logic::{self, DataControlError},
DataControlDevice, DataControlDeviceData, DataControlIpc, DataControlOfferData,
},
},
wl_seat::WlSeatGlobal,
},
leaks::Tracker,
object::{Object, Version},
wire::{
ext_data_control_device_v1::*, ExtDataControlDeviceV1Id, ExtDataControlOfferV1Id,
ExtDataControlSourceV1Id,
},
},
std::rc::Rc,
thiserror::Error,
};
pub struct ExtDataControlDeviceV1 {
pub id: ExtDataControlDeviceV1Id,
pub data: DataControlDeviceData<ExtDataControlIpc>,
pub tracker: Tracker<Self>,
}
impl ExtDataControlDeviceV1 {
pub fn new(
id: ExtDataControlDeviceV1Id,
client: &Rc<Client>,
version: Version,
seat: &Rc<WlSeatGlobal>,
) -> Self {
Self {
id,
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<ExtDataControlOfferV1>) {
self.data.client.event(DataOffer {
self_id: self.id,
id: offer.id,
})
}
pub fn send_selection(&self, offer: Option<&Rc<ExtDataControlOfferV1>>) {
let id = offer.map(|o| o.id).unwrap_or(ExtDataControlOfferV1Id::NONE);
self.data.client.event(Selection {
self_id: self.id,
id,
})
}
pub fn send_primary_selection(&self, offer: Option<&Rc<ExtDataControlOfferV1>>) {
let id = offer.map(|o| o.id).unwrap_or(ExtDataControlOfferV1Id::NONE);
self.data.client.event(PrimarySelection {
self_id: self.id,
id,
})
}
}
impl ExtDataControlDeviceV1RequestHandler for ExtDataControlDeviceV1 {
type Error = ExtDataControlDeviceV1Error;
fn set_selection(&self, req: SetSelection, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::device_set_selection(self, req.source.is_some().then_some(req.source))?;
Ok(())
}
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::device_destroy(self)?;
Ok(())
}
fn set_primary_selection(
&self,
req: SetPrimarySelection,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
logic::device_set_primary_selection(self, req.source.is_some().then_some(req.source))?;
Ok(())
}
}
pub struct ExtDataControlIpc;
impl DataControlIpc for ExtDataControlIpc {
const PRIMARY_SELECTION_SINCE: Version = Version(1);
type Device = ExtDataControlDeviceV1;
type OfferId = ExtDataControlOfferV1Id;
type Offer = ExtDataControlOfferV1;
type SourceId = ExtDataControlSourceV1Id;
type Source = ExtDataControlSourceV1;
fn create_offer(id: Self::OfferId, data: DataControlOfferData<Self>) -> Rc<Self::Offer> {
let rc = Rc::new(ExtDataControlOfferV1 {
id,
data,
tracker: Default::default(),
});
track!(rc.data.client, rc);
rc
}
}
impl DataControlDevice for ExtDataControlDeviceV1 {
type Ipc = ExtDataControlIpc;
fn data(&self) -> &DataControlDeviceData<Self::Ipc> {
&self.data
}
fn send_data_offer(&self, offer: &Rc<<Self::Ipc as DataControlIpc>::Offer>) {
self.send_data_offer(offer)
}
fn send_selection(&self, offer: Option<&Rc<<Self::Ipc as DataControlIpc>::Offer>>) {
self.send_selection(offer)
}
fn send_primary_selection(&self, offer: Option<&Rc<<Self::Ipc as DataControlIpc>::Offer>>) {
self.send_primary_selection(offer)
}
}
object_base! {
self = ExtDataControlDeviceV1;
version = self.data.version;
}
impl Object for ExtDataControlDeviceV1 {
fn break_loops(&self) {
logic::data_device_break_loops(self);
}
}
simple_add_obj!(ExtDataControlDeviceV1);
#[derive(Debug, Error)]
pub enum ExtDataControlDeviceV1Error {
#[error(transparent)]
DataControlError(#[from] DataControlError),
}

View file

@ -0,0 +1,134 @@
use {
crate::{
client::{Client, ClientCaps, ClientError, CAP_DATA_CONTROL_MANAGER},
globals::{Global, GlobalName},
ifs::ipc::{
data_control::{
ext_data_control_device_v1::ExtDataControlDeviceV1,
ext_data_control_source_v1::ExtDataControlSourceV1, DynDataControlDevice,
},
IpcLocation,
},
leaks::Tracker,
object::{Object, Version},
wire::{ext_data_control_manager_v1::*, ExtDataControlManagerV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct ExtDataControlManagerV1Global {
name: GlobalName,
}
pub struct ExtDataControlManagerV1 {
pub id: ExtDataControlManagerV1Id,
pub client: Rc<Client>,
pub version: Version,
tracker: Tracker<Self>,
}
impl ExtDataControlManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: ExtDataControlManagerV1Id,
client: &Rc<Client>,
version: Version,
) -> Result<(), ExtDataControlManagerV1Error> {
let obj = Rc::new(ExtDataControlManagerV1 {
id,
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
impl ExtDataControlManagerV1RequestHandler for ExtDataControlManagerV1 {
type Error = ExtDataControlManagerV1Error;
fn create_data_source(
&self,
req: CreateDataSource,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let res = Rc::new(ExtDataControlSourceV1::new(
req.id,
&self.client,
self.version,
));
track!(self.client, res);
self.client.add_client_obj(&res)?;
Ok(())
}
fn get_data_device(&self, req: GetDataDevice, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let seat = self.client.lookup(req.seat)?;
let dev = Rc::new(ExtDataControlDeviceV1::new(
req.id,
&self.client,
self.version,
&seat.global,
));
track!(self.client, dev);
seat.global.add_data_control_device(dev.clone());
self.client.add_client_obj(&dev)?;
dev.clone()
.handle_new_source(IpcLocation::Clipboard, seat.global.get_selection());
dev.clone().handle_new_source(
IpcLocation::PrimarySelection,
seat.global.get_primary_selection(),
);
Ok(())
}
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.remove_obj(self)?;
Ok(())
}
}
global_base!(
ExtDataControlManagerV1Global,
ExtDataControlManagerV1,
ExtDataControlManagerV1Error
);
impl Global for ExtDataControlManagerV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
1
}
fn required_caps(&self) -> ClientCaps {
CAP_DATA_CONTROL_MANAGER
}
}
simple_add_global!(ExtDataControlManagerV1Global);
object_base! {
self = ExtDataControlManagerV1;
version = self.version;
}
impl Object for ExtDataControlManagerV1 {}
simple_add_obj!(ExtDataControlManagerV1);
#[derive(Debug, Error)]
pub enum ExtDataControlManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(ExtDataControlManagerV1Error, ClientError);

View file

@ -0,0 +1,76 @@
use {
crate::{
ifs::ipc::data_control::{
ext_data_control_device_v1::ExtDataControlIpc,
private::{
logic::{self, DataControlError},
DataControlOffer, DataControlOfferData,
},
},
leaks::Tracker,
object::Object,
wire::{ext_data_control_offer_v1::*, ExtDataControlOfferV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct ExtDataControlOfferV1 {
pub id: ExtDataControlOfferV1Id,
pub data: DataControlOfferData<ExtDataControlIpc>,
pub tracker: Tracker<Self>,
}
impl DataControlOffer for ExtDataControlOfferV1 {
type Ipc = ExtDataControlIpc;
fn data(&self) -> &DataControlOfferData<Self::Ipc> {
&self.data
}
fn send_offer(&self, mime_type: &str) {
self.send_offer(mime_type);
}
}
impl ExtDataControlOfferV1 {
pub fn send_offer(&self, mime_type: &str) {
self.data.client.event(Offer {
self_id: self.id,
mime_type,
})
}
}
impl ExtDataControlOfferV1RequestHandler for ExtDataControlOfferV1 {
type Error = ExtDataControlOfferV1Error;
fn receive(&self, req: Receive, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::data_offer_receive(self, req.mime_type, req.fd);
Ok(())
}
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::data_offer_destroy(self)?;
Ok(())
}
}
object_base! {
self = ExtDataControlOfferV1;
version = self.data.device.data.version;
}
impl Object for ExtDataControlOfferV1 {
fn break_loops(&self) {
logic::data_offer_break_loops(self);
}
}
simple_add_obj!(ExtDataControlOfferV1);
#[derive(Debug, Error)]
pub enum ExtDataControlOfferV1Error {
#[error(transparent)]
DataControlError(#[from] DataControlError),
}

View file

@ -0,0 +1,107 @@
use {
crate::{
client::Client,
ifs::ipc::{
data_control::{
ext_data_control_device_v1::ExtDataControlIpc,
private::{
logic::{self, DataControlError},
DataControlSource, DataControlSourceData,
},
},
IpcLocation, SourceData,
},
leaks::Tracker,
object::{Object, Version},
wire::{ext_data_control_source_v1::*, ExtDataControlSourceV1Id},
},
std::{cell::Cell, rc::Rc},
thiserror::Error,
uapi::OwnedFd,
};
pub struct ExtDataControlSourceV1 {
pub id: ExtDataControlSourceV1Id,
pub data: DataControlSourceData,
pub tracker: Tracker<Self>,
}
impl DataControlSource for ExtDataControlSourceV1 {
type Ipc = ExtDataControlIpc;
fn data(&self) -> &DataControlSourceData {
&self.data
}
fn send_cancelled(&self) {
self.send_cancelled();
}
fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
self.send_send(mime_type, fd);
}
}
impl ExtDataControlSourceV1 {
pub fn new(id: ExtDataControlSourceV1Id, client: &Rc<Client>, version: Version) -> Self {
Self {
id,
data: DataControlSourceData {
data: SourceData::new(client),
version,
location: Cell::new(IpcLocation::Clipboard),
used: Cell::new(false),
},
tracker: Default::default(),
}
}
pub fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
self.data.data.client.event(Send {
self_id: self.id,
mime_type,
fd,
})
}
pub fn send_cancelled(&self) {
self.data.data.client.event(Cancelled { self_id: self.id })
}
}
impl ExtDataControlSourceV1RequestHandler for ExtDataControlSourceV1 {
type Error = ExtDataControlSourceV1Error;
fn offer(&self, req: Offer, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::data_source_offer(self, req.mime_type)?;
Ok(())
}
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::data_source_destroy(self)?;
Ok(())
}
}
object_base! {
self = ExtDataControlSourceV1;
version = self.data.version;
}
impl Object for ExtDataControlSourceV1 {
fn break_loops(&self) {
logic::data_source_break_loops(self);
}
}
dedicated_add_obj!(
ExtDataControlSourceV1,
ExtDataControlSourceV1Id,
ext_data_sources
);
#[derive(Debug, Error)]
pub enum ExtDataControlSourceV1Error {
#[error(transparent)]
DataControlError(#[from] DataControlError),
}