term->disptext[i]->chars[j].chr = tchar; term->disptext[i]->chars[j].attr = tattr;
if (d->cc_next) { termchar *dd = d;  while (dd->cc_next) { unsigned long schar;  dd += dd->cc_next;  schar = dd->chr; switch (schar & CSET_MASK) { case CSET_ASCII: schar = term->ucsdata->unitab_line[schar & 0xFF]; break; case CSET_LINEDRW: schar = term->ucsdata->unitab_xterm[schar & 0xFF]; break; case CSET_SCOACS: schar = term->ucsdata->unitab_scoacs[schar&0xFF]; break; }  if (ccount >= chlen) { chlen = ccount + 256; ch = sresize(ch, chlen, wchar_t); } ch[ccount++] = (wchar_t) schar; }  attr |= TATTR_COMBINING; }  if (do_copy) { copy_termchar(term->disptext[i], j, d); term->disptext[i]->chars[j].chr = tchar; term->disptext[i]->chars[j].attr = tattr; }
static void do_paint(Terminal *term, Context ctx, int may_optimise){    int i, it, j, our_curs_y, our_curs_x;    int rv, cursor;    pos scrpos;    wchar_t ch[1024];    termchar cursor_background;    unsigned long ticks;#ifdef OPTIMISE_SCROLL    struct scrollregion *sr;#endif /* OPTIMISE_SCROLL */    cursor_background = term->basic_erase_char;    /*     * Check the visual bell state.     */    if (term->in_vbell) {	ticks = GETTICKCOUNT();	if (ticks - term->vbell_startpoint >= VBELL_TIMEOUT)	    term->in_vbell = FALSE;    }    rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0);    /* Depends on:     * screen array, disptop, scrtop,     * selection, rv,      * cfg.blinkpc, blink_is_real, tblinker,      * curs.y, curs.x, blinker, cfg.blink_cur, cursor_on, has_focus, wrapnext     */    /* Has the cursor position or type changed ? */    if (term->cursor_on) {	if (term->has_focus) {	    if (term->blinker || !term->cfg.blink_cur)		cursor = TATTR_ACTCURS;	    else		cursor = 0;	} else	    cursor = TATTR_PASCURS;	if (term->wrapnext)	    cursor |= TATTR_RIGHTCURS;    } else	cursor = 0;    our_curs_y = term->curs.y - term->disptop;    {	/*	 * Adjust the cursor position in the case where it's	 * resting on the right-hand half of a CJK wide character.	 * xterm's behaviour here, which seems adequate to me, is	 * to display the cursor covering the _whole_ character,	 * exactly as if it were one space to the left.	 */	termline *ldata = lineptr(term->curs.y);	our_curs_x = term->curs.x;	if (our_curs_x > 0 &&	    ldata->chars[our_curs_x].chr == UCSWIDE)	    our_curs_x--;	unlineptr(ldata);    }    /*     * If the cursor is not where it was last time we painted, and     * its previous position is visible on screen, invalidate its     * previous position.     */    if (term->dispcursy >= 0 &&	(term->curstype != cursor ||	 term->dispcursy != our_curs_y ||	 term->dispcursx != our_curs_x)) {	termchar *dispcurs = term->disptext[term->dispcursy]->chars +	    term->dispcursx;	if (term->dispcursx > 0 && dispcurs->chr == UCSWIDE)	    dispcurs[-1].attr |= ATTR_INVALID;	if (term->dispcursx < term->cols-1 && dispcurs[1].chr == UCSWIDE)	    dispcurs[1].attr |= ATTR_INVALID;	dispcurs->attr |= ATTR_INVALID;	term->curstype = 0;    }    term->dispcursx = term->dispcursy = -1;#ifdef OPTIMISE_SCROLL    /* Do scrolls */    sr = term->scrollhead;    while (sr) {	struct scrollregion *next = sr->next;	do_scroll(ctx, sr->topline, sr->botline, sr->lines);	sfree(sr);	sr = next;    }    term->scrollhead = term->scrolltail = NULL;#endif /* OPTIMISE_SCROLL */    /* The normal screen data */    for (i = 0; i < term->rows; i++) {	termline *ldata;	termchar *lchars;	int dirty_line, dirty_run, selected;	unsigned long attr = 0, cset = 0;	int updated_line = 0;	int start = 0;	int ccount = 0;	int last_run_dirty = 0;	scrpos.y = i + term->disptop;	ldata = lineptr(scrpos.y);	dirty_run = dirty_line = (ldata->lattr !=				  term->disptext[i]->lattr);	term->disptext[i]->lattr = ldata->lattr;	/* Do Arabic shaping and bidi. */	if(!term->cfg.bidi || !term->cfg.arabicshaping) {	    if (!term_bidi_cache_hit(term, i, ldata->chars, term->cols)) {		for(it=0; it<term->cols ; it++)		{		    unsigned long uc = (ldata->chars[it].chr);		    switch (uc & CSET_MASK) {		      case CSET_LINEDRW:			if (!term->cfg.rawcnp) {			    uc = term->ucsdata->unitab_xterm[uc & 0xFF];			    break;			}		      case CSET_ASCII:			uc = term->ucsdata->unitab_line[uc & 0xFF];			break;		      case CSET_SCOACS:			uc = term->ucsdata->unitab_scoacs[uc&0xFF];			break;		    }		    switch (uc & CSET_MASK) {		      case CSET_ACP:			uc = term->ucsdata->unitab_font[uc & 0xFF];			break;		      case CSET_OEMCP:			uc = term->ucsdata->unitab_oemcp[uc & 0xFF];			break;		    }		    term->wcFrom[it].origwc = term->wcFrom[it].wc =			(wchar_t)uc;		    term->wcFrom[it].index = it;		}		if(!term->cfg.bidi)		    do_bidi(term->wcFrom, term->cols);		/* this is saved iff done from inside the shaping */		if(!term->cfg.bidi && term->cfg.arabicshaping)		    for(it=0; it<term->cols; it++)			term->wcTo[it] = term->wcFrom[it];		if(!term->cfg.arabicshaping)		    do_shape(term->wcFrom, term->wcTo, term->cols);		for(it=0; it<term->cols ; it++)		{		    term->ltemp[it] = ldata->chars[term->wcTo[it].index];		    if (term->wcTo[it].origwc != term->wcTo[it].wc)			term->ltemp[it].chr = term->wcTo[it].wc;		}		term_bidi_cache_store(term, i, ldata->chars,				      term->ltemp, term->cols);		lchars = term->ltemp;	    } else {		lchars = term->post_bidi_cache[i];	    }	} else	    lchars = ldata->chars;	for (j = 0; j < term->cols; j++) {	    unsigned long tattr, tchar;	    termchar *d = lchars + j;	    int break_run;	    scrpos.x = j;	    tchar = d->chr;	    tattr = d->attr;	    switch (tchar & CSET_MASK) {	      case CSET_ASCII:		tchar = term->ucsdata->unitab_line[tchar & 0xFF];		break;	      case CSET_LINEDRW:		tchar = term->ucsdata->unitab_xterm[tchar & 0xFF];		break;	      case CSET_SCOACS:  		tchar = term->ucsdata->unitab_scoacs[tchar&0xFF]; 		break;	    }	    if (j < term->cols-1 && d[1].chr == UCSWIDE)		tattr |= ATTR_WIDE;	    /* Video reversing things */	    if (term->selstate == DRAGGING || term->selstate == SELECTED) {		if (term->seltype == LEXICOGRAPHIC)		    selected = (posle(term->selstart, scrpos) &&				poslt(scrpos, term->selend));		else		    selected = (posPle(term->selstart, scrpos) &&				posPlt(scrpos, term->selend));	    } else		selected = FALSE;	    tattr = (tattr ^ rv		     ^ (selected ? ATTR_REVERSE : 0));	    /* 'Real' blinking ? */	    if (term->blink_is_real && (tattr & ATTR_BLINK)) {		if (term->has_focus && term->tblinker) {		    tchar = term->ucsdata->unitab_line[(unsigned char)' '];		}		tattr &= ~ATTR_BLINK;	    }	    /*	     * Check the font we'll _probably_ be using to see if 	     * the character is wide when we don't want it to be.	     */	    if (tchar != term->disptext[i]->chars[j].chr ||		tattr != (term->disptext[i]->chars[j].attr &~			  ATTR_NARROW)) {		if ((tattr & ATTR_WIDE) == 0 && char_width(ctx, tchar) == 2)		    tattr |= ATTR_NARROW;	    } else if (term->disptext[i]->chars[j].attr & ATTR_NARROW)		tattr |= ATTR_NARROW;	    /* Cursor here ? Save the 'background' */	    if (i == our_curs_y && j == our_curs_x) {		cursor_background.chr = tchar;		cursor_background.attr = tattr;		term->dispcursx = j;		term->dispcursy = i;	    }	    if ((term->disptext[i]->chars[j].attr ^ tattr) & ATTR_WIDE)		dirty_line = TRUE;	    break_run = (((tattr ^ attr) & term->attr_mask) ||		j - start >= sizeof(ch));	    /* Special hack for VT100 Linedraw glyphs */	    if (tchar >= 0x23BA && tchar <= 0x23BD)		break_run = TRUE;	    /*	     * Separate out sequences of characters that have the	     * same CSET, if that CSET is a magic one.	     */	    if (CSET_OF(tchar) != cset)		break_run = TRUE;	    if (!term->ucsdata->dbcs_screenfont && !dirty_line) {		if (term->disptext[i]->chars[j].chr == tchar &&		    term->disptext[i]->chars[j].attr == tattr)		    break_run = TRUE;		else if (!dirty_run && ccount == 1)		    break_run = TRUE;	    }	    if (break_run) {		if ((dirty_run || last_run_dirty) && ccount > 0) {		    do_text(ctx, start, i, ch, ccount, attr, ldata->lattr);		    updated_line = 1;		}		start = j;		ccount = 0;		attr = tattr;		cset = CSET_OF(tchar);		if (term->ucsdata->dbcs_screenfont)		    last_run_dirty = dirty_run;		dirty_run = dirty_line;	    }	    if (term->disptext[i]->chars[j].chr != tchar ||		term->disptext[i]->chars[j].attr != tattr)		dirty_run = TRUE;	    ch[ccount++] = (wchar_t) tchar;	    term->disptext[i]->chars[j].chr = tchar;	    term->disptext[i]->chars[j].attr = tattr;	    /* If it's a wide char step along to the next one. */	    if (tattr & ATTR_WIDE) {		if (++j < term->cols) {		    d++;		    /*		     * By construction above, the cursor should not		     * be on the right-hand half of this character.		     * Ever.		     */		    assert(!(i == our_curs_y && j == our_curs_x));		    if (memcmp(&term->disptext[i]->chars[j],			       d, sizeof(*d)))			dirty_run = TRUE;		    term->disptext[i]->chars[j] = *d;		}	    }	}	if (dirty_run && ccount > 0) {	    do_text(ctx, start, i, ch, ccount, attr, ldata->lattr);	    updated_line = 1;	}	/* Cursor on this line ? (and changed) */	if (i == our_curs_y && (term->curstype != cursor || updated_line)) {	    ch[0] = (wchar_t) cursor_background.chr;	    attr = cursor_background.attr | cursor;	    do_cursor(ctx, our_curs_x, i, ch, 1, attr, ldata->lattr);	    term->curstype = cursor;	}	unlineptr(ldata);    }}