]> git.proxmox.com Git - qemu.git/blame - console.c
removed warnings
[qemu.git] / console.c
CommitLineData
e7f0ad58
FB
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 */
24#include "vl.h"
25
6d6f7c28 26//#define DEBUG_CONSOLE
e7f0ad58
FB
27#define DEFAULT_BACKSCROLL 512
28#define MAX_CONSOLES 12
29
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)
32
6d6f7c28
PB
33typedef 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
e7f0ad58
FB
43typedef struct TextCell {
44 uint8_t ch;
6d6f7c28 45 TextAttributes t_attrib;
e7f0ad58
FB
46} TextCell;
47
48#define MAX_ESC_PARAMS 3
49
50enum TTYState {
51 TTY_STATE_NORM,
52 TTY_STATE_ESC,
53 TTY_STATE_CSI,
54};
55
95219897
PB
56/* ??? This is mis-named.
57 It is used for both text and graphical consoles. */
e7f0ad58
FB
58struct TextConsole {
59 int text_console; /* true if text console */
60 DisplayState *ds;
95219897
PB
61 /* Graphic console state. */
62 vga_hw_update_ptr hw_update;
63 vga_hw_invalidate_ptr hw_invalidate;
64 vga_hw_screen_dump_ptr hw_screen_dump;
65 void *hw;
66
e7f0ad58
FB
67 int g_width, g_height;
68 int width;
69 int height;
70 int total_height;
71 int backscroll_height;
e7f0ad58
FB
72 int x, y;
73 int y_displayed;
74 int y_base;
6d6f7c28
PB
75 TextAttributes t_attrib_default; /* default text attributes */
76 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58
FB
77 TextCell *cells;
78
79 enum TTYState state;
80 int esc_params[MAX_ESC_PARAMS];
81 int nb_esc_params;
82
83 /* kbd read handler */
84 IOReadHandler *fd_read;
85 void *fd_opaque;
86};
87
88static TextConsole *active_console;
89static TextConsole *consoles[MAX_CONSOLES];
90static int nb_consoles = 0;
91
95219897
PB
92void vga_hw_update(void)
93{
94 if (active_console->hw_update)
95 active_console->hw_update(active_console->hw);
96}
97
98void vga_hw_invalidate(void)
99{
100 if (active_console->hw_invalidate)
101 active_console->hw_invalidate(active_console->hw);
102}
103
104void vga_hw_screen_dump(const char *filename)
105{
106 /* There is currently no was of specifying which screen we want to dump,
107 so always dump the dirst one. */
108 if (consoles[0]->hw_screen_dump)
109 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
110}
111
e7f0ad58
FB
112/* convert a RGBA color to a color index usable in graphic primitives */
113static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
114{
115 unsigned int r, g, b, color;
116
117 switch(ds->depth) {
118#if 0
119 case 8:
120 r = (rgba >> 16) & 0xff;
121 g = (rgba >> 8) & 0xff;
122 b = (rgba) & 0xff;
123 color = (rgb_to_index[r] * 6 * 6) +
124 (rgb_to_index[g] * 6) +
125 (rgb_to_index[b]);
126 break;
127#endif
128 case 15:
129 r = (rgba >> 16) & 0xff;
130 g = (rgba >> 8) & 0xff;
131 b = (rgba) & 0xff;
132 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
133 break;
134 case 16:
135 r = (rgba >> 16) & 0xff;
136 g = (rgba >> 8) & 0xff;
137 b = (rgba) & 0xff;
138 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
139 break;
140 case 32:
141 default:
142 color = rgba;
143 break;
144 }
145 return color;
146}
147
148static void vga_fill_rect (DisplayState *ds,
149 int posx, int posy, int width, int height, uint32_t color)
150{
151 uint8_t *d, *d1;
152 int x, y, bpp;
153
154 bpp = (ds->depth + 7) >> 3;
155 d1 = ds->data +
156 ds->linesize * posy + bpp * posx;
157 for (y = 0; y < height; y++) {
158 d = d1;
159 switch(bpp) {
160 case 1:
161 for (x = 0; x < width; x++) {
162 *((uint8_t *)d) = color;
163 d++;
164 }
165 break;
166 case 2:
167 for (x = 0; x < width; x++) {
168 *((uint16_t *)d) = color;
169 d += 2;
170 }
171 break;
172 case 4:
173 for (x = 0; x < width; x++) {
174 *((uint32_t *)d) = color;
175 d += 4;
176 }
177 break;
178 }
179 d1 += ds->linesize;
180 }
181}
182
183/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
184static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
185{
186 const uint8_t *s;
187 uint8_t *d;
188 int wb, y, bpp;
189
190 bpp = (ds->depth + 7) >> 3;
191 wb = w * bpp;
192 if (yd <= ys) {
193 s = ds->data +
194 ds->linesize * ys + bpp * xs;
195 d = ds->data +
196 ds->linesize * yd + bpp * xd;
197 for (y = 0; y < h; y++) {
198 memmove(d, s, wb);
199 d += ds->linesize;
200 s += ds->linesize;
201 }
202 } else {
203 s = ds->data +
204 ds->linesize * (ys + h - 1) + bpp * xs;
205 d = ds->data +
206 ds->linesize * (yd + h - 1) + bpp * xd;
207 for (y = 0; y < h; y++) {
208 memmove(d, s, wb);
209 d -= ds->linesize;
210 s -= ds->linesize;
211 }
212 }
213}
214
215/***********************************************************/
216/* basic char display */
217
218#define FONT_HEIGHT 16
219#define FONT_WIDTH 8
220
221#include "vgafont.h"
222
223#define cbswap_32(__x) \
224((uint32_t)( \
225 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
226 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
227 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
228 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
229
230#ifdef WORDS_BIGENDIAN
231#define PAT(x) x
232#else
233#define PAT(x) cbswap_32(x)
234#endif
235
236static const uint32_t dmask16[16] = {
237 PAT(0x00000000),
238 PAT(0x000000ff),
239 PAT(0x0000ff00),
240 PAT(0x0000ffff),
241 PAT(0x00ff0000),
242 PAT(0x00ff00ff),
243 PAT(0x00ffff00),
244 PAT(0x00ffffff),
245 PAT(0xff000000),
246 PAT(0xff0000ff),
247 PAT(0xff00ff00),
248 PAT(0xff00ffff),
249 PAT(0xffff0000),
250 PAT(0xffff00ff),
251 PAT(0xffffff00),
252 PAT(0xffffffff),
253};
254
255static const uint32_t dmask4[4] = {
256 PAT(0x00000000),
257 PAT(0x0000ffff),
258 PAT(0xffff0000),
259 PAT(0xffffffff),
260};
261
6d6f7c28
PB
262static uint32_t color_table[2][8];
263
264enum color_names {
265 COLOR_BLACK = 0,
266 COLOR_RED = 1,
267 COLOR_GREEN = 2,
268 COLOR_YELLOW = 3,
269 COLOR_BLUE = 4,
270 COLOR_MAGENTA = 5,
271 COLOR_CYAN = 6,
272 COLOR_WHITE = 7
273};
274
275static const uint32_t color_table_rgb[2][8] = {
276 { /* dark */
277 RGB(0x00, 0x00, 0x00), /* black */
278 RGB(0xaa, 0x00, 0x00), /* red */
279 RGB(0x00, 0xaa, 0x00), /* green */
280 RGB(0xaa, 0xaa, 0x00), /* yellow */
281 RGB(0x00, 0x00, 0xaa), /* blue */
282 RGB(0xaa, 0x00, 0xaa), /* magenta */
283 RGB(0x00, 0xaa, 0xaa), /* cyan */
284 RGB(0xaa, 0xaa, 0xaa), /* white */
285 },
286 { /* bright */
287 RGB(0x00, 0x00, 0x00), /* black */
288 RGB(0xff, 0x00, 0x00), /* red */
289 RGB(0x00, 0xff, 0x00), /* green */
290 RGB(0xff, 0xff, 0x00), /* yellow */
291 RGB(0x00, 0x00, 0xff), /* blue */
292 RGB(0xff, 0x00, 0xff), /* magenta */
293 RGB(0x00, 0xff, 0xff), /* cyan */
294 RGB(0xff, 0xff, 0xff), /* white */
295 }
e7f0ad58
FB
296};
297
298static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
299{
300 switch(ds->depth) {
301 case 8:
302 col |= col << 8;
303 col |= col << 16;
304 break;
305 case 15:
306 case 16:
307 col |= col << 16;
308 break;
309 default:
310 break;
311 }
312
313 return col;
314}
6d6f7c28
PB
315#ifdef DEBUG_CONSOLE
316static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
317{
318 if (t_attrib->bold) {
319 printf("b");
320 } else {
321 printf(" ");
322 }
323 if (t_attrib->uline) {
324 printf("u");
325 } else {
326 printf(" ");
327 }
328 if (t_attrib->blink) {
329 printf("l");
330 } else {
331 printf(" ");
332 }
333 if (t_attrib->invers) {
334 printf("i");
335 } else {
336 printf(" ");
337 }
338 if (t_attrib->unvisible) {
339 printf("n");
340 } else {
341 printf(" ");
342 }
343
344 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
345}
346#endif
e7f0ad58
FB
347
348static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 349 TextAttributes *t_attrib)
e7f0ad58
FB
350{
351 uint8_t *d;
352 const uint8_t *font_ptr;
353 unsigned int font_data, linesize, xorcol, bpp;
354 int i;
6d6f7c28
PB
355 unsigned int fgcol, bgcol;
356
357#ifdef DEBUG_CONSOLE
358 printf("x: %2i y: %2i", x, y);
359 console_print_text_attributes(t_attrib, ch);
360#endif
361
362 if (t_attrib->invers) {
363 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
364 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
365 } else {
366 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
367 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
368 }
e7f0ad58
FB
369
370 bpp = (ds->depth + 7) >> 3;
371 d = ds->data +
372 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
373 linesize = ds->linesize;
374 font_ptr = vgafont16 + FONT_HEIGHT * ch;
375 xorcol = bgcol ^ fgcol;
376 switch(ds->depth) {
377 case 8:
378 for(i = 0; i < FONT_HEIGHT; i++) {
379 font_data = *font_ptr++;
6d6f7c28
PB
380 if (t_attrib->uline
381 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
382 font_data = 0xFFFF;
383 }
e7f0ad58
FB
384 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
385 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
386 d += linesize;
387 }
388 break;
389 case 16:
390 case 15:
391 for(i = 0; i < FONT_HEIGHT; i++) {
392 font_data = *font_ptr++;
6d6f7c28
PB
393 if (t_attrib->uline
394 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
395 font_data = 0xFFFF;
396 }
e7f0ad58
FB
397 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
398 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
399 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
400 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
401 d += linesize;
402 }
403 break;
404 case 32:
405 for(i = 0; i < FONT_HEIGHT; i++) {
406 font_data = *font_ptr++;
6d6f7c28
PB
407 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
408 font_data = 0xFFFF;
409 }
e7f0ad58
FB
410 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
411 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
412 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
413 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
414 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
415 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
416 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
417 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
418 d += linesize;
419 }
420 break;
421 }
422}
423
424static void text_console_resize(TextConsole *s)
425{
426 TextCell *cells, *c, *c1;
427 int w1, x, y, last_width;
428
429 last_width = s->width;
430 s->width = s->g_width / FONT_WIDTH;
431 s->height = s->g_height / FONT_HEIGHT;
432
433 w1 = last_width;
434 if (s->width < w1)
435 w1 = s->width;
436
437 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
438 for(y = 0; y < s->total_height; y++) {
439 c = &cells[y * s->width];
440 if (w1 > 0) {
441 c1 = &s->cells[y * last_width];
442 for(x = 0; x < w1; x++) {
443 *c++ = *c1++;
444 }
445 }
446 for(x = w1; x < s->width; x++) {
447 c->ch = ' ';
6d6f7c28 448 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
449 c++;
450 }
451 }
452 free(s->cells);
453 s->cells = cells;
454}
455
456static void update_xy(TextConsole *s, int x, int y)
457{
458 TextCell *c;
459 int y1, y2;
460
461 if (s == active_console) {
462 y1 = (s->y_base + y) % s->total_height;
463 y2 = y1 - s->y_displayed;
464 if (y2 < 0)
465 y2 += s->total_height;
466 if (y2 < s->height) {
467 c = &s->cells[y1 * s->width + x];
468 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 469 &(c->t_attrib));
e7f0ad58
FB
470 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
471 FONT_WIDTH, FONT_HEIGHT);
472 }
473 }
474}
475
476static void console_show_cursor(TextConsole *s, int show)
477{
478 TextCell *c;
479 int y, y1;
480
481 if (s == active_console) {
482 y1 = (s->y_base + s->y) % s->total_height;
483 y = y1 - s->y_displayed;
484 if (y < 0)
485 y += s->total_height;
486 if (y < s->height) {
487 c = &s->cells[y1 * s->width + s->x];
488 if (show) {
6d6f7c28
PB
489 TextAttributes t_attrib = s->t_attrib_default;
490 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
491 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
e7f0ad58
FB
492 } else {
493 vga_putcharxy(s->ds, s->x, y, c->ch,
6d6f7c28 494 &(c->t_attrib));
e7f0ad58
FB
495 }
496 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
497 FONT_WIDTH, FONT_HEIGHT);
498 }
499 }
500}
501
502static void console_refresh(TextConsole *s)
503{
504 TextCell *c;
505 int x, y, y1;
506
507 if (s != active_console)
508 return;
509
510 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
6d6f7c28 511 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
512 y1 = s->y_displayed;
513 for(y = 0; y < s->height; y++) {
514 c = s->cells + y1 * s->width;
515 for(x = 0; x < s->width; x++) {
516 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 517 &(c->t_attrib));
e7f0ad58
FB
518 c++;
519 }
520 if (++y1 == s->total_height)
521 y1 = 0;
522 }
523 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
524 console_show_cursor(s, 1);
525}
526
527static void console_scroll(int ydelta)
528{
529 TextConsole *s;
530 int i, y1;
531
532 s = active_console;
533 if (!s || !s->text_console)
534 return;
535
536 if (ydelta > 0) {
537 for(i = 0; i < ydelta; i++) {
538 if (s->y_displayed == s->y_base)
539 break;
540 if (++s->y_displayed == s->total_height)
541 s->y_displayed = 0;
542 }
543 } else {
544 ydelta = -ydelta;
545 i = s->backscroll_height;
546 if (i > s->total_height - s->height)
547 i = s->total_height - s->height;
548 y1 = s->y_base - i;
549 if (y1 < 0)
550 y1 += s->total_height;
551 for(i = 0; i < ydelta; i++) {
552 if (s->y_displayed == y1)
553 break;
554 if (--s->y_displayed < 0)
555 s->y_displayed = s->total_height - 1;
556 }
557 }
558 console_refresh(s);
559}
560
561static void console_put_lf(TextConsole *s)
562{
563 TextCell *c;
564 int x, y1;
565
566 s->x = 0;
567 s->y++;
568 if (s->y >= s->height) {
569 s->y = s->height - 1;
6d6f7c28 570
e7f0ad58
FB
571 if (s->y_displayed == s->y_base) {
572 if (++s->y_displayed == s->total_height)
573 s->y_displayed = 0;
574 }
575 if (++s->y_base == s->total_height)
576 s->y_base = 0;
577 if (s->backscroll_height < s->total_height)
578 s->backscroll_height++;
579 y1 = (s->y_base + s->height - 1) % s->total_height;
580 c = &s->cells[y1 * s->width];
581 for(x = 0; x < s->width; x++) {
582 c->ch = ' ';
6d6f7c28 583 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
584 c++;
585 }
586 if (s == active_console && s->y_displayed == s->y_base) {
587 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
588 s->width * FONT_WIDTH,
589 (s->height - 1) * FONT_HEIGHT);
590 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
591 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 592 color_table[0][s->t_attrib_default.bgcol]);
e7f0ad58
FB
593 dpy_update(s->ds, 0, 0,
594 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
595 }
596 }
597}
598
6d6f7c28
PB
599/* Set console attributes depending on the current escape codes.
600 * NOTE: I know this code is not very efficient (checking every color for it
601 * self) but it is more readable and better maintainable.
602 */
603static void console_handle_escape(TextConsole *s)
604{
605 int i;
606
607 if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
608 s->t_attrib = s->t_attrib_default;
609 return;
610 }
611 for (i=0; i<s->nb_esc_params; i++) {
612 switch (s->esc_params[i]) {
613 case 0: /* reset all console attributes to default */
614 s->t_attrib = s->t_attrib_default;
615 break;
616 case 1:
617 s->t_attrib.bold = 1;
618 break;
619 case 4:
620 s->t_attrib.uline = 1;
621 break;
622 case 5:
623 s->t_attrib.blink = 1;
624 break;
625 case 7:
626 s->t_attrib.invers = 1;
627 break;
628 case 8:
629 s->t_attrib.unvisible = 1;
630 break;
631 case 22:
632 s->t_attrib.bold = 0;
633 break;
634 case 24:
635 s->t_attrib.uline = 0;
636 break;
637 case 25:
638 s->t_attrib.blink = 0;
639 break;
640 case 27:
641 s->t_attrib.invers = 0;
642 break;
643 case 28:
644 s->t_attrib.unvisible = 0;
645 break;
646 /* set foreground color */
647 case 30:
648 s->t_attrib.fgcol=COLOR_BLACK;
649 break;
650 case 31:
651 s->t_attrib.fgcol=COLOR_RED;
652 break;
653 case 32:
654 s->t_attrib.fgcol=COLOR_GREEN;
655 break;
656 case 33:
657 s->t_attrib.fgcol=COLOR_YELLOW;
658 break;
659 case 34:
660 s->t_attrib.fgcol=COLOR_BLUE;
661 break;
662 case 35:
663 s->t_attrib.fgcol=COLOR_MAGENTA;
664 break;
665 case 36:
666 s->t_attrib.fgcol=COLOR_CYAN;
667 break;
668 case 37:
669 s->t_attrib.fgcol=COLOR_WHITE;
670 break;
671 /* set background color */
672 case 40:
673 s->t_attrib.bgcol=COLOR_BLACK;
674 break;
675 case 41:
676 s->t_attrib.bgcol=COLOR_RED;
677 break;
678 case 42:
679 s->t_attrib.bgcol=COLOR_GREEN;
680 break;
681 case 43:
682 s->t_attrib.bgcol=COLOR_YELLOW;
683 break;
684 case 44:
685 s->t_attrib.bgcol=COLOR_BLUE;
686 break;
687 case 45:
688 s->t_attrib.bgcol=COLOR_MAGENTA;
689 break;
690 case 46:
691 s->t_attrib.bgcol=COLOR_CYAN;
692 break;
693 case 47:
694 s->t_attrib.bgcol=COLOR_WHITE;
695 break;
696 }
697 }
698}
699
e7f0ad58
FB
700static void console_putchar(TextConsole *s, int ch)
701{
702 TextCell *c;
703 int y1, i, x;
704
705 switch(s->state) {
706 case TTY_STATE_NORM:
707 switch(ch) {
6d6f7c28 708 case '\r': /* carriage return */
e7f0ad58
FB
709 s->x = 0;
710 break;
6d6f7c28 711 case '\n': /* newline */
e7f0ad58
FB
712 console_put_lf(s);
713 break;
6d6f7c28
PB
714 case '\b': /* backspace */
715 if(s->x > 0) s->x--;
716 y1 = (s->y_base + s->y) % s->total_height;
717 c = &s->cells[y1 * s->width + s->x];
718 c->ch = ' ';
719 c->t_attrib = s->t_attrib;
720 update_xy(s, s->x, s->y);
721 break;
722 case '\t': /* tabspace */
723 if (s->x + (8 - (s->x % 8)) > s->width) {
724 console_put_lf(s);
725 } else {
726 s->x = s->x + (8 - (s->x % 8));
727 }
728 break;
729 case '\a': /* alert aka. bell */
730 /* TODO: has to be implemented */
731 break;
732 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
733 s->state = TTY_STATE_ESC;
734 break;
735 default:
736 y1 = (s->y_base + s->y) % s->total_height;
737 c = &s->cells[y1 * s->width + s->x];
738 c->ch = ch;
6d6f7c28 739 c->t_attrib = s->t_attrib;
e7f0ad58
FB
740 update_xy(s, s->x, s->y);
741 s->x++;
742 if (s->x >= s->width)
743 console_put_lf(s);
744 break;
745 }
746 break;
6d6f7c28 747 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
748 if (ch == '[') {
749 for(i=0;i<MAX_ESC_PARAMS;i++)
750 s->esc_params[i] = 0;
751 s->nb_esc_params = 0;
752 s->state = TTY_STATE_CSI;
753 } else {
754 s->state = TTY_STATE_NORM;
755 }
756 break;
6d6f7c28 757 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
758 if (ch >= '0' && ch <= '9') {
759 if (s->nb_esc_params < MAX_ESC_PARAMS) {
760 s->esc_params[s->nb_esc_params] =
761 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
762 }
763 } else {
764 s->nb_esc_params++;
765 if (ch == ';')
766 break;
767 s->state = TTY_STATE_NORM;
768 switch(ch) {
769 case 'D':
770 if (s->x > 0)
771 s->x--;
772 break;
773 case 'C':
774 if (s->x < (s->width - 1))
775 s->x++;
776 break;
777 case 'K':
778 /* clear to eol */
779 y1 = (s->y_base + s->y) % s->total_height;
780 for(x = s->x; x < s->width; x++) {
781 c = &s->cells[y1 * s->width + x];
782 c->ch = ' ';
6d6f7c28 783 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
784 c++;
785 update_xy(s, x, s->y);
786 }
787 break;
788 default:
789 break;
790 }
6d6f7c28 791 console_handle_escape(s);
e7f0ad58
FB
792 break;
793 }
794 }
795}
796
797void console_select(unsigned int index)
798{
799 TextConsole *s;
6d6f7c28 800
e7f0ad58
FB
801 if (index >= MAX_CONSOLES)
802 return;
803 s = consoles[index];
804 if (s) {
805 active_console = s;
806 if (s->text_console) {
807 if (s->g_width != s->ds->width ||
8e3a9fd2 808 s->g_height != s->ds->height) {
6d6f7c28
PB
809 s->g_width = s->ds->width;
810 s->g_height = s->ds->height;
e7f0ad58 811 text_console_resize(s);
95219897 812 }
e7f0ad58 813 console_refresh(s);
95219897
PB
814 } else {
815 vga_hw_invalidate();
e7f0ad58
FB
816 }
817 }
818}
819
820static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
821{
822 TextConsole *s = chr->opaque;
823 int i;
824
825 console_show_cursor(s, 0);
826 for(i = 0; i < len; i++) {
827 console_putchar(s, buf[i]);
828 }
829 console_show_cursor(s, 1);
830 return len;
831}
832
833static void console_chr_add_read_handler(CharDriverState *chr,
834 IOCanRWHandler *fd_can_read,
835 IOReadHandler *fd_read, void *opaque)
836{
837 TextConsole *s = chr->opaque;
838 s->fd_read = fd_read;
839 s->fd_opaque = opaque;
840}
841
6fcfafb7
FB
842static void console_send_event(CharDriverState *chr, int event)
843{
844 TextConsole *s = chr->opaque;
845 int i;
846
847 if (event == CHR_EVENT_FOCUS) {
848 for(i = 0; i < nb_consoles; i++) {
849 if (consoles[i] == s) {
850 console_select(i);
851 break;
852 }
853 }
854 }
855}
856
e7f0ad58
FB
857/* called when an ascii key is pressed */
858void kbd_put_keysym(int keysym)
859{
860 TextConsole *s;
861 uint8_t buf[16], *q;
862 int c;
863
864 s = active_console;
865 if (!s || !s->text_console)
866 return;
867
868 switch(keysym) {
869 case QEMU_KEY_CTRL_UP:
870 console_scroll(-1);
871 break;
872 case QEMU_KEY_CTRL_DOWN:
873 console_scroll(1);
874 break;
875 case QEMU_KEY_CTRL_PAGEUP:
876 console_scroll(-10);
877 break;
878 case QEMU_KEY_CTRL_PAGEDOWN:
879 console_scroll(10);
880 break;
881 default:
882 if (s->fd_read) {
883 /* convert the QEMU keysym to VT100 key string */
884 q = buf;
885 if (keysym >= 0xe100 && keysym <= 0xe11f) {
886 *q++ = '\033';
887 *q++ = '[';
888 c = keysym - 0xe100;
889 if (c >= 10)
890 *q++ = '0' + (c / 10);
891 *q++ = '0' + (c % 10);
892 *q++ = '~';
893 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
894 *q++ = '\033';
895 *q++ = '[';
896 *q++ = keysym & 0xff;
897 } else {
898 *q++ = keysym;
899 }
900 s->fd_read(s->fd_opaque, buf, q - buf);
901 }
902 break;
903 }
904}
905
95219897 906static TextConsole *new_console(DisplayState *ds, int text)
e7f0ad58
FB
907{
908 TextConsole *s;
95219897 909 int i;
e7f0ad58
FB
910
911 if (nb_consoles >= MAX_CONSOLES)
912 return NULL;
913 s = qemu_mallocz(sizeof(TextConsole));
914 if (!s) {
915 return NULL;
916 }
95219897 917 if (!active_console || (active_console->text_console && !text))
e7f0ad58
FB
918 active_console = s;
919 s->ds = ds;
95219897
PB
920 s->text_console = text;
921 if (text) {
922 consoles[nb_consoles++] = s;
923 } else {
924 /* HACK: Put graphical consoles before text consoles. */
925 for (i = nb_consoles; i > 0; i--) {
926 if (!consoles[i - 1]->text_console)
927 break;
928 consoles[i] = consoles[i - 1];
929 }
930 consoles[i] = s;
931 }
932 return s;
933}
934
935TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
936 vga_hw_invalidate_ptr invalidate,
937 vga_hw_screen_dump_ptr screen_dump,
938 void *opaque)
939{
940 TextConsole *s;
941
942 s = new_console(ds, 0);
943 if (!s)
944 return NULL;
945 s->hw_update = update;
946 s->hw_invalidate = invalidate;
947 s->hw_screen_dump = screen_dump;
948 s->hw = opaque;
e7f0ad58
FB
949 return s;
950}
951
95219897 952int is_graphic_console(void)
e7f0ad58 953{
95219897 954 return !active_console->text_console;
e7f0ad58
FB
955}
956
957CharDriverState *text_console_init(DisplayState *ds)
958{
959 CharDriverState *chr;
960 TextConsole *s;
6d6f7c28 961 int i,j;
e7f0ad58 962 static int color_inited;
6d6f7c28 963
e7f0ad58
FB
964 chr = qemu_mallocz(sizeof(CharDriverState));
965 if (!chr)
966 return NULL;
95219897 967 s = new_console(ds, 1);
e7f0ad58
FB
968 if (!s) {
969 free(chr);
970 return NULL;
971 }
e7f0ad58
FB
972 chr->opaque = s;
973 chr->chr_write = console_puts;
974 chr->chr_add_read_handler = console_chr_add_read_handler;
6fcfafb7
FB
975 chr->chr_send_event = console_send_event;
976
e7f0ad58
FB
977 if (!color_inited) {
978 color_inited = 1;
6d6f7c28
PB
979 for(j = 0; j < 2; j++) {
980 for(i = 0; i < 8; i++) {
981 color_table[j][i] = col_expand(s->ds,
982 vga_get_color(s->ds, color_table_rgb[j][i]));
983 }
e7f0ad58
FB
984 }
985 }
986 s->y_displayed = 0;
987 s->y_base = 0;
988 s->total_height = DEFAULT_BACKSCROLL;
989 s->x = 0;
990 s->y = 0;
e7f0ad58
FB
991 s->g_width = s->ds->width;
992 s->g_height = s->ds->height;
6d6f7c28
PB
993
994 /* Set text attribute defaults */
995 s->t_attrib_default.bold = 0;
996 s->t_attrib_default.uline = 0;
997 s->t_attrib_default.blink = 0;
998 s->t_attrib_default.invers = 0;
999 s->t_attrib_default.unvisible = 0;
1000 s->t_attrib_default.fgcol = COLOR_WHITE;
1001 s->t_attrib_default.bgcol = COLOR_BLACK;
1002
1003 /* set current text attributes to default */
1004 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1005 text_console_resize(s);
1006
1007 return chr;
1008}