version 1.108, 2017/02/08 15:49:29 |
version 1.109, 2017/02/08 16:45:18 |
|
|
|
|
static void screen_write_initctx(struct screen_write_ctx *, |
static void screen_write_initctx(struct screen_write_ctx *, |
struct tty_ctx *); |
struct tty_ctx *); |
static void screen_write_flush(struct screen_write_ctx *); |
static void screen_write_collect_clear(struct screen_write_ctx *, u_int, |
|
u_int); |
|
static void screen_write_collect_scroll(struct screen_write_ctx *); |
|
static void screen_write_collect_flush(struct screen_write_ctx *); |
|
|
static int screen_write_overwrite(struct screen_write_ctx *, |
static int screen_write_overwrite(struct screen_write_ctx *, |
struct grid_cell *, u_int); |
struct grid_cell *, u_int); |
|
|
GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 } |
GRID_FLAG_PADDING, 0, 8, 8, { { 0 }, 0, 0, 0 } |
}; |
}; |
|
|
#define screen_dirty_bit(s, x, y) (((y) * screen_size_x(s)) + (x)) |
struct screen_write_collect_item { |
#define screen_dirty_clear(s, sx, sy, ex, ey) \ |
u_int x; |
do { \ |
|
if (s->dirty != NULL) { \ |
|
bit_nclear(s->dirty, \ |
|
screen_dirty_bit(s, sx, sy), \ |
|
screen_dirty_bit(s, ex, ey)); \ |
|
} \ |
|
} while (0) |
|
|
|
|
u_int used; |
|
char data[256]; |
|
|
|
struct grid_cell gc; |
|
|
|
TAILQ_ENTRY (screen_write_collect_item) entry; |
|
}; |
|
struct screen_write_collect_line { |
|
TAILQ_HEAD(, screen_write_collect_item) items; |
|
}; |
|
|
/* Initialize writing with a window. */ |
/* Initialize writing with a window. */ |
void |
void |
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, |
screen_write_start(struct screen_write_ctx *ctx, struct window_pane *wp, |
struct screen *s) |
struct screen *s) |
{ |
{ |
u_int size; |
|
char tmp[16]; |
char tmp[16]; |
|
u_int y; |
|
|
|
memset(ctx, 0, sizeof *ctx); |
|
|
ctx->wp = wp; |
ctx->wp = wp; |
if (wp != NULL && s == NULL) |
if (wp != NULL && s == NULL) |
ctx->s = wp->screen; |
ctx->s = wp->screen; |
else |
else |
ctx->s = s; |
ctx->s = s; |
|
|
size = screen_size_x(ctx->s) * screen_size_y(ctx->s); |
ctx->list = xcalloc(screen_size_y(ctx->s), sizeof *ctx->list); |
if (ctx->s->dirtysize != size) { |
for (y = 0; y < screen_size_y(ctx->s); y++) |
free(ctx->s->dirty); |
TAILQ_INIT(&ctx->list[y].items); |
ctx->s->dirty = NULL; |
ctx->item = xcalloc(1, sizeof *ctx->item); |
ctx->s->dirtysize = size; |
|
} |
|
ctx->dirty = 0; |
|
|
|
ctx->cells = ctx->written = ctx->skipped = 0; |
|
|
|
if (wp != NULL) |
if (wp != NULL) |
snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); |
snprintf(tmp, sizeof tmp, "pane %%%u", wp->id); |
log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), |
log_debug("%s: size %ux%u, %s", __func__, screen_size_x(ctx->s), |
|
|
void |
void |
screen_write_stop(struct screen_write_ctx *ctx) |
screen_write_stop(struct screen_write_ctx *ctx) |
{ |
{ |
screen_write_flush(ctx); |
screen_write_collect_end(ctx); |
|
screen_write_collect_flush(ctx); |
|
|
log_debug("%s: %u of %u written (dirty %u, skipped %u)", __func__, |
log_debug("%s: %u cells (%u written, %u skipped)", __func__, |
ctx->written, ctx->cells, ctx->cells - ctx->written, ctx->skipped); |
ctx->cells, ctx->written, ctx->skipped); |
} |
|
|
|
/* Flush outstanding cell writes. */ |
free(ctx->item); |
static void |
free(ctx->list); /* flush will have emptied */ |
screen_write_flush(struct screen_write_ctx *ctx) |
|
{ |
|
struct screen *s = ctx->s; |
|
struct tty_ctx ttyctx; |
|
u_int x, y, offset, cx, cy, dirty; |
|
struct grid_cell gc; |
|
|
|
if (ctx->dirty == 0) |
|
return; |
|
dirty = 0; |
|
log_debug("%s: dirty %u", __func__, ctx->dirty); |
|
|
|
cx = s->cx; |
|
cy = s->cy; |
|
|
|
offset = 0; |
|
for (y = 0; y < screen_size_y(s); y++) { |
|
for (x = 0; x < screen_size_x(s); x++) { |
|
offset++; |
|
if (!bit_test(s->dirty, offset - 1)) |
|
continue; |
|
bit_clear(s->dirty, offset - 1); |
|
|
|
screen_write_cursormove(ctx, x, y); |
|
grid_view_get_cell(s->grid, x, y, &gc); |
|
|
|
screen_write_initctx(ctx, &ttyctx); |
|
ttyctx.cell = &gc; |
|
tty_write(tty_cmd_cell, &ttyctx); |
|
ctx->written++; |
|
|
|
if (++dirty == ctx->dirty) |
|
break; |
|
} |
|
if (dirty == ctx->dirty) |
|
break; |
|
} |
|
ctx->dirty = 0; |
|
|
|
s->cx = cx; |
|
s->cy = cy; |
|
} |
} |
|
|
/* Reset screen state. */ |
/* Reset screen state. */ |
|
|
struct tty_ctx ttyctx; |
struct tty_ctx ttyctx; |
struct grid_cell gc; |
struct grid_cell gc; |
u_int xx, yy; |
u_int xx, yy; |
u_int sx = screen_size_x(s), sy = screen_size_y(s); |
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
|
|
screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); |
|
|
|
memcpy(&gc, &grid_default_cell, sizeof gc); |
memcpy(&gc, &grid_default_cell, sizeof gc); |
utf8_set(&gc.data, 'E'); |
utf8_set(&gc.data, 'E'); |
|
|
|
|
s->rupper = 0; |
s->rupper = 0; |
s->rlower = screen_size_y(s) - 1; |
s->rlower = screen_size_y(s) - 1; |
|
|
|
screen_write_collect_clear(ctx, 0, screen_size_y(s) - 1); |
tty_write(tty_cmd_alignmenttest, &ttyctx); |
tty_write(tty_cmd_alignmenttest, &ttyctx); |
} |
} |
|
|
|
|
if (s->cx > screen_size_x(s) - 1) |
if (s->cx > screen_size_x(s) - 1) |
return; |
return; |
|
|
screen_write_flush(ctx); |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); |
grid_view_insert_cells(s->grid, s->cx, s->cy, nx, bg); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = nx; |
ttyctx.num = nx; |
tty_write(tty_cmd_insertcharacter, &ttyctx); |
tty_write(tty_cmd_insertcharacter, &ttyctx); |
} |
} |
|
|
if (s->cx > screen_size_x(s) - 1) |
if (s->cx > screen_size_x(s) - 1) |
return; |
return; |
|
|
screen_write_flush(ctx); |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); |
grid_view_delete_cells(s->grid, s->cx, s->cy, nx, bg); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = nx; |
ttyctx.num = nx; |
tty_write(tty_cmd_deletecharacter, &ttyctx); |
tty_write(tty_cmd_deletecharacter, &ttyctx); |
} |
} |
|
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
|
|
screen_dirty_clear(s, s->cx, s->cy, s->cx + nx - 1, s->cy); |
|
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8); |
grid_view_clear(s->grid, s->cx, s->cy, nx, 1, 8); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = nx; |
ttyctx.num = nx; |
tty_write(tty_cmd_clearcharacter, &ttyctx); |
tty_write(tty_cmd_clearcharacter, &ttyctx); |
} |
} |
|
|
if (ny == 0) |
if (ny == 0) |
return; |
return; |
|
|
screen_write_flush(ctx); |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
grid_view_insert_lines(gd, s->cy, ny, bg); |
grid_view_insert_lines(gd, s->cy, ny, bg); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = ny; |
ttyctx.num = ny; |
tty_write(tty_cmd_insertline, &ttyctx); |
tty_write(tty_cmd_insertline, &ttyctx); |
return; |
return; |
|
|
if (ny == 0) |
if (ny == 0) |
return; |
return; |
|
|
screen_write_flush(ctx); |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
|
|
else |
else |
grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg); |
grid_view_insert_lines_region(gd, s->rlower, s->cy, ny, bg); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = ny; |
ttyctx.num = ny; |
tty_write(tty_cmd_insertline, &ttyctx); |
tty_write(tty_cmd_insertline, &ttyctx); |
} |
} |
|
|
if (ny == 0) |
if (ny == 0) |
return; |
return; |
|
|
screen_write_flush(ctx); |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
grid_view_delete_lines(gd, s->cy, ny, bg); |
grid_view_delete_lines(gd, s->cy, ny, bg); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = ny; |
ttyctx.num = ny; |
tty_write(tty_cmd_deleteline, &ttyctx); |
tty_write(tty_cmd_deleteline, &ttyctx); |
return; |
return; |
|
|
if (ny == 0) |
if (ny == 0) |
return; |
return; |
|
|
screen_write_flush(ctx); |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
|
|
else |
else |
grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg); |
grid_view_delete_lines_region(gd, s->rlower, s->cy, ny, bg); |
|
|
|
screen_write_collect_flush(ctx); |
ttyctx.num = ny; |
ttyctx.num = ny; |
tty_write(tty_cmd_deleteline, &ttyctx); |
tty_write(tty_cmd_deleteline, &ttyctx); |
} |
} |
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy); |
|
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); |
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); |
|
|
|
screen_write_collect_clear(ctx, s->cy, 1); |
tty_write(tty_cmd_clearline, &ttyctx); |
tty_write(tty_cmd_clearline, &ttyctx); |
} |
} |
|
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy); |
|
grid_view_clear(s->grid, s->cx, s->cy, sx - s->cx, 1, 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); |
|
else |
|
screen_write_collect_flush(ctx); |
tty_write(tty_cmd_clearendofline, &ttyctx); |
tty_write(tty_cmd_clearendofline, &ttyctx); |
} |
} |
|
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
if (s->cx > sx - 1) { |
if (s->cx > sx - 1) |
screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy); |
|
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); |
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); |
} else { |
else |
screen_dirty_clear(s, 0, s->cy, s->cx, s->cy); |
|
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); |
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); |
|
else |
|
screen_write_collect_flush(ctx); |
tty_write(tty_cmd_clearstartofline, &ttyctx); |
tty_write(tty_cmd_clearstartofline, &ttyctx); |
} |
} |
|
|
|
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
|
|
if (s->cy == s->rupper) { |
if (s->cy == s->rupper) |
screen_write_flush(ctx); |
|
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); |
grid_view_scroll_region_down(s->grid, s->rupper, s->rlower); |
} else if (s->cy > 0) |
else if (s->cy > 0) |
s->cy--; |
s->cy--; |
|
|
|
screen_write_collect_flush(ctx); |
tty_write(tty_cmd_reverseindex, &ttyctx); |
tty_write(tty_cmd_reverseindex, &ttyctx); |
} |
} |
|
|
|
|
screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) |
screen_write_linefeed(struct screen_write_ctx *ctx, int wrapped) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
|
struct grid *gd = s->grid; |
struct grid_line *gl; |
struct grid_line *gl; |
struct tty_ctx ttyctx; |
struct tty_ctx ttyctx; |
u_int sx = screen_size_x(s), sy = screen_size_y(s); |
|
|
|
screen_write_initctx(ctx, &ttyctx); |
gl = &gd->linedata[gd->hsize + s->cy]; |
|
|
gl = &s->grid->linedata[s->grid->hsize + s->cy]; |
|
if (wrapped) |
if (wrapped) |
gl->flags |= GRID_LINE_WRAPPED; |
gl->flags |= GRID_LINE_WRAPPED; |
else |
else |
gl->flags &= ~GRID_LINE_WRAPPED; |
gl->flags &= ~GRID_LINE_WRAPPED; |
|
|
if (s->cy == s->rlower) { |
if (s->cy == s->rlower) { |
screen_dirty_clear(s, 0, s->rupper, sx - 1, s->rupper); |
grid_view_scroll_region_up(gd, s->rupper, s->rlower); |
screen_write_flush(ctx); |
|
grid_view_scroll_region_up(s->grid, s->rupper, s->rlower); |
|
} else if (s->cy < sy - 1) |
|
s->cy++; |
|
|
|
ttyctx.num = wrapped; |
screen_write_collect_scroll(ctx); |
tty_write(tty_cmd_linefeed, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
|
tty_write(tty_cmd_linefeed, &ttyctx); |
|
} else if (s->cy < screen_size_y(s) - 1) |
|
s->cy++; |
} |
} |
|
|
/* Carriage return (cursor to start of line). */ |
/* Carriage return (cursor to start of line). */ |
|
|
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
/* Scroll into history if it is enabled and clearing entire screen. */ |
/* Scroll into history if it is enabled and clearing entire screen. */ |
if (s->cx == 0 && s->cy == 0 && gd->flags & GRID_HISTORY) { |
if (s->cx == 0 && s->cy == 0 && (gd->flags & GRID_HISTORY)) |
screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); |
|
grid_view_clear_history(gd, bg); |
grid_view_clear_history(gd, bg); |
} else { |
else { |
if (s->cx <= sx - 1) { |
if (s->cx <= sx - 1) |
screen_dirty_clear(s, s->cx, s->cy, sx - 1, s->cy); |
|
grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg); |
grid_view_clear(gd, s->cx, s->cy, sx - s->cx, 1, bg); |
} |
|
screen_dirty_clear(s, 0, s->cy + 1, sx - 1, sy - 1); |
|
grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); |
grid_view_clear(gd, 0, s->cy + 1, sx, sy - (s->cy + 1), bg); |
} |
} |
|
|
|
screen_write_collect_clear(ctx, s->cy + 1, sy - (s->cy + 1)); |
|
screen_write_collect_flush(ctx); |
tty_write(tty_cmd_clearendofscreen, &ttyctx); |
tty_write(tty_cmd_clearendofscreen, &ttyctx); |
} |
} |
|
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
if (s->cy > 0) { |
if (s->cy > 0) |
screen_dirty_clear(s, 0, 0, sx - 1, s->cy); |
|
grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); |
grid_view_clear(s->grid, 0, 0, sx, s->cy, bg); |
} |
if (s->cx > sx - 1) |
if (s->cx > sx - 1) { |
grid_view_clear(s->grid, 0, s->cy, sx, 1, 8); |
screen_dirty_clear(s, 0, s->cy, sx - 1, s->cy); |
else |
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg); |
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, 8); |
} else { |
|
screen_dirty_clear(s, 0, s->cy, s->cx, s->cy); |
|
grid_view_clear(s->grid, 0, s->cy, s->cx + 1, 1, bg); |
|
} |
|
|
|
|
screen_write_collect_clear(ctx, 0, s->cy); |
|
screen_write_collect_flush(ctx); |
tty_write(tty_cmd_clearstartofscreen, &ttyctx); |
tty_write(tty_cmd_clearstartofscreen, &ttyctx); |
} |
} |
|
|
|
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
ttyctx.bg = bg; |
ttyctx.bg = bg; |
|
|
screen_dirty_clear(s, 0, 0, sx - 1, sy - 1); |
|
|
|
/* Scroll into history if it is enabled. */ |
/* Scroll into history if it is enabled. */ |
if (s->grid->flags & GRID_HISTORY) |
if (s->grid->flags & GRID_HISTORY) |
grid_view_clear_history(s->grid, bg); |
grid_view_clear_history(s->grid, bg); |
else |
else |
grid_view_clear(s->grid, 0, 0, sx, sy, bg); |
grid_view_clear(s->grid, 0, 0, sx, sy, bg); |
|
|
|
screen_write_collect_clear(ctx, 0, sy); |
tty_write(tty_cmd_clearscreen, &ttyctx); |
tty_write(tty_cmd_clearscreen, &ttyctx); |
} |
} |
|
|
|
|
gd->hscrolled = gd->hsize = 0; |
gd->hscrolled = gd->hsize = 0; |
} |
} |
|
|
|
/* Clear 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; |
|
size_t size; |
|
|
|
for (i = y ; i < y + n; i++) { |
|
if (TAILQ_EMPTY(&ctx->list[i].items)) |
|
continue; |
|
size = 0; |
|
TAILQ_FOREACH_SAFE(ci, &ctx->list[i].items, entry, tmp) { |
|
size += ci->used; |
|
TAILQ_REMOVE(&ctx->list[i].items, ci, entry); |
|
free(ci); |
|
} |
|
ctx->skipped += size; |
|
log_debug("discarding %zu bytes on line %u", size, i); |
|
} |
|
} |
|
|
|
/* Scroll collected lines up. */ |
|
static void |
|
screen_write_collect_scroll(struct screen_write_ctx *ctx) |
|
{ |
|
struct screen *s = ctx->s; |
|
struct screen_write_collect_line *cl; |
|
u_int y; |
|
|
|
screen_write_collect_clear(ctx, s->rupper, 1); |
|
for (y = s->rupper; y < s->rlower; y++) { |
|
cl = &ctx->list[y + 1]; |
|
TAILQ_CONCAT(&ctx->list[y].items, &cl->items, entry); |
|
TAILQ_INIT(&cl->items); |
|
} |
|
} |
|
|
|
/* Flush collected lines. */ |
|
static void |
|
screen_write_collect_flush(struct screen_write_ctx *ctx) |
|
{ |
|
struct screen *s = ctx->s; |
|
struct screen_write_collect_item *ci, *tmp; |
|
u_int y, cx, cy; |
|
struct tty_ctx ttyctx; |
|
|
|
cx = s->cx; cy = s->cy; |
|
for (y = 0; y < screen_size_y(s); y++) { |
|
TAILQ_FOREACH_SAFE(ci, &ctx->list[y].items, entry, tmp) { |
|
screen_write_cursormove(ctx, ci->x, y); |
|
screen_write_initctx(ctx, &ttyctx); |
|
ttyctx.cell = &ci->gc; |
|
ttyctx.ptr = ci->data; |
|
ttyctx.num = ci->used; |
|
tty_write(tty_cmd_cells, &ttyctx); |
|
ctx->written += ci->used; |
|
|
|
TAILQ_REMOVE(&ctx->list[y].items, ci, entry); |
|
free(ci); |
|
} |
|
} |
|
s->cx = cx; s->cy = cy; |
|
} |
|
|
|
/* Finish and store collected cells. */ |
|
void |
|
screen_write_collect_end(struct screen_write_ctx *ctx) |
|
{ |
|
struct screen *s = ctx->s; |
|
struct screen_write_collect_item *ci = ctx->item; |
|
struct grid_cell gc; |
|
|
|
if (ci->used == 0) |
|
return; |
|
ci->data[ci->used] = '\0'; |
|
|
|
ci->x = s->cx; |
|
TAILQ_INSERT_TAIL(&ctx->list[s->cy].items, ci, entry); |
|
ctx->item = xcalloc(1, sizeof *ctx->item); |
|
|
|
log_debug("%s: %u %s (at %u,%u)", __func__, ci->used, ci->data, s->cx, |
|
s->cy); |
|
|
|
memcpy(&gc, &ci->gc, sizeof gc); |
|
grid_view_set_cells(s->grid, s->cx, s->cy, &gc, ci->data, ci->used); |
|
s->cx += ci->used; |
|
} |
|
|
|
/* Write cell data, collecting if necessary. */ |
|
void |
|
screen_write_collect_add(struct screen_write_ctx *ctx, |
|
const struct grid_cell *gc) |
|
{ |
|
struct screen *s = ctx->s; |
|
struct screen_write_collect_item *ci; |
|
u_int sx = screen_size_x(s); |
|
int collect; |
|
|
|
/* |
|
* Don't need to check that the attributes and whatnot are still the |
|
* same - input_parse will do a flush when anything that isn't a plain |
|
* character is encountered. Also nothing should make it here that |
|
* isn't a single ASCII character. |
|
*/ |
|
|
|
collect = 1; |
|
if (gc->data.width != 1) |
|
collect = 0; |
|
else if (gc->attr & GRID_ATTR_CHARSET) |
|
collect = 0; |
|
else if (~s->mode & MODE_WRAP) |
|
collect = 0; |
|
else if (s->mode & MODE_INSERT) |
|
collect = 0; |
|
else if (s->sel.flag) |
|
collect = 0; |
|
if (!collect) { |
|
screen_write_collect_end(ctx); |
|
screen_write_cell(ctx, gc); |
|
return; |
|
} |
|
ctx->cells++; |
|
|
|
if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) |
|
screen_write_collect_end(ctx); |
|
if (s->cx > sx - 1) { |
|
screen_write_linefeed(ctx, 1); |
|
s->cx = 0; |
|
} |
|
|
|
ci = ctx->item; /* may have changed */ |
|
if (ci->used == 0) |
|
memcpy(&ci->gc, gc, sizeof ci->gc); |
|
ci->data[ci->used++] = gc->data.data[0]; |
|
if (ci->used == (sizeof ci->data) - 1) |
|
screen_write_collect_end(ctx); |
|
} |
|
|
/* Write cell data. */ |
/* Write cell data. */ |
void |
void |
screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) |
screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct grid *gd = s->grid; |
struct grid *gd = s->grid; |
struct tty_ctx ttyctx; |
|
u_int width, xx, last; |
|
u_int sx = screen_size_x(s), sy = screen_size_y(s); |
|
struct grid_line *gl; |
struct grid_line *gl; |
struct grid_cell tmp_gc, now_gc; |
|
struct grid_cell_entry *gce; |
struct grid_cell_entry *gce; |
int insert, skip, selected; |
struct grid_cell tmp_gc, now_gc; |
|
struct tty_ctx ttyctx; |
|
u_int sx = screen_size_x(s), sy = screen_size_y(s); |
|
u_int width = gc->data.width, xx, last; |
|
int selected, skip = 1; |
|
|
ctx->cells++; |
/* Ignore padding cells. */ |
|
|
/* Ignore padding. */ |
|
if (gc->flags & GRID_FLAG_PADDING) |
if (gc->flags & GRID_FLAG_PADDING) |
return; |
return; |
width = gc->data.width; |
ctx->cells++; |
|
|
/* |
/* If the width is zero, combine onto the previous character. */ |
* If this is a wide character and there is no room on the screen for |
|
* the entire character, don't print it. |
|
*/ |
|
if (!(s->mode & MODE_WRAP) && (width > 1 && |
|
(width > sx || (s->cx != sx && s->cx > sx - width)))) |
|
return; |
|
|
|
/* |
|
* If the width is zero, combine onto the previous character, if |
|
* there is space. |
|
*/ |
|
if (width == 0) { |
if (width == 0) { |
if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) { |
if ((gc = screen_write_combine(ctx, &gc->data, &xx)) != 0) { |
screen_write_cursormove(ctx, xx, s->cy); |
screen_write_cursormove(ctx, xx, s->cy); |
|
|
return; |
return; |
} |
} |
|
|
|
/* If this character doesn't fit, ignore it. */ |
|
if ((~s->mode & MODE_WRAP) && |
|
width > 1 && |
|
(width > sx || (s->cx != sx && s->cx > sx - width))) |
|
return; |
|
|
/* If in insert mode, make space for the cells. */ |
/* If in insert mode, make space for the cells. */ |
if (s->mode & MODE_INSERT) { |
if (s->mode & MODE_INSERT) { |
if (s->cx <= sx - width) { |
grid_view_insert_cells(s->grid, s->cx, s->cy, width, 8); |
screen_write_flush(ctx); |
skip = 0; |
xx = sx - s->cx - width; |
} |
grid_view_insert_cells(s->grid, s->cx, s->cy, xx, 8); |
|
} |
|
insert = 1; |
|
} else |
|
insert = 0; |
|
skip = !insert; |
|
|
|
/* Check this will fit on the current line and wrap if not. */ |
/* Check this will fit on the current line and wrap if not. */ |
if ((s->mode & MODE_WRAP) && s->cx > sx - width) { |
if ((s->mode & MODE_WRAP) && s->cx > sx - width) { |
screen_write_linefeed(ctx, 1); |
screen_write_linefeed(ctx, 1); |
s->cx = 0; /* carriage return */ |
s->cx = 0; |
} |
} |
|
|
/* Sanity check cursor position. */ |
/* Sanity check cursor position. */ |
if (s->cx > sx - width || s->cy > sy - 1) |
if (s->cx > sx - width || s->cy > sy - 1) |
return; |
return; |
|
|
/* Initialise the redraw context. */ |
|
screen_write_initctx(ctx, &ttyctx); |
screen_write_initctx(ctx, &ttyctx); |
|
|
/* Handle overwriting of UTF-8 characters. */ |
/* Handle overwriting of UTF-8 characters. */ |
|
|
skip = 0; |
skip = 0; |
else if (gc->data.width != 1) |
else if (gc->data.width != 1) |
skip = 0; |
skip = 0; |
|
else if (gc->data.size != 1) |
|
skip = 0; |
else if (gce->data.data != gc->data.data[0]) |
else if (gce->data.data != gc->data.data[0]) |
skip = 0; |
skip = 0; |
} |
} |
|
|
|
|
/* Update the selection the flag and set the cell. */ |
/* Update the selection the flag and set the cell. */ |
selected = screen_check_selection(s, s->cx, s->cy); |
selected = screen_check_selection(s, s->cx, s->cy); |
if (selected && ~gc->flags & GRID_FLAG_SELECTED) { |
if (selected && (~gc->flags & GRID_FLAG_SELECTED)) { |
skip = 0; |
|
memcpy(&tmp_gc, gc, sizeof tmp_gc); |
memcpy(&tmp_gc, gc, sizeof tmp_gc); |
tmp_gc.flags |= GRID_FLAG_SELECTED; |
tmp_gc.flags |= GRID_FLAG_SELECTED; |
grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); |
grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); |
} else if (!selected && gc->flags & GRID_FLAG_SELECTED) { |
} else if (!selected && (gc->flags & GRID_FLAG_SELECTED)) { |
skip = 0; |
|
memcpy(&tmp_gc, gc, sizeof tmp_gc); |
memcpy(&tmp_gc, gc, sizeof tmp_gc); |
tmp_gc.flags &= ~GRID_FLAG_SELECTED; |
tmp_gc.flags &= ~GRID_FLAG_SELECTED; |
grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); |
grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); |
} else if (!skip) |
} else if (!skip) |
grid_view_set_cell(gd, s->cx, s->cy, gc); |
grid_view_set_cell(gd, s->cx, s->cy, gc); |
|
if (selected) |
|
skip = 0; |
|
|
/* |
/* |
* Move the cursor. If not wrapping, stick at the last character and |
* Move the cursor. If not wrapping, stick at the last character and |
|
|
s->cx = sx - last; |
s->cx = sx - last; |
|
|
/* Create space for character in insert mode. */ |
/* Create space for character in insert mode. */ |
if (insert) { |
if (s->mode & MODE_INSERT) { |
|
screen_write_collect_flush(ctx); |
ttyctx.num = width; |
ttyctx.num = width; |
tty_write(tty_cmd_insertcharacter, &ttyctx); |
tty_write(tty_cmd_insertcharacter, &ttyctx); |
} |
} |
|
|
/* Write to the screen. */ |
/* Write to the screen. */ |
if (selected) { |
if (!skip) { |
screen_write_flush(ctx); |
if (selected) { |
screen_select_cell(s, &tmp_gc, gc); |
screen_select_cell(s, &tmp_gc, gc); |
ttyctx.cell = &tmp_gc; |
ttyctx.cell = &tmp_gc; |
|
} else |
|
ttyctx.cell = gc; |
tty_write(tty_cmd_cell, &ttyctx); |
tty_write(tty_cmd_cell, &ttyctx); |
ctx->written++; |
ctx->written++; |
} else if (!skip) { |
|
/* |
|
* If wp is NULL, we are not updating the terminal and don't |
|
* care about actually writing the cells (tty_write will just |
|
* return). So don't even bother allocating the dirty array. |
|
*/ |
|
if (ctx->wp != NULL && s->dirty == NULL) { |
|
log_debug("%s: allocating %u bits", __func__, |
|
s->dirtysize); |
|
s->dirty = bit_alloc(s->dirtysize); |
|
} |
|
if (s->dirty != NULL) { |
|
bit_set(s->dirty, screen_dirty_bit(s, |
|
ttyctx.ocx, ttyctx.ocy)); |
|
ctx->dirty++; |
|
} |
|
} else |
} else |
ctx->skipped++; |
ctx->skipped++; |
} |
} |