feat: add a mouse idle timer that clears hover state
This commit is contained in:
		
							parent
							
								
									50d47a73f2
								
							
						
					
					
						commit
						f53dc74e9d
					
				
					 1 changed files with 33 additions and 5 deletions
				
			
		| 
						 | 
				
			
			@ -53,9 +53,11 @@ no_sleep: bool = false,
 | 
			
		|||
final_exit: []const u8 = "normal",
 | 
			
		||||
render_pending: bool = false,
 | 
			
		||||
keepalive_timer: ?tp.Cancellable = null,
 | 
			
		||||
mouse_idle_timer: ?tp.Cancellable = null,
 | 
			
		||||
 | 
			
		||||
const keepalive = std.time.us_per_day * 365; // one year
 | 
			
		||||
const idle_frames = 0;
 | 
			
		||||
const mouse_idle_time_milliseconds = 3000;
 | 
			
		||||
 | 
			
		||||
const init_delay = 1; // ms
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -149,6 +151,11 @@ fn init_delayed(self: *Self) !void {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
fn deinit(self: *Self) void {
 | 
			
		||||
    if (self.mouse_idle_timer) |*t| {
 | 
			
		||||
        t.cancel() catch {};
 | 
			
		||||
        t.deinit();
 | 
			
		||||
        self.mouse_idle_timer = null;
 | 
			
		||||
    }
 | 
			
		||||
    if (self.keepalive_timer) |*t| {
 | 
			
		||||
        t.cancel() catch {};
 | 
			
		||||
        t.deinit();
 | 
			
		||||
| 
						 | 
				
			
			@ -174,6 +181,16 @@ fn listen_sigwinch(self: *Self) tp.result {
 | 
			
		|||
    self.sigwinch_signal = tp.signal.init(std.posix.SIG.WINCH, tp.message.fmt(.{"sigwinch"})) catch |e| return tp.exit_error(e, @errorReturnTrace());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn update_mouse_idle_timer(self: *Self) void {
 | 
			
		||||
    const delay = std.time.us_per_ms * @as(u64, mouse_idle_time_milliseconds);
 | 
			
		||||
    if (self.mouse_idle_timer) |*t| {
 | 
			
		||||
        t.cancel() catch {};
 | 
			
		||||
        t.deinit();
 | 
			
		||||
        self.mouse_idle_timer = null;
 | 
			
		||||
    }
 | 
			
		||||
    self.mouse_idle_timer = tp.self_pid().delay_send_cancellable(self.a, delay, .{"MOUSE_IDLE"}) catch return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn receive(self: *Self, from: tp.pid_ref, m: tp.message) tp.result {
 | 
			
		||||
    const frame = tracy.initZone(@src(), .{ .name = "tui" });
 | 
			
		||||
    defer frame.deinit();
 | 
			
		||||
| 
						 | 
				
			
			@ -300,6 +317,11 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
 | 
			
		|||
    if (try m.match(.{ "PRJ", tp.more })) // drop late project manager query responses
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (try m.match(.{"MOUSE_IDLE"})) {
 | 
			
		||||
        try self.clear_hover_focus();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return tp.unexpected(m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -380,6 +402,7 @@ fn dispatch_input(ctx: *anyopaque, cbor_msg: []const u8) void {
 | 
			
		|||
 | 
			
		||||
fn dispatch_mouse(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void {
 | 
			
		||||
    const self: *Self = @ptrCast(@alignCast(ctx));
 | 
			
		||||
    self.update_mouse_idle_timer();
 | 
			
		||||
    const m: tp.message = .{ .buf = cbor_msg };
 | 
			
		||||
    const from = tp.self_pid();
 | 
			
		||||
    self.unrendered_input_events_count += 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -390,6 +413,7 @@ fn dispatch_mouse(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) voi
 | 
			
		|||
 | 
			
		||||
fn dispatch_mouse_drag(ctx: *anyopaque, y: c_int, x: c_int, cbor_msg: []const u8) void {
 | 
			
		||||
    const self: *Self = @ptrCast(@alignCast(ctx));
 | 
			
		||||
    self.update_mouse_idle_timer();
 | 
			
		||||
    const m: tp.message = .{ .buf = cbor_msg };
 | 
			
		||||
    const from = tp.self_pid();
 | 
			
		||||
    self.unrendered_input_events_count += 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,15 +516,19 @@ fn send_mouse_drag(self: *Self, y: c_int, x: c_int, from: tp.pid_ref, m: tp.mess
 | 
			
		|||
            _ = try w.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", true }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (self.hover_focus) |h| {
 | 
			
		||||
            var buf: [256]u8 = undefined;
 | 
			
		||||
            _ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
 | 
			
		||||
        }
 | 
			
		||||
        self.hover_focus = null;
 | 
			
		||||
        try self.clear_hover_focus();
 | 
			
		||||
    }
 | 
			
		||||
    if (self.drag_source) |w| _ = try w.send(from, m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn clear_hover_focus(self: *Self) tp.result {
 | 
			
		||||
    if (self.hover_focus) |h| {
 | 
			
		||||
        var buf: [256]u8 = undefined;
 | 
			
		||||
        _ = try h.send(tp.self_pid(), tp.message.fmtbuf(&buf, .{ "H", false }) catch |e| return tp.exit_error(e, @errorReturnTrace()));
 | 
			
		||||
    }
 | 
			
		||||
    self.hover_focus = null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn save_config(self: *const Self) !void {
 | 
			
		||||
    try root.write_config(self.config, self.a);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue