#include <sys/types.h>
#include <sys/ascii.h>
#include <sys/visual_io.h>
#include <sys/font.h>
#include <sys/tem.h>
#include <sys/tem_impl.h>
#include <sys/ksynch.h>
#include <sys/sysmacros.h>
#include <sys/mutex.h>
#include <sys/note.h>
#include <sys/t_lock.h>
tem_safe_callbacks_t tem_safe_text_callbacks = {
&tem_safe_text_display,
&tem_safe_text_copy,
&tem_safe_text_cursor,
NULL,
&tem_safe_text_cls
};
tem_safe_callbacks_t tem_safe_pix_callbacks = {
&tem_safe_pix_display,
&tem_safe_pix_copy,
&tem_safe_pix_cursor,
&tem_safe_pix_bit2pix,
&tem_safe_pix_cls
};
static void tem_safe_control(struct tem_vt_state *, tem_char_t,
cred_t *, enum called_from);
static void tem_safe_setparam(struct tem_vt_state *, int, int);
static void tem_safe_selgraph(struct tem_vt_state *);
static void tem_safe_chkparam(struct tem_vt_state *, tem_char_t,
cred_t *, enum called_from);
static void tem_safe_getparams(struct tem_vt_state *, tem_char_t,
cred_t *, enum called_from);
static void tem_safe_outch(struct tem_vt_state *, tem_char_t,
cred_t *, enum called_from);
static void tem_safe_parse(struct tem_vt_state *, tem_char_t,
cred_t *, enum called_from);
static void tem_safe_new_line(struct tem_vt_state *,
cred_t *, enum called_from);
static void tem_safe_cr(struct tem_vt_state *);
static void tem_safe_lf(struct tem_vt_state *,
cred_t *, enum called_from);
static void tem_safe_send_data(struct tem_vt_state *, cred_t *,
enum called_from);
static void tem_safe_cls(struct tem_vt_state *,
cred_t *, enum called_from);
static void tem_safe_tab(struct tem_vt_state *,
cred_t *, enum called_from);
static void tem_safe_back_tab(struct tem_vt_state *,
cred_t *, enum called_from);
static void tem_safe_clear_tabs(struct tem_vt_state *, int);
static void tem_safe_set_tab(struct tem_vt_state *);
static void tem_safe_mv_cursor(struct tem_vt_state *, int, int,
cred_t *, enum called_from);
static void tem_safe_shift(struct tem_vt_state *, int, int,
cred_t *, enum called_from);
static void tem_safe_scroll(struct tem_vt_state *, int, int,
int, int, cred_t *, enum called_from);
static void tem_safe_clear_chars(struct tem_vt_state *tem,
int count, screen_pos_t row, screen_pos_t col,
cred_t *credp, enum called_from called_from);
static void tem_safe_copy_area(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp, enum called_from called_from);
#if 0
static void tem_safe_image_display(struct tem_vt_state *, uchar_t *,
int, int, screen_pos_t, screen_pos_t,
cred_t *, enum called_from);
#endif
static void tem_safe_bell(struct tem_vt_state *tem,
enum called_from called_from);
static void tem_safe_pix_clear_prom_output(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from);
static void tem_safe_get_color(struct tem_vt_state *,
text_color_t *, text_color_t *, term_char_t *);
static void tem_safe_set_color(text_color_t *, color_t *);
static void tem_safe_virtual_cls(struct tem_vt_state *, int, screen_pos_t,
screen_pos_t);
static void tem_safe_virtual_display(struct tem_vt_state *,
term_char_t *, int, screen_pos_t, screen_pos_t);
static void tem_safe_virtual_copy(struct tem_vt_state *, screen_pos_t,
screen_pos_t, screen_pos_t, screen_pos_t,
screen_pos_t, screen_pos_t);
static void tem_safe_align_cursor(struct tem_vt_state *tem);
static void bit_to_pix4(struct tem_vt_state *tem, tem_char_t c,
text_color_t fg_color, text_color_t bg_color);
static void bit_to_pix8(struct tem_vt_state *tem, tem_char_t c,
text_color_t fg_color, text_color_t bg_color);
static void bit_to_pix16(struct tem_vt_state *tem, tem_char_t c,
text_color_t fg_color, text_color_t bg_color);
static void bit_to_pix24(struct tem_vt_state *tem, tem_char_t c,
text_color_t fg_color, text_color_t bg_color);
static void bit_to_pix32(struct tem_vt_state *tem, tem_char_t c,
text_color_t fg_color, text_color_t bg_color);
#define PIX4TO32(pix4) (uint32_t)( \
cmap4_to_24.red[pix4] << 16 | \
cmap4_to_24.green[pix4] << 8 | \
cmap4_to_24.blue[pix4])
#define tem_safe_callback_display (*tems.ts_callbacks->tsc_display)
#define tem_safe_callback_copy (*tems.ts_callbacks->tsc_copy)
#define tem_safe_callback_cursor (*tems.ts_callbacks->tsc_cursor)
#define tem_safe_callback_cls (*tems.ts_callbacks->tsc_cls)
#define tem_safe_callback_bit2pix(tem, c) { \
ASSERT(tems.ts_callbacks->tsc_bit2pix != NULL); \
(void) (*tems.ts_callbacks->tsc_bit2pix)((tem), (c));\
}
void
tem_safe_check_first_time(
struct tem_vt_state *tem,
cred_t *credp,
enum called_from called_from)
{
static int first_time = 1;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (!first_time)
return;
first_time = 0;
if (tems.ts_display_mode == VIS_TEXT)
tem_safe_text_cursor(tem, VIS_GET_CURSOR, credp, called_from);
else
tem_safe_pix_cursor(tem, VIS_GET_CURSOR, credp, called_from);
tem_safe_align_cursor(tem);
}
void
tem_safe_polled_write(
tem_vt_state_t tem_arg,
uchar_t *buf,
int len)
{
struct tem_vt_state *tem = (struct tem_vt_state *)tem_arg;
#ifdef __lock_lint
_NOTE(NO_COMPETING_THREADS_NOW)
_NOTE(NO_COMPETING_THREADS_AS_SIDE_EFFECT)
#endif
if (!tem->tvs_initialized) {
return;
}
tem_safe_check_first_time(tem, kcred, CALLED_FROM_STANDALONE);
tem_safe_terminal_emulate(tem, buf, len, NULL, CALLED_FROM_STANDALONE);
}
static void
tem_safe_input_partial(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
unsigned i;
uint8_t c;
if (tem->tvs_utf8_left == 0)
return;
for (i = 0; i < sizeof (tem->tvs_utf8_partial); i++) {
c = (tem->tvs_utf8_partial >> (24 - (i << 3))) & 0xff;
if (c != 0) {
tem_safe_parse(tem, c, credp, called_from);
}
}
tem->tvs_utf8_left = 0;
tem->tvs_utf8_partial = 0;
}
static void
tem_safe_input_byte(struct tem_vt_state *tem, uchar_t c, cred_t *credp,
enum called_from called_from)
{
if ((c & 0x80) == 0x00) {
tem_safe_input_partial(tem, credp, called_from);
tem_safe_parse(tem, c, credp, called_from);
return;
}
if ((c & 0xe0) == 0xc0) {
tem_safe_input_partial(tem, credp, called_from);
tem->tvs_utf8_left = 1;
tem->tvs_utf8_partial = c;
return;
}
if ((c & 0xf0) == 0xe0) {
tem_safe_input_partial(tem, credp, called_from);
tem->tvs_utf8_left = 2;
tem->tvs_utf8_partial = c;
return;
}
if ((c & 0xf8) == 0xf0) {
tem_safe_input_partial(tem, credp, called_from);
tem->tvs_utf8_left = 3;
tem->tvs_utf8_partial = c;
return;
}
if ((c & 0xc0) == 0x80) {
if (tem->tvs_utf8_left == 0) {
tem_safe_parse(tem, c, credp, called_from);
return;
}
tem->tvs_utf8_left--;
tem->tvs_utf8_partial = (tem->tvs_utf8_partial << 8) | c;
if (tem->tvs_utf8_left == 0) {
tem_char_t v, u;
uint8_t b;
v = 0;
u = tem->tvs_utf8_partial;
b = (u >> 24) & 0xff;
if (b != 0) {
v = b & 0x07;
b = (u >> 16) & 0xff;
v = (v << 6) | (b & 0x3f);
b = (u >> 8) & 0xff;
v = (v << 6) | (b & 0x3f);
b = u & 0xff;
v = (v << 6) | (b & 0x3f);
} else if ((b = (u >> 16) & 0xff) != 0) {
v = b & 0x0f;
b = (u >> 8) & 0xff;
v = (v << 6) | (b & 0x3f);
b = u & 0xff;
v = (v << 6) | (b & 0x3f);
} else if ((b = (u >> 8) & 0xff) != 0) {
v = b & 0x1f;
b = u & 0xff;
v = (v << 6) | (b & 0x3f);
}
tem_safe_parse(tem, v, credp, called_from);
tem->tvs_utf8_partial = 0;
}
return;
}
tem_safe_input_partial(tem, credp, called_from);
tem_safe_parse(tem, c, credp, called_from);
}
void
tem_safe_terminal_emulate(
struct tem_vt_state *tem,
uchar_t *buf,
int len,
cred_t *credp,
enum called_from called_from)
{
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (tem->tvs_isactive && !tem->tvs_cursor_hidden)
tem_safe_callback_cursor(tem,
VIS_HIDE_CURSOR, credp, called_from);
for (; len > 0; len--, buf++)
tem_safe_input_byte(tem, *buf, credp, called_from);
tem_safe_send_data(tem, credp, called_from);
if (tem->tvs_isactive && !tem->tvs_cursor_hidden)
tem_safe_callback_cursor(tem,
VIS_DISPLAY_CURSOR, credp, called_from);
}
static void
tems_safe_display(struct vis_consdisplay *pda, cred_t *credp,
enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
tems.ts_fb_polledio->display(tems.ts_fb_polledio->arg, pda);
else
tems_display_layered(pda, credp);
}
void
tems_safe_copy(struct vis_conscopy *pca, cred_t *credp,
enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
tems.ts_fb_polledio->copy(tems.ts_fb_polledio->arg, pca);
else
tems_copy_layered(pca, credp);
}
static void
tems_safe_cursor(struct vis_conscursor *pca, cred_t *credp,
enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
tems.ts_fb_polledio->cursor(tems.ts_fb_polledio->arg, pca);
else
tems_cursor_layered(pca, credp);
}
static void
tem_safe_control(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
enum called_from called_from)
{
tem->tvs_state = A_STATE_START;
switch (ch) {
case A_BEL:
tem_safe_bell(tem, called_from);
break;
case A_BS:
tem_safe_mv_cursor(tem,
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col - 1,
credp, called_from);
break;
case A_HT:
tem_safe_tab(tem, credp, called_from);
break;
case A_NL:
case A_VT:
tem_safe_send_data(tem, credp, called_from);
tem_safe_lf(tem, credp, called_from);
break;
case A_FF:
tem_safe_send_data(tem, credp, called_from);
tem_safe_cls(tem, credp, called_from);
break;
case A_CR:
tem_safe_send_data(tem, credp, called_from);
tem_safe_cr(tem);
break;
case A_ESC:
tem->tvs_state = A_STATE_ESC;
break;
case A_CSI:
{
int i;
tem->tvs_curparam = 0;
tem->tvs_paramval = 0;
tem->tvs_gotparam = B_FALSE;
for (i = 0; i < TEM_MAXPARAMS; i++)
tem->tvs_params[i] = -1;
tem->tvs_state = A_STATE_CSI;
}
break;
case A_GS:
tem_safe_back_tab(tem, credp, called_from);
break;
default:
break;
}
}
static void
tem_safe_setparam(struct tem_vt_state *tem, int count, int newparam)
{
int i;
for (i = 0; i < count; i++) {
if (tem->tvs_params[i] == -1)
tem->tvs_params[i] = newparam;
}
}
static void
tem_select_color(struct tem_vt_state *tem, int color, boolean_t fg)
{
if (color < 0 || color > 255)
return;
if (tems.ts_display_mode == VIS_TEXT && color > 15)
return;
if (fg == B_TRUE) {
tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
tem->tvs_fg_color.n = color;
} else {
tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
tem->tvs_bg_color.n = color;
}
if (color < 8) {
if (fg == B_TRUE)
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
else
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
return;
}
if (color < 16) {
if (fg == B_TRUE) {
tem->tvs_fg_color.n -= 8;
tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
} else {
tem->tvs_bg_color.n -= 8;
tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
}
}
}
static void
tem_safe_selgraph(struct tem_vt_state *tem)
{
int curparam;
int count = 0;
int param;
int r, g, b;
tem->tvs_state = A_STATE_START;
curparam = tem->tvs_curparam;
do {
param = tem->tvs_params[count];
switch (param) {
case -1:
case 0:
tem->tvs_fg_color = tems.ts_init_color.fg_color;
tem->tvs_bg_color = tems.ts_init_color.bg_color;
tem->tvs_flags = tems.ts_init_color.a_flags;
break;
case 1:
tem->tvs_flags |= TEM_ATTR_BOLD;
break;
case 2:
tem->tvs_flags &= ~TEM_ATTR_BOLD;
break;
case 4:
tem->tvs_flags |= TEM_ATTR_UNDERLINE;
break;
case 5:
tem->tvs_flags |= TEM_ATTR_BLINK;
break;
case 7:
if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
tem->tvs_flags &= ~TEM_ATTR_REVERSE;
} else {
tem->tvs_flags |= TEM_ATTR_REVERSE;
}
break;
case 22:
tem->tvs_flags &= ~TEM_ATTR_BOLD;
break;
case 24:
tem->tvs_flags &= ~TEM_ATTR_UNDERLINE;
break;
case 25:
tem->tvs_flags &= ~TEM_ATTR_BLINK;
break;
case 27:
if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
tem->tvs_flags |= TEM_ATTR_REVERSE;
} else {
tem->tvs_flags &= ~TEM_ATTR_REVERSE;
}
break;
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
tem->tvs_fg_color.n = param - 30;
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
break;
case 38:
if (curparam < 3) {
curparam = 0;
break;
}
count++;
curparam--;
param = tem->tvs_params[count];
switch (param) {
case 2:
if (curparam < 4) {
curparam = 0;
break;
}
r = tem->tvs_params[++count];
g = tem->tvs_params[++count];
b = tem->tvs_params[++count];
curparam -= 3;
if (r < 0 || r > 255 || g < 0 || g > 255 ||
b < 0 || b > 255)
break;
if (tems.ts_display_mode == VIS_PIXEL &&
tems.ts_pdepth > 8) {
tem->tvs_flags |= TEM_ATTR_RGB_FG;
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
tem->tvs_fg_color.rgb.a =
tem->tvs_alpha;
tem->tvs_fg_color.rgb.r = r;
tem->tvs_fg_color.rgb.g = g;
tem->tvs_fg_color.rgb.b = b;
}
break;
case 5:
count++;
curparam--;
tem_select_color(tem, tem->tvs_params[count],
B_TRUE);
break;
default:
curparam = 0;
break;
}
break;
case 39:
tem->tvs_fg_color = tems.ts_init_color.fg_color;
tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_FG)
tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
else
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_FG;
break;
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
tem->tvs_bg_color.n = param - 40;
tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
break;
case 48:
if (curparam < 3) {
curparam = 0;
break;
}
count++;
curparam--;
param = tem->tvs_params[count];
switch (param) {
case 2:
if (curparam < 4) {
curparam = 0;
break;
}
r = tem->tvs_params[++count];
g = tem->tvs_params[++count];
b = tem->tvs_params[++count];
curparam -= 3;
if (r < 0 || r > 255 || g < 0 || g > 255 ||
b < 0 || b > 255)
break;
if (tems.ts_display_mode == VIS_PIXEL &&
tems.ts_pdepth > 8) {
tem->tvs_flags |= TEM_ATTR_RGB_BG;
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
tem->tvs_bg_color.rgb.a =
tem->tvs_alpha;
tem->tvs_bg_color.rgb.r = r;
tem->tvs_bg_color.rgb.g = g;
tem->tvs_bg_color.rgb.b = b;
}
break;
case 5:
count++;
curparam--;
tem_select_color(tem, tem->tvs_params[count],
B_FALSE);
break;
default:
curparam = 0;
break;
}
break;
case 49:
tem->tvs_bg_color = tems.ts_init_color.bg_color;
tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
if (tems.ts_init_color.a_flags & TEM_ATTR_BRIGHT_BG)
tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
else
tem->tvs_flags &= ~TEM_ATTR_BRIGHT_BG;
break;
case 90:
case 91:
case 92:
case 93:
case 94:
case 95:
case 96:
case 97:
tem->tvs_fg_color.n = param - 90;
tem->tvs_flags |= TEM_ATTR_BRIGHT_FG;
tem->tvs_flags &= ~TEM_ATTR_RGB_FG;
break;
case 100:
case 101:
case 102:
case 103:
case 104:
case 105:
case 106:
case 107:
tem->tvs_bg_color.n = param - 100;
tem->tvs_flags |= TEM_ATTR_BRIGHT_BG;
tem->tvs_flags &= ~TEM_ATTR_RGB_BG;
break;
default:
break;
}
count++;
curparam--;
} while (curparam > 0);
}
static void
tem_safe_window(struct tem_vt_state *tem, enum called_from called_from)
{
int curparam;
int param;
int index = 0;
mblk_t *bp;
size_t len;
char buf[27];
tem->tvs_state = A_STATE_START;
curparam = tem->tvs_curparam;
do {
param = tem->tvs_params[index];
switch (param) {
case 8:
index += 2;
curparam -= 2;
break;
case 18:
if (called_from == CALLED_FROM_STANDALONE)
break;
if (!canputnext(tem->tvs_queue))
break;
len = snprintf(buf, sizeof (buf), "%c[8;%u;%ut",
0x1b, tems.ts_c_dimension.height,
tems.ts_c_dimension.width);
bp = allocb(len, BPRI_HI);
if (bp != NULL) {
bp->b_datap->db_type = M_CTL;
bcopy(buf, bp->b_wptr, len);
bp->b_wptr += len;
(void) putnext(tem->tvs_queue, bp);
}
break;
}
index++;
curparam--;
} while (curparam > 0);
}
static void
tem_safe_chkparam(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
enum called_from called_from)
{
int i;
int row;
int col;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
MUTEX_HELD(&tem->tvs_lock));
row = tem->tvs_c_cursor.row;
col = tem->tvs_c_cursor.col;
switch (ch) {
case 'm':
tem_safe_send_data(tem, credp, called_from);
tem_safe_selgraph(tem);
break;
case '@':
tem_safe_setparam(tem, 1, 1);
tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_RIGHT,
credp, called_from);
break;
case 'A':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row - tem->tvs_params[0], col,
credp, called_from);
break;
case 'd':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, tem->tvs_params[0] - 1, col,
credp, called_from);
break;
case 'e':
case 'B':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row + tem->tvs_params[0], col,
credp, called_from);
break;
case 'a':
case 'C':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row, col + tem->tvs_params[0],
credp, called_from);
break;
case '`':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
credp, called_from);
break;
case 'D':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row, col - tem->tvs_params[0],
credp, called_from);
break;
case 'E':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row + tem->tvs_params[0], 0,
credp, called_from);
break;
case 'F':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row - tem->tvs_params[0], 0,
credp, called_from);
break;
case 'G':
tem_safe_setparam(tem, 1, 1);
tem_safe_mv_cursor(tem, row, tem->tvs_params[0] - 1,
credp, called_from);
break;
case 'g':
tem_safe_setparam(tem, 1, 0);
tem_safe_clear_tabs(tem, tem->tvs_params[0]);
break;
case 'f':
case 'H':
tem_safe_setparam(tem, 2, 1);
tem_safe_mv_cursor(tem,
tem->tvs_params[0] - 1,
tem->tvs_params[1] - 1,
credp, called_from);
break;
case 'I':
break;
case 'J':
tem_safe_send_data(tem, credp, called_from);
tem_safe_setparam(tem, 1, 0);
switch (tem->tvs_params[0]) {
case 0:
tem_safe_clear_chars(tem,
tems.ts_c_dimension.width -
tem->tvs_c_cursor.col,
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col, credp, called_from);
for (row = tem->tvs_c_cursor.row + 1;
row < tems.ts_c_dimension.height;
row++) {
tem_safe_clear_chars(tem,
tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
case 1:
for (row = 0;
row < tem->tvs_c_cursor.row;
row++) {
tem_safe_clear_chars(tem,
tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
tem_safe_clear_chars(tem,
tem->tvs_c_cursor.col + 1,
tem->tvs_c_cursor.row,
0, credp, called_from);
break;
case 2:
for (row = 0;
row < tems.ts_c_dimension.height;
row++) {
tem_safe_clear_chars(tem,
tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
}
break;
case 'K':
tem_safe_send_data(tem, credp, called_from);
tem_safe_setparam(tem, 1, 0);
switch (tem->tvs_params[0]) {
case 0:
tem_safe_clear_chars(tem,
(tems.ts_c_dimension.width -
tem->tvs_c_cursor.col),
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col,
credp, called_from);
break;
case 1:
tem_safe_clear_chars(tem,
tem->tvs_c_cursor.col + 1,
tem->tvs_c_cursor.row,
0, credp, called_from);
break;
case 2:
tem_safe_clear_chars(tem,
tems.ts_c_dimension.width,
tem->tvs_c_cursor.row,
0, credp, called_from);
break;
}
break;
case 'L':
tem_safe_send_data(tem, credp, called_from);
tem_safe_setparam(tem, 1, 1);
tem_safe_scroll(tem,
tem->tvs_c_cursor.row,
tems.ts_c_dimension.height - 1,
tem->tvs_params[0], TEM_SCROLL_DOWN,
credp, called_from);
break;
case 'M':
tem_safe_send_data(tem, credp, called_from);
tem_safe_setparam(tem, 1, 1);
tem_safe_scroll(tem,
tem->tvs_c_cursor.row,
tems.ts_c_dimension.height - 1,
tem->tvs_params[0], TEM_SCROLL_UP,
credp, called_from);
break;
case 'P':
tem_safe_setparam(tem, 1, 1);
tem_safe_shift(tem, tem->tvs_params[0], TEM_SHIFT_LEFT,
credp, called_from);
break;
case 'S':
tem_safe_send_data(tem, credp, called_from);
tem_safe_setparam(tem, 1, 1);
tem_safe_scroll(tem, 0,
tems.ts_c_dimension.height - 1,
tem->tvs_params[0], TEM_SCROLL_UP,
credp, called_from);
break;
case 'T':
tem_safe_send_data(tem, credp, called_from);
tem_safe_setparam(tem, 1, 1);
tem_safe_scroll(tem, 0,
tems.ts_c_dimension.height - 1,
tem->tvs_params[0], TEM_SCROLL_DOWN,
credp, called_from);
break;
case 't':
tem_safe_send_data(tem, credp, called_from);
tem_safe_window(tem, called_from);
break;
case 'X':
tem_safe_setparam(tem, 1, 1);
tem_safe_clear_chars(tem,
tem->tvs_params[0],
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col,
credp, called_from);
break;
case 'Z':
tem_safe_setparam(tem, 1, 1);
if (tem->tvs_params[0] > tems.ts_c_dimension.width)
tem->tvs_params[0] = tems.ts_c_dimension.width;
for (i = 0; i < tem->tvs_params[0]; i++)
tem_safe_back_tab(tem, credp, called_from);
break;
}
tem->tvs_state = A_STATE_START;
}
static void
tem_safe_chkparam_qmark(struct tem_vt_state *tem, tem_char_t ch, cred_t *credp,
enum called_from called_from)
{
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
MUTEX_HELD(&tem->tvs_lock));
switch (ch) {
case 'h':
tem_safe_setparam(tem, 1, 1);
switch (tem->tvs_params[0]) {
case 7:
tem->tvs_stateflags |= TVS_AUTOWRAP;
break;
case 25:
tem_safe_send_data(tem, credp, called_from);
tem->tvs_cursor_hidden = B_FALSE;
break;
}
break;
case 'l':
tem_safe_setparam(tem, 1, 1);
switch (tem->tvs_params[0]) {
case 7:
tem->tvs_stateflags &= ~TVS_AUTOWRAP;
break;
case 25:
tem_safe_send_data(tem, credp, called_from);
tem->tvs_cursor_hidden = B_TRUE;
break;
}
break;
}
tem->tvs_state = A_STATE_START;
}
static void
tem_safe_getparams(struct tem_vt_state *tem, tem_char_t ch,
cred_t *credp, enum called_from called_from)
{
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
MUTEX_HELD(&tem->tvs_lock));
if (ch >= '0' && ch <= '9') {
tem->tvs_paramval = ((tem->tvs_paramval * 10) + (ch - '0'));
tem->tvs_gotparam = B_TRUE;
return;
} else if (tem->tvs_state == A_STATE_CSI_EQUAL) {
tem->tvs_state = A_STATE_START;
} else if (tem->tvs_state == A_STATE_CSI_QMARK) {
if (tem->tvs_curparam < TEM_MAXPARAMS) {
if (tem->tvs_gotparam) {
tem->tvs_params[tem->tvs_curparam] =
tem->tvs_paramval;
}
tem->tvs_curparam++;
}
if (ch == ';') {
tem->tvs_gotparam = B_FALSE;
tem->tvs_paramval = 0;
} else {
tem_safe_chkparam_qmark(tem, ch, credp, called_from);
}
} else {
if (tem->tvs_curparam < TEM_MAXPARAMS) {
if (tem->tvs_gotparam) {
tem->tvs_params[tem->tvs_curparam] =
tem->tvs_paramval;
}
tem->tvs_curparam++;
}
if (ch == ';') {
tem->tvs_gotparam = B_FALSE;
tem->tvs_paramval = 0;
} else {
tem_safe_chkparam(tem, ch, credp, called_from);
}
}
}
static void
tem_safe_outch(struct tem_vt_state *tem, tem_char_t ch,
cred_t *credp, enum called_from called_from)
{
text_color_t fg;
text_color_t bg;
text_attr_t attr;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if ((tem->tvs_stateflags & (TVS_AUTOWRAP | TVS_WRAPPED)) ==
(TVS_AUTOWRAP | TVS_WRAPPED)) {
tem_safe_new_line(tem, credp, called_from);
}
tem_safe_get_attr(tem, &fg, &bg, &attr, TEM_ATTR_REVERSE);
tem->tvs_outbuf[tem->tvs_outindex].tc_char = ch | TEM_ATTR(attr);
tem->tvs_outbuf[tem->tvs_outindex].tc_fg_color = fg;
tem->tvs_outbuf[tem->tvs_outindex].tc_bg_color = bg;
tem->tvs_outindex++;
tem->tvs_c_cursor.col++;
if (tem->tvs_c_cursor.col >= tems.ts_c_dimension.width) {
tem->tvs_stateflags |= TVS_WRAPPED;
tem->tvs_c_cursor.col--;
tem_safe_send_data(tem, credp, called_from);
} else {
tem->tvs_stateflags &= ~TVS_WRAPPED;
}
}
static void
tem_safe_new_line(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
tem_safe_cr(tem);
tem_safe_lf(tem, credp, called_from);
}
static void
tem_safe_cr(struct tem_vt_state *tem)
{
tem->tvs_c_cursor.col = 0;
tem->tvs_stateflags &= ~TVS_WRAPPED;
tem_safe_align_cursor(tem);
}
static void
tem_safe_lf(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
int row;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
MUTEX_HELD(&tem->tvs_lock));
tem->tvs_stateflags &= ~TVS_WRAPPED;
row = tem->tvs_c_cursor.row + 1;
if (row >= tems.ts_c_dimension.height) {
if (tem->tvs_nscroll != 0) {
tem_safe_scroll(tem, 0,
tems.ts_c_dimension.height - 1,
tem->tvs_nscroll, TEM_SCROLL_UP,
credp, called_from);
row = tems.ts_c_dimension.height -
tem->tvs_nscroll;
} else {
row = 0;
}
}
tem_safe_mv_cursor(tem, row, tem->tvs_c_cursor.col,
credp, called_from);
if (tem->tvs_nscroll == 0) {
tem_safe_clear_chars(tem,
tems.ts_c_dimension.width -
tem->tvs_c_cursor.col,
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col,
credp, called_from);
}
tem_safe_align_cursor(tem);
}
static void
tem_safe_send_data(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
MUTEX_HELD(&tem->tvs_lock));
if (tem->tvs_outindex == 0) {
tem_safe_align_cursor(tem);
return;
}
tem_safe_virtual_display(tem,
tem->tvs_outbuf, tem->tvs_outindex,
tem->tvs_s_cursor.row, tem->tvs_s_cursor.col);
if (tem->tvs_isactive) {
tem_safe_callback_display(tem,
tem->tvs_outbuf, tem->tvs_outindex,
tem->tvs_s_cursor.row, tem->tvs_s_cursor.col,
credp, called_from);
}
tem->tvs_outindex = 0;
tem_safe_align_cursor(tem);
}
static void
tem_safe_align_cursor(struct tem_vt_state *tem)
{
tem->tvs_s_cursor.row = tem->tvs_c_cursor.row;
tem->tvs_s_cursor.col = tem->tvs_c_cursor.col;
}
static void
tem_safe_parse(struct tem_vt_state *tem, tem_char_t ch,
cred_t *credp, enum called_from called_from)
{
int i;
ASSERT((called_from == CALLED_FROM_STANDALONE) ||
MUTEX_HELD(&tem->tvs_lock));
if (tem->tvs_state == A_STATE_START) {
if (ch == A_CSI || ch == A_ESC || ch < ' ') {
tem_safe_control(tem, ch, credp, called_from);
} else {
tem_safe_outch(tem, ch, credp, called_from);
}
return;
}
if (tem->tvs_state != A_STATE_ESC) {
if (tem->tvs_state != A_STATE_CSI) {
tem_safe_getparams(tem, ch, credp, called_from);
return;
}
switch (ch) {
case '?':
tem->tvs_state = A_STATE_CSI_QMARK;
return;
case '=':
tem->tvs_state = A_STATE_CSI_EQUAL;
return;
case 's':
tem->tvs_state = A_STATE_START;
return;
case 'u':
tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
tem->tvs_r_cursor.col, credp, called_from);
tem->tvs_state = A_STATE_START;
return;
case 'p':
tem_safe_send_data(tem, credp, called_from);
if (tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE) {
tem->tvs_flags &= ~TEM_ATTR_SCREEN_REVERSE;
if (tem->tvs_flags & TEM_ATTR_REVERSE)
tem->tvs_flags &= ~TEM_ATTR_REVERSE;
else
tem->tvs_flags |= TEM_ATTR_REVERSE;
}
tem_safe_cls(tem, credp, called_from);
tem->tvs_state = A_STATE_START;
return;
case 'q':
tem_safe_send_data(tem, credp, called_from);
if (!(tem->tvs_flags & TEM_ATTR_SCREEN_REVERSE)) {
tem->tvs_flags |= TEM_ATTR_SCREEN_REVERSE;
if (!(tem->tvs_flags & TEM_ATTR_REVERSE))
tem->tvs_flags |= TEM_ATTR_REVERSE;
else
tem->tvs_flags &= ~TEM_ATTR_REVERSE;
}
tem_safe_cls(tem, credp, called_from);
tem->tvs_state = A_STATE_START;
return;
case 'r':
tem->tvs_nscroll = tem->tvs_paramval;
if (tem->tvs_nscroll > tems.ts_c_dimension.height)
tem->tvs_nscroll = tems.ts_c_dimension.height;
if (tem->tvs_nscroll < 0)
tem->tvs_nscroll = 1;
tem->tvs_state = A_STATE_START;
return;
default:
tem_safe_getparams(tem, ch, credp, called_from);
return;
}
}
if (ch == '[') {
tem->tvs_curparam = 0;
tem->tvs_paramval = 0;
tem->tvs_gotparam = B_FALSE;
for (i = 0; i < TEM_MAXPARAMS; i++)
tem->tvs_params[i] = -1;
tem->tvs_state = A_STATE_CSI;
} else if (ch == 'Q') {
tem->tvs_state = A_STATE_START;
} else if (ch == 'C') {
tem->tvs_state = A_STATE_START;
} else {
tem->tvs_state = A_STATE_START;
if (ch == 'c') {
tem_safe_reset_display(tem, credp, called_from,
B_TRUE, B_TRUE);
} else if (ch == 'H') {
tem_safe_set_tab(tem);
} else if (ch == '7') {
tem->tvs_r_cursor.row = tem->tvs_c_cursor.row;
tem->tvs_r_cursor.col = tem->tvs_c_cursor.col;
} else if (ch == '8') {
tem_safe_mv_cursor(tem, tem->tvs_r_cursor.row,
tem->tvs_r_cursor.col, credp, called_from);
} else if (ch < ' ') {
tem_safe_control(tem, ch, credp, called_from);
} else {
tem_safe_outch(tem, ch, credp, called_from);
}
}
}
static void
tem_safe_bell(struct tem_vt_state *tem, enum called_from called_from)
{
if (called_from == CALLED_FROM_STANDALONE)
(void) beep_polled(BEEP_CONSOLE);
else
(void) beep(BEEP_CONSOLE);
}
static void
tem_safe_scroll(struct tem_vt_state *tem, int start, int end, int count,
int direction, cred_t *credp, enum called_from called_from)
{
int row;
int lines_affected;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
lines_affected = end - start + 1;
if (count > lines_affected)
count = lines_affected;
if (count <= 0)
return;
switch (direction) {
case TEM_SCROLL_UP:
if (count < lines_affected) {
tem_safe_copy_area(tem, 0, start + count,
tems.ts_c_dimension.width - 1, end,
0, start, credp, called_from);
}
for (row = (end - count) + 1; row <= end; row++) {
tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
case TEM_SCROLL_DOWN:
if (count < lines_affected) {
tem_safe_copy_area(tem, 0, start,
tems.ts_c_dimension.width - 1,
end - count, 0, start + count,
credp, called_from);
}
for (row = start; row < start + count; row++) {
tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
break;
}
}
static int
tem_copy_width(term_char_t *src, term_char_t *dst, int cols)
{
int width = cols - 1;
while (width >= 0) {
if (TEM_CHAR_ATTR(src[width].tc_char) == TEM_ATTR_IMAGE ||
TEM_CHAR_ATTR(dst[width].tc_char) == TEM_ATTR_IMAGE)
break;
if (src[width].tc_char != dst[width].tc_char ||
src[width].tc_fg_color.n != dst[width].tc_fg_color.n ||
src[width].tc_bg_color.n != dst[width].tc_bg_color.n) {
break;
}
width--;
}
return (width + 1);
}
static void
tem_safe_copy_area(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp, enum called_from called_from)
{
size_t soffset, toffset;
term_char_t *src, *dst;
int rows;
int cols;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (s_col < 0 || s_row < 0 ||
e_col < 0 || e_row < 0 ||
t_col < 0 || t_row < 0 ||
s_col >= tems.ts_c_dimension.width ||
e_col >= tems.ts_c_dimension.width ||
t_col >= tems.ts_c_dimension.width ||
s_row >= tems.ts_c_dimension.height ||
e_row >= tems.ts_c_dimension.height ||
t_row >= tems.ts_c_dimension.height)
return;
if (s_row > e_row || s_col > e_col)
return;
rows = e_row - s_row + 1;
cols = e_col - s_col + 1;
if (t_row + rows > tems.ts_c_dimension.height ||
t_col + cols > tems.ts_c_dimension.width)
return;
soffset = s_col + s_row * tems.ts_c_dimension.width;
toffset = t_col + t_row * tems.ts_c_dimension.width;
src = tem->tvs_screen_buf + soffset;
dst = tem->tvs_screen_buf + toffset;
if (toffset <= soffset) {
for (int i = 0; i < rows; i++) {
int increment = i * tems.ts_c_dimension.width;
int width;
width = tem_copy_width(src + increment,
dst + increment, cols);
tem_safe_virtual_copy(tem, s_col, s_row + i,
e_col - cols + width, s_row + i,
t_col, t_row + i);
if (tem->tvs_isactive) {
tem_safe_callback_copy(tem, s_col, s_row + i,
e_col - cols + width, s_row + i,
t_col, t_row + i, credp, called_from);
}
}
} else {
for (int i = rows - 1; i >= 0; i--) {
int increment = i * tems.ts_c_dimension.width;
int width;
width = tem_copy_width(src + increment,
dst + increment, cols);
tem_safe_virtual_copy(tem, s_col, s_row + i,
e_col - cols + width, s_row + i,
t_col, t_row + i);
if (tem->tvs_isactive) {
tem_safe_callback_copy(tem, s_col, s_row + i,
e_col - cols + width, s_row + i,
t_col, t_row + i, credp, called_from);
}
}
}
}
static void
tem_safe_clear_chars(struct tem_vt_state *tem, int count, screen_pos_t row,
screen_pos_t col, cred_t *credp, enum called_from called_from)
{
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (row < 0 || row >= tems.ts_c_dimension.height ||
col < 0 || col >= tems.ts_c_dimension.width ||
count < 0)
return;
if (count > tems.ts_c_dimension.width ||
col + count > tems.ts_c_dimension.width)
count = tems.ts_c_dimension.width - col;
tem_safe_virtual_cls(tem, count, row, col);
if (!tem->tvs_isactive)
return;
tem_safe_callback_cls(tem, count, row, col, credp, called_from);
}
void
tem_safe_text_display(struct tem_vt_state *tem, term_char_t *string,
int count, screen_pos_t row, screen_pos_t col,
cred_t *credp, enum called_from called_from)
{
struct vis_consdisplay da;
int i;
tem_char_t c;
text_color_t bg, fg;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
da.data = (uint8_t *)&c;
da.width = 1;
da.row = row;
da.col = col;
for (i = 0; i < count; i++) {
tem_safe_get_color(tem, &fg, &bg, &string[i]);
tem_safe_set_color(&fg, &da.fg_color);
tem_safe_set_color(&bg, &da.bg_color);
c = TEM_CHAR(string[i].tc_char);
tems_safe_display(&da, credp, called_from);
da.col++;
}
}
#if 0
static void
tem_safe_image_display(struct tem_vt_state *tem, uchar_t *image,
int height, int width, screen_pos_t row, screen_pos_t col,
cred_t *credp, enum called_from called_from)
{
struct vis_consdisplay da;
mutex_enter(&tems.ts_lock);
mutex_enter(&tem->tvs_lock);
da.data = image;
da.width = (screen_size_t)width;
da.height = (screen_size_t)height;
da.row = row;
da.col = col;
tems_safe_display(&da, credp, called_from);
mutex_exit(&tem->tvs_lock);
mutex_exit(&tems.ts_lock);
}
#endif
void
tem_safe_text_copy(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp, enum called_from called_from)
{
struct vis_conscopy da;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
da.s_row = s_row;
da.s_col = s_col;
da.e_row = e_row;
da.e_col = e_col;
da.t_row = t_row;
da.t_col = t_col;
tems_safe_copy(&da, credp, called_from);
}
void
tem_safe_text_cls(struct tem_vt_state *tem,
int count, screen_pos_t row, screen_pos_t col, cred_t *credp,
enum called_from called_from)
{
text_attr_t attr;
term_char_t c;
int i;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
TEM_ATTR_SCREEN_REVERSE);
c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
if (count > tems.ts_c_dimension.width ||
col + count > tems.ts_c_dimension.width)
count = tems.ts_c_dimension.width - col;
for (i = 0; i < count; i++)
tems.ts_blank_line[i] = c;
tem_safe_text_display(tem, tems.ts_blank_line, count, row, col,
credp, called_from);
}
void
tem_safe_pix_display(struct tem_vt_state *tem,
term_char_t *string, int count,
screen_pos_t row, screen_pos_t col,
cred_t *credp, enum called_from called_from)
{
struct vis_consdisplay da;
int i;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
da.data = (uchar_t *)tem->tvs_pix_data;
da.width = (screen_size_t)tems.ts_font.vf_width;
da.height = (screen_size_t)tems.ts_font.vf_height;
da.row = (row * da.height) + tems.ts_p_offset.y;
da.col = (col * da.width) + tems.ts_p_offset.x;
for (i = 0; i < count; i++) {
if (!TEM_ATTR_ISSET(string[i].tc_char, TEM_ATTR_IMAGE)) {
tem_safe_callback_bit2pix(tem, &string[i]);
tems_safe_display(&da, credp, called_from);
}
da.col += da.width;
}
}
void
tem_safe_pix_copy(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row,
cred_t *credp,
enum called_from called_from)
{
struct vis_conscopy ma;
static boolean_t need_clear = B_TRUE;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (need_clear && tem->tvs_first_line > 0) {
tem_safe_pix_clear_prom_output(tem, credp, called_from);
}
need_clear = B_FALSE;
ma.s_row = s_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
ma.e_row = (e_row + 1) * tems.ts_font.vf_height +
tems.ts_p_offset.y - 1;
ma.t_row = t_row * tems.ts_font.vf_height + tems.ts_p_offset.y;
if (tem->tvs_first_line > 0 && t_row < s_row && t_col == 0 &&
e_col == tems.ts_c_dimension.width - 1) {
ma.s_col = s_col * tems.ts_font.vf_width;
ma.e_col = tems.ts_p_dimension.width - 1;
ma.t_col = t_col * tems.ts_font.vf_width;
} else {
ma.s_col = s_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
ma.e_col = (e_col + 1) * tems.ts_font.vf_width +
tems.ts_p_offset.x - 1;
ma.t_col = t_col * tems.ts_font.vf_width + tems.ts_p_offset.x;
}
tems_safe_copy(&ma, credp, called_from);
if (tem->tvs_first_line > 0 && t_row < s_row) {
tem->tvs_first_line -= (s_row - t_row);
if (tem->tvs_first_line <= 0) {
tem->tvs_first_line = 0;
}
}
}
void
tem_safe_pix_bit2pix(struct tem_vt_state *tem, term_char_t *c)
{
text_color_t fg, bg;
void (*fp)(struct tem_vt_state *, tem_char_t,
text_color_t, text_color_t);
tem_safe_get_color(tem, &fg, &bg, c);
switch (tems.ts_pdepth) {
case 4:
fp = bit_to_pix4;
break;
case 8:
fp = bit_to_pix8;
break;
case 15:
case 16:
fp = bit_to_pix16;
break;
case 24:
fp = bit_to_pix24;
break;
case 32:
fp = bit_to_pix32;
break;
default:
return;
}
fp(tem, c->tc_char, fg, bg);
}
void
tem_safe_pix_cls(struct tem_vt_state *tem, int count,
screen_pos_t row, screen_pos_t col, cred_t *credp,
enum called_from called_from)
{
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tem_safe_pix_cls_range(tem, row, 1, tems.ts_p_offset.y,
col, count, tems.ts_p_offset.x, B_FALSE, credp, called_from);
}
static void
tem_safe_pix_clear_prom_output(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
int nrows, ncols, width, height, offset;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
width = tems.ts_font.vf_width;
height = tems.ts_font.vf_height;
offset = tems.ts_p_offset.y % height;
nrows = tems.ts_p_offset.y / height;
ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
if (nrows > 0)
tem_safe_pix_cls_range(tem, 0, nrows, offset, 0, ncols, 0,
B_FALSE, credp, called_from);
}
void
tem_safe_pix_clear_entire_screen(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
struct vis_consclear cl;
text_color_t fg_color;
text_color_t bg_color;
text_attr_t attr;
term_char_t c;
int nrows, ncols, width, height;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
TEM_ATTR_SCREEN_REVERSE);
c.tc_char = TEM_ATTR(attr);
tem_safe_get_color(tem, &fg_color, &bg_color, &c);
tem_safe_set_color(&bg_color, &cl.bg_color);
if (tems_cls_layered(&cl, credp) == 0)
return;
width = tems.ts_font.vf_width;
height = tems.ts_font.vf_height;
nrows = (tems.ts_p_dimension.height + (height - 1))/ height;
ncols = (tems.ts_p_dimension.width + (width - 1))/ width;
tem_safe_pix_cls_range(tem, 0, nrows, tems.ts_p_offset.y, 0, ncols,
tems.ts_p_offset.x, B_FALSE, credp, called_from);
if (tem->tvs_first_line > 0)
tem->tvs_first_line = 0;
}
static void
tem_safe_cls(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
int row;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (tems.ts_display_mode == VIS_TEXT) {
for (row = 0; row < tems.ts_c_dimension.height; row++) {
tem_safe_clear_chars(tem, tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
tem->tvs_c_cursor.row = 0;
tem->tvs_c_cursor.col = 0;
tem_safe_align_cursor(tem);
return;
}
ASSERT(tems.ts_display_mode == VIS_PIXEL);
for (row = 0; row < tems.ts_c_dimension.height; row++) {
tem_safe_virtual_cls(tem, tems.ts_c_dimension.width, row, 0);
}
tem->tvs_c_cursor.row = 0;
tem->tvs_c_cursor.col = 0;
tem_safe_align_cursor(tem);
if (!tem->tvs_isactive)
return;
tem_safe_pix_clear_entire_screen(tem, credp, called_from);
}
static void
tem_safe_back_tab(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
int i;
screen_pos_t tabstop;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tabstop = 0;
for (i = tem->tvs_ntabs - 1; i >= 0; i--) {
if (tem->tvs_tabs[i] < tem->tvs_c_cursor.col) {
tabstop = tem->tvs_tabs[i];
break;
}
}
tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
tabstop, credp, called_from);
}
static void
tem_safe_tab(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from)
{
size_t i;
screen_pos_t tabstop;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tabstop = tems.ts_c_dimension.width - 1;
for (i = 0; i < tem->tvs_ntabs; i++) {
if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
tabstop = tem->tvs_tabs[i];
break;
}
}
tem_safe_mv_cursor(tem, tem->tvs_c_cursor.row,
tabstop, credp, called_from);
}
static void
tem_safe_set_tab(struct tem_vt_state *tem)
{
size_t i, j;
if (tem->tvs_ntabs == tem->tvs_maxtab)
return;
if (tem->tvs_ntabs == 0 ||
tem->tvs_tabs[tem->tvs_ntabs] < tem->tvs_c_cursor.col) {
tem->tvs_tabs[tem->tvs_ntabs++] = tem->tvs_c_cursor.col;
return;
}
for (i = 0; i < tem->tvs_ntabs; i++) {
if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col)
return;
if (tem->tvs_tabs[i] > tem->tvs_c_cursor.col) {
for (j = tem->tvs_ntabs - 1; j >= i; j--)
tem->tvs_tabs[j+ 1] = tem->tvs_tabs[j];
tem->tvs_tabs[i] = tem->tvs_c_cursor.col;
tem->tvs_ntabs++;
return;
}
}
}
static void
tem_safe_clear_tabs(struct tem_vt_state *tem, int action)
{
size_t i, j;
switch (action) {
case 3:
tem->tvs_ntabs = 0;
break;
case 0:
for (i = 0; i < tem->tvs_ntabs; i++) {
if (tem->tvs_tabs[i] == tem->tvs_c_cursor.col) {
tem->tvs_ntabs--;
for (j = i; j < tem->tvs_ntabs; j++)
tem->tvs_tabs[j] = tem->tvs_tabs[j + 1];
return;
}
}
break;
}
}
static void
tem_safe_mv_cursor(struct tem_vt_state *tem, int row, int col,
cred_t *credp, enum called_from called_from)
{
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (row < 0)
row = 0;
if (row >= tems.ts_c_dimension.height)
row = tems.ts_c_dimension.height - 1;
if (col < 0)
col = 0;
if (col >= tems.ts_c_dimension.width) {
tem->tvs_stateflags |= TVS_WRAPPED;
col = tems.ts_c_dimension.width - 1;
} else {
tem->tvs_stateflags &= ~TVS_WRAPPED;
}
tem_safe_send_data(tem, credp, called_from);
tem->tvs_c_cursor.row = (screen_pos_t)row;
tem->tvs_c_cursor.col = (screen_pos_t)col;
tem_safe_align_cursor(tem);
}
void
tem_safe_reset_emulator(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from,
boolean_t init_color)
{
int j;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tem->tvs_c_cursor.row = 0;
tem->tvs_c_cursor.col = 0;
tem->tvs_r_cursor.row = 0;
tem->tvs_r_cursor.col = 0;
tem->tvs_s_cursor.row = 0;
tem->tvs_s_cursor.col = 0;
tem->tvs_outindex = 0;
tem->tvs_state = A_STATE_START;
tem->tvs_gotparam = B_FALSE;
tem->tvs_curparam = 0;
tem->tvs_paramval = 0;
tem->tvs_nscroll = 1;
if (init_color) {
tem->tvs_alpha = 0xff;
tem->tvs_fg_color = tems.ts_init_color.fg_color;
tem->tvs_bg_color = tems.ts_init_color.bg_color;
tem->tvs_flags = tems.ts_init_color.a_flags;
}
tem->tvs_ntabs = 0;
for (j = 8; j < tems.ts_c_dimension.width; j += 8)
tem->tvs_tabs[tem->tvs_ntabs++] = (screen_pos_t)j;
for (j = 0; j < TEM_MAXPARAMS; j++)
tem->tvs_params[j] = 0;
}
void
tem_safe_reset_display(struct tem_vt_state *tem,
cred_t *credp, enum called_from called_from,
boolean_t clear_txt, boolean_t init_color)
{
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
tem_safe_reset_emulator(tem, credp, called_from, init_color);
if (clear_txt) {
if (tem->tvs_isactive)
tem_safe_callback_cursor(tem,
VIS_HIDE_CURSOR, credp, called_from);
tem_safe_cls(tem, credp, called_from);
if (tem->tvs_isactive)
tem_safe_callback_cursor(tem,
VIS_DISPLAY_CURSOR, credp, called_from);
}
}
static void
tem_safe_shift(
struct tem_vt_state *tem,
int count,
int direction,
cred_t *credp,
enum called_from called_from)
{
int rest_of_line;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
rest_of_line = tems.ts_c_dimension.width - tem->tvs_c_cursor.col;
if (count > rest_of_line)
count = rest_of_line;
if (count <= 0)
return;
switch (direction) {
case TEM_SHIFT_LEFT:
if (count < rest_of_line) {
tem_safe_copy_area(tem,
tem->tvs_c_cursor.col + count,
tem->tvs_c_cursor.row,
tems.ts_c_dimension.width - 1,
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col,
tem->tvs_c_cursor.row,
credp, called_from);
}
tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
(tems.ts_c_dimension.width - count), credp,
called_from);
break;
case TEM_SHIFT_RIGHT:
if (count < rest_of_line) {
tem_safe_copy_area(tem,
tem->tvs_c_cursor.col,
tem->tvs_c_cursor.row,
tems.ts_c_dimension.width - count - 1,
tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col + count,
tem->tvs_c_cursor.row,
credp, called_from);
}
tem_safe_clear_chars(tem, count, tem->tvs_c_cursor.row,
tem->tvs_c_cursor.col, credp, called_from);
break;
}
}
void
tem_safe_text_cursor(struct tem_vt_state *tem, short action,
cred_t *credp, enum called_from called_from)
{
struct vis_conscursor ca;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
ca.row = tem->tvs_c_cursor.row;
ca.col = tem->tvs_c_cursor.col;
ca.action = action;
tems_safe_cursor(&ca, credp, called_from);
if (action == VIS_GET_CURSOR) {
tem->tvs_c_cursor.row = ca.row;
tem->tvs_c_cursor.col = ca.col;
}
}
void
tem_safe_pix_cursor(struct tem_vt_state *tem, short action,
cred_t *credp, enum called_from called_from)
{
struct vis_conscursor ca;
text_color_t fg, bg;
term_char_t c;
text_attr_t attr;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
ca.row = tem->tvs_c_cursor.row * tems.ts_font.vf_height +
tems.ts_p_offset.y;
ca.col = tem->tvs_c_cursor.col * tems.ts_font.vf_width +
tems.ts_p_offset.x;
ca.width = (screen_size_t)tems.ts_font.vf_width;
ca.height = (screen_size_t)tems.ts_font.vf_height;
tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
TEM_ATTR_REVERSE);
c.tc_char = TEM_ATTR(attr);
tem_safe_get_color(tem, &fg, &bg, &c);
tem_safe_set_color(&fg, &ca.fg_color);
tem_safe_set_color(&bg, &ca.bg_color);
ca.action = action;
tems_safe_cursor(&ca, credp, called_from);
if (action == VIS_GET_CURSOR) {
tem->tvs_c_cursor.row = 0;
tem->tvs_c_cursor.col = 0;
if (ca.row != 0) {
tem->tvs_c_cursor.row = (ca.row - tems.ts_p_offset.y) /
tems.ts_font.vf_height;
}
if (ca.col != 0) {
tem->tvs_c_cursor.col = (ca.col - tems.ts_p_offset.x) /
tems.ts_font.vf_width;
}
}
}
static void
bit_to_pix4(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
text_color_t bg)
{
uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
font_bit_to_pix4(&tems.ts_font, dest, c, fg.n, bg.n);
}
static void
bit_to_pix8(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
text_color_t bg)
{
uint8_t *dest = (uint8_t *)tem->tvs_pix_data;
font_bit_to_pix8(&tems.ts_font, dest, c, fg.n, bg.n);
}
static void
bit_to_pix16(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
text_color_t bg)
{
uint16_t *dest;
dest = (uint16_t *)tem->tvs_pix_data;
font_bit_to_pix16(&tems.ts_font, dest, c, fg.n, bg.n);
}
static void
bit_to_pix24(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
text_color_t bg)
{
uint8_t *dest;
dest = (uint8_t *)tem->tvs_pix_data;
font_bit_to_pix24(&tems.ts_font, dest, c, fg.n, bg.n);
}
static void
bit_to_pix32(struct tem_vt_state *tem, tem_char_t c, text_color_t fg,
text_color_t bg)
{
uint32_t *dest;
dest = (uint32_t *)tem->tvs_pix_data;
font_bit_to_pix32(&tems.ts_font, dest, c, fg.n, bg.n);
}
void
tem_safe_get_attr(struct tem_vt_state *tem, text_color_t *fg,
text_color_t *bg, text_attr_t *attr, uint8_t flag)
{
if (tem->tvs_flags & flag) {
*fg = tem->tvs_bg_color;
*bg = tem->tvs_fg_color;
} else {
*fg = tem->tvs_fg_color;
*bg = tem->tvs_bg_color;
}
if (attr != NULL)
*attr = tem->tvs_flags;
}
static void
tem_safe_get_color(struct tem_vt_state *tem, text_color_t *fg,
text_color_t *bg, term_char_t *c)
{
boolean_t bold_font;
*fg = c->tc_fg_color;
*bg = c->tc_bg_color;
bold_font = tems.ts_font.vf_map_count[VFNT_MAP_BOLD] != 0;
if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG) &&
c->tc_fg_color.n < XLATE_NCOLORS) {
if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_FG) ||
(TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BOLD) && !bold_font))
fg->n = brt_xlate[c->tc_fg_color.n];
else
fg->n = dim_xlate[c->tc_fg_color.n];
}
if (!TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG) &&
c->tc_bg_color.n < XLATE_NCOLORS) {
if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_BRIGHT_BG))
bg->n = brt_xlate[c->tc_bg_color.n];
else
bg->n = dim_xlate[c->tc_bg_color.n];
}
if (tems.ts_display_mode == VIS_TEXT)
return;
if (tems.ts_pdepth == 8) {
#ifndef _HAVE_TEM_FIRMWARE
fg->n = tems.ts_color_map(fg->n);
bg->n = tems.ts_color_map(bg->n);
#endif
return;
}
if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_FG)) {
fg->n = rgb_to_color(&rgb_info,
fg->rgb.a, fg->rgb.r, fg->rgb.g, fg->rgb.b);
} else {
#ifdef _HAVE_TEM_FIRMWARE
if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32)
fg->n = PIX4TO32(fg->n);
#else
fg->n = rgb_color_map(&rgb_info, fg->n, tem->tvs_alpha);
#endif
}
if (TEM_ATTR_ISSET(c->tc_char, TEM_ATTR_RGB_BG)) {
bg->n = rgb_to_color(&rgb_info,
bg->rgb.a, bg->rgb.r, bg->rgb.g, bg->rgb.b);
} else {
#ifdef _HAVE_TEM_FIRMWARE
if (tems.ts_pdepth == 24 || tems.ts_pdepth == 32)
bg->n = PIX4TO32(bg->n);
#else
bg->n = rgb_color_map(&rgb_info, bg->n, tem->tvs_alpha);
#endif
}
}
static void
tem_safe_set_color(text_color_t *t, color_t *c)
{
switch (tems.ts_pdepth) {
case 4:
c->four = t->n & 0xFF;
break;
case 8:
c->eight = t->n & 0xFF;
break;
case 15:
case 16:
c->sixteen[0] = (t->n >> 8) & 0xFF;
c->sixteen[1] = t->n & 0xFF;
break;
case 24:
c->twentyfour[0] = (t->n >> 16) & 0xFF;
c->twentyfour[1] = (t->n >> 8) & 0xFF;
c->twentyfour[2] = t->n & 0xFF;
break;
default:
*(uint32_t *)c = t->n;
break;
}
}
void
tem_safe_pix_cls_range(struct tem_vt_state *tem,
screen_pos_t row, int nrows, int offset_y,
screen_pos_t col, int ncols, int offset_x,
boolean_t sroll_up, cred_t *credp,
enum called_from called_from)
{
struct vis_consdisplay da;
int i, j;
int row_add = 0;
term_char_t c;
text_attr_t attr;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (sroll_up)
row_add = tems.ts_c_dimension.height - 1;
da.width = (screen_size_t)tems.ts_font.vf_width;
da.height = (screen_size_t)tems.ts_font.vf_height;
tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
TEM_ATTR_SCREEN_REVERSE);
c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
tem_safe_callback_bit2pix(tem, &c);
da.data = (uchar_t *)tem->tvs_pix_data;
for (i = 0; i < nrows; i++, row++) {
da.row = (row + row_add) * da.height + offset_y;
da.col = col * da.width + offset_x;
for (j = 0; j < ncols; j++) {
tems_safe_display(&da, credp, called_from);
da.col += da.width;
}
}
}
static void
tem_safe_virtual_display(struct tem_vt_state *tem, term_char_t *string,
int count, screen_pos_t row, screen_pos_t col)
{
int i, width;
term_char_t *addr;
if (row < 0 || row >= tems.ts_c_dimension.height ||
col < 0 || col >= tems.ts_c_dimension.width ||
col + count > tems.ts_c_dimension.width)
return;
width = tems.ts_c_dimension.width;
addr = tem->tvs_screen_buf + (row * width + col);
for (i = 0; i < count; i++) {
*addr++ = string[i];
}
}
static void
i_virtual_copy_tem_chars(term_char_t *base,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row)
{
term_char_t *from;
term_char_t *to;
int cnt;
screen_size_t chars_per_row;
term_char_t *to_row_start;
term_char_t *from_row_start;
screen_size_t rows_to_move;
int cols = tems.ts_c_dimension.width;
chars_per_row = e_col - s_col + 1;
rows_to_move = e_row - s_row + 1;
to_row_start = base + ((t_row * cols) + t_col);
from_row_start = base + ((s_row * cols) + s_col);
if (to_row_start < from_row_start) {
while (rows_to_move-- > 0) {
to = to_row_start;
from = from_row_start;
to_row_start += cols;
from_row_start += cols;
for (cnt = chars_per_row; cnt-- > 0; )
*to++ = *from++;
}
} else {
cnt = rows_to_move * cols + chars_per_row;
to_row_start += cnt;
from_row_start += cnt;
while (rows_to_move-- > 0) {
to_row_start -= cols;
from_row_start -= cols;
to = to_row_start;
from = from_row_start;
for (cnt = chars_per_row; cnt-- > 0; )
*--to = *--from;
}
}
}
static void
tem_safe_virtual_copy(struct tem_vt_state *tem,
screen_pos_t s_col, screen_pos_t s_row,
screen_pos_t e_col, screen_pos_t e_row,
screen_pos_t t_col, screen_pos_t t_row)
{
screen_size_t chars_per_row;
screen_size_t rows_to_move;
int rows = tems.ts_c_dimension.height;
int cols = tems.ts_c_dimension.width;
if (s_col < 0 || s_col >= cols ||
s_row < 0 || s_row >= rows ||
e_col < 0 || e_col >= cols ||
e_row < 0 || e_row >= rows ||
t_col < 0 || t_col >= cols ||
t_row < 0 || t_row >= rows ||
s_col > e_col ||
s_row > e_row)
return;
chars_per_row = e_col - s_col + 1;
rows_to_move = e_row - s_row + 1;
if (t_row + rows_to_move > rows ||
t_col + chars_per_row > cols)
return;
i_virtual_copy_tem_chars(tem->tvs_screen_buf, s_col, s_row,
e_col, e_row, t_col, t_row);
}
static void
tem_safe_virtual_cls(struct tem_vt_state *tem,
int count, screen_pos_t row, screen_pos_t col)
{
int i;
text_attr_t attr;
term_char_t c;
tem_safe_get_attr(tem, &c.tc_fg_color, &c.tc_bg_color, &attr,
TEM_ATTR_SCREEN_REVERSE);
c.tc_char = TEM_ATTR(attr & ~TEM_ATTR_UNDERLINE) | ' ';
for (i = 0; i < tems.ts_c_dimension.width; i++)
tems.ts_blank_line[i] = c;
tem_safe_virtual_display(tem, tems.ts_blank_line, count, row, col);
}
void
tem_safe_blank_screen(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
int row;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (tems.ts_display_mode == VIS_PIXEL) {
tem_safe_pix_clear_entire_screen(tem, credp, called_from);
return;
}
for (row = 0; row < tems.ts_c_dimension.height; row++) {
tem_safe_callback_cls(tem,
tems.ts_c_dimension.width,
row, 0, credp, called_from);
}
}
void
tem_safe_unblank_screen(struct tem_vt_state *tem, cred_t *credp,
enum called_from called_from)
{
int row;
ASSERT((MUTEX_HELD(&tems.ts_lock) && MUTEX_HELD(&tem->tvs_lock)) ||
called_from == CALLED_FROM_STANDALONE);
if (tems.ts_display_mode == VIS_PIXEL)
tem_safe_pix_clear_entire_screen(tem, credp, called_from);
tem_safe_callback_cursor(tem, VIS_HIDE_CURSOR, credp, called_from);
for (row = 0; row < tems.ts_c_dimension.height; row++) {
tem_safe_callback_display(tem, tem->tvs_screen_rows[row],
tems.ts_c_dimension.width, row, 0, credp, called_from);
}
tem_safe_callback_cursor(tem, VIS_DISPLAY_CURSOR, credp, called_from);
}