aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsaac Freund <mail@isaacfreund.com>2021-11-19 11:33:27 +0100
committerIsaac Freund <mail@isaacfreund.com>2021-11-19 11:33:27 +0100
commit9212ac89fa4c1a540798143a33dd3e331c31a76c (patch)
treee87f0291e017b6e1b11aed381b8cbaccb3d8e78f
parent0cbe2b9fc34f253ac86115c469eef46ad0387ecb (diff)
downloadriver-9212ac89fa4c1a540798143a33dd3e331c31a76c.tar.gz
river-9212ac89fa4c1a540798143a33dd3e331c31a76c.tar.xz
Cursor: fix pointer drags with focus-follows-cursor
-rw-r--r--river/Cursor.zig40
-rw-r--r--river/Seat.zig33
2 files changed, 50 insertions, 23 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig
index 17b752e..e67e7d5 100644
--- a/river/Cursor.zig
+++ b/river/Cursor.zig
@@ -750,24 +750,7 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64,
switch (self.mode) {
.passthrough => {
self.wlr_cursor.move(device, dx, dy);
-
- if (self.surfaceAt()) |result| {
- const focus_change = self.seat.wlr_seat.pointer_state.focused_surface != result.surface;
- if (server.config.focus_follows_cursor == .normal and focus_change) {
- switch (result.parent) {
- .view => |view| {
- if (self.seat.focused != .view or self.seat.focused.view != view) {
- self.seat.focusOutput(view.output);
- self.seat.focus(view);
- server.root.startTransaction();
- }
- },
- .layer_surface => {},
- .xwayland_unmanaged => assert(build_options.xwayland),
- }
- }
- }
-
+ self.checkFocusFollowsCursor();
self.passthrough(time);
},
.down => |view| {
@@ -826,6 +809,27 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64,
}
}
+pub fn checkFocusFollowsCursor(self: *Self) void {
+ // Don't do focus-follows-cursor if a drag is in progress as focus change can't occur
+ if (self.seat.pointer_drag) return;
+ if (server.config.focus_follows_cursor == .disabled) return;
+ if (self.surfaceAt()) |result| {
+ if (self.seat.wlr_seat.pointer_state.focused_surface != result.surface) {
+ switch (result.parent) {
+ .view => |view| {
+ if (self.seat.focused != .view or self.seat.focused.view != view) {
+ self.seat.focusOutput(view.output);
+ self.seat.focus(view);
+ server.root.startTransaction();
+ }
+ },
+ .layer_surface => {},
+ .xwayland_unmanaged => assert(build_options.xwayland),
+ }
+ }
+ }
+}
+
/// Handle potential change in location of views on the output, as well as
/// the target view of a cursor operation potentially being moved to a non-visible tag,
/// becoming fullscreen, etc.
diff --git a/river/Seat.zig b/river/Seat.zig
index 966263d..ad94fc8 100644
--- a/river/Seat.zig
+++ b/river/Seat.zig
@@ -19,6 +19,7 @@ const Self = @This();
const build_options = @import("build_options");
const std = @import("std");
+const assert = std.debug.assert;
const wlr = @import("wlroots");
const wl = @import("wayland").server.wl;
const xkb = @import("xkbcommon");
@@ -81,11 +82,15 @@ focus_stack: ViewStack(*View) = .{},
/// List of status tracking objects relaying changes to this seat to clients.
status_trackers: std.SinglyLinkedList(SeatStatus) = .{},
+/// True if a pointer drag is currently in progress
+pointer_drag: bool = false,
+
request_set_selection: wl.Listener(*wlr.Seat.event.RequestSetSelection) =
wl.Listener(*wlr.Seat.event.RequestSetSelection).init(handleRequestSetSelection),
request_start_drag: wl.Listener(*wlr.Seat.event.RequestStartDrag) =
wl.Listener(*wlr.Seat.event.RequestStartDrag).init(handleRequestStartDrag),
start_drag: wl.Listener(*wlr.Drag) = wl.Listener(*wlr.Drag).init(handleStartDrag),
+pointer_drag_destroy: wl.Listener(*wlr.Drag) = wl.Listener(*wlr.Drag).init(handlePointerDragDestroy),
request_set_primary_selection: wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection) =
wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection).init(handleRequestSetPrimarySelection),
@@ -443,7 +448,15 @@ fn handleRequestStartDrag(
const self = @fieldParentPtr(Self, "request_start_drag", listener);
if (!self.wlr_seat.validatePointerGrabSerial(event.origin, event.serial)) {
- log.debug("ignoring request to start drag, failed to validate serial {}", .{event.serial});
+ log.debug("ignoring request to start drag, " ++
+ "failed to validate pointer serial {}", .{event.serial});
+ if (event.drag.source) |source| source.destroy();
+ return;
+ }
+
+ if (self.pointer_drag) {
+ log.debug("ignoring request to start pointer drag, " ++
+ "another pointer drag is already in progress", .{});
if (event.drag.source) |source| source.destroy();
return;
}
@@ -452,12 +465,14 @@ fn handleRequestStartDrag(
self.wlr_seat.startPointerDrag(event.drag, event.serial);
}
-fn handleStartDrag(
- listener: *wl.Listener(*wlr.Drag),
- wlr_drag: *wlr.Drag,
-) void {
+fn handleStartDrag(listener: *wl.Listener(*wlr.Drag), wlr_drag: *wlr.Drag) void {
const self = @fieldParentPtr(Self, "start_drag", listener);
+ assert(wlr_drag.grab_type == .keyboard_pointer);
+
+ self.pointer_drag = true;
+ wlr_drag.events.destroy.add(&self.pointer_drag_destroy);
+
if (wlr_drag.icon) |wlr_drag_icon| {
const node = util.gpa.create(std.SinglyLinkedList(DragIcon).Node) catch {
log.crit("out of memory", .{});
@@ -469,6 +484,14 @@ fn handleStartDrag(
self.cursor.mode = .passthrough;
}
+fn handlePointerDragDestroy(listener: *wl.Listener(*wlr.Drag), wlr_drag: *wlr.Drag) void {
+ const self = @fieldParentPtr(Self, "pointer_drag_destroy", listener);
+ self.pointer_drag = false;
+ self.pointer_drag_destroy.link.remove();
+ self.cursor.checkFocusFollowsCursor();
+ self.cursor.updateState();
+}
+
fn handleRequestSetPrimarySelection(
listener: *wl.Listener(*wlr.Seat.event.RequestSetPrimarySelection),
event: *wlr.Seat.event.RequestSetPrimarySelection,