Skip to content

Commit

Permalink
dnd: correct handling of cursor buffer offset
Browse files Browse the repository at this point in the history
  • Loading branch information
cmeissl committed Sep 22, 2024
1 parent ad449f9 commit 81d18be
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 27 deletions.
13 changes: 9 additions & 4 deletions src/backend/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,11 +451,16 @@ where
}

if !exclude_dnd_icon {
if let Some(wl_surface) = get_dnd_icon(&seat) {
if let Some(dnd_icon) = get_dnd_icon(&seat) {
elements.extend(
cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), scale)
.into_iter()
.map(CosmicElement::Dnd),
cursor::draw_dnd_icon(
renderer,
&dnd_icon.surface,
(location + dnd_icon.offset.to_f64()).to_i32_round(),
scale,
)
.into_iter()
.map(CosmicElement::Dnd),
);
}
}
Expand Down
41 changes: 37 additions & 4 deletions src/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ use indexmap::IndexMap;
use layout::TilingExceptions;
use std::{
collections::HashMap,
sync::atomic::Ordering,
sync::{atomic::Ordering, Mutex},
time::{Duration, Instant},
};
use wayland_backend::server::ClientId;

use crate::wayland::protocols::workspace::WorkspaceCapabilities;
use crate::wayland::{handlers::data_device, protocols::workspace::WorkspaceCapabilities};
use cosmic_comp_config::{
workspace::{WorkspaceLayout, WorkspaceMode},
TileBehavior,
Expand All @@ -33,7 +33,9 @@ use smithay::{
LayerSurface, PopupKind, WindowSurface, WindowSurfaceType,
},
input::{
pointer::{Focus, GrabStartData as PointerGrabStartData},
pointer::{
CursorImageStatus, CursorImageSurfaceData, Focus, GrabStartData as PointerGrabStartData,
},
Seat,
},
output::Output,
Expand All @@ -43,7 +45,7 @@ use smithay::{
},
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size},
wayland::{
compositor::with_states,
compositor::{with_states, SurfaceAttributes},
foreign_toplevel_list::ForeignToplevelListState,
seat::WaylandFocus,
session_lock::LockSurface,
Expand Down Expand Up @@ -1222,6 +1224,37 @@ impl Common {
}
}
}

data_device::on_commit(surface, seat);
}

let is_cursor_image = shell.seats.iter().any(|seat| {
seat.user_data()
.get::<Mutex<CursorImageStatus>>()
.map(|guard| {
matches!(*guard.lock().unwrap(), CursorImageStatus::Surface(ref cursor_surface) if cursor_surface == surface)
})
.unwrap_or(false)
});

if is_cursor_image {
with_states(surface, |states| {
let cursor_image_attributes = states.data_map.get::<CursorImageSurfaceData>();

if let Some(mut cursor_image_attributes) =
cursor_image_attributes.map(|attrs| attrs.lock().unwrap())
{
let buffer_delta = states
.cached_state
.get::<SurfaceAttributes>()
.current()
.buffer_delta
.take();
if let Some(buffer_delta) = buffer_delta {
cursor_image_attributes.hotspot -= buffer_delta;
}
}
});
}

if let Some(mapped) = shell.element_for_surface(surface) {
Expand Down
89 changes: 74 additions & 15 deletions src/wayland/handlers/data_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,61 @@
use crate::state::State;
use smithay::{
delegate_data_device,
input::Seat,
input::{
pointer::{CursorImageStatus, CursorImageSurfaceData},
Seat,
},
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
utils::IsAlive,
wayland::selection::data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
utils::{IsAlive, Logical, Point},
wayland::{
compositor::{self, SurfaceAttributes},
selection::data_device::{
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
},
},
};
use std::sync::Mutex;

#[derive(Debug, Clone)]
pub struct DnDIcon {
surface: Mutex<Option<WlSurface>>,
pub surface: WlSurface,
pub offset: Point<i32, Logical>,
}

pub fn get_dnd_icon(seat: &Seat<State>) -> Option<WlSurface> {
pub fn get_dnd_icon(seat: &Seat<State>) -> Option<DnDIcon> {
let userdata = seat.user_data();
userdata
.get::<DnDIcon>()
.and_then(|x| x.surface.lock().unwrap().clone())
.filter(IsAlive::alive)
.get::<Mutex<Option<DnDIcon>>>()
.and_then(|x| x.lock().unwrap().clone())
.filter(|icon| icon.surface.alive())
}

pub fn on_commit(surface: &WlSurface, seat: &Seat<State>) {
let userdata = seat.user_data();

let Some(mut guard) = userdata
.get::<Mutex<Option<DnDIcon>>>()
.map(|guard| guard.lock().unwrap())
else {
return;
};

let Some(icon) = guard.as_mut() else {
return;
};

if &icon.surface == surface {
compositor::with_states(surface, |states| {
let buffer_delta = states
.cached_state
.get::<SurfaceAttributes>()
.current()
.buffer_delta
.take()
.unwrap_or_default();
icon.offset += buffer_delta;
});
}
}

impl ClientDndGrabHandler for State {
Expand All @@ -32,16 +68,39 @@ impl ClientDndGrabHandler for State {
seat: Seat<Self>,
) {
let user_data = seat.user_data();
user_data.insert_if_missing_threadsafe(|| DnDIcon {
surface: Mutex::new(None),
});
*user_data.get::<DnDIcon>().unwrap().surface.lock().unwrap() = icon;
user_data.insert_if_missing_threadsafe::<Mutex<Option<DnDIcon>>, _>(|| Default::default());

let offset = seat
.user_data()
.get::<Mutex<CursorImageStatus>>()
.map(|guard| {
if let CursorImageStatus::Surface(ref surface) = *guard.lock().unwrap() {
compositor::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()
}
})
.unwrap_or_default();

*user_data
.get::<Mutex<Option<DnDIcon>>>()
.unwrap()
.lock()
.unwrap() = icon.map(|surface| DnDIcon { surface, offset })
}
fn dropped(&mut self, seat: Seat<Self>) {
seat.user_data()
.get::<DnDIcon>()
.get::<Mutex<Option<DnDIcon>>>()
.unwrap()
.surface
.lock()
.unwrap()
.take();
Expand Down
13 changes: 9 additions & 4 deletions src/wayland/handlers/screencopy/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,11 +540,16 @@ pub fn render_window_to_buffer(
);
}

if let Some(wl_surface) = get_dnd_icon(&seat) {
if let Some(dnd_icon) = get_dnd_icon(&seat) {
elements.extend(
cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), 1.0)
.into_iter()
.map(WindowCaptureElement::from),
cursor::draw_dnd_icon(
renderer,
&dnd_icon.surface,
(location + dnd_icon.offset.to_f64()).to_i32_round(),
1.0,
)
.into_iter()
.map(WindowCaptureElement::from),
);
}
}
Expand Down

0 comments on commit 81d18be

Please sign in to comment.