mirror of
https://github.com/kovidgoyal/kitty.git
synced 2025-12-13 20:36:22 +01:00
Dont rewrap text in the alternate screen buffer
Avoids flicker during live resize with no resize_debounce_time. See https://github.com/kovidgoyal/kitty/discussions/9142 for discussion.
This commit is contained in:
@@ -174,6 +174,9 @@ Detailed list of changes
|
||||
- macOS: Fix closing an OS Window when another OS Window is minimized causing
|
||||
the minimized window to be un-minimized (:iss:`8913`)
|
||||
|
||||
- Do not rewrap the text in the alternate screen buffer. Avoids flicker during
|
||||
live resize with no :opt:`resize_debounce_time` (:disc:`9142`)
|
||||
|
||||
0.44.0 [2025-11-03]
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -311,3 +311,83 @@ resize_screen_buffers(LineBuf *lb, HistoryBuf *hb, index_type lines, index_type
|
||||
ans.ok = true;
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void
|
||||
nuke_in_line(CPUCell *cp, GPUCell *gp, index_type start, index_type x_limit) {
|
||||
for (index_type x = start; x < x_limit; x++) {
|
||||
cell_set_char(cp + x, 0); cp[x].is_multicell = false;
|
||||
clear_sprite_position(gp[x]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nuke_multicell_char_at(LineBuf *lb, index_type x_, index_type y_) {
|
||||
CPUCell *cp; GPUCell *gp;
|
||||
linebuf_init_cells(lb, y_, &cp, &gp);
|
||||
index_type num_lines_above = cp[x_].y;
|
||||
index_type y_max_limit = MIN(lb->ynum, y_ + cp[x_].scale - num_lines_above);
|
||||
while (cp[x_].x && x_ > 0) x_--;
|
||||
index_type x_limit = MIN(lb->xnum, x_ + mcd_x_limit(&cp[x_]));
|
||||
for (index_type y = y_; y < y_max_limit; y++) {
|
||||
linebuf_init_cells(lb, y, &cp, &gp);
|
||||
nuke_in_line(cp, gp, x_, x_limit);
|
||||
}
|
||||
for (int y = (int)y_ - 1; y > -1 && num_lines_above; y--, num_lines_above--) {
|
||||
linebuf_init_cells(lb, y, &cp, &gp);
|
||||
nuke_in_line(cp, gp, x_, x_limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ResizeResult
|
||||
resize_screen_buffer_without_rewrap(LineBuf *lb, index_type lines, index_type columns, TrackCursor *cursors) {
|
||||
ResizeResult ans = {0};
|
||||
ans.lb = alloc_linebuf(lines, columns, lb->text_cache);
|
||||
if (!ans.lb) return ans;
|
||||
Rewrap r = { .src = {.lb=lb},};
|
||||
exclude_empty_lines_at_bottom(&r);
|
||||
ans.num_content_lines_before = r.num_content_lines_before;
|
||||
ans.num_content_lines_after = MIN(lines, r.num_content_lines_before);
|
||||
|
||||
index_type xcommon = MIN(lb->xnum, ans.lb->xnum);
|
||||
for (index_type y = 0; y < ans.num_content_lines_after; y++) {
|
||||
linebuf_init_line(lb, y); linebuf_init_line(ans.lb, y);
|
||||
ans.lb->line_attrs[y] = lb->line_attrs[y]; ans.lb->line_attrs[y].has_dirty_text = true;
|
||||
memcpy(ans.lb->line->cpu_cells, lb->line->cpu_cells, xcommon * sizeof(lb->line->cpu_cells[0]));
|
||||
memcpy(ans.lb->line->gpu_cells, lb->line->gpu_cells, xcommon * sizeof(lb->line->gpu_cells[0]));
|
||||
if (xcommon > lb->line->xnum) {
|
||||
// extend the colors/styles of the last cell to edge
|
||||
GPUCell e = lb->line->gpu_cells[xcommon-1]; clear_sprite_position(e);
|
||||
for (index_type x = xcommon; x < ans.lb->line->xnum; x++) ans.lb->line->gpu_cells[x] = e;
|
||||
} else if (xcommon < lb->line->xnum) {
|
||||
// remove multicell chars that were split at the right edge
|
||||
index_type last_x = xcommon - 1;
|
||||
CPUCell *c = ans.lb->line->cpu_cells + last_x;
|
||||
if (c->is_multicell && c->x + 1u < mcd_x_limit(c)) {
|
||||
while (ans.lb->line->cpu_cells[last_x].x && last_x > 0) last_x--;
|
||||
nuke_in_line(ans.lb->line->cpu_cells, ans.lb->line->gpu_cells, last_x, ans.lb->line->xnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set bg color for extra lines at bottom
|
||||
if (ans.num_content_lines_before < lines) {
|
||||
linebuf_init_line(lb, lb->ynum-1); GPUCell *g = lb->line->gpu_cells;
|
||||
for (index_type y = ans.num_content_lines_after; y < ans.lb->ynum; y++) {
|
||||
linebuf_init_line(ans.lb, y);
|
||||
for (index_type x = 0; x < ans.lb->xnum; x++) ans.lb->line->gpu_cells[x].bg = g->bg;
|
||||
}
|
||||
} else if (ans.num_content_lines_after < ans.num_content_lines_before) {
|
||||
// delete multicell chars split at the bottom
|
||||
linebuf_init_line(ans.lb, ans.num_content_lines_after-1);
|
||||
for (index_type x = 0; x < ans.lb->xnum; x++) {
|
||||
CPUCell *c = ans.lb->line->cpu_cells + x;
|
||||
if (c->is_multicell && c->y < c->scale-1) nuke_multicell_char_at(ans.lb, x, ans.num_content_lines_after-1);
|
||||
}
|
||||
}
|
||||
for (TrackCursor *tc = cursors; !tc->is_sentinel; tc++) {
|
||||
tc->dest_x = MIN(tc->x, ans.lb->xnum-1);
|
||||
tc->dest_y = MIN(tc->y, ans.lb->ynum-1);
|
||||
}
|
||||
ans.ok = true;
|
||||
return ans;
|
||||
}
|
||||
|
||||
@@ -23,3 +23,5 @@ typedef struct ResizeResult {
|
||||
|
||||
ResizeResult
|
||||
resize_screen_buffers(LineBuf *lb, HistoryBuf *hb, index_type lines, index_type columns, ANSIBuf *as_ansi_buf, TrackCursor *cursors);
|
||||
ResizeResult
|
||||
resize_screen_buffer_without_rewrap(LineBuf *lb, index_type lines, index_type columns, TrackCursor *cursors);
|
||||
|
||||
@@ -249,10 +249,9 @@ rewrap(Screen *screen, unsigned int lines, unsigned int columns, index_type *ncl
|
||||
cursors[0] = (TrackCursor){.x=alt_saved_cursor->before.x, .y=alt_saved_cursor->before.y};
|
||||
if (!main_is_active) cursors[1] = (TrackCursor){.x=cursor->before.x, .y=cursor->before.y};
|
||||
else cursors[1].is_sentinel = true;
|
||||
ResizeResult ar = resize_screen_buffers(screen->alt_linebuf, NULL, lines, columns, &screen->as_ansi_buf, cursors);
|
||||
ResizeResult ar = resize_screen_buffer_without_rewrap(screen->alt_linebuf, lines, columns, cursors);
|
||||
if (!ar.ok) {
|
||||
Py_DecRef((PyObject*)mr.lb); Py_DecRef((PyObject*)mr.hb);
|
||||
PyErr_NoMemory(); return false;
|
||||
Py_DecRef((PyObject*)ar.lb); PyErr_NoMemory(); return false;
|
||||
}
|
||||
alt_saved_cursor->temp.x = cursors[0].dest_x; alt_saved_cursor->temp.y = cursors[0].dest_y;
|
||||
if (!main_is_active) { cursor->temp.x = cursors[1].dest_x; cursor->temp.y = cursors[1].dest_y; }
|
||||
|
||||
@@ -643,6 +643,28 @@ def test_multicell(self: TestMulticell) -> None:
|
||||
ac(x, -1, is_multicell=True, x=x-2, y=0, text='' if x > 2 else 'B')
|
||||
ac(x, 0, is_multicell=True, x=x-2, y=1, text='')
|
||||
|
||||
# resize without rewrap (alt screen)
|
||||
s = self.create_screen(lines=6, cols=6)
|
||||
s.toggle_alt_screen()
|
||||
|
||||
def reset_alt():
|
||||
s.reset()
|
||||
s.resize(6, 6)
|
||||
s.toggle_alt_screen()
|
||||
multicell(s, 'XY', scale=3)
|
||||
s.resize(6, 5)
|
||||
for y in range(3):
|
||||
for x in range(3):
|
||||
ac(x, y, is_multicell=True, text='X' if x == 0 and y == 0 else '')
|
||||
for x in range(3, 5):
|
||||
ac(x, y, is_multicell=False, text='')
|
||||
reset_alt()
|
||||
multicell(s, 'XY', scale=3)
|
||||
s.resize(2, 6)
|
||||
for y in range(s.lines):
|
||||
for x in range(s.columns):
|
||||
ac(x, y, is_multicell=False, text='')
|
||||
|
||||
# selections
|
||||
s = self.create_screen(lines=5, cols=8)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user