diff --git a/src/ifs/ipc.rs b/src/ifs/ipc.rs index 45cabda7..e9f320dc 100644 --- a/src/ifs/ipc.rs +++ b/src/ifs/ipc.rs @@ -1,14 +1,18 @@ use { crate::{ client::{Client, ClientError, ClientId, WaylandObject}, + fixed::Fixed, ifs::wl_seat::{WlSeatError, WlSeatGlobal}, utils::{ bitflags::BitflagsExt, cell_ext::CellExt, clonecell::CloneCell, numcell::NumCell, smallmap::SmallMap, }, + wire::WlSurfaceId, }, ahash::AHashSet, + smallvec::SmallVec, std::{ + any, cell::{Cell, RefCell}, ops::Deref, rc::Rc, @@ -35,55 +39,122 @@ pub enum Role { Dnd, } +pub trait DataSource: DynDataSource { + fn send_cancelled(self: &Rc, seat: &Rc); +} + +pub trait DynDataSource: 'static { + fn source_data(&self) -> &SourceData; + fn send_send(self: Rc, mime_type: &str, fd: Rc); + fn offer_to(self: Rc, client: &Rc); + fn detach_seat(self: Rc, seat: &Rc); + fn cancel_offers(&self); + + fn send_target(&self, mime_type: Option<&str>) { + let _ = mime_type; + log::warn!( + "send_target called on data source of type {}", + any::type_name_of_val(self) + ) + } + fn send_dnd_finished(&self) { + log::warn!( + "send_dnd_finished called on data source of type {}", + any::type_name_of_val(self) + ) + } + fn update_selected_action(&self) { + log::warn!( + "update_selected_action called on data source of type {}", + any::type_name_of_val(self) + ) + } +} + +pub trait DataOffer: DynDataOffer { + type Device; + + fn offer_data(&self) -> &OfferData; +} + +pub trait DynDataOffer: 'static { + fn offer_id(&self) -> DataOfferId; + fn client_id(&self) -> ClientId; + fn send_offer(self: Rc, mime_type: &str); + fn destroy(&self); + fn cancel(&self); + fn get_seat(&self) -> Rc; + + fn send_action(&self, action: u32) { + let _ = action; + log::warn!( + "send_action called on data source of type {}", + any::type_name_of_val(self) + ) + } + fn send_enter(&self, surface: WlSurfaceId, x: Fixed, y: Fixed, serial: u32) { + let _ = surface; + let _ = x; + let _ = y; + let _ = serial; + log::warn!( + "send_enter called on data source of type {}", + any::type_name_of_val(self) + ) + } + fn send_source_actions(&self) { + log::warn!( + "send_source_actions called on data source of type {}", + any::type_name_of_val(self) + ) + } +} + +pub trait XIpcVtable: IpcVtable { + fn create_xwm_source(client: &Rc) -> Self::Source; + fn remove_from_seat(device: &Self::Device); +} + pub trait IpcVtable: Sized { type Device; - type Source; - type Offer: WaylandObject; + type Source: DataSource; + type Offer: DataOffer + WaylandObject; - fn get_device_data(dd: &Self::Device) -> &DeviceData; + fn get_device_data(dd: &Self::Device) -> &DeviceData; fn get_device_seat(dd: &Self::Device) -> Rc; - fn create_xwm_source(client: &Rc) -> Self::Source; fn set_seat_selection( seat: &Rc, source: &Rc, serial: Option, ) -> Result<(), WlSeatError>; - fn get_offer_data(offer: &Self::Offer) -> &OfferData; - fn get_source_data(src: &Self::Source) -> &SourceData; fn for_each_device(seat: &WlSeatGlobal, client: ClientId, f: C) where C: FnMut(&Rc); fn create_offer( client: &Rc, dd: &Rc, - data: OfferData, + data: OfferData, ) -> Result, ClientError>; fn send_selection(dd: &Self::Device, offer: Option<&Rc>); - fn send_cancelled(source: &Rc, seat: &Rc); - fn get_offer_id(offer: &Self::Offer) -> DataOfferId; fn send_offer(dd: &Self::Device, offer: &Rc); - fn send_mime_type(offer: &Rc, mime_type: &str); fn unset(seat: &Rc, role: Role); - fn send_send(src: &Rc, mime_type: &str, fd: Rc); - fn remove_from_seat(device: &Self::Device); - fn get_offer_seat(offer: &Self::Offer) -> Rc; } -pub struct DeviceData { - selection: CloneCell>>, - dnd: CloneCell>>, +pub struct DeviceData { + selection: CloneCell>>, + dnd: CloneCell>>, pub is_xwm: bool, } -pub struct OfferData { - device: CloneCell>>, - source: CloneCell>>, +pub struct OfferData { + device: CloneCell>>, + source: CloneCell>>, shared: Rc, pub is_xwm: bool, } -impl OfferData { - pub fn source(&self) -> Option> { +impl OfferData { + pub fn source(&self) -> Option> { self.source.get() } } @@ -108,11 +179,10 @@ const SOURCE_STATE_DROPPED: u32 = 1 << 3; const SOURCE_STATE_CANCELLED: u32 = 1 << 4; const SOURCE_STATE_DROPPED_OR_CANCELLED: u32 = SOURCE_STATE_DROPPED | SOURCE_STATE_CANCELLED; -pub struct SourceData { +pub struct SourceData { pub seat: CloneCell>>, pub id: DataSourceId, - offers: SmallMap, 1>, - offer_client: Cell, + offers: SmallMap, 1>, mime_types: RefCell>, pub client: Rc, state: NumCell, @@ -142,13 +212,12 @@ impl Default for SharedState { } } -impl SourceData { +impl SourceData { fn new(client: &Rc, is_xwm: bool) -> Self { Self { seat: Default::default(), id: client.state.data_source_ids.next(), offers: Default::default(), - offer_client: Cell::new(client.id), mime_types: Default::default(), client: client.clone(), state: NumCell::new(0), @@ -170,12 +239,12 @@ impl SourceData { } } -pub fn attach_seat( - src: &T::Source, +pub fn attach_seat( + src: &S, seat: &Rc, role: Role, ) -> Result<(), IpcError> { - let data = T::get_source_data(src); + let data = src.source_data(); let mut state = data.state.get(); if state.contains(SOURCE_STATE_USED) { return Err(IpcError::AlreadyAttached); @@ -197,26 +266,30 @@ pub fn attach_seat( } pub fn cancel_offers(src: &T::Source) { - let data = T::get_source_data(src); + let data = src.source_data(); while let Some((_, offer)) = data.offers.pop() { - let data = T::get_offer_data(&offer); - data.source.take(); - destroy_data_offer::(&offer); + offer.cancel(); } } +pub fn cancel_offer(offer: &T::Offer) { + let data = offer.offer_data(); + data.source.take(); + destroy_data_offer::(&offer); +} + pub fn detach_seat(src: &Rc, seat: &Rc) { - let data = T::get_source_data(src); + let data = src.source_data(); data.seat.set(None); cancel_offers::(src); if !data.state.get().contains(SOURCE_STATE_FINISHED) { - T::send_cancelled(src, seat); + src.send_cancelled(seat); } // data.client.flush(); } -pub fn offer_source_to(src: &Rc, client: &Rc) { - let data = T::get_source_data(src); +pub fn offer_source_to(src: &Rc, client: &Rc) { + let data = src.source_data(); let seat = match data.seat.get() { Some(a) => a, _ => { @@ -224,8 +297,7 @@ pub fn offer_source_to(src: &Rc, client: &Rc) { return; } }; - cancel_offers::(src); - data.offer_client.set(client.id); + src.cancel_offers(); let shared = data.shared.get(); shared.role.set(data.role.get()); T::for_each_device(&seat, client.id, |dd| { @@ -243,11 +315,11 @@ pub fn offer_source_to(src: &Rc, client: &Rc) { return; } }; - data.offers.insert(T::get_offer_id(&offer), offer.clone()); + data.offers.insert(offer.offer_id(), offer.clone()); let mt = data.mime_types.borrow_mut(); T::send_offer(dd, &offer); for mt in mt.deref() { - T::send_mime_type(&offer, mt); + offer.clone().send_offer(mt); } match data.role.get() { Role::Selection => { @@ -265,10 +337,10 @@ pub fn offer_source_to(src: &Rc, client: &Rc) { } pub fn add_data_source_mime_type(src: &T::Source, mime_type: &str) { - let data = T::get_source_data(src); + let data = src.source_data(); if data.mime_types.borrow_mut().insert(mime_type.to_string()) { for (_, offer) in &data.offers { - T::send_mime_type(&offer, mime_type); + offer.send_offer(mime_type); // let data = T::get_offer_data(&offer); // data.client.flush(); } @@ -276,14 +348,14 @@ pub fn add_data_source_mime_type(src: &T::Source, mime_type: &str) } pub fn destroy_data_source(src: &T::Source) { - let data = T::get_source_data(src); + let data = src.source_data(); if let Some(seat) = data.seat.take() { T::unset(&seat, data.role.get()); } } pub fn destroy_data_offer(offer: &T::Offer) { - let data = T::get_offer_data(offer); + let data = offer.offer_data(); if let Some(device) = data.device.take() { let device_data = T::get_device_data(&device); match data.shared.role.get() { @@ -297,8 +369,8 @@ pub fn destroy_data_offer(offer: &T::Offer) { } } if let Some(src) = data.source.take() { - let src_data = T::get_source_data(&src); - src_data.offers.remove(&T::get_offer_id(offer)); + let src_data = src.source_data(); + src_data.offers.remove(&offer.offer_id()); if src_data.offers.is_empty() && src_data.role.get() == Role::Dnd && data.shared.state.get().contains(OFFER_STATE_DROPPED) @@ -314,21 +386,27 @@ pub fn destroy_data_device(dd: &T::Device) { let data = T::get_device_data(dd); let offers = [data.selection.take(), data.dnd.take()]; for offer in offers.into_iter().flat_map(|o| o.into_iter()) { - T::get_offer_data(&offer).device.take(); + offer.offer_data().device.take(); destroy_data_offer::(&offer); } } fn break_source_loops(src: &T::Source) { - let data = T::get_source_data(src); - if data.offer_client.get() == data.client.id { - data.offers.take(); + let data = src.source_data(); + let mut remove = SmallVec::<[DataOfferId; 1]>::new(); + for (id, offer) in &data.offers { + if offer.client_id() == data.client.id { + remove.push(id); + } + } + while let Some(id) = remove.pop() { + data.offers.remove(&id); } destroy_data_source::(src); } fn break_offer_loops(offer: &T::Offer) { - let data = T::get_offer_data(offer); + let data = offer.offer_data(); data.device.set(None); destroy_data_offer::(offer); } @@ -341,9 +419,9 @@ fn break_device_loops(dd: &T::Device) { } pub fn receive_data_offer(offer: &T::Offer, mime_type: &str, fd: Rc) { - let data = T::get_offer_data(offer); + let data = offer.offer_data(); if let Some(src) = data.source.get() { - T::send_send(&src, mime_type, fd); + src.send_send(mime_type, fd); // let data = T::get_source_data(&src); // data.client.flush(); } diff --git a/src/ifs/ipc/wl_data_device.rs b/src/ifs/ipc/wl_data_device.rs index 2fb6bc87..a92ac640 100644 --- a/src/ifs/ipc/wl_data_device.rs +++ b/src/ifs/ipc/wl_data_device.rs @@ -5,8 +5,7 @@ use { ifs::{ ipc::{ break_device_loops, destroy_data_device, wl_data_offer::WlDataOffer, - wl_data_source::WlDataSource, DataOfferId, DeviceData, IpcVtable, OfferData, Role, - SourceData, + wl_data_source::WlDataSource, DeviceData, IpcVtable, OfferData, Role, XIpcVtable, }, wl_seat::{WlSeatError, WlSeatGlobal}, wl_surface::{SurfaceRole, WlSurfaceError}, @@ -19,7 +18,6 @@ use { }, std::rc::Rc, thiserror::Error, - uapi::OwnedFd, }; #[allow(dead_code)] @@ -30,7 +28,7 @@ pub struct WlDataDevice { pub client: Rc, pub version: u32, pub seat: Rc, - pub data: DeviceData, + pub data: DeviceData, pub tracker: Tracker, } @@ -171,7 +169,8 @@ impl WlDataDevice { } else { Some(self.client.lookup(req.source)?) }; - self.seat.set_selection(src, Some(req.serial))?; + self.seat + .set_wl_data_source_selection(src, Some(req.serial))?; Ok(()) } @@ -186,12 +185,22 @@ impl WlDataDevice { pub struct ClipboardIpc; +impl XIpcVtable for ClipboardIpc { + fn create_xwm_source(client: &Rc) -> Self::Source { + WlDataSource::new(WlDataSourceId::NONE, client, true, 3) + } + + fn remove_from_seat(device: &Self::Device) { + device.seat.remove_data_device(device); + } +} + impl IpcVtable for ClipboardIpc { type Device = WlDataDevice; type Source = WlDataSource; type Offer = WlDataOffer; - fn get_device_data(dd: &Self::Device) -> &DeviceData { + fn get_device_data(dd: &Self::Device) -> &DeviceData { &dd.data } @@ -199,24 +208,12 @@ impl IpcVtable for ClipboardIpc { dd.seat.clone() } - fn create_xwm_source(client: &Rc) -> Self::Source { - WlDataSource::new(WlDataSourceId::NONE, client, true, 3) - } - fn set_seat_selection( seat: &Rc, source: &Rc, serial: Option, ) -> Result<(), WlSeatError> { - seat.set_selection(Some(source.clone()), serial) - } - - fn get_offer_data(offer: &Self::Offer) -> &OfferData { - &offer.data - } - - fn get_source_data(src: &Self::Source) -> &SourceData { - &src.data + seat.set_wl_data_source_selection(Some(source.clone()), serial) } fn for_each_device(seat: &WlSeatGlobal, client: ClientId, f: C) @@ -229,7 +226,7 @@ impl IpcVtable for ClipboardIpc { fn create_offer( client: &Rc, device: &Rc, - offer_data: OfferData, + offer_data: OfferData, ) -> Result, ClientError> { let rc = Rc::new(WlDataOffer { id: client.new_id()?, @@ -247,40 +244,16 @@ impl IpcVtable for ClipboardIpc { dd.send_selection(offer); } - fn send_cancelled(source: &Rc, seat: &Rc) { - source.send_cancelled(seat); - } - - fn get_offer_id(offer: &Self::Offer) -> DataOfferId { - offer.offer_id - } - fn send_offer(dd: &Self::Device, offer: &Rc) { dd.send_data_offer(offer); } - fn send_mime_type(offer: &Rc, mime_type: &str) { - offer.send_offer(mime_type); - } - fn unset(seat: &Rc, role: Role) { match role { Role::Selection => seat.unset_selection(), Role::Dnd => seat.cancel_dnd(), } } - - fn send_send(src: &Rc, mime_type: &str, fd: Rc) { - src.send_send(mime_type, fd); - } - - fn remove_from_seat(device: &Self::Device) { - device.seat.remove_data_device(device); - } - - fn get_offer_seat(offer: &Self::Offer) -> Rc { - offer.device.seat.clone() - } } object_base! { diff --git a/src/ifs/ipc/wl_data_offer.rs b/src/ifs/ipc/wl_data_offer.rs index 4c13fc4b..7553dbff 100644 --- a/src/ifs/ipc/wl_data_offer.rs +++ b/src/ifs/ipc/wl_data_offer.rs @@ -1,12 +1,16 @@ use { crate::{ - client::{Client, ClientError}, - ifs::ipc::{ - break_offer_loops, destroy_data_offer, receive_data_offer, - wl_data_device::{ClipboardIpc, WlDataDevice}, - wl_data_device_manager::DND_ALL, - DataOfferId, OfferData, Role, OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED, - OFFER_STATE_FINISHED, SOURCE_STATE_FINISHED, + client::{Client, ClientError, ClientId}, + fixed::Fixed, + ifs::{ + ipc::{ + break_offer_loops, cancel_offer, destroy_data_offer, receive_data_offer, + wl_data_device::{ClipboardIpc, WlDataDevice}, + wl_data_device_manager::DND_ALL, + DataOffer, DataOfferId, DynDataOffer, OfferData, Role, OFFER_STATE_ACCEPTED, + OFFER_STATE_DROPPED, OFFER_STATE_FINISHED, SOURCE_STATE_FINISHED, + }, + wl_seat::WlSeatGlobal, }, leaks::Tracker, object::Object, @@ -14,7 +18,7 @@ use { bitflags::BitflagsExt, buffd::{MsgParser, MsgParserError}, }, - wire::{wl_data_offer::*, WlDataOfferId}, + wire::{wl_data_offer::*, WlDataOfferId, WlSurfaceId}, xwayland::XWaylandEvent, }, std::rc::Rc, @@ -35,15 +39,61 @@ pub struct WlDataOffer { pub offer_id: DataOfferId, pub client: Rc, pub device: Rc, - pub data: OfferData, + pub data: OfferData, pub tracker: Tracker, } +impl DataOffer for WlDataOffer { + type Device = WlDataDevice; + + fn offer_data(&self) -> &OfferData { + &self.data + } +} + +impl DynDataOffer for WlDataOffer { + fn offer_id(&self) -> DataOfferId { + self.offer_id + } + + fn client_id(&self) -> ClientId { + self.client.id + } + + fn send_action(&self, action: u32) { + WlDataOffer::send_action(self, action); + } + + fn send_offer(self: Rc, mime_type: &str) { + WlDataOffer::send_offer(&self, mime_type); + } + + fn destroy(&self) { + destroy_data_offer::(self); + } + + fn cancel(&self) { + cancel_offer::(self); + } + + fn send_enter(&self, surface: WlSurfaceId, x: Fixed, y: Fixed, serial: u32) { + self.device.send_enter(surface, x, y, self.id, serial); + } + + fn send_source_actions(&self) { + WlDataOffer::send_source_actions(self); + } + + fn get_seat(&self) -> Rc { + self.device.seat.clone() + } +} + impl WlDataOffer { pub fn send_offer(self: &Rc, mime_type: &str) { if self.data.is_xwm { if let Some(src) = self.data.source.get() { - if !src.data.is_xwm { + if !src.source_data().is_xwm { self.client.state.xwayland.queue.push( XWaylandEvent::ClipboardAddOfferMimeType( self.clone(), @@ -63,7 +113,7 @@ impl WlDataOffer { 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.data.actions.get() { + if let Some(source_actions) = src.source_data().actions.get() { self.client.event(SourceActions { self_id: self.id, source_actions, @@ -134,7 +184,7 @@ impl WlDataOffer { } state |= OFFER_STATE_FINISHED; if let Some(src) = self.data.source.get() { - src.data.state.or_assign(SOURCE_STATE_FINISHED); + src.source_data().state.or_assign(SOURCE_STATE_FINISHED); src.send_dnd_finished(); } else { log::error!("no source"); diff --git a/src/ifs/ipc/wl_data_source.rs b/src/ifs/ipc/wl_data_source.rs index ff6d9d6b..74aa0948 100644 --- a/src/ifs/ipc/wl_data_source.rs +++ b/src/ifs/ipc/wl_data_source.rs @@ -4,11 +4,12 @@ use { ifs::{ ipc::{ add_data_source_mime_type, break_source_loops, cancel_offers, destroy_data_source, + detach_seat, offer_source_to, wl_data_device::ClipboardIpc, wl_data_device_manager::{DND_ALL, DND_NONE}, - wl_data_offer::WlDataOffer, - SharedState, SourceData, OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED, - SOURCE_STATE_CANCELLED, SOURCE_STATE_DROPPED, + DataSource, DynDataOffer, DynDataSource, SharedState, SourceData, + OFFER_STATE_ACCEPTED, OFFER_STATE_DROPPED, SOURCE_STATE_CANCELLED, + SOURCE_STATE_DROPPED, }, wl_seat::WlSeatGlobal, xdg_toplevel_drag_v1::XdgToplevelDragV1, @@ -36,12 +37,52 @@ const INVALID_SOURCE: u32 = 1; pub struct WlDataSource { pub id: WlDataSourceId, - pub data: SourceData, + pub data: SourceData, pub version: u32, pub tracker: Tracker, pub toplevel_drag: CloneCell>>, } +impl DataSource for WlDataSource { + fn send_cancelled(self: &Rc, seat: &Rc) { + WlDataSource::send_cancelled(self, seat); + } +} + +impl DynDataSource for WlDataSource { + fn source_data(&self) -> &SourceData { + &self.data + } + + fn send_send(self: Rc, mime_type: &str, fd: Rc) { + WlDataSource::send_send(&self, mime_type, fd); + } + + fn offer_to(self: Rc, client: &Rc) { + offer_source_to::(&self, client); + } + + fn detach_seat(self: Rc, seat: &Rc) { + detach_seat::(&self, seat); + } + + fn cancel_offers(&self) { + cancel_offers::(self); + } + + fn send_target(&self, mime_type: Option<&str>) { + WlDataSource::send_target(self, mime_type); + } + + fn send_dnd_finished(&self) { + WlDataSource::send_dnd_finished(self); + } + + fn update_selected_action(&self) { + WlDataSource::update_selected_action(self); + } +} + impl WlDataSource { pub fn new(id: WlDataSourceId, client: &Rc, is_xwm: bool, version: u32) -> Self { Self { @@ -97,9 +138,9 @@ impl WlDataSource { } } - pub fn for_each_data_offer(&self, mut f: C) { + pub fn for_each_data_offer(&self, mut f: C) { for (_, offer) in &self.data.offers { - f(&offer); + f(&*offer); } } diff --git a/src/ifs/ipc/zwp_primary_selection_device_v1.rs b/src/ifs/ipc/zwp_primary_selection_device_v1.rs index 0c589d30..b9a09176 100644 --- a/src/ifs/ipc/zwp_primary_selection_device_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_device_v1.rs @@ -5,8 +5,8 @@ use { ipc::{ break_device_loops, destroy_data_device, zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1, - zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, DataOfferId, - DeviceData, IpcVtable, OfferData, Role, SourceData, + zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, DeviceData, + IpcVtable, OfferData, Role, XIpcVtable, }, wl_seat::{WlSeatError, WlSeatGlobal}, }, @@ -21,7 +21,6 @@ use { }, std::rc::Rc, thiserror::Error, - uapi::OwnedFd, }; pub struct ZwpPrimarySelectionDeviceV1 { @@ -29,7 +28,7 @@ pub struct ZwpPrimarySelectionDeviceV1 { pub client: Rc, pub version: u32, pub seat: Rc, - data: DeviceData, + data: DeviceData, pub tracker: Tracker, } @@ -112,7 +111,7 @@ impl ZwpPrimarySelectionDeviceV1 { } else { Some(self.client.lookup(req.source)?) }; - self.seat.set_primary_selection(src, Some(req.serial))?; + self.seat.set_zwp_primary_selection(src, Some(req.serial))?; Ok(()) } @@ -127,12 +126,22 @@ impl ZwpPrimarySelectionDeviceV1 { pub struct PrimarySelectionIpc; +impl XIpcVtable for PrimarySelectionIpc { + fn create_xwm_source(client: &Rc) -> Self::Source { + ZwpPrimarySelectionSourceV1::new(ZwpPrimarySelectionSourceV1Id::NONE, client, true) + } + + fn remove_from_seat(device: &Self::Device) { + device.seat.remove_primary_selection_device(device); + } +} + impl IpcVtable for PrimarySelectionIpc { type Device = ZwpPrimarySelectionDeviceV1; type Source = ZwpPrimarySelectionSourceV1; type Offer = ZwpPrimarySelectionOfferV1; - fn get_device_data(dd: &Self::Device) -> &DeviceData { + fn get_device_data(dd: &Self::Device) -> &DeviceData { &dd.data } @@ -140,24 +149,12 @@ impl IpcVtable for PrimarySelectionIpc { dd.seat.clone() } - fn create_xwm_source(client: &Rc) -> Self::Source { - ZwpPrimarySelectionSourceV1::new(ZwpPrimarySelectionSourceV1Id::NONE, client, true) - } - fn set_seat_selection( seat: &Rc, source: &Rc, serial: Option, ) -> Result<(), WlSeatError> { - seat.set_primary_selection(Some(source.clone()), serial) - } - - fn get_offer_data(offer: &Self::Offer) -> &OfferData { - &offer.data - } - - fn get_source_data(src: &Self::Source) -> &SourceData { - &src.data + seat.set_zwp_primary_selection(Some(source.clone()), serial) } fn for_each_device(seat: &WlSeatGlobal, client: ClientId, f: C) @@ -170,7 +167,7 @@ impl IpcVtable for PrimarySelectionIpc { fn create_offer( client: &Rc, device: &Rc, - offer_data: OfferData, + offer_data: OfferData, ) -> Result, ClientError> { let id = if device.data.is_xwm { ZwpPrimarySelectionOfferV1Id::NONE @@ -193,37 +190,13 @@ impl IpcVtable for PrimarySelectionIpc { dd.send_selection(offer); } - fn send_cancelled(source: &Rc, _seat: &Rc) { - source.send_cancelled(); - } - - fn get_offer_id(offer: &Self::Offer) -> DataOfferId { - offer.offer_id - } - fn send_offer(dd: &Self::Device, offer: &Rc) { dd.send_data_offer(offer); } - fn send_mime_type(offer: &Rc, mime_type: &str) { - offer.send_offer(mime_type); - } - fn unset(seat: &Rc, _role: Role) { seat.unset_primary_selection(); } - - fn send_send(src: &Rc, mime_type: &str, fd: Rc) { - src.send_send(mime_type, fd); - } - - fn remove_from_seat(device: &Self::Device) { - device.seat.remove_primary_selection_device(device); - } - - fn get_offer_seat(offer: &Self::Offer) -> Rc { - offer.seat.clone() - } } object_base! { diff --git a/src/ifs/ipc/zwp_primary_selection_offer_v1.rs b/src/ifs/ipc/zwp_primary_selection_offer_v1.rs index 41d4de02..54fba396 100644 --- a/src/ifs/ipc/zwp_primary_selection_offer_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_offer_v1.rs @@ -1,10 +1,13 @@ use { crate::{ - client::{Client, ClientError}, + client::{Client, ClientError, ClientId}, ifs::{ ipc::{ - break_offer_loops, destroy_data_offer, receive_data_offer, - zwp_primary_selection_device_v1::PrimarySelectionIpc, DataOfferId, OfferData, + break_offer_loops, cancel_offer, destroy_data_offer, receive_data_offer, + zwp_primary_selection_device_v1::{ + PrimarySelectionIpc, ZwpPrimarySelectionDeviceV1, + }, + DataOffer, DataOfferId, DynDataOffer, OfferData, }, wl_seat::WlSeatGlobal, }, @@ -23,15 +26,49 @@ pub struct ZwpPrimarySelectionOfferV1 { pub offer_id: DataOfferId, pub seat: Rc, pub client: Rc, - pub data: OfferData, + pub data: OfferData, pub tracker: Tracker, } +impl DataOffer for ZwpPrimarySelectionOfferV1 { + type Device = ZwpPrimarySelectionDeviceV1; + + fn offer_data(&self) -> &OfferData { + &self.data + } +} + +impl DynDataOffer for ZwpPrimarySelectionOfferV1 { + fn offer_id(&self) -> DataOfferId { + self.offer_id + } + + fn client_id(&self) -> ClientId { + self.client.id + } + + fn send_offer(self: Rc, mime_type: &str) { + ZwpPrimarySelectionOfferV1::send_offer(&self, mime_type); + } + + fn destroy(&self) { + destroy_data_offer::(self); + } + + fn cancel(&self) { + cancel_offer::(self); + } + + fn get_seat(&self) -> Rc { + self.seat.clone() + } +} + impl ZwpPrimarySelectionOfferV1 { pub fn send_offer(self: &Rc, mime_type: &str) { if self.data.is_xwm { if let Some(src) = self.data.source.get() { - if !src.data.is_xwm { + if !src.source_data().is_xwm { self.client.state.xwayland.queue.push( XWaylandEvent::PrimarySelectionAddOfferMimeType( self.clone(), diff --git a/src/ifs/ipc/zwp_primary_selection_source_v1.rs b/src/ifs/ipc/zwp_primary_selection_source_v1.rs index a563f9fe..a657882b 100644 --- a/src/ifs/ipc/zwp_primary_selection_source_v1.rs +++ b/src/ifs/ipc/zwp_primary_selection_source_v1.rs @@ -1,9 +1,13 @@ use { crate::{ client::{Client, ClientError}, - ifs::ipc::{ - add_data_source_mime_type, break_source_loops, destroy_data_source, - zwp_primary_selection_device_v1::PrimarySelectionIpc, SourceData, + 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, + DataSource, DynDataSource, SourceData, + }, + wl_seat::WlSeatGlobal, }, leaks::Tracker, object::Object, @@ -18,10 +22,38 @@ use { pub struct ZwpPrimarySelectionSourceV1 { pub id: ZwpPrimarySelectionSourceV1Id, - pub data: SourceData, + pub data: SourceData, pub tracker: Tracker, } +impl DataSource for ZwpPrimarySelectionSourceV1 { + fn send_cancelled(self: &Rc, _seat: &Rc) { + ZwpPrimarySelectionSourceV1::send_cancelled(self); + } +} + +impl DynDataSource for ZwpPrimarySelectionSourceV1 { + fn source_data(&self) -> &SourceData { + &self.data + } + + fn send_send(self: Rc, mime_type: &str, fd: Rc) { + ZwpPrimarySelectionSourceV1::send_send(&self, mime_type, fd) + } + + fn offer_to(self: Rc, client: &Rc) { + offer_source_to::(&self, client); + } + + fn detach_seat(self: Rc, seat: &Rc) { + detach_seat::(&self, seat); + } + + fn cancel_offers(&self) { + cancel_offers::(self); + } +} + impl ZwpPrimarySelectionSourceV1 { pub fn new(id: ZwpPrimarySelectionSourceV1Id, client: &Rc, is_xwm: bool) -> Self { Self { diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 75b17516..1a3d6dc7 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -26,7 +26,7 @@ use { PrimarySelectionIpc, ZwpPrimarySelectionDeviceV1, }, zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, - IpcError, + DynDataSource, IpcError, }, wl_seat::{ kb_owner::KbOwnerHolder, @@ -143,9 +143,9 @@ pub struct WlSeatGlobal { kb_state: RefCell, cursor: CloneCell>>, tree_changed: Rc, - selection: CloneCell>>, + selection: CloneCell>>, selection_serial: Cell, - primary_selection: CloneCell>>, + primary_selection: CloneCell>>, primary_selection_serial: Cell, pointer_owner: PointerOwnerHolder, kb_owner: KbOwnerHolder, @@ -709,25 +709,26 @@ impl WlSeatGlobal { } } - fn set_selection_( + fn set_selection_( self: &Rc, - field: &CloneCell>>, - src: Option>, + field: &CloneCell>>, + src: Option>, ) -> Result<(), WlSeatError> { if let (Some(new), Some(old)) = (&src, &field.get()) { - if T::get_source_data(new).id == T::get_source_data(old).id { + if new.source_data().id == old.source_data().id { return Ok(()); } } if let Some(new) = &src { - ipc::attach_seat::(new, self, ipc::Role::Selection)?; + ipc::attach_seat(&**new, self, ipc::Role::Selection)?; } - if let Some(old) = field.set(src.clone()) { - ipc::detach_seat::(&old, self); + let src_dyn = src.clone().map(|s| s as Rc); + if let Some(old) = field.set(src_dyn) { + old.detach_seat(self); } if let Some(client) = self.keyboard_node.get().node_client() { match src { - Some(src) => ipc::offer_source_to::(&src, &client), + Some(src) => ipc::offer_source_to::(&src, &client), _ => T::for_each_device(self, client.id, |device| { T::send_selection(device, None); }), @@ -756,10 +757,10 @@ impl WlSeatGlobal { } pub fn unset_selection(self: &Rc) { - let _ = self.set_selection(None, None); + let _ = self.set_wl_data_source_selection(None, None); } - pub fn set_selection( + pub fn set_wl_data_source_selection( self: &Rc, selection: Option>, serial: Option, @@ -772,7 +773,14 @@ impl WlSeatGlobal { return Err(WlSeatError::OfferHasDrag); } } - self.set_selection_::(&self.selection, selection) + self.set_selection(selection) + } + + pub fn set_selection( + self: &Rc, + selection: Option>, + ) -> Result<(), WlSeatError> { + self.set_selection_::(&self.selection, selection) } pub fn may_modify_selection(&self, client: &Rc, serial: u32) -> bool { @@ -795,10 +803,10 @@ impl WlSeatGlobal { } pub fn unset_primary_selection(self: &Rc) { - let _ = self.set_primary_selection(None, None); + let _ = self.set_zwp_primary_selection(None, None); } - pub fn set_primary_selection( + pub fn set_zwp_primary_selection( self: &Rc, selection: Option>, serial: Option, @@ -806,7 +814,14 @@ impl WlSeatGlobal { if let Some(serial) = serial { self.primary_selection_serial.set(serial); } - self.set_selection_::(&self.primary_selection, selection) + self.set_primary_selection(selection) + } + + pub fn set_primary_selection( + self: &Rc, + selection: Option>, + ) -> Result<(), WlSeatError> { + self.set_selection_::(&self.primary_selection, selection) } pub fn reload_known_cursor(&self) { diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 8ba365c4..57748764 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -1,15 +1,13 @@ use { crate::{ backend::{ConnectorId, InputEvent, KeyState, AXIS_120}, - client::{Client, ClientId}, + client::ClientId, fixed::Fixed, ifs::{ ipc, ipc::{ wl_data_device::{ClipboardIpc, WlDataDevice}, - zwp_primary_selection_device_v1::{ - PrimarySelectionIpc, ZwpPrimarySelectionDeviceV1, - }, + zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1, }, wl_seat::{ wl_keyboard::{self, WlKeyboard}, @@ -27,7 +25,7 @@ use { }, state::DeviceHandlerData, tree::{Direction, FloatNode, Node, ToplevelNode}, - utils::{bitflags::BitflagsExt, clonecell::CloneCell, smallmap::SmallMap}, + utils::{bitflags::BitflagsExt, smallmap::SmallMap}, wire::WlDataOfferId, xkbcommon::{ModifierState, XKB_KEY_DOWN, XKB_KEY_UP}, }, @@ -429,19 +427,6 @@ impl WlSeatGlobal { self.kb_owner.set_kb_node(self, node); } - fn offer_selection( - &self, - field: &CloneCell>>, - client: &Rc, - ) { - match field.get() { - Some(sel) => ipc::offer_source_to::(&sel, client), - None => T::for_each_device(self, client.id, |dd| { - T::send_selection(dd, None); - }), - } - } - fn for_each_seat(&self, ver: u32, client: ClientId, mut f: C) where C: FnMut(&Rc), @@ -757,8 +742,22 @@ impl WlSeatGlobal { }); if self.keyboard_node.get().node_client_id() != Some(surface.client.id) { - self.offer_selection::(&self.selection, &surface.client); - self.offer_selection::(&self.primary_selection, &surface.client); + match self.selection.get() { + Some(sel) => sel.offer_to(&surface.client), + None => { + self.for_each_data_device(0, surface.client.id, |dd| { + dd.send_selection(None); + }); + } + } + match self.primary_selection.get() { + Some(sel) => sel.offer_to(&surface.client), + None => { + self.for_each_primary_selection_device(0, surface.client.id, |dd| { + dd.send_selection(None); + }); + } + } } } } @@ -820,9 +819,9 @@ impl WlSeatGlobal { serial: u32, ) { if let Some(src) = &dnd.src { - ipc::offer_source_to::(src, &surface.client); + ipc::offer_source_to::(src, &surface.client); src.for_each_data_offer(|offer| { - offer.device.send_enter(surface.id, x, y, offer.id, serial); + offer.send_enter(surface.id, x, y, serial); offer.send_source_actions(); }) } else if surface.client.id == dnd.client.id { diff --git a/src/ifs/wl_seat/pointer_owner.rs b/src/ifs/wl_seat/pointer_owner.rs index ddd9ecf0..91c82e5d 100644 --- a/src/ifs/wl_seat/pointer_owner.rs +++ b/src/ifs/wl_seat/pointer_owner.rs @@ -371,7 +371,7 @@ impl PointerOwner for GrabPointerOwner { icon.set_dnd_icon_seat(seat.id, Some(seat)); } if let Some(new) = &src { - ipc::attach_seat::(new, seat, ipc::Role::Dnd)?; + ipc::attach_seat(&**new, seat, ipc::Role::Dnd)?; if let Some(drag) = new.toplevel_drag.get() { drag.start_drag(); } diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index ba661c0e..9b9a8d25 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -12,7 +12,7 @@ use { zwp_primary_selection_device_v1::{ PrimarySelectionIpc, ZwpPrimarySelectionDeviceV1, }, - IpcVtable, + DataOffer, DynDataOffer, DynDataSource, IpcVtable, XIpcVtable, }, wl_seat::{SeatId, WlSeatGlobal}, wl_surface::{ @@ -181,7 +181,7 @@ impl Default for SelectionData { } } -impl SelectionData { +impl SelectionData { fn destroy(&self) { for (_, offer) in self.offers.lock().drain() { destroy_data_offer::(&offer.offer); @@ -202,7 +202,7 @@ impl SelectionData { fn seat_removed(&self, id: SeatId) { if let Some(offer) = self.active_offer.get() { - if T::get_offer_seat(&offer.offer).id() == id { + if offer.offer.get_seat().id() == id { self.active_offer.take(); } } @@ -657,7 +657,7 @@ impl Wm { offer: Rc, mt: String, ) { - let seat = T::get_offer_seat(&offer); + let seat = offer.get_seat(); let enhanced = match sd.offers.get(&seat.id()) { Some(r) if !rc_eq(&r.offer, &offer) => { return; @@ -678,15 +678,15 @@ impl Wm { } async fn dd_set_offer(&mut self, sd: &SelectionData, offer: Rc) { - let seat = T::get_offer_seat(&offer); + let seat = offer.get_seat(); let mut mime_types = vec![]; if let Some(offer) = sd.offers.remove(&seat.id()) { destroy_data_offer::(&offer.offer); mime_types = mem::take(offer.mime_types.borrow_mut().deref_mut()); } - match T::get_offer_data(&offer).source() { + match offer.offer_data().source() { None => return, - Some(s) if T::get_source_data(&s).is_xwm => return, + Some(s) if s.source_data().is_xwm => return, _ => {} } sd.offers.set( @@ -801,7 +801,7 @@ impl Wm { mime_type: String, fd: Rc, ) { - let seat = match T::get_source_data(src).seat.get() { + let seat = match src.source_data().seat.get() { Some(s) => s, _ => return, }; @@ -839,7 +839,7 @@ impl Wm { } fn dd_cancel_source(&mut self, sd: &SelectionData, src: &Rc) { - if let Some(seat) = T::get_source_data(src).seat.get() { + if let Some(seat) = src.source_data().seat.get() { if let Some(cur) = sd.sources.get(&seat.id()) { if rc_eq(src, &cur) { sd.sources.remove(&seat.id()); @@ -1508,7 +1508,7 @@ impl Wm { } } - async fn handle_xfixes_selection_notify_( + async fn handle_xfixes_selection_notify_( &mut self, sd: &SelectionData, event: &XfixesSelectionNotify, @@ -1663,7 +1663,7 @@ impl Wm { } } - async fn handle_selection_notify_( + async fn handle_selection_notify_( &mut self, sd: &SelectionData, event: &SelectionNotify,