]> git.proxmox.com Git - mirror_qemu.git/blame - console.c
Fix incorrect return type.
[mirror_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
6d6f7c28 56
e7f0ad58
FB
57struct 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;
e7f0ad58
FB
65 int x, y;
66 int y_displayed;
67 int y_base;
6d6f7c28
PB
68 TextAttributes t_attrib_default; /* default text attributes */
69 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58
FB
70 TextCell *cells;
71
72 enum TTYState state;
73 int esc_params[MAX_ESC_PARAMS];
74 int nb_esc_params;
75
76 /* kbd read handler */
77 IOReadHandler *fd_read;
78 void *fd_opaque;
79};
80
81static TextConsole *active_console;
82static TextConsole *consoles[MAX_CONSOLES];
83static int nb_consoles = 0;
84
85/* convert a RGBA color to a color index usable in graphic primitives */
86static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
87{
88 unsigned int r, g, b, color;
89
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;
117 }
118 return color;
119}
120
121static void vga_fill_rect (DisplayState *ds,
122 int posx, int posy, int width, int height, uint32_t color)
123{
124 uint8_t *d, *d1;
125 int x, y, bpp;
126
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++;
137 }
138 break;
139 case 2:
140 for (x = 0; x < width; x++) {
141 *((uint16_t *)d) = color;
142 d += 2;
143 }
144 break;
145 case 4:
146 for (x = 0; x < width; x++) {
147 *((uint32_t *)d) = color;
148 d += 4;
149 }
150 break;
151 }
152 d1 += ds->linesize;
153 }
154}
155
156/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
157static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
158{
159 const uint8_t *s;
160 uint8_t *d;
161 int wb, y, bpp;
162
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;
174 }
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;
184 }
185 }
186}
187
188/***********************************************************/
189/* basic char display */
190
191#define FONT_HEIGHT 16
192#define FONT_WIDTH 8
193
194#include "vgafont.h"
195
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) ))
202
203#ifdef WORDS_BIGENDIAN
204#define PAT(x) x
205#else
206#define PAT(x) cbswap_32(x)
207#endif
208
209static 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),
226};
227
228static const uint32_t dmask4[4] = {
229 PAT(0x00000000),
230 PAT(0x0000ffff),
231 PAT(0xffff0000),
232 PAT(0xffffffff),
233};
234
6d6f7c28
PB
235static uint32_t color_table[2][8];
236
237enum 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
248static 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 }
e7f0ad58
FB
269};
270
271static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
272{
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;
284 }
285
286 return col;
287}
6d6f7c28
PB
288#ifdef DEBUG_CONSOLE
289static 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
e7f0ad58
FB
320
321static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 322 TextAttributes *t_attrib)
e7f0ad58
FB
323{
324 uint8_t *d;
325 const uint8_t *font_ptr;
326 unsigned int font_data, linesize, xorcol, bpp;
327 int i;
6d6f7c28
PB
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 }
e7f0ad58
FB
342
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++;
6d6f7c28
PB
353 if (t_attrib->uline
354 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
355 font_data = 0xFFFF;
356 }
e7f0ad58
FB
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;
360 }
361 break;
362 case 16:
363 case 15:
364 for(i = 0; i < FONT_HEIGHT; i++) {
365 font_data = *font_ptr++;
6d6f7c28
PB
366 if (t_attrib->uline
367 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
368 font_data = 0xFFFF;
369 }
e7f0ad58
FB
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;
375 }
376 break;
377 case 32:
378 for(i = 0; i < FONT_HEIGHT; i++) {
379 font_data = *font_ptr++;
6d6f7c28
PB
380 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
381 font_data = 0xFFFF;
382 }
e7f0ad58
FB
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;
392 }
393 break;
394 }
395}
396
397static void text_console_resize(TextConsole *s)
398{
399 TextCell *cells, *c, *c1;
400 int w1, x, y, last_width;
401
402 last_width = s->width;
403 s->width = s->g_width / FONT_WIDTH;
404 s->height = s->g_height / FONT_HEIGHT;
405
406 w1 = last_width;
407 if (s->width < w1)
408 w1 = s->width;
409
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++;
417 }
418 }
419 for(x = w1; x < s->width; x++) {
420 c->ch = ' ';
6d6f7c28 421 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
422 c++;
423 }
424 }
425 free(s->cells);
426 s->cells = cells;
427}
428
429static void update_xy(TextConsole *s, int x, int y)
430{
431 TextCell *c;
432 int y1, y2;
433
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,
6d6f7c28 442 &(c->t_attrib));
e7f0ad58
FB
443 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
444 FONT_WIDTH, FONT_HEIGHT);
445 }
446 }
447}
448
449static void console_show_cursor(TextConsole *s, int show)
450{
451 TextCell *c;
452 int y, y1;
453
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) {
6d6f7c28
PB
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);
e7f0ad58
FB
465 } else {
466 vga_putcharxy(s->ds, s->x, y, c->ch,
6d6f7c28 467 &(c->t_attrib));
e7f0ad58
FB
468 }
469 dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
470 FONT_WIDTH, FONT_HEIGHT);
471 }
472 }
473}
474
475static void console_refresh(TextConsole *s)
476{
477 TextCell *c;
478 int x, y, y1;
479
480 if (s != active_console)
481 return;
482
483 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
6d6f7c28 484 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
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,
6d6f7c28 490 &(c->t_attrib));
e7f0ad58
FB
491 c++;
492 }
493 if (++y1 == s->total_height)
494 y1 = 0;
495 }
496 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
497 console_show_cursor(s, 1);
498}
499
500static void console_scroll(int ydelta)
501{
502 TextConsole *s;
503 int i, y1;
504
505 s = active_console;
506 if (!s || !s->text_console)
507 return;
508
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;
515 }
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;
529 }
530 }
531 console_refresh(s);
532}
533
534static void console_put_lf(TextConsole *s)
535{
536 TextCell *c;
537 int x, y1;
538
539 s->x = 0;
540 s->y++;
541 if (s->y >= s->height) {
542 s->y = s->height - 1;
6d6f7c28 543
e7f0ad58
FB
544 if (s->y_displayed == s->y_base) {
545 if (++s->y_displayed == s->total_height)
546 s->y_displayed = 0;
547 }
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 = ' ';
6d6f7c28 556 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
557 c++;
558 }
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,
6d6f7c28 565 color_table[0][s->t_attrib_default.bgcol]);
e7f0ad58
FB
566 dpy_update(s->ds, 0, 0,
567 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
568 }
569 }
570}
571
6d6f7c28
PB
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 */
576static 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
e7f0ad58
FB
673static void console_putchar(TextConsole *s, int ch)
674{
675 TextCell *c;
676 int y1, i, x;
677
678 switch(s->state) {
679 case TTY_STATE_NORM:
680 switch(ch) {
6d6f7c28 681 case '\r': /* carriage return */
e7f0ad58
FB
682 s->x = 0;
683 break;
6d6f7c28 684 case '\n': /* newline */
e7f0ad58
FB
685 console_put_lf(s);
686 break;
6d6f7c28
PB
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) */
e7f0ad58
FB
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;
6d6f7c28 712 c->t_attrib = s->t_attrib;
e7f0ad58
FB
713 update_xy(s, s->x, s->y);
714 s->x++;
715 if (s->x >= s->width)
716 console_put_lf(s);
717 break;
718 }
719 break;
6d6f7c28 720 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
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;
728 }
729 break;
6d6f7c28 730 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
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';
735 }
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 = ' ';
6d6f7c28 756 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
757 c++;
758 update_xy(s, x, s->y);
759 }
760 break;
761 default:
762 break;
763 }
6d6f7c28 764 console_handle_escape(s);
e7f0ad58
FB
765 break;
766 }
767 }
768}
769
770void console_select(unsigned int index)
771{
772 TextConsole *s;
6d6f7c28 773
e7f0ad58
FB
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 ||
8e3a9fd2 781 s->g_height != s->ds->height) {
6d6f7c28
PB
782 s->g_width = s->ds->width;
783 s->g_height = s->ds->height;
e7f0ad58 784 text_console_resize(s);
6d6f7c28 785 }
e7f0ad58
FB
786 console_refresh(s);
787 }
788 }
789}
790
791static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
792{
793 TextConsole *s = chr->opaque;
794 int i;
795
796 console_show_cursor(s, 0);
797 for(i = 0; i < len; i++) {
798 console_putchar(s, buf[i]);
799 }
800 console_show_cursor(s, 1);
801 return len;
802}
803
804static void console_chr_add_read_handler(CharDriverState *chr,
805 IOCanRWHandler *fd_can_read,
806 IOReadHandler *fd_read, void *opaque)
807{
808 TextConsole *s = chr->opaque;
809 s->fd_read = fd_read;
810 s->fd_opaque = opaque;
811}
812
6fcfafb7
FB
813static void console_send_event(CharDriverState *chr, int event)
814{
815 TextConsole *s = chr->opaque;
816 int i;
817
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;
823 }
824 }
825 }
826}
827
e7f0ad58
FB
828/* called when an ascii key is pressed */
829void kbd_put_keysym(int keysym)
830{
831 TextConsole *s;
832 uint8_t buf[16], *q;
833 int c;
834
835 s = active_console;
836 if (!s || !s->text_console)
837 return;
838
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;
870 }
871 s->fd_read(s->fd_opaque, buf, q - buf);
872 }
873 break;
874 }
875}
876
877TextConsole *graphic_console_init(DisplayState *ds)
878{
879 TextConsole *s;
880
881 if (nb_consoles >= MAX_CONSOLES)
882 return NULL;
883 s = qemu_mallocz(sizeof(TextConsole));
884 if (!s) {
885 return NULL;
886 }
887 if (!active_console)
888 active_console = s;
889 s->ds = ds;
890 consoles[nb_consoles++] = s;
891 return s;
892}
893
894int is_active_console(TextConsole *s)
895{
896 return s == active_console;
897}
898
899CharDriverState *text_console_init(DisplayState *ds)
900{
901 CharDriverState *chr;
902 TextConsole *s;
6d6f7c28 903 int i,j;
e7f0ad58 904 static int color_inited;
6d6f7c28 905
e7f0ad58
FB
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;
913 }
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;
6fcfafb7
FB
918 chr->chr_send_event = console_send_event;
919
e7f0ad58
FB
920 if (!color_inited) {
921 color_inited = 1;
6d6f7c28
PB
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 }
e7f0ad58
FB
927 }
928 }
929 s->y_displayed = 0;
930 s->y_base = 0;
931 s->total_height = DEFAULT_BACKSCROLL;
932 s->x = 0;
933 s->y = 0;
e7f0ad58
FB
934 s->g_width = s->ds->width;
935 s->g_height = s->ds->height;
6d6f7c28
PB
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;
e7f0ad58
FB
948 text_console_resize(s);
949
950 return chr;
951}