diff options
Diffstat (limited to 'screen-write.c')
-rw-r--r-- | screen-write.c | 207 |
1 files changed, 167 insertions, 40 deletions
diff --git a/screen-write.c b/screen-write.c index aa7bd76e..8a2a19e3 100644 --- a/screen-write.c +++ b/screen-write.c @@ -25,6 +25,10 @@ static void screen_write_collect_clear(struct screen_write_ctx *, u_int, u_int); +static int screen_write_collect_clear_end(struct screen_write_ctx *, u_int, + u_int, u_int); +static int screen_write_collect_clear_start(struct screen_write_ctx *, u_int, + u_int, u_int); static void screen_write_collect_scroll(struct screen_write_ctx *); static void screen_write_collect_flush(struct screen_write_ctx *, int, const char *); @@ -42,8 +46,12 @@ struct screen_write_collect_item { u_int x; int wrapped; + enum { TEXT, CLEAR, CLEAR_END, CLEAR_START } type; u_int used; - char data[256]; + union { + u_int bg; + char data[256]; + }; struct grid_cell gc; @@ -924,33 +932,39 @@ screen_write_deleteline(struct screen_write_ctx *ctx, u_int ny, u_int bg) void screen_write_clearline(struct screen_write_ctx *ctx, u_int bg) { - struct screen *s = ctx->s; - struct grid_line *gl; - struct tty_ctx ttyctx; - u_int sx = screen_size_x(s); + struct screen *s = ctx->s; + struct grid_line *gl; + u_int sx = screen_size_x(s); + struct screen_write_collect_item *ci = ctx->item; gl = grid_get_line(s->grid, s->grid->hsize + s->cy); if (gl->cellsize == 0 && COLOUR_DEFAULT(bg)) return; - screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.bg = bg; - grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); screen_write_collect_clear(ctx, s->cy, 1); - screen_write_collect_flush(ctx, 0, __func__); - tty_write(tty_cmd_clearline, &ttyctx); + ci->x = 0; + ci->type = CLEAR; + ci->bg = bg; + TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry); + ctx->item = xcalloc(1, sizeof *ctx->item); } /* Clear to end of line from cursor. */ void screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) { - struct screen *s = ctx->s; - struct grid_line *gl; - struct tty_ctx ttyctx; - u_int sx = screen_size_x(s); + struct screen *s = ctx->s; + struct grid_line *gl; + struct tty_ctx ttyctx; + u_int sx = screen_size_x(s); + struct screen_write_collect_item *ci = ctx->item; + + if (s->cx == 0) { + screen_write_clearline(ctx, bg); + return; + } gl = grid_get_line(s->grid, s->grid->hsize + s->cy); if (s->cx > sx - 1 || (s->cx >= gl->cellsize && COLOUR_DEFAULT(bg))) @@ -961,19 +975,28 @@ screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, bg); - if (s->cx == 0) - screen_write_collect_clear(ctx, s->cy, 1); - screen_write_collect_flush(ctx, 0, __func__); - tty_write(tty_cmd_clearendofline, &ttyctx); + if (!screen_write_collect_clear_end(ctx, s->cy, s->cx, bg)) { + ci->x = s->cx; + ci->type = CLEAR_END; + ci->bg = bg; + TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry); + ctx->item = xcalloc(1, sizeof *ctx->item); + } } /* Clear to start of line from cursor. */ void screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) { - struct screen *s = ctx->s; - struct tty_ctx ttyctx; - u_int sx = screen_size_x(s); + struct screen *s = ctx->s; + struct tty_ctx ttyctx; + u_int sx = screen_size_x(s); + struct screen_write_collect_item *ci = ctx->item; + + if (s->cx >= sx - 1) { + screen_write_clearline(ctx, bg); + return; + } screen_write_initctx(ctx, &ttyctx, 1); ttyctx.bg = bg; @@ -983,10 +1006,13 @@ screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) else grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); - if (s->cx > sx - 1) - screen_write_collect_clear(ctx, s->cy, 1); - screen_write_collect_flush(ctx, 0, __func__); - tty_write(tty_cmd_clearstartofline, &ttyctx); + if (!screen_write_collect_clear_start(ctx, s->cy, s->cx, bg)) { + ci->x = s->cx; + ci->type = CLEAR_START; + ci->bg = bg; + TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry); + ctx->item = xcalloc(1, sizeof *ctx->item); + } } /* Move cursor to px,py. */ @@ -1018,16 +1044,17 @@ screen_write_reverseindex(struct screen_write_ctx *ctx, u_int bg) struct screen *s = ctx->s; struct tty_ctx ttyctx; - screen_write_initctx(ctx, &ttyctx, 1); - ttyctx.bg = bg; - - if (s->cy == s->rupper) + if (s->cy == s->rupper) { grid_view_scroll_region_down(s->grid, s->rupper, s->rlower, bg); - else if (s->cy > 0) + screen_write_collect_flush(ctx, 0, __func__); + + screen_write_initctx(ctx, &ttyctx, 1); + ttyctx.bg = bg; + + tty_write(tty_cmd_reverseindex, &ttyctx); + } else if (s->cy > 0) screen_write_set_cursor(ctx, -1, s->cy - 1); - screen_write_collect_flush(ctx, 0, __func__); - tty_write(tty_cmd_reverseindex, &ttyctx); } /* Set scroll region. */ @@ -1217,25 +1244,114 @@ screen_write_clearhistory(struct screen_write_ctx *ctx) grid_clear_history(ctx->s->grid); } -/* Clear a collected line. */ +/* Clear to start of a collected line. */ +static int +screen_write_collect_clear_start(struct screen_write_ctx *ctx, u_int y, u_int x, + u_int bg) +{ + struct screen_write_collect_item *ci, *tmp; + size_t size = 0; + u_int items = 0; + int redundant = 0; + + if (TAILQ_EMPTY(&ctx->list[y].items)) + return (0); + TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { + switch (ci->type) { + case CLEAR: + continue; + case CLEAR_START: + if (ci->x >= x) { + if (ci->bg == bg) + redundant = 1; + continue; + } + break; + case CLEAR_END: + if (ci->x <= x) + ci->x = x; + continue; + case TEXT: + if (ci->x > x) + continue; + break; + } + items++; + size += ci->used; + TAILQ_REMOVE(&ctx->list[y].items, ci, entry); + free(ci); + } + ctx->skipped += size; + log_debug("%s: dropped %u items (%zu bytes) (line %u)", __func__, items, + size, y); + return (redundant); +} + +/* Clear to end of a collected line. */ +static int +screen_write_collect_clear_end(struct screen_write_ctx *ctx, u_int y, u_int x, + u_int bg) +{ + struct screen_write_collect_item *ci, *tmp; + size_t size = 0; + int redundant = 0; + u_int items = 0; + + if (TAILQ_EMPTY(&ctx->list[y].items)) + return (0); + TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { + switch (ci->type) { + case CLEAR: + continue; + case CLEAR_START: + if (ci->x >= x) + ci->x = x; + continue; + case CLEAR_END: + if (ci->x <= x) { + if (ci->bg == bg) + redundant = 1; + continue; + } + break; + case TEXT: + if (ci->x < x) + continue; + break; + } + items++; + size += ci->used; + TAILQ_REMOVE(&ctx->list[y].items, ci, entry); + free(ci); + } + ctx->skipped += size; + log_debug("%s: dropped %u items (%zu bytes) (line %u)", __func__, items, + size, y); + return (redundant); +} + +/* Clear part of a collected line. */ static void screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) { struct screen_write_collect_item *ci, *tmp; - u_int i; + u_int i, items; size_t size; for (i = y; i < y + n; i++) { if (TAILQ_EMPTY(&ctx->list[i].items)) continue; + items = 0; size = 0; TAILQ_FOREACH_SAFE(ci, &ctx->list[i].items, entry, tmp) { + items++; size += ci->used; TAILQ_REMOVE(&ctx->list[i].items, ci, entry); free(ci); } ctx->skipped += size; - log_debug("%s: dropped %zu bytes (line %u)", __func__, size, i); + log_debug("%s: dropped %u items (%zu bytes) (line %u)", + __func__, items, size, y); } } @@ -1290,11 +1406,22 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { screen_write_set_cursor(ctx, ci->x, y); screen_write_initctx(ctx, &ttyctx, 0); - ttyctx.cell = &ci->gc; - ttyctx.wrapped = ci->wrapped; - ttyctx.ptr = ci->data; - ttyctx.num = ci->used; - tty_write(tty_cmd_cells, &ttyctx); + if (ci->type == CLEAR) { + ttyctx.bg = ci->bg; + tty_write(tty_cmd_clearline, &ttyctx); + } else if (ci->type == CLEAR_END) { + ttyctx.bg = ci->bg; + tty_write(tty_cmd_clearendofline, &ttyctx); + } else if (ci->type == CLEAR_START) { + ttyctx.bg = ci->bg; + tty_write(tty_cmd_clearstartofline, &ttyctx); + } else { + ttyctx.cell = &ci->gc; + ttyctx.wrapped = ci->wrapped; + ttyctx.ptr = ci->data; + ttyctx.num = ci->used; + tty_write(tty_cmd_cells, &ttyctx); + } items++; written += ci->used; |