From 8f7997e270aa879365eab7fdbcb5332e2dc7bf0b Mon Sep 17 00:00:00 2001 From: kossLAN Date: Fri, 29 May 2026 21:50:09 -0400 Subject: [PATCH] wl-seat: split selection handling --- src/ifs/wl_seat.rs | 155 ++------------------------------- src/ifs/wl_seat/selection.rs | 160 +++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 150 deletions(-) create mode 100644 src/ifs/wl_seat/selection.rs diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 1a02f4d3..62211638 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -7,6 +7,7 @@ mod kb_owner; mod pointer_owner; mod position_hint; mod seat_object; +mod selection; pub mod tablet; pub mod text_input; mod touch_owner; @@ -38,16 +39,12 @@ use { ifs::{ ext_idle_notification_v1::ExtIdleNotificationV1, data_transfer::{ - self, DynDataSource, TransferError, TransferLocation, + self, DynDataSource, TransferError, data_control::{DataControlDeviceId, DynDataControlDevice}, - offer_source_to_regular_client, - wl_data_device::{ClipboardTransfer, WlDataDevice}, + wl_data_device::WlDataDevice, wl_data_source::WlDataSource, - x_data_device::{XClipboardTransfer, XTransferDevice, XTransferDeviceId, XPrimarySelectionTransfer}, - zwp_primary_selection_device_v1::{ - PrimarySelectionTransfer, ZwpPrimarySelectionDeviceV1, - }, - zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, + x_data_device::{XTransferDevice, XTransferDeviceId}, + zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1, }, wl_output::WlOutputGlobal, wl_seat::{ @@ -1287,66 +1284,6 @@ impl WlSeatGlobal { } } - fn set_selection_( - self: &Rc, - field: &CloneCell>>, - src: Option>, - location: TransferLocation, - ) -> Result<(), WlSeatError> - where - T: data_transfer::IterableTransferVtable, - X: data_transfer::TransferVtable, - 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); - 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::(src.clone().map(|v| v as Rc<_>), &client); - // client.flush(); - } - let dyn_source = src.map(|s| s as Rc); - for dd in self.data_control_devices.lock().values() { - dd.clone().handle_new_source(location, dyn_source.clone()); - } - Ok(()) - } - - fn offer_selection_to_client( - &self, - selection: Option>, - client: &Rc, - ) where - T: data_transfer::IterableTransferVtable, - X: data_transfer::TransferVtable, - { - 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::(src, client), - _ => T::for_each_device(self, client.id, |device| { - T::send_selection(device, None); - }), - } - } - } - pub fn start_drag( self: &Rc, origin: &Rc, @@ -1398,88 +1335,6 @@ impl WlSeatGlobal { self.pointer_owner.cancel_dnd(self); } - pub fn unset_selection(self: &Rc) { - let _ = self.set_wl_data_source_selection(None, None); - } - - pub fn set_wl_data_source_selection( - self: &Rc, - selection: Option>, - serial: Option, - ) -> 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( - self: &Rc, - selection: Option>, - ) -> Result<(), WlSeatError> { - self.set_selection_::( - &self.selection, - selection, - TransferLocation::Clipboard, - ) - } - - pub fn get_selection(&self) -> Option> { - self.selection.get() - } - - pub fn may_modify_selection(&self, client: &Rc, 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, serial: Option) -> 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) { - let _ = self.set_zwp_primary_selection(None, None); - } - - pub fn set_zwp_primary_selection( - self: &Rc, - selection: Option>, - serial: Option, - ) -> Result<(), WlSeatError> { - if let Some(serial) = serial { - self.primary_selection_serial.set(serial); - } - self.set_primary_selection(selection) - } - - pub fn set_primary_selection( - self: &Rc, - selection: Option>, - ) -> Result<(), WlSeatError> { - self.set_selection_::( - &self.primary_selection, - selection, - TransferLocation::PrimarySelection, - ) - } - - pub fn get_primary_selection(&self) -> Option> { - self.primary_selection.get() - } - pub fn dnd_icon(&self) -> Option> { self.pointer_owner.dnd_icon() } diff --git a/src/ifs/wl_seat/selection.rs b/src/ifs/wl_seat/selection.rs new file mode 100644 index 00000000..7509507e --- /dev/null +++ b/src/ifs/wl_seat/selection.rs @@ -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_( + self: &Rc, + field: &CloneCell>>, + src: Option>, + location: TransferLocation, + ) -> Result<(), WlSeatError> + where + T: data_transfer::IterableTransferVtable, + X: data_transfer::TransferVtable, + 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); + 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::(src.clone().map(|v| v as Rc<_>), &client); + // client.flush(); + } + let dyn_source = src.map(|s| s as Rc); + 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( + &self, + selection: Option>, + client: &Rc, + ) where + T: data_transfer::IterableTransferVtable, + X: data_transfer::TransferVtable, + { + 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::(src, client), + _ => T::for_each_device(self, client.id, |device| { + T::send_selection(device, None); + }), + } + } + } + + pub fn unset_selection(self: &Rc) { + let _ = self.set_wl_data_source_selection(None, None); + } + + pub fn set_wl_data_source_selection( + self: &Rc, + selection: Option>, + serial: Option, + ) -> 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( + self: &Rc, + selection: Option>, + ) -> Result<(), WlSeatError> { + self.set_selection_::( + &self.selection, + selection, + TransferLocation::Clipboard, + ) + } + + pub fn get_selection(&self) -> Option> { + self.selection.get() + } + + pub fn may_modify_selection(&self, client: &Rc, 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, serial: Option) -> 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) { + let _ = self.set_zwp_primary_selection(None, None); + } + + pub fn set_zwp_primary_selection( + self: &Rc, + selection: Option>, + serial: Option, + ) -> Result<(), WlSeatError> { + if let Some(serial) = serial { + self.primary_selection_serial.set(serial); + } + self.set_primary_selection(selection) + } + + pub fn set_primary_selection( + self: &Rc, + selection: Option>, + ) -> Result<(), WlSeatError> { + self.set_selection_::( + &self.primary_selection, + selection, + TransferLocation::PrimarySelection, + ) + } + + pub fn get_primary_selection(&self) -> Option> { + self.primary_selection.get() + } +}