anvil: xwayland clipboard sync

This commit is contained in:
Victoria Brekenfeld 2023-03-02 19:41:28 +01:00
parent 61e139917a
commit d8b6bb485a
2 changed files with 127 additions and 8 deletions

View file

@ -1,18 +1,28 @@
use std::cell::RefCell;
use std::{cell::RefCell, os::unix::io::OwnedFd};
use smithay::{
desktop::space::SpaceElement,
input::pointer::Focus,
utils::{Logical, Rectangle, SERIAL_COUNTER},
wayland::compositor::with_states,
wayland::{
compositor::with_states,
data_device::{
clear_data_device_selection, current_data_device_selection_userdata,
request_data_device_client_selection, set_data_device_selection,
},
primary_selection::{
clear_primary_selection, current_primary_selection_userdata, request_primary_client_selection,
set_primary_selection,
},
},
xwayland::{
xwm::{Reorder, ResizeEdge as X11ResizeEdge, XwmId},
xwm::{Reorder, ResizeEdge as X11ResizeEdge, SelectionType, XwmId},
X11Surface, X11Wm, XwmHandler,
},
};
use tracing::trace;
use tracing::{error, trace};
use crate::{state::Backend, AnvilState, CalloopData};
use crate::{focus::FocusTarget, state::Backend, AnvilState, CalloopData};
use super::{
place_new_window, FullscreenSurface, MoveSurfaceGrab, ResizeData, ResizeState, ResizeSurfaceGrab,
@ -232,6 +242,64 @@ impl<BackendData: Backend> XwmHandler for CalloopData<BackendData> {
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, _button: u32) {
self.state.move_request_x11(&window)
}
fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionType) -> bool {
if let Some(keyboard) = self.state.seat.get_keyboard() {
// check that an X11 window is focused
if let Some(FocusTarget::Window(WindowElement::X11(surface))) = keyboard.current_focus() {
if surface.xwm_id().unwrap() == xwm {
return true;
}
}
}
false
}
fn send_selection(&mut self, _xwm: XwmId, selection: SelectionType, mime_type: String, fd: OwnedFd) {
match selection {
SelectionType::Clipboard => {
if let Err(err) = request_data_device_client_selection(&self.state.seat, mime_type, fd) {
error!(?err, "Failed to request current wayland clipboard for Xwayland",);
}
}
SelectionType::Primary => {
if let Err(err) = request_primary_client_selection(&self.state.seat, mime_type, fd) {
error!(
?err,
"Failed to request current wayland primary selection for Xwayland",
);
}
}
}
}
fn new_selection(&mut self, _xwm: XwmId, selection: SelectionType, mime_types: Vec<String>) {
trace!(?selection, ?mime_types, "Got Selection from X11",);
// TODO check, that focused windows is X11 window before doing this
match selection {
SelectionType::Clipboard => {
set_data_device_selection(&self.state.display_handle, &self.state.seat, mime_types, ())
}
SelectionType::Primary => {
set_primary_selection(&self.state.display_handle, &self.state.seat, mime_types, ())
}
}
}
fn cleared_selection(&mut self, _xwm: XwmId, selection: SelectionType) {
match selection {
SelectionType::Clipboard => {
if current_data_device_selection_userdata(&self.state.seat).is_some() {
clear_data_device_selection(&self.state.display_handle, &self.state.seat)
}
}
SelectionType::Primary => {
if current_primary_selection_userdata(&self.state.seat).is_some() {
clear_primary_selection(&self.state.display_handle, &self.state.seat)
}
}
}
}
}
impl<BackendData: Backend> AnvilState<BackendData> {

View file

@ -77,8 +77,13 @@ use crate::cursor::Cursor;
use crate::{focus::FocusTarget, shell::WindowElement};
#[cfg(feature = "xwayland")]
use smithay::{
reexports::wayland_protocols::wp::primary_selection::zv1::server::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1,
utils::Size,
xwayland::{X11Wm, XWayland, XWaylandEvent},
wayland::{
data_device::with_source_metadata as with_data_device_source_metadata,
primary_selection::with_source_metadata as with_primary_source_metadata,
},
xwayland::{xwm::SelectionType, X11Wm, XWayland, XWaylandEvent},
};
pub struct CalloopData<BackendData: Backend + 'static> {
@ -156,8 +161,30 @@ impl<BackendData: Backend> DataDeviceHandler for AnvilState<BackendData> {
fn data_device_state(&self) -> &DataDeviceState {
&self.data_device_state
}
fn send_selection(&mut self, _mime_type: String, _fd: OwnedFd, _seat: Seat<Self>) {
unreachable!("Anvil doesn't do server-side selections");
#[cfg(feature = "xwayland")]
fn new_selection(&mut self, source: Option<WlDataSource>, _seat: Seat<Self>) {
if let Some(xwm) = self.xwm.as_mut() {
if let Some(source) = source {
if let Ok(Err(err)) = with_data_device_source_metadata(&source, |metadata| {
xwm.new_selection(SelectionType::Clipboard, Some(metadata.mime_types.clone()))
}) {
warn!(?err, "Failed to set Xwayland clipboard selection");
}
} else if let Err(err) = xwm.new_selection(SelectionType::Clipboard, None) {
warn!(?err, "Failed to clear Xwayland clipboard selection");
}
}
}
#[cfg(feature = "xwayland")]
fn send_selection(&mut self, mime_type: String, fd: OwnedFd, _seat: Seat<Self>, _user_data: &()) {
if let Some(xwm) = self.xwm.as_mut() {
if let Err(err) = xwm.send_selection(SelectionType::Clipboard, mime_type, fd, self.handle.clone())
{
warn!(?err, "Failed to send clipboard (X11 -> Wayland)");
}
}
}
}
impl<BackendData: Backend> ClientDndGrabHandler for AnvilState<BackendData> {
@ -182,6 +209,30 @@ impl<BackendData: Backend> PrimarySelectionHandler for AnvilState<BackendData> {
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.primary_selection_state
}
#[cfg(feature = "xwayland")]
fn new_selection(&mut self, source: Option<ZwpPrimarySelectionSourceV1>, _seat: Seat<Self>) {
if let Some(xwm) = self.xwm.as_mut() {
if let Some(source) = source {
if let Ok(Err(err)) = with_primary_source_metadata(&source, |metadata| {
xwm.new_selection(SelectionType::Primary, Some(metadata.mime_types.clone()))
}) {
warn!(?err, "Failed to set Xwayland primary selection");
}
} else if let Err(err) = xwm.new_selection(SelectionType::Primary, None) {
warn!(?err, "Failed to clear Xwayland primary selection");
}
}
}
#[cfg(feature = "xwayland")]
fn send_selection(&mut self, mime_type: String, fd: OwnedFd, _seat: Seat<Self>, _user_data: &()) {
if let Some(xwm) = self.xwm.as_mut() {
if let Err(err) = xwm.send_selection(SelectionType::Primary, mime_type, fd, self.handle.clone()) {
warn!(?err, "Failed to send primary (X11 -> Wayland)");
}
}
}
}
delegate_primary_selection!(@<BackendData: Backend + 'static> AnvilState<BackendData>);