mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-19 05:33:44 -04:00
grid: don't pre-allocate the entire grid (with all scrollback lines)
The row array may now contain NULL pointers. This means the corresponding row hasn't yet been allocated and initialized. On a resize, we explicitly allocate the visible rows. Uninitialized rows are then allocated the first time they are referenced.
This commit is contained in:
parent
8f0d574dcb
commit
1ff1b3a71e
7 changed files with 68 additions and 45 deletions
|
|
@ -26,7 +26,7 @@ cmd_scrollback_up(struct terminal *term, int rows)
|
||||||
assert(new_view < term->grid->num_rows);
|
assert(new_view < term->grid->num_rows);
|
||||||
|
|
||||||
/* Avoid scrolling in uninitialized rows */
|
/* Avoid scrolling in uninitialized rows */
|
||||||
while (!term->grid->rows[new_view]->initialized)
|
while (term->grid->rows[new_view] == NULL)
|
||||||
new_view = (new_view + 1) % term->grid->num_rows;
|
new_view = (new_view + 1) % term->grid->num_rows;
|
||||||
|
|
||||||
if (new_view == term->grid->view) {
|
if (new_view == term->grid->view) {
|
||||||
|
|
@ -87,7 +87,7 @@ cmd_scrollback_down(struct terminal *term, int rows)
|
||||||
|
|
||||||
for (int i = 0; i < term->rows; i++) {
|
for (int i = 0; i < term->rows; i++) {
|
||||||
int row_no = (new_view + i) % term->grid->num_rows;
|
int row_no = (new_view + i) % term->grid->num_rows;
|
||||||
if (!term->grid->rows[row_no]->initialized) {
|
if (term->grid->rows[row_no] == NULL) {
|
||||||
all_initialized = false;
|
all_initialized = false;
|
||||||
new_view--;
|
new_view--;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
19
grid.c
19
grid.c
|
|
@ -25,3 +25,22 @@ grid_swap_row(struct grid *grid, int row_a, int row_b)
|
||||||
grid->rows[real_a]->dirty = true;
|
grid->rows[real_a]->dirty = true;
|
||||||
grid->rows[real_b]->dirty = true;
|
grid->rows[real_b]->dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct row *
|
||||||
|
grid_row_alloc(int cols)
|
||||||
|
{
|
||||||
|
struct row *row = malloc(sizeof(*row));
|
||||||
|
row->cells = calloc(cols, sizeof(row->cells[0]));
|
||||||
|
row->dirty = false; /* TODO: parameter? */
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
grid_row_free(struct row *row)
|
||||||
|
{
|
||||||
|
if (row == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(row->cells);
|
||||||
|
free(row);
|
||||||
|
}
|
||||||
|
|
|
||||||
28
grid.h
28
grid.h
|
|
@ -3,18 +3,34 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
|
void grid_swap_row(struct grid *grid, int row_a, int row_b);
|
||||||
|
struct row *grid_row_alloc(int cols);
|
||||||
|
void grid_row_free(struct row *row);
|
||||||
|
|
||||||
static inline struct row *
|
static inline struct row *
|
||||||
grid_row(struct grid *grid, int row)
|
grid_row(struct grid *grid, int row_no)
|
||||||
{
|
{
|
||||||
assert(grid->offset >= 0);
|
assert(grid->offset >= 0);
|
||||||
return grid->rows[(grid->offset + row + grid->num_rows) % grid->num_rows];
|
|
||||||
|
int real_row = (grid->offset + row_no + grid->num_rows) % grid->num_rows;
|
||||||
|
struct row *row = grid->rows[real_row];
|
||||||
|
|
||||||
|
if (row == NULL) {
|
||||||
|
row = grid_row_alloc(grid->num_cols);
|
||||||
|
grid->rows[real_row] = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct row *
|
static inline struct row *
|
||||||
grid_row_in_view(struct grid *grid, int row)
|
grid_row_in_view(struct grid *grid, int row_no)
|
||||||
{
|
{
|
||||||
assert(grid->view >= 0);
|
assert(grid->view >= 0);
|
||||||
return grid->rows[(grid->view + row + grid->num_rows) % grid->num_rows];
|
|
||||||
}
|
|
||||||
|
|
||||||
void grid_swap_row(struct grid *grid, int row_a, int row_b);
|
int real_row = (grid->offset + row_no + grid->num_rows) % grid->num_rows;
|
||||||
|
struct row *row = grid->rows[real_row];
|
||||||
|
|
||||||
|
assert(row != NULL);
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
|
||||||
12
main.c
12
main.c
|
|
@ -624,15 +624,11 @@ out:
|
||||||
if (term.kbd.xkb != NULL)
|
if (term.kbd.xkb != NULL)
|
||||||
xkb_context_unref(term.kbd.xkb);
|
xkb_context_unref(term.kbd.xkb);
|
||||||
|
|
||||||
for (int row = 0; row < term.normal.num_rows; row++) {
|
for (int row = 0; row < term.normal.num_rows; row++)
|
||||||
free(term.normal.rows[row]->cells);
|
grid_row_free(term.normal.rows[row]);
|
||||||
free(term.normal.rows[row]);
|
|
||||||
}
|
|
||||||
free(term.normal.rows);
|
free(term.normal.rows);
|
||||||
for (int row = 0; row < term.alt.num_rows; row++) {
|
for (int row = 0; row < term.alt.num_rows; row++)
|
||||||
free(term.alt.rows[row]->cells);
|
grid_row_free(term.alt.rows[row]);
|
||||||
free(term.alt.rows[row]);
|
|
||||||
}
|
|
||||||
free(term.alt.rows);
|
free(term.alt.rows);
|
||||||
|
|
||||||
for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) {
|
for (size_t i = 0; i < sizeof(term.fonts) / sizeof(term.fonts[0]); i++) {
|
||||||
|
|
|
||||||
47
render.c
47
render.c
|
|
@ -346,21 +346,27 @@ reflow(struct row **new_grid, int new_cols, int new_rows,
|
||||||
size_t copy_cols = min(new_cols, old_cols);
|
size_t copy_cols = min(new_cols, old_cols);
|
||||||
size_t clear_cols = new_cols - copy_cols;
|
size_t clear_cols = new_cols - copy_cols;
|
||||||
|
|
||||||
|
if (old_grid[r] == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (new_grid[r] == NULL)
|
||||||
|
new_grid[r] = grid_row_alloc(new_cols);
|
||||||
|
|
||||||
struct cell *new_cells = new_grid[r]->cells;
|
struct cell *new_cells = new_grid[r]->cells;
|
||||||
const struct cell *old_cells = old_grid[r]->cells;
|
const struct cell *old_cells = old_grid[r]->cells;
|
||||||
|
|
||||||
new_grid[r]->initialized = old_grid[r]->initialized;
|
|
||||||
new_grid[r]->dirty = old_grid[r]->dirty;
|
new_grid[r]->dirty = old_grid[r]->dirty;
|
||||||
|
|
||||||
memcpy(new_cells, old_cells, copy_cols * sizeof(new_cells[0]));
|
memcpy(new_cells, old_cells, copy_cols * sizeof(new_cells[0]));
|
||||||
memset(&new_cells[copy_cols], 0, clear_cols * sizeof(new_cells[0]));
|
memset(&new_cells[copy_cols], 0, clear_cols * sizeof(new_cells[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
for (int r = min(new_rows, old_rows); r < new_rows; r++) {
|
for (int r = min(new_rows, old_rows); r < new_rows; r++) {
|
||||||
new_grid[r]->initialized = false;
|
new_grid[r]->initialized = false;
|
||||||
new_grid[r]->dirty = false;
|
new_grid[r]->dirty = false;
|
||||||
memset(new_grid[r]->cells, 0, new_cols * sizeof(new_grid[r]->cells[0]));
|
memset(new_grid[r]->cells, 0, new_cols * sizeof(new_grid[r]->cells[0]));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move to terminal.c? */
|
/* Move to terminal.c? */
|
||||||
|
|
@ -386,20 +392,14 @@ render_resize(struct terminal *term, int width, int height)
|
||||||
const int new_alt_grid_rows = new_rows;
|
const int new_alt_grid_rows = new_rows;
|
||||||
|
|
||||||
/* Allocate new 'normal' grid */
|
/* Allocate new 'normal' grid */
|
||||||
struct row **normal = malloc(new_normal_grid_rows * sizeof(normal[0]));
|
struct row **normal = calloc(new_normal_grid_rows, sizeof(normal[0]));
|
||||||
for (int r = 0; r < new_normal_grid_rows; r++) {
|
for (int r = 0; r < new_rows; r++)
|
||||||
struct row *row = malloc(sizeof(*row));
|
normal[r] = grid_row_alloc(new_cols);
|
||||||
row->cells = malloc(new_cols * sizeof(row->cells[0]));
|
|
||||||
normal[r] = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Allocate new 'alt' grid */
|
/* Allocate new 'alt' grid */
|
||||||
struct row **alt = malloc(new_alt_grid_rows * sizeof(alt[0]));
|
struct row **alt = calloc(new_alt_grid_rows, sizeof(alt[0]));
|
||||||
for (int r = 0; r < new_alt_grid_rows; r++) {
|
for (int r = 0; r < new_rows; r++)
|
||||||
struct row *row = malloc(sizeof(*row));
|
alt[r] = grid_row_alloc(new_cols);
|
||||||
row->cells = malloc(new_cols * sizeof(row->cells[0]));
|
|
||||||
alt[r] = row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reflow content */
|
/* Reflow content */
|
||||||
reflow(normal, new_cols, new_normal_grid_rows,
|
reflow(normal, new_cols, new_normal_grid_rows,
|
||||||
|
|
@ -407,23 +407,14 @@ render_resize(struct terminal *term, int width, int height)
|
||||||
reflow(alt, new_cols, new_alt_grid_rows,
|
reflow(alt, new_cols, new_alt_grid_rows,
|
||||||
term->alt.rows, old_cols, old_alt_grid_rows);
|
term->alt.rows, old_cols, old_alt_grid_rows);
|
||||||
|
|
||||||
for (int r = 0; r < new_rows; r++) {
|
|
||||||
normal[r]->initialized = true;
|
|
||||||
alt[r]->initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free old 'normal' grid */
|
/* Free old 'normal' grid */
|
||||||
for (int r = 0; r < term->normal.num_rows; r++) {
|
for (int r = 0; r < term->normal.num_rows; r++)
|
||||||
free(term->normal.rows[r]->cells);
|
grid_row_free(term->normal.rows[r]);
|
||||||
free(term->normal.rows[r]);
|
|
||||||
}
|
|
||||||
free(term->normal.rows);
|
free(term->normal.rows);
|
||||||
|
|
||||||
/* Free old 'alt' grid */
|
/* Free old 'alt' grid */
|
||||||
for (int r = 0; r < term->alt.num_rows; r++) {
|
for (int r = 0; r < term->alt.num_rows; r++)
|
||||||
free(term->alt.rows[r]->cells);
|
grid_row_free(term->alt.rows[r]);
|
||||||
free(term->alt.rows[r]);
|
|
||||||
}
|
|
||||||
free(term->alt.rows);
|
free(term->alt.rows);
|
||||||
|
|
||||||
term->cols = new_cols;
|
term->cols = new_cols;
|
||||||
|
|
@ -431,8 +422,10 @@ render_resize(struct terminal *term, int width, int height)
|
||||||
|
|
||||||
term->normal.rows = normal;
|
term->normal.rows = normal;
|
||||||
term->normal.num_rows = new_normal_grid_rows;
|
term->normal.num_rows = new_normal_grid_rows;
|
||||||
|
term->normal.num_cols = new_cols;
|
||||||
term->alt.rows = alt;
|
term->alt.rows = alt;
|
||||||
term->alt.num_rows = new_alt_grid_rows;
|
term->alt.num_rows = new_alt_grid_rows;
|
||||||
|
term->alt.num_cols = new_cols;
|
||||||
|
|
||||||
LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d",
|
LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d",
|
||||||
term->width, term->height, term->cols, term->rows);
|
term->width, term->height, term->cols, term->rows);
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,6 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows
|
||||||
for (int r = max(region.end - rows, 0); r < region.end; r++) {
|
for (int r = max(region.end - rows, 0); r < region.end; r++) {
|
||||||
struct row *row = grid_row(term->grid, r);
|
struct row *row = grid_row(term->grid, r);
|
||||||
erase_line(term, row);
|
erase_line(term, row);
|
||||||
row->initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
term_damage_scroll(term, DAMAGE_SCROLL, region, rows);
|
||||||
|
|
|
||||||
|
|
@ -94,11 +94,11 @@ struct damage {
|
||||||
struct row {
|
struct row {
|
||||||
struct cell *cells;
|
struct cell *cells;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool initialized;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct grid {
|
struct grid {
|
||||||
int num_rows;
|
int num_rows;
|
||||||
|
int num_cols;
|
||||||
int offset;
|
int offset;
|
||||||
int view;
|
int view;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue