From 38822d66b8736dc120548671c02d3fa99eaab5b2 Mon Sep 17 00:00:00 2001 From: Gregor Lohaus Date: Sun, 31 May 2026 17:51:53 +0200 Subject: [PATCH] Fixed the partial-dirty blanking regression --- .../jprototerm/GhosttyTerminalRenderer.java | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/gregor/jprototerm/GhosttyTerminalRenderer.java b/src/main/java/com/gregor/jprototerm/GhosttyTerminalRenderer.java index 088dc47..f84709a 100644 --- a/src/main/java/com/gregor/jprototerm/GhosttyTerminalRenderer.java +++ b/src/main/java/com/gregor/jprototerm/GhosttyTerminalRenderer.java @@ -679,18 +679,21 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { private PixelBuffer pixelBuffer; private WritableImage image; private long[] rowHashes = new long[0]; + private boolean[] paintedRows = new boolean[0]; private CursorState lastCursor = CursorState.none(); private GlyphCache glyphs; private boolean valid; private void invalidate() { rowHashes = new long[0]; + paintedRows = new boolean[0]; lastCursor = CursorState.none(); valid = false; } private boolean canPaintDirty(RenderStateSnapshot snapshot) { - return valid && snapshot != null && rowHashes.length == snapshot.rows(); + return valid && snapshot != null && rowHashes.length == snapshot.rows() + && paintedRows.length == snapshot.rows() && allRowsPainted(); } private void paintFull(GraphicsContext gc, RenderStateSnapshot snapshot, @@ -698,10 +701,11 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { ensure(paneWidth, paneHeight); fillRect(0, 0, width, height, argbPre(PANE_BACKGROUND)); if (snapshot != null) { + prepareRows(snapshot.rows()); paintSnapshot(snapshot); drawCursor(snapshot); rememberSnapshot(snapshot); - valid = true; + valid = allRowsPainted(); } else { invalidate(); } @@ -722,6 +726,7 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { if (scroll != 0) { scrollContentPixels(scroll); scrollHashes(scroll); + scrollPaintedRows(scroll); } CursorState cursor = CursorState.from(snapshot); @@ -739,7 +744,7 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { } } lastCursor = cursor; - valid = true; + valid = allRowsPainted(); drawCursor(snapshot); drawBorder(active); present(gc, px, py); @@ -771,7 +776,7 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { } repaintCursorRow(snapshot, newCursorRow, repainted); lastCursor = cursor; - valid = true; + valid = allRowsPainted(); drawCursor(snapshot); drawBorder(active); present(gc, px, py); @@ -831,12 +836,12 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { } private boolean canDiff(RenderStateSnapshot snapshot) { - return rowHashes.length == snapshot.rows() && snapshot.renderRows().size() == snapshot.rows(); + return canPaintDirty(snapshot) && snapshot.renderRows().size() == snapshot.rows(); } private void rememberSnapshot(RenderStateSnapshot snapshot) { if (rowHashes.length != snapshot.rows()) { - rowHashes = new long[snapshot.rows()]; + prepareRows(snapshot.rows()); } for (RenderRow row : snapshot.renderRows()) { rowHashes[row.row()] = rowHash(row); @@ -900,6 +905,17 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { rowHashes = shifted; } + private void scrollPaintedRows(int rows) { + boolean[] shifted = new boolean[paintedRows.length]; + for (int row = 0; row < shifted.length; row++) { + int previous = row - rows; + if (previous >= 0 && previous < paintedRows.length) { + shifted[row] = paintedRows[previous]; + } + } + paintedRows = shifted; + } + private void scrollContentPixels(int rows) { int dy = rows * lineHeight(); int top = contentTop(); @@ -956,6 +972,30 @@ final class GhosttyTerminalRenderer extends TerminalRenderer { paintRowSidePadding(row, rowTop, rowHeight); paintRowBackgrounds(row, rowTop, rowHeight); paintRowText(row, rowTop); + markPainted(row.row()); + } + + private void prepareRows(int rows) { + rowHashes = new long[rows]; + paintedRows = new boolean[rows]; + } + + private void markPainted(int row) { + if (row >= 0 && row < paintedRows.length) { + paintedRows[row] = true; + } + } + + private boolean allRowsPainted() { + if (paintedRows.length == 0) { + return false; + } + for (boolean painted : paintedRows) { + if (!painted) { + return false; + } + } + return true; } private void paintRowSidePadding(RenderRow row, int rowTop, int rowHeight) {