blob: 35dc603c92345b143a82f7398e3eeb076b9b2982 [file] [log] [blame]
bellarde7f0ad52004-07-14 17:28:59 +00001/*
2 * QEMU graphical console
ths5fafdf22007-09-16 21:08:06 +00003 *
bellarde7f0ad52004-07-14 17:28:59 +00004 * Copyright (c) 2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde7f0ad52004-07-14 17:28:59 +00006 * 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
pbrook6d6f7c22006-03-11 15:35:30 +000026//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000027#define DEFAULT_BACKSCROLL 512
28#define MAX_CONSOLES 12
29
bellard26489842006-06-25 17:37:36 +000030#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
31#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000032
pbrook6d6f7c22006-03-11 15:35:30 +000033typedef 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
bellarde7f0ad52004-07-14 17:28:59 +000043typedef struct TextCell {
44 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000045 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000046} 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
bellarde15d7372006-06-25 16:26:29 +000056typedef struct QEMUFIFO {
57 uint8_t *buf;
58 int buf_size;
59 int count, wptr, rptr;
60} QEMUFIFO;
61
62int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
63{
64 int l, len;
65
66 l = f->buf_size - f->count;
67 if (len1 > l)
68 len1 = l;
69 len = len1;
70 while (len > 0) {
71 l = f->buf_size - f->wptr;
72 if (l > len)
73 l = len;
74 memcpy(f->buf + f->wptr, buf, l);
75 f->wptr += l;
76 if (f->wptr >= f->buf_size)
77 f->wptr = 0;
78 buf += l;
79 len -= l;
80 }
81 f->count += len1;
82 return len1;
83}
84
85int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
86{
87 int l, len;
88
89 if (len1 > f->count)
90 len1 = f->count;
91 len = len1;
92 while (len > 0) {
93 l = f->buf_size - f->rptr;
94 if (l > len)
95 l = len;
96 memcpy(buf, f->buf + f->rptr, l);
97 f->rptr += l;
98 if (f->rptr >= f->buf_size)
99 f->rptr = 0;
100 buf += l;
101 len -= l;
102 }
103 f->count -= len1;
104 return len1;
105}
106
thsaf3a9032007-07-11 23:14:59 +0000107typedef enum {
108 GRAPHIC_CONSOLE,
109 TEXT_CONSOLE,
110 TEXT_CONSOLE_FIXED_SIZE
111} console_type_t;
112
pbrook95219892006-04-09 01:06:34 +0000113/* ??? This is mis-named.
114 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000115struct TextConsole {
thsaf3a9032007-07-11 23:14:59 +0000116 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000117 DisplayState *ds;
pbrook95219892006-04-09 01:06:34 +0000118 /* Graphic console state. */
119 vga_hw_update_ptr hw_update;
120 vga_hw_invalidate_ptr hw_invalidate;
121 vga_hw_screen_dump_ptr hw_screen_dump;
122 void *hw;
123
bellarde7f0ad52004-07-14 17:28:59 +0000124 int g_width, g_height;
125 int width;
126 int height;
127 int total_height;
128 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000129 int x, y;
thsadb47962007-01-16 23:02:36 +0000130 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000131 int y_displayed;
132 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000133 TextAttributes t_attrib_default; /* default text attributes */
134 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000135 TextCell *cells;
136
137 enum TTYState state;
138 int esc_params[MAX_ESC_PARAMS];
139 int nb_esc_params;
140
pbrooke5b0bc42007-01-27 23:46:43 +0000141 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000142 /* fifo for key pressed */
143 QEMUFIFO out_fifo;
144 uint8_t out_fifo_buf[16];
145 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000146};
147
148static TextConsole *active_console;
149static TextConsole *consoles[MAX_CONSOLES];
150static int nb_consoles = 0;
151
pbrook95219892006-04-09 01:06:34 +0000152void vga_hw_update(void)
153{
thsadb47962007-01-16 23:02:36 +0000154 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000155 active_console->hw_update(active_console->hw);
156}
157
158void vga_hw_invalidate(void)
159{
160 if (active_console->hw_invalidate)
161 active_console->hw_invalidate(active_console->hw);
162}
163
164void vga_hw_screen_dump(const char *filename)
165{
166 /* There is currently no was of specifying which screen we want to dump,
167 so always dump the dirst one. */
168 if (consoles[0]->hw_screen_dump)
169 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
170}
171
bellarde7f0ad52004-07-14 17:28:59 +0000172/* convert a RGBA color to a color index usable in graphic primitives */
173static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
174{
175 unsigned int r, g, b, color;
176
177 switch(ds->depth) {
178#if 0
179 case 8:
180 r = (rgba >> 16) & 0xff;
181 g = (rgba >> 8) & 0xff;
182 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000183 color = (rgb_to_index[r] * 6 * 6) +
184 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000185 (rgb_to_index[b]);
186 break;
187#endif
188 case 15:
189 r = (rgba >> 16) & 0xff;
190 g = (rgba >> 8) & 0xff;
191 b = (rgba) & 0xff;
192 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
193 break;
194 case 16:
195 r = (rgba >> 16) & 0xff;
196 g = (rgba >> 8) & 0xff;
197 b = (rgba) & 0xff;
198 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
199 break;
200 case 32:
201 default:
202 color = rgba;
203 break;
204 }
205 return color;
206}
207
ths5fafdf22007-09-16 21:08:06 +0000208static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000209 int posx, int posy, int width, int height, uint32_t color)
210{
211 uint8_t *d, *d1;
212 int x, y, bpp;
ths5fafdf22007-09-16 21:08:06 +0000213
bellarde7f0ad52004-07-14 17:28:59 +0000214 bpp = (ds->depth + 7) >> 3;
ths5fafdf22007-09-16 21:08:06 +0000215 d1 = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000216 ds->linesize * posy + bpp * posx;
217 for (y = 0; y < height; y++) {
218 d = d1;
219 switch(bpp) {
220 case 1:
221 for (x = 0; x < width; x++) {
222 *((uint8_t *)d) = color;
223 d++;
224 }
225 break;
226 case 2:
227 for (x = 0; x < width; x++) {
228 *((uint16_t *)d) = color;
229 d += 2;
230 }
231 break;
232 case 4:
233 for (x = 0; x < width; x++) {
234 *((uint32_t *)d) = color;
235 d += 4;
236 }
237 break;
238 }
239 d1 += ds->linesize;
240 }
241}
242
243/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
244static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
245{
246 const uint8_t *s;
247 uint8_t *d;
248 int wb, y, bpp;
249
250 bpp = (ds->depth + 7) >> 3;
251 wb = w * bpp;
252 if (yd <= ys) {
ths5fafdf22007-09-16 21:08:06 +0000253 s = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000254 ds->linesize * ys + bpp * xs;
ths5fafdf22007-09-16 21:08:06 +0000255 d = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000256 ds->linesize * yd + bpp * xd;
257 for (y = 0; y < h; y++) {
258 memmove(d, s, wb);
259 d += ds->linesize;
260 s += ds->linesize;
261 }
262 } else {
ths5fafdf22007-09-16 21:08:06 +0000263 s = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000264 ds->linesize * (ys + h - 1) + bpp * xs;
ths5fafdf22007-09-16 21:08:06 +0000265 d = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000266 ds->linesize * (yd + h - 1) + bpp * xd;
267 for (y = 0; y < h; y++) {
268 memmove(d, s, wb);
269 d -= ds->linesize;
270 s -= ds->linesize;
271 }
272 }
273}
274
275/***********************************************************/
276/* basic char display */
277
278#define FONT_HEIGHT 16
279#define FONT_WIDTH 8
280
281#include "vgafont.h"
282
283#define cbswap_32(__x) \
284((uint32_t)( \
285 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
286 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
287 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
288 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
289
290#ifdef WORDS_BIGENDIAN
291#define PAT(x) x
292#else
293#define PAT(x) cbswap_32(x)
294#endif
295
296static const uint32_t dmask16[16] = {
297 PAT(0x00000000),
298 PAT(0x000000ff),
299 PAT(0x0000ff00),
300 PAT(0x0000ffff),
301 PAT(0x00ff0000),
302 PAT(0x00ff00ff),
303 PAT(0x00ffff00),
304 PAT(0x00ffffff),
305 PAT(0xff000000),
306 PAT(0xff0000ff),
307 PAT(0xff00ff00),
308 PAT(0xff00ffff),
309 PAT(0xffff0000),
310 PAT(0xffff00ff),
311 PAT(0xffffff00),
312 PAT(0xffffffff),
313};
314
315static const uint32_t dmask4[4] = {
316 PAT(0x00000000),
317 PAT(0x0000ffff),
318 PAT(0xffff0000),
319 PAT(0xffffffff),
320};
321
pbrook6d6f7c22006-03-11 15:35:30 +0000322static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000323
pbrook6d6f7c22006-03-11 15:35:30 +0000324enum color_names {
325 COLOR_BLACK = 0,
326 COLOR_RED = 1,
327 COLOR_GREEN = 2,
328 COLOR_YELLOW = 3,
329 COLOR_BLUE = 4,
330 COLOR_MAGENTA = 5,
331 COLOR_CYAN = 6,
332 COLOR_WHITE = 7
333};
334
335static const uint32_t color_table_rgb[2][8] = {
336 { /* dark */
bellard26489842006-06-25 17:37:36 +0000337 QEMU_RGB(0x00, 0x00, 0x00), /* black */
338 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
339 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
340 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
341 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
342 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
343 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
344 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000345 },
346 { /* bright */
bellard26489842006-06-25 17:37:36 +0000347 QEMU_RGB(0x00, 0x00, 0x00), /* black */
348 QEMU_RGB(0xff, 0x00, 0x00), /* red */
349 QEMU_RGB(0x00, 0xff, 0x00), /* green */
350 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
351 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
352 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
353 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
354 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000355 }
bellarde7f0ad52004-07-14 17:28:59 +0000356};
357
358static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
359{
360 switch(ds->depth) {
361 case 8:
362 col |= col << 8;
363 col |= col << 16;
364 break;
365 case 15:
366 case 16:
367 col |= col << 16;
368 break;
369 default:
370 break;
371 }
372
373 return col;
374}
pbrook6d6f7c22006-03-11 15:35:30 +0000375#ifdef DEBUG_CONSOLE
376static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
377{
378 if (t_attrib->bold) {
379 printf("b");
380 } else {
381 printf(" ");
382 }
383 if (t_attrib->uline) {
384 printf("u");
385 } else {
386 printf(" ");
387 }
388 if (t_attrib->blink) {
389 printf("l");
390 } else {
391 printf(" ");
392 }
393 if (t_attrib->invers) {
394 printf("i");
395 } else {
396 printf(" ");
397 }
398 if (t_attrib->unvisible) {
399 printf("n");
400 } else {
401 printf(" ");
402 }
403
404 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
405}
406#endif
bellarde7f0ad52004-07-14 17:28:59 +0000407
ths5fafdf22007-09-16 21:08:06 +0000408static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000409 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000410{
411 uint8_t *d;
412 const uint8_t *font_ptr;
413 unsigned int font_data, linesize, xorcol, bpp;
414 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000415 unsigned int fgcol, bgcol;
416
417#ifdef DEBUG_CONSOLE
418 printf("x: %2i y: %2i", x, y);
419 console_print_text_attributes(t_attrib, ch);
420#endif
421
422 if (t_attrib->invers) {
423 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
424 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
425 } else {
426 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
427 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
428 }
bellarde7f0ad52004-07-14 17:28:59 +0000429
430 bpp = (ds->depth + 7) >> 3;
ths5fafdf22007-09-16 21:08:06 +0000431 d = ds->data +
bellarde7f0ad52004-07-14 17:28:59 +0000432 ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
433 linesize = ds->linesize;
434 font_ptr = vgafont16 + FONT_HEIGHT * ch;
435 xorcol = bgcol ^ fgcol;
436 switch(ds->depth) {
437 case 8:
438 for(i = 0; i < FONT_HEIGHT; i++) {
439 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000440 if (t_attrib->uline
441 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
442 font_data = 0xFFFF;
443 }
bellarde7f0ad52004-07-14 17:28:59 +0000444 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
445 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
446 d += linesize;
447 }
448 break;
449 case 16:
450 case 15:
451 for(i = 0; i < FONT_HEIGHT; i++) {
452 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000453 if (t_attrib->uline
454 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
455 font_data = 0xFFFF;
456 }
bellarde7f0ad52004-07-14 17:28:59 +0000457 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
458 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
459 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
460 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
461 d += linesize;
462 }
463 break;
464 case 32:
465 for(i = 0; i < FONT_HEIGHT; i++) {
466 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000467 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
468 font_data = 0xFFFF;
469 }
bellarde7f0ad52004-07-14 17:28:59 +0000470 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
471 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
472 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
473 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
474 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
475 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
476 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
477 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
478 d += linesize;
479 }
480 break;
481 }
482}
483
484static void text_console_resize(TextConsole *s)
485{
486 TextCell *cells, *c, *c1;
487 int w1, x, y, last_width;
488
489 last_width = s->width;
490 s->width = s->g_width / FONT_WIDTH;
491 s->height = s->g_height / FONT_HEIGHT;
492
493 w1 = last_width;
494 if (s->width < w1)
495 w1 = s->width;
496
497 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
498 for(y = 0; y < s->total_height; y++) {
499 c = &cells[y * s->width];
500 if (w1 > 0) {
501 c1 = &s->cells[y * last_width];
502 for(x = 0; x < w1; x++) {
503 *c++ = *c1++;
504 }
505 }
506 for(x = w1; x < s->width; x++) {
507 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000508 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000509 c++;
510 }
511 }
512 free(s->cells);
513 s->cells = cells;
514}
515
516static void update_xy(TextConsole *s, int x, int y)
517{
518 TextCell *c;
519 int y1, y2;
520
521 if (s == active_console) {
522 y1 = (s->y_base + y) % s->total_height;
523 y2 = y1 - s->y_displayed;
524 if (y2 < 0)
525 y2 += s->total_height;
526 if (y2 < s->height) {
527 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000528 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000529 &(c->t_attrib));
ths5fafdf22007-09-16 21:08:06 +0000530 dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
bellarde7f0ad52004-07-14 17:28:59 +0000531 FONT_WIDTH, FONT_HEIGHT);
532 }
533 }
534}
535
536static void console_show_cursor(TextConsole *s, int show)
537{
538 TextCell *c;
539 int y, y1;
540
541 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000542 int x = s->x;
543 if (x >= s->width) {
544 x = s->width - 1;
545 }
bellarde7f0ad52004-07-14 17:28:59 +0000546 y1 = (s->y_base + s->y) % s->total_height;
547 y = y1 - s->y_displayed;
548 if (y < 0)
549 y += s->total_height;
550 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000551 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000552 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000553 TextAttributes t_attrib = s->t_attrib_default;
554 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000555 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000556 } else {
thsed8276a2007-02-10 22:37:56 +0000557 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000558 }
ths5fafdf22007-09-16 21:08:06 +0000559 dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
bellarde7f0ad52004-07-14 17:28:59 +0000560 FONT_WIDTH, FONT_HEIGHT);
561 }
562 }
563}
564
565static void console_refresh(TextConsole *s)
566{
567 TextCell *c;
568 int x, y, y1;
569
ths5fafdf22007-09-16 21:08:06 +0000570 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000571 return;
572
573 vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
pbrook6d6f7c22006-03-11 15:35:30 +0000574 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000575 y1 = s->y_displayed;
576 for(y = 0; y < s->height; y++) {
577 c = s->cells + y1 * s->width;
578 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000579 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000580 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000581 c++;
582 }
583 if (++y1 == s->total_height)
584 y1 = 0;
585 }
586 dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
587 console_show_cursor(s, 1);
588}
589
590static void console_scroll(int ydelta)
591{
592 TextConsole *s;
593 int i, y1;
ths5fafdf22007-09-16 21:08:06 +0000594
bellarde7f0ad52004-07-14 17:28:59 +0000595 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000596 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000597 return;
598
599 if (ydelta > 0) {
600 for(i = 0; i < ydelta; i++) {
601 if (s->y_displayed == s->y_base)
602 break;
603 if (++s->y_displayed == s->total_height)
604 s->y_displayed = 0;
605 }
606 } else {
607 ydelta = -ydelta;
608 i = s->backscroll_height;
609 if (i > s->total_height - s->height)
610 i = s->total_height - s->height;
611 y1 = s->y_base - i;
612 if (y1 < 0)
613 y1 += s->total_height;
614 for(i = 0; i < ydelta; i++) {
615 if (s->y_displayed == y1)
616 break;
617 if (--s->y_displayed < 0)
618 s->y_displayed = s->total_height - 1;
619 }
620 }
621 console_refresh(s);
622}
623
624static void console_put_lf(TextConsole *s)
625{
626 TextCell *c;
627 int x, y1;
628
bellarde7f0ad52004-07-14 17:28:59 +0000629 s->y++;
630 if (s->y >= s->height) {
631 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000632
bellarde7f0ad52004-07-14 17:28:59 +0000633 if (s->y_displayed == s->y_base) {
634 if (++s->y_displayed == s->total_height)
635 s->y_displayed = 0;
636 }
637 if (++s->y_base == s->total_height)
638 s->y_base = 0;
639 if (s->backscroll_height < s->total_height)
640 s->backscroll_height++;
641 y1 = (s->y_base + s->height - 1) % s->total_height;
642 c = &s->cells[y1 * s->width];
643 for(x = 0; x < s->width; x++) {
644 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000645 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000646 c++;
647 }
648 if (s == active_console && s->y_displayed == s->y_base) {
ths5fafdf22007-09-16 21:08:06 +0000649 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
650 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000651 (s->height - 1) * FONT_HEIGHT);
652 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000653 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000654 color_table[0][s->t_attrib_default.bgcol]);
ths5fafdf22007-09-16 21:08:06 +0000655 dpy_update(s->ds, 0, 0,
bellarde7f0ad52004-07-14 17:28:59 +0000656 s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
657 }
658 }
659}
660
pbrook6d6f7c22006-03-11 15:35:30 +0000661/* Set console attributes depending on the current escape codes.
662 * NOTE: I know this code is not very efficient (checking every color for it
663 * self) but it is more readable and better maintainable.
664 */
665static void console_handle_escape(TextConsole *s)
666{
667 int i;
668
pbrook6d6f7c22006-03-11 15:35:30 +0000669 for (i=0; i<s->nb_esc_params; i++) {
670 switch (s->esc_params[i]) {
671 case 0: /* reset all console attributes to default */
672 s->t_attrib = s->t_attrib_default;
673 break;
674 case 1:
675 s->t_attrib.bold = 1;
676 break;
677 case 4:
678 s->t_attrib.uline = 1;
679 break;
680 case 5:
681 s->t_attrib.blink = 1;
682 break;
683 case 7:
684 s->t_attrib.invers = 1;
685 break;
686 case 8:
687 s->t_attrib.unvisible = 1;
688 break;
689 case 22:
690 s->t_attrib.bold = 0;
691 break;
692 case 24:
693 s->t_attrib.uline = 0;
694 break;
695 case 25:
696 s->t_attrib.blink = 0;
697 break;
698 case 27:
699 s->t_attrib.invers = 0;
700 break;
701 case 28:
702 s->t_attrib.unvisible = 0;
703 break;
704 /* set foreground color */
705 case 30:
706 s->t_attrib.fgcol=COLOR_BLACK;
707 break;
708 case 31:
709 s->t_attrib.fgcol=COLOR_RED;
710 break;
711 case 32:
712 s->t_attrib.fgcol=COLOR_GREEN;
713 break;
714 case 33:
715 s->t_attrib.fgcol=COLOR_YELLOW;
716 break;
717 case 34:
718 s->t_attrib.fgcol=COLOR_BLUE;
719 break;
720 case 35:
721 s->t_attrib.fgcol=COLOR_MAGENTA;
722 break;
723 case 36:
724 s->t_attrib.fgcol=COLOR_CYAN;
725 break;
726 case 37:
727 s->t_attrib.fgcol=COLOR_WHITE;
728 break;
729 /* set background color */
730 case 40:
731 s->t_attrib.bgcol=COLOR_BLACK;
732 break;
733 case 41:
734 s->t_attrib.bgcol=COLOR_RED;
735 break;
736 case 42:
737 s->t_attrib.bgcol=COLOR_GREEN;
738 break;
739 case 43:
740 s->t_attrib.bgcol=COLOR_YELLOW;
741 break;
742 case 44:
743 s->t_attrib.bgcol=COLOR_BLUE;
744 break;
745 case 45:
746 s->t_attrib.bgcol=COLOR_MAGENTA;
747 break;
748 case 46:
749 s->t_attrib.bgcol=COLOR_CYAN;
750 break;
751 case 47:
752 s->t_attrib.bgcol=COLOR_WHITE;
753 break;
754 }
755 }
756}
757
thsadb47962007-01-16 23:02:36 +0000758static void console_clear_xy(TextConsole *s, int x, int y)
759{
760 int y1 = (s->y_base + y) % s->total_height;
761 TextCell *c = &s->cells[y1 * s->width + x];
762 c->ch = ' ';
763 c->t_attrib = s->t_attrib_default;
764 c++;
765 update_xy(s, x, y);
766}
767
bellarde7f0ad52004-07-14 17:28:59 +0000768static void console_putchar(TextConsole *s, int ch)
769{
770 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000771 int y1, i;
772 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000773
774 switch(s->state) {
775 case TTY_STATE_NORM:
776 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000777 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000778 s->x = 0;
779 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000780 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000781 console_put_lf(s);
782 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000783 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000784 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000785 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000786 break;
787 case '\t': /* tabspace */
788 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000789 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000790 console_put_lf(s);
791 } else {
792 s->x = s->x + (8 - (s->x % 8));
793 }
794 break;
795 case '\a': /* alert aka. bell */
796 /* TODO: has to be implemented */
797 break;
thsadb47962007-01-16 23:02:36 +0000798 case 14:
799 /* SI (shift in), character set 0 (ignored) */
800 break;
801 case 15:
802 /* SO (shift out), character set 1 (ignored) */
803 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000804 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000805 s->state = TTY_STATE_ESC;
806 break;
807 default:
thsed8276a2007-02-10 22:37:56 +0000808 if (s->x >= s->width) {
809 /* line wrap */
810 s->x = 0;
811 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000812 }
bellarde7f0ad52004-07-14 17:28:59 +0000813 y1 = (s->y_base + s->y) % s->total_height;
814 c = &s->cells[y1 * s->width + s->x];
815 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000816 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000817 update_xy(s, s->x, s->y);
818 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000819 break;
820 }
821 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000822 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000823 if (ch == '[') {
824 for(i=0;i<MAX_ESC_PARAMS;i++)
825 s->esc_params[i] = 0;
826 s->nb_esc_params = 0;
827 s->state = TTY_STATE_CSI;
828 } else {
829 s->state = TTY_STATE_NORM;
830 }
831 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000832 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000833 if (ch >= '0' && ch <= '9') {
834 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000835 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000836 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
837 }
838 } else {
839 s->nb_esc_params++;
840 if (ch == ';')
841 break;
thsadb47962007-01-16 23:02:36 +0000842#ifdef DEBUG_CONSOLE
843 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
844 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
845#endif
bellarde7f0ad52004-07-14 17:28:59 +0000846 s->state = TTY_STATE_NORM;
847 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000848 case 'A':
849 /* move cursor up */
850 if (s->esc_params[0] == 0) {
851 s->esc_params[0] = 1;
852 }
853 s->y -= s->esc_params[0];
854 if (s->y < 0) {
855 s->y = 0;
bellarde7f0ad52004-07-14 17:28:59 +0000856 }
857 break;
thsadb47962007-01-16 23:02:36 +0000858 case 'B':
859 /* move cursor down */
860 if (s->esc_params[0] == 0) {
861 s->esc_params[0] = 1;
862 }
863 s->y += s->esc_params[0];
864 if (s->y >= s->height) {
865 s->y = s->height - 1;
866 }
867 break;
868 case 'C':
869 /* move cursor right */
870 if (s->esc_params[0] == 0) {
871 s->esc_params[0] = 1;
872 }
873 s->x += s->esc_params[0];
874 if (s->x >= s->width) {
875 s->x = s->width - 1;
876 }
877 break;
878 case 'D':
879 /* move cursor left */
880 if (s->esc_params[0] == 0) {
881 s->esc_params[0] = 1;
882 }
883 s->x -= s->esc_params[0];
884 if (s->x < 0) {
885 s->x = 0;
886 }
887 break;
888 case 'G':
889 /* move cursor to column */
890 s->x = s->esc_params[0] - 1;
891 if (s->x < 0) {
892 s->x = 0;
893 }
894 break;
895 case 'f':
896 case 'H':
897 /* move cursor to row, column */
898 s->x = s->esc_params[1] - 1;
899 if (s->x < 0) {
900 s->x = 0;
901 }
902 s->y = s->esc_params[0] - 1;
903 if (s->y < 0) {
904 s->y = 0;
905 }
906 break;
907 case 'J':
908 switch (s->esc_params[0]) {
909 case 0:
910 /* clear to end of screen */
911 for (y = s->y; y < s->height; y++) {
912 for (x = 0; x < s->width; x++) {
913 if (y == s->y && x < s->x) {
914 continue;
915 }
916 console_clear_xy(s, x, y);
917 }
918 }
919 break;
920 case 1:
921 /* clear from beginning of screen */
922 for (y = 0; y <= s->y; y++) {
923 for (x = 0; x < s->width; x++) {
924 if (y == s->y && x > s->x) {
925 break;
926 }
927 console_clear_xy(s, x, y);
928 }
929 }
930 break;
931 case 2:
932 /* clear entire screen */
933 for (y = 0; y <= s->height; y++) {
934 for (x = 0; x < s->width; x++) {
935 console_clear_xy(s, x, y);
936 }
937 }
938 break;
939 }
940 case 'K':
941 switch (s->esc_params[0]) {
942 case 0:
943 /* clear to eol */
944 for(x = s->x; x < s->width; x++) {
945 console_clear_xy(s, x, s->y);
946 }
947 break;
948 case 1:
949 /* clear from beginning of line */
950 for (x = 0; x <= s->x; x++) {
951 console_clear_xy(s, x, s->y);
952 }
953 break;
954 case 2:
955 /* clear entire line */
956 for(x = 0; x < s->width; x++) {
957 console_clear_xy(s, x, s->y);
958 }
bellarde7f0ad52004-07-14 17:28:59 +0000959 break;
960 }
thsadb47962007-01-16 23:02:36 +0000961 break;
962 case 'm':
pbrook6d6f7c22006-03-11 15:35:30 +0000963 console_handle_escape(s);
bellarde7f0ad52004-07-14 17:28:59 +0000964 break;
thsadb47962007-01-16 23:02:36 +0000965 case 'n':
966 /* report cursor position */
967 /* TODO: send ESC[row;colR */
968 break;
969 case 's':
970 /* save cursor position */
971 s->x_saved = s->x;
972 s->y_saved = s->y;
973 break;
974 case 'u':
975 /* restore cursor position */
976 s->x = s->x_saved;
977 s->y = s->y_saved;
978 break;
979 default:
980#ifdef DEBUG_CONSOLE
981 fprintf(stderr, "unhandled escape character '%c'\n", ch);
982#endif
983 break;
984 }
985 break;
bellarde7f0ad52004-07-14 17:28:59 +0000986 }
987 }
988}
989
990void console_select(unsigned int index)
991{
992 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +0000993
bellarde7f0ad52004-07-14 17:28:59 +0000994 if (index >= MAX_CONSOLES)
995 return;
996 s = consoles[index];
997 if (s) {
998 active_console = s;
thsaf3a9032007-07-11 23:14:59 +0000999 if (s->console_type != GRAPHIC_CONSOLE) {
bellarde7f0ad52004-07-14 17:28:59 +00001000 if (s->g_width != s->ds->width ||
bellard8e3a9fd2004-10-09 17:32:58 +00001001 s->g_height != s->ds->height) {
thsaf3a9032007-07-11 23:14:59 +00001002 if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) {
1003 dpy_resize(s->ds, s->g_width, s->g_height);
1004 } else {
pbrook6d6f7c22006-03-11 15:35:30 +00001005 s->g_width = s->ds->width;
1006 s->g_height = s->ds->height;
bellarde7f0ad52004-07-14 17:28:59 +00001007 text_console_resize(s);
pbrook95219892006-04-09 01:06:34 +00001008 }
thsaf3a9032007-07-11 23:14:59 +00001009 }
bellarde7f0ad52004-07-14 17:28:59 +00001010 console_refresh(s);
pbrook95219892006-04-09 01:06:34 +00001011 } else {
1012 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001013 }
1014 }
1015}
1016
1017static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1018{
1019 TextConsole *s = chr->opaque;
1020 int i;
1021
1022 console_show_cursor(s, 0);
1023 for(i = 0; i < len; i++) {
1024 console_putchar(s, buf[i]);
1025 }
1026 console_show_cursor(s, 1);
1027 return len;
1028}
1029
bellard6fcfafb2004-08-01 21:48:30 +00001030static void console_send_event(CharDriverState *chr, int event)
1031{
1032 TextConsole *s = chr->opaque;
1033 int i;
1034
1035 if (event == CHR_EVENT_FOCUS) {
1036 for(i = 0; i < nb_consoles; i++) {
1037 if (consoles[i] == s) {
1038 console_select(i);
1039 break;
1040 }
1041 }
1042 }
1043}
1044
bellarde15d7372006-06-25 16:26:29 +00001045static void kbd_send_chars(void *opaque)
1046{
1047 TextConsole *s = opaque;
1048 int len;
1049 uint8_t buf[16];
ths5fafdf22007-09-16 21:08:06 +00001050
pbrooke5b0bc42007-01-27 23:46:43 +00001051 len = qemu_chr_can_read(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001052 if (len > s->out_fifo.count)
1053 len = s->out_fifo.count;
1054 if (len > 0) {
1055 if (len > sizeof(buf))
1056 len = sizeof(buf);
1057 qemu_fifo_read(&s->out_fifo, buf, len);
pbrooke5b0bc42007-01-27 23:46:43 +00001058 qemu_chr_read(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001059 }
1060 /* characters are pending: we send them a bit later (XXX:
1061 horrible, should change char device API) */
1062 if (s->out_fifo.count > 0) {
1063 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1064 }
1065}
1066
bellarde7f0ad52004-07-14 17:28:59 +00001067/* called when an ascii key is pressed */
1068void kbd_put_keysym(int keysym)
1069{
1070 TextConsole *s;
1071 uint8_t buf[16], *q;
1072 int c;
1073
1074 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001075 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001076 return;
1077
1078 switch(keysym) {
1079 case QEMU_KEY_CTRL_UP:
1080 console_scroll(-1);
1081 break;
1082 case QEMU_KEY_CTRL_DOWN:
1083 console_scroll(1);
1084 break;
1085 case QEMU_KEY_CTRL_PAGEUP:
1086 console_scroll(-10);
1087 break;
1088 case QEMU_KEY_CTRL_PAGEDOWN:
1089 console_scroll(10);
1090 break;
1091 default:
bellarde15d7372006-06-25 16:26:29 +00001092 /* convert the QEMU keysym to VT100 key string */
1093 q = buf;
1094 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1095 *q++ = '\033';
1096 *q++ = '[';
1097 c = keysym - 0xe100;
1098 if (c >= 10)
1099 *q++ = '0' + (c / 10);
1100 *q++ = '0' + (c % 10);
1101 *q++ = '~';
1102 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1103 *q++ = '\033';
1104 *q++ = '[';
1105 *q++ = keysym & 0xff;
1106 } else {
bellarde7f0ad52004-07-14 17:28:59 +00001107 *q++ = keysym;
bellarde15d7372006-06-25 16:26:29 +00001108 }
pbrooke5b0bc42007-01-27 23:46:43 +00001109 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001110 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1111 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001112 }
1113 break;
1114 }
1115}
1116
thsaf3a9032007-07-11 23:14:59 +00001117static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001118{
1119 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001120 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001121
1122 if (nb_consoles >= MAX_CONSOLES)
1123 return NULL;
1124 s = qemu_mallocz(sizeof(TextConsole));
1125 if (!s) {
1126 return NULL;
1127 }
thsaf3a9032007-07-11 23:14:59 +00001128 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1129 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001130 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001131 }
bellarde7f0ad52004-07-14 17:28:59 +00001132 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001133 s->console_type = console_type;
1134 if (console_type != GRAPHIC_CONSOLE) {
pbrook95219892006-04-09 01:06:34 +00001135 consoles[nb_consoles++] = s;
1136 } else {
1137 /* HACK: Put graphical consoles before text consoles. */
1138 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001139 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001140 break;
1141 consoles[i] = consoles[i - 1];
1142 }
1143 consoles[i] = s;
1144 }
bellarde7f0ad52004-07-14 17:28:59 +00001145 return s;
1146}
1147
pbrook95219892006-04-09 01:06:34 +00001148TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1149 vga_hw_invalidate_ptr invalidate,
1150 vga_hw_screen_dump_ptr screen_dump,
1151 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001152{
pbrook95219892006-04-09 01:06:34 +00001153 TextConsole *s;
1154
thsaf3a9032007-07-11 23:14:59 +00001155 s = new_console(ds, GRAPHIC_CONSOLE);
pbrook95219892006-04-09 01:06:34 +00001156 if (!s)
1157 return NULL;
1158 s->hw_update = update;
1159 s->hw_invalidate = invalidate;
1160 s->hw_screen_dump = screen_dump;
1161 s->hw = opaque;
1162 return s;
1163}
1164
1165int is_graphic_console(void)
1166{
thsaf3a9032007-07-11 23:14:59 +00001167 return active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001168}
1169
thsaf3a9032007-07-11 23:14:59 +00001170CharDriverState *text_console_init(DisplayState *ds, const char *p)
bellarde7f0ad52004-07-14 17:28:59 +00001171{
1172 CharDriverState *chr;
1173 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001174 int i,j;
thsaf3a9032007-07-11 23:14:59 +00001175 unsigned width;
1176 unsigned height;
bellarde7f0ad52004-07-14 17:28:59 +00001177 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001178
bellarde7f0ad52004-07-14 17:28:59 +00001179 chr = qemu_mallocz(sizeof(CharDriverState));
1180 if (!chr)
1181 return NULL;
thsaf3a9032007-07-11 23:14:59 +00001182 s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
bellarde7f0ad52004-07-14 17:28:59 +00001183 if (!s) {
1184 free(chr);
1185 return NULL;
1186 }
bellarde7f0ad52004-07-14 17:28:59 +00001187 chr->opaque = s;
1188 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001189 chr->chr_send_event = console_send_event;
1190
pbrooke5b0bc42007-01-27 23:46:43 +00001191 s->chr = chr;
bellarde15d7372006-06-25 16:26:29 +00001192 s->out_fifo.buf = s->out_fifo_buf;
1193 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1194 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
ths5fafdf22007-09-16 21:08:06 +00001195
bellarde7f0ad52004-07-14 17:28:59 +00001196 if (!color_inited) {
1197 color_inited = 1;
pbrook6d6f7c22006-03-11 15:35:30 +00001198 for(j = 0; j < 2; j++) {
1199 for(i = 0; i < 8; i++) {
ths5fafdf22007-09-16 21:08:06 +00001200 color_table[j][i] = col_expand(s->ds,
pbrook6d6f7c22006-03-11 15:35:30 +00001201 vga_get_color(s->ds, color_table_rgb[j][i]));
1202 }
bellarde7f0ad52004-07-14 17:28:59 +00001203 }
1204 }
1205 s->y_displayed = 0;
1206 s->y_base = 0;
1207 s->total_height = DEFAULT_BACKSCROLL;
1208 s->x = 0;
1209 s->y = 0;
thsaf3a9032007-07-11 23:14:59 +00001210 width = s->ds->width;
1211 height = s->ds->height;
1212 if (p != 0) {
1213 width = strtoul(p, (char **)&p, 10);
1214 if (*p == 'C') {
1215 p++;
1216 width *= FONT_WIDTH;
1217 }
1218 if (*p == 'x') {
1219 p++;
1220 height = strtoul(p, (char **)&p, 10);
1221 if (*p == 'C') {
1222 p++;
1223 height *= FONT_HEIGHT;
1224 }
1225 }
1226 }
1227 s->g_width = width;
1228 s->g_height = height;
pbrook6d6f7c22006-03-11 15:35:30 +00001229
1230 /* Set text attribute defaults */
1231 s->t_attrib_default.bold = 0;
1232 s->t_attrib_default.uline = 0;
1233 s->t_attrib_default.blink = 0;
1234 s->t_attrib_default.invers = 0;
1235 s->t_attrib_default.unvisible = 0;
1236 s->t_attrib_default.fgcol = COLOR_WHITE;
1237 s->t_attrib_default.bgcol = COLOR_BLACK;
1238
1239 /* set current text attributes to default */
1240 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001241 text_console_resize(s);
1242
ths86e94de2007-01-05 22:01:59 +00001243 qemu_chr_reset(chr);
1244
bellarde7f0ad52004-07-14 17:28:59 +00001245 return chr;
1246}