dnd: correct handling of cursor buffer offset
This commit is contained in:
parent
bd04d68106
commit
afdb656778
4 changed files with 130 additions and 27 deletions
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -43,7 +45,8 @@ 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,
|
||||
shell::wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState},
|
||||
|
|
@ -1216,6 +1219,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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue