diff --git a/anvil/src/shell/mod.rs b/anvil/src/shell/mod.rs index 1202a3bc2e..df9d0d184c 100644 --- a/anvil/src/shell/mod.rs +++ b/anvil/src/shell/mod.rs @@ -178,6 +178,21 @@ impl CompositorHandler for AnvilState { }); } + if matches!(&self.dnd_icon, Some(icon) if &icon.surface == surface) { + let dnd_icon = self.dnd_icon.as_mut().unwrap(); + with_states(&dnd_icon.surface, |states| { + let buffer_delta = states + .cached_state + .get::() + .current() + .buffer_delta + .take() + .unwrap_or_default(); + tracing::trace!(offset = ?dnd_icon.offset, ?buffer_delta, "moving dnd offset"); + dnd_icon.offset += buffer_delta; + }); + } + ensure_initial_configure(surface, &self.space, &mut self.popups) } } diff --git a/anvil/src/state.rs b/anvil/src/state.rs index adc6e45cf4..a3756b2c6b 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -29,7 +29,7 @@ use smithay::{ }, input::{ keyboard::{Keysym, LedState, XkbConfig}, - pointer::{CursorImageStatus, PointerHandle}, + pointer::{CursorImageStatus, CursorImageSurfaceData, PointerHandle}, Seat, SeatHandler, SeatState, }, output::Output, @@ -44,7 +44,7 @@ use smithay::{ Display, DisplayHandle, Resource, }, }, - utils::{Clock, Monotonic, Rectangle}, + utils::{Clock, Logical, Monotonic, Point, Rectangle}, wayland::{ compositor::{get_parent, with_states, CompositorClientState, CompositorState}, dmabuf::DmabufFeedback, @@ -101,7 +101,7 @@ use crate::{ #[cfg(feature = "xwayland")] use smithay::{ delegate_xwayland_keyboard_grab, delegate_xwayland_shell, - utils::{Point, Size}, + utils::Size, wayland::selection::{SelectionSource, SelectionTarget}, wayland::xwayland_keyboard_grab::{XWaylandKeyboardGrabHandler, XWaylandKeyboardGrabState}, wayland::xwayland_shell, @@ -153,7 +153,7 @@ pub struct AnvilState { pub xwayland_shell_state: xwayland_shell::XWaylandShellState, pub single_pixel_buffer_state: SinglePixelBufferState, - pub dnd_icon: Option, + pub dnd_icon: Option, // input-related fields pub suppressed_keys: Vec, @@ -174,6 +174,12 @@ pub struct AnvilState { pub show_window_preview: bool, } +#[derive(Debug)] +pub struct DndIcon { + pub surface: WlSurface, + pub offset: Point, +} + delegate_compositor!(@ AnvilState); impl DataDeviceHandler for AnvilState { @@ -184,7 +190,21 @@ impl DataDeviceHandler for AnvilState { impl ClientDndGrabHandler for AnvilState { fn started(&mut self, _source: Option, icon: Option, _seat: Seat) { - self.dnd_icon = icon; + let offset = if let CursorImageStatus::Surface(ref surface) = self.cursor_status { + with_states(surface, |states| { + let hotspot = states + .data_map + .get::() + .unwrap() + .lock() + .unwrap() + .hotspot; + Point::from((-hotspot.x, -hotspot.y)) + }) + } else { + (0, 0).into() + }; + self.dnd_icon = icon.map(|surface| DndIcon { surface, offset }); } fn dropped(&mut self, _seat: Seat) { self.dnd_icon = None; diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 53a3546ea1..f8fdb82f19 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -6,7 +6,7 @@ use std::{ time::{Duration, Instant}, }; -use crate::state::SurfaceDmabufFeedback; +use crate::state::{DndIcon, SurfaceDmabufFeedback}; use crate::{ drawing::*, render::*, @@ -1567,7 +1567,7 @@ fn render_surface<'a>( pointer_location: Point, pointer_image: &MemoryRenderBuffer, pointer_element: &mut PointerElement, - dnd_icon: &Option, + dnd_icon: &Option, cursor_status: &mut CursorImageStatus, clock: &Clock, show_window_preview: bool, @@ -1591,8 +1591,7 @@ fn render_surface<'a>( } else { (0, 0).into() }; - let cursor_pos = pointer_location - output_geometry.loc.to_f64() - cursor_hotspot.to_f64(); - let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round(); + let cursor_pos = pointer_location - output_geometry.loc.to_f64(); // set cursor pointer_element.set_buffer(pointer_image.clone()); @@ -1611,16 +1610,28 @@ fn render_surface<'a>( pointer_element.set_status(cursor_status.clone()); } - custom_elements.extend(pointer_element.render_elements(renderer, cursor_pos_scaled, scale, 1.0)); + custom_elements.extend( + pointer_element.render_elements( + renderer, + (cursor_pos - cursor_hotspot.to_f64()) + .to_physical(scale) + .to_i32_round(), + scale, + 1.0, + ), + ); // draw the dnd icon if applicable { - if let Some(wl_surface) = dnd_icon.as_ref() { - if wl_surface.alive() { + if let Some(icon) = dnd_icon.as_ref() { + let dnd_icon_pos = (cursor_pos + icon.offset.to_f64()) + .to_physical(scale) + .to_i32_round(); + if icon.surface.alive() { custom_elements.extend(AsRenderElements::>::render_elements( - &SurfaceTree::from_surface(wl_surface), + &SurfaceTree::from_surface(&icon.surface), renderer, - cursor_pos_scaled, + dnd_icon_pos, scale, 1.0, )); diff --git a/anvil/src/winit.rs b/anvil/src/winit.rs index 67ee961225..8c6c85664d 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -277,8 +277,7 @@ pub fn run_winit() { } else { (0, 0).into() }; - let cursor_pos = state.pointer.current_location() - cursor_hotspot.to_f64(); - let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round(); + let cursor_pos = state.pointer.current_location(); #[cfg(feature = "debug")] let mut renderdoc = state.renderdoc.as_mut(); @@ -310,15 +309,27 @@ pub fn run_winit() { let mut elements = Vec::>::new(); - elements.extend(pointer_element.render_elements(renderer, cursor_pos_scaled, scale, 1.0)); + elements.extend( + pointer_element.render_elements( + renderer, + (cursor_pos - cursor_hotspot.to_f64()) + .to_physical(scale) + .to_i32_round(), + scale, + 1.0, + ), + ); // draw the dnd icon if any - if let Some(surface) = dnd_icon { - if surface.alive() { + if let Some(icon) = dnd_icon { + let dnd_icon_pos = (cursor_pos + icon.offset.to_f64()) + .to_physical(scale) + .to_i32_round(); + if icon.surface.alive() { elements.extend(AsRenderElements::::render_elements( - &smithay::desktop::space::SurfaceTree::from_surface(surface), + &smithay::desktop::space::SurfaceTree::from_surface(&icon.surface), renderer, - cursor_pos_scaled, + dnd_icon_pos, scale, 1.0, )); diff --git a/anvil/src/x11.rs b/anvil/src/x11.rs index 7835aad178..128f8a6d53 100644 --- a/anvil/src/x11.rs +++ b/anvil/src/x11.rs @@ -346,24 +346,30 @@ pub fn run_x11() { } else { (0, 0).into() }; - let cursor_pos = state.pointer.current_location() - cursor_hotspot.to_f64(); - let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round(); + let cursor_pos = state.pointer.current_location(); pointer_element.set_status(state.cursor_status.clone()); - elements.extend(pointer_element.render_elements( - &mut backend_data.renderer, - cursor_pos_scaled, - scale, - 1.0, - )); + elements.extend( + pointer_element.render_elements( + &mut backend_data.renderer, + (cursor_pos - cursor_hotspot.to_f64()) + .to_physical(scale) + .to_i32_round(), + scale, + 1.0, + ), + ); // draw the dnd icon if any - if let Some(surface) = state.dnd_icon.as_ref() { - if surface.alive() { + if let Some(icon) = state.dnd_icon.as_ref() { + let dnd_icon_pos = (cursor_pos + icon.offset.to_f64()) + .to_physical(scale) + .to_i32_round(); + if icon.surface.alive() { elements.extend(AsRenderElements::::render_elements( - &smithay::desktop::space::SurfaceTree::from_surface(surface), + &smithay::desktop::space::SurfaceTree::from_surface(&icon.surface), &mut backend_data.renderer, - cursor_pos_scaled, + dnd_icon_pos, scale, 1.0, )); diff --git a/wlcs_anvil/src/main_loop.rs b/wlcs_anvil/src/main_loop.rs index 81e9a93e98..fa40b6f837 100644 --- a/wlcs_anvil/src/main_loop.rs +++ b/wlcs_anvil/src/main_loop.rs @@ -115,19 +115,30 @@ pub fn run(channel: Channel) { } else { (0, 0).into() }; - let cursor_pos = state.pointer.current_location() - cursor_hotspot.to_f64(); - let cursor_pos_scaled = cursor_pos.to_physical(scale).to_i32_round(); + let cursor_pos = state.pointer.current_location(); pointer_element.set_status(state.cursor_status.clone()); - elements.extend(pointer_element.render_elements(&mut renderer, cursor_pos_scaled, scale, 1.0)); + elements.extend( + pointer_element.render_elements( + &mut renderer, + (cursor_pos - cursor_hotspot.to_f64()) + .to_physical(scale) + .to_i32_round(), + scale, + 1.0, + ), + ); // draw the dnd icon if any - if let Some(surface) = state.dnd_icon.as_ref() { - if surface.alive() { + if let Some(icon) = state.dnd_icon.as_ref() { + if icon.surface.alive() { + let dnd_icon_pos = (cursor_pos + icon.offset.to_f64()) + .to_physical(scale) + .to_i32_round(); elements.extend(AsRenderElements::::render_elements( - &smithay::desktop::space::SurfaceTree::from_surface(surface), + &smithay::desktop::space::SurfaceTree::from_surface(&icon.surface), &mut renderer, - cursor_pos_scaled, + dnd_icon_pos, scale, 1.0, ));