/* FULL-TERMCHAR */
if (a->chr != bchr)
return FALSE;
- if (a->attr != battr)
+ if ((a->attr &~ DATTR_MASK) != (battr &~ DATTR_MASK))
return FALSE;
while (a->cc_next || b->cc_next) {
if (!a->cc_next || !b->cc_next)
* store a two-byte value with the top bit clear (indicating
* just that value), or a four-byte value with the top bit set
* (indicating the same value with its top bit clear).
+ *
+ * However, first I permute the bits of the attribute value, so
+ * that the eight bits of colour (four in each of fg and bg)
+ * which are never non-zero unless xterm 256-colour mode is in
+ * use are placed higher up the word than everything else. This
+ * ensures that attribute values remain 16-bit _unless_ the
+ * user uses extended colour.
*/
- if (c->attr < 0x8000) {
- add(b, (unsigned char)((c->attr >> 8) & 0xFF));
- add(b, (unsigned char)(c->attr & 0xFF));
+ unsigned attr, colourbits;
+
+ attr = c->attr;
+
+ assert(ATTR_BGSHIFT > ATTR_FGSHIFT);
+
+ colourbits = (attr >> (ATTR_BGSHIFT + 4)) & 0xF;
+ colourbits <<= 4;
+ colourbits |= (attr >> (ATTR_FGSHIFT + 4)) & 0xF;
+
+ attr = (((attr >> (ATTR_BGSHIFT + 8)) << (ATTR_BGSHIFT + 4)) |
+ (attr & ((1 << (ATTR_BGSHIFT + 4))-1)));
+ attr = (((attr >> (ATTR_FGSHIFT + 8)) << (ATTR_FGSHIFT + 4)) |
+ (attr & ((1 << (ATTR_FGSHIFT + 4))-1)));
+
+ attr |= (colourbits << (32-9));
+
+ if (attr < 0x8000) {
+ add(b, (unsigned char)((attr >> 8) & 0xFF));
+ add(b, (unsigned char)(attr & 0xFF));
} else {
- add(b, (unsigned char)(((c->attr >> 24) & 0x7F) | 0x80));
- add(b, (unsigned char)((c->attr >> 16) & 0xFF));
- add(b, (unsigned char)((c->attr >> 8) & 0xFF));
- add(b, (unsigned char)(c->attr & 0xFF));
+ add(b, (unsigned char)(((attr >> 24) & 0x7F) | 0x80));
+ add(b, (unsigned char)((attr >> 16) & 0xFF));
+ add(b, (unsigned char)((attr >> 8) & 0xFF));
+ add(b, (unsigned char)(attr & 0xFF));
}
}
static void makeliteral_cc(struct buf *b, termchar *c, unsigned long *state)
static void readliteral_attr(struct buf *b, termchar *c, termline *ldata,
unsigned long *state)
{
- int val;
+ unsigned val, attr, colourbits;
val = get(b) << 8;
val |= get(b);
if (val >= 0x8000) {
+ val &= ~0x8000;
val <<= 16;
val |= get(b) << 8;
val |= get(b);
}
- c->attr = val;
+ colourbits = (val >> (32-9)) & 0xFF;
+ attr = (val & ((1<<(32-9))-1));
+
+ attr = (((attr >> (ATTR_FGSHIFT + 4)) << (ATTR_FGSHIFT + 8)) |
+ (attr & ((1 << (ATTR_FGSHIFT + 4))-1)));
+ attr = (((attr >> (ATTR_BGSHIFT + 4)) << (ATTR_BGSHIFT + 8)) |
+ (attr & ((1 << (ATTR_BGSHIFT + 4))-1)));
+
+ attr |= (colourbits >> 4) << (ATTR_BGSHIFT + 4);
+ attr |= (colourbits & 0xF) << (ATTR_FGSHIFT + 4);
+
+ c->attr = attr;
}
static void readliteral_cc(struct buf *b, termchar *c, termline *ldata,
unsigned long *state)
term_update(term);
}
+static void term_schedule_update(Terminal *term)
+{
+ if (!term->window_update_pending) {
+ term->window_update_pending = TRUE;
+ term->next_update = schedule_timer(UPDATE_DELAY, term_timer, term);
+ }
+}
+
/*
* Call this whenever the terminal window state changes, to queue
* an update.
static void seen_disp_event(Terminal *term)
{
term->seen_disp_event = TRUE; /* for scrollback-reset-on-activity */
- if (!term->window_update_pending) {
- term->window_update_pending = TRUE;
- term->next_update = schedule_timer(UPDATE_DELAY, term_timer, term);
- }
+ term_schedule_update(term);
}
/*
*/
static void term_schedule_tblink(Terminal *term)
{
- if (term->tblink_pending)
- return; /* already well in hand */
if (term->blink_is_real) {
- term->next_tblink = schedule_timer(TBLINK_DELAY, term_timer, term);
+ if (!term->tblink_pending)
+ term->next_tblink = schedule_timer(TBLINK_DELAY, term_timer, term);
term->tblink_pending = TRUE;
} else {
term->tblinker = 1; /* reset when not in use */
*/
static void term_schedule_cblink(Terminal *term)
{
- if (term->cblink_pending)
- return; /* already well in hand */
- if (term->cfg.blink_cur) {
- term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term);
+ if (term->cfg.blink_cur && term->has_focus) {
+ if (!term->cblink_pending)
+ term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term);
term->cblink_pending = TRUE;
} else {
term->cblinker = 1; /* reset when not in use */
else if (term->curs.y < term->rows - 1)
term->curs.y++;
term->curs.x = 0;
+ cline = scrlineptr(term->curs.y);
/* Now we must check_boundary again, of course. */
check_boundary(term, term->curs.x, term->curs.y);
check_boundary(term, term->curs.x+2, term->curs.y);
/* xterm-style bright foreground */
term->curr_attr &= ~ATTR_FGMASK;
term->curr_attr |=
- ((term->esc_args[i] - 90 + 16)
+ ((term->esc_args[i] - 90 + 8)
<< ATTR_FGSHIFT);
break;
case 39: /* default-foreground */
/* xterm-style bright background */
term->curr_attr &= ~ATTR_BGMASK;
term->curr_attr |=
- ((term->esc_args[i] - 100 + 16)
+ ((term->esc_args[i] - 100 + 8)
<< ATTR_BGSHIFT);
break;
case 49: /* default-background */
term->curr_attr &= ~ATTR_BGMASK;
term->curr_attr |= ATTR_DEFBG;
break;
+ case 38: /* xterm 256-colour mode */
+ if (i+2 < term->esc_nargs &&
+ term->esc_args[i+1] == 5) {
+ term->curr_attr &= ~ATTR_FGMASK;
+ term->curr_attr |=
+ ((term->esc_args[i+2] & 0xFF)
+ << ATTR_FGSHIFT);
+ i += 2;
+ }
+ break;
+ case 48: /* xterm 256-colour mode */
+ if (i+2 < term->esc_nargs &&
+ term->esc_args[i+1] == 5) {
+ term->curr_attr &= ~ATTR_BGMASK;
+ term->curr_attr |=
+ ((term->esc_args[i+2] & 0xFF)
+ << ATTR_BGSHIFT);
+ i += 2;
+ }
+ break;
}
}
set_erase_char(term);
if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
long colour =
(sco2ansicolour[term->esc_args[0] & 0x7] |
- ((term->esc_args[0] & 0x8) << 1)) <<
+ (term->esc_args[0] & 0x8)) <<
ATTR_FGSHIFT;
term->curr_attr &= ~ATTR_FGMASK;
term->curr_attr |= colour;
if (term->esc_args[0] >= 0 && term->esc_args[0] < 16) {
long colour =
(sco2ansicolour[term->esc_args[0] & 0x7] |
- ((term->esc_args[0] & 0x8) << 1)) <<
+ (term->esc_args[0] & 0x8)) <<
ATTR_BGSHIFT;
term->curr_attr &= ~ATTR_BGMASK;
term->curr_attr |= colour;
term->termstate = TOPLEVEL;
term->curr_attr &= ~ATTR_FGMASK;
term->curr_attr &= ~ATTR_BOLD;
- term->curr_attr |= (c & 0x7) << ATTR_FGSHIFT;
- if ((c & 0x8) || term->vt52_bold)
- term->curr_attr |= ATTR_BOLD;
-
+ term->curr_attr |= (c & 0xF) << ATTR_FGSHIFT;
set_erase_char(term);
break;
case VT52_BG:
term->termstate = TOPLEVEL;
term->curr_attr &= ~ATTR_BGMASK;
term->curr_attr &= ~ATTR_BLINK;
- term->curr_attr |= (c & 0x7) << ATTR_BGSHIFT;
-
- /* Note: bold background */
- if (c & 0x8)
- term->curr_attr |= ATTR_BLINK;
-
+ term->curr_attr |= (c & 0xF) << ATTR_BGSHIFT;
set_erase_char(term);
break;
#endif
}
term_print_flush(term);
- logflush(term->logctx);
+ if (term->cfg.logflush)
+ logflush(term->logctx);
}
/*
}
static void term_bidi_cache_store(Terminal *term, int line, termchar *lbefore,
- termchar *lafter, int width)
+ termchar *lafter, bidi_char *wcTo,
+ int width, int size)
{
+ int i;
+
if (!term->pre_bidi_cache || term->bidi_cache_size <= line) {
int j = term->bidi_cache_size;
term->bidi_cache_size = line+1;
term->post_bidi_cache[j].chars = NULL;
term->pre_bidi_cache[j].width =
term->post_bidi_cache[j].width = -1;
+ term->pre_bidi_cache[j].forward =
+ term->post_bidi_cache[j].forward = NULL;
+ term->pre_bidi_cache[j].backward =
+ term->post_bidi_cache[j].backward = NULL;
j++;
}
}
sfree(term->pre_bidi_cache[line].chars);
sfree(term->post_bidi_cache[line].chars);
+ sfree(term->post_bidi_cache[line].forward);
+ sfree(term->post_bidi_cache[line].backward);
term->pre_bidi_cache[line].width = width;
- term->pre_bidi_cache[line].chars = snewn(width, termchar);
+ term->pre_bidi_cache[line].chars = snewn(size, termchar);
term->post_bidi_cache[line].width = width;
- term->post_bidi_cache[line].chars = snewn(width, termchar);
+ term->post_bidi_cache[line].chars = snewn(size, termchar);
+ term->post_bidi_cache[line].forward = snewn(width, int);
+ term->post_bidi_cache[line].backward = snewn(width, int);
+
+ memcpy(term->pre_bidi_cache[line].chars, lbefore, size * TSIZE);
+ memcpy(term->post_bidi_cache[line].chars, lafter, size * TSIZE);
+ memset(term->post_bidi_cache[line].forward, 0, width * sizeof(int));
+ memset(term->post_bidi_cache[line].backward, 0, width * sizeof(int));
+
+ for (i = 0; i < width; i++) {
+ int p = wcTo[i].index;
+
+ assert(0 <= p && p < width);
+
+ term->post_bidi_cache[line].backward[i] = p;
+ term->post_bidi_cache[line].forward[p] = i;
+ }
+}
+
+/*
+ * Prepare the bidi information for a screen line. Returns the
+ * transformed list of termchars, or NULL if no transformation at
+ * all took place (because bidi is disabled). If return was
+ * non-NULL, auxiliary information such as the forward and reverse
+ * mappings of permutation position are available in
+ * term->post_bidi_cache[scr_y].*.
+ */
+static termchar *term_bidi_line(Terminal *term, struct termline *ldata,
+ int scr_y)
+{
+ termchar *lchars;
+ int it;
+
+ /* Do Arabic shaping and bidi. */
+ if(!term->cfg.bidi || !term->cfg.arabicshaping) {
+
+ if (!term_bidi_cache_hit(term, scr_y, ldata->chars, term->cols)) {
+
+ if (term->wcFromTo_size < term->cols) {
+ term->wcFromTo_size = term->cols;
+ term->wcFrom = sresize(term->wcFrom, term->wcFromTo_size,
+ bidi_char);
+ term->wcTo = sresize(term->wcTo, term->wcFromTo_size,
+ bidi_char);
+ }
+
+ 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;
+ }
- memcpy(term->pre_bidi_cache[line].chars, lbefore, width * TSIZE);
- memcpy(term->post_bidi_cache[line].chars, lafter, width * TSIZE);
+ 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);
+
+ if (term->ltemp_size < ldata->size) {
+ term->ltemp_size = ldata->size;
+ term->ltemp = sresize(term->ltemp, term->ltemp_size,
+ termchar);
+ }
+
+ memcpy(term->ltemp, ldata->chars, ldata->size * TSIZE);
+
+ for(it=0; it<term->cols ; it++)
+ {
+ term->ltemp[it] = ldata->chars[term->wcTo[it].index];
+ if (term->ltemp[it].cc_next)
+ term->ltemp[it].cc_next -=
+ it - 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, scr_y, ldata->chars,
+ term->ltemp, term->wcTo,
+ term->cols, ldata->size);
+
+ lchars = term->ltemp;
+ } else {
+ lchars = term->post_bidi_cache[scr_y].chars;
+ }
+ } else {
+ lchars = NULL;
+ }
+
+ return lchars;
}
/*
*/
static void do_paint(Terminal *term, Context ctx, int may_optimise)
{
- int i, it, j, our_curs_y, our_curs_x;
+ int i, j, our_curs_y, our_curs_x;
int rv, cursor;
pos scrpos;
wchar_t *ch;
int chlen;
- termchar cursor_background;
#ifdef OPTIMISE_SCROLL
struct scrollregion *sr;
#endif /* OPTIMISE_SCROLL */
-
- cursor_background = term->basic_erase_char;
+ termchar *newline;
chlen = 1024;
ch = snewn(chlen, wchar_t);
+ newline = snewn(term->cols, termchar);
+
rv = (!term->rvideo ^ !term->in_vbell ? ATTR_REVERSE : 0);
/* Depends on:
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.
+ * Adjust the cursor position:
+ * - for bidi
+ * - 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);
+ termchar *lchars;
+
our_curs_x = term->curs.x;
+
+ if ( (lchars = term_bidi_line(term, ldata, our_curs_y)) != NULL) {
+ our_curs_x = term->post_bidi_cache[our_curs_y].forward[our_curs_x];
+ } else
+ lchars = ldata->chars;
+
if (our_curs_x > 0 &&
- ldata->chars[our_curs_x].chr == UCSWIDE)
+ lchars[our_curs_x].chr == UCSWIDE)
our_curs_x--;
+
unlineptr(ldata);
}
int start = 0;
int ccount = 0;
int last_run_dirty = 0;
+ int laststart, dirtyrect;
+ int *backward;
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)) {
-
- if (term->wcFromTo_size < term->cols) {
- term->wcFromTo_size = term->cols;
- term->wcFrom = sresize(term->wcFrom, term->wcFromTo_size,
- bidi_char);
- term->wcTo = sresize(term->wcTo, term->wcFromTo_size,
- bidi_char);
- }
-
- 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);
-
- if (term->ltemp_size < ldata->size) {
- term->ltemp_size = ldata->size;
- term->ltemp = sresize(term->ltemp, term->ltemp_size,
- termchar);
- }
-
- memcpy(term->ltemp, ldata->chars, ldata->size * TSIZE);
-
- for(it=0; it<term->cols ; it++)
- {
- term->ltemp[it] = ldata->chars[term->wcTo[it].index];
- if (term->ltemp[it].cc_next)
- term->ltemp[it].cc_next -=
- it - 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, ldata->size);
-
- lchars = term->ltemp;
- } else {
- lchars = term->post_bidi_cache[i].chars;
- }
- } else
+ lchars = term_bidi_line(term, ldata, i);
+ if (lchars) {
+ backward = term->post_bidi_cache[i].backward;
+ } else {
lchars = ldata->chars;
+ backward = NULL;
+ }
+ /*
+ * First loop: work along the line deciding what we want
+ * each character cell to look like.
+ */
for (j = 0; j < term->cols; j++) {
unsigned long tattr, tchar;
termchar *d = lchars + j;
- int break_run, do_copy;
- scrpos.x = j;
+ scrpos.x = backward ? backward[j] : j;
tchar = d->chr;
tattr = d->attr;
tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) |
ATTR_DEFFG | ATTR_DEFBG;
+ if (!term->cfg.xterm_256_colour) {
+ int colour;
+ colour = (tattr & ATTR_FGMASK) >> ATTR_FGSHIFT;
+ if (colour >= 16 && colour < 256)
+ tattr = (tattr &~ ATTR_FGMASK) | ATTR_DEFFG;
+ colour = (tattr & ATTR_BGMASK) >> ATTR_BGSHIFT;
+ if (colour >= 16 && colour < 256)
+ tattr = (tattr &~ ATTR_BGMASK) | ATTR_DEFBG;
+ }
+
switch (tchar & CSET_MASK) {
case CSET_ASCII:
tchar = term->ucsdata->unitab_line[tchar & 0xFF];
*/
if (tchar != term->disptext[i]->chars[j].chr ||
tattr != (term->disptext[i]->chars[j].attr &~
- ATTR_NARROW)) {
+ (ATTR_NARROW | DATTR_MASK))) {
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) {
- /* FULL-TERMCHAR */
- cursor_background.chr = tchar;
- cursor_background.attr = tattr;
- /* For once, this cc_next field is an absolute index in lchars */
- if (d->cc_next)
- cursor_background.cc_next = d->cc_next + j;
- else
- cursor_background.cc_next = 0;
+ tattr |= cursor;
+ term->curstype = cursor;
term->dispcursx = j;
term->dispcursy = i;
}
+ /* FULL-TERMCHAR */
+ newline[j].attr = tattr;
+ newline[j].chr = tchar;
+ /* Combining characters are still read from lchars */
+ newline[j].cc_next = 0;
+ }
+
+ /*
+ * Now loop over the line again, noting where things have
+ * changed.
+ *
+ * During this loop, we keep track of where we last saw
+ * DATTR_STARTRUN. Any mismatch automatically invalidates
+ * _all_ of the containing run that was last printed: that
+ * is, any rectangle that was drawn in one go in the
+ * previous update should be either left completely alone
+ * or overwritten in its entirety. This, along with the
+ * expectation that front ends clip all text runs to their
+ * bounding rectangle, should solve any possible problems
+ * with fonts that overflow their character cells.
+ */
+ laststart = 0;
+ dirtyrect = FALSE;
+ for (j = 0; j < term->cols; j++) {
+ if (term->disptext[i]->chars[j].attr & DATTR_STARTRUN) {
+ laststart = j;
+ dirtyrect = FALSE;
+ }
+
+ if (term->disptext[i]->chars[j].chr != newline[j].chr ||
+ (term->disptext[i]->chars[j].attr &~ DATTR_MASK)
+ != newline[j].attr) {
+ int k;
+
+ for (k = laststart; k < j; k++)
+ term->disptext[i]->chars[k].attr |= ATTR_INVALID;
+
+ dirtyrect = TRUE;
+ }
+
+ if (dirtyrect)
+ term->disptext[i]->chars[j].attr |= ATTR_INVALID;
+ }
+
+ /*
+ * Finally, loop once more and actually do the drawing.
+ */
+ dirty_run = dirty_line = (ldata->lattr !=
+ term->disptext[i]->lattr);
+ term->disptext[i]->lattr = ldata->lattr;
+
+ for (j = 0; j < term->cols; j++) {
+ unsigned long tattr, tchar;
+ int break_run, do_copy;
+ termchar *d = lchars + j;
+
+ tattr = newline[j].attr;
+ tchar = newline[j].chr;
+
if ((term->disptext[i]->chars[j].attr ^ tattr) & ATTR_WIDE)
dirty_line = TRUE;
if (!term->ucsdata->dbcs_screenfont && !dirty_line) {
if (term->disptext[i]->chars[j].chr == tchar &&
- term->disptext[i]->chars[j].attr == tattr)
+ (term->disptext[i]->chars[j].attr &~ DATTR_MASK) == 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);
+ do_text(ctx, start, i, ch, ccount, attr,
+ ldata->lattr);
+ if (attr & (TATTR_ACTCURS | TATTR_PASCURS))
+ do_cursor(ctx, start, i, ch, ccount, attr,
+ ldata->lattr);
+
updated_line = 1;
}
start = j;
copy_termchar(term->disptext[i], j, d);
term->disptext[i]->chars[j].chr = tchar;
term->disptext[i]->chars[j].attr = tattr;
+ if (start == j)
+ term->disptext[i]->chars[j].attr |= DATTR_STARTRUN;
}
/* If it's a wide char step along to the next one. */
}
}
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;
- ccount = 1;
+ do_text(ctx, start, i, ch, ccount, attr,
+ ldata->lattr);
+ if (attr & (TATTR_ACTCURS | TATTR_PASCURS))
+ do_cursor(ctx, start, i, ch, ccount, attr,
+ ldata->lattr);
- if (cursor_background.cc_next) {
- termchar *dd = ldata->chars + cursor_background.cc_next;
-
- while (1) {
- unsigned long schar;
-
- 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;
-
- if (dd->cc_next)
- dd += dd->cc_next;
- else
- break;
- }
-
- attr |= TATTR_COMBINING;
- }
-
- do_cursor(ctx, our_curs_x, i, ch, ccount, attr, ldata->lattr);
- term->curstype = cursor;
+ updated_line = 1;
}
unlineptr(ldata);
}
+ sfree(newline);
sfree(ch);
}
for (i = 0; i < term->rows; i++)
for (j = 0; j < term->cols; j++)
- term->disptext[i]->chars[j].attr = ATTR_INVALID;
+ term->disptext[i]->chars[j].attr |= ATTR_INVALID;
+
+ term_schedule_update(term);
}
/*
for (i = top; i <= bottom && i < term->rows; i++) {
if ((term->disptext[i]->lattr & LATTR_MODE) == LATTR_NORM)
for (j = left; j <= right && j < term->cols; j++)
- term->disptext[i]->chars[j].attr = ATTR_INVALID;
+ term->disptext[i]->chars[j].attr |= ATTR_INVALID;
else
for (j = left / 2; j <= right / 2 + 1 && j < term->cols; j++)
- term->disptext[i]->chars[j].attr = ATTR_INVALID;
+ term->disptext[i]->chars[j].attr |= ATTR_INVALID;
}
if (immediately) {
do_paint (term, ctx, FALSE);
} else {
- if (!term->window_update_pending) {
- term->window_update_pending = TRUE;
- term->next_update = schedule_timer(UPDATE_DELAY, term_timer, term);
- }
+ term_schedule_update(term);
}
}
x = term->cols - 1;
selpoint.y = y + term->disptop;
- selpoint.x = x;
ldata = lineptr(selpoint.y);
+
if ((ldata->lattr & LATTR_MODE) != LATTR_NORM)
- selpoint.x /= 2;
+ x /= 2;
+
+ /*
+ * Transform x through the bidi algorithm to find the _logical_
+ * click point from the physical one.
+ */
+ if (term_bidi_line(term, ldata, y) != NULL) {
+ x = term->post_bidi_cache[y].backward[x];
+ }
+
+ selpoint.x = x;
unlineptr(ldata);
if (raw_mouse) {
{
term->logctx = logctx;
}
+
+void term_set_focus(Terminal *term, int has_focus)
+{
+ term->has_focus = has_focus;
+ term_schedule_cblink(term);
+}