Skip to content

Commit

Permalink
wayland: implement wlr-data-control
Browse files Browse the repository at this point in the history
  • Loading branch information
mahkoh committed Mar 31, 2024
1 parent 8bca8b0 commit e9927b2
Show file tree
Hide file tree
Showing 18 changed files with 983 additions and 33 deletions.
6 changes: 4 additions & 2 deletions src/client/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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},
Expand All @@ -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>>,
}

Expand Down Expand Up @@ -87,6 +88,7 @@ impl Objects {
seats: Default::default(),
screencasts: Default::default(),
timelines: Default::default(),
zwlr_data_sources: Default::default(),
ids: RefCell::new(vec![]),
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>) {
Expand Down
52 changes: 43 additions & 9 deletions src/ifs/ipc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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>,
Expand All @@ -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| {
Expand Down
14 changes: 10 additions & 4 deletions src/ifs/ipc/wl_data_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>) {
Expand Down Expand Up @@ -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) {
Expand Down
28 changes: 22 additions & 6 deletions src/ifs/ipc/x_data_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -61,19 +66,30 @@ 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(),
offer: None,
});
}

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)
}
}
Loading

0 comments on commit e9927b2

Please sign in to comment.