From 42b898d83947fe38afc183bc2760cf61eedb6f80 Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Sat, 24 Feb 2024 18:17:51 +0100 Subject: [PATCH] handle role specific buffer offset --- Cargo.lock | 12 ++--------- src/handlers/compositor.rs | 43 ++++++++++++++++++++++++++++++++++++-- src/handlers/mod.rs | 26 +++++++++++++++++++---- src/input/mod.rs | 14 ++++++------- src/niri.rs | 40 ++++++++++++++++++++++------------- 5 files changed, 97 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 00bedd34..ff7baa64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3346,12 +3346,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scan_fmt" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" - [[package]] name = "schemars" version = "0.8.21" @@ -3528,7 +3522,7 @@ checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/Smithay/smithay.git#f364c73cae953aebfa189075e9f118f9008e100b" +source = "git+https://github.com/Smithay/smithay.git#b29ff8fdbfa3a15b777d36a7c5f19f86dfe5c94c" dependencies = [ "appendlist", "bitflags 2.6.0", @@ -3545,7 +3539,6 @@ dependencies = [ "gl_generator", "indexmap", "input", - "lazy_static", "libc", "libloading", "libseat", @@ -3555,7 +3548,6 @@ dependencies = [ "profiling", "rand", "rustix 0.38.37", - "scan_fmt", "smallvec", "tempfile", "thiserror", @@ -3602,7 +3594,7 @@ dependencies = [ [[package]] name = "smithay-drm-extras" version = "0.1.0" -source = "git+https://github.com/Smithay/smithay.git#f364c73cae953aebfa189075e9f118f9008e100b" +source = "git+https://github.com/Smithay/smithay.git#b29ff8fdbfa3a15b777d36a7c5f19f86dfe5c94c" dependencies = [ "drm", "libdisplay-info", diff --git a/src/handlers/compositor.rs b/src/handlers/compositor.rs index 57be5ad3..ceb22b78 100644 --- a/src/handlers/compositor.rs +++ b/src/handlers/compositor.rs @@ -1,7 +1,7 @@ use std::collections::hash_map::Entry; use smithay::backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state}; -use smithay::input::pointer::CursorImageStatus; +use smithay::input::pointer::{CursorImageStatus, CursorImageSurfaceData}; use smithay::reexports::calloop::Interest; use smithay::reexports::wayland_server::protocol::wl_buffer; use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface; @@ -297,13 +297,52 @@ impl CompositorHandler for State { &self.niri.cursor_manager.cursor_image(), CursorImageStatus::Surface(s) if s == &root_surface ) { + // In case the cursor surface has been committed handle the role specific + // buffer offset by applying the offset on the cursor image hotspot + if surface == &root_surface { + 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 + .get::() + .current() + .buffer_delta + .take(); + if let Some(buffer_delta) = buffer_delta { + cursor_image_attributes.hotspot -= buffer_delta; + } + } + }); + } + // FIXME: granular redraws for cursors. self.niri.queue_redraw_all(); return; } // This might be a DnD icon surface. - if self.niri.dnd_icon.as_ref() == Some(&root_surface) { + if matches!(&self.niri.dnd_icon, Some(icon) if icon.surface == root_surface) { + let dnd_icon = self.niri.dnd_icon.as_mut().unwrap(); + + // In case the dnd surface has been committed handle the role specific + // buffer offset by applying the offset on the dnd icon offset + if surface == &dnd_icon.surface { + with_states(&dnd_icon.surface, |states| { + let buffer_delta = states + .cached_state + .get::() + .current() + .buffer_delta + .take() + .unwrap_or_default(); + dnd_icon.offset += buffer_delta; + }); + } + // FIXME: granular redraws for cursors. self.niri.queue_redraw_all(); return; diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 3e0bb18f..63bde132 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -12,7 +12,9 @@ use smithay::backend::allocator::dmabuf::Dmabuf; use smithay::backend::drm::DrmNode; use smithay::backend::input::TabletToolDescriptor; use smithay::desktop::{PopupKind, PopupManager}; -use smithay::input::pointer::{CursorIcon, CursorImageStatus, PointerHandle}; +use smithay::input::pointer::{ + CursorIcon, CursorImageStatus, CursorImageSurfaceData, PointerHandle, +}; use smithay::input::{keyboard, Seat, SeatHandler, SeatState}; use smithay::output::Output; use smithay::reexports::rustix::fs::{fcntl_setfl, OFlags}; @@ -22,7 +24,7 @@ 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, Rectangle, Size}; +use smithay::utils::{Logical, Point, Rectangle, Size}; use smithay::wayland::compositor::with_states; use smithay::wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier}; use smithay::wayland::drm_lease::{ @@ -64,7 +66,7 @@ use smithay::{ }; pub use crate::handlers::xdg_shell::KdeDecorationsModeState; -use crate::niri::{ClientState, State}; +use crate::niri::{ClientState, DndIcon, State}; use crate::protocols::foreign_toplevel::{ self, ForeignToplevelHandler, ForeignToplevelManagerState, }; @@ -225,7 +227,23 @@ impl ClientDndGrabHandler for State { icon: Option, _seat: Seat, ) { - self.niri.dnd_icon = icon; + let offset = if let CursorImageStatus::Surface(ref surface) = + self.niri.cursor_manager.cursor_image() + { + 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.niri.dnd_icon = icon.map(|surface| DndIcon { surface, offset }); // FIXME: more granular self.niri.queue_redraw_all(); } diff --git a/src/input/mod.rs b/src/input/mod.rs index 7fc606ba..afa215ff 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -11,7 +11,7 @@ use niri_ipc::LayoutSwitchTarget; use smithay::backend::input::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Device, DeviceCapability, Event, GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _, - InputBackend, InputEvent, KeyState, KeyboardKeyEvent, MouseButton, PointerAxisEvent, + InputBackend, InputEvent, KeyState, KeyboardKeyEvent, Keycode, MouseButton, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent, }; @@ -2305,10 +2305,10 @@ impl State { /// to them from being delivered. #[allow(clippy::too_many_arguments)] fn should_intercept_key( - suppressed_keys: &mut HashSet, + suppressed_keys: &mut HashSet, bindings: &Binds, comp_mod: CompositorMod, - key_code: u32, + key_code: Keycode, modified: Keysym, raw: Option, pressed: bool, @@ -2754,8 +2754,8 @@ mod tests { // The key_code we pick is arbitrary, the only thing // that matters is that they are different between cases. - let close_key_code = close_keysym.into(); - let close_key_event = |suppr: &mut HashSet, mods: ModifiersState, pressed| { + let close_key_code = Keycode::from(close_keysym.raw() + 8u32); + let close_key_event = |suppr: &mut HashSet, mods: ModifiersState, pressed| { should_intercept_key( suppr, &bindings, @@ -2771,12 +2771,12 @@ mod tests { }; // Key event with the code which can't trigger any action. - let none_key_event = |suppr: &mut HashSet, mods: ModifiersState, pressed| { + let none_key_event = |suppr: &mut HashSet, mods: ModifiersState, pressed| { should_intercept_key( suppr, &bindings, comp_mod, - Keysym::l.into(), + Keycode::from(Keysym::l.raw() + 8), Keysym::l, Some(Keysym::l), pressed, diff --git a/src/niri.rs b/src/niri.rs index bdebe8bd..a2c81ae6 100644 --- a/src/niri.rs +++ b/src/niri.rs @@ -17,6 +17,7 @@ use niri_config::{ DEFAULT_BACKGROUND_COLOR, }; use smithay::backend::allocator::Fourcc; +use smithay::backend::input::Keycode; use smithay::backend::renderer::damage::OutputDamageTracker; use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement; use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement}; @@ -248,7 +249,7 @@ pub struct Niri { pub seat: Seat, /// Scancodes of the keys to suppress. - pub suppressed_keys: HashSet, + pub suppressed_keys: HashSet, pub bind_cooldown_timers: HashMap, pub bind_repeat_timer: Option, pub keyboard_focus: KeyboardFocus, @@ -259,7 +260,7 @@ pub struct Niri { pub cursor_manager: CursorManager, pub cursor_texture_cache: CursorTextureCache, pub cursor_shape_manager_state: CursorShapeManagerState, - pub dnd_icon: Option, + pub dnd_icon: Option, pub pointer_focus: PointerFocus, /// Whether the pointer is hidden, for example due to a previous touch input. /// @@ -304,6 +305,12 @@ pub struct Niri { pub mapped_cast_output: HashMap, } +#[derive(Debug)] +pub struct DndIcon { + pub surface: WlSurface, + pub offset: Point, +} + pub struct OutputState { pub global: GlobalId, pub frame_clock: FrameClock, @@ -2588,8 +2595,8 @@ impl Niri { let output_scale = Scale::from(output.current_scale().fractional_scale()); - let (mut pointer_elements, pointer_pos) = match render_cursor { - RenderCursor::Hidden => (vec![], pointer_pos.to_physical_precise_round(output_scale)), + let mut pointer_elements = match render_cursor { + RenderCursor::Hidden => vec![], RenderCursor::Surface { surface, hotspot } => { let pointer_pos = (pointer_pos - hotspot.to_f64()).to_physical_precise_round(output_scale); @@ -2603,7 +2610,7 @@ impl Niri { Kind::Cursor, ); - (pointer_elements, pointer_pos) + pointer_elements } RenderCursor::Named { icon, @@ -2619,7 +2626,7 @@ impl Niri { let mut pointer_elements = vec![]; let pointer_element = match MemoryRenderBufferRenderElement::from_buffer( renderer, - pointer_pos.to_f64(), + pointer_pos, &texture, None, None, @@ -2636,14 +2643,16 @@ impl Niri { pointer_elements.push(OutputRenderElements::NamedPointer(element)); } - (pointer_elements, pointer_pos) + pointer_elements } }; - if let Some(dnd_icon) = &self.dnd_icon { + if let Some(dnd_icon) = self.dnd_icon.as_ref() { + let pointer_pos = + (pointer_pos + dnd_icon.offset.to_f64()).to_physical_precise_round(output_scale); pointer_elements.extend(render_elements_from_surface_tree( renderer, - dnd_icon, + &dnd_icon.surface, pointer_pos, output_scale, 1., @@ -2684,6 +2693,7 @@ impl Niri { let dnd = self .dnd_icon .as_ref() + .map(|icon| &icon.surface) .map(|surface| (surface, bbox_from_surface_tree(surface, surface_pos))); // FIXME we basically need to pick the largest scale factor across the overlapping @@ -2745,7 +2755,7 @@ impl Niri { } cursor_image => { // There's no cursor surface, but there might be a DnD icon. - let Some(surface) = &self.dnd_icon else { + let Some(surface) = self.dnd_icon.as_ref().map(|icon| &icon.surface) else { return; }; @@ -3267,7 +3277,7 @@ impl Niri { ); } - if let Some(surface) = &self.dnd_icon { + if let Some(surface) = self.dnd_icon.as_ref().map(|icon| &icon.surface) { with_surface_tree_downward( surface, (), @@ -3405,7 +3415,7 @@ impl Niri { ); } - if let Some(surface) = &self.dnd_icon { + if let Some(surface) = self.dnd_icon.as_ref().map(|icon| &icon.surface) { send_dmabuf_feedback_surface_tree( surface, output, @@ -3507,7 +3517,7 @@ impl Niri { ); } - if let Some(surface) = &self.dnd_icon { + if let Some(surface) = self.dnd_icon.as_ref().map(|icon| &icon.surface) { send_frames_surface_tree( surface, output, @@ -3575,7 +3585,7 @@ impl Niri { } } - if let Some(surface) = &self.dnd_icon { + if let Some(surface) = &self.dnd_icon.as_ref().map(|icon| &icon.surface) { send_frames_surface_tree( surface, output, @@ -3614,7 +3624,7 @@ impl Niri { ); } - if let Some(surface) = &self.dnd_icon { + if let Some(surface) = self.dnd_icon.as_ref().map(|icon| &icon.surface) { take_presentation_feedback_surface_tree( surface, &mut feedback,