Commit 211452a41a25
tarball7 files changed+122-15
@@ -41,6 +41,21 @@ impl CompositorHandler for State {
4141
4242
fn commit(&mut self, surface: &WlSurface) {4343
on_commit_buffer_handler::<Self>(surface);44
+ if let Some(icon) = self45
+ .input46
+ .dnd_icon47
+ .as_mut()48
+ .filter(|i| &i.surface == surface)49
+ {50
+ let delta = with_states(surface, |s| {51
+ s.cached_state52
+ .get::<SurfaceAttributes>()53
+ .current()54
+ .buffer_delta55
+ .take()56
+ });57
+ icon.offset += delta.unwrap_or_default();58
+ }4459
// Importing at commit keeps first-time dmabuf imports, which take4560
// milliseconds on NVIDIA, out of the render racing the next vblank.4661
if let Err(e) = import_surface_tree(&mut self.renderer, surface) {@@ -13,6 +13,7 @@ use smithay::backend::renderer::element::{Id, Kind};
1313
use smithay::backend::renderer::utils::CommitCounter;1414
use smithay::input::pointer::CursorIcon;1515
use smithay::input::pointer::{CursorImageAttributes, CursorImageStatus};16
+use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;1617
use smithay::utils::{Logical, Physical, Point, Rectangle, Transform};1718
use smithay::wayland::compositor::with_states;1819
use std::collections::HashMap;@@ -143,3 +144,28 @@ fn load_image(theme: &xcursor::CursorTheme, name: &str, size: u32) -> Image {
143144
);144145
Some((buffer, (image.xhot as i32, image.yhot as i32).into()))145146
}147
+148
+/// The surface a drag carries under the pointer. `offset` accumulates the149
+/// attach offsets the client commits, as the icon has no hotspot of its own.150
+pub struct DndIcon {151
+ pub surface: WlSurface,152
+ pub offset: Point<i32, Logical>,153
+}154
+155
+impl DndIcon {156
+ /// Elements for the icon with the pointer at `pos`, in output-local coordinates.157
+ pub fn elements(&self, renderer: &mut VulkanRenderer, pos: Point<f64, Logical>) -> Vec<Draw> {158
+ let p = pos + self.offset.to_f64();159
+ render_elements_from_surface_tree(160
+ renderer,161
+ &self.surface,162
+ (p.x.round() as i32, p.y.round() as i32),163
+ 1.0,164
+ 1.0,165
+ Kind::Unspecified,166
+ )167
+ .into_iter()168
+ .map(Draw::Surface)169
+ .collect()170
+ }171
+}@@ -1084,6 +1084,7 @@ fn render_surface(state: &mut State, crtc: crtc::Handle, target: u64) -> bool {
10841084
&surface.output,10851085
now,10861086
elapsed,1087
+ input.dnd_icon.as_ref(),10871088
);10881089
crate::frame::send_cursor_frames(wm, input, surface.id, &surface.output, elapsed);10891090
(animating || failed) && !surface.queued@@ -1,6 +1,7 @@
11
//! What every output shows, shared by the backends and screen capture.22
//! Backends only decide when to draw and how to present.33
4
+use crate::cursor::DndIcon;45
use crate::lock::Lock;56
use crate::scene::Draw;67
use crate::state::Input;@@ -37,15 +38,20 @@ pub fn compose(
3738
cursor: bool,3839
) -> Vec<Draw> {3940
let mut elements = Vec::new();40
- if cursor && let Some(area) = ctx.wm.layout.output(o).map(|out| out.area) {41
+ if let Some(area) = ctx.wm.layout.output(o).map(|out| out.area) {4142
let pos = ctx.input.pointer_pos;4243
if area.contains(pos.x, pos.y) {4344
let local = pos - Point::from((area.x, area.y));44
- elements.extend(ctx.input.cursor.elements(45
- ctx.renderer,46
- &ctx.input.cursor_status,47
- local,48
- ));45
+ if cursor {46
+ elements.extend(ctx.input.cursor.elements(47
+ ctx.renderer,48
+ &ctx.input.cursor_status,49
+ local,50
+ ));51
+ }52
+ if let Some(icon) = &ctx.input.dnd_icon {53
+ elements.extend(icon.elements(ctx.renderer, local));54
+ }4955
}5056
}5157
match crate::lock::elements(ctx.lock, ctx.renderer, output) {@@ -75,7 +81,17 @@ pub fn send_frame_callbacks(
7581
output: &Output,7682
now: u64,7783
elapsed: Duration,84
+ dnd_icon: Option<&DndIcon>,7885
) {86
+ if let Some(icon) = dnd_icon {87
+ send_frames_surface_tree(88
+ &icon.surface,89
+ output,90
+ elapsed,91
+ Some(Duration::ZERO),92
+ |_, _| Some(output.clone()),93
+ );94
+ }7995
if lock.active() {8096
crate::lock::send_frames(lock, output, elapsed);8197
return;@@ -265,6 +265,7 @@ pub fn render(state: &mut State) {
265265
&host.output,266266
now,267267
elapsed,268
+ input.dnd_icon.as_ref(),268269
);269270
if damage.is_some() {270271
captures.output_damaged(&host.output);@@ -1,10 +1,11 @@
1
+use crate::cursor::DndIcon;12
use crate::state::State;2
-use smithay::input::dnd::{DndGrabHandler, GrabType, Source};3
-use smithay::input::pointer::CursorImageStatus;3
+use smithay::input::dnd::{DnDGrab, DndGrabHandler, DndTarget, GrabType, Source};4
+use smithay::input::pointer::{CursorImageStatus, Focus};45
use smithay::input::{Seat, SeatHandler, SeatState};56
use smithay::reexports::wayland_server::Resource;67
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;7
-use smithay::utils::Serial;8
+use smithay::utils::{Logical, Point, Serial};89
use smithay::wayland::seat::WaylandFocus;910
use smithay::wayland::selection::data_device::{1011
DataDeviceHandler, DataDeviceState, WaylandDndGrabHandler, set_data_device_focus,@@ -103,7 +104,28 @@ impl smithay::wayland::selection::ext_data_control::DataControlHandler for State
103104
}104105
}105106
106
-impl DndGrabHandler for State {}107
+impl DndGrabHandler for State {108
+ fn dropped(109
+ &mut self,110
+ _target: Option<DndTarget<'_, Self>>,111
+ _validated: bool,112
+ _seat: Seat<Self>,113
+ _location: Point<f64, Logical>,114
+ ) {115
+ self.end_dnd();116
+ }117
+118
+ fn cancelled(&mut self, _seat: Seat<Self>, _location: Point<f64, Logical>) {119
+ self.end_dnd();120
+ }121
+}122
+123
+impl State {124
+ fn end_dnd(&mut self) {125
+ self.input.dnd_icon = None;126
+ self.dirty.redraw = true;127
+ }128
+}107129
108130
impl smithay::input::tablet::TabletSeatHandler for State {109131
type ToolFocus = WlSurface;@@ -113,12 +135,36 @@ impl WaylandDndGrabHandler for State {
113135
fn dnd_requested<S: Source>(114136
&mut self,115137
source: S,116
- _icon: Option<WlSurface>,117
- _seat: Seat<Self>,118
- _serial: Serial,119
- _type: GrabType,138
+ icon: Option<WlSurface>,139
+ seat: Seat<Self>,140
+ serial: Serial,141
+ type_: GrabType,120142
) {121
- source.cancel();143
+ self.input.dnd_icon = icon.map(|surface| DndIcon {144
+ surface,145
+ offset: Point::default(),146
+ });147
+ self.dirty.redraw = true;148
+ let dh = self.core.display.clone();149
+ match type_ {150
+ GrabType::Pointer => {151
+ let Some(start_data) = seat152
+ .get_pointer()153
+ .and_then(|pointer| pointer.grab_start_data())154
+ else {155
+ source.cancel();156
+ return self.end_dnd();157
+ };158
+ let grab = DnDGrab::new_pointer(&dh, start_data, source, seat.clone());159
+ if let Some(pointer) = seat.get_pointer() {160
+ pointer.set_grab(self, grab, serial, Focus::Keep);161
+ }162
+ }163
+ GrabType::Touch => {164
+ source.cancel();165
+ self.end_dnd();166
+ }167
+ }122168
}123169
}124170
@@ -59,6 +59,7 @@ pub struct Input {
5959
pub warping: bool,6060
pub cursor: crate::cursor::Cursor,6161
pub cursor_status: CursorImageStatus,62
+ pub dnd_icon: Option<crate::cursor::DndIcon>,6263
}6364
6465
/// What needs doing after this batch of events.@@ -189,6 +190,7 @@ impl State {
189190
warping: false,190191
cursor: crate::cursor::Cursor::load(),191192
cursor_status: CursorImageStatus::default_named(),193
+ dnd_icon: None,192194
},193195
dirty: Dirty {194196
redraw: true,