diff options
| author | Isaac Freund <mail@isaacfreund.com> | 2023-03-14 12:43:59 +0100 |
|---|---|---|
| committer | Isaac Freund <mail@isaacfreund.com> | 2023-03-14 13:34:55 +0100 |
| commit | a679743fa0f926ebd392b53fad260a74ecb1a9a9 (patch) | |
| tree | c51d45ebf4c385b0f861d976aa065fa6caa97277 | |
| parent | 9db41115a8a2f5a8973d52a440562a9cd81ffcba (diff) | |
| download | river-a679743fa0f926ebd392b53fad260a74ecb1a9a9.tar.gz river-a679743fa0f926ebd392b53fad260a74ecb1a9a9.tar.xz | |
Cursor: lock to current geometry during move/resize
This eliminates cursor jitter entirely during interactive resize.
This also fixes a bug where the xdg-toplevel resizing state was not
cleared if a resize operation was aborted due to a change in view tags
or similar.
| -rw-r--r-- | river/Cursor.zig | 75 | ||||
| -rw-r--r-- | river/Root.zig | 22 |
2 files changed, 47 insertions, 50 deletions
diff --git a/river/Cursor.zig b/river/Cursor.zig index d7497f9..c584556 100644 --- a/river/Cursor.zig +++ b/river/Cursor.zig @@ -861,12 +861,6 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64, const view = data.view; view.pending.move(@floatToInt(i32, dx), @floatToInt(i32, dy)); - self.wlr_cursor.warpClosest( - device, - @intToFloat(f64, data.offset_x + view.pending.box.x), - @intToFloat(f64, data.offset_y + view.pending.box.y), - ); - server.root.applyPending(); }, .resize => |*data| { @@ -915,17 +909,6 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64, } } - { - // Keep cursor locked to the original offset from the resize edges - const box = &data.view.pending.box; - const off_x = data.offset_x; - const off_y = data.offset_y; - const cursor_x = if (data.edges.left) off_x + box.x else box.x + box.width - off_x; - const cursor_y = if (data.edges.top) off_y + box.y else box.y + box.height - off_y; - - self.wlr_cursor.warpClosest(device, @intToFloat(f64, cursor_x), @intToFloat(f64, cursor_y)); - } - server.root.applyPending(); }, } @@ -979,42 +962,34 @@ pub fn updateState(self: *Self) void { constraint.updateState(); } - if (self.shouldPassthrough()) { - self.mode = .passthrough; - var now: os.timespec = undefined; - os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); - const msec = @intCast(u32, now.tv_sec * std.time.ms_per_s + - @divTrunc(now.tv_nsec, std.time.ns_per_ms)); - self.passthrough(msec); - } -} - -fn shouldPassthrough(self: Self) bool { - // We clear focus on hiding the cursor and should not re-focus until the cursor is moved - // and shown again. - if (self.hidden) return false; - switch (self.mode) { .passthrough => { - // If we are not currently in down/resize/move mode, we *always* need to passthrough() - // as what is under the cursor may have changed and we are not locked to a single - // target view. - return true; - }, - .down => { - // TODO: It's hard to determine from the target surface alone whether - // the surface is visible or not currently. Switching to the wlroots - // scene graph will fix this, but for now just don't bother. - return false; + if (!self.hidden) { + var now: os.timespec = undefined; + os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported"); + const msec = @intCast(u32, now.tv_sec * std.time.ms_per_s + + @divTrunc(now.tv_nsec, std.time.ns_per_ms)); + self.passthrough(msec); + } }, - .resize, .move => { - assert(server.lock_manager.state != .locked); - const target = if (self.mode == .resize) self.mode.resize.view else self.mode.move.view; - // The target view is no longer visible, is part of the layout, or is fullscreen. - return target.current.output == null or - target.current.tags & target.current.output.?.current.tags == 0 or - (!target.current.float and target.current.output.?.layout != null) or - target.current.fullscreen; + // TODO: Leave down mode if the target surface is no longer visible. + .down => assert(!self.hidden), + inline .move, .resize => |data, mode| { + assert(!self.hidden); + + // These conditions are checked in Root.applyPending() + assert(data.view.current.tags & data.view.current.output.?.current.tags != 0); + assert(data.view.current.float or data.view.current.output.?.layout == null); + assert(!data.view.current.fullscreen); + + // Keep the cursor locked to the original offset from the edges of the view. + const box = &data.view.current.box; + const dx = data.offset_x; + const dy = data.offset_y; + const lx = if (mode == .move or data.edges.left) dx + box.x else box.x + box.width - dx; + const ly = if (mode == .move or data.edges.top) dy + box.y else box.y + box.height - dy; + + self.wlr_cursor.warpClosest(null, @intToFloat(f64, lx), @intToFloat(f64, ly)); }, } } diff --git a/river/Root.zig b/river/Root.zig index 92685eb..b90c52a 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -493,6 +493,28 @@ pub fn applyPending(root: *Self) void { } } + { + var it = server.input_manager.seats.first; + while (it) |node| : (it = node.next) { + const cursor = &node.data.cursor; + + switch (cursor.mode) { + .passthrough, .down => {}, + inline .move, .resize => |data| { + if (data.view.inflight.output == null or + data.view.inflight.tags & data.view.inflight.output.?.inflight.tags == 0 or + (!data.view.inflight.float and data.view.inflight.output.?.layout != null) or + data.view.inflight.fullscreen) + { + cursor.mode = .passthrough; + data.view.pending.resizing = false; + data.view.inflight.resizing = false; + } + }, + } + } + } + if (root.inflight_layout_demands == 0) { root.sendConfigures(); } |
