anvil: handle dnd icon buffer offset

This commit is contained in:
Christian Meissl 2024-09-14 13:17:16 +02:00 committed by Victoria Brekenfeld
parent 86e8b80eeb
commit 03aaea2415
6 changed files with 114 additions and 40 deletions

View file

@ -178,6 +178,21 @@ impl<BackendData: Backend> CompositorHandler for AnvilState<BackendData> {
});
}
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::<SurfaceAttributes>()
.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)
}
}

View file

@ -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<BackendData: Backend + 'static> {
pub xwayland_shell_state: xwayland_shell::XWaylandShellState,
pub single_pixel_buffer_state: SinglePixelBufferState,
pub dnd_icon: Option<WlSurface>,
pub dnd_icon: Option<DndIcon>,
// input-related fields
pub suppressed_keys: Vec<Keysym>,
@ -174,6 +174,12 @@ pub struct AnvilState<BackendData: Backend + 'static> {
pub show_window_preview: bool,
}
#[derive(Debug)]
pub struct DndIcon {
pub surface: WlSurface,
pub offset: Point<i32, Logical>,
}
delegate_compositor!(@<BackendData: Backend + 'static> AnvilState<BackendData>);
impl<BackendData: Backend> DataDeviceHandler for AnvilState<BackendData> {
@ -184,7 +190,21 @@ impl<BackendData: Backend> DataDeviceHandler for AnvilState<BackendData> {
impl<BackendData: Backend> ClientDndGrabHandler for AnvilState<BackendData> {
fn started(&mut self, _source: Option<WlDataSource>, icon: Option<WlSurface>, _seat: Seat<Self>) {
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::<CursorImageSurfaceData>()
.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>) {
self.dnd_icon = None;

View file

@ -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<f64, Logical>,
pointer_image: &MemoryRenderBuffer,
pointer_element: &mut PointerElement,
dnd_icon: &Option<wl_surface::WlSurface>,
dnd_icon: &Option<DndIcon>,
cursor_status: &mut CursorImageStatus,
clock: &Clock<Monotonic>,
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::<UdevRenderer<'a>>::render_elements(
&SurfaceTree::from_surface(wl_surface),
&SurfaceTree::from_surface(&icon.surface),
renderer,
cursor_pos_scaled,
dnd_icon_pos,
scale,
1.0,
));

View file

@ -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::<CustomRenderElements<GlesRenderer>>::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::<GlesRenderer>::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,
));

View file

@ -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(
elements.extend(
pointer_element.render_elements(
&mut backend_data.renderer,
cursor_pos_scaled,
(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::<GlesRenderer>::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,
));

View file

@ -115,19 +115,30 @@ pub fn run(channel: Channel<WlcsEvent>) {
} 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::<DummyRenderer>::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,
));