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 !exclude_dnd_icon {
|
||||||
if let Some(wl_surface) = get_dnd_icon(&seat) {
|
if let Some(dnd_icon) = get_dnd_icon(&seat) {
|
||||||
elements.extend(
|
elements.extend(
|
||||||
cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), scale)
|
cursor::draw_dnd_icon(
|
||||||
.into_iter()
|
renderer,
|
||||||
.map(CosmicElement::Dnd),
|
&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 layout::TilingExceptions;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::atomic::Ordering,
|
sync::{atomic::Ordering, Mutex},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use wayland_backend::server::ClientId;
|
use wayland_backend::server::ClientId;
|
||||||
|
|
||||||
use crate::wayland::protocols::workspace::WorkspaceCapabilities;
|
use crate::wayland::{handlers::data_device, protocols::workspace::WorkspaceCapabilities};
|
||||||
use cosmic_comp_config::{
|
use cosmic_comp_config::{
|
||||||
workspace::{WorkspaceLayout, WorkspaceMode},
|
workspace::{WorkspaceLayout, WorkspaceMode},
|
||||||
TileBehavior,
|
TileBehavior,
|
||||||
|
|
@ -33,7 +33,9 @@ use smithay::{
|
||||||
LayerSurface, PopupKind, WindowSurface, WindowSurfaceType,
|
LayerSurface, PopupKind, WindowSurface, WindowSurfaceType,
|
||||||
},
|
},
|
||||||
input::{
|
input::{
|
||||||
pointer::{Focus, GrabStartData as PointerGrabStartData},
|
pointer::{
|
||||||
|
CursorImageStatus, CursorImageSurfaceData, Focus, GrabStartData as PointerGrabStartData,
|
||||||
|
},
|
||||||
Seat,
|
Seat,
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
|
|
@ -43,7 +45,8 @@ use smithay::{
|
||||||
},
|
},
|
||||||
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size},
|
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
compositor::with_states,
|
compositor::{with_states, SurfaceAttributes},
|
||||||
|
foreign_toplevel_list::ForeignToplevelListState,
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
session_lock::LockSurface,
|
session_lock::LockSurface,
|
||||||
shell::wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState},
|
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) {
|
if let Some(mapped) = shell.element_for_surface(surface) {
|
||||||
|
|
|
||||||
|
|
@ -3,25 +3,61 @@
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use smithay::{
|
use smithay::{
|
||||||
delegate_data_device,
|
delegate_data_device,
|
||||||
input::Seat,
|
input::{
|
||||||
|
pointer::{CursorImageStatus, CursorImageSurfaceData},
|
||||||
|
Seat,
|
||||||
|
},
|
||||||
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
|
reexports::wayland_server::protocol::{wl_data_source::WlDataSource, wl_surface::WlSurface},
|
||||||
utils::IsAlive,
|
utils::{IsAlive, Logical, Point},
|
||||||
wayland::selection::data_device::{
|
wayland::{
|
||||||
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
|
compositor::{self, SurfaceAttributes},
|
||||||
|
selection::data_device::{
|
||||||
|
ClientDndGrabHandler, DataDeviceHandler, DataDeviceState, ServerDndGrabHandler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct DnDIcon {
|
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();
|
let userdata = seat.user_data();
|
||||||
userdata
|
userdata
|
||||||
.get::<DnDIcon>()
|
.get::<Mutex<Option<DnDIcon>>>()
|
||||||
.and_then(|x| x.surface.lock().unwrap().clone())
|
.and_then(|x| x.lock().unwrap().clone())
|
||||||
.filter(IsAlive::alive)
|
.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 {
|
impl ClientDndGrabHandler for State {
|
||||||
|
|
@ -32,16 +68,39 @@ impl ClientDndGrabHandler for State {
|
||||||
seat: Seat<Self>,
|
seat: Seat<Self>,
|
||||||
) {
|
) {
|
||||||
let user_data = seat.user_data();
|
let user_data = seat.user_data();
|
||||||
user_data.insert_if_missing_threadsafe(|| DnDIcon {
|
user_data.insert_if_missing_threadsafe::<Mutex<Option<DnDIcon>>, _>(|| Default::default());
|
||||||
surface: Mutex::new(None),
|
|
||||||
});
|
let offset = seat
|
||||||
*user_data.get::<DnDIcon>().unwrap().surface.lock().unwrap() = icon;
|
.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>) {
|
fn dropped(&mut self, seat: Seat<Self>) {
|
||||||
seat.user_data()
|
seat.user_data()
|
||||||
.get::<DnDIcon>()
|
.get::<Mutex<Option<DnDIcon>>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.surface
|
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.take();
|
.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(
|
elements.extend(
|
||||||
cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), 1.0)
|
cursor::draw_dnd_icon(
|
||||||
.into_iter()
|
renderer,
|
||||||
.map(WindowCaptureElement::from),
|
&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