wayland: implement wlr-data-control
This commit is contained in:
parent
8bca8b0e86
commit
99be020c19
18 changed files with 985 additions and 33 deletions
|
|
@ -3,7 +3,7 @@ use {
|
|||
client::{Client, ClientError},
|
||||
ifs::{
|
||||
ipc::{
|
||||
wl_data_source::WlDataSource,
|
||||
wl_data_source::WlDataSource, zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
|
||||
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
|
||||
},
|
||||
jay_output::JayOutput,
|
||||
|
|
@ -32,7 +32,7 @@ use {
|
|||
JayOutputId, JayScreencastId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId,
|
||||
WlPointerId, WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId,
|
||||
WpLinuxDrmSyncobjTimelineV1Id, XdgPositionerId, XdgSurfaceId, XdgToplevelId,
|
||||
XdgWmBaseId, ZwpPrimarySelectionSourceV1Id,
|
||||
XdgWmBaseId, ZwlrDataControlSourceV1Id, ZwpPrimarySelectionSourceV1Id,
|
||||
},
|
||||
},
|
||||
std::{cell::RefCell, mem, rc::Rc},
|
||||
|
|
@ -59,6 +59,7 @@ pub struct Objects {
|
|||
pub seats: CopyHashMap<WlSeatId, Rc<WlSeat>>,
|
||||
pub screencasts: CopyHashMap<JayScreencastId, Rc<JayScreencast>>,
|
||||
pub timelines: CopyHashMap<WpLinuxDrmSyncobjTimelineV1Id, Rc<WpLinuxDrmSyncobjTimelineV1>>,
|
||||
pub zwlr_data_sources: CopyHashMap<ZwlrDataControlSourceV1Id, Rc<ZwlrDataControlSourceV1>>,
|
||||
ids: RefCell<Vec<usize>>,
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +88,7 @@ impl Objects {
|
|||
seats: Default::default(),
|
||||
screencasts: Default::default(),
|
||||
timelines: Default::default(),
|
||||
zwlr_data_sources: Default::default(),
|
||||
ids: RefCell::new(vec![]),
|
||||
}
|
||||
}
|
||||
|
|
@ -118,6 +120,8 @@ impl Objects {
|
|||
self.seats.clear();
|
||||
self.pointers.clear();
|
||||
self.screencasts.clear();
|
||||
self.timelines.clear();
|
||||
self.zwlr_data_sources.clear();
|
||||
}
|
||||
|
||||
pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use {
|
|||
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
|
||||
ipc::{
|
||||
wl_data_device_manager::WlDataDeviceManagerGlobal,
|
||||
zwlr_data_control_manager_v1::ZwlrDataControlManagerV1Global,
|
||||
zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1Global,
|
||||
},
|
||||
jay_compositor::JayCompositorGlobal,
|
||||
|
|
@ -171,6 +172,7 @@ impl Globals {
|
|||
add_singleton!(ZwpIdleInhibitManagerV1Global);
|
||||
add_singleton!(ExtIdleNotifierV1Global);
|
||||
add_singleton!(XdgToplevelDragManagerV1Global);
|
||||
add_singleton!(ZwlrDataControlManagerV1Global);
|
||||
}
|
||||
|
||||
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ use {
|
|||
client::{Client, ClientError, ClientId},
|
||||
fixed::Fixed,
|
||||
ifs::{
|
||||
ipc::x_data_device::XIpcDevice,
|
||||
ipc::{
|
||||
x_data_device::XIpcDevice, zwlr_data_control_device_v1::ZwlrDataControlDeviceV1,
|
||||
},
|
||||
wl_seat::{WlSeatError, WlSeatGlobal},
|
||||
},
|
||||
utils::{
|
||||
|
|
@ -31,6 +33,10 @@ pub mod wl_data_source;
|
|||
pub mod x_data_device;
|
||||
pub mod x_data_offer;
|
||||
pub mod x_data_source;
|
||||
pub mod zwlr_data_control_device_v1;
|
||||
pub mod zwlr_data_control_manager_v1;
|
||||
pub mod zwlr_data_control_offer_v1;
|
||||
pub mod zwlr_data_control_source_v1;
|
||||
pub mod zwp_primary_selection_device_manager_v1;
|
||||
pub mod zwp_primary_selection_device_v1;
|
||||
pub mod zwp_primary_selection_offer_v1;
|
||||
|
|
@ -60,8 +66,9 @@ pub trait DynDataSource: 'static {
|
|||
fn send_send(&self, mime_type: &str, fd: Rc<OwnedFd>);
|
||||
fn offer_to_regular_client(self: Rc<Self>, client: &Rc<Client>);
|
||||
fn offer_to_x(self: Rc<Self>, dd: &Rc<XIpcDevice>);
|
||||
fn offer_to_wlr_device(self: Rc<Self>, dd: &Rc<ZwlrDataControlDeviceV1>);
|
||||
fn detach_seat(&self, seat: &Rc<WlSeatGlobal>);
|
||||
fn cancel_offers(&self);
|
||||
fn cancel_unprivileged_offers(&self);
|
||||
|
||||
fn send_target(&self, mime_type: Option<&str>) {
|
||||
let _ = mime_type;
|
||||
|
|
@ -98,6 +105,10 @@ pub trait DynDataOffer: 'static {
|
|||
fn cancel(&self);
|
||||
fn get_seat(&self) -> Rc<WlSeatGlobal>;
|
||||
|
||||
fn is_privileged(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn send_action(&self, action: u32) {
|
||||
let _ = action;
|
||||
log::warn!(
|
||||
|
|
@ -129,6 +140,12 @@ pub trait IterableIpcVtable: IpcVtable {
|
|||
C: FnMut(&Rc<Self::Device>);
|
||||
}
|
||||
|
||||
pub trait WlrIpcVtable: IpcVtable<Device = ZwlrDataControlDeviceV1> {
|
||||
fn for_each_device<C>(seat: &WlSeatGlobal, f: C)
|
||||
where
|
||||
C: FnMut(&Rc<Self::Device>);
|
||||
}
|
||||
|
||||
pub trait IpcVtable: Sized {
|
||||
const LOCATION: IpcLocation;
|
||||
|
||||
|
|
@ -277,11 +294,17 @@ pub fn attach_seat<S: DynDataSource>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn cancel_offers<S: DynDataSource>(src: &S) {
|
||||
pub fn cancel_offers<S: DynDataSource>(src: &S, cancel_privileged: bool) {
|
||||
let data = src.source_data();
|
||||
while let Some((_, offer)) = data.offers.pop() {
|
||||
offer.cancel();
|
||||
}
|
||||
let mut offers = data.offers.take();
|
||||
offers.retain(|o| {
|
||||
let retain = !cancel_privileged && o.1.is_privileged();
|
||||
if !retain {
|
||||
o.1.cancel();
|
||||
}
|
||||
retain
|
||||
});
|
||||
data.offers.replace(offers);
|
||||
}
|
||||
|
||||
pub fn cancel_offer<T: IpcVtable>(offer: &T::Offer) {
|
||||
|
|
@ -293,7 +316,7 @@ pub fn cancel_offer<T: IpcVtable>(offer: &T::Offer) {
|
|||
pub fn detach_seat<S: DataSource>(src: &S, seat: &Rc<WlSeatGlobal>) {
|
||||
let data = src.source_data();
|
||||
data.seat.set(None);
|
||||
cancel_offers(src);
|
||||
cancel_offers(src, true);
|
||||
if !data.state.get().contains(SOURCE_STATE_FINISHED) {
|
||||
src.send_cancelled(seat);
|
||||
}
|
||||
|
|
@ -342,12 +365,23 @@ where
|
|||
S: DynDataSource,
|
||||
{
|
||||
let data = src.source_data();
|
||||
src.cancel_offers();
|
||||
src.cancel_unprivileged_offers();
|
||||
let shared = data.shared.get();
|
||||
shared.role.set(data.role.get());
|
||||
offer_source_to_device::<T, S>(src, dd, data, shared);
|
||||
}
|
||||
|
||||
pub fn offer_source_to_wlr_device<T, S>(src: &Rc<S>, dd: &Rc<T::Device>)
|
||||
where
|
||||
T: IpcVtable<Device = ZwlrDataControlDeviceV1>,
|
||||
S: DynDataSource,
|
||||
{
|
||||
let data = src.source_data();
|
||||
let shared = data.shared.get();
|
||||
shared.role.set(data.role.get());
|
||||
offer_source_to_device::<T, _>(src, dd, data, shared);
|
||||
}
|
||||
|
||||
fn offer_source_to_regular_client<T: IterableIpcVtable, S: DynDataSource>(
|
||||
src: &Rc<S>,
|
||||
client: &Rc<Client>,
|
||||
|
|
@ -360,7 +394,7 @@ fn offer_source_to_regular_client<T: IterableIpcVtable, S: DynDataSource>(
|
|||
return;
|
||||
}
|
||||
};
|
||||
src.cancel_offers();
|
||||
src.cancel_unprivileged_offers();
|
||||
let shared = data.shared.get();
|
||||
shared.role.set(data.role.get());
|
||||
T::for_each_device(&seat, client.id, |dd| {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
306
src/ifs/ipc/zwlr_data_control_device_v1.rs
Normal file
306
src/ifs/ipc/zwlr_data_control_device_v1.rs
Normal 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);
|
||||
145
src/ifs/ipc/zwlr_data_control_manager_v1.rs
Normal file
145
src/ifs/ipc/zwlr_data_control_manager_v1.rs
Normal 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);
|
||||
135
src/ifs/ipc/zwlr_data_control_offer_v1.rs
Normal file
135
src/ifs/ipc/zwlr_data_control_offer_v1.rs
Normal 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);
|
||||
169
src/ifs/ipc/zwlr_data_control_source_v1.rs
Normal file
169
src/ifs/ipc/zwlr_data_control_source_v1.rs
Normal 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);
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ use {
|
|||
wl_data_device::{ClipboardIpc, WlDataDevice},
|
||||
wl_data_source::WlDataSource,
|
||||
x_data_device::{XClipboardIpc, XIpcDevice, XIpcDeviceId, XPrimarySelectionIpc},
|
||||
zwlr_data_control_device_v1::{
|
||||
WlrClipboardIpc, WlrPrimarySelectionIpc, ZwlrDataControlDeviceV1,
|
||||
},
|
||||
zwp_primary_selection_device_v1::{
|
||||
PrimarySelectionIpc, ZwpPrimarySelectionDeviceV1,
|
||||
},
|
||||
|
|
@ -64,7 +67,8 @@ use {
|
|||
},
|
||||
wire::{
|
||||
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
||||
WlSeatId, ZwpPrimarySelectionDeviceV1Id, ZwpRelativePointerV1Id,
|
||||
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
||||
ZwpRelativePointerV1Id,
|
||||
},
|
||||
xkbcommon::{XkbKeymap, XkbState},
|
||||
},
|
||||
|
|
@ -141,6 +145,8 @@ pub struct WlSeatGlobal {
|
|||
AHashMap<ZwpPrimarySelectionDeviceV1Id, Rc<ZwpPrimarySelectionDeviceV1>>,
|
||||
>,
|
||||
>,
|
||||
wlr_data_devices:
|
||||
CopyHashMap<(ClientId, ZwlrDataControlDeviceV1Id), Rc<ZwlrDataControlDeviceV1>>,
|
||||
repeat_rate: Cell<(i32, i32)>,
|
||||
kb_map: CloneCell<Rc<XkbKeymap>>,
|
||||
kb_state: RefCell<XkbState>,
|
||||
|
|
@ -219,6 +225,7 @@ impl WlSeatGlobal {
|
|||
constraint: Default::default(),
|
||||
idle_notifications: Default::default(),
|
||||
last_input_usec: Cell::new(now_usec()),
|
||||
wlr_data_devices: Default::default(),
|
||||
});
|
||||
state.add_cursor_size(*DEFAULT_CURSOR_SIZE);
|
||||
let seat = slf.clone();
|
||||
|
|
@ -394,6 +401,15 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn add_wlr_device(&self, device: &Rc<ZwlrDataControlDeviceV1>) {
|
||||
self.wlr_data_devices
|
||||
.set((device.client.id, device.id), device.clone());
|
||||
}
|
||||
|
||||
pub fn remove_wlr_device(&self, device: &ZwlrDataControlDeviceV1) {
|
||||
self.wlr_data_devices.remove(&(device.client.id, device.id));
|
||||
}
|
||||
|
||||
pub fn get_output(&self) -> Rc<OutputNode> {
|
||||
self.output.get()
|
||||
}
|
||||
|
|
@ -727,7 +743,7 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
fn set_selection_<T, X, S>(
|
||||
fn set_selection_<T, X, W, S>(
|
||||
self: &Rc<Self>,
|
||||
field: &CloneCell<Option<Rc<dyn DynDataSource>>>,
|
||||
src: Option<Rc<S>>,
|
||||
|
|
@ -735,6 +751,7 @@ impl WlSeatGlobal {
|
|||
where
|
||||
T: ipc::IterableIpcVtable,
|
||||
X: ipc::IpcVtable<Device = XIpcDevice>,
|
||||
W: ipc::WlrIpcVtable,
|
||||
S: DynDataSource,
|
||||
{
|
||||
if let (Some(new), Some(old)) = (&src, &field.get()) {
|
||||
|
|
@ -750,9 +767,13 @@ impl WlSeatGlobal {
|
|||
old.detach_seat(self);
|
||||
}
|
||||
if let Some(client) = self.keyboard_node.get().node_client() {
|
||||
self.offer_selection_to_client::<T, X>(src.map(|v| v as Rc<_>), &client);
|
||||
self.offer_selection_to_client::<T, X>(src.clone().map(|v| v as Rc<_>), &client);
|
||||
// client.flush();
|
||||
}
|
||||
W::for_each_device(self, |device| match &src {
|
||||
Some(src) => src.clone().offer_to_wlr_device(device),
|
||||
_ => W::send_selection(device, None),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -765,7 +786,7 @@ impl WlSeatGlobal {
|
|||
X: ipc::IpcVtable<Device = XIpcDevice>,
|
||||
{
|
||||
if let Some(src) = &selection {
|
||||
src.cancel_offers();
|
||||
src.cancel_unprivileged_offers();
|
||||
}
|
||||
if client.is_xwayland {
|
||||
self.for_each_x_data_device(|dd| match &selection {
|
||||
|
|
@ -824,7 +845,14 @@ impl WlSeatGlobal {
|
|||
self: &Rc<Self>,
|
||||
selection: Option<Rc<S>>,
|
||||
) -> Result<(), WlSeatError> {
|
||||
self.set_selection_::<ClipboardIpc, XClipboardIpc, _>(&self.selection, selection)
|
||||
self.set_selection_::<ClipboardIpc, XClipboardIpc, WlrClipboardIpc, _>(
|
||||
&self.selection,
|
||||
selection,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_selection(&self) -> Option<Rc<dyn DynDataSource>> {
|
||||
self.selection.get()
|
||||
}
|
||||
|
||||
pub fn may_modify_selection(&self, client: &Rc<Client>, serial: u32) -> bool {
|
||||
|
|
@ -865,12 +893,16 @@ impl WlSeatGlobal {
|
|||
self: &Rc<Self>,
|
||||
selection: Option<Rc<S>>,
|
||||
) -> Result<(), WlSeatError> {
|
||||
self.set_selection_::<PrimarySelectionIpc, XPrimarySelectionIpc, _>(
|
||||
self.set_selection_::<PrimarySelectionIpc, XPrimarySelectionIpc, WlrPrimarySelectionIpc, _>(
|
||||
&self.primary_selection,
|
||||
selection,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_primary_selection(&self) -> Option<Rc<dyn DynDataSource>> {
|
||||
self.primary_selection.get()
|
||||
}
|
||||
|
||||
pub fn reload_known_cursor(&self) {
|
||||
if let Some(kc) = self.desired_known_cursor.get() {
|
||||
self.set_known_cursor(kc);
|
||||
|
|
@ -978,6 +1010,7 @@ impl WlSeatGlobal {
|
|||
self.bindings.borrow_mut().clear();
|
||||
self.data_devices.borrow_mut().clear();
|
||||
self.primary_selection_devices.borrow_mut().clear();
|
||||
self.wlr_data_devices.clear();
|
||||
self.cursor.set(None);
|
||||
self.selection.set(None);
|
||||
self.primary_selection.set(None);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use {
|
|||
ipc::{
|
||||
wl_data_device::{ClipboardIpc, WlDataDevice},
|
||||
x_data_device::{XClipboardIpc, XPrimarySelectionIpc},
|
||||
zwlr_data_control_device_v1::ZwlrDataControlDeviceV1,
|
||||
zwp_primary_selection_device_v1::{
|
||||
PrimarySelectionIpc, ZwpPrimarySelectionDeviceV1,
|
||||
},
|
||||
|
|
@ -508,6 +509,17 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn for_each_wlr_data_device<C>(&self, ver: u32, mut f: C)
|
||||
where
|
||||
C: FnMut(&Rc<ZwlrDataControlDeviceV1>),
|
||||
{
|
||||
for dd in self.wlr_data_devices.lock().values() {
|
||||
if dd.version >= ver {
|
||||
f(dd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn surface_pointer_frame(&self, surface: &WlSurface) {
|
||||
self.surface_pointer_event(POINTER_FRAME_SINCE_VERSION, surface, |p| p.send_frame());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,6 +76,10 @@ impl<K: Eq, V, const N: usize> SmallMap<K, V, N> {
|
|||
unsafe { self.m.get().deref_mut().take() }
|
||||
}
|
||||
|
||||
pub fn replace(&self, other: SmallVec<[(K, V); N]>) -> SmallVec<[(K, V); N]> {
|
||||
unsafe { mem::replace(&mut self.m.get().deref_mut().m, other) }
|
||||
}
|
||||
|
||||
pub fn pop(&self) -> Option<(K, V)> {
|
||||
unsafe { self.m.get().deref_mut().pop() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1733,13 +1733,13 @@ impl Wm {
|
|||
data: SourceData::new(&self.client),
|
||||
location: T::LOCATION,
|
||||
});
|
||||
for target in &targets {
|
||||
add_data_source_mime_type::<T>(&source, target);
|
||||
}
|
||||
if let Err(e) = T::set_seat_selection(&seat, &source, None) {
|
||||
log::error!("Could not set selection: {}", ErrorFmt(e));
|
||||
return Ok(());
|
||||
}
|
||||
for target in &targets {
|
||||
add_data_source_mime_type::<T>(&source, target);
|
||||
}
|
||||
sd.sources.set(seat.id(), source);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
30
wire/zwlr_data_control_device_v1.txt
Normal file
30
wire/zwlr_data_control_device_v1.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# requests
|
||||
|
||||
msg set_selection = 0 {
|
||||
source: id(zwlr_data_control_source_v1),
|
||||
}
|
||||
|
||||
msg destroy = 1 {
|
||||
|
||||
}
|
||||
|
||||
msg set_primary_selection = 2 {
|
||||
source: id(zwlr_data_control_source_v1),
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
msg data_offer = 0 {
|
||||
id: id(zwlr_data_control_offer_v1),
|
||||
}
|
||||
|
||||
msg selection = 1 {
|
||||
id: id(zwlr_data_control_offer_v1),
|
||||
}
|
||||
|
||||
msg finished = 2 {
|
||||
}
|
||||
|
||||
msg primary_selection = 3 {
|
||||
id: id(zwlr_data_control_offer_v1),
|
||||
}
|
||||
14
wire/zwlr_data_control_manager_v1.txt
Normal file
14
wire/zwlr_data_control_manager_v1.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# requests
|
||||
|
||||
msg create_data_source = 0 {
|
||||
id: id(zwlr_data_control_source_v1),
|
||||
}
|
||||
|
||||
msg get_data_device = 1 {
|
||||
id: id(zwlr_data_control_device_v1),
|
||||
seat: id(wl_seat),
|
||||
}
|
||||
|
||||
msg destroy = 2 {
|
||||
|
||||
}
|
||||
16
wire/zwlr_data_control_offer_v1.txt
Normal file
16
wire/zwlr_data_control_offer_v1.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# requests
|
||||
|
||||
msg receive = 0 {
|
||||
mime_type: str,
|
||||
fd: fd,
|
||||
}
|
||||
|
||||
msg destroy = 1 {
|
||||
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
msg offer = 0 {
|
||||
mime_type: str,
|
||||
}
|
||||
20
wire/zwlr_data_control_source_v1.txt
Normal file
20
wire/zwlr_data_control_source_v1.txt
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# requests
|
||||
|
||||
msg offer = 0 {
|
||||
mime_type: str,
|
||||
}
|
||||
|
||||
msg destroy = 1 {
|
||||
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
msg send = 0 {
|
||||
mime_type: str,
|
||||
fd: fd,
|
||||
}
|
||||
|
||||
msg cancelled = 1 {
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue