From 4ad5199997d010d4c101681984424b91aedbecc1 Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Sat, 24 Feb 2024 12:55:12 +0100 Subject: [PATCH] wip: fix buffer offset --- anvil/src/shell/mod.rs | 34 +++++++++++++++++++++++ anvil/src/state.rs | 39 ++++++++++++++++++++------- anvil/src/udev.rs | 29 +++++++++++++------- anvil/src/winit.rs | 25 ++++++++++++----- anvil/src/x11.rs | 30 ++++++++++++--------- src/backend/renderer/utils/wayland.rs | 31 +++------------------ src/wayland/seat/pointer.rs | 28 +++++++++++++++++-- wlcs_anvil/src/main_loop.rs | 25 ++++++++++++----- 8 files changed, 167 insertions(+), 74 deletions(-) diff --git a/anvil/src/shell/mod.rs b/anvil/src/shell/mod.rs index a00ea262ed4c..6cdf61409c17 100644 --- a/anvil/src/shell/mod.rs +++ b/anvil/src/shell/mod.rs @@ -151,10 +151,44 @@ impl CompositorHandler for AnvilState { } if let Some(window) = self.window_for_surface(&root) { window.0.on_commit(); + + if &root == surface { + let buffer_offset = with_states(surface, |states| { + states + .cached_state + .current::() + .buffer_delta + .take() + }); + + if let Some(buffer_offset) = buffer_offset { + let current_loc = self.space.element_location(&window).unwrap(); + self.space.map_element(window, current_loc + buffer_offset, false); + } + } } } self.popups.commit(surface); + if let Some(dnd_icon) = self.dnd_icon.as_mut().and_then(|icon| { + if &icon.surface == surface { + Some(icon) + } else { + None + } + }) { + with_states(surface, |states| { + let buffer_delta = states + .cached_state + .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 4714a8aa495d..07a76f588a71 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -26,7 +26,7 @@ use smithay::{ }, input::{ keyboard::{Keysym, LedState, XkbConfig}, - pointer::{CursorImageStatus, PointerHandle}, + pointer::{CursorImageAttributes, CursorImageStatus, PointerHandle}, Seat, SeatHandler, SeatState, }, output::Output, @@ -41,7 +41,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, @@ -59,11 +59,11 @@ use smithay::{ security_context::{ SecurityContext, SecurityContextHandler, SecurityContextListenerSource, SecurityContextState, }, - selection::data_device::{ - set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, - ServerDndGrabHandler, - }, selection::{ + data_device::{ + set_data_device_focus, ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, + ServerDndGrabHandler, + }, primary_selection::{set_primary_focus, PrimarySelectionHandler, PrimarySelectionState}, wlr_data_control::{DataControlHandler, DataControlState}, SelectionHandler, @@ -96,7 +96,7 @@ use crate::{ #[cfg(feature = "xwayland")] use smithay::{ delegate_xwayland_keyboard_grab, - utils::{Point, Size}, + utils::Size, wayland::selection::{SelectionSource, SelectionTarget}, wayland::xwayland_keyboard_grab::{XWaylandKeyboardGrabHandler, XWaylandKeyboardGrabState}, xwayland::{X11Wm, XWayland, XWaylandEvent}, @@ -148,7 +148,7 @@ pub struct AnvilState { pub presentation_state: PresentationState, pub fractional_scale_manager_state: FractionalScaleManagerState, - pub dnd_icon: Option, + pub dnd_icon: Option, // input-related fields pub suppressed_keys: Vec, @@ -171,6 +171,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 { @@ -181,7 +187,22 @@ impl DataDeviceHandler for AnvilState { impl ClientDndGrabHandler for AnvilState { fn started(&mut self, _source: Option, icon: Option, _seat: Seat) { - self.dnd_icon = icon; + let cursor_status = self.cursor_status.lock().unwrap(); + let offset = if let CursorImageStatus::Surface(ref surface) = *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 921d218ebae8..41b28517d776 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -8,7 +8,7 @@ use std::{ time::{Duration, Instant}, }; -use crate::state::SurfaceDmabufFeedback; +use crate::state::{DndIcon, SurfaceDmabufFeedback}; use crate::{ drawing::*, render::*, @@ -1566,7 +1566,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, @@ -1590,8 +1590,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()); @@ -1610,16 +1609,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 0c2de8e37e96..7a207ae94f3d 100644 --- a/anvil/src/winit.rs +++ b/anvil/src/winit.rs @@ -291,8 +291,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(); @@ -324,15 +323,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 24637d8e1631..1997514f5e18 100644 --- a/anvil/src/x11.rs +++ b/anvil/src/x11.rs @@ -360,24 +360,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(cursor_guard.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/src/backend/renderer/utils/wayland.rs b/src/backend/renderer/utils/wayland.rs index 3c956a20e636..39b3f4e9860f 100644 --- a/src/backend/renderer/utils/wayland.rs +++ b/src/backend/renderer/utils/wayland.rs @@ -37,7 +37,6 @@ pub struct RendererSurfaceState { pub(crate) buffer_dimensions: Option>, pub(crate) buffer_scale: i32, pub(crate) buffer_transform: Transform, - pub(crate) buffer_delta: Option>, pub(crate) buffer_has_alpha: Option, pub(crate) buffer: Option, pub(crate) damage: DamageBag, @@ -45,8 +44,6 @@ pub struct RendererSurfaceState { pub(crate) textures: HashMap<(TypeId, usize), Box>, pub(crate) surface_view: Option, pub(crate) opaque_regions: Vec>, - - accumulated_buffer_delta: Point, } #[derive(Debug)] @@ -96,12 +93,6 @@ impl RendererSurfaceState { #[profiling::function] pub(crate) fn update_buffer(&mut self, states: &SurfaceData) { let mut attrs = states.cached_state.current::(); - self.buffer_delta = attrs.buffer_delta.take(); - - if let Some(delta) = self.buffer_delta { - self.accumulated_buffer_delta += delta; - } - match attrs.buffer.take() { Some(BufferAssignment::NewBuffer(buffer)) => { // new contents @@ -126,8 +117,7 @@ impl RendererSurfaceState { .buffer_dimensions .unwrap() .to_logical(self.buffer_scale, self.buffer_transform); - let surface_view = - SurfaceView::from_states(states, surface_size, self.accumulated_buffer_delta); + let surface_view = SurfaceView::from_states(states, surface_size); self.surface_view = Some(surface_view); let mut buffer_damage = attrs @@ -266,16 +256,6 @@ impl RendererSurfaceState { self.textures.get(&texture_id).and_then(|e| e.downcast_ref()) } - /// Location of the buffer relative to the previous call of take_accumulated_buffer_delta - /// - /// In other words, the x and y, combined with the new surface size define in which directions - /// the surface's size changed since last call to this method. - /// - /// Once delta is taken this method returns `None` to avoid processing it several times. - pub fn take_accumulated_buffer_delta(&mut self) -> Point { - std::mem::take(&mut self.accumulated_buffer_delta) - } - /// Gets the opaque regions of this surface pub fn opaque_regions(&self) -> Option<&[Rectangle]> { // If the surface is unmapped there can be no opaque regions @@ -359,23 +339,18 @@ pub fn on_commit_buffer_handler(surface: &WlSurface) { } impl SurfaceView { - fn from_states( - states: &SurfaceData, - surface_size: Size, - buffer_delta: Point, - ) -> SurfaceView { + fn from_states(states: &SurfaceData, surface_size: Size) -> SurfaceView { viewporter::ensure_viewport_valid(states, surface_size); let viewport = states.cached_state.current::(); let src = viewport .src .unwrap_or_else(|| Rectangle::from_loc_and_size((0.0, 0.0), surface_size.to_f64())); let dst = viewport.size().unwrap_or(surface_size); - let mut offset = if states.role == Some("subsurface") { + let offset = if states.role == Some("subsurface") { states.cached_state.current::().location } else { Default::default() }; - offset += buffer_delta; SurfaceView { src, dst, offset } } diff --git a/src/wayland/seat/pointer.rs b/src/wayland/seat/pointer.rs index 14c0cc31630b..6769d18de62a 100644 --- a/src/wayland/seat/pointer.rs +++ b/src/wayland/seat/pointer.rs @@ -528,8 +528,8 @@ where return; } - compositor::with_states(&surface, |states| { - states.data_map.insert_if_missing_threadsafe(|| { + let initial = compositor::with_states(&surface, |states| { + let initial = states.data_map.insert_if_missing_threadsafe(|| { Mutex::new(CursorImageAttributes { hotspot: (0, 0).into(), }) @@ -541,8 +541,32 @@ where .lock() .unwrap() .hotspot = (hotspot_x, hotspot_y).into(); + initial }); + if initial { + compositor::add_post_commit_hook::(&surface, |_, _, surface| { + compositor::with_states(surface, |states| { + let cursor_image_attributes = + states.data_map.get::>(); + + if let Some(mut cursor_image_attributes) = + cursor_image_attributes.map(|attrs| attrs.lock().unwrap()) + { + let buffer_delta = states + .cached_state + .current::() + .buffer_delta + .take(); + if let Some(buffer_delta) = buffer_delta { + tracing::trace!(hotspot = ?cursor_image_attributes.hotspot, ?buffer_delta, "decrementing cursor hotspot"); + cursor_image_attributes.hotspot -= buffer_delta; + } + } + }); + }); + } + CursorImageStatus::Surface(surface) } None => CursorImageStatus::Hidden, diff --git a/wlcs_anvil/src/main_loop.rs b/wlcs_anvil/src/main_loop.rs index 215b9f699436..6e41889bf015 100644 --- a/wlcs_anvil/src/main_loop.rs +++ b/wlcs_anvil/src/main_loop.rs @@ -119,19 +119,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(cursor_guard.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, ));