1
0
Fork 0
forked from wry/wry

ipc: create separate offers/sources for X

This commit is contained in:
Julian Orth 2024-03-31 18:42:23 +02:00
parent 4e9dacce1a
commit 8bca8b0e86
19 changed files with 830 additions and 552 deletions

View file

@ -5,7 +5,8 @@ use {
ifs::{
ipc::{
break_device_loops, destroy_data_device, wl_data_offer::WlDataOffer,
wl_data_source::WlDataSource, DeviceData, IpcVtable, OfferData, Role, XIpcVtable,
wl_data_source::WlDataSource, DeviceData, IpcLocation, IpcVtable,
IterableIpcVtable, OfferData, Role,
},
wl_seat::{WlSeatError, WlSeatGlobal},
wl_surface::{SurfaceRole, WlSurfaceError},
@ -13,8 +14,7 @@ use {
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{wl_data_device::*, WlDataDeviceId, WlDataOfferId, WlDataSourceId, WlSurfaceId},
xwayland::XWaylandEvent,
wire::{wl_data_device::*, WlDataDeviceId, WlDataOfferId, WlSurfaceId},
},
std::rc::Rc,
thiserror::Error,
@ -38,60 +38,34 @@ impl WlDataDevice {
client: &Rc<Client>,
version: u32,
seat: &Rc<WlSeatGlobal>,
is_xwm: bool,
) -> Self {
Self {
id,
client: client.clone(),
version,
seat: seat.clone(),
data: DeviceData {
selection: Default::default(),
dnd: Default::default(),
is_xwm,
},
data: Default::default(),
tracker: Default::default(),
}
}
pub fn send_data_offer(&self, offer: &Rc<WlDataOffer>) {
if self.data.is_xwm {
self.client
.state
.xwayland
.queue
.push(XWaylandEvent::ClipboardSetOffer(offer.clone()));
} else {
self.client.event(DataOffer {
self_id: self.id,
id: offer.id,
})
}
self.client.event(DataOffer {
self_id: self.id,
id: offer.id,
})
}
pub fn send_selection(&self, offer: Option<&Rc<WlDataOffer>>) {
if self.data.is_xwm {
self.client
.state
.xwayland
.queue
.push(XWaylandEvent::ClipboardSetSelection(
self.seat.id(),
offer.cloned(),
));
} else {
let id = offer.map(|o| o.id).unwrap_or(WlDataOfferId::NONE);
self.client.event(Selection {
self_id: self.id,
id,
})
}
let id = offer.map(|o| o.id).unwrap_or(WlDataOfferId::NONE);
self.client.event(Selection {
self_id: self.id,
id,
})
}
pub fn send_leave(&self) {
if !self.data.is_xwm {
self.client.event(Leave { self_id: self.id })
}
self.client.event(Leave { self_id: self.id })
}
pub fn send_enter(
@ -102,33 +76,27 @@ impl WlDataDevice {
offer: WlDataOfferId,
serial: u32,
) {
if !self.data.is_xwm {
self.client.event(Enter {
self_id: self.id,
serial,
surface,
x,
y,
id: offer,
})
}
self.client.event(Enter {
self_id: self.id,
serial,
surface,
x,
y,
id: offer,
})
}
pub fn send_motion(&self, time_usec: u64, x: Fixed, y: Fixed) {
if !self.data.is_xwm {
self.client.event(Motion {
self_id: self.id,
time: (time_usec / 1000) as _,
x,
y,
})
}
self.client.event(Motion {
self_id: self.id,
time: (time_usec / 1000) as _,
x,
y,
})
}
pub fn send_drop(&self) {
if !self.data.is_xwm {
self.client.event(Drop { self_id: self.id })
}
self.client.event(Drop { self_id: self.id })
}
fn start_drag(&self, parser: MsgParser<'_, '_>) -> Result<(), WlDataDeviceError> {
@ -185,17 +153,18 @@ impl WlDataDevice {
pub struct ClipboardIpc;
impl XIpcVtable for ClipboardIpc {
fn create_xwm_source(client: &Rc<Client>) -> Self::Source {
WlDataSource::new(WlDataSourceId::NONE, client, true, 3)
}
fn remove_from_seat(device: &Self::Device) {
device.seat.remove_data_device(device);
impl IterableIpcVtable for ClipboardIpc {
fn for_each_device<C>(seat: &WlSeatGlobal, client: ClientId, f: C)
where
C: FnMut(&Rc<Self::Device>),
{
seat.for_each_data_device(0, client, f);
}
}
impl IpcVtable for ClipboardIpc {
const LOCATION: IpcLocation = IpcLocation::Clipboard;
type Device = WlDataDevice;
type Source = WlDataSource;
type Offer = WlDataOffer;
@ -216,27 +185,20 @@ impl IpcVtable for ClipboardIpc {
seat.set_wl_data_source_selection(Some(source.clone()), serial)
}
fn for_each_device<C>(seat: &WlSeatGlobal, client: ClientId, f: C)
where
C: FnMut(&Rc<Self::Device>),
{
seat.for_each_data_device(0, client, f);
}
fn create_offer(
client: &Rc<Client>,
device: &Rc<WlDataDevice>,
offer_data: OfferData<Self::Device>,
) -> Result<Rc<Self::Offer>, ClientError> {
let rc = Rc::new(WlDataOffer {
id: client.new_id()?,
offer_id: client.state.data_offer_ids.next(),
client: client.clone(),
id: device.client.new_id()?,
offer_id: device.client.state.data_offer_ids.next(),
client: device.client.clone(),
device: device.clone(),
data: offer_data,
tracker: Default::default(),
});
track!(client, rc);
track!(device.client, rc);
device.client.add_server_obj(&rc);
Ok(rc)
}
@ -254,6 +216,10 @@ impl IpcVtable for ClipboardIpc {
Role::Dnd => seat.cancel_dnd(),
}
}
fn device_client(dd: &Rc<Self::Device>) -> &Rc<Client> {
&dd.client
}
}
object_base! {

View file

@ -61,7 +61,7 @@ impl WlDataDeviceManager {
parser: MsgParser<'_, '_>,
) -> Result<(), WlDataDeviceManagerError> {
let req: CreateDataSource = self.client.parse(self, parser)?;
let res = Rc::new(WlDataSource::new(req.id, &self.client, false, self.version));
let res = Rc::new(WlDataSource::new(req.id, &self.client, self.version));
track!(self.client, res);
self.client.add_client_obj(&res)?;
Ok(())
@ -78,7 +78,6 @@ impl WlDataDeviceManager {
&self.client,
self.version,
&seat.global,
false,
));
track!(self.client, dev);
seat.global.add_data_device(&dev);

View file

@ -19,7 +19,6 @@ use {
buffd::{MsgParser, MsgParserError},
},
wire::{wl_data_offer::*, WlDataOfferId, WlSurfaceId},
xwayland::XWaylandEvent,
},
std::rc::Rc,
thiserror::Error,
@ -64,8 +63,8 @@ impl DynDataOffer for WlDataOffer {
WlDataOffer::send_action(self, action);
}
fn send_offer(self: Rc<Self>, mime_type: &str) {
WlDataOffer::send_offer(&self, mime_type);
fn send_offer(&self, mime_type: &str) {
WlDataOffer::send_offer(self, mime_type);
}
fn destroy(&self) {
@ -90,46 +89,29 @@ impl DynDataOffer for WlDataOffer {
}
impl WlDataOffer {
pub fn send_offer(self: &Rc<Self>, mime_type: &str) {
if self.data.is_xwm {
if let Some(src) = self.data.source.get() {
if !src.source_data().is_xwm {
self.client.state.xwayland.queue.push(
XWaylandEvent::ClipboardAddOfferMimeType(
self.clone(),
mime_type.to_string(),
),
);
}
}
} else {
self.client.event(Offer {
self_id: self.id,
mime_type,
})
}
pub fn send_offer(&self, mime_type: &str) {
self.client.event(Offer {
self_id: self.id,
mime_type,
})
}
pub fn send_source_actions(&self) {
if !self.data.is_xwm {
if let Some(src) = self.data.source.get() {
if let Some(source_actions) = src.source_data().actions.get() {
self.client.event(SourceActions {
self_id: self.id,
source_actions,
})
}
if let Some(src) = self.data.source.get() {
if let Some(source_actions) = src.source_data().actions.get() {
self.client.event(SourceActions {
self_id: self.id,
source_actions,
})
}
}
}
pub fn send_action(&self, dnd_action: u32) {
if !self.data.is_xwm {
self.client.event(Action {
self_id: self.id,
dnd_action,
})
}
self.client.event(Action {
self_id: self.id,
dnd_action,
})
}
fn accept(&self, parser: MsgParser<'_, '_>) -> Result<(), WlDataOfferError> {

View file

@ -4,9 +4,10 @@ use {
ifs::{
ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
detach_seat, offer_source_to,
detach_seat, offer_source_to_regular_client, offer_source_to_x,
wl_data_device::ClipboardIpc,
wl_data_device_manager::{DND_ALL, DND_NONE},
x_data_device::{XClipboardIpc, XIpcDevice},
DataSource, DynDataOffer, DynDataSource, SharedState, SourceData,
OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED, SOURCE_STATE_CANCELLED,
SOURCE_STATE_DROPPED,
@ -23,7 +24,6 @@ use {
clonecell::CloneCell,
},
wire::{wl_data_source::*, WlDataSourceId},
xwayland::XWaylandEvent,
},
std::rc::Rc,
thiserror::Error,
@ -44,7 +44,7 @@ pub struct WlDataSource {
}
impl DataSource for WlDataSource {
fn send_cancelled(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>) {
fn send_cancelled(&self, seat: &Rc<WlSeatGlobal>) {
WlDataSource::send_cancelled(self, seat);
}
}
@ -54,20 +54,24 @@ impl DynDataSource for WlDataSource {
&self.data
}
fn send_send(self: Rc<Self>, mime_type: &str, fd: Rc<OwnedFd>) {
WlDataSource::send_send(&self, mime_type, fd);
fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
WlDataSource::send_send(self, mime_type, fd);
}
fn offer_to(self: Rc<Self>, client: &Rc<Client>) {
offer_source_to::<ClipboardIpc, Self>(&self, client);
fn offer_to_regular_client(self: Rc<Self>, client: &Rc<Client>) {
offer_source_to_regular_client::<ClipboardIpc, Self>(&self, client);
}
fn detach_seat(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
detach_seat::<ClipboardIpc>(&self, seat);
fn offer_to_x(self: Rc<Self>, dd: &Rc<XIpcDevice>) {
offer_source_to_x::<XClipboardIpc, Self>(&self, dd);
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat);
}
fn cancel_offers(&self) {
cancel_offers::<ClipboardIpc>(self);
cancel_offers(self);
}
fn send_target(&self, mime_type: Option<&str>) {
@ -84,11 +88,11 @@ impl DynDataSource for WlDataSource {
}
impl WlDataSource {
pub fn new(id: WlDataSourceId, client: &Rc<Client>, is_xwm: bool, version: u32) -> Self {
pub fn new(id: WlDataSourceId, client: &Rc<Client>, version: u32) -> Self {
Self {
id,
tracker: Default::default(),
data: SourceData::new(client, is_xwm),
data: SourceData::new(client),
version,
toplevel_drag: Default::default(),
}
@ -108,7 +112,7 @@ impl WlDataSource {
self.data.shared.set(Rc::new(SharedState::default()));
self.send_target(None);
self.send_action(DND_NONE);
cancel_offers::<ClipboardIpc>(self);
cancel_offers(self);
}
pub fn update_selected_action(&self) {
@ -159,74 +163,44 @@ impl WlDataSource {
shared.state.or_assign(OFFER_STATE_DROPPED);
}
pub fn send_cancelled(self: &Rc<Self>, seat: &Rc<WlSeatGlobal>) {
if self.data.is_xwm {
self.data
.client
.state
.xwayland
.queue
.push(XWaylandEvent::ClipboardCancelSource(self.clone()));
} else {
self.data.state.or_assign(SOURCE_STATE_CANCELLED);
if let Some(drag) = self.toplevel_drag.take() {
drag.finish_drag(seat);
}
self.data.client.event(Cancelled { self_id: self.id })
pub fn send_cancelled(&self, seat: &Rc<WlSeatGlobal>) {
self.data.state.or_assign(SOURCE_STATE_CANCELLED);
if let Some(drag) = self.toplevel_drag.take() {
drag.finish_drag(seat);
}
self.data.client.event(Cancelled { self_id: self.id })
}
pub fn send_send(self: &Rc<Self>, mime_type: &str, fd: Rc<OwnedFd>) {
if self.data.is_xwm {
self.data
.client
.state
.xwayland
.queue
.push(XWaylandEvent::ClipboardSendSource(
self.clone(),
mime_type.to_string(),
fd,
));
} else {
self.data.client.event(Send {
self_id: self.id,
mime_type,
fd,
})
}
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_target(&self, mime_type: Option<&str>) {
if !self.data.is_xwm {
self.data.client.event(Target {
self_id: self.id,
mime_type,
})
}
self.data.client.event(Target {
self_id: self.id,
mime_type,
})
}
pub fn send_dnd_finished(&self) {
if !self.data.is_xwm {
self.data.client.event(DndFinished { self_id: self.id })
}
self.data.client.event(DndFinished { self_id: self.id })
}
pub fn send_action(&self, dnd_action: u32) {
if !self.data.is_xwm {
self.data.client.event(Action {
self_id: self.id,
dnd_action,
})
}
self.data.client.event(Action {
self_id: self.id,
dnd_action,
})
}
pub fn send_dnd_drop_performed(&self) {
if !self.data.is_xwm {
self.data
.client
.event(DndDropPerformed { self_id: self.id })
}
self.data
.client
.event(DndDropPerformed { self_id: self.id })
}
fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), WlDataSourceError> {

View file

@ -0,0 +1,134 @@
use {
crate::{
client::{Client, ClientError},
ifs::{
ipc::{
x_data_offer::XDataOffer, x_data_source::XDataSource, DeviceData, IpcLocation,
IpcVtable, OfferData, Role,
},
wl_seat::{WlSeatError, WlSeatGlobal},
},
state::State,
xwayland::XWaylandEvent,
},
std::rc::Rc,
XWaylandEvent::IpcSetOffer,
};
linear_ids!(XIpcDeviceIds, XIpcDeviceId, u64);
pub struct XIpcDevice {
pub id: XIpcDeviceId,
pub clipboard: DeviceData<XDataOffer>,
pub primary_selection: DeviceData<XDataOffer>,
pub seat: Rc<WlSeatGlobal>,
pub state: Rc<State>,
pub client: Rc<Client>,
}
#[derive(Default)]
pub struct XClipboardIpc;
#[derive(Default)]
pub struct XPrimarySelectionIpc;
pub trait XIpc {
const LOCATION: IpcLocation;
fn x_unset(seat: &Rc<WlSeatGlobal>);
fn x_device_data(dd: &XIpcDevice) -> &DeviceData<XDataOffer>;
}
impl XIpc for XClipboardIpc {
const LOCATION: IpcLocation = IpcLocation::Clipboard;
fn x_unset(seat: &Rc<WlSeatGlobal>) {
seat.unset_selection();
}
fn x_device_data(dd: &XIpcDevice) -> &DeviceData<XDataOffer> {
&dd.clipboard
}
}
impl XIpc for XPrimarySelectionIpc {
const LOCATION: IpcLocation = IpcLocation::PrimarySelection;
fn x_unset(seat: &Rc<WlSeatGlobal>) {
seat.unset_primary_selection();
}
fn x_device_data(dd: &XIpcDevice) -> &DeviceData<XDataOffer> {
&dd.primary_selection
}
}
impl<T: XIpc> IpcVtable for T {
const LOCATION: IpcLocation = T::LOCATION;
type Device = XIpcDevice;
type Source = XDataSource;
type Offer = XDataOffer;
fn get_device_data(dd: &Self::Device) -> &DeviceData<Self::Offer> {
T::x_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> {
match source.location {
IpcLocation::Clipboard => seat.set_selection(Some(source.clone())),
IpcLocation::PrimarySelection => seat.set_primary_selection(Some(source.clone())),
}
}
fn create_offer(
dd: &Rc<Self::Device>,
data: OfferData<Self::Device>,
) -> Result<Rc<Self::Offer>, ClientError> {
debug_assert!(dd.client.is_xwayland);
let rc = Rc::new(XDataOffer {
offer_id: dd.state.data_offer_ids.next(),
device: dd.clone(),
data,
tracker: Default::default(),
location: T::LOCATION,
});
track!(dd.client, rc);
Ok(rc)
}
fn send_selection(dd: &Self::Device, offer: Option<&Rc<Self::Offer>>) {
dd.state
.xwayland
.queue
.push(XWaylandEvent::IpcSetSelection {
seat: dd.seat.id(),
location: T::LOCATION,
offer: offer.cloned(),
});
}
fn send_offer(dd: &Self::Device, offer: &Rc<Self::Offer>) {
dd.state.xwayland.queue.push(IpcSetOffer {
location: T::LOCATION,
seat: dd.seat.id(),
offer: offer.clone(),
});
}
fn unset(seat: &Rc<WlSeatGlobal>, _role: Role) {
T::x_unset(seat)
}
fn device_client(dd: &Rc<Self::Device>) -> &Rc<Client> {
&dd.client
}
}

View file

@ -0,0 +1,70 @@
use {
crate::{
client::ClientId,
ifs::{
ipc::{
cancel_offer, destroy_data_offer,
x_data_device::{XClipboardIpc, XIpcDevice, XPrimarySelectionIpc},
DataOffer, DataOfferId, DynDataOffer, IpcLocation, OfferData,
},
wl_seat::WlSeatGlobal,
},
leaks::Tracker,
xwayland::XWaylandEvent,
},
std::rc::Rc,
XWaylandEvent::IpcAddOfferMimeType,
};
pub struct XDataOffer {
pub offer_id: DataOfferId,
pub device: Rc<XIpcDevice>,
pub data: OfferData<XIpcDevice>,
pub tracker: Tracker<Self>,
pub location: IpcLocation,
}
impl DataOffer for XDataOffer {
type Device = XIpcDevice;
fn offer_data(&self) -> &OfferData<Self::Device> {
&self.data
}
}
impl DynDataOffer for XDataOffer {
fn offer_id(&self) -> DataOfferId {
self.offer_id
}
fn client_id(&self) -> ClientId {
self.device.client.id
}
fn send_offer(&self, mime_type: &str) {
self.device.state.xwayland.queue.push(IpcAddOfferMimeType {
location: self.location,
seat: self.device.seat.id(),
offer: self.offer_id,
mime_type: mime_type.to_string(),
})
}
fn destroy(&self) {
match self.location {
IpcLocation::Clipboard => destroy_data_offer::<XClipboardIpc>(self),
IpcLocation::PrimarySelection => destroy_data_offer::<XPrimarySelectionIpc>(self),
}
}
fn cancel(&self) {
match self.location {
IpcLocation::Clipboard => cancel_offer::<XClipboardIpc>(self),
IpcLocation::PrimarySelection => cancel_offer::<XPrimarySelectionIpc>(self),
}
}
fn get_seat(&self) -> Rc<WlSeatGlobal> {
self.device.seat.clone()
}
}

View file

@ -0,0 +1,79 @@
use {
crate::{
client::Client,
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,
},
wl_seat::WlSeatGlobal,
},
state::State,
xwayland::XWaylandEvent::{IpcCancelSource, IpcSendSource, IpcSetSelection},
},
std::rc::Rc,
uapi::OwnedFd,
};
pub struct XDataSource {
pub state: Rc<State>,
pub device: Rc<XIpcDevice>,
pub data: SourceData,
pub location: IpcLocation,
}
impl DataSource for XDataSource {
fn send_cancelled(&self, seat: &Rc<WlSeatGlobal>) {
self.state.xwayland.queue.push(IpcCancelSource {
location: self.location,
seat: seat.id(),
source: self.data.id,
});
}
}
impl DynDataSource for XDataSource {
fn source_data(&self) -> &SourceData {
&self.data
}
fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
self.state.xwayland.queue.push(IpcSendSource {
location: self.location,
seat: self.device.seat.id(),
source: self.data.id,
mime_type: mime_type.to_string(),
fd,
});
}
fn offer_to_regular_client(self: Rc<Self>, client: &Rc<Client>) {
match self.location {
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>) {
self.cancel_offers();
self.state.xwayland.queue.push(IpcSetSelection {
location: self.location,
seat: self.device.seat.id(),
offer: None,
});
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat);
}
fn cancel_offers(&self) {
cancel_offers(self)
}
}

View file

@ -55,11 +55,7 @@ impl ZwpPrimarySelectionDeviceManagerV1 {
parser: MsgParser<'_, '_>,
) -> Result<(), ZwpPrimarySelectionDeviceManagerV1Error> {
let req: CreateSource = self.client.parse(self, parser)?;
let res = Rc::new(ZwpPrimarySelectionSourceV1::new(
req.id,
&self.client,
false,
));
let res = Rc::new(ZwpPrimarySelectionSourceV1::new(req.id, &self.client));
track!(self.client, res);
self.client.add_client_obj(&res)?;
Ok(())
@ -76,7 +72,6 @@ impl ZwpPrimarySelectionDeviceManagerV1 {
&self.client,
self.version,
&seat.global,
false,
));
track!(self.client, dev);
seat.global.add_primary_selection_device(&dev);

View file

@ -6,7 +6,7 @@ use {
break_device_loops, destroy_data_device,
zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1,
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, DeviceData,
IpcVtable, OfferData, Role, XIpcVtable,
IpcLocation, IpcVtable, IterableIpcVtable, OfferData, Role,
},
wl_seat::{WlSeatError, WlSeatGlobal},
},
@ -15,9 +15,8 @@ use {
utils::buffd::{MsgParser, MsgParserError},
wire::{
zwp_primary_selection_device_v1::*, ZwpPrimarySelectionDeviceV1Id,
ZwpPrimarySelectionOfferV1Id, ZwpPrimarySelectionSourceV1Id,
ZwpPrimarySelectionOfferV1Id,
},
xwayland::XWaylandEvent,
},
std::rc::Rc,
thiserror::Error,
@ -38,56 +37,32 @@ impl ZwpPrimarySelectionDeviceV1 {
client: &Rc<Client>,
version: u32,
seat: &Rc<WlSeatGlobal>,
is_xwm: bool,
) -> Self {
Self {
id,
client: client.clone(),
version,
seat: seat.clone(),
data: DeviceData {
selection: Default::default(),
dnd: Default::default(),
is_xwm,
},
data: Default::default(),
tracker: Default::default(),
}
}
pub fn send_data_offer(&self, offer: &Rc<ZwpPrimarySelectionOfferV1>) {
if self.data.is_xwm {
self.client
.state
.xwayland
.queue
.push(XWaylandEvent::PrimarySelectionSetOffer(offer.clone()));
} else {
self.client.event(DataOffer {
self_id: self.id,
offer: offer.id,
})
}
self.client.event(DataOffer {
self_id: self.id,
offer: offer.id,
})
}
pub fn send_selection(&self, offer: Option<&Rc<ZwpPrimarySelectionOfferV1>>) {
if self.data.is_xwm {
self.client
.state
.xwayland
.queue
.push(XWaylandEvent::PrimarySelectionSetSelection(
self.seat.id(),
offer.cloned(),
));
} else {
let id = offer
.map(|o| o.id)
.unwrap_or(ZwpPrimarySelectionOfferV1Id::NONE);
self.client.event(Selection {
self_id: self.id,
id,
})
}
let id = offer
.map(|o| o.id)
.unwrap_or(ZwpPrimarySelectionOfferV1Id::NONE);
self.client.event(Selection {
self_id: self.id,
id,
})
}
fn set_selection(
@ -126,17 +101,18 @@ impl ZwpPrimarySelectionDeviceV1 {
pub struct PrimarySelectionIpc;
impl XIpcVtable for PrimarySelectionIpc {
fn create_xwm_source(client: &Rc<Client>) -> Self::Source {
ZwpPrimarySelectionSourceV1::new(ZwpPrimarySelectionSourceV1Id::NONE, client, true)
}
fn remove_from_seat(device: &Self::Device) {
device.seat.remove_primary_selection_device(device);
impl IterableIpcVtable for PrimarySelectionIpc {
fn for_each_device<C>(seat: &WlSeatGlobal, client: ClientId, f: C)
where
C: FnMut(&Rc<Self::Device>),
{
seat.for_each_primary_selection_device(0, client, f)
}
}
impl IpcVtable for PrimarySelectionIpc {
const LOCATION: IpcLocation = IpcLocation::PrimarySelection;
type Device = ZwpPrimarySelectionDeviceV1;
type Source = ZwpPrimarySelectionSourceV1;
type Offer = ZwpPrimarySelectionOfferV1;
@ -157,32 +133,20 @@ impl IpcVtable for PrimarySelectionIpc {
seat.set_zwp_primary_selection(Some(source.clone()), serial)
}
fn for_each_device<C>(seat: &WlSeatGlobal, client: ClientId, f: C)
where
C: FnMut(&Rc<Self::Device>),
{
seat.for_each_primary_selection_device(0, client, f)
}
fn create_offer(
client: &Rc<Client>,
device: &Rc<ZwpPrimarySelectionDeviceV1>,
offer_data: OfferData<Self::Device>,
) -> Result<Rc<Self::Offer>, ClientError> {
let id = if device.data.is_xwm {
ZwpPrimarySelectionOfferV1Id::NONE
} else {
client.new_id()?
};
let rc = Rc::new(ZwpPrimarySelectionOfferV1 {
id,
offer_id: client.state.data_offer_ids.next(),
id: device.client.new_id()?,
offer_id: device.client.state.data_offer_ids.next(),
seat: device.seat.clone(),
client: client.clone(),
client: device.client.clone(),
data: offer_data,
tracker: Default::default(),
});
track!(client, rc);
track!(device.client, rc);
device.client.add_server_obj(&rc);
Ok(rc)
}
@ -197,6 +161,10 @@ impl IpcVtable for PrimarySelectionIpc {
fn unset(seat: &Rc<WlSeatGlobal>, _role: Role) {
seat.unset_primary_selection();
}
fn device_client(dd: &Rc<Self::Device>) -> &Rc<Client> {
&dd.client
}
}
object_base! {

View file

@ -15,7 +15,6 @@ use {
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwp_primary_selection_offer_v1::*, ZwpPrimarySelectionOfferV1Id},
xwayland::XWaylandEvent,
},
std::rc::Rc,
thiserror::Error,
@ -47,8 +46,8 @@ impl DynDataOffer for ZwpPrimarySelectionOfferV1 {
self.client.id
}
fn send_offer(self: Rc<Self>, mime_type: &str) {
ZwpPrimarySelectionOfferV1::send_offer(&self, mime_type);
fn send_offer(&self, mime_type: &str) {
ZwpPrimarySelectionOfferV1::send_offer(self, mime_type);
}
fn destroy(&self) {
@ -65,24 +64,11 @@ impl DynDataOffer for ZwpPrimarySelectionOfferV1 {
}
impl ZwpPrimarySelectionOfferV1 {
pub fn send_offer(self: &Rc<Self>, mime_type: &str) {
if self.data.is_xwm {
if let Some(src) = self.data.source.get() {
if !src.source_data().is_xwm {
self.client.state.xwayland.queue.push(
XWaylandEvent::PrimarySelectionAddOfferMimeType(
self.clone(),
mime_type.to_string(),
),
);
}
}
} else {
self.client.event(Offer {
self_id: self.id,
mime_type,
})
}
pub fn send_offer(&self, mime_type: &str) {
self.client.event(Offer {
self_id: self.id,
mime_type,
})
}
fn receive(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwpPrimarySelectionOfferV1Error> {

View file

@ -4,7 +4,9 @@ use {
ifs::{
ipc::{
add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source,
detach_seat, offer_source_to, zwp_primary_selection_device_v1::PrimarySelectionIpc,
detach_seat, offer_source_to_regular_client, offer_source_to_x,
x_data_device::{XIpcDevice, XPrimarySelectionIpc},
zwp_primary_selection_device_v1::PrimarySelectionIpc,
DataSource, DynDataSource, SourceData,
},
wl_seat::WlSeatGlobal,
@ -13,7 +15,6 @@ use {
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{zwp_primary_selection_source_v1::*, ZwpPrimarySelectionSourceV1Id},
xwayland::XWaylandEvent,
},
std::rc::Rc,
thiserror::Error,
@ -27,7 +28,7 @@ pub struct ZwpPrimarySelectionSourceV1 {
}
impl DataSource for ZwpPrimarySelectionSourceV1 {
fn send_cancelled(self: &Rc<Self>, _seat: &Rc<WlSeatGlobal>) {
fn send_cancelled(&self, _seat: &Rc<WlSeatGlobal>) {
ZwpPrimarySelectionSourceV1::send_cancelled(self);
}
}
@ -37,64 +38,46 @@ impl DynDataSource for ZwpPrimarySelectionSourceV1 {
&self.data
}
fn send_send(self: Rc<Self>, mime_type: &str, fd: Rc<OwnedFd>) {
ZwpPrimarySelectionSourceV1::send_send(&self, mime_type, fd)
fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
ZwpPrimarySelectionSourceV1::send_send(self, mime_type, fd)
}
fn offer_to(self: Rc<Self>, client: &Rc<Client>) {
offer_source_to::<PrimarySelectionIpc, Self>(&self, client);
fn offer_to_regular_client(self: Rc<Self>, client: &Rc<Client>) {
offer_source_to_regular_client::<PrimarySelectionIpc, Self>(&self, client);
}
fn detach_seat(self: Rc<Self>, seat: &Rc<WlSeatGlobal>) {
detach_seat::<PrimarySelectionIpc>(&self, seat);
fn offer_to_x(self: Rc<Self>, dd: &Rc<XIpcDevice>) {
offer_source_to_x::<XPrimarySelectionIpc, Self>(&self, dd);
}
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>) {
detach_seat(self, seat);
}
fn cancel_offers(&self) {
cancel_offers::<PrimarySelectionIpc>(self);
cancel_offers(self);
}
}
impl ZwpPrimarySelectionSourceV1 {
pub fn new(id: ZwpPrimarySelectionSourceV1Id, client: &Rc<Client>, is_xwm: bool) -> Self {
pub fn new(id: ZwpPrimarySelectionSourceV1Id, client: &Rc<Client>) -> Self {
Self {
id,
data: SourceData::new(client, is_xwm),
data: SourceData::new(client),
tracker: Default::default(),
}
}
pub fn send_cancelled(self: &Rc<Self>) {
if self.data.is_xwm {
self.data
.client
.state
.xwayland
.queue
.push(XWaylandEvent::PrimarySelectionCancelSource(self.clone()));
} else {
self.data.client.event(Cancelled { self_id: self.id });
}
pub fn send_cancelled(&self) {
self.data.client.event(Cancelled { self_id: self.id });
}
pub fn send_send(self: &Rc<Self>, mime_type: &str, fd: Rc<OwnedFd>) {
if self.data.is_xwm {
self.data
.client
.state
.xwayland
.queue
.push(XWaylandEvent::PrimarySelectionSendSource(
self.clone(),
mime_type.to_string(),
fd,
));
} else {
self.data.client.event(Send {
self_id: self.id,
mime_type,
fd,
})
}
pub fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>) {
self.data.client.event(Send {
self_id: self.id,
mime_type,
fd,
})
}
fn offer(&self, parser: MsgParser<'_, '_>) -> Result<(), ZwpPrimarySelectionSourceV1Error> {