GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
fix(context): self-heal a stale drag grab on the next fresh press
If a button release never reaches the app (eaten compositor-side or
lost to a focus change), active_grab stayed armed forever and every
subsequent mouse event was redirected to the stale drag target — the
entire UI stopped responding until restart. A fresh press at a new
position now ends the stale drag (DragEnd to the old target) and drops
the grab before dispatching normally.
Co-Authored-By: Claude Fable 5 <[email protected]>
src/context.rs | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/context.rs b/src/context.rs
index b183a80..952792f 100644
--- a/src/context.rs
+++ b/src/context.rs
@@ -194,6 +194,20 @@ impl UiContext {
// its first move. drag_start_pos is cleared on release, so an
// equal position here means "same press, next root".
if self.drag_start_pos != Some((*x, *y)) {
+ // A fresh press while a grab is still armed means the
+ // release never arrived (lost to a focus change or eaten
+ // compositor-side). End the stale drag and drop the grab —
+ // otherwise active_grab redirects every event to the old
+ // target forever and the whole UI stops responding.
+ if self.active_grab.is_some() {
+ if self.is_dragging {
+ if let Some(target_ptr) = self.drag_target.and_then(|id| self.tree.get_ptr(id)) {
+ (*target_ptr).handle_event(&Event::DragEnd, self);
+ (*target_ptr).mark_dirty(self);
+ }
+ }
+ self.active_grab = None;
+ }
self.drag_start_pos = Some((*x, *y));
self.is_dragging = false;
self.drag_target = None;