version 1.192, 2021/01/27 10:42:52 |
version 1.193, 2021/01/29 09:48:43 |
|
|
|
|
#include "tmux.h" |
#include "tmux.h" |
|
|
|
static struct screen_write_citem *screen_write_collect_trim( |
|
struct screen_write_ctx *, u_int, u_int, u_int, int *); |
static void screen_write_collect_clear(struct screen_write_ctx *, u_int, |
static void screen_write_collect_clear(struct screen_write_ctx *, u_int, |
u_int); |
u_int); |
static void screen_write_collect_clear_end(struct screen_write_ctx *, u_int, |
static void screen_write_collect_scroll(struct screen_write_ctx *, u_int); |
u_int); |
|
static void screen_write_collect_clear_start(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 *, int, |
static void screen_write_collect_flush(struct screen_write_ctx *, int, |
const char *); |
const char *); |
|
|
|
|
static const struct grid_cell *screen_write_combine(struct screen_write_ctx *, |
static const struct grid_cell *screen_write_combine(struct screen_write_ctx *, |
const struct utf8_data *, u_int *); |
const struct utf8_data *, u_int *); |
|
|
struct screen_write_collect_item { |
struct screen_write_citem { |
u_int x; |
u_int x; |
int wrapped; |
int wrapped; |
|
|
enum { TEXT, CLEAR_END, CLEAR_START } type; |
enum { TEXT, CLEAR } type; |
u_int used; |
u_int used; |
u_int bg; |
u_int bg; |
|
|
struct grid_cell gc; |
struct grid_cell gc; |
|
|
TAILQ_ENTRY(screen_write_collect_item) entry; |
TAILQ_ENTRY(screen_write_citem) entry; |
}; |
}; |
struct screen_write_collect_line { |
struct screen_write_cline { |
u_int bg; |
char *data; |
char *data; |
TAILQ_HEAD(, screen_write_citem) items; |
TAILQ_HEAD(, screen_write_collect_item) items; |
|
}; |
}; |
|
TAILQ_HEAD(, screen_write_citem) screen_write_citem_freelist = |
|
TAILQ_HEAD_INITIALIZER(screen_write_citem_freelist); |
|
|
|
static struct screen_write_citem * |
|
screen_write_get_citem(void) |
|
{ |
|
struct screen_write_citem *ci; |
|
|
|
ci = TAILQ_FIRST(&screen_write_citem_freelist); |
|
if (ci != NULL) { |
|
TAILQ_REMOVE(&screen_write_citem_freelist, ci, entry); |
|
memset(ci, 0, sizeof *ci); |
|
return (ci); |
|
} |
|
return (xcalloc(1, sizeof *ci)); |
|
} |
|
|
static void |
static void |
|
screen_write_free_citem(struct screen_write_citem *ci) |
|
{ |
|
TAILQ_INSERT_TAIL(&screen_write_citem_freelist, ci, entry); |
|
} |
|
|
|
static void |
screen_write_offset_timer(__unused int fd, __unused short events, void *data) |
screen_write_offset_timer(__unused int fd, __unused short events, void *data) |
{ |
{ |
struct window *w = data; |
struct window *w = data; |
|
|
* Redraw is already deferred to redraw another pane - redraw |
* Redraw is already deferred to redraw another pane - redraw |
* this one also when that happens. |
* this one also when that happens. |
*/ |
*/ |
log_debug("adding %%%u to deferred redraw", wp->id); |
log_debug("%s: adding %%%u to deferred redraw", __func__, |
|
wp->id); |
wp->flags |= PANE_REDRAW; |
wp->flags |= PANE_REDRAW; |
return (-1); |
return (-1); |
} |
} |
|
|
|
|
if (ctx->s->write_list == NULL) |
if (ctx->s->write_list == NULL) |
screen_write_make_list(ctx->s); |
screen_write_make_list(ctx->s); |
ctx->item = xcalloc(1, sizeof *ctx->item); |
ctx->item = screen_write_get_citem(); |
|
|
ctx->scrolled = 0; |
ctx->scrolled = 0; |
ctx->bg = 8; |
ctx->bg = 8; |
|
|
screen_write_collect_end(ctx); |
screen_write_collect_end(ctx); |
screen_write_collect_flush(ctx, 0, __func__); |
screen_write_collect_flush(ctx, 0, __func__); |
|
|
log_debug("%s: %u cells (%u written, %u skipped)", __func__, |
screen_write_free_citem(ctx->item); |
ctx->cells, ctx->written, ctx->skipped); |
|
if (ctx->wp != NULL) { |
|
ctx->wp->written += ctx->written; |
|
ctx->wp->skipped += ctx->skipped; |
|
} |
|
|
|
free(ctx->item); |
|
} |
} |
|
|
/* Reset screen state. */ |
/* Reset screen state. */ |
|
|
void |
void |
screen_write_clearline(struct screen_write_ctx *ctx, u_int bg) |
screen_write_clearline(struct screen_write_ctx *ctx, u_int bg) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct grid_line *gl; |
struct grid_line *gl; |
u_int sx = screen_size_x(s); |
u_int sx = screen_size_x(s); |
|
struct screen_write_citem *ci = ctx->item; |
|
|
gl = grid_get_line(s->grid, s->grid->hsize + s->cy); |
gl = grid_get_line(s->grid, s->grid->hsize + s->cy); |
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg)) |
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg)) |
|
|
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); |
screen_write_collect_clear(ctx, s->cy, 1); |
ctx->s->write_list[s->cy].bg = 1 + bg; |
ci->x = 0; |
ctx->item->used = 0; |
ci->used = sx; |
|
ci->type = CLEAR; |
|
ci->bg = bg; |
|
TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); |
|
ctx->item = screen_write_get_citem(); |
} |
} |
|
|
/* Clear to end of line from cursor. */ |
/* Clear to end of line from cursor. */ |
void |
void |
screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) |
screen_write_clearendofline(struct screen_write_ctx *ctx, u_int bg) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct grid_line *gl; |
struct grid_line *gl; |
u_int sx = screen_size_x(s); |
u_int sx = screen_size_x(s); |
struct screen_write_collect_item *ci = ctx->item; |
struct screen_write_citem *ci = ctx->item, *before; |
|
|
if (s->cx == 0) { |
if (s->cx == 0) { |
screen_write_clearline(ctx, bg); |
screen_write_clearline(ctx, bg); |
|
|
|
|
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); |
|
|
screen_write_collect_clear_end(ctx, s->cy, s->cx); |
before = screen_write_collect_trim(ctx, s->cy, s->cx, sx - s->cx, NULL); |
ci->x = s->cx; |
ci->x = s->cx; |
ci->type = CLEAR_END; |
ci->used = sx - s->cx; |
|
ci->type = CLEAR; |
ci->bg = bg; |
ci->bg = bg; |
TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); |
if (before == NULL) |
ctx->item = xcalloc(1, sizeof *ctx->item); |
TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); |
|
else |
|
TAILQ_INSERT_BEFORE(before, ci, entry); |
|
ctx->item = screen_write_get_citem(); |
} |
} |
|
|
/* Clear to start of line from cursor. */ |
/* Clear to start of line from cursor. */ |
|
|
screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) |
screen_write_clearstartofline(struct screen_write_ctx *ctx, u_int bg) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
u_int sx = screen_size_x(s); |
u_int sx = screen_size_x(s); |
struct screen_write_collect_item *ci = ctx->item; |
struct screen_write_citem *ci = ctx->item, *before; |
|
|
if (s->cx >= sx - 1) { |
if (s->cx >= sx - 1) { |
screen_write_clearline(ctx, bg); |
screen_write_clearline(ctx, bg); |
|
|
else |
else |
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); |
|
|
screen_write_collect_clear_start(ctx, s->cy, s->cx); |
before = screen_write_collect_trim(ctx, s->cy, 0, s->cx + 1, NULL); |
ci->x = s->cx; |
ci->x = 0; |
ci->type = CLEAR_START; |
ci->used = s->cx + 1; |
|
ci->type = CLEAR; |
ci->bg = bg; |
ci->bg = bg; |
TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); |
if (before == NULL) |
ctx->item = xcalloc(1, sizeof *ctx->item); |
TAILQ_INSERT_TAIL(&ctx->s->write_list[s->cy].items, ci, entry); |
|
else |
|
TAILQ_INSERT_BEFORE(before, ci, entry); |
|
ctx->item = screen_write_get_citem(); |
} |
} |
|
|
/* Move cursor to px,py. */ |
/* Move cursor to px,py. */ |
|
|
if (py != -1 && (u_int)py > screen_size_y(s) - 1) |
if (py != -1 && (u_int)py > screen_size_y(s) - 1) |
py = screen_size_y(s) - 1; |
py = screen_size_y(s) - 1; |
|
|
|
log_debug("%s: from %u,%u to %u,%u", __func__, s->cx, s->cy, px, py); |
screen_write_set_cursor(ctx, px, py); |
screen_write_set_cursor(ctx, px, py); |
} |
} |
|
|
|
|
|
|
if (s->cy == s->rlower) { |
if (s->cy == s->rlower) { |
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); |
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); |
screen_write_collect_scroll(ctx); |
screen_write_collect_scroll(ctx, bg); |
ctx->scrolled++; |
ctx->scrolled++; |
} else if (s->cy < screen_size_y(s) - 1) |
} else if (s->cy < screen_size_y(s) - 1) |
screen_write_set_cursor(ctx, -1, s->cy + 1); |
screen_write_set_cursor(ctx, -1, s->cy + 1); |
|
|
|
|
for (i = 0; i < lines; i++) { |
for (i = 0; i < lines; i++) { |
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); |
grid_view_scroll_region_up(gd, s->rupper, s->rlower, bg); |
screen_write_collect_scroll(ctx); |
screen_write_collect_scroll(ctx, bg); |
} |
} |
ctx->scrolled += lines; |
ctx->scrolled += lines; |
} |
} |
|
|
grid_clear_history(ctx->s->grid); |
grid_clear_history(ctx->s->grid); |
} |
} |
|
|
/* Clear to start of a collected line. */ |
/* Trim collected items. */ |
static void |
static struct screen_write_citem * |
screen_write_collect_clear_start(struct screen_write_ctx *ctx, u_int y, u_int x) |
screen_write_collect_trim(struct screen_write_ctx *ctx, u_int y, u_int x, |
|
u_int used, int *wrapped) |
{ |
{ |
struct screen_write_collect_item *ci, *tmp; |
struct screen_write_cline *cl = &ctx->s->write_list[y]; |
size_t size = 0; |
struct screen_write_citem *ci, *ci2, *tmp, *before = NULL; |
u_int items = 0; |
u_int sx = x, ex = x + used - 1; |
|
u_int csx, cex; |
|
|
if (TAILQ_EMPTY(&ctx->s->write_list[y].items)) |
if (TAILQ_EMPTY(&cl->items)) |
return; |
return (NULL); |
TAILQ_FOREACH_SAFE(ci, &ctx->s->write_list[y].items, entry, tmp) { |
TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { |
switch (ci->type) { |
csx = ci->x; |
case CLEAR_START: |
cex = ci->x + ci->used - 1; |
break; |
|
case CLEAR_END: |
/* Item is entirely before. */ |
if (ci->x <= x) |
if (cex < sx) { |
ci->x = x; |
log_debug("%s: %p %u-%u before %u-%u", __func__, ci, |
|
csx, cex, sx, ex); |
continue; |
continue; |
case TEXT: |
} |
if (ci->x > x) |
|
continue; |
/* Item is entirely after. */ |
|
if (csx > ex) { |
|
log_debug("%s: %p %u-%u after %u-%u", __func__, ci, |
|
csx, cex, sx, ex); |
|
before = ci; |
break; |
break; |
} |
} |
items++; |
|
size += ci->used; |
|
TAILQ_REMOVE(&ctx->s->write_list[y].items, ci, entry); |
|
free(ci); |
|
} |
|
ctx->skipped += size; |
|
log_debug("%s: dropped %u items (%zu bytes) (line %u)", __func__, items, |
|
size, y); |
|
} |
|
|
|
/* Clear to end of a collected line. */ |
/* Item is entirely inside. */ |
static void |
if (csx >= sx && cex <= ex) { |
screen_write_collect_clear_end(struct screen_write_ctx *ctx, u_int y, u_int x) |
log_debug("%s: %p %u-%u inside %u-%u", __func__, ci, |
{ |
csx, cex, sx, ex); |
struct screen_write_collect_item *ci, *tmp; |
TAILQ_REMOVE(&cl->items, ci, entry); |
size_t size = 0; |
screen_write_free_citem(ci); |
u_int items = 0; |
if (csx == 0 && ci->wrapped && wrapped != NULL) |
|
*wrapped = 1; |
|
continue; |
|
} |
|
|
if (TAILQ_EMPTY(&ctx->s->write_list[y].items)) |
/* Item under the start. */ |
return; |
if (csx < sx && cex >= sx && cex <= ex) { |
TAILQ_FOREACH_SAFE(ci, &ctx->s->write_list[y].items, entry, tmp) { |
log_debug("%s: %p %u-%u start %u-%u", __func__, ci, |
switch (ci->type) { |
csx, cex, sx, ex); |
case CLEAR_START: |
ci->used = sx - csx; |
if (ci->x >= x) |
log_debug("%s: %p now %u-%u", __func__, ci, ci->x, |
ci->x = x; |
ci->x + ci->used + 1); |
continue; |
continue; |
case CLEAR_END: |
} |
|
|
|
/* Item covers the end. */ |
|
if (cex > ex && csx >= sx && csx <= ex) { |
|
log_debug("%s: %p %u-%u end %u-%u", __func__, ci, |
|
csx, cex, sx, ex); |
|
ci->x = ex + 1; |
|
ci->used = cex - ex; |
|
log_debug("%s: %p now %u-%u", __func__, ci, ci->x, |
|
ci->x + ci->used + 1); |
|
before = ci; |
break; |
break; |
case TEXT: |
|
if (ci->x < x) |
|
continue; |
|
break; |
|
} |
} |
items++; |
|
size += ci->used; |
/* Item must cover both sides. */ |
TAILQ_REMOVE(&ctx->s->write_list[y].items, ci, entry); |
log_debug("%s: %p %u-%u under %u-%u", __func__, ci, |
free(ci); |
csx, cex, sx, ex); |
|
ci2 = screen_write_get_citem(); |
|
ci2->type = ci->type; |
|
ci2->bg = ci->bg; |
|
memcpy(&ci2->gc, &ci->gc, sizeof ci2->gc); |
|
TAILQ_INSERT_AFTER(&cl->items, ci, ci2, entry); |
|
|
|
ci->used = sx - csx; |
|
ci2->x = ex + 1; |
|
ci2->used = cex - ex; |
|
|
|
log_debug("%s: %p now %u-%u (%p) and %u-%u (%p)", __func__, ci, |
|
ci->x, ci->x + ci->used - 1, ci, ci2->x, |
|
ci2->x + ci2->used - 1, ci2); |
|
before = ci2; |
|
break; |
} |
} |
ctx->skipped += size; |
return (before); |
log_debug("%s: dropped %u items (%zu bytes) (line %u)", __func__, items, |
|
size, y); |
|
} |
} |
|
|
/* Clear collected lines. */ |
/* Clear collected lines. */ |
static void |
static void |
screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) |
screen_write_collect_clear(struct screen_write_ctx *ctx, u_int y, u_int n) |
{ |
{ |
struct screen_write_collect_item *ci, *tmp; |
struct screen_write_cline *cl; |
struct screen_write_collect_line *cl; |
u_int i; |
u_int i, items; |
|
size_t size; |
|
|
|
for (i = y; i < y + n; i++) { |
for (i = y; i < y + n; i++) { |
if (TAILQ_EMPTY(&ctx->s->write_list[i].items)) |
|
continue; |
|
items = 0; |
|
size = 0; |
|
cl = &ctx->s->write_list[i]; |
cl = &ctx->s->write_list[i]; |
TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { |
TAILQ_CONCAT(&screen_write_citem_freelist, &cl->items, entry); |
items++; |
|
size += ci->used; |
|
TAILQ_REMOVE(&cl->items, ci, entry); |
|
free(ci); |
|
} |
|
ctx->skipped += size; |
|
log_debug("%s: dropped %u items (%zu bytes) (line %u)", |
|
__func__, items, size, y); |
|
} |
} |
} |
} |
|
|
/* Scroll collected lines up. */ |
/* Scroll collected lines up. */ |
static void |
static void |
screen_write_collect_scroll(struct screen_write_ctx *ctx) |
screen_write_collect_scroll(struct screen_write_ctx *ctx, u_int bg) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct screen_write_collect_line *cl; |
struct screen_write_cline *cl; |
u_int y; |
u_int y; |
char *saved; |
char *saved; |
|
struct screen_write_citem *ci; |
|
|
log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, |
log_debug("%s: at %u,%u (region %u-%u)", __func__, s->cx, s->cy, |
s->rupper, s->rlower); |
s->rupper, s->rlower); |
|
|
for (y = s->rupper; y < s->rlower; y++) { |
for (y = s->rupper; y < s->rlower; y++) { |
cl = &ctx->s->write_list[y + 1]; |
cl = &ctx->s->write_list[y + 1]; |
TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry); |
TAILQ_CONCAT(&ctx->s->write_list[y].items, &cl->items, entry); |
ctx->s->write_list[y].bg = cl->bg; |
|
ctx->s->write_list[y].data = cl->data; |
ctx->s->write_list[y].data = cl->data; |
} |
} |
ctx->s->write_list[s->rlower].bg = 1 + 8; |
|
ctx->s->write_list[s->rlower].data = saved; |
ctx->s->write_list[s->rlower].data = saved; |
|
|
|
ci = screen_write_get_citem(); |
|
ci->x = 0; |
|
ci->used = screen_size_x(s); |
|
ci->type = CLEAR; |
|
ci->bg = bg; |
|
TAILQ_INSERT_TAIL(&ctx->s->write_list[s->rlower].items, ci, entry); |
} |
} |
|
|
/* Flush collected lines. */ |
/* Flush collected lines. */ |
|
|
screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, |
screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, |
const char *from) |
const char *from) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct screen_write_collect_item *ci, *tmp; |
struct screen_write_citem *ci, *tmp; |
struct screen_write_collect_line *cl; |
struct screen_write_cline *cl; |
u_int y, cx, cy, items = 0; |
u_int y, cx, cy, last, items = 0; |
struct tty_ctx ttyctx; |
struct tty_ctx ttyctx; |
size_t written = 0; |
|
|
|
if (ctx->scrolled != 0) { |
if (ctx->scrolled != 0) { |
log_debug("%s: scrolled %u (region %u-%u)", __func__, |
log_debug("%s: scrolled %u (region %u-%u)", __func__, |
|
|
cx = s->cx; cy = s->cy; |
cx = s->cx; cy = s->cy; |
for (y = 0; y < screen_size_y(s); y++) { |
for (y = 0; y < screen_size_y(s); y++) { |
cl = &ctx->s->write_list[y]; |
cl = &ctx->s->write_list[y]; |
if (cl->bg != 0) { |
last = UINT_MAX; |
screen_write_set_cursor(ctx, 0, y); |
|
screen_write_initctx(ctx, &ttyctx, 1); |
|
ttyctx.bg = cl->bg - 1; |
|
tty_write(tty_cmd_clearline, &ttyctx); |
|
} |
|
TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { |
TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { |
|
if (last != UINT_MAX && ci->x <= last) { |
|
fatalx("collect list not in order: %u <= %u", |
|
ci->x, last); |
|
} |
screen_write_set_cursor(ctx, ci->x, y); |
screen_write_set_cursor(ctx, ci->x, y); |
if (ci->type == CLEAR_END) { |
if (ci->type == CLEAR) { |
screen_write_initctx(ctx, &ttyctx, 1); |
screen_write_initctx(ctx, &ttyctx, 1); |
ttyctx.bg = ci->bg; |
ttyctx.bg = ci->bg; |
tty_write(tty_cmd_clearendofline, &ttyctx); |
ttyctx.num = ci->used; |
} else if (ci->type == CLEAR_START) { |
tty_write(tty_cmd_clearcharacter, &ttyctx); |
screen_write_initctx(ctx, &ttyctx, 1); |
|
ttyctx.bg = ci->bg; |
|
tty_write(tty_cmd_clearstartofline, &ttyctx); |
|
} else { |
} else { |
screen_write_initctx(ctx, &ttyctx, 0); |
screen_write_initctx(ctx, &ttyctx, 0); |
ttyctx.cell = &ci->gc; |
ttyctx.cell = &ci->gc; |
|
|
ttyctx.num = ci->used; |
ttyctx.num = ci->used; |
tty_write(tty_cmd_cells, &ttyctx); |
tty_write(tty_cmd_cells, &ttyctx); |
} |
} |
|
|
items++; |
items++; |
written += ci->used; |
|
|
|
TAILQ_REMOVE(&cl->items, ci, entry); |
TAILQ_REMOVE(&cl->items, ci, entry); |
free(ci); |
screen_write_free_citem(ci); |
|
last = ci->x; |
} |
} |
cl->bg = 0; |
|
} |
} |
s->cx = cx; s->cy = cy; |
s->cx = cx; s->cy = cy; |
|
|
log_debug("%s: flushed %u items (%zu bytes) (%s)", __func__, items, |
log_debug("%s: flushed %u items (%s)", __func__, items, from); |
written, from); |
|
ctx->written += written; |
|
} |
} |
|
|
/* Finish and store collected cells. */ |
/* Finish and store collected cells. */ |
void |
void |
screen_write_collect_end(struct screen_write_ctx *ctx) |
screen_write_collect_end(struct screen_write_ctx *ctx) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct screen_write_collect_item *ci = ctx->item; |
struct screen_write_citem *ci = ctx->item, *before; |
struct screen_write_collect_line *cl = &s->write_list[s->cy]; |
struct screen_write_cline *cl = &s->write_list[s->cy]; |
struct grid_cell gc; |
struct grid_cell gc; |
u_int xx; |
u_int xx; |
|
int wrapped = ci->wrapped; |
|
|
if (ci->used == 0) |
if (ci->used == 0) |
return; |
return; |
|
|
|
before = screen_write_collect_trim(ctx, s->cy, s->cx, ci->used, |
|
&wrapped); |
ci->x = s->cx; |
ci->x = s->cx; |
TAILQ_INSERT_TAIL(&cl->items, ci, entry); |
ci->wrapped = wrapped; |
ctx->item = xcalloc(1, sizeof *ctx->item); |
if (before == NULL) |
|
TAILQ_INSERT_TAIL(&cl->items, ci, entry); |
|
else |
|
TAILQ_INSERT_BEFORE(before, ci, entry); |
|
ctx->item = screen_write_get_citem(); |
|
|
log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used, |
log_debug("%s: %u %.*s (at %u,%u)", __func__, ci->used, |
(int)ci->used, cl->data + ci->x, s->cx, s->cy); |
(int)ci->used, cl->data + ci->x, s->cx, s->cy); |
|
|
screen_write_collect_add(struct screen_write_ctx *ctx, |
screen_write_collect_add(struct screen_write_ctx *ctx, |
const struct grid_cell *gc) |
const struct grid_cell *gc) |
{ |
{ |
struct screen *s = ctx->s; |
struct screen *s = ctx->s; |
struct screen_write_collect_item *ci; |
struct screen_write_citem *ci; |
u_int sx = screen_size_x(s); |
u_int sx = screen_size_x(s); |
int collect; |
int collect; |
|
|
/* |
/* |
* Don't need to check that the attributes and whatnot are still the |
* Don't need to check that the attributes and whatnot are still the |
|
|
screen_write_cell(ctx, gc); |
screen_write_cell(ctx, gc); |
return; |
return; |
} |
} |
ctx->cells++; |
|
|
|
if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) |
if (s->cx > sx - 1 || ctx->item->used > sx - 1 - s->cx) |
screen_write_collect_end(ctx); |
screen_write_collect_end(ctx); |
|
|
/* Ignore padding cells. */ |
/* Ignore padding cells. */ |
if (gc->flags & GRID_FLAG_PADDING) |
if (gc->flags & GRID_FLAG_PADDING) |
return; |
return; |
ctx->cells++; |
|
|
|
/* If the width is zero, combine onto the previous character. */ |
/* If the width is zero, combine onto the previous character. */ |
if (width == 0) { |
if (width == 0) { |
|
|
} else |
} else |
ttyctx.cell = gc; |
ttyctx.cell = gc; |
tty_write(tty_cmd_cell, &ttyctx); |
tty_write(tty_cmd_cell, &ttyctx); |
ctx->written++; |
} |
} else |
|
ctx->skipped++; |
|
} |
} |
|
|
/* Combine a UTF-8 zero-width character onto the previous. */ |
/* Combine a UTF-8 zero-width character onto the previous. */ |