Rename --*able-softmmu --*able-system.
[qemu/mini2440.git] / console.c
blobd1eb406550cd565057aaab837854eccfd488fa1f
1 /*
2 * QEMU graphical console
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "vl.h"
26 //#define DEBUG_CONSOLE
27 #define DEFAULT_BACKSCROLL 512
28 #define MAX_CONSOLES 12
30 #define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
31 #define RGB(r, g, b) RGBA(r, g, b, 0xff)
33 typedef struct TextAttributes {
34 uint8_t fgcol:4;
35 uint8_t bgcol:4;
36 uint8_t bold:1;
37 uint8_t uline:1;
38 uint8_t blink:1;
39 uint8_t invers:1;
40 uint8_t unvisible:1;
41 } TextAttributes;
43 typedef struct TextCell {
44 uint8_t ch;
45 TextAttributes t_attrib;
46 } TextCell;
48 #define MAX_ESC_PARAMS 3
50 enum TTYState {
51 TTY_STATE_NORM,
52 TTY_STATE_ESC,
53 TTY_STATE_CSI,
57 struct TextConsole {
58 int text_console; /* true if text console */
59 DisplayState *ds;
60 int g_width, g_height;
61 int width;
62 int height;
63 int total_height;
64 int backscroll_height;
65 int x, y;
66 int y_displayed;
67 int y_base;
68 TextAttributes t_attrib_default; /* default text attributes */
69 TextAttributes t_attrib; /* currently active text attributes */
70 TextCell *cells;
72 enum TTYState state;
73 int esc_params[MAX_ESC_PARAMS];
74 int nb_esc_params;
76 /* kbd read handler */
77 IOReadHandler *fd_read;
78 void *fd_opaque;
81 static TextConsole *active_console;
82 static TextConsole *consoles[MAX_CONSOLES];
83 static int nb_consoles = 0;
85 /* convert a RGBA color to a color index usable in graphic primitives */
86 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
88 unsigned int r, g, b, color;
90 switch(ds->depth) {
91 #if 0
92 case 8:
93 r = (rgba >> 16) & 0xff;
94 g = (rgba >> 8) & 0xff;
95 b = (rgba) & 0xff;
96 color = (rgb_to_index[r] * 6 * 6) +
97 (rgb_to_index[g] * 6) +
98 (rgb_to_index[b]);
99 break;
100 #endif
101 case 15:
102 r = (rgba >> 16) & 0xff;
103 g = (rgba >> 8) & 0xff;
104 b = (rgba) & 0xff;
105 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
106 break;
107 case 16:
108 r = (rgba >> 16) & 0xff;
109 g = (rgba >> 8) & 0xff;
110 b = (rgba) & 0xff;
111 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
112 break;
113 case 32:
114 default:
115 color = rgba;
116 break;
118 return color;
121 static void vga_fill_rect (DisplayState *ds,
122 int posx, int posy, int width, int height, uint32_t color)
124 uint8_t *d, *d1;
125 int x, y, bpp;
127 bpp = (ds->depth + 7) >> 3;
128 d1 = ds->data +
129 ds->linesize * posy + bpp * posx;
130 for (y = 0; y < height; y++) {
131 d = d1;
132 switch(bpp) {
133 case 1:
134 for (x = 0; x < width; x++) {
135 *((uint8_t *)d) = color;
136 d++;
138 break;
139 case 2:
140 for (x = 0; x < width; x++) {
141 *((uint16_t *)d) = color;
142 d += 2;
144 break;
145 case 4:
146 for (x = 0; x < width; x++) {
147 *((uint32_t *)d) = color;
148 d += 4;
150 break;
152 d1 += ds->linesize;
156 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
157 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
159 const uint8_t *s;
160 uint8_t *d;
161 int wb, y, bpp;
163 bpp = (ds->depth + 7) >> 3;
164 wb = w * bpp;
165 if (yd <= ys) {
166 s = ds->data +
167 ds->linesize * ys + bpp * xs;
168 d = ds->data +
169 ds->linesize * yd + bpp * xd;
170 for (y = 0; y < h; y++) {
171 memmove(d, s, wb);
172 d += ds->linesize;
173 s += ds->linesize;
175 } else {
176 s = ds->data +
177 ds->linesize * (ys + h - 1) + bpp * xs;
178 d = ds->data +
179 ds->linesize * (yd + h - 1) + bpp * xd;
180 for (y = 0; y < h; y++) {
181 memmove(d, s, wb);
182 d -= ds->linesize;
183 s -= ds->linesize;
188 /***********************************************************/
189 /* basic char display */
191 #define FONT_HEIGHT 16
192 #define FONT_WIDTH 8
194 #include "vgafont.h"
196 #define cbswap_32(__x) \
197 ((uint32_t)( \
198 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
199 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
200 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
201 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
203 #ifdef WORDS_BIGENDIAN
204 #define PAT(x) x
205 #else
206 #define PAT(x) cbswap_32(x)
207 #endif
209 static const uint32_t dmask16[16] = {
210 PAT(0x00000000),
211 PAT(0x000000ff),
212 PAT(0x0000ff00),
213 PAT(0x0000ffff),
214 PAT(0x00ff0000),
215 PAT(0x00ff00ff),
216 PAT(0x00ffff00),
217 PAT(0x00ffffff),
218 PAT(0xff000000),
219 PAT(0xff0000ff),
220 PAT(0xff00ff00),
221 PAT(0xff00ffff),
222 PAT(0xffff0000),
223 PAT(0xffff00ff),
224 PAT(0xffffff00),
225 PAT(0xffffffff),
228 static const uint32_t dmask4[4] = {
229 PAT(0x00000000),
230 PAT(0x0000ffff),
231 PAT(0xffff0000),
232 PAT(0xffffffff),
235 static uint32_t color_table[2][8];
237 enum color_names {
238 COLOR_BLACK = 0,
239 COLOR_RED = 1,
240 COLOR_GREEN = 2,
241 COLOR_YELLOW = 3,
242 COLOR_BLUE = 4,
243 COLOR_MAGENTA = 5,
244 COLOR_CYAN = 6,
245 COLOR_WHITE = 7
248 static const uint32_t color_table_rgb[2][8] = {
249 { /* dark */
250 RGB(0x00, 0x00, 0x00), /* black */
251 RGB(0xaa, 0x00, 0x00), /* red */
252 RGB(0x00, 0xaa, 0x00), /* green */
253 RGB(0xaa, 0xaa, 0x00), /* yellow */
254 RGB(0x00, 0x00, 0xaa), /* blue */
255 RGB(0xaa, 0x00, 0xaa), /* magenta */
256 RGB(0x00, 0xaa, 0xaa), /* cyan */
257 RGB(0xaa, 0xaa, 0xaa), /* white */
259 { /* bright */
260 RGB(0x00, 0x00, 0x00), /* black */
261 RGB(0xff, 0x00, 0x00), /* red */
262 RGB(0x00, 0xff, 0x00), /* green */
263 RGB(0xff, 0xff, 0x00), /* yellow */
264 RGB(0x00, 0x00, 0xff), /* blue */
265 RGB(0xff, 0x00, 0xff), /* magenta */
266 RGB(0x00, 0xff, 0xff), /* cyan */
267 RGB(0xff, 0xff, 0xff), /* white */
271 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
273 switch(ds->depth) {
274 case 8:
275 col |= col << 8;
276 col |= col << 16;
277 break;
278 case 15:
279 case 16:
280 col |= col << 16;
281 break;
282 default:
283 break;
286 return col;
288 #ifdef DEBUG_CONSOLE
289 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
291 if (t_attrib->bold) {
292 printf("b");
293 } else {
294 printf(" ");
296 if (t_attrib->uline) {
297 printf("u");
298 } else {
299 printf(" ");
301 if (t_attrib->blink) {
302 printf("l");
303 } else {
304 printf(" ");
306 if (t_attrib->invers) {
307 printf("i");
308 } else {
309 printf(" ");
311 if (t_attrib->unvisible) {
312 printf("n");
313 } else {
314 printf(" ");
317 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
319 #endif
321 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
322 TextAttributes *t_attrib)
324 uint8_t *d;
325 const uint8_t *font_ptr;
326 unsigned int font_data, linesize, xorcol, bpp;
327 int i;
328 unsigned int fgcol, bgcol;
330 #ifdef DEBUG_CONSOLE
331 printf("x: %2i y: %2i", x, y);
332 console_print_text_attributes(t_attrib, ch);
333 #endif
335 if (t_attrib->invers) {
336 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
337 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
338 } else {
339 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
340 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
343 bpp = (ds->depth + 7) >> 3;
344 d = ds->data +
345 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
346 linesize = ds->linesize;
347 font_ptr = vgafont16 + FONT_HEIGHT * ch;
348 xorcol = bgcol ^ fgcol;
349 switch(ds->depth) {
350 case 8:
351 for(i = 0; i < FONT_HEIGHT; i++) {
352 font_data = *font_ptr++;
353 if (t_attrib->uline
354 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
355 font_data = 0xFFFF;
357 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
358 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
359 d += linesize;
361 break;
362 case 16:
363 case 15:
364 for(i = 0; i < FONT_HEIGHT; i++) {
365 font_data = *font_ptr++;
366 if (t_attrib->uline
367 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
368 font_data = 0xFFFF;
370 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
371 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
372 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
373 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
374 d += linesize;
376 break;
377 case 32:
378 for(i = 0; i < FONT_HEIGHT; i++) {
379 font_data = *font_ptr++;
380 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
381 font_data = 0xFFFF;
383 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
384 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
385 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
386 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
387 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
388 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
389 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
390 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
391 d += linesize;
393 break;
397 static void text_console_resize(TextConsole *s)
399 TextCell *cells, *c, *c1;
400 int w1, x, y, last_width;
402 last_width = s->width;
403 s->width = s->g_width / FONT_WIDTH;
404 s->height = s->g_height / FONT_HEIGHT;
406 w1 = last_width;
407 if (s->width < w1)
408 w1 = s->width;
410 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
411 for(y = 0; y < s->total_height; y++) {
412 c = &cells[y * s->width];
413 if (w1 > 0) {
414 c1 = &s->cells[y * last_width];
415 for(x = 0; x < w1; x++) {
416 *c++ = *c1++;
419 for(x = w1; x < s->width; x++) {
420 c->ch = ' ';
421 c->t_attrib = s->t_attrib_default;
422 c++;
425 free(s->cells);
426 s->cells = cells;
429 static void update_xy(TextConsole *s, int x, int y)
431 TextCell *c;
432 int y1, y2;
434 if (s == active_console) {
435 y1 = (s->y_base + y) % s->total_height;
436 y2 = y1 - s->y_displayed;
437 if (y2 < 0)
438 y2 += s->total_height;
439 if (y2 < s->height) {
440 c = &s->cells[y1 * s->width + x];
441 vga_putcharxy(s->ds, x, y2, c->ch,
442 &(c->t_attrib));
443 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
444 FONT_WIDTH, FONT_HEIGHT);
449 static void console_show_cursor(TextConsole *s, int show)
451 TextCell *c;
452 int y, y1;
454 if (s == active_console) {
455 y1 = (s->y_base + s->y) % s->total_height;
456 y = y1 - s->y_displayed;
457 if (y < 0)
458 y += s->total_height;
459 if (y < s->height) {
460 c = &s->cells[y1 * s->width + s->x];
461 if (show) {
462 TextAttributes t_attrib = s->t_attrib_default;
463 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
464 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
465 } else {
466 vga_putcharxy(s->ds, s->x, y, c->ch,
467 &(c->t_attrib));
469 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
470 FONT_WIDTH, FONT_HEIGHT);
475 static void console_refresh(TextConsole *s)
477 TextCell *c;
478 int x, y, y1;
480 if (s != active_console)
481 return;
483 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
484 color_table[0][COLOR_BLACK]);
485 y1 = s->y_displayed;
486 for(y = 0; y < s->height; y++) {
487 c = s->cells + y1 * s->width;
488 for(x = 0; x < s->width; x++) {
489 vga_putcharxy(s->ds, x, y, c->ch,
490 &(c->t_attrib));
491 c++;
493 if (++y1 == s->total_height)
494 y1 = 0;
496 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
497 console_show_cursor(s, 1);
500 static void console_scroll(int ydelta)
502 TextConsole *s;
503 int i, y1;
505 s = active_console;
506 if (!s || !s->text_console)
507 return;
509 if (ydelta > 0) {
510 for(i = 0; i < ydelta; i++) {
511 if (s->y_displayed == s->y_base)
512 break;
513 if (++s->y_displayed == s->total_height)
514 s->y_displayed = 0;
516 } else {
517 ydelta = -ydelta;
518 i = s->backscroll_height;
519 if (i > s->total_height - s->height)
520 i = s->total_height - s->height;
521 y1 = s->y_base - i;
522 if (y1 < 0)
523 y1 += s->total_height;
524 for(i = 0; i < ydelta; i++) {
525 if (s->y_displayed == y1)
526 break;
527 if (--s->y_displayed < 0)
528 s->y_displayed = s->total_height - 1;
531 console_refresh(s);
534 static void console_put_lf(TextConsole *s)
536 TextCell *c;
537 int x, y1;
539 s->x = 0;
540 s->y++;
541 if (s->y >= s->height) {
542 s->y = s->height - 1;
544 if (s->y_displayed == s->y_base) {
545 if (++s->y_displayed == s->total_height)
546 s->y_displayed = 0;
548 if (++s->y_base == s->total_height)
549 s->y_base = 0;
550 if (s->backscroll_height < s->total_height)
551 s->backscroll_height++;
552 y1 = (s->y_base + s->height - 1) % s->total_height;
553 c = &s->cells[y1 * s->width];
554 for(x = 0; x < s->width; x++) {
555 c->ch = ' ';
556 c->t_attrib = s->t_attrib_default;
557 c++;
559 if (s == active_console && s->y_displayed == s->y_base) {
560 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
561 s->width * FONT_WIDTH,
562 (s->height - 1) * FONT_HEIGHT);
563 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
564 s->width * FONT_WIDTH, FONT_HEIGHT,
565 color_table[0][s->t_attrib_default.bgcol]);
566 dpy_update(s->ds, 0, 0,
567 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
572 /* Set console attributes depending on the current escape codes.
573 * NOTE: I know this code is not very efficient (checking every color for it
574 * self) but it is more readable and better maintainable.
576 static void console_handle_escape(TextConsole *s)
578 int i;
580 if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
581 s->t_attrib = s->t_attrib_default;
582 return;
584 for (i=0; i<s->nb_esc_params; i++) {
585 switch (s->esc_params[i]) {
586 case 0: /* reset all console attributes to default */
587 s->t_attrib = s->t_attrib_default;
588 break;
589 case 1:
590 s->t_attrib.bold = 1;
591 break;
592 case 4:
593 s->t_attrib.uline = 1;
594 break;
595 case 5:
596 s->t_attrib.blink = 1;
597 break;
598 case 7:
599 s->t_attrib.invers = 1;
600 break;
601 case 8:
602 s->t_attrib.unvisible = 1;
603 break;
604 case 22:
605 s->t_attrib.bold = 0;
606 break;
607 case 24:
608 s->t_attrib.uline = 0;
609 break;
610 case 25:
611 s->t_attrib.blink = 0;
612 break;
613 case 27:
614 s->t_attrib.invers = 0;
615 break;
616 case 28:
617 s->t_attrib.unvisible = 0;
618 break;
619 /* set foreground color */
620 case 30:
621 s->t_attrib.fgcol=COLOR_BLACK;
622 break;
623 case 31:
624 s->t_attrib.fgcol=COLOR_RED;
625 break;
626 case 32:
627 s->t_attrib.fgcol=COLOR_GREEN;
628 break;
629 case 33:
630 s->t_attrib.fgcol=COLOR_YELLOW;
631 break;
632 case 34:
633 s->t_attrib.fgcol=COLOR_BLUE;
634 break;
635 case 35:
636 s->t_attrib.fgcol=COLOR_MAGENTA;
637 break;
638 case 36:
639 s->t_attrib.fgcol=COLOR_CYAN;
640 break;
641 case 37:
642 s->t_attrib.fgcol=COLOR_WHITE;
643 break;
644 /* set background color */
645 case 40:
646 s->t_attrib.bgcol=COLOR_BLACK;
647 break;
648 case 41:
649 s->t_attrib.bgcol=COLOR_RED;
650 break;
651 case 42:
652 s->t_attrib.bgcol=COLOR_GREEN;
653 break;
654 case 43:
655 s->t_attrib.bgcol=COLOR_YELLOW;
656 break;
657 case 44:
658 s->t_attrib.bgcol=COLOR_BLUE;
659 break;
660 case 45:
661 s->t_attrib.bgcol=COLOR_MAGENTA;
662 break;
663 case 46:
664 s->t_attrib.bgcol=COLOR_CYAN;
665 break;
666 case 47:
667 s->t_attrib.bgcol=COLOR_WHITE;
668 break;
673 static void console_putchar(TextConsole *s, int ch)
675 TextCell *c;
676 int y1, i, x;
678 switch(s->state) {
679 case TTY_STATE_NORM:
680 switch(ch) {
681 case '\r': /* carriage return */
682 s->x = 0;
683 break;
684 case '\n': /* newline */
685 console_put_lf(s);
686 break;
687 case '\b': /* backspace */
688 if(s->x > 0) s->x--;
689 y1 = (s->y_base + s->y) % s->total_height;
690 c = &s->cells[y1 * s->width + s->x];
691 c->ch = ' ';
692 c->t_attrib = s->t_attrib;
693 update_xy(s, s->x, s->y);
694 break;
695 case '\t': /* tabspace */
696 if (s->x + (8 - (s->x % 8)) > s->width) {
697 console_put_lf(s);
698 } else {
699 s->x = s->x + (8 - (s->x % 8));
701 break;
702 case '\a': /* alert aka. bell */
703 /* TODO: has to be implemented */
704 break;
705 case 27: /* esc (introducing an escape sequence) */
706 s->state = TTY_STATE_ESC;
707 break;
708 default:
709 y1 = (s->y_base + s->y) % s->total_height;
710 c = &s->cells[y1 * s->width + s->x];
711 c->ch = ch;
712 c->t_attrib = s->t_attrib;
713 update_xy(s, s->x, s->y);
714 s->x++;
715 if (s->x >= s->width)
716 console_put_lf(s);
717 break;
719 break;
720 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
721 if (ch == '[') {
722 for(i=0;i<MAX_ESC_PARAMS;i++)
723 s->esc_params[i] = 0;
724 s->nb_esc_params = 0;
725 s->state = TTY_STATE_CSI;
726 } else {
727 s->state = TTY_STATE_NORM;
729 break;
730 case TTY_STATE_CSI: /* handle escape sequence parameters */
731 if (ch >= '0' && ch <= '9') {
732 if (s->nb_esc_params < MAX_ESC_PARAMS) {
733 s->esc_params[s->nb_esc_params] =
734 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
736 } else {
737 s->nb_esc_params++;
738 if (ch == ';')
739 break;
740 s->state = TTY_STATE_NORM;
741 switch(ch) {
742 case 'D':
743 if (s->x > 0)
744 s->x--;
745 break;
746 case 'C':
747 if (s->x < (s->width - 1))
748 s->x++;
749 break;
750 case 'K':
751 /* clear to eol */
752 y1 = (s->y_base + s->y) % s->total_height;
753 for(x = s->x; x < s->width; x++) {
754 c = &s->cells[y1 * s->width + x];
755 c->ch = ' ';
756 c->t_attrib = s->t_attrib_default;
757 c++;
758 update_xy(s, x, s->y);
760 break;
761 default:
762 break;
764 console_handle_escape(s);
765 break;
770 void console_select(unsigned int index)
772 TextConsole *s;
774 if (index >= MAX_CONSOLES)
775 return;
776 s = consoles[index];
777 if (s) {
778 active_console = s;
779 if (s->text_console) {
780 if (s->g_width != s->ds->width ||
781 s->g_height != s->ds->height) {
782 s->g_width = s->ds->width;
783 s->g_height = s->ds->height;
784 text_console_resize(s);
786 console_refresh(s);
791 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
793 TextConsole *s = chr->opaque;
794 int i;
796 console_show_cursor(s, 0);
797 for(i = 0; i < len; i++) {
798 console_putchar(s, buf[i]);
800 console_show_cursor(s, 1);
801 return len;
804 static void console_chr_add_read_handler(CharDriverState *chr,
805 IOCanRWHandler *fd_can_read,
806 IOReadHandler *fd_read, void *opaque)
808 TextConsole *s = chr->opaque;
809 s->fd_read = fd_read;
810 s->fd_opaque = opaque;
813 static void console_send_event(CharDriverState *chr, int event)
815 TextConsole *s = chr->opaque;
816 int i;
818 if (event == CHR_EVENT_FOCUS) {
819 for(i = 0; i < nb_consoles; i++) {
820 if (consoles[i] == s) {
821 console_select(i);
822 break;
828 /* called when an ascii key is pressed */
829 void kbd_put_keysym(int keysym)
831 TextConsole *s;
832 uint8_t buf[16], *q;
833 int c;
835 s = active_console;
836 if (!s || !s->text_console)
837 return;
839 switch(keysym) {
840 case QEMU_KEY_CTRL_UP:
841 console_scroll(-1);
842 break;
843 case QEMU_KEY_CTRL_DOWN:
844 console_scroll(1);
845 break;
846 case QEMU_KEY_CTRL_PAGEUP:
847 console_scroll(-10);
848 break;
849 case QEMU_KEY_CTRL_PAGEDOWN:
850 console_scroll(10);
851 break;
852 default:
853 if (s->fd_read) {
854 /* convert the QEMU keysym to VT100 key string */
855 q = buf;
856 if (keysym >= 0xe100 && keysym <= 0xe11f) {
857 *q++ = '\033';
858 *q++ = '[';
859 c = keysym - 0xe100;
860 if (c >= 10)
861 *q++ = '0' + (c / 10);
862 *q++ = '0' + (c % 10);
863 *q++ = '~';
864 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
865 *q++ = '\033';
866 *q++ = '[';
867 *q++ = keysym & 0xff;
868 } else {
869 *q++ = keysym;
871 s->fd_read(s->fd_opaque, buf, q - buf);
873 break;
877 TextConsole *graphic_console_init(DisplayState *ds)
879 TextConsole *s;
881 if (nb_consoles >= MAX_CONSOLES)
882 return NULL;
883 s = qemu_mallocz(sizeof(TextConsole));
884 if (!s) {
885 return NULL;
887 if (!active_console)
888 active_console = s;
889 s->ds = ds;
890 consoles[nb_consoles++] = s;
891 return s;
894 int is_active_console(TextConsole *s)
896 return s == active_console;
899 CharDriverState *text_console_init(DisplayState *ds)
901 CharDriverState *chr;
902 TextConsole *s;
903 int i,j;
904 static int color_inited;
906 chr = qemu_mallocz(sizeof(CharDriverState));
907 if (!chr)
908 return NULL;
909 s = graphic_console_init(ds);
910 if (!s) {
911 free(chr);
912 return NULL;
914 s->text_console = 1;
915 chr->opaque = s;
916 chr->chr_write = console_puts;
917 chr->chr_add_read_handler = console_chr_add_read_handler;
918 chr->chr_send_event = console_send_event;
920 if (!color_inited) {
921 color_inited = 1;
922 for(j = 0; j < 2; j++) {
923 for(i = 0; i < 8; i++) {
924 color_table[j][i] = col_expand(s->ds,
925 vga_get_color(s->ds, color_table_rgb[j][i]));
929 s->y_displayed = 0;
930 s->y_base = 0;
931 s->total_height = DEFAULT_BACKSCROLL;
932 s->x = 0;
933 s->y = 0;
934 s->g_width = s->ds->width;
935 s->g_height = s->ds->height;
937 /* Set text attribute defaults */
938 s->t_attrib_default.bold = 0;
939 s->t_attrib_default.uline = 0;
940 s->t_attrib_default.blink = 0;
941 s->t_attrib_default.invers = 0;
942 s->t_attrib_default.unvisible = 0;
943 s->t_attrib_default.fgcol = COLOR_WHITE;
944 s->t_attrib_default.bgcol = COLOR_BLACK;
946 /* set current text attributes to default */
947 s->t_attrib = s->t_attrib_default;
948 text_console_resize(s);
950 return chr;