From a3c657132674520de9f52de805057a598abfc5a2 Mon Sep 17 00:00:00 2001 From: Leon Henrik Plickat Date: Wed, 23 Jun 2021 15:56:38 +0200 Subject: [PATCH] cursor: reset state if needed on transaction commit A transaction may move the current target of a cursor action to a non-visible tag, make it fullscreen, or otherwise change things such that the current cursor state no longer makes sense. To handle this, check if we should reset cursor state every time a transaction is committed. --- river/Cursor.zig | 35 +++++++++++++++++++++++++++++++++++ river/Root.zig | 5 +++++ river/util.zig | 1 + 3 files changed, 41 insertions(+) diff --git a/river/Cursor.zig b/river/Cursor.zig index 5a09a88..dd1f51b 100644 --- a/river/Cursor.zig +++ b/river/Cursor.zig @@ -20,6 +20,7 @@ const Self = @This(); const build_options = @import("build_options"); const std = @import("std"); const assert = std.debug.assert; +const os = std.os; const math = std.math; const wlr = @import("wlroots"); const wayland = @import("wayland"); @@ -674,6 +675,40 @@ fn processMotion(self: *Self, device: *wlr.InputDevice, time: u32, delta_x: f64, } } +/// 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. +pub fn maybeResetState(self: *Self) void { + switch (self.mode) { + .passthrough => {}, + .down => |target| { + // If the target view is no longer visible, abort the operation. + if (target.current.tags & target.output.current.tags == 0) { + self.mode = .passthrough; + } + }, + .resize, .move => { + // If the target view is no longer visible, or now fullscreen or no + // longer floating, abort the operation. + const target = if (self.mode == .resize) self.mode.resize.view else self.mode.move; + if (target.current.tags & target.output.current.tags == 0 or + (!target.current.float and target.output.current.layout != null) or + target.current.fullscreen) + { + self.mode = .passthrough; + } + }, + } + + if (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 + + @divFloor(now.tv_nsec, std.time.ns_per_ms)); + self.passthrough(msec); + } +} + /// Pass an event on to the surface under the cursor, if any. fn passthrough(self: *Self, time: u32) void { assert(self.mode == .passthrough); diff --git a/river/Root.zig b/river/Root.zig index aad7541..b51abed 100644 --- a/river/Root.zig +++ b/river/Root.zig @@ -405,6 +405,11 @@ fn commitTransaction(self: *Self) void { output.damage.addWhole(); } + + var seat_it = server.input_manager.seats.first; + while (seat_it) |seat_node| : (seat_it = seat_node.next) { + seat_node.data.cursor.maybeResetState(); + } } /// Send the new output configuration to all wlr-output-manager clients diff --git a/river/util.zig b/river/util.zig index d28122c..ceeea07 100644 --- a/river/util.zig +++ b/river/util.zig @@ -16,6 +16,7 @@ // along with this program. If not, see . const std = @import("std"); +const os = std.os; /// The global general-purpose allocator used throughout river's code pub const gpa = std.heap.c_allocator;