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:
parent
9db41115a8
commit
a679743fa0
@ -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;
|
||||
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);
|
||||
}
|
||||
},
|
||||
.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;
|
||||
},
|
||||
.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));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user