diff --git a/src/dnd.rs b/src/dnd.rs index f0d2630..97e48a8 100644 --- a/src/dnd.rs +++ b/src/dnd.rs @@ -56,6 +56,14 @@ pub enum AfterDrag { SlideOut, } +/// During a real drag the compositor owns the pointer and the origin gets +/// no button events. A release that reaches the dragged thumbnail means the +/// compositor never took the drag over (e.g. a flick released before the +/// drag started), so valw has to end it itself. +pub fn release_ends_drag(dragged: Option, released_on: u64) -> bool { + dragged == Some(released_on) +} + /// `expired`: the thumbnail's timer fired while it was being dragged. pub fn after_drag(outcome: Outcome, expired: bool) -> AfterDrag { match (outcome, expired) { @@ -142,6 +150,13 @@ mod tests { assert!(through_pipe("text/html", Path::new("/tmp/a.png")).is_err()); } + #[test] + fn a_release_on_the_dragged_thumbnail_ends_the_drag() { + assert!(release_ends_drag(Some(3), 3)); + assert!(!release_ends_drag(Some(3), 4), "another thumbnail"); + assert!(!release_ends_drag(None, 3), "no drag going on"); + } + #[test] fn after_drag_decisions() { assert_eq!(after_drag(Outcome::Dropped, false), AfterDrag::Close); diff --git a/src/host.rs b/src/host.rs index 488f761..86be708 100644 --- a/src/host.rs +++ b/src/host.rs @@ -302,6 +302,10 @@ impl Host { let Some(drag) = self.drag.take_if(|d| d.source.inner() == source) else { return; }; + self.finish_drag(drag, outcome, qh); + } + + fn finish_drag(&mut self, drag: Drag, outcome: Outcome, qh: &QueueHandle) { tracing::info!("drag-out {outcome:?}"); drag.icon_viewport.destroy(); drag.icon.destroy(); @@ -361,6 +365,13 @@ pub fn pointer(state: &mut State, events: &[PointerEvent], qh: &QueueHandle { + let dragged = host.drag.as_ref().map(|d| d.thumb); + if dnd::release_ends_drag(dragged, host.thumbs[i].id) { + tracing::info!("the compositor never took the drag over"); + let drag = host.drag.take().expect("checked above"); + host.finish_drag(drag, Outcome::Cancelled, qh); + continue; + } let t = &mut host.thumbs[i]; if t.release(x, y, qh) == Some(Action::OpenEditor) { open_editor(&t.path);