Skip to content

Commit

Permalink
ipc: implement ext-data-control
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Oct 8, 2024
1 parent 4d86f69 commit 53b172b
Show file tree
Hide file tree
Showing 12 changed files with 577 additions and 7 deletions.
1 change: 1 addition & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Jay supports the following wayland protocols:

| Global | Version | Privileged |
|-----------------------------------------|:----------------|---------------|
| ext_data_control_manager_v1 | 1 | Yes |
| ext_foreign_toplevel_list_v1 | 1 | Yes |
| ext_idle_notifier_v1 | 1 | Yes |
| ext_session_lock_manager_v1 | 1 | Yes |
Expand Down
18 changes: 12 additions & 6 deletions src/client/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use {
client::{Client, ClientError},
ifs::{
ipc::{
data_control::zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
data_control::{
ext_data_control_source_v1::ExtDataControlSourceV1,
zwlr_data_control_source_v1::ZwlrDataControlSourceV1,
},
wl_data_source::WlDataSource,
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
},
Expand Down Expand Up @@ -32,11 +35,11 @@ use {
copyhashmap::{CopyHashMap, Locked},
},
wire::{
JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId, WlBufferId,
WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId, WlSeatId,
WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id, XdgPopupId,
XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId, ZwlrDataControlSourceV1Id,
ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
ExtDataControlSourceV1Id, JayOutputId, JayScreencastId, JayToplevelId, JayWorkspaceId,
WlBufferId, WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, WlRegistryId,
WlSeatId, WlSurfaceId, WpDrmLeaseConnectorV1Id, WpLinuxDrmSyncobjTimelineV1Id,
XdgPopupId, XdgPositionerId, XdgSurfaceId, XdgToplevelId, XdgWmBaseId,
ZwlrDataControlSourceV1Id, ZwpPrimarySelectionSourceV1Id, ZwpTabletToolV2Id,
},
},
std::{cell::RefCell, mem, rc::Rc},
Expand Down Expand Up @@ -68,6 +71,7 @@ pub struct Objects {
pub drm_lease_outputs: CopyHashMap<WpDrmLeaseConnectorV1Id, Rc<WpDrmLeaseConnectorV1>>,
pub tablet_tools: CopyHashMap<ZwpTabletToolV2Id, Rc<ZwpTabletToolV2>>,
pub xdg_popups: CopyHashMap<XdgPopupId, Rc<XdgPopup>>,
pub ext_data_sources: CopyHashMap<ExtDataControlSourceV1Id, Rc<ExtDataControlSourceV1>>,
ids: RefCell<Vec<usize>>,
}

Expand Down Expand Up @@ -101,6 +105,7 @@ impl Objects {
drm_lease_outputs: Default::default(),
tablet_tools: Default::default(),
xdg_popups: Default::default(),
ext_data_sources: Default::default(),
ids: RefCell::new(vec![]),
}
}
Expand Down Expand Up @@ -138,6 +143,7 @@ impl Objects {
self.drm_lease_outputs.clear();
self.tablet_tools.clear();
self.xdg_popups.clear();
self.ext_data_sources.clear();
}

pub fn id<T>(&self, client_data: &Client) -> Result<T, ClientError>
Expand Down
6 changes: 5 additions & 1 deletion src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use {
ext_idle_notifier_v1::ExtIdleNotifierV1Global,
ext_session_lock_manager_v1::ExtSessionLockManagerV1Global,
ipc::{
data_control::zwlr_data_control_manager_v1::ZwlrDataControlManagerV1Global,
data_control::{
ext_data_control_manager_v1::ExtDataControlManagerV1Global,
zwlr_data_control_manager_v1::ZwlrDataControlManagerV1Global,
},
wl_data_device_manager::WlDataDeviceManagerGlobal,
zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1Global,
},
Expand Down Expand Up @@ -197,6 +200,7 @@ impl Globals {
add_singleton!(ZwpPointerGesturesV1Global);
add_singleton!(ZwpTabletManagerV2Global);
add_singleton!(JayDamageTrackingGlobal);
add_singleton!(ExtDataControlManagerV1Global);
}

pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
Expand Down
4 changes: 4 additions & 0 deletions src/ifs/ipc/data_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ use {
std::rc::Rc,
};

pub mod ext_data_control_device_v1;
pub mod ext_data_control_manager_v1;
pub mod ext_data_control_offer_v1;
pub mod ext_data_control_source_v1;
mod private;
pub mod zwlr_data_control_device_v1;
pub mod zwlr_data_control_manager_v1;
Expand Down
158 changes: 158 additions & 0 deletions src/ifs/ipc/data_control/ext_data_control_device_v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
use {
crate::{
client::Client,
ifs::{
ipc::data_control::{
ext_data_control_offer_v1::ExtDataControlOfferV1,
ext_data_control_source_v1::ExtDataControlSourceV1,
private::{
logic::{self, DataControlError},
DataControlDevice, DataControlDeviceData, DataControlIpc, DataControlOfferData,
},
},
wl_seat::WlSeatGlobal,
},
leaks::Tracker,
object::{Object, Version},
wire::{
ext_data_control_device_v1::*, ExtDataControlDeviceV1Id, ExtDataControlOfferV1Id,
ExtDataControlSourceV1Id,
},
},
std::rc::Rc,
thiserror::Error,
};

pub struct ExtDataControlDeviceV1 {
pub id: ExtDataControlDeviceV1Id,
pub data: DataControlDeviceData<ExtDataControlIpc>,
pub tracker: Tracker<Self>,
}

impl ExtDataControlDeviceV1 {
pub fn new(
id: ExtDataControlDeviceV1Id,
client: &Rc<Client>,
version: Version,
seat: &Rc<WlSeatGlobal>,
) -> Self {
Self {
id,
data: DataControlDeviceData {
data_control_device_id: client.state.data_control_device_ids.next(),
client: client.clone(),
version,
seat: seat.clone(),
clipboard_data: Default::default(),
primary_selection_data: Default::default(),
},
tracker: Default::default(),
}
}

pub fn send_data_offer(&self, offer: &Rc<ExtDataControlOfferV1>) {
self.data.client.event(DataOffer {
self_id: self.id,
id: offer.id,
})
}

pub fn send_selection(&self, offer: Option<&Rc<ExtDataControlOfferV1>>) {
let id = offer.map(|o| o.id).unwrap_or(ExtDataControlOfferV1Id::NONE);
self.data.client.event(Selection {
self_id: self.id,
id,
})
}

pub fn send_primary_selection(&self, offer: Option<&Rc<ExtDataControlOfferV1>>) {
let id = offer.map(|o| o.id).unwrap_or(ExtDataControlOfferV1Id::NONE);
self.data.client.event(PrimarySelection {
self_id: self.id,
id,
})
}
}

impl ExtDataControlDeviceV1RequestHandler for ExtDataControlDeviceV1 {
type Error = ExtDataControlDeviceV1Error;

fn set_selection(&self, req: SetSelection, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::device_set_selection(self, req.source.is_some().then_some(req.source))?;
Ok(())
}

fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
logic::device_destroy(self)?;
Ok(())
}

fn set_primary_selection(
&self,
req: SetPrimarySelection,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
logic::device_set_primary_selection(self, req.source.is_some().then_some(req.source))?;
Ok(())
}
}

pub struct ExtDataControlIpc;

impl DataControlIpc for ExtDataControlIpc {
const PRIMARY_SELECTION_SINCE: Version = Version(1);
type Device = ExtDataControlDeviceV1;
type OfferId = ExtDataControlOfferV1Id;
type Offer = ExtDataControlOfferV1;
type SourceId = ExtDataControlSourceV1Id;
type Source = ExtDataControlSourceV1;

fn create_offer(id: Self::OfferId, data: DataControlOfferData<Self>) -> Rc<Self::Offer> {
let rc = Rc::new(ExtDataControlOfferV1 {
id,
data,
tracker: Default::default(),
});
track!(rc.data.client, rc);
rc
}
}

impl DataControlDevice for ExtDataControlDeviceV1 {
type Ipc = ExtDataControlIpc;

fn data(&self) -> &DataControlDeviceData<Self::Ipc> {
&self.data
}

fn send_data_offer(&self, offer: &Rc<<Self::Ipc as DataControlIpc>::Offer>) {
self.send_data_offer(offer)
}

fn send_selection(&self, offer: Option<&Rc<<Self::Ipc as DataControlIpc>::Offer>>) {
self.send_selection(offer)
}

fn send_primary_selection(&self, offer: Option<&Rc<<Self::Ipc as DataControlIpc>::Offer>>) {
self.send_primary_selection(offer)
}
}

object_base! {
self = ExtDataControlDeviceV1;
version = self.data.version;
}

impl Object for ExtDataControlDeviceV1 {
fn break_loops(&self) {
logic::data_device_break_loops(self);
}
}

simple_add_obj!(ExtDataControlDeviceV1);

#[derive(Debug, Error)]
pub enum ExtDataControlDeviceV1Error {
#[error(transparent)]
DataControlError(#[from] DataControlError),
}
134 changes: 134 additions & 0 deletions src/ifs/ipc/data_control/ext_data_control_manager_v1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use {
crate::{
client::{Client, ClientCaps, ClientError, CAP_DATA_CONTROL_MANAGER},
globals::{Global, GlobalName},
ifs::ipc::{
data_control::{
ext_data_control_device_v1::ExtDataControlDeviceV1,
ext_data_control_source_v1::ExtDataControlSourceV1, DynDataControlDevice,
},
IpcLocation,
},
leaks::Tracker,
object::{Object, Version},
wire::{ext_data_control_manager_v1::*, ExtDataControlManagerV1Id},
},
std::rc::Rc,
thiserror::Error,
};

pub struct ExtDataControlManagerV1Global {
name: GlobalName,
}

pub struct ExtDataControlManagerV1 {
pub id: ExtDataControlManagerV1Id,
pub client: Rc<Client>,
pub version: Version,
tracker: Tracker<Self>,
}

impl ExtDataControlManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}

fn bind_(
self: Rc<Self>,
id: ExtDataControlManagerV1Id,
client: &Rc<Client>,
version: Version,
) -> Result<(), ExtDataControlManagerV1Error> {
let obj = Rc::new(ExtDataControlManagerV1 {
id,
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}

impl ExtDataControlManagerV1RequestHandler for ExtDataControlManagerV1 {
type Error = ExtDataControlManagerV1Error;

fn create_data_source(
&self,
req: CreateDataSource,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let res = Rc::new(ExtDataControlSourceV1::new(
req.id,
&self.client,
self.version,
));
track!(self.client, res);
self.client.add_client_obj(&res)?;
Ok(())
}

fn get_data_device(&self, req: GetDataDevice, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let seat = self.client.lookup(req.seat)?;
let dev = Rc::new(ExtDataControlDeviceV1::new(
req.id,
&self.client,
self.version,
&seat.global,
));
track!(self.client, dev);
seat.global.add_data_control_device(dev.clone());
self.client.add_client_obj(&dev)?;
dev.clone()
.handle_new_source(IpcLocation::Clipboard, seat.global.get_selection());
dev.clone().handle_new_source(
IpcLocation::PrimarySelection,
seat.global.get_primary_selection(),
);
Ok(())
}

fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.remove_obj(self)?;
Ok(())
}
}

global_base!(
ExtDataControlManagerV1Global,
ExtDataControlManagerV1,
ExtDataControlManagerV1Error
);

impl Global for ExtDataControlManagerV1Global {
fn singleton(&self) -> bool {
true
}

fn version(&self) -> u32 {
1
}

fn required_caps(&self) -> ClientCaps {
CAP_DATA_CONTROL_MANAGER
}
}

simple_add_global!(ExtDataControlManagerV1Global);

object_base! {
self = ExtDataControlManagerV1;
version = self.version;
}

impl Object for ExtDataControlManagerV1 {}

simple_add_obj!(ExtDataControlManagerV1);

#[derive(Debug, Error)]
pub enum ExtDataControlManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(ExtDataControlManagerV1Error, ClientError);
Loading

0 comments on commit 53b172b

Please sign in to comment.