Cursor: fix move/resize with high poll rate/low dpi mice

This commit is contained in:
Isaac Freund 2021-10-30 19:16:31 +02:00
parent 4b0c5acc46
commit 8134b81283
No known key found for this signature in database
GPG key ID: 86DED400DDFD7A11

View file

@ -43,9 +43,21 @@ const XwaylandUnmanaged = @import("XwaylandUnmanaged.zig");
const Mode = union(enum) {
passthrough: void,
down: *View,
move: *View,
move: struct {
view: *View,
/// View coordinates are stored as i32s as they are in logical pixels.
/// However, it is possible to move the cursor by a fraction of a
/// logical pixel and this happens in practice with low dpi, high
/// polling rate mice. Therefore we must accumulate the current
/// fractional offset of the mouse to avoid rounding down tiny
/// motions to 0.
delta_x: f64 = 0,
delta_y: f64 = 0,
},
resize: struct {
view: *View,
delta_x: f64 = 0,
delta_y: f64 = 0,
/// Offset from the lower right corner of the view
offset_x: i32,
offset_y: i32,
@ -184,7 +196,7 @@ pub fn handleViewUnmap(self: *Self, view: *View) void {
if (switch (self.mode) {
.passthrough => false,
.down => |target_view| target_view == view,
.move => |target_view| target_view == view,
.move => |data| data.view == view,
.resize => |data| data.view == view,
}) {
self.mode = .passthrough;
@ -649,7 +661,7 @@ pub fn enterMode(self: *Self, mode: std.meta.Tag((Mode)), view: *View) void {
.move, .resize => {
switch (mode) {
.passthrough, .down => unreachable,
.move => self.mode = .{ .move = view },
.move => self.mode = .{ .move = .{ .view = view } },
.resize => {
const cur_box = &view.current.box;
self.mode = .{ .resize = .{
@ -768,8 +780,14 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64,
self.wlr_cursor.y - @intToFloat(f64, output_box.y + view.current.box.y - view.surface_box.y),
);
},
.move => |view| {
view.move(@floatToInt(i32, delta_x), @floatToInt(i32, delta_y));
.move => |*data| {
dx += data.delta_x;
dy += data.delta_y;
data.delta_x = dx - @trunc(dx);
data.delta_y = dy - @trunc(dy);
const view = data.view;
view.move(@floatToInt(i32, dx), @floatToInt(i32, dy));
self.wlr_cursor.move(
device,
@intToFloat(f64, view.pending.box.x - view.current.box.x),
@ -777,13 +795,18 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64,
);
view.applyPending();
},
.resize => |data| {
.resize => |*data| {
dx += data.delta_x;
dy += data.delta_y;
data.delta_x = dx - @trunc(dx);
data.delta_y = dy - @trunc(dy);
const border_width = if (data.view.draw_borders) server.config.border_width else 0;
// Set width/height of view, clamp to view size constraints and output dimensions
const box = &data.view.pending.box;
box.width = @intCast(u32, math.max(0, @intCast(i32, box.width) + @floatToInt(i32, delta_x)));
box.height = @intCast(u32, math.max(0, @intCast(i32, box.height) + @floatToInt(i32, delta_y)));
box.width = @intCast(u32, math.max(0, @intCast(i32, box.width) + @floatToInt(i32, dx)));
box.height = @intCast(u32, math.max(0, @intCast(i32, box.height) + @floatToInt(i32, dy)));
data.view.applyConstraints();
@ -830,7 +853,7 @@ fn shouldPassthrough(self: Self) bool {
return target.current.tags & target.output.current.tags == 0;
},
.resize, .move => {
const target = if (self.mode == .resize) self.mode.resize.view else self.mode.move;
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.tags & target.output.current.tags == 0 or
(!target.current.float and target.output.current.layout != null) or