mirror of
https://github.com/Smithay/smithay.git
synced 2024-09-28 03:21:14 +02:00
anvil: xwayland clipboard sync
This commit is contained in:
parent
61e139917a
commit
d8b6bb485a
2 changed files with 127 additions and 8 deletions
|
@ -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> {
|
||||
|
|
|
@ -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>);
|
||||
|
||||
|
|
Loading…
Reference in a new issue