From 7ca46b44b2910d49b612fd06859560a4db2c1528 Mon Sep 17 00:00:00 2001 From: Ivan Molodetskikh Date: Thu, 18 Dec 2025 11:56:26 +0300 Subject: [PATCH] Update Smithay (DnD rework, primary GPU improvement) --- Cargo.lock | 4 +-- src/handlers/mod.rs | 70 ++++++++++++++++++++++++--------------- src/handlers/xdg_shell.rs | 5 ++- src/input/mod.rs | 32 ++++++++++-------- 4 files changed, 66 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94bff755..cdabe240 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3423,7 +3423,7 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smithay" version = "0.7.0" -source = "git+https://github.com/Smithay/smithay.git#d743e1a317fa0f01d1c4cadd96d277a1ec7b59d9" +source = "git+https://github.com/Smithay/smithay.git#6329f5b21693c53b0370cc7f62523ea4d0a42073" dependencies = [ "aliasable", "appendlist", @@ -3497,7 +3497,7 @@ dependencies = [ [[package]] name = "smithay-drm-extras" version = "0.1.0" -source = "git+https://github.com/Smithay/smithay.git#d743e1a317fa0f01d1c4cadd96d277a1ec7b59d9" +source = "git+https://github.com/Smithay/smithay.git#6329f5b21693c53b0370cc7f62523ea4d0a42073" dependencies = [ "drm", "libdisplay-info", diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 73575b45..de79778e 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -13,16 +13,16 @@ use smithay::backend::allocator::dmabuf::Dmabuf; use smithay::backend::drm::DrmNode; use smithay::backend::input::{InputEvent, TabletToolDescriptor}; use smithay::desktop::{PopupKind, PopupManager}; -use smithay::input::pointer::{CursorIcon, CursorImageStatus, PointerHandle}; +use smithay::input::dnd::{self, DnDGrab, DndGrabHandler, DndTarget}; +use smithay::input::pointer::{CursorIcon, CursorImageStatus, Focus, PointerHandle}; use smithay::input::{keyboard, Seat, SeatHandler, SeatState}; use smithay::output::Output; use smithay::reexports::rustix::fs::{fcntl_setfl, OFlags}; use smithay::reexports::wayland_protocols_wlr::screencopy::v1::server::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1; -use smithay::reexports::wayland_server::protocol::wl_data_source::WlDataSource; use smithay::reexports::wayland_server::protocol::wl_output::WlOutput; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::reexports::wayland_server::Resource; -use smithay::utils::{Logical, Point, Rectangle}; +use smithay::utils::{Logical, Point, Rectangle, Serial}; use smithay::wayland::compositor::{get_parent, with_states}; use smithay::wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier}; use smithay::wayland::drm_lease::{ @@ -41,8 +41,7 @@ use smithay::wayland::security_context::{ SecurityContext, SecurityContextHandler, SecurityContextListenerSource, }; use smithay::wayland::selection::data_device::{ - set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, - ServerDndGrabHandler, + set_data_device_focus, DataDeviceHandler, DataDeviceState, WaylandDndGrabHandler, }; use smithay::wayland::selection::ext_data_control::{ DataControlHandler as ExtDataControlHandler, DataControlState as ExtDataControlState, @@ -314,23 +313,51 @@ impl DataDeviceHandler for State { } } -impl ClientDndGrabHandler for State { - fn started( +impl WaylandDndGrabHandler for State { + fn dnd_requested( &mut self, - _source: Option, + source: S, icon: Option, - _seat: Seat, + seat: Seat, + serial: Serial, + type_: dnd::GrabType, ) { self.niri.dnd_icon = icon.map(|surface| DndIcon { surface, offset: Point::new(0, 0), }); + + match type_ { + dnd::GrabType::Pointer => { + let pointer = seat.get_pointer().unwrap(); + let start_data = pointer.grab_start_data().unwrap(); + let grab = + DnDGrab::new_pointer(&self.niri.display_handle, start_data, source, seat); + pointer.set_grab(self, grab, serial, Focus::Keep); + } + dnd::GrabType::Touch => { + let touch = seat.get_touch().unwrap(); + let start_data = touch.grab_start_data().unwrap(); + let grab = DnDGrab::new_touch(&self.niri.display_handle, start_data, source, seat); + touch.set_grab(self, grab, serial); + } + } + // FIXME: more granular self.niri.queue_redraw_all(); } +} - fn dropped(&mut self, target: Option, validated: bool, _seat: Seat) { - trace!("client dropped, target: {target:?}, validated: {validated}"); +impl DndGrabHandler for State { + fn dropped( + &mut self, + target: Option>, + validated: bool, + _seat: Seat, + location: Point, + ) { + let target: Option<&WlSurface> = target.map(DndTarget::into_inner); + trace!("dnd dropped, target: {target:?}, validated: {validated}"); // End DnD before activating a specific window below so that it takes precedence. self.niri.layout.dnd_end(); @@ -339,7 +366,7 @@ impl ClientDndGrabHandler for State { // example. On successful drop, additionally activate the target window. let mut activate_output = true; if let Some(target) = validated.then_some(target).flatten() { - let root = self.niri.find_root_shell_surface(&target); + let root = self.niri.find_root_shell_surface(target); if let Some((mapped, _)) = self.niri.layout.find_window_and_output(&root) { let window = mapped.window.clone(); self.niri.layout.activate_window(&window); @@ -349,19 +376,10 @@ impl ClientDndGrabHandler for State { } if activate_output { - // Find the output from cursor coordinates. - // - // FIXME: uhhh, we can't actually properly tell if the DnD comes from pointer or touch, - // and if it comes from touch, then what the coordinates are. Need to pass more - // parameters from Smithay I guess. - // - // Assume that hidden pointer means touch DnD. - if self.niri.pointer_visibility.is_visible() { - // We can't even get the current pointer location because it's locked (we're deep - // in the grab call stack here). So use the last known one. - if let Some(output) = &self.niri.pointer_contents.output { - self.niri.layout.focus_output(output); - } + // Find the output from drop coordinates. + if let Some((output, _)) = self.niri.output_under(location) { + let output = output.clone(); + self.niri.layout.focus_output(&output); } } @@ -371,8 +389,6 @@ impl ClientDndGrabHandler for State { } } -impl ServerDndGrabHandler for State {} - delegate_data_device!(State); impl PrimarySelectionHandler for State { diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index e3969b7f..217e32b2 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -24,7 +24,6 @@ use smithay::wayland::compositor::{ }; use smithay::wayland::dmabuf::get_dmabuf; use smithay::wayland::input_method::InputMethodSeat; -use smithay::wayland::selection::data_device::DnDGrab; use smithay::wayland::shell::kde::decoration::{KdeDecorationHandler, KdeDecorationState}; use smithay::wayland::shell::wlr_layer::{self, Layer}; use smithay::wayland::shell::xdg::decoration::XdgDecorationHandler; @@ -85,7 +84,7 @@ impl XdgShellHandler for State { if focus.id().same_client_as(&wl_surface.id()) { // Deny move requests from DnD grabs to work around // https://gitlab.gnome.org/GNOME/gtk/-/issues/7113 - let is_dnd_grab = grab.as_any().is::>(); + let is_dnd_grab = Self::is_dnd_grab(grab.as_any()); if !is_dnd_grab { grab_start_data = @@ -105,7 +104,7 @@ impl XdgShellHandler for State { if focus.id().same_client_as(&wl_surface.id()) { // Deny move requests from DnD grabs to work around // https://gitlab.gnome.org/GNOME/gtk/-/issues/7113 - let is_dnd_grab = grab.as_any().is::>(); + let is_dnd_grab = Self::is_dnd_grab(grab.as_any()); if !is_dnd_grab { grab_start_data = diff --git a/src/input/mod.rs b/src/input/mod.rs index e7c7590e..4cfb7adc 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -19,6 +19,7 @@ use smithay::backend::input::{ TabletToolTipState, TouchEvent, }; use smithay::backend::libinput::LibinputInputBackend; +use smithay::input::dnd::DnDGrab; use smithay::input::keyboard::{keysyms, FilterResult, Keysym, Layout, ModifiersState}; use smithay::input::pointer::{ AxisFrame, ButtonEvent, CursorIcon, CursorImageStatus, Focus, GestureHoldBeginEvent, @@ -31,10 +32,11 @@ use smithay::input::touch::{ }; use smithay::input::SeatHandler; use smithay::output::Output; +use smithay::reexports::wayland_server::protocol::wl_data_source::WlDataSource; +use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; use smithay::utils::{Logical, Point, Rectangle, Transform, SERIAL_COUNTER}; use smithay::wayland::keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitor; use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint}; -use smithay::wayland::selection::data_device::DnDGrab; use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait}; use touch_overview_grab::TouchOverviewGrab; @@ -2583,10 +2585,9 @@ impl State { self.niri.maybe_activate_pointer_constraint(); // Inform the layout of an ongoing DnD operation. - let mut is_dnd_grab = false; - pointer.with_grab(|_, grab| { - is_dnd_grab = grab.as_any().is::>(); - }); + let is_dnd_grab = pointer + .with_grab(|_, grab| Self::is_dnd_grab(grab.as_any())) + .unwrap_or(false); if is_dnd_grab { if let Some((output, pos_within_output)) = self.niri.output_under(new_pos) { let output = output.clone(); @@ -2682,10 +2683,9 @@ impl State { self.niri.tablet_cursor_location = None; // Inform the layout of an ongoing DnD operation. - let mut is_dnd_grab = false; - pointer.with_grab(|_, grab| { - is_dnd_grab = grab.as_any().is::>(); - }); + let is_dnd_grab = pointer + .with_grab(|_, grab| Self::is_dnd_grab(grab.as_any())) + .unwrap_or(false); if is_dnd_grab { if let Some((output, pos_within_output)) = self.niri.output_under(pos) { let output = output.clone(); @@ -4212,10 +4212,9 @@ impl State { ); // Inform the layout of an ongoing DnD operation. - let mut is_dnd_grab = false; - handle.with_grab(|_, grab| { - is_dnd_grab = grab.as_any().is::>(); - }); + let is_dnd_grab = handle + .with_grab(|_, grab| Self::is_dnd_grab(grab.as_any())) + .unwrap_or(false); if is_dnd_grab { if let Some((output, pos_within_output)) = self.niri.output_under(pos) { let output = output.clone(); @@ -4256,6 +4255,13 @@ impl State { self.do_action(action, true); } } + + pub fn is_dnd_grab(grab: &dyn Any) -> bool { + // Normal DnD + grab.is::>() + // Null-source DnD: weston-dnd --self-only + || grab.is::>() + } } /// Check whether the key should be intercepted and mark intercepted