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 25, 2024
1 parent be1462d commit 4abbe94
Show file tree
Hide file tree
Showing 13 changed files with 575 additions and 3 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_image_capture_source_manager_v1 | 1 | |
| ext_foreign_toplevel_list_v1 | 1 | Yes |
| ext_idle_notifier_v1 | 1 | Yes |
Expand Down
2 changes: 2 additions & 0 deletions release-notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- Add support fo ext-data-control-v1.

# 1.7.0 (2024-10-25)

- Various bugfixes.
Expand Down
10 changes: 8 additions & 2 deletions src/client/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ use {
ext_image_capture_source_v1::ExtImageCaptureSourceV1,
ext_image_copy::ext_image_copy_capture_session_v1::ExtImageCopyCaptureSessionV1,
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 @@ -35,7 +38,7 @@ use {
copyhashmap::{CopyHashMap, Locked},
},
wire::{
ExtForeignToplevelHandleV1Id, ExtImageCaptureSourceV1Id,
ExtDataControlSourceV1Id, ExtForeignToplevelHandleV1Id, ExtImageCaptureSourceV1Id,
ExtImageCopyCaptureSessionV1Id, JayOutputId, JayScreencastId, JayToplevelId,
JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId, WlPointerId, WlRegionId,
WlRegistryId, WlSeatId, WlSurfaceId, WpDrmLeaseConnectorV1Id,
Expand Down Expand Up @@ -78,6 +81,7 @@ pub struct Objects {
CopyHashMap<ExtForeignToplevelHandleV1Id, Rc<ExtForeignToplevelHandleV1>>,
pub ext_copy_sessions:
CopyHashMap<ExtImageCopyCaptureSessionV1Id, Rc<ExtImageCopyCaptureSessionV1>>,
pub ext_data_sources: CopyHashMap<ExtDataControlSourceV1Id, Rc<ExtDataControlSourceV1>>,
ids: RefCell<Vec<usize>>,
}

Expand Down Expand Up @@ -114,6 +118,7 @@ impl Objects {
image_capture_sources: Default::default(),
foreign_toplevel_handles: Default::default(),
ext_copy_sessions: Default::default(),
ext_data_sources: Default::default(),
ids: RefCell::new(vec![]),
}
}
Expand Down Expand Up @@ -154,6 +159,7 @@ impl Objects {
self.image_capture_sources.clear();
self.foreign_toplevel_handles.clear();
self.ext_copy_sessions.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 @@ -10,7 +10,10 @@ use {
ext_output_image_capture_source_manager_v1::ExtOutputImageCaptureSourceManagerV1Global,
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 @@ -207,6 +210,7 @@ impl Globals {
add_singleton!(ExtImageCopyCaptureManagerV1Global);
add_singleton!(WpFifoManagerV1Global);
add_singleton!(WpCommitTimingManagerV1Global);
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 4abbe94

Please sign in to comment.