1
0
Fork 0
forked from wry/wry

wayland: implement wlr-data-control

This commit is contained in:
Julian Orth 2024-03-31 01:36:45 +01:00
parent 8bca8b0e86
commit 99be020c19
18 changed files with 985 additions and 33 deletions

View file

@ -4,10 +4,12 @@ use {
ifs::{
ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
detach_seat, offer_source_to_regular_client, offer_source_to_x,
detach_seat, offer_source_to_regular_client, offer_source_to_wlr_device,
offer_source_to_x,
wl_data_device::ClipboardIpc,
wl_data_device_manager::{DND_ALL, DND_NONE},
x_data_device::{XClipboardIpc, XIpcDevice},
zwlr_data_control_device_v1::{WlrClipboardIpc, ZwlrDataControlDeviceV1},
DataSource, DynDataOffer, DynDataSource, SharedState, SourceData,
OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED, SOURCE_STATE_CANCELLED,
SOURCE_STATE_DROPPED,
@ -66,12 +68,16 @@ impl DynDataSource for WlDataSource {
offer_source_to_x::<XClipboardIpc, Self>(&self, dd);
}
fn offer_to_wlr_device(self: Rc<Self>, dd: &Rc<ZwlrDataControlDeviceV1>) {
offer_source_to_wlr_device::<WlrClipboardIpc, Self>(&self, dd)
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat);
}
fn cancel_offers(&self) {
cancel_offers(self);
fn cancel_unprivileged_offers(&self) {
cancel_offers(self, false);
}
fn send_target(&self, mime_type: Option<&str>) {
@ -112,7 +118,7 @@ impl WlDataSource {
self.data.shared.set(Rc::new(SharedState::default()));
self.send_target(None);
self.send_action(DND_NONE);
cancel_offers(self);
cancel_offers(self, false);
}
pub fn update_selected_action(&self) {

View file

@ -4,9 +4,14 @@ use {
ifs::{
ipc::{
cancel_offers, detach_seat, offer_source_to_regular_client,
wl_data_device::ClipboardIpc, x_data_device::XIpcDevice,
zwp_primary_selection_device_v1::PrimarySelectionIpc, DataSource, DynDataSource,
IpcLocation, SourceData,
offer_source_to_wlr_device,
wl_data_device::ClipboardIpc,
x_data_device::XIpcDevice,
zwlr_data_control_device_v1::{
WlrClipboardIpc, WlrPrimarySelectionIpc, ZwlrDataControlDeviceV1,
},
zwp_primary_selection_device_v1::PrimarySelectionIpc,
DataSource, DynDataSource, IpcLocation, SourceData,
},
wl_seat::WlSeatGlobal,
},
@ -61,7 +66,7 @@ impl DynDataSource for XDataSource {
}
fn offer_to_x(self: Rc<Self>, _dd: &Rc<XIpcDevice>) {
self.cancel_offers();
self.cancel_unprivileged_offers();
self.state.xwayland.queue.push(IpcSetSelection {
location: self.location,
seat: self.device.seat.id(),
@ -69,11 +74,22 @@ impl DynDataSource for XDataSource {
});
}
fn offer_to_wlr_device(self: Rc<Self>, dd: &Rc<ZwlrDataControlDeviceV1>) {
match self.location {
IpcLocation::Clipboard => {
offer_source_to_wlr_device::<WlrClipboardIpc, Self>(&self, dd)
}
IpcLocation::PrimarySelection => {
offer_source_to_wlr_device::<WlrPrimarySelectionIpc, Self>(&self, dd)
}
}
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat);
}
fn cancel_offers(&self) {
cancel_offers(self)
fn cancel_unprivileged_offers(&self) {
cancel_offers(self, false)
}
}

View file

@ -0,0 +1,306 @@
use {
crate::{
client::{Client, ClientError},
ifs::{
ipc::{
destroy_data_device,
zwlr_data_control_device_v1::private::{
WlrClipboardIpcCore, WlrIpcImpl, WlrPrimarySelectionIpcCore,
},
zwlr_data_control_offer_v1::ZwlrDataControlOfferV1,
zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
DeviceData, IpcLocation, IpcVtable, OfferData, Role, WlrIpcVtable,
},
wl_seat::{WlSeatError, WlSeatGlobal},
},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{
zwlr_data_control_device_v1::*, ZwlrDataControlDeviceV1Id, ZwlrDataControlOfferV1Id,
ZwlrDataControlSourceV1Id,
},
},
std::rc::Rc,
thiserror::Error,
};
pub const PRIMARY_SELECTION_SINCE: u32 = 2;
pub struct ZwlrDataControlDeviceV1 {
pub id: ZwlrDataControlDeviceV1Id,
pub client: Rc<Client>,
pub version: u32,
pub seat: Rc<WlSeatGlobal>,
pub clipboard_data: DeviceData<ZwlrDataControlOfferV1>,
pub primary_selection_data: DeviceData<ZwlrDataControlOfferV1>,
pub tracker: Tracker<Self>,
}
impl ZwlrDataControlDeviceV1 {
pub fn new(
id: ZwlrDataControlDeviceV1Id,
client: &Rc<Client>,
version: u32,
seat: &Rc<WlSeatGlobal>,
) -> Self {
Self {
id,
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<ZwlrDataControlOfferV1>) {
self.client.event(DataOffer {
self_id: self.id,
id: offer.id,
})
}
pub fn send_selection(&self, offer: Option<&Rc<ZwlrDataControlOfferV1>>) {
let id = offer
.map(|o| o.id)
.unwrap_or(ZwlrDataControlOfferV1Id::NONE);
self.client.event(Selection {
self_id: self.id,
id,
})
}
pub fn send_primary_selection(&self, offer: Option<&Rc<ZwlrDataControlOfferV1>>) {
let id = offer
.map(|o| o.id)
.unwrap_or(ZwlrDataControlOfferV1Id::NONE);
self.client.event(PrimarySelection {
self_id: self.id,
id,
})
}
fn use_source(
&self,
source: ZwlrDataControlSourceV1Id,
location: IpcLocation,
) -> Result<Option<Rc<ZwlrDataControlSourceV1>>, 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))
}
}
fn set_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlDeviceV1Error> {
let req: SetSelection = self.client.parse(self, parser)?;
let src = self.use_source(req.source, IpcLocation::Clipboard)?;
self.seat.set_selection(src)?;
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlDeviceV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
destroy_data_device::<WlrClipboardIpc>(self);
destroy_data_device::<WlrPrimarySelectionIpc>(self);
self.seat.remove_wlr_device(self);
self.client.remove_obj(self)?;
Ok(())
}
fn set_primary_selection(
&self,
parser: MsgParser<'_, '_>,
) -> Result<(), ZwlrDataControlDeviceV1Error> {
let req: SetPrimarySelection = self.client.parse(self, parser)?;
let src = self.use_source(req.source, IpcLocation::PrimarySelection)?;
self.seat.set_primary_selection(src)?;
Ok(())
}
}
mod private {
use std::marker::PhantomData;
pub struct WlrClipboardIpcCore;
pub struct WlrPrimarySelectionIpcCore;
pub struct WlrIpcImpl<T>(PhantomData<T>);
}
pub type WlrClipboardIpc = WlrIpcImpl<WlrClipboardIpcCore>;
pub type WlrPrimarySelectionIpc = WlrIpcImpl<WlrPrimarySelectionIpcCore>;
trait WlrIpc {
const MIN_VERSION: u32;
const LOCATION: IpcLocation;
fn wlr_get_device_data(dd: &ZwlrDataControlDeviceV1) -> &DeviceData<ZwlrDataControlOfferV1>;
fn wlr_set_seat_selection(
seat: &Rc<WlSeatGlobal>,
source: &Rc<ZwlrDataControlSourceV1>,
) -> Result<(), WlSeatError>;
fn wlr_send_selection(dd: &ZwlrDataControlDeviceV1, offer: Option<&Rc<ZwlrDataControlOfferV1>>);
fn wlr_unset(seat: &Rc<WlSeatGlobal>);
}
impl WlrIpc for WlrClipboardIpcCore {
const MIN_VERSION: u32 = 1;
const LOCATION: IpcLocation = IpcLocation::Clipboard;
fn wlr_get_device_data(dd: &ZwlrDataControlDeviceV1) -> &DeviceData<ZwlrDataControlOfferV1> {
&dd.clipboard_data
}
fn wlr_set_seat_selection(
seat: &Rc<WlSeatGlobal>,
source: &Rc<ZwlrDataControlSourceV1>,
) -> Result<(), WlSeatError> {
seat.set_selection(Some(source.clone()))
}
fn wlr_send_selection(
dd: &ZwlrDataControlDeviceV1,
offer: Option<&Rc<ZwlrDataControlOfferV1>>,
) {
dd.send_selection(offer)
}
fn wlr_unset(seat: &Rc<WlSeatGlobal>) {
seat.unset_selection()
}
}
impl WlrIpc for WlrPrimarySelectionIpcCore {
const MIN_VERSION: u32 = PRIMARY_SELECTION_SINCE;
const LOCATION: IpcLocation = IpcLocation::PrimarySelection;
fn wlr_get_device_data(dd: &ZwlrDataControlDeviceV1) -> &DeviceData<ZwlrDataControlOfferV1> {
&dd.primary_selection_data
}
fn wlr_set_seat_selection(
seat: &Rc<WlSeatGlobal>,
source: &Rc<ZwlrDataControlSourceV1>,
) -> Result<(), WlSeatError> {
seat.set_primary_selection(Some(source.clone()))
}
fn wlr_send_selection(
dd: &ZwlrDataControlDeviceV1,
offer: Option<&Rc<ZwlrDataControlOfferV1>>,
) {
dd.send_primary_selection(offer)
}
fn wlr_unset(seat: &Rc<WlSeatGlobal>) {
seat.unset_primary_selection()
}
}
impl<T: WlrIpc> WlrIpcVtable for WlrIpcImpl<T> {
fn for_each_device<C>(seat: &WlSeatGlobal, f: C)
where
C: FnMut(&Rc<Self::Device>),
{
seat.for_each_wlr_data_device(T::MIN_VERSION, f)
}
}
impl<T: WlrIpc> IpcVtable for WlrIpcImpl<T> {
const LOCATION: IpcLocation = T::LOCATION;
type Device = ZwlrDataControlDeviceV1;
type Source = ZwlrDataControlSourceV1;
type Offer = ZwlrDataControlOfferV1;
fn get_device_data(dd: &Self::Device) -> &DeviceData<Self::Offer> {
T::wlr_get_device_data(dd)
}
fn get_device_seat(dd: &Self::Device) -> Rc<WlSeatGlobal> {
dd.seat.clone()
}
fn set_seat_selection(
seat: &Rc<WlSeatGlobal>,
source: &Rc<Self::Source>,
serial: Option<u32>,
) -> Result<(), WlSeatError> {
debug_assert!(serial.is_none());
let _ = serial;
T::wlr_set_seat_selection(seat, source)
}
fn create_offer(
device: &Rc<ZwlrDataControlDeviceV1>,
offer_data: OfferData<Self::Device>,
) -> Result<Rc<Self::Offer>, ClientError> {
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,
tracker: Default::default(),
});
track!(device.client, rc);
device.client.add_server_obj(&rc);
Ok(rc)
}
fn send_selection(dd: &Self::Device, offer: Option<&Rc<Self::Offer>>) {
T::wlr_send_selection(dd, offer)
}
fn send_offer(dd: &Self::Device, offer: &Rc<Self::Offer>) {
dd.send_data_offer(offer);
}
fn unset(seat: &Rc<WlSeatGlobal>, _role: Role) {
T::wlr_unset(seat)
}
fn device_client(dd: &Rc<Self::Device>) -> &Rc<Client> {
&dd.client
}
}
object_base! {
self = ZwlrDataControlDeviceV1;
SET_SELECTION => set_selection,
DESTROY => destroy,
SET_PRIMARY_SELECTION => set_primary_selection if self.version >= 2,
}
impl Object for ZwlrDataControlDeviceV1 {
fn break_loops(&self) {
self.seat.remove_wlr_device(self);
}
}
simple_add_obj!(ZwlrDataControlDeviceV1);
#[derive(Debug, Error)]
pub enum ZwlrDataControlDeviceV1Error {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error(transparent)]
WlSeatError(Box<WlSeatError>),
#[error("The source has already been used")]
AlreadyUsed,
}
efrom!(ZwlrDataControlDeviceV1Error, MsgParserError);
efrom!(ZwlrDataControlDeviceV1Error, ClientError);
efrom!(ZwlrDataControlDeviceV1Error, WlSeatError);

View file

@ -0,0 +1,145 @@
use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::ipc::{
zwlr_data_control_device_v1::{ZwlrDataControlDeviceV1, PRIMARY_SELECTION_SINCE},
zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwlr_data_control_manager_v1::*, ZwlrDataControlManagerV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct ZwlrDataControlManagerV1Global {
name: GlobalName,
}
pub struct ZwlrDataControlManagerV1 {
pub id: ZwlrDataControlManagerV1Id,
pub client: Rc<Client>,
pub version: u32,
tracker: Tracker<Self>,
}
impl ZwlrDataControlManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: ZwlrDataControlManagerV1Id,
client: &Rc<Client>,
version: u32,
) -> Result<(), ZwlrDataControlManagerV1Error> {
let obj = Rc::new(ZwlrDataControlManagerV1 {
id,
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
impl ZwlrDataControlManagerV1 {
fn create_data_source(
&self,
parser: MsgParser<'_, '_>,
) -> Result<(), ZwlrDataControlManagerV1Error> {
let req: CreateDataSource = self.client.parse(self, parser)?;
let res = Rc::new(ZwlrDataControlSourceV1::new(
req.id,
&self.client,
self.version,
));
track!(self.client, res);
self.client.add_client_obj(&res)?;
Ok(())
}
fn get_data_device(
self: &Rc<Self>,
parser: MsgParser<'_, '_>,
) -> Result<(), ZwlrDataControlManagerV1Error> {
let req: GetDataDevice = self.client.parse(&**self, parser)?;
let seat = self.client.lookup(req.seat)?;
let dev = Rc::new(ZwlrDataControlDeviceV1::new(
req.id,
&self.client,
self.version,
&seat.global,
));
track!(self.client, dev);
seat.global.add_wlr_device(&dev);
self.client.add_client_obj(&dev)?;
match seat.global.get_selection() {
Some(s) => s.offer_to_wlr_device(&dev),
_ => dev.send_selection(None),
}
if self.version >= PRIMARY_SELECTION_SINCE {
match seat.global.get_primary_selection() {
Some(s) => s.offer_to_wlr_device(&dev),
_ => dev.send_primary_selection(None),
}
}
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlManagerV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
}
global_base!(
ZwlrDataControlManagerV1Global,
ZwlrDataControlManagerV1,
ZwlrDataControlManagerV1Error
);
impl Global for ZwlrDataControlManagerV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
2
}
fn secure(&self) -> bool {
true
}
}
simple_add_global!(ZwlrDataControlManagerV1Global);
object_base! {
self = ZwlrDataControlManagerV1;
CREATE_DATA_SOURCE => create_data_source,
GET_DATA_DEVICE => get_data_device,
DESTROY => destroy,
}
impl Object for ZwlrDataControlManagerV1 {}
simple_add_obj!(ZwlrDataControlManagerV1);
#[derive(Debug, Error)]
pub enum ZwlrDataControlManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
}
efrom!(ZwlrDataControlManagerV1Error, ClientError);
efrom!(ZwlrDataControlManagerV1Error, MsgParserError);

View file

@ -0,0 +1,135 @@
use {
crate::{
client::{Client, ClientError, ClientId},
ifs::{
ipc::{
break_offer_loops, cancel_offer, destroy_data_offer, receive_data_offer,
zwlr_data_control_device_v1::{
WlrClipboardIpc, WlrPrimarySelectionIpc, ZwlrDataControlDeviceV1,
},
DataOffer, DataOfferId, DynDataOffer, IpcLocation, OfferData,
},
wl_seat::WlSeatGlobal,
},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwlr_data_control_offer_v1::*, ZwlrDataControlOfferV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct ZwlrDataControlOfferV1 {
pub id: ZwlrDataControlOfferV1Id,
pub offer_id: DataOfferId,
pub client: Rc<Client>,
pub device: Rc<ZwlrDataControlDeviceV1>,
pub data: OfferData<ZwlrDataControlDeviceV1>,
pub location: IpcLocation,
pub tracker: Tracker<Self>,
}
impl DataOffer for ZwlrDataControlOfferV1 {
type Device = ZwlrDataControlDeviceV1;
fn offer_data(&self) -> &OfferData<ZwlrDataControlDeviceV1> {
&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 destroy(&self) {
match self.location {
IpcLocation::Clipboard => destroy_data_offer::<WlrClipboardIpc>(self),
IpcLocation::PrimarySelection => destroy_data_offer::<WlrPrimarySelectionIpc>(self),
}
}
fn cancel(&self) {
match self.location {
IpcLocation::Clipboard => cancel_offer::<WlrClipboardIpc>(self),
IpcLocation::PrimarySelection => cancel_offer::<WlrPrimarySelectionIpc>(self),
}
}
fn get_seat(&self) -> Rc<WlSeatGlobal> {
self.device.seat.clone()
}
fn is_privileged(&self) -> bool {
true
}
}
impl ZwlrDataControlOfferV1 {
pub fn send_offer(&self, mime_type: &str) {
self.client.event(Offer {
self_id: self.id,
mime_type,
})
}
fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlOfferV1Error> {
let req: Receive = self.client.parse(self, parser)?;
match self.location {
IpcLocation::Clipboard => {
receive_data_offer::<WlrClipboardIpc>(self, req.mime_type, req.fd)
}
IpcLocation::PrimarySelection => {
receive_data_offer::<WlrPrimarySelectionIpc>(self, req.mime_type, req.fd)
}
}
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlOfferV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
match self.location {
IpcLocation::Clipboard => destroy_data_offer::<WlrClipboardIpc>(self),
IpcLocation::PrimarySelection => destroy_data_offer::<WlrPrimarySelectionIpc>(self),
}
self.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
self = ZwlrDataControlOfferV1;
RECEIVE => receive,
DESTROY => destroy,
}
impl Object for ZwlrDataControlOfferV1 {
fn break_loops(&self) {
match self.location {
IpcLocation::Clipboard => break_offer_loops::<WlrClipboardIpc>(self),
IpcLocation::PrimarySelection => break_offer_loops::<WlrPrimarySelectionIpc>(self),
}
}
}
simple_add_obj!(ZwlrDataControlOfferV1);
#[derive(Debug, Error)]
pub enum ZwlrDataControlOfferV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
}
efrom!(ZwlrDataControlOfferV1Error, ClientError);
efrom!(ZwlrDataControlOfferV1Error, MsgParserError);

View file

@ -0,0 +1,169 @@
use {
crate::{
client::{Client, ClientError},
ifs::{
ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
detach_seat, offer_source_to_regular_client, offer_source_to_wlr_device,
offer_source_to_x,
wl_data_device::ClipboardIpc,
x_data_device::{XClipboardIpc, XIpcDevice, XPrimarySelectionIpc},
zwlr_data_control_device_v1::{
WlrClipboardIpc, WlrPrimarySelectionIpc, ZwlrDataControlDeviceV1,
},
zwp_primary_selection_device_v1::PrimarySelectionIpc,
DataSource, DynDataSource, IpcLocation, SourceData,
},
wl_seat::WlSeatGlobal,
},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwlr_data_control_source_v1::*, ZwlrDataControlSourceV1Id},
},
std::{cell::Cell, rc::Rc},
thiserror::Error,
uapi::OwnedFd,
};
pub struct ZwlrDataControlSourceV1 {
pub id: ZwlrDataControlSourceV1Id,
pub data: SourceData,
pub version: u32,
pub location: Cell<IpcLocation>,
pub used: Cell<bool>,
pub tracker: Tracker<Self>,
}
impl DataSource for ZwlrDataControlSourceV1 {
fn send_cancelled(&self, _seat: &Rc<WlSeatGlobal>) {
ZwlrDataControlSourceV1::send_cancelled(self);
}
}
impl DynDataSource for ZwlrDataControlSourceV1 {
fn source_data(&self) -> &SourceData {
&self.data
}
fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
ZwlrDataControlSourceV1::send_send(&self, mime_type, fd);
}
fn offer_to_regular_client(self: Rc<Self>, client: &Rc<Client>) {
match self.location.get() {
IpcLocation::Clipboard => {
offer_source_to_regular_client::<ClipboardIpc, Self>(&self, client)
}
IpcLocation::PrimarySelection => {
offer_source_to_regular_client::<PrimarySelectionIpc, Self>(&self, client)
}
}
}
fn offer_to_x(self: Rc<Self>, dd: &Rc<XIpcDevice>) {
match self.location.get() {
IpcLocation::Clipboard => offer_source_to_x::<XClipboardIpc, Self>(&self, dd),
IpcLocation::PrimarySelection => {
offer_source_to_x::<XPrimarySelectionIpc, Self>(&self, dd)
}
}
}
fn offer_to_wlr_device(self: Rc<Self>, dd: &Rc<ZwlrDataControlDeviceV1>) {
match self.location.get() {
IpcLocation::Clipboard => {
offer_source_to_wlr_device::<WlrClipboardIpc, Self>(&self, dd)
}
IpcLocation::PrimarySelection => {
offer_source_to_wlr_device::<WlrPrimarySelectionIpc, Self>(&self, dd)
}
}
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat)
}
fn cancel_unprivileged_offers(&self) {
cancel_offers(self, false)
}
}
impl ZwlrDataControlSourceV1 {
pub fn new(id: ZwlrDataControlSourceV1Id, client: &Rc<Client>, version: u32) -> Self {
Self {
id,
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<OwnedFd>) {
self.data.client.event(Send {
self_id: self.id,
mime_type,
fd,
})
}
pub fn send_cancelled(&self) {
self.data.client.event(Cancelled { self_id: self.id })
}
fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlSourceV1Error> {
let req: Offer = self.data.client.parse(self, parser)?;
if self.used.get() {
return Err(ZwlrDataControlSourceV1Error::AlreadyUsed);
}
add_data_source_mime_type::<WlrClipboardIpc>(self, req.mime_type);
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwlrDataControlSourceV1Error> {
let _req: Destroy = self.data.client.parse(self, parser)?;
match self.location.get() {
IpcLocation::Clipboard => destroy_data_source::<WlrClipboardIpc>(self),
IpcLocation::PrimarySelection => destroy_data_source::<WlrPrimarySelectionIpc>(self),
}
self.data.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
self = ZwlrDataControlSourceV1;
OFFER => offer,
DESTROY => destroy,
}
impl Object for ZwlrDataControlSourceV1 {
fn break_loops(&self) {
match self.location.get() {
IpcLocation::Clipboard => break_source_loops::<WlrClipboardIpc>(self),
IpcLocation::PrimarySelection => break_source_loops::<WlrPrimarySelectionIpc>(self),
}
}
}
dedicated_add_obj!(
ZwlrDataControlSourceV1,
ZwlrDataControlSourceV1Id,
zwlr_data_sources
);
#[derive(Debug, Error)]
pub enum ZwlrDataControlSourceV1Error {
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("The source has already been used")]
AlreadyUsed,
}
efrom!(ZwlrDataControlSourceV1Error, ClientError);
efrom!(ZwlrDataControlSourceV1Error, MsgParserError);

View file

@ -4,8 +4,10 @@ use {
ifs::{
ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
detach_seat, offer_source_to_regular_client, offer_source_to_x,
detach_seat, offer_source_to_regular_client, offer_source_to_wlr_device,
offer_source_to_x,
x_data_device::{XIpcDevice, XPrimarySelectionIpc},
zwlr_data_control_device_v1::{WlrPrimarySelectionIpc, ZwlrDataControlDeviceV1},
zwp_primary_selection_device_v1::PrimarySelectionIpc,
DataSource, DynDataSource, SourceData,
},
@ -50,12 +52,16 @@ impl DynDataSource for ZwpPrimarySelectionSourceV1 {
offer_source_to_x::<XPrimarySelectionIpc, Self>(&self, dd);
}
fn offer_to_wlr_device(self: Rc<Self>, dd: &Rc<ZwlrDataControlDeviceV1>) {
offer_source_to_wlr_device::<WlrPrimarySelectionIpc, Self>(&self, dd)
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat);
}
fn cancel_offers(&self) {
cancel_offers(self);
fn cancel_unprivileged_offers(&self) {
cancel_offers(self, false);
}
}