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.
This commit is contained in:
Isaac Freund 2023-03-14 12:43:59 +01:00
parent 9db41115a8
commit a679743fa0
No known key found for this signature in database
GPG Key ID: 86DED400DDFD7A11
2 changed files with 47 additions and 50 deletions

View File

@ -861,12 +861,6 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64,
const view = data.view; const view = data.view;
view.pending.move(@floatToInt(i32, dx), @floatToInt(i32, dy)); 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(); server.root.applyPending();
}, },
.resize => |*data| { .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(); server.root.applyPending();
}, },
} }
@ -979,42 +962,34 @@ pub fn updateState(self: *Self) void {
constraint.updateState(); 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) { switch (self.mode) {
.passthrough => { .passthrough => {
// If we are not currently in down/resize/move mode, we *always* need to passthrough() if (!self.hidden) {
// as what is under the cursor may have changed and we are not locked to a single var now: os.timespec = undefined;
// target view. os.clock_gettime(os.CLOCK.MONOTONIC, &now) catch @panic("CLOCK_MONOTONIC not supported");
return true; const msec = @intCast(u32, now.tv_sec * std.time.ms_per_s +
@divTrunc(now.tv_nsec, std.time.ns_per_ms));
self.passthrough(msec);
}
}, },
.down => { // TODO: Leave down mode if the target surface is no longer visible.
// TODO: It's hard to determine from the target surface alone whether .down => assert(!self.hidden),
// the surface is visible or not currently. Switching to the wlroots inline .move, .resize => |data, mode| {
// scene graph will fix this, but for now just don't bother. assert(!self.hidden);
return false;
}, // These conditions are checked in Root.applyPending()
.resize, .move => { assert(data.view.current.tags & data.view.current.output.?.current.tags != 0);
assert(server.lock_manager.state != .locked); assert(data.view.current.float or data.view.current.output.?.layout == null);
const target = if (self.mode == .resize) self.mode.resize.view else self.mode.move.view; assert(!data.view.current.fullscreen);
// The target view is no longer visible, is part of the layout, or is fullscreen.
return target.current.output == null or // Keep the cursor locked to the original offset from the edges of the view.
target.current.tags & target.current.output.?.current.tags == 0 or const box = &data.view.current.box;
(!target.current.float and target.current.output.?.layout != null) or const dx = data.offset_x;
target.current.fullscreen; 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));
}, },
} }
} }

View File

@ -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) { if (root.inflight_layout_demands == 0) {
root.sendConfigures(); root.sendConfigures();
} }