Add drag-and-drop support between x11 windows

This commit is contained in:
Ottatop 2023-08-02 15:12:10 -05:00
parent 4e4eb0fe7c
commit 7048a89dbf
3 changed files with 100 additions and 8 deletions

View file

@ -7,8 +7,8 @@ use std::time::Duration;
use smithay::{
backend::renderer::utils,
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_output,
delegate_presentation, delegate_relative_pointer, delegate_seat, delegate_shm,
delegate_viewporter, delegate_xdg_shell,
delegate_presentation, delegate_primary_selection, delegate_relative_pointer, delegate_seat,
delegate_shm, delegate_viewporter, delegate_xdg_shell,
desktop::{
find_popup_root_surface, utils::surface_primary_scanout_output, PopupKeyboardGrab,
PopupKind, PopupPointerGrab, PopupUngrabStrategy, Window,
@ -38,6 +38,7 @@ use smithay::{
},
dmabuf,
fractional_scale::{self, FractionalScaleHandler},
primary_selection::{PrimarySelectionHandler, PrimarySelectionState},
seat::WaylandFocus,
shell::xdg::{
Configure, PopupSurface, PositionerState, ToplevelSurface, XdgPopupSurfaceData,
@ -207,6 +208,15 @@ impl<B: Backend> DataDeviceHandler for State<B> {
}
delegate_data_device!(@<B: Backend> State<B>);
impl<B: Backend> PrimarySelectionHandler for State<B> {
type SelectionUserData = ();
fn primary_selection_state(&self) -> &PrimarySelectionState {
&self.primary_selection_state
}
}
delegate_primary_selection!(@<B: Backend> State<B>);
impl<B: Backend> SeatHandler for State<B> {
type KeyboardFocus = FocusTarget;
type PointerFocus = FocusTarget;

View file

@ -7,9 +7,19 @@
use smithay::{
reexports::wayland_server::Resource,
utils::{Logical, Point, Rectangle, SERIAL_COUNTER},
wayland::compositor::{self, CompositorHandler},
wayland::{
compositor::{self, CompositorHandler},
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, WmWindowType, XwmId},
xwm::{Reorder, SelectionType, WmWindowType, XwmId},
X11Surface, X11Wm, XwmHandler,
},
};
@ -375,13 +385,80 @@ impl<B: Backend> XwmHandler for CalloopData<B> {
);
}
// TODO: allow_selection_access
fn allow_selection_access(&mut self, xwm: XwmId, _selection: SelectionType) -> bool {
self.state
.seat
.get_keyboard()
.and_then(|kb| kb.current_focus())
.is_some_and(|focus| {
if let FocusTarget::Window(WindowElement::X11(surface)) = focus {
surface.xwm_id().expect("x11surface had no xwm id") == xwm
} else {
false
}
})
}
// TODO: send_selection
fn send_selection(
&mut self,
xwm: XwmId,
selection: SelectionType,
mime_type: String,
fd: std::os::fd::OwnedFd,
) {
match selection {
SelectionType::Clipboard => {
if let Err(err) =
request_data_device_client_selection(&self.state.seat, mime_type, fd)
{
tracing::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)
{
tracing::error!(
?err,
"Failed to request current wayland primary selection for XWayland"
);
}
}
}
}
// TODO: new_selection
fn new_selection(&mut self, xwm: XwmId, selection: SelectionType, mime_types: Vec<String>) {
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, ());
}
}
}
// TODO: cleared_selection
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);
}
}
}
}
}
/// Make assumptions on whether or not the surface should be floating.

View file

@ -57,6 +57,7 @@ use smithay::{
dmabuf::DmabufFeedback,
fractional_scale::FractionalScaleManagerState,
output::OutputManagerState,
primary_selection::PrimarySelectionState,
shell::xdg::{XdgShellState, XdgToplevelSurfaceData},
shm::ShmState,
socket::ListeningSocketSource,
@ -90,6 +91,8 @@ pub struct State<B: Backend> {
pub xdg_shell_state: XdgShellState,
pub viewporter_state: ViewporterState,
pub fractional_scale_manager_state: FractionalScaleManagerState,
pub primary_selection_state: PrimarySelectionState,
pub input_state: InputState,
pub api_state: ApiState,
pub focus_state: FocusState,
@ -889,6 +892,8 @@ impl<B: Backend> State<B> {
fractional_scale_manager_state: FractionalScaleManagerState::new::<Self>(
&display_handle,
),
primary_selection_state: PrimarySelectionState::new::<Self>(&display_handle),
input_state: InputState::new(),
api_state: ApiState::new(),
focus_state: FocusState::new(),