diff options
-rw-r--r-- | tty.c | 233 |
1 files changed, 145 insertions, 88 deletions
@@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.164 2009-10-28 23:12:38 tcunha Exp $ */ +/* $Id: tty.c,v 1.165 2009-10-28 23:15:32 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -33,8 +33,9 @@ void tty_fill_acs(struct tty *); int tty_try_256(struct tty *, u_char, const char *); int tty_try_88(struct tty *, u_char, const char *); -void tty_attributes_fg(struct tty *, const struct grid_cell *); -void tty_attributes_bg(struct tty *, const struct grid_cell *); +void tty_colours(struct tty *, const struct grid_cell *, int *); +void tty_colours_fg(struct tty *, const struct grid_cell *, int *); +void tty_colours_bg(struct tty *, const struct grid_cell *, int *); void tty_redraw_region(struct tty *, const struct tty_ctx *); void tty_emulate_repeat( @@ -1125,14 +1126,23 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) { struct grid_cell *tc = &tty->cell; u_char changed; - u_int fg, bg, attr; + u_int fg = gc->fg, bg = gc->bg, attr = gc->attr; + + /* If any bits are being cleared, reset everything. */ + if (tc->attr & ~attr) + tty_reset(tty); + + /* + * Set the colours. This may call tty_reset() (so it comes next) and + * may add to the desired attributes in attr. + */ + tty_colours(tty, gc, &attr); /* * If no setab, try to use the reverse attribute as a best-effort for a * non-default background. This is a bit of a hack but it doesn't do * any serious harm and makes a couple of applications happier. */ - fg = gc->fg; bg = gc->bg; attr = gc->attr; if (!tty_term_has(tty->term, TTYC_SETAB)) { if (attr & GRID_ATTR_REVERSE) { if (fg != 7 && fg != 8) @@ -1143,10 +1153,6 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) } } - /* If any bits are being cleared, reset everything. */ - if (tc->attr & ~attr) - tty_reset(tty); - /* Filter out attribute bits already set. */ changed = attr & ~tc->attr; tc->attr = attr; @@ -1172,116 +1178,167 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc) tty_putcode(tty, TTYC_INVIS); if (changed & GRID_ATTR_CHARSET) tty_putcode(tty, TTYC_SMACS); - - /* Set foreground colour. */ - if (fg != tc->fg || - (gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)) { - tty_attributes_fg(tty, gc); - tc->fg = fg; - tc->flags &= ~GRID_FLAG_FG256; - tc->flags |= gc->flags & GRID_FLAG_FG256; - } - - /* Set background colour. */ - if (bg != tc->bg || - (gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)) { - tty_attributes_bg(tty, gc); - tc->bg = bg; - tc->flags &= ~GRID_FLAG_BG256; - tc->flags |= gc->flags & GRID_FLAG_BG256; - } } -int -tty_try_256(struct tty *tty, u_char colour, const char *type) +void +tty_colours(struct tty *tty, const struct grid_cell *gc, int *attr) { - char s[32]; - - if (!(tty->term->flags & TERM_256COLOURS) && - !(tty->term_flags & TERM_256COLOURS)) - return (-1); + struct grid_cell *tc = &tty->cell; + u_char fg = gc->fg, bg = gc->bg; + int flags, have_ax; + int fg_default, bg_default; - xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); - tty_puts(tty, s); - return (0); -} + /* No changes? Nothing is necessary. */ + flags = (gc->flags ^ tc->flags) & (GRID_FLAG_FG256|GRID_FLAG_BG256); + if (fg == tc->fg && bg == tc->bg && flags == 0) + return; -int -tty_try_88(struct tty *tty, u_char colour, const char *type) -{ - char s[32]; + /* + * Is either the default colour? This is handled specially because the + * best solution might be to reset both colours to default, in which + * case if only one is default need to fall onward to set the other + * colour. + */ + fg_default = (fg == 8 && !(gc->flags & GRID_FLAG_FG256)); + bg_default = (bg == 8 && !(gc->flags & GRID_FLAG_BG256)); + if (fg_default || bg_default) { + /* + * If don't have AX but do have op, send sgr0 (op can't + * actually be used because it is sometimes the same as sgr0 + * and sometimes isn't). This resets both colours to default. + * + * Otherwise, try to set the default colour only as needed. + */ + have_ax = tty_term_has(tty->term, TTYC_AX); + if (!have_ax && tty_term_has(tty->term, TTYC_OP)) + tty_reset(tty); + else { + if (fg_default && + fg != tc->fg && !(tc->flags & GRID_FLAG_FG256)) { + if (have_ax) + tty_puts(tty, "\033[39m"); + else if (tc->fg != 7) + tty_putcode1(tty, TTYC_SETAF, 7); + tc->fg = 8; + tc->flags &= ~GRID_FLAG_FG256; + } + if (bg_default && + bg != tc->bg && !(tc->flags & GRID_FLAG_BG256)) { + if (have_ax) + tty_puts(tty, "\033[49m"); + else if (tc->bg != 0) + tty_putcode1(tty, TTYC_SETAB, 0); + tc->bg = 8; + tc->flags &= ~GRID_FLAG_BG256; + } + } + } - if (!(tty->term->flags & TERM_88COLOURS) && - !(tty->term_flags & TERM_88COLOURS)) - return (-1); - colour = colour_256to88(colour); + /* Set the foreground colour. */ + if (!fg_default && (fg != tc->fg || + ((gc->flags & GRID_FLAG_FG256) != (tc->flags & GRID_FLAG_FG256)))) + tty_colours_fg(tty, gc, attr); - xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); - tty_puts(tty, s); - return (0); + /* + * Set the background colour. This must come after the foreground as + * tty_colour_fg() can call tty_reset(). + */ + if (!bg_default && (bg != tc->bg || + ((gc->flags & GRID_FLAG_BG256) != (tc->flags & GRID_FLAG_BG256)))) + tty_colours_bg(tty, gc, attr); } void -tty_attributes_fg(struct tty *tty, const struct grid_cell *gc) +tty_colours_fg(struct tty *tty, const struct grid_cell *gc, int *attr) { - u_char fg; + struct grid_cell *tc = &tty->cell; + u_char fg = gc->fg; - fg = gc->fg; + /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_FG256) { + /* Try as 256 colours or translating to 88. */ if (tty_try_256(tty, fg, "38") == 0) - return; + goto save_fg; if (tty_try_88(tty, fg, "38") == 0) - return; + goto save_fg; + + /* Translate to 16-colour palette, updating bold if needed. */ fg = colour_256to16(fg); if (fg & 8) { fg &= 7; - tty_putcode(tty, TTYC_BOLD); - tty->cell.attr |= GRID_ATTR_BRIGHT; - } else if (tty->cell.attr & GRID_ATTR_BRIGHT) - tty_reset(tty); + (*attr) |= GRID_ATTR_BRIGHT; + } else + tty_reset(tty); /* turn off bold */ } - if (fg == 8) { - if (tty_term_has(tty->term, TTYC_AX)) { - /* AX is an extension that means \033[39m works. */ - tty_puts(tty, "\033[39m"); - } else if (tty_term_has(tty->term, TTYC_OP)) { - /* - * op can be used to look for default colours but there - * is no point in using it - with some terminals it - * does SGR0 and others not, so SGR0 is needed anyway - * to put the terminal into a known state. - */ - tty_reset(tty); - } else - tty_putcode1(tty, TTYC_SETAF, 7); - } else - tty_putcode1(tty, TTYC_SETAF, fg); + /* Otherwise set the foreground colour. */ + tty_putcode1(tty, TTYC_SETAF, fg); + +save_fg: + /* Save the new values in the terminal current cell. */ + tc->fg = fg; + tc->flags &= ~GRID_FLAG_FG256; + tc->flags |= gc->flags & GRID_FLAG_FG256; } void -tty_attributes_bg(struct tty *tty, const struct grid_cell *gc) +tty_colours_bg(struct tty *tty, const struct grid_cell *gc, unused int *attr) { - u_char bg; + struct grid_cell *tc = &tty->cell; + u_char bg = gc->bg; - bg = gc->bg; + /* Is this a 256-colour colour? */ if (gc->flags & GRID_FLAG_BG256) { + /* Try as 256 colours or translating to 88. */ if (tty_try_256(tty, bg, "48") == 0) - return; + goto save_bg; if (tty_try_88(tty, bg, "48") == 0) - return; + goto save_bg; + + /* + * Translate to 16-colour palette. Bold background doesn't + * exist portably, so just discard the bold bit if set. + */ bg = colour_256to16(bg); if (bg & 8) bg &= 7; } - if (bg == 8) { - if (tty_term_has(tty->term, TTYC_AX)) { - tty_puts(tty, "\033[49m"); - } else if (tty_term_has(tty->term, TTYC_OP)) - tty_reset(tty); - else - tty_putcode1(tty, TTYC_SETAB, 0); - } else - tty_putcode1(tty, TTYC_SETAB, bg); + /* Otherwise set the background colour. */ + tty_putcode1(tty, TTYC_SETAB, bg); + +save_bg: + /* Save the new values in the terminal current cell. */ + tc->bg = bg; + tc->flags &= ~GRID_FLAG_BG256; + tc->flags |= gc->flags & GRID_FLAG_BG256; +} + +int +tty_try_256(struct tty *tty, u_char colour, const char *type) +{ + char s[32]; + + if (!(tty->term->flags & TERM_256COLOURS) && + !(tty->term_flags & TERM_256COLOURS)) + return (-1); + + xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); + tty_puts(tty, s); + return (0); +} + +int +tty_try_88(struct tty *tty, u_char colour, const char *type) +{ + char s[32]; + + if (!(tty->term->flags & TERM_88COLOURS) && + !(tty->term_flags & TERM_88COLOURS)) + return (-1); + colour = colour_256to88(colour); + + xsnprintf(s, sizeof s, "\033[%s;5;%hhum", type, colour); + tty_puts(tty, s); + return (0); } |