Commit 6d6f7c288dbd892fb85028cb7a7fe8812ac11135

Authored by pbrook
1 parent d2ec1774

Improved terminal emulation (Piotr Esden-Tempski).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1773 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 268 additions and 48 deletions
console.c
... ... @@ -23,16 +23,26 @@
23 23 */
24 24 #include "vl.h"
25 25  
  26 +//#define DEBUG_CONSOLE
26 27 #define DEFAULT_BACKSCROLL 512
27 28 #define MAX_CONSOLES 12
28 29  
29 30 #define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
30 31 #define RGB(r, g, b) RGBA(r, g, b, 0xff)
31 32  
  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;
  42 +
32 43 typedef struct TextCell {
33 44 uint8_t ch;
34   - uint8_t bgcol:4;
35   - uint8_t fgcol:4;
  45 + TextAttributes t_attrib;
36 46 } TextCell;
37 47  
38 48 #define MAX_ESC_PARAMS 3
... ... @@ -43,6 +53,7 @@ enum TTYState {
43 53 TTY_STATE_CSI,
44 54 };
45 55  
  56 +
46 57 struct TextConsole {
47 58 int text_console; /* true if text console */
48 59 DisplayState *ds;
... ... @@ -51,11 +62,11 @@ struct TextConsole {
51 62 int height;
52 63 int total_height;
53 64 int backscroll_height;
54   - int fgcol;
55   - int bgcol;
56 65 int x, y;
57 66 int y_displayed;
58 67 int y_base;
  68 + TextAttributes t_attrib_default; /* default text attributes */
  69 + TextAttributes t_attrib; /* currently active text attributes */
59 70 TextCell *cells;
60 71  
61 72 enum TTYState state;
... ... @@ -221,17 +232,40 @@ static const uint32_t dmask4[4] = {
221 232 PAT(0xffffffff),
222 233 };
223 234  
224   -static uint32_t color_table[8];
225   -
226   -static const uint32_t color_table_rgb[8] = {
227   - RGB(0x00, 0x00, 0x00),
228   - RGB(0xff, 0x00, 0x00),
229   - RGB(0x00, 0xff, 0x00),
230   - RGB(0xff, 0xff, 0x00),
231   - RGB(0x00, 0x00, 0xff),
232   - RGB(0xff, 0x00, 0xff),
233   - RGB(0x00, 0xff, 0xff),
234   - RGB(0xff, 0xff, 0xff),
  235 +static uint32_t color_table[2][8];
  236 +
  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
  246 +};
  247 +
  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 */
  258 + },
  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 */
  268 + }
235 269 };
236 270  
237 271 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
... ... @@ -251,14 +285,60 @@ static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
251 285  
252 286 return col;
253 287 }
  288 +#ifdef DEBUG_CONSOLE
  289 +static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
  290 +{
  291 + if (t_attrib->bold) {
  292 + printf("b");
  293 + } else {
  294 + printf(" ");
  295 + }
  296 + if (t_attrib->uline) {
  297 + printf("u");
  298 + } else {
  299 + printf(" ");
  300 + }
  301 + if (t_attrib->blink) {
  302 + printf("l");
  303 + } else {
  304 + printf(" ");
  305 + }
  306 + if (t_attrib->invers) {
  307 + printf("i");
  308 + } else {
  309 + printf(" ");
  310 + }
  311 + if (t_attrib->unvisible) {
  312 + printf("n");
  313 + } else {
  314 + printf(" ");
  315 + }
  316 +
  317 + printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
  318 +}
  319 +#endif
254 320  
255 321 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
256   - unsigned int fgcol, unsigned int bgcol)
  322 + TextAttributes *t_attrib)
257 323 {
258 324 uint8_t *d;
259 325 const uint8_t *font_ptr;
260 326 unsigned int font_data, linesize, xorcol, bpp;
261 327 int i;
  328 + unsigned int fgcol, bgcol;
  329 +
  330 +#ifdef DEBUG_CONSOLE
  331 + printf("x: %2i y: %2i", x, y);
  332 + console_print_text_attributes(t_attrib, ch);
  333 +#endif
  334 +
  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];
  341 + }
262 342  
263 343 bpp = (ds->depth + 7) >> 3;
264 344 d = ds->data +
... ... @@ -270,6 +350,10 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
270 350 case 8:
271 351 for(i = 0; i < FONT_HEIGHT; i++) {
272 352 font_data = *font_ptr++;
  353 + if (t_attrib->uline
  354 + && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  355 + font_data = 0xFFFF;
  356 + }
273 357 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
274 358 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
275 359 d += linesize;
... ... @@ -279,6 +363,10 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
279 363 case 15:
280 364 for(i = 0; i < FONT_HEIGHT; i++) {
281 365 font_data = *font_ptr++;
  366 + if (t_attrib->uline
  367 + && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  368 + font_data = 0xFFFF;
  369 + }
282 370 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
283 371 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
284 372 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
... ... @@ -289,6 +377,9 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
289 377 case 32:
290 378 for(i = 0; i < FONT_HEIGHT; i++) {
291 379 font_data = *font_ptr++;
  380 + if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  381 + font_data = 0xFFFF;
  382 + }
292 383 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
293 384 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
294 385 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
... ... @@ -327,8 +418,7 @@ static void text_console_resize(TextConsole *s)
327 418 }
328 419 for(x = w1; x < s->width; x++) {
329 420 c->ch = ' ';
330   - c->fgcol = 7;
331   - c->bgcol = 0;
  421 + c->t_attrib = s->t_attrib_default;
332 422 c++;
333 423 }
334 424 }
... ... @@ -349,7 +439,7 @@ static void update_xy(TextConsole *s, int x, int y)
349 439 if (y2 < s->height) {
350 440 c = &s->cells[y1 * s->width + x];
351 441 vga_putcharxy(s->ds, x, y2, c->ch,
352   - color_table[c->fgcol], color_table[c->bgcol]);
  442 + &(c->t_attrib));
353 443 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
354 444 FONT_WIDTH, FONT_HEIGHT);
355 445 }
... ... @@ -369,11 +459,12 @@ static void console_show_cursor(TextConsole *s, int show)
369 459 if (y < s->height) {
370 460 c = &s->cells[y1 * s->width + s->x];
371 461 if (show) {
372   - vga_putcharxy(s->ds, s->x, y, c->ch,
373   - color_table[0], color_table[7]);
  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);
374 465 } else {
375 466 vga_putcharxy(s->ds, s->x, y, c->ch,
376   - color_table[c->fgcol], color_table[c->bgcol]);
  467 + &(c->t_attrib));
377 468 }
378 469 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
379 470 FONT_WIDTH, FONT_HEIGHT);
... ... @@ -390,13 +481,13 @@ static void console_refresh(TextConsole *s)
390 481 return;
391 482  
392 483 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
393   - color_table[0]);
  484 + color_table[0][COLOR_BLACK]);
394 485 y1 = s->y_displayed;
395 486 for(y = 0; y < s->height; y++) {
396 487 c = s->cells + y1 * s->width;
397 488 for(x = 0; x < s->width; x++) {
398 489 vga_putcharxy(s->ds, x, y, c->ch,
399   - color_table[c->fgcol], color_table[c->bgcol]);
  490 + &(c->t_attrib));
400 491 c++;
401 492 }
402 493 if (++y1 == s->total_height)
... ... @@ -449,7 +540,7 @@ static void console_put_lf(TextConsole *s)
449 540 s->y++;
450 541 if (s->y >= s->height) {
451 542 s->y = s->height - 1;
452   -
  543 +
453 544 if (s->y_displayed == s->y_base) {
454 545 if (++s->y_displayed == s->total_height)
455 546 s->y_displayed = 0;
... ... @@ -462,8 +553,7 @@ static void console_put_lf(TextConsole *s)
462 553 c = &s->cells[y1 * s->width];
463 554 for(x = 0; x < s->width; x++) {
464 555 c->ch = ' ';
465   - c->fgcol = s->fgcol;
466   - c->bgcol = s->bgcol;
  556 + c->t_attrib = s->t_attrib_default;
467 557 c++;
468 558 }
469 559 if (s == active_console && s->y_displayed == s->y_base) {
... ... @@ -472,13 +562,114 @@ static void console_put_lf(TextConsole *s)
472 562 (s->height - 1) * FONT_HEIGHT);
473 563 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
474 564 s->width * FONT_WIDTH, FONT_HEIGHT,
475   - color_table[s->bgcol]);
  565 + color_table[0][s->t_attrib_default.bgcol]);
476 566 dpy_update(s->ds, 0, 0,
477 567 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
478 568 }
479 569 }
480 570 }
481 571  
  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.
  575 + */
  576 +static void console_handle_escape(TextConsole *s)
  577 +{
  578 + int i;
  579 +
  580 + if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
  581 + s->t_attrib = s->t_attrib_default;
  582 + return;
  583 + }
  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;
  669 + }
  670 + }
  671 +}
  672 +
482 673 static void console_putchar(TextConsole *s, int ch)
483 674 {
484 675 TextCell *c;
... ... @@ -487,21 +678,38 @@ static void console_putchar(TextConsole *s, int ch)
487 678 switch(s->state) {
488 679 case TTY_STATE_NORM:
489 680 switch(ch) {
490   - case '\r':
  681 + case '\r': /* carriage return */
491 682 s->x = 0;
492 683 break;
493   - case '\n':
  684 + case '\n': /* newline */
494 685 console_put_lf(s);
495 686 break;
496   - case 27:
  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));
  700 + }
  701 + break;
  702 + case '\a': /* alert aka. bell */
  703 + /* TODO: has to be implemented */
  704 + break;
  705 + case 27: /* esc (introducing an escape sequence) */
497 706 s->state = TTY_STATE_ESC;
498 707 break;
499 708 default:
500 709 y1 = (s->y_base + s->y) % s->total_height;
501 710 c = &s->cells[y1 * s->width + s->x];
502 711 c->ch = ch;
503   - c->fgcol = s->fgcol;
504   - c->bgcol = s->bgcol;
  712 + c->t_attrib = s->t_attrib;
505 713 update_xy(s, s->x, s->y);
506 714 s->x++;
507 715 if (s->x >= s->width)
... ... @@ -509,7 +717,7 @@ static void console_putchar(TextConsole *s, int ch)
509 717 break;
510 718 }
511 719 break;
512   - case TTY_STATE_ESC:
  720 + case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
513 721 if (ch == '[') {
514 722 for(i=0;i<MAX_ESC_PARAMS;i++)
515 723 s->esc_params[i] = 0;
... ... @@ -519,7 +727,7 @@ static void console_putchar(TextConsole *s, int ch)
519 727 s->state = TTY_STATE_NORM;
520 728 }
521 729 break;
522   - case TTY_STATE_CSI:
  730 + case TTY_STATE_CSI: /* handle escape sequence parameters */
523 731 if (ch >= '0' && ch <= '9') {
524 732 if (s->nb_esc_params < MAX_ESC_PARAMS) {
525 733 s->esc_params[s->nb_esc_params] =
... ... @@ -545,8 +753,7 @@ static void console_putchar(TextConsole *s, int ch)
545 753 for(x = s->x; x < s->width; x++) {
546 754 c = &s->cells[y1 * s->width + x];
547 755 c->ch = ' ';
548   - c->fgcol = s->fgcol;
549   - c->bgcol = s->bgcol;
  756 + c->t_attrib = s->t_attrib_default;
550 757 c++;
551 758 update_xy(s, x, s->y);
552 759 }
... ... @@ -554,6 +761,7 @@ static void console_putchar(TextConsole *s, int ch)
554 761 default:
555 762 break;
556 763 }
  764 + console_handle_escape(s);
557 765 break;
558 766 }
559 767 }
... ... @@ -562,7 +770,7 @@ static void console_putchar(TextConsole *s, int ch)
562 770 void console_select(unsigned int index)
563 771 {
564 772 TextConsole *s;
565   -
  773 +
566 774 if (index >= MAX_CONSOLES)
567 775 return;
568 776 s = consoles[index];
... ... @@ -571,10 +779,10 @@ void console_select(unsigned int index)
571 779 if (s->text_console) {
572 780 if (s->g_width != s->ds->width ||
573 781 s->g_height != s->ds->height) {
574   - s->g_width = s->ds->width;
575   - s->g_height = s->ds->height;
  782 + s->g_width = s->ds->width;
  783 + s->g_height = s->ds->height;
576 784 text_console_resize(s);
577   - }
  785 + }
578 786 console_refresh(s);
579 787 }
580 788 }
... ... @@ -692,9 +900,9 @@ CharDriverState *text_console_init(DisplayState *ds)
692 900 {
693 901 CharDriverState *chr;
694 902 TextConsole *s;
695   - int i;
  903 + int i,j;
696 904 static int color_inited;
697   -
  905 +
698 906 chr = qemu_mallocz(sizeof(CharDriverState));
699 907 if (!chr)
700 908 return NULL;
... ... @@ -711,9 +919,11 @@ CharDriverState *text_console_init(DisplayState *ds)
711 919  
712 920 if (!color_inited) {
713 921 color_inited = 1;
714   - for(i = 0; i < 8; i++) {
715   - color_table[i] = col_expand(s->ds,
716   - vga_get_color(s->ds, color_table_rgb[i]));
  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]));
  926 + }
717 927 }
718 928 }
719 929 s->y_displayed = 0;
... ... @@ -721,10 +931,20 @@ CharDriverState *text_console_init(DisplayState *ds)
721 931 s->total_height = DEFAULT_BACKSCROLL;
722 932 s->x = 0;
723 933 s->y = 0;
724   - s->fgcol = 7;
725   - s->bgcol = 0;
726 934 s->g_width = s->ds->width;
727 935 s->g_height = s->ds->height;
  936 +
  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;
  945 +
  946 + /* set current text attributes to default */
  947 + s->t_attrib = s->t_attrib_default;
728 948 text_console_resize(s);
729 949  
730 950 return chr;
... ...