diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-29 08:17:38 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-10-01 00:12:16 -0300 |
| commit | 6f7c79650857da578b9e6f8c49c772eb7c40bcae (patch) | |
| tree | d5e9dcfe134f67d497dfbb4b31a64811b1f6d345 /src/look.zig | |
| parent | ab668719385c94df3e274f71cb744f5917c1da7e (diff) | |
| download | pardes-6f7c79650857da578b9e6f8c49c772eb7c40bcae.tar.gz pardes-6f7c79650857da578b9e6f8c49c772eb7c40bcae.zip | |
GUI goldens settle on the window's idle, not two captures that agree
test/gui_golden.py hashed a scene once two captures 400 ms apart agreed;
on a loaded machine a slow frame agreed with itself before the scene's
change landed and every later hash moved up a scene. A test window now
writes a status file into its capture directory each loop step (gui.zig
writeTestStatus: step, frames captured, idle — nothing owes a frame,
nothing moves, nothing waits on the core's clock), and the harness waits
for an idle step two past the one current when it asks: a 9P write has
been served by then, so the frame is the scene's. Two things kept a
window from ever going idle, both fixed:
- Look-hover re-armed forever: resting on a word with nothing to open, the
hover wait ran its two frames, found nothing, cancelled, and the next
present's pointer refresh started it again: a frame every other frame
for as long as the pointer rested there, live too (CPU). The place last
refused is remembered (Pardes.look_hover_refused) until the pointer
moves off it.
- The virtual clock moved only on a wait that timed out, so a steady
trickle of events held it still; it now moves to the core's wake too
when an event cut the wait short and nothing owes a frame.
Captures go to a directory of their own, outside the session's (a file
written there every frame is a change in the directory its panes look
at). All 17 goldens match the file as recorded at oooopqyv; eight runs,
five alongside a ReleaseFast build and three with all 16 cores saturated
(load 13-19), were byte-identical, 14 s a run unloaded (was ~30).
Tests: the resting pointer lets the core go idle.
Diffstat (limited to 'src/look.zig')
| -rw-r--r-- | src/look.zig | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/src/look.zig b/src/look.zig index 4ee5a638..39f7420e 100644 --- a/src/look.zig +++ b/src/look.zig @@ -934,6 +934,12 @@ fn noteLookHover(p: *Pardes, col: u16, row: u16, body_hit: ?Mouse.BodyHit, tag_h if (p.look_hover_wait) |waiting| if (waiting.col == col and waiting.row == row and waiting.pane == id and waiting.serial == pane.serial and mouse.sameBodyCell(waiting.body_hit, body_hit) and tag_layer.sameCell(waiting.tag_hit, tag_hit)) return; + // Found nothing to open here a moment ago: the pointer resting on it + // does not start another wait (and another frame) every frame. + if (p.look_hover_refused) |refused| + if (refused.col == col and refused.row == row and refused.pane == id and refused.serial == pane.serial and mouse.sameBodyCell(refused.body_hit, body_hit) and tag_layer.sameCell(refused.tag_hit, tag_hit)) return; + p.look_hover_refused = null; + cancelLookHover(p); p.look_hover_wait = .{ .col = col, .row = row, .pane = id, .serial = pane.serial, .body_hit = body_hit, .tag_hit = tag_hit }; } @@ -958,8 +964,10 @@ pub fn advanceLookHover(p: *Pardes) void { if (waiting.frames < delay) return; const pane = p.panes[waiting.pane] orelse return cancelLookHover(p); if (pane.serial != waiting.serial) return cancelLookHover(p); - const pointed = edit.pointerTextSelection(p, waiting.pane, waiting.col, waiting.row, waiting.body_hit, waiting.tag_hit) orelse + const pointed = edit.pointerTextSelection(p, waiting.pane, waiting.col, waiting.row, waiting.body_hit, waiting.tag_hit) orelse { + p.look_hover_refused = waiting.*; return cancelLookHover(p); + }; if (comptime pdf_enabled) if (!pointed.on_tag and panes.Pdf.paneNativeReady(p, pane)) { const probe = panes.Pdf.probeAt(p, pane, waiting.col, waiting.row) orelse return cancelLookHover(p); @@ -976,7 +984,10 @@ pub fn advanceLookHover(p: *Pardes) void { return; }; const operand = exec.pointerOperand(p, pane, pointed.sel); - if (operand.text == null or operand.text.?.len == 0) return cancelLookHover(p); + if (operand.text == null or operand.text.?.len == 0) { + p.look_hover_refused = waiting.*; + return cancelLookHover(p); + } var preview = operand.preview; if (preview) |*sel| sel.state = .done; p.look_hover_preview = .{ @@ -1727,3 +1738,21 @@ test "Look ignores missing and out of bounds pane addresses" { try std.testing.expect(pane.body.vsel.active); // a miss changes nothing, the selection included } } + +test "a pointer resting where a look-hover found nothing does not wake the core every frame" { + const p = try Pardes.init(std.testing.allocator, .{ .cols = 80, .rows = 24 }); + defer p.deinit(); + _ = try p.setTestFile(" \n" ** 30); + p.sync(); + const r = p.rects[p.active]; + // Resting on blanks in the body: a wait, then nothing to open. + p.update(.{ .mouse = .{ .button = .none, .kind = .motion, .col = r.x + 20, .row = r.y + 5 } }); + var frames: usize = 0; + while (p.nextWake() != null and frames < 20) : (frames += 1) { + p.update(.tick); + // What a shell's present does after every frame. + p.acknowledgePanelPresentation(&.{}); + } + try std.testing.expect(frames < 20); + try std.testing.expect(p.look_hover_wait == null and p.look_hover_preview == null); +} |
