Cursor: add workaround in pointer drag termination

Currently wlroots sends use the drag destroy event before sending the
wl_data_device.leave event to the client, which makes things a bit
awkward. My patch fixing this has been merged to wlroots master so we
can remove this when upgrading to wlroots 0.15, but until then this
workaround will fix the issue.
This commit is contained in:
Isaac Freund 2021-11-23 22:51:29 +01:00
parent 9212ac89fa
commit bd70c010e9
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
2 changed files with 23 additions and 2 deletions

2
deps/zig-wayland vendored

@ -1 +1 @@
Subproject commit a8e1efcfd34ac798f19d8a62ebe3bb368c17f585 Subproject commit 38b5de89b3e3de670bb2496de56e5173d626fad5

View File

@ -84,6 +84,7 @@ status_trackers: std.SinglyLinkedList(SeatStatus) = .{},
/// True if a pointer drag is currently in progress /// True if a pointer drag is currently in progress
pointer_drag: bool = false, pointer_drag: bool = false,
pointer_drag_idle_source: ?*wl.EventSource = null,
request_set_selection: wl.Listener(*wlr.Seat.event.RequestSetSelection) = request_set_selection: wl.Listener(*wlr.Seat.event.RequestSetSelection) =
wl.Listener(*wlr.Seat.event.RequestSetSelection).init(handleRequestSetSelection), wl.Listener(*wlr.Seat.event.RequestSetSelection).init(handleRequestSetSelection),
@ -128,6 +129,8 @@ pub fn deinit(self: *Self) void {
self.focus_stack.remove(node); self.focus_stack.remove(node);
util.gpa.destroy(node); util.gpa.destroy(node);
} }
if (self.pointer_drag_idle_source) |idle_source| idle_source.remove();
} }
/// Set the current focus. If a visible view is passed it will be focused. /// Set the current focus. If a visible view is passed it will be focused.
@ -476,6 +479,7 @@ fn handleStartDrag(listener: *wl.Listener(*wlr.Drag), wlr_drag: *wlr.Drag) void
if (wlr_drag.icon) |wlr_drag_icon| { if (wlr_drag.icon) |wlr_drag_icon| {
const node = util.gpa.create(std.SinglyLinkedList(DragIcon).Node) catch { const node = util.gpa.create(std.SinglyLinkedList(DragIcon).Node) catch {
log.crit("out of memory", .{}); log.crit("out of memory", .{});
wlr_drag.seat_client.client.postNoMemory();
return; return;
}; };
node.data.init(self, wlr_drag_icon); node.data.init(self, wlr_drag_icon);
@ -486,8 +490,25 @@ fn handleStartDrag(listener: *wl.Listener(*wlr.Drag), wlr_drag: *wlr.Drag) void
fn handlePointerDragDestroy(listener: *wl.Listener(*wlr.Drag), wlr_drag: *wlr.Drag) void { fn handlePointerDragDestroy(listener: *wl.Listener(*wlr.Drag), wlr_drag: *wlr.Drag) void {
const self = @fieldParentPtr(Self, "pointer_drag_destroy", listener); const self = @fieldParentPtr(Self, "pointer_drag_destroy", listener);
self.pointer_drag = false;
self.pointer_drag_destroy.link.remove(); self.pointer_drag_destroy.link.remove();
// TODO(wlroots): wlroots 0.14 doesn't send the wl_data_device.leave event
// until after this signal has been emitted. Triggering a wl_pointer.enter
// before the wl_data_device.leave breaks clients, so use an idle event
// source as a workaround. This has been fixed on the wlroots master branch
// in commit c9ba9e82.
const event_loop = server.wl_server.getEventLoop();
assert(self.pointer_drag_idle_source == null);
self.pointer_drag_idle_source = event_loop.addIdle(*Self, finishPointerDragDestroy, self) catch {
log.crit("out of memory", .{});
wlr_drag.seat_client.client.postNoMemory();
return;
};
}
fn finishPointerDragDestroy(self: *Self) callconv(.C) void {
self.pointer_drag_idle_source = null;
self.pointer_drag = false;
self.cursor.checkFocusFollowsCursor(); self.cursor.checkFocusFollowsCursor();
self.cursor.updateState(); self.cursor.updateState();
} }