/* Insert nx characters. */ void screen_write_insertcharacter(struct screen_write_ctx *ctx, u_int nx) { struct screen *s = ctx->s; struct tty_ctx ttyctx; if (nx == 0) nx = 1; if (nx > screen_size_x(s) - s->cx) nx = screen_size_x(s) - s->cx; if (nx == 0) return; screen_write_initctx(ctx, &ttyctx, 0); if (s->cx <= screen_size_x(s) - 1) grid_view_insert_cells(s->grid, s->cx, s->cy, nx); ttyctx.num = nx; tty_write(tty_cmd_insertcharacter, &ttyctx); }
/* Write cell data. */ void screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) { struct screen *s = ctx->s; 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_cell tmp_gc, now_gc; struct grid_cell_entry *gce; int insert, skip, selected, wrapped = 0; ctx->cells++; /* Ignore padding. */ if (gc->flags & GRID_FLAG_PADDING) return; width = gc->data.width; /* * 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 (screen_write_combine(ctx, &gc->data) == 0) { screen_write_initctx(ctx, &ttyctx); tty_write(tty_cmd_utf8character, &ttyctx); } return; } /* Initialise the redraw context. */ screen_write_initctx(ctx, &ttyctx); /* If in insert mode, make space for the cells. */ if (s->mode & MODE_INSERT) { if (s->cx <= sx - width) { screen_write_flush(ctx); 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. */ if ((s->mode & MODE_WRAP) && s->cx > sx - width) { screen_write_flush(ctx); screen_write_save_last(ctx, &ttyctx); screen_write_linefeed(ctx, 1); s->cx = 0; /* carriage return */ skip = 0; wrapped = 1; } /* Sanity check cursor position. */ if (s->cx > sx - width || s->cy > sy - 1) return; /* Handle overwriting of UTF-8 characters. */ gl = &s->grid->linedata[s->grid->hsize + s->cy]; if (gl->flags & GRID_LINE_EXTENDED) { grid_view_get_cell(gd, s->cx, s->cy, &now_gc); if (screen_write_overwrite(ctx, &now_gc, width)) skip = 0; } /* * If the new character is UTF-8 wide, fill in padding cells. Have * already ensured there is enough room. */ for (xx = s->cx + 1; xx < s->cx + width; xx++) { grid_view_set_cell(gd, xx, s->cy, &screen_write_pad_cell); skip = 0; } /* If no change, do not draw. */ if (skip) { if (s->cx >= gl->cellsize) skip = grid_cells_equal(gc, &grid_default_cell); else { gce = &gl->celldata[s->cx]; if (gce->flags & GRID_FLAG_EXTENDED) skip = 0; else if (gc->flags != gce->flags) skip = 0; else if (gc->attr != gce->data.attr) skip = 0; else if (gc->fg != gce->data.fg) skip = 0; else if (gc->bg != gce->data.bg) skip = 0; else if (gc->data.width != 1) skip = 0; else if (gce->data.data != gc->data.data[0]) skip = 0; } } /* Update the selection the flag and set the cell. */ selected = screen_check_selection(s, s->cx, s->cy); if (selected && ~gc->flags & GRID_FLAG_SELECTED) { skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags |= GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!selected && gc->flags & GRID_FLAG_SELECTED) { skip = 0; memcpy(&tmp_gc, gc, sizeof tmp_gc); tmp_gc.flags &= ~GRID_FLAG_SELECTED; grid_view_set_cell(gd, s->cx, s->cy, &tmp_gc); } else if (!skip) grid_view_set_cell(gd, s->cx, s->cy, gc); /* * Move the cursor. If not wrapping, stick at the last character and * replace it. */ last = !(s->mode & MODE_WRAP); if (s->cx <= sx - last - width) s->cx += width; else s->cx = sx - last; /* Create space for character in insert mode. */ if (insert) { ttyctx.num = width; tty_write(tty_cmd_insertcharacter, &ttyctx); } /* Write to the screen. */ if (selected) { screen_write_flush(ctx); screen_select_cell(s, &tmp_gc, gc); ttyctx.cell = &tmp_gc; tty_write(tty_cmd_cell, &ttyctx); ctx->written++; } else if (!skip) { if (wrapped) { ttyctx.cell = gc; tty_write(tty_cmd_cell, &ttyctx); ctx->written++; } else { /* * 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 ctx->skipped++; }