wl-seat: split selection handling
This commit is contained in:
parent
4074cee365
commit
8f7997e270
2 changed files with 165 additions and 150 deletions
|
|
@ -7,6 +7,7 @@ mod kb_owner;
|
||||||
mod pointer_owner;
|
mod pointer_owner;
|
||||||
mod position_hint;
|
mod position_hint;
|
||||||
mod seat_object;
|
mod seat_object;
|
||||||
|
mod selection;
|
||||||
pub mod tablet;
|
pub mod tablet;
|
||||||
pub mod text_input;
|
pub mod text_input;
|
||||||
mod touch_owner;
|
mod touch_owner;
|
||||||
|
|
@ -38,16 +39,12 @@ use {
|
||||||
ifs::{
|
ifs::{
|
||||||
ext_idle_notification_v1::ExtIdleNotificationV1,
|
ext_idle_notification_v1::ExtIdleNotificationV1,
|
||||||
data_transfer::{
|
data_transfer::{
|
||||||
self, DynDataSource, TransferError, TransferLocation,
|
self, DynDataSource, TransferError,
|
||||||
data_control::{DataControlDeviceId, DynDataControlDevice},
|
data_control::{DataControlDeviceId, DynDataControlDevice},
|
||||||
offer_source_to_regular_client,
|
wl_data_device::WlDataDevice,
|
||||||
wl_data_device::{ClipboardTransfer, WlDataDevice},
|
|
||||||
wl_data_source::WlDataSource,
|
wl_data_source::WlDataSource,
|
||||||
x_data_device::{XClipboardTransfer, XTransferDevice, XTransferDeviceId, XPrimarySelectionTransfer},
|
x_data_device::{XTransferDevice, XTransferDeviceId},
|
||||||
zwp_primary_selection_device_v1::{
|
zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1,
|
||||||
PrimarySelectionTransfer, ZwpPrimarySelectionDeviceV1,
|
|
||||||
},
|
|
||||||
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
|
|
||||||
},
|
},
|
||||||
wl_output::WlOutputGlobal,
|
wl_output::WlOutputGlobal,
|
||||||
wl_seat::{
|
wl_seat::{
|
||||||
|
|
@ -1287,66 +1284,6 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_selection_<T, X, S>(
|
|
||||||
self: &Rc<Self>,
|
|
||||||
field: &CloneCell<Option<Rc<dyn DynDataSource>>>,
|
|
||||||
src: Option<Rc<S>>,
|
|
||||||
location: TransferLocation,
|
|
||||||
) -> Result<(), WlSeatError>
|
|
||||||
where
|
|
||||||
T: data_transfer::IterableTransferVtable,
|
|
||||||
X: data_transfer::TransferVtable<Device = XTransferDevice>,
|
|
||||||
S: DynDataSource,
|
|
||||||
{
|
|
||||||
if let (Some(new), Some(old)) = (&src, &field.get())
|
|
||||||
&& new.source_data().id == old.source_data().id
|
|
||||||
{
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if let Some(new) = &src {
|
|
||||||
data_transfer::attach_seat(&**new, self, data_transfer::Role::Selection)?;
|
|
||||||
}
|
|
||||||
let src_dyn = src.clone().map(|s| s as Rc<dyn DynDataSource>);
|
|
||||||
if let Some(old) = field.set(src_dyn) {
|
|
||||||
old.detach_seat(self);
|
|
||||||
}
|
|
||||||
if let Some(client) = self.keyboard_node.get().node_client() {
|
|
||||||
self.offer_selection_to_client::<T, X>(src.clone().map(|v| v as Rc<_>), &client);
|
|
||||||
// client.flush();
|
|
||||||
}
|
|
||||||
let dyn_source = src.map(|s| s as Rc<dyn DynDataSource>);
|
|
||||||
for dd in self.data_control_devices.lock().values() {
|
|
||||||
dd.clone().handle_new_source(location, dyn_source.clone());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn offer_selection_to_client<T, X>(
|
|
||||||
&self,
|
|
||||||
selection: Option<Rc<dyn DynDataSource>>,
|
|
||||||
client: &Rc<Client>,
|
|
||||||
) where
|
|
||||||
T: data_transfer::IterableTransferVtable,
|
|
||||||
X: data_transfer::TransferVtable<Device = XTransferDevice>,
|
|
||||||
{
|
|
||||||
if let Some(src) = &selection {
|
|
||||||
src.cancel_unprivileged_offers();
|
|
||||||
}
|
|
||||||
if client.is_xwayland {
|
|
||||||
self.for_each_x_data_device(|dd| match &selection {
|
|
||||||
Some(src) => src.clone().offer_to_x(&dd),
|
|
||||||
_ => X::send_selection(&dd, None),
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
match selection {
|
|
||||||
Some(src) => offer_source_to_regular_client::<T>(src, client),
|
|
||||||
_ => T::for_each_device(self, client.id, |device| {
|
|
||||||
T::send_selection(device, None);
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start_drag(
|
pub fn start_drag(
|
||||||
self: &Rc<Self>,
|
self: &Rc<Self>,
|
||||||
origin: &Rc<WlSurface>,
|
origin: &Rc<WlSurface>,
|
||||||
|
|
@ -1398,88 +1335,6 @@ impl WlSeatGlobal {
|
||||||
self.pointer_owner.cancel_dnd(self);
|
self.pointer_owner.cancel_dnd(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unset_selection(self: &Rc<Self>) {
|
|
||||||
let _ = self.set_wl_data_source_selection(None, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_wl_data_source_selection(
|
|
||||||
self: &Rc<Self>,
|
|
||||||
selection: Option<Rc<WlDataSource>>,
|
|
||||||
serial: Option<u64>,
|
|
||||||
) -> Result<(), WlSeatError> {
|
|
||||||
if let Some(serial) = serial {
|
|
||||||
self.selection_serial.set(serial);
|
|
||||||
}
|
|
||||||
if let Some(selection) = &selection
|
|
||||||
&& selection.toplevel_drag.is_some()
|
|
||||||
{
|
|
||||||
return Err(WlSeatError::OfferHasDrag);
|
|
||||||
}
|
|
||||||
self.set_selection(selection)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_selection<S: DynDataSource>(
|
|
||||||
self: &Rc<Self>,
|
|
||||||
selection: Option<Rc<S>>,
|
|
||||||
) -> Result<(), WlSeatError> {
|
|
||||||
self.set_selection_::<ClipboardTransfer, XClipboardTransfer, _>(
|
|
||||||
&self.selection,
|
|
||||||
selection,
|
|
||||||
TransferLocation::Clipboard,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_selection(&self) -> Option<Rc<dyn DynDataSource>> {
|
|
||||||
self.selection.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn may_modify_selection(&self, client: &Rc<Client>, serial: u64) -> bool {
|
|
||||||
if serial < self.selection_serial.get() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.keyboard_node.get().node_client_id() == Some(client.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn may_modify_primary_selection(&self, client: &Rc<Client>, serial: Option<u64>) -> bool {
|
|
||||||
if let Some(serial) = serial
|
|
||||||
&& serial < self.primary_selection_serial.get()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self.keyboard_node.get().node_client_id() == Some(client.id)
|
|
||||||
|| self.pointer_node().and_then(|n| n.node_client_id()) == Some(client.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unset_primary_selection(self: &Rc<Self>) {
|
|
||||||
let _ = self.set_zwp_primary_selection(None, None);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_zwp_primary_selection(
|
|
||||||
self: &Rc<Self>,
|
|
||||||
selection: Option<Rc<ZwpPrimarySelectionSourceV1>>,
|
|
||||||
serial: Option<u64>,
|
|
||||||
) -> Result<(), WlSeatError> {
|
|
||||||
if let Some(serial) = serial {
|
|
||||||
self.primary_selection_serial.set(serial);
|
|
||||||
}
|
|
||||||
self.set_primary_selection(selection)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_primary_selection<S: DynDataSource>(
|
|
||||||
self: &Rc<Self>,
|
|
||||||
selection: Option<Rc<S>>,
|
|
||||||
) -> Result<(), WlSeatError> {
|
|
||||||
self.set_selection_::<PrimarySelectionTransfer, XPrimarySelectionTransfer, _>(
|
|
||||||
&self.primary_selection,
|
|
||||||
selection,
|
|
||||||
TransferLocation::PrimarySelection,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_primary_selection(&self) -> Option<Rc<dyn DynDataSource>> {
|
|
||||||
self.primary_selection.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dnd_icon(&self) -> Option<Rc<DndIcon>> {
|
pub fn dnd_icon(&self) -> Option<Rc<DndIcon>> {
|
||||||
self.pointer_owner.dnd_icon()
|
self.pointer_owner.dnd_icon()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
160
src/ifs/wl_seat/selection.rs
Normal file
160
src/ifs/wl_seat/selection.rs
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
use {
|
||||||
|
super::{WlSeatError, WlSeatGlobal},
|
||||||
|
crate::{
|
||||||
|
client::Client,
|
||||||
|
ifs::data_transfer::{
|
||||||
|
self, DynDataSource, TransferLocation, offer_source_to_regular_client,
|
||||||
|
wl_data_device::ClipboardTransfer,
|
||||||
|
wl_data_source::WlDataSource,
|
||||||
|
x_data_device::{XClipboardTransfer, XPrimarySelectionTransfer, XTransferDevice},
|
||||||
|
zwp_primary_selection_device_v1::PrimarySelectionTransfer,
|
||||||
|
zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
|
||||||
|
},
|
||||||
|
utils::clonecell::CloneCell,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl WlSeatGlobal {
|
||||||
|
fn set_selection_<T, X, S>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
field: &CloneCell<Option<Rc<dyn DynDataSource>>>,
|
||||||
|
src: Option<Rc<S>>,
|
||||||
|
location: TransferLocation,
|
||||||
|
) -> Result<(), WlSeatError>
|
||||||
|
where
|
||||||
|
T: data_transfer::IterableTransferVtable,
|
||||||
|
X: data_transfer::TransferVtable<Device = XTransferDevice>,
|
||||||
|
S: DynDataSource,
|
||||||
|
{
|
||||||
|
if let (Some(new), Some(old)) = (&src, &field.get())
|
||||||
|
&& new.source_data().id == old.source_data().id
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
if let Some(new) = &src {
|
||||||
|
data_transfer::attach_seat(&**new, self, data_transfer::Role::Selection)?;
|
||||||
|
}
|
||||||
|
let src_dyn = src.clone().map(|s| s as Rc<dyn DynDataSource>);
|
||||||
|
if let Some(old) = field.set(src_dyn) {
|
||||||
|
old.detach_seat(self);
|
||||||
|
}
|
||||||
|
if let Some(client) = self.keyboard_node.get().node_client() {
|
||||||
|
self.offer_selection_to_client::<T, X>(src.clone().map(|v| v as Rc<_>), &client);
|
||||||
|
// client.flush();
|
||||||
|
}
|
||||||
|
let dyn_source = src.map(|s| s as Rc<dyn DynDataSource>);
|
||||||
|
for dd in self.data_control_devices.lock().values() {
|
||||||
|
dd.clone().handle_new_source(location, dyn_source.clone());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn offer_selection_to_client<T, X>(
|
||||||
|
&self,
|
||||||
|
selection: Option<Rc<dyn DynDataSource>>,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
) where
|
||||||
|
T: data_transfer::IterableTransferVtable,
|
||||||
|
X: data_transfer::TransferVtable<Device = XTransferDevice>,
|
||||||
|
{
|
||||||
|
if let Some(src) = &selection {
|
||||||
|
src.cancel_unprivileged_offers();
|
||||||
|
}
|
||||||
|
if client.is_xwayland {
|
||||||
|
self.for_each_x_data_device(|dd| match &selection {
|
||||||
|
Some(src) => src.clone().offer_to_x(&dd),
|
||||||
|
_ => X::send_selection(&dd, None),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
match selection {
|
||||||
|
Some(src) => offer_source_to_regular_client::<T>(src, client),
|
||||||
|
_ => T::for_each_device(self, client.id, |device| {
|
||||||
|
T::send_selection(device, None);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unset_selection(self: &Rc<Self>) {
|
||||||
|
let _ = self.set_wl_data_source_selection(None, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_wl_data_source_selection(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
selection: Option<Rc<WlDataSource>>,
|
||||||
|
serial: Option<u64>,
|
||||||
|
) -> Result<(), WlSeatError> {
|
||||||
|
if let Some(serial) = serial {
|
||||||
|
self.selection_serial.set(serial);
|
||||||
|
}
|
||||||
|
if let Some(selection) = &selection
|
||||||
|
&& selection.toplevel_drag.is_some()
|
||||||
|
{
|
||||||
|
return Err(WlSeatError::OfferHasDrag);
|
||||||
|
}
|
||||||
|
self.set_selection(selection)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_selection<S: DynDataSource>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
selection: Option<Rc<S>>,
|
||||||
|
) -> Result<(), WlSeatError> {
|
||||||
|
self.set_selection_::<ClipboardTransfer, XClipboardTransfer, _>(
|
||||||
|
&self.selection,
|
||||||
|
selection,
|
||||||
|
TransferLocation::Clipboard,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_selection(&self) -> Option<Rc<dyn DynDataSource>> {
|
||||||
|
self.selection.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_modify_selection(&self, client: &Rc<Client>, serial: u64) -> bool {
|
||||||
|
if serial < self.selection_serial.get() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.keyboard_node.get().node_client_id() == Some(client.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn may_modify_primary_selection(&self, client: &Rc<Client>, serial: Option<u64>) -> bool {
|
||||||
|
if let Some(serial) = serial
|
||||||
|
&& serial < self.primary_selection_serial.get()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.keyboard_node.get().node_client_id() == Some(client.id)
|
||||||
|
|| self.pointer_node().and_then(|n| n.node_client_id()) == Some(client.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unset_primary_selection(self: &Rc<Self>) {
|
||||||
|
let _ = self.set_zwp_primary_selection(None, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_zwp_primary_selection(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
selection: Option<Rc<ZwpPrimarySelectionSourceV1>>,
|
||||||
|
serial: Option<u64>,
|
||||||
|
) -> Result<(), WlSeatError> {
|
||||||
|
if let Some(serial) = serial {
|
||||||
|
self.primary_selection_serial.set(serial);
|
||||||
|
}
|
||||||
|
self.set_primary_selection(selection)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_primary_selection<S: DynDataSource>(
|
||||||
|
self: &Rc<Self>,
|
||||||
|
selection: Option<Rc<S>>,
|
||||||
|
) -> Result<(), WlSeatError> {
|
||||||
|
self.set_selection_::<PrimarySelectionTransfer, XPrimarySelectionTransfer, _>(
|
||||||
|
&self.primary_selection,
|
||||||
|
selection,
|
||||||
|
TransferLocation::PrimarySelection,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_primary_selection(&self) -> Option<Rc<dyn DynDataSource>> {
|
||||||
|
self.primary_selection.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue