a73x

e0e1171e

main: widen computePollTimeoutMs to accept a second deadline

a73x   2026-04-19 07:00

Commit message
main: widen computePollTimeoutMs to accept a second deadline

Prep for cursor blink deadline. Call site still passes null for
the blink slot until the blink state machine lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

src/main.zig
Old New
@@ -341,7 +341,8 @@ fn runTerminal(alloc: std.mem.Allocator) !void {
341 341
342 while (!window.should_close and p.isChildAlive()) { 342 while (!window.should_close and p.isChildAlive()) {
343 const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs()); 343 const repeat_timeout_ms = remainingRepeatTimeoutMs(keyboard.nextRepeatDeadlineNs());
344 const timeout = computePollTimeoutMs(repeat_timeout_ms, render_pending); 344 // Blink deadline wired up in Task 4; null for now.
345 const timeout = computePollTimeoutMs(repeat_timeout_ms, null, render_pending);
345 try frame_loop.waitForWork(&pollfds_extra, timeout); 346 try frame_loop.waitForWork(&pollfds_extra, timeout);
346 347
347 // PTY output 348 // PTY output
@@ -788,9 +789,17 @@ fn remainingRepeatTimeoutMs(deadline_ns: ?i128) ?i32 {
788 return @intCast(@divTrunc(remaining_ns + std.time.ns_per_ms - 1, std.time.ns_per_ms)); 789 return @intCast(@divTrunc(remaining_ns + std.time.ns_per_ms - 1, std.time.ns_per_ms));
789 } 790 }
790 791
791 fn computePollTimeoutMs(next_repeat_in_ms: ?i32, render_pending: bool) i32 { 792 fn computePollTimeoutMs(
793 next_repeat_in_ms: ?i32,
794 next_blink_in_ms: ?i32,
795 render_pending: bool,
796 ) i32 {
792 if (render_pending) return 0; 797 if (render_pending) return 0;
793 return next_repeat_in_ms orelse -1; 798 if (next_repeat_in_ms) |r| {
799 if (next_blink_in_ms) |b| return if (r < b) r else b;
800 return r;
801 }
802 return next_blink_in_ms orelse -1;
794 } 803 }
795 804
796 fn extractSelectedText( 805 fn extractSelectedText(
@@ -1627,10 +1636,26 @@ fn mapKeysymToInputKey(keysym: u32) ?vt.InputKey {
1627 }; 1636 };
1628 } 1637 }
1629 1638
1630 test "event loop waits indefinitely when idle and wakes for imminent repeat" { 1639 test "computePollTimeoutMs: idle with no deadlines returns -1" {
1631 try std.testing.expectEqual(@as(i32, -1), computePollTimeoutMs(null, false)); 1640 try std.testing.expectEqual(@as(i32, -1), computePollTimeoutMs(null, null, false));
1632 try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(5, true)); 1641 }
1633 try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(17, false)); 1642
1643 test "computePollTimeoutMs: render_pending forces zero regardless of deadlines" {
1644 try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(5, null, true));
1645 try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(null, 5, true));
1646 try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(3, 7, true));
1647 try std.testing.expectEqual(@as(i32, 0), computePollTimeoutMs(null, null, true));
1648 }
1649
1650 test "computePollTimeoutMs: single deadline passes through" {
1651 try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(17, null, false));
1652 try std.testing.expectEqual(@as(i32, 500), computePollTimeoutMs(null, 500, false));
1653 }
1654
1655 test "computePollTimeoutMs: returns min of two deadlines" {
1656 try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(17, 500, false));
1657 try std.testing.expectEqual(@as(i32, 17), computePollTimeoutMs(500, 17, false));
1658 try std.testing.expectEqual(@as(i32, 7), computePollTimeoutMs(7, 7, false));
1634 } 1659 }
1635 1660
1636 test "planRowRefresh requests full rebuild for full dirty state" { 1661 test "planRowRefresh requests full rebuild for full dirty state" {