summaryrefslogtreecommitdiff
path: root/src/draw.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-10-01 13:14:00 -0300
committerGabriel Schneider <[email protected]>2026-10-01 13:44:34 -0300
commit7c84ebe66494c3b05dcd23f198b5c5f4189cb708 (patch)
tree83e38912052956bbd3c45f210d4806467637b702 /src/draw.zig
parentd19cce311a827e7fb176ecc35cb0a49f2bc6899f (diff)
downloadpardes-7c84ebe66494c3b05dcd23f198b5c5f4189cb708.tar.gz
pardes-7c84ebe66494c3b05dcd23f198b5c5f4189cb708.zip
A window whose focus moves to a PDF or picture while the cursor glides goes idle: the glide stops instead of holding frames for ever
glideCursor returned early when no cursor was drawn, so a glide under way (right-click a PDF from a tag: the cursor sets off for the new pane) was never stepped again and cursor_glide.moving() kept continuous() true: the GUI redrew at full rate, every frame, until focus came back to a cursor. With no cursor drawn the glide is now dropped; the next cursor lands. A pixel shell's only: the terminal has no cursor glide. Co-Authored-By: Claude Opus 5.5 <[email protected]>
Diffstat (limited to 'src/draw.zig')
-rw-r--r--src/draw.zig39
1 files changed, 38 insertions, 1 deletions
diff --git a/src/draw.zig b/src/draw.zig
index 0ea0b35e..9fcbb15f 100644
--- a/src/draw.zig
+++ b/src/draw.zig
@@ -225,7 +225,15 @@ fn glideCursor(p: *Pardes, s: *Surface) void {
s.chrome.cursor_alpha = 1;
s.chrome.cursor_idle_ms = std.math.maxInt(u32);
if (!builtins.capabilities.lift) return;
- const box = focusedCursorBox(p, s) orelse return;
+ const box = focusedCursorBox(p, s) orelse {
+ // No cursor drawn (a PDF or picture took focus, a program hid its
+ // own): a glide under way has nowhere to land, and its springs,
+ // never stepped again, held continuous() and the frames on for
+ // ever. It stops; the next cursor lands where it is.
+ p.cursor_glide = .{};
+ p.cursor_crossing = false;
+ return;
+ };
const motion = animation.Motion.of(p.settings.motion);
var snap = if (s.cursor) |cursor| cursor.bar else false;
var frame: PaneFrame = .{};
@@ -2341,6 +2349,35 @@ test "focus moved to another column glides from where the cursor was drawn" {
try std.testing.expect(!p.cursor_glide.moving() and !p.cursor_crossing);
}
+test "focus moving to a pane with no cursor while the cursor glides lets the session go idle" {
+ if (!builtins.capabilities.lift) return error.SkipZigTest;
+ const p = try Pardes.init(std.testing.allocator, .{ .cols = 120, .rows = 20 });
+ defer p.deinit();
+ var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
+ defer arena.deinit();
+ p.settings.motion = .smooth;
+ try twoColumns(p, &arena);
+ p.active = 0;
+ p.advance(3 * std.time.ns_per_s);
+ _ = arena.reset(.retain_capacity);
+ _ = try p.render(arena.allocator());
+ p.active = 1;
+ _ = arena.reset(.retain_capacity);
+ _ = try p.render(arena.allocator());
+ try std.testing.expect(p.cursor_glide.moving());
+ // Mid-glide, the pane focused draws no cursor (as a PDF pane does).
+ p.panes[1].?.body.mode = .tty;
+ p.update(.{ .output = .{ .pane = 1, .bytes = "\x1b[?25l" } });
+ p.advance(3 * std.time.ns_per_s + 20 * std.time.ns_per_ms);
+ _ = arena.reset(.retain_capacity);
+ const hidden = try p.render(arena.allocator());
+ try std.testing.expect(hidden.cursor == null);
+ p.advance(5 * std.time.ns_per_s);
+ _ = arena.reset(.retain_capacity);
+ _ = try p.render(arena.allocator());
+ try std.testing.expect(!p.cursor_glide.moving() and !p.continuous());
+}
+
test "a pane focus reaches brightens on the same spring the one it leaves dims on, and Motion off snaps" {
if (!builtins.capabilities.lift) return error.SkipZigTest;
const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 });