]> git.proxmox.com Git - qemu.git/blame - console.c
vc: colorize chardev title line with blue background.
[qemu.git] / console.c
CommitLineData
e7f0ad58
FB
1/*
2 * QEMU graphical console
5fafdf24 3 *
e7f0ad58 4 * Copyright (c) 2004 Fabrice Bellard
5fafdf24 5 *
e7f0ad58
FB
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 */
87ecb68b
PB
24#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
e7f0ad58 27
6d6f7c28 28//#define DEBUG_CONSOLE
e7f0ad58
FB
29#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
31
26489844
FB
32#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
e7f0ad58 34
6d6f7c28
PB
35typedef struct TextAttributes {
36 uint8_t fgcol:4;
37 uint8_t bgcol:4;
38 uint8_t bold:1;
39 uint8_t uline:1;
40 uint8_t blink:1;
41 uint8_t invers:1;
42 uint8_t unvisible:1;
43} TextAttributes;
44
e7f0ad58
FB
45typedef struct TextCell {
46 uint8_t ch;
6d6f7c28 47 TextAttributes t_attrib;
e7f0ad58
FB
48} TextCell;
49
50#define MAX_ESC_PARAMS 3
51
52enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
56};
57
e15d7371
FB
58typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
9596ebb7 64static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
e15d7371
FB
65{
66 int l, len;
67
68 l = f->buf_size - f->count;
69 if (len1 > l)
70 len1 = l;
71 len = len1;
72 while (len > 0) {
73 l = f->buf_size - f->wptr;
74 if (l > len)
75 l = len;
76 memcpy(f->buf + f->wptr, buf, l);
77 f->wptr += l;
78 if (f->wptr >= f->buf_size)
79 f->wptr = 0;
80 buf += l;
81 len -= l;
82 }
83 f->count += len1;
84 return len1;
85}
86
9596ebb7 87static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
e15d7371
FB
88{
89 int l, len;
90
91 if (len1 > f->count)
92 len1 = f->count;
93 len = len1;
94 while (len > 0) {
95 l = f->buf_size - f->rptr;
96 if (l > len)
97 l = len;
98 memcpy(buf, f->buf + f->rptr, l);
99 f->rptr += l;
100 if (f->rptr >= f->buf_size)
101 f->rptr = 0;
102 buf += l;
103 len -= l;
104 }
105 f->count -= len1;
106 return len1;
107}
108
af3a9031
TS
109typedef enum {
110 GRAPHIC_CONSOLE,
c21bbcfa
AZ
111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
c227f099 113} console_type_t;
af3a9031 114
95219897
PB
115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
e7f0ad58 117struct TextConsole {
c227f099 118 console_type_t console_type;
e7f0ad58 119 DisplayState *ds;
95219897
PB
120 /* Graphic console state. */
121 vga_hw_update_ptr hw_update;
122 vga_hw_invalidate_ptr hw_invalidate;
123 vga_hw_screen_dump_ptr hw_screen_dump;
4d3b6f6e 124 vga_hw_text_update_ptr hw_text_update;
95219897
PB
125 void *hw;
126
e7f0ad58
FB
127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
e7f0ad58 132 int x, y;
adb47967 133 int x_saved, y_saved;
e7f0ad58
FB
134 int y_displayed;
135 int y_base;
6d6f7c28
PB
136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58 138 TextCell *cells;
4d3b6f6e 139 int text_x[2], text_y[2], cursor_invalidate;
e7f0ad58 140
14778c20
PB
141 int update_x0;
142 int update_y0;
143 int update_x1;
144 int update_y1;
145
e7f0ad58
FB
146 enum TTYState state;
147 int esc_params[MAX_ESC_PARAMS];
148 int nb_esc_params;
149
e5b0bc44 150 CharDriverState *chr;
e15d7371
FB
151 /* fifo for key pressed */
152 QEMUFIFO out_fifo;
153 uint8_t out_fifo_buf[16];
154 QEMUTimer *kbd_timer;
e7f0ad58
FB
155};
156
157static TextConsole *active_console;
158static TextConsole *consoles[MAX_CONSOLES];
159static int nb_consoles = 0;
160
95219897
PB
161void vga_hw_update(void)
162{
adb47967 163 if (active_console && active_console->hw_update)
95219897
PB
164 active_console->hw_update(active_console->hw);
165}
166
167void vga_hw_invalidate(void)
168{
169 if (active_console->hw_invalidate)
170 active_console->hw_invalidate(active_console->hw);
171}
172
173void vga_hw_screen_dump(const char *filename)
174{
8571c055
AZ
175 TextConsole *previous_active_console;
176
177 previous_active_console = active_console;
178 active_console = consoles[0];
179 /* There is currently no way of specifying which screen we want to dump,
7b455225 180 so always dump the first one. */
95219897
PB
181 if (consoles[0]->hw_screen_dump)
182 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
8571c055 183 active_console = previous_active_console;
95219897
PB
184}
185
c227f099 186void vga_hw_text_update(console_ch_t *chardata)
4d3b6f6e
AZ
187{
188 if (active_console && active_console->hw_text_update)
189 active_console->hw_text_update(active_console->hw, chardata);
190}
191
e7f0ad58
FB
192/* convert a RGBA color to a color index usable in graphic primitives */
193static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
194{
195 unsigned int r, g, b, color;
196
0e1f5a0c 197 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
198#if 0
199 case 8:
200 r = (rgba >> 16) & 0xff;
201 g = (rgba >> 8) & 0xff;
202 b = (rgba) & 0xff;
5fafdf24
TS
203 color = (rgb_to_index[r] * 6 * 6) +
204 (rgb_to_index[g] * 6) +
e7f0ad58
FB
205 (rgb_to_index[b]);
206 break;
207#endif
208 case 15:
209 r = (rgba >> 16) & 0xff;
210 g = (rgba >> 8) & 0xff;
211 b = (rgba) & 0xff;
212 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
213 break;
214 case 16:
215 r = (rgba >> 16) & 0xff;
216 g = (rgba >> 8) & 0xff;
217 b = (rgba) & 0xff;
218 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
219 break;
220 case 32:
221 default:
222 color = rgba;
223 break;
224 }
225 return color;
226}
227
5fafdf24 228static void vga_fill_rect (DisplayState *ds,
e7f0ad58
FB
229 int posx, int posy, int width, int height, uint32_t color)
230{
231 uint8_t *d, *d1;
232 int x, y, bpp;
3b46e624 233
0e1f5a0c
AL
234 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
235 d1 = ds_get_data(ds) +
236 ds_get_linesize(ds) * posy + bpp * posx;
e7f0ad58
FB
237 for (y = 0; y < height; y++) {
238 d = d1;
239 switch(bpp) {
240 case 1:
241 for (x = 0; x < width; x++) {
242 *((uint8_t *)d) = color;
243 d++;
244 }
245 break;
246 case 2:
247 for (x = 0; x < width; x++) {
248 *((uint16_t *)d) = color;
249 d += 2;
250 }
251 break;
252 case 4:
253 for (x = 0; x < width; x++) {
254 *((uint32_t *)d) = color;
255 d += 4;
256 }
257 break;
258 }
0e1f5a0c 259 d1 += ds_get_linesize(ds);
e7f0ad58
FB
260 }
261}
262
263/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
264static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
265{
266 const uint8_t *s;
267 uint8_t *d;
268 int wb, y, bpp;
269
0e1f5a0c 270 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
e7f0ad58
FB
271 wb = w * bpp;
272 if (yd <= ys) {
0e1f5a0c
AL
273 s = ds_get_data(ds) +
274 ds_get_linesize(ds) * ys + bpp * xs;
275 d = ds_get_data(ds) +
276 ds_get_linesize(ds) * yd + bpp * xd;
e7f0ad58
FB
277 for (y = 0; y < h; y++) {
278 memmove(d, s, wb);
0e1f5a0c
AL
279 d += ds_get_linesize(ds);
280 s += ds_get_linesize(ds);
e7f0ad58
FB
281 }
282 } else {
0e1f5a0c
AL
283 s = ds_get_data(ds) +
284 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
285 d = ds_get_data(ds) +
286 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
e7f0ad58
FB
287 for (y = 0; y < h; y++) {
288 memmove(d, s, wb);
0e1f5a0c
AL
289 d -= ds_get_linesize(ds);
290 s -= ds_get_linesize(ds);
e7f0ad58
FB
291 }
292 }
293}
294
295/***********************************************************/
296/* basic char display */
297
298#define FONT_HEIGHT 16
299#define FONT_WIDTH 8
300
301#include "vgafont.h"
302
303#define cbswap_32(__x) \
304((uint32_t)( \
305 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
306 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
307 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
308 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
309
e2542fe2 310#ifdef HOST_WORDS_BIGENDIAN
e7f0ad58
FB
311#define PAT(x) x
312#else
313#define PAT(x) cbswap_32(x)
314#endif
315
316static const uint32_t dmask16[16] = {
317 PAT(0x00000000),
318 PAT(0x000000ff),
319 PAT(0x0000ff00),
320 PAT(0x0000ffff),
321 PAT(0x00ff0000),
322 PAT(0x00ff00ff),
323 PAT(0x00ffff00),
324 PAT(0x00ffffff),
325 PAT(0xff000000),
326 PAT(0xff0000ff),
327 PAT(0xff00ff00),
328 PAT(0xff00ffff),
329 PAT(0xffff0000),
330 PAT(0xffff00ff),
331 PAT(0xffffff00),
332 PAT(0xffffffff),
333};
334
335static const uint32_t dmask4[4] = {
336 PAT(0x00000000),
337 PAT(0x0000ffff),
338 PAT(0xffff0000),
339 PAT(0xffffffff),
340};
341
6d6f7c28
PB
342static uint32_t color_table[2][8];
343
344enum color_names {
345 COLOR_BLACK = 0,
346 COLOR_RED = 1,
347 COLOR_GREEN = 2,
348 COLOR_YELLOW = 3,
349 COLOR_BLUE = 4,
350 COLOR_MAGENTA = 5,
351 COLOR_CYAN = 6,
352 COLOR_WHITE = 7
353};
354
355static const uint32_t color_table_rgb[2][8] = {
356 { /* dark */
26489844
FB
357 QEMU_RGB(0x00, 0x00, 0x00), /* black */
358 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
359 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
360 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
361 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
362 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
363 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
364 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
365 },
366 { /* bright */
26489844
FB
367 QEMU_RGB(0x00, 0x00, 0x00), /* black */
368 QEMU_RGB(0xff, 0x00, 0x00), /* red */
369 QEMU_RGB(0x00, 0xff, 0x00), /* green */
370 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
371 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
372 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
373 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
374 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 375 }
e7f0ad58
FB
376};
377
378static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
379{
0e1f5a0c 380 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
381 case 8:
382 col |= col << 8;
383 col |= col << 16;
384 break;
385 case 15:
386 case 16:
387 col |= col << 16;
388 break;
389 default:
390 break;
391 }
392
393 return col;
394}
6d6f7c28
PB
395#ifdef DEBUG_CONSOLE
396static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
397{
398 if (t_attrib->bold) {
399 printf("b");
400 } else {
401 printf(" ");
402 }
403 if (t_attrib->uline) {
404 printf("u");
405 } else {
406 printf(" ");
407 }
408 if (t_attrib->blink) {
409 printf("l");
410 } else {
411 printf(" ");
412 }
413 if (t_attrib->invers) {
414 printf("i");
415 } else {
416 printf(" ");
417 }
418 if (t_attrib->unvisible) {
419 printf("n");
420 } else {
421 printf(" ");
422 }
423
424 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
425}
426#endif
e7f0ad58 427
5fafdf24 428static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 429 TextAttributes *t_attrib)
e7f0ad58
FB
430{
431 uint8_t *d;
432 const uint8_t *font_ptr;
433 unsigned int font_data, linesize, xorcol, bpp;
434 int i;
6d6f7c28
PB
435 unsigned int fgcol, bgcol;
436
437#ifdef DEBUG_CONSOLE
438 printf("x: %2i y: %2i", x, y);
439 console_print_text_attributes(t_attrib, ch);
440#endif
441
442 if (t_attrib->invers) {
443 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
444 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
445 } else {
446 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
447 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
448 }
e7f0ad58 449
0e1f5a0c
AL
450 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
451 d = ds_get_data(ds) +
452 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
453 linesize = ds_get_linesize(ds);
e7f0ad58
FB
454 font_ptr = vgafont16 + FONT_HEIGHT * ch;
455 xorcol = bgcol ^ fgcol;
0e1f5a0c 456 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
457 case 8:
458 for(i = 0; i < FONT_HEIGHT; i++) {
459 font_data = *font_ptr++;
6d6f7c28
PB
460 if (t_attrib->uline
461 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
462 font_data = 0xFFFF;
463 }
e7f0ad58
FB
464 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
465 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
466 d += linesize;
467 }
468 break;
469 case 16:
470 case 15:
471 for(i = 0; i < FONT_HEIGHT; i++) {
472 font_data = *font_ptr++;
6d6f7c28
PB
473 if (t_attrib->uline
474 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
475 font_data = 0xFFFF;
476 }
e7f0ad58
FB
477 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
478 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
479 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
480 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
481 d += linesize;
482 }
483 break;
484 case 32:
485 for(i = 0; i < FONT_HEIGHT; i++) {
486 font_data = *font_ptr++;
6d6f7c28
PB
487 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
488 font_data = 0xFFFF;
489 }
e7f0ad58
FB
490 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
491 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
492 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
493 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
494 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
495 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
496 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
497 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
498 d += linesize;
499 }
500 break;
501 }
502}
503
504static void text_console_resize(TextConsole *s)
505{
506 TextCell *cells, *c, *c1;
507 int w1, x, y, last_width;
508
509 last_width = s->width;
510 s->width = s->g_width / FONT_WIDTH;
511 s->height = s->g_height / FONT_HEIGHT;
512
513 w1 = last_width;
514 if (s->width < w1)
515 w1 = s->width;
516
517 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
518 for(y = 0; y < s->total_height; y++) {
519 c = &cells[y * s->width];
520 if (w1 > 0) {
521 c1 = &s->cells[y * last_width];
522 for(x = 0; x < w1; x++) {
523 *c++ = *c1++;
524 }
525 }
526 for(x = w1; x < s->width; x++) {
527 c->ch = ' ';
6d6f7c28 528 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
529 c++;
530 }
531 }
a528b80c 532 qemu_free(s->cells);
e7f0ad58
FB
533 s->cells = cells;
534}
535
4d3b6f6e
AZ
536static inline void text_update_xy(TextConsole *s, int x, int y)
537{
538 s->text_x[0] = MIN(s->text_x[0], x);
539 s->text_x[1] = MAX(s->text_x[1], x);
540 s->text_y[0] = MIN(s->text_y[0], y);
541 s->text_y[1] = MAX(s->text_y[1], y);
542}
543
14778c20
PB
544static void invalidate_xy(TextConsole *s, int x, int y)
545{
546 if (s->update_x0 > x * FONT_WIDTH)
547 s->update_x0 = x * FONT_WIDTH;
548 if (s->update_y0 > y * FONT_HEIGHT)
549 s->update_y0 = y * FONT_HEIGHT;
550 if (s->update_x1 < (x + 1) * FONT_WIDTH)
551 s->update_x1 = (x + 1) * FONT_WIDTH;
552 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
553 s->update_y1 = (y + 1) * FONT_HEIGHT;
554}
555
e7f0ad58
FB
556static void update_xy(TextConsole *s, int x, int y)
557{
558 TextCell *c;
559 int y1, y2;
560
561 if (s == active_console) {
0e1f5a0c 562 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
563 text_update_xy(s, x, y);
564 return;
565 }
566
e7f0ad58
FB
567 y1 = (s->y_base + y) % s->total_height;
568 y2 = y1 - s->y_displayed;
569 if (y2 < 0)
570 y2 += s->total_height;
571 if (y2 < s->height) {
572 c = &s->cells[y1 * s->width + x];
5fafdf24 573 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 574 &(c->t_attrib));
14778c20 575 invalidate_xy(s, x, y2);
e7f0ad58
FB
576 }
577 }
578}
579
580static void console_show_cursor(TextConsole *s, int show)
581{
582 TextCell *c;
583 int y, y1;
584
585 if (s == active_console) {
ed8276ac 586 int x = s->x;
4d3b6f6e 587
0e1f5a0c 588 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
589 s->cursor_invalidate = 1;
590 return;
591 }
592
ed8276ac
TS
593 if (x >= s->width) {
594 x = s->width - 1;
595 }
e7f0ad58
FB
596 y1 = (s->y_base + s->y) % s->total_height;
597 y = y1 - s->y_displayed;
598 if (y < 0)
599 y += s->total_height;
600 if (y < s->height) {
ed8276ac 601 c = &s->cells[y1 * s->width + x];
e7f0ad58 602 if (show) {
6d6f7c28
PB
603 TextAttributes t_attrib = s->t_attrib_default;
604 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
ed8276ac 605 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
e7f0ad58 606 } else {
ed8276ac 607 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
e7f0ad58 608 }
14778c20 609 invalidate_xy(s, x, y);
e7f0ad58
FB
610 }
611 }
612}
613
614static void console_refresh(TextConsole *s)
615{
616 TextCell *c;
617 int x, y, y1;
618
5fafdf24 619 if (s != active_console)
e7f0ad58 620 return;
0e1f5a0c 621 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
622 s->text_x[0] = 0;
623 s->text_y[0] = 0;
624 s->text_x[1] = s->width - 1;
625 s->text_y[1] = s->height - 1;
626 s->cursor_invalidate = 1;
627 return;
628 }
e7f0ad58 629
0e1f5a0c 630 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
6d6f7c28 631 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
632 y1 = s->y_displayed;
633 for(y = 0; y < s->height; y++) {
634 c = s->cells + y1 * s->width;
635 for(x = 0; x < s->width; x++) {
5fafdf24 636 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 637 &(c->t_attrib));
e7f0ad58
FB
638 c++;
639 }
640 if (++y1 == s->total_height)
641 y1 = 0;
642 }
e7f0ad58 643 console_show_cursor(s, 1);
14778c20 644 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
e7f0ad58
FB
645}
646
647static void console_scroll(int ydelta)
648{
649 TextConsole *s;
650 int i, y1;
3b46e624 651
e7f0ad58 652 s = active_console;
af3a9031 653 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
654 return;
655
656 if (ydelta > 0) {
657 for(i = 0; i < ydelta; i++) {
658 if (s->y_displayed == s->y_base)
659 break;
660 if (++s->y_displayed == s->total_height)
661 s->y_displayed = 0;
662 }
663 } else {
664 ydelta = -ydelta;
665 i = s->backscroll_height;
666 if (i > s->total_height - s->height)
667 i = s->total_height - s->height;
668 y1 = s->y_base - i;
669 if (y1 < 0)
670 y1 += s->total_height;
671 for(i = 0; i < ydelta; i++) {
672 if (s->y_displayed == y1)
673 break;
674 if (--s->y_displayed < 0)
675 s->y_displayed = s->total_height - 1;
676 }
677 }
678 console_refresh(s);
679}
680
681static void console_put_lf(TextConsole *s)
682{
683 TextCell *c;
684 int x, y1;
685
e7f0ad58
FB
686 s->y++;
687 if (s->y >= s->height) {
688 s->y = s->height - 1;
6d6f7c28 689
e7f0ad58
FB
690 if (s->y_displayed == s->y_base) {
691 if (++s->y_displayed == s->total_height)
692 s->y_displayed = 0;
693 }
694 if (++s->y_base == s->total_height)
695 s->y_base = 0;
696 if (s->backscroll_height < s->total_height)
697 s->backscroll_height++;
698 y1 = (s->y_base + s->height - 1) % s->total_height;
699 c = &s->cells[y1 * s->width];
700 for(x = 0; x < s->width; x++) {
701 c->ch = ' ';
6d6f7c28 702 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
703 c++;
704 }
705 if (s == active_console && s->y_displayed == s->y_base) {
0e1f5a0c 706 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
707 s->text_x[0] = 0;
708 s->text_y[0] = 0;
709 s->text_x[1] = s->width - 1;
710 s->text_y[1] = s->height - 1;
711 return;
712 }
713
5fafdf24
TS
714 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
715 s->width * FONT_WIDTH,
e7f0ad58
FB
716 (s->height - 1) * FONT_HEIGHT);
717 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
5fafdf24 718 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 719 color_table[0][s->t_attrib_default.bgcol]);
14778c20
PB
720 s->update_x0 = 0;
721 s->update_y0 = 0;
722 s->update_x1 = s->width * FONT_WIDTH;
723 s->update_y1 = s->height * FONT_HEIGHT;
e7f0ad58
FB
724 }
725 }
726}
727
6d6f7c28
PB
728/* Set console attributes depending on the current escape codes.
729 * NOTE: I know this code is not very efficient (checking every color for it
730 * self) but it is more readable and better maintainable.
731 */
732static void console_handle_escape(TextConsole *s)
733{
734 int i;
735
6d6f7c28
PB
736 for (i=0; i<s->nb_esc_params; i++) {
737 switch (s->esc_params[i]) {
738 case 0: /* reset all console attributes to default */
739 s->t_attrib = s->t_attrib_default;
740 break;
741 case 1:
742 s->t_attrib.bold = 1;
743 break;
744 case 4:
745 s->t_attrib.uline = 1;
746 break;
747 case 5:
748 s->t_attrib.blink = 1;
749 break;
750 case 7:
751 s->t_attrib.invers = 1;
752 break;
753 case 8:
754 s->t_attrib.unvisible = 1;
755 break;
756 case 22:
757 s->t_attrib.bold = 0;
758 break;
759 case 24:
760 s->t_attrib.uline = 0;
761 break;
762 case 25:
763 s->t_attrib.blink = 0;
764 break;
765 case 27:
766 s->t_attrib.invers = 0;
767 break;
768 case 28:
769 s->t_attrib.unvisible = 0;
770 break;
771 /* set foreground color */
772 case 30:
773 s->t_attrib.fgcol=COLOR_BLACK;
774 break;
775 case 31:
776 s->t_attrib.fgcol=COLOR_RED;
777 break;
778 case 32:
779 s->t_attrib.fgcol=COLOR_GREEN;
780 break;
781 case 33:
782 s->t_attrib.fgcol=COLOR_YELLOW;
783 break;
784 case 34:
785 s->t_attrib.fgcol=COLOR_BLUE;
786 break;
787 case 35:
788 s->t_attrib.fgcol=COLOR_MAGENTA;
789 break;
790 case 36:
791 s->t_attrib.fgcol=COLOR_CYAN;
792 break;
793 case 37:
794 s->t_attrib.fgcol=COLOR_WHITE;
795 break;
796 /* set background color */
797 case 40:
798 s->t_attrib.bgcol=COLOR_BLACK;
799 break;
800 case 41:
801 s->t_attrib.bgcol=COLOR_RED;
802 break;
803 case 42:
804 s->t_attrib.bgcol=COLOR_GREEN;
805 break;
806 case 43:
807 s->t_attrib.bgcol=COLOR_YELLOW;
808 break;
809 case 44:
810 s->t_attrib.bgcol=COLOR_BLUE;
811 break;
812 case 45:
813 s->t_attrib.bgcol=COLOR_MAGENTA;
814 break;
815 case 46:
816 s->t_attrib.bgcol=COLOR_CYAN;
817 break;
818 case 47:
819 s->t_attrib.bgcol=COLOR_WHITE;
820 break;
821 }
822 }
823}
824
adb47967
TS
825static void console_clear_xy(TextConsole *s, int x, int y)
826{
827 int y1 = (s->y_base + y) % s->total_height;
828 TextCell *c = &s->cells[y1 * s->width + x];
829 c->ch = ' ';
830 c->t_attrib = s->t_attrib_default;
831 c++;
832 update_xy(s, x, y);
833}
834
e7f0ad58
FB
835static void console_putchar(TextConsole *s, int ch)
836{
837 TextCell *c;
adb47967
TS
838 int y1, i;
839 int x, y;
e7f0ad58
FB
840
841 switch(s->state) {
842 case TTY_STATE_NORM:
843 switch(ch) {
6d6f7c28 844 case '\r': /* carriage return */
e7f0ad58
FB
845 s->x = 0;
846 break;
6d6f7c28 847 case '\n': /* newline */
e7f0ad58
FB
848 console_put_lf(s);
849 break;
6d6f7c28 850 case '\b': /* backspace */
5fafdf24 851 if (s->x > 0)
e15d7371 852 s->x--;
6d6f7c28
PB
853 break;
854 case '\t': /* tabspace */
855 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 856 s->x = 0;
6d6f7c28
PB
857 console_put_lf(s);
858 } else {
859 s->x = s->x + (8 - (s->x % 8));
860 }
861 break;
862 case '\a': /* alert aka. bell */
863 /* TODO: has to be implemented */
864 break;
adb47967
TS
865 case 14:
866 /* SI (shift in), character set 0 (ignored) */
867 break;
868 case 15:
869 /* SO (shift out), character set 1 (ignored) */
870 break;
6d6f7c28 871 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
872 s->state = TTY_STATE_ESC;
873 break;
874 default:
ed8276ac
TS
875 if (s->x >= s->width) {
876 /* line wrap */
877 s->x = 0;
878 console_put_lf(s);
adb47967 879 }
e7f0ad58
FB
880 y1 = (s->y_base + s->y) % s->total_height;
881 c = &s->cells[y1 * s->width + s->x];
882 c->ch = ch;
6d6f7c28 883 c->t_attrib = s->t_attrib;
e7f0ad58
FB
884 update_xy(s, s->x, s->y);
885 s->x++;
e7f0ad58
FB
886 break;
887 }
888 break;
6d6f7c28 889 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
890 if (ch == '[') {
891 for(i=0;i<MAX_ESC_PARAMS;i++)
892 s->esc_params[i] = 0;
893 s->nb_esc_params = 0;
894 s->state = TTY_STATE_CSI;
895 } else {
896 s->state = TTY_STATE_NORM;
897 }
898 break;
6d6f7c28 899 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
900 if (ch >= '0' && ch <= '9') {
901 if (s->nb_esc_params < MAX_ESC_PARAMS) {
5fafdf24 902 s->esc_params[s->nb_esc_params] =
e7f0ad58
FB
903 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
904 }
905 } else {
906 s->nb_esc_params++;
907 if (ch == ';')
908 break;
adb47967
TS
909#ifdef DEBUG_CONSOLE
910 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
911 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
912#endif
e7f0ad58
FB
913 s->state = TTY_STATE_NORM;
914 switch(ch) {
adb47967
TS
915 case 'A':
916 /* move cursor up */
917 if (s->esc_params[0] == 0) {
918 s->esc_params[0] = 1;
919 }
920 s->y -= s->esc_params[0];
921 if (s->y < 0) {
922 s->y = 0;
923 }
924 break;
925 case 'B':
926 /* move cursor down */
927 if (s->esc_params[0] == 0) {
928 s->esc_params[0] = 1;
929 }
930 s->y += s->esc_params[0];
931 if (s->y >= s->height) {
932 s->y = s->height - 1;
933 }
e7f0ad58
FB
934 break;
935 case 'C':
adb47967
TS
936 /* move cursor right */
937 if (s->esc_params[0] == 0) {
938 s->esc_params[0] = 1;
939 }
940 s->x += s->esc_params[0];
941 if (s->x >= s->width) {
942 s->x = s->width - 1;
943 }
e7f0ad58 944 break;
adb47967
TS
945 case 'D':
946 /* move cursor left */
947 if (s->esc_params[0] == 0) {
948 s->esc_params[0] = 1;
949 }
950 s->x -= s->esc_params[0];
951 if (s->x < 0) {
952 s->x = 0;
953 }
954 break;
955 case 'G':
956 /* move cursor to column */
957 s->x = s->esc_params[0] - 1;
958 if (s->x < 0) {
959 s->x = 0;
960 }
961 break;
962 case 'f':
963 case 'H':
964 /* move cursor to row, column */
965 s->x = s->esc_params[1] - 1;
966 if (s->x < 0) {
967 s->x = 0;
968 }
969 s->y = s->esc_params[0] - 1;
970 if (s->y < 0) {
971 s->y = 0;
972 }
973 break;
974 case 'J':
975 switch (s->esc_params[0]) {
976 case 0:
977 /* clear to end of screen */
978 for (y = s->y; y < s->height; y++) {
979 for (x = 0; x < s->width; x++) {
980 if (y == s->y && x < s->x) {
981 continue;
982 }
983 console_clear_xy(s, x, y);
984 }
985 }
986 break;
987 case 1:
988 /* clear from beginning of screen */
989 for (y = 0; y <= s->y; y++) {
990 for (x = 0; x < s->width; x++) {
991 if (y == s->y && x > s->x) {
992 break;
993 }
994 console_clear_xy(s, x, y);
995 }
996 }
997 break;
998 case 2:
999 /* clear entire screen */
1000 for (y = 0; y <= s->height; y++) {
1001 for (x = 0; x < s->width; x++) {
1002 console_clear_xy(s, x, y);
1003 }
1004 }
1005 break;
1006 }
e7f0ad58 1007 case 'K':
adb47967
TS
1008 switch (s->esc_params[0]) {
1009 case 0:
e7f0ad58 1010 /* clear to eol */
e7f0ad58 1011 for(x = s->x; x < s->width; x++) {
adb47967 1012 console_clear_xy(s, x, s->y);
e7f0ad58
FB
1013 }
1014 break;
adb47967
TS
1015 case 1:
1016 /* clear from beginning of line */
1017 for (x = 0; x <= s->x; x++) {
1018 console_clear_xy(s, x, s->y);
1019 }
1020 break;
1021 case 2:
1022 /* clear entire line */
1023 for(x = 0; x < s->width; x++) {
1024 console_clear_xy(s, x, s->y);
1025 }
e7f0ad58
FB
1026 break;
1027 }
adb47967
TS
1028 break;
1029 case 'm':
6d6f7c28 1030 console_handle_escape(s);
e7f0ad58 1031 break;
adb47967
TS
1032 case 'n':
1033 /* report cursor position */
1034 /* TODO: send ESC[row;colR */
1035 break;
1036 case 's':
1037 /* save cursor position */
1038 s->x_saved = s->x;
1039 s->y_saved = s->y;
1040 break;
1041 case 'u':
1042 /* restore cursor position */
1043 s->x = s->x_saved;
1044 s->y = s->y_saved;
1045 break;
1046 default:
1047#ifdef DEBUG_CONSOLE
1048 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1049#endif
1050 break;
1051 }
1052 break;
e7f0ad58
FB
1053 }
1054 }
1055}
1056
1057void console_select(unsigned int index)
1058{
1059 TextConsole *s;
6d6f7c28 1060
e7f0ad58
FB
1061 if (index >= MAX_CONSOLES)
1062 return;
7d957bd8
AL
1063 active_console->g_width = ds_get_width(active_console->ds);
1064 active_console->g_height = ds_get_height(active_console->ds);
e7f0ad58
FB
1065 s = consoles[index];
1066 if (s) {
7d957bd8 1067 DisplayState *ds = s->ds;
e7f0ad58 1068 active_console = s;
68f00996 1069 if (ds_get_bits_per_pixel(s->ds)) {
7b5d76da 1070 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
68f00996
AL
1071 } else {
1072 s->ds->surface->width = s->width;
1073 s->ds->surface->height = s->height;
1074 }
7d957bd8 1075 dpy_resize(s->ds);
4d3b6f6e 1076 vga_hw_invalidate();
e7f0ad58
FB
1077 }
1078}
1079
1080static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1081{
1082 TextConsole *s = chr->opaque;
1083 int i;
1084
14778c20
PB
1085 s->update_x0 = s->width * FONT_WIDTH;
1086 s->update_y0 = s->height * FONT_HEIGHT;
1087 s->update_x1 = 0;
1088 s->update_y1 = 0;
e7f0ad58
FB
1089 console_show_cursor(s, 0);
1090 for(i = 0; i < len; i++) {
1091 console_putchar(s, buf[i]);
1092 }
1093 console_show_cursor(s, 1);
14778c20
PB
1094 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1095 dpy_update(s->ds, s->update_x0, s->update_y0,
1096 s->update_x1 - s->update_x0,
1097 s->update_y1 - s->update_y0);
1098 }
e7f0ad58
FB
1099 return len;
1100}
1101
6fcfafb7
FB
1102static void console_send_event(CharDriverState *chr, int event)
1103{
1104 TextConsole *s = chr->opaque;
1105 int i;
1106
1107 if (event == CHR_EVENT_FOCUS) {
1108 for(i = 0; i < nb_consoles; i++) {
1109 if (consoles[i] == s) {
1110 console_select(i);
1111 break;
1112 }
1113 }
1114 }
1115}
1116
e15d7371
FB
1117static void kbd_send_chars(void *opaque)
1118{
1119 TextConsole *s = opaque;
1120 int len;
1121 uint8_t buf[16];
3b46e624 1122
e5b0bc44 1123 len = qemu_chr_can_read(s->chr);
e15d7371
FB
1124 if (len > s->out_fifo.count)
1125 len = s->out_fifo.count;
1126 if (len > 0) {
1127 if (len > sizeof(buf))
1128 len = sizeof(buf);
1129 qemu_fifo_read(&s->out_fifo, buf, len);
e5b0bc44 1130 qemu_chr_read(s->chr, buf, len);
e15d7371
FB
1131 }
1132 /* characters are pending: we send them a bit later (XXX:
1133 horrible, should change char device API) */
1134 if (s->out_fifo.count > 0) {
1135 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1136 }
1137}
1138
e7f0ad58
FB
1139/* called when an ascii key is pressed */
1140void kbd_put_keysym(int keysym)
1141{
1142 TextConsole *s;
1143 uint8_t buf[16], *q;
1144 int c;
1145
1146 s = active_console;
af3a9031 1147 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
1148 return;
1149
1150 switch(keysym) {
1151 case QEMU_KEY_CTRL_UP:
1152 console_scroll(-1);
1153 break;
1154 case QEMU_KEY_CTRL_DOWN:
1155 console_scroll(1);
1156 break;
1157 case QEMU_KEY_CTRL_PAGEUP:
1158 console_scroll(-10);
1159 break;
1160 case QEMU_KEY_CTRL_PAGEDOWN:
1161 console_scroll(10);
1162 break;
1163 default:
e15d7371
FB
1164 /* convert the QEMU keysym to VT100 key string */
1165 q = buf;
1166 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1167 *q++ = '\033';
1168 *q++ = '[';
1169 c = keysym - 0xe100;
1170 if (c >= 10)
1171 *q++ = '0' + (c / 10);
1172 *q++ = '0' + (c % 10);
1173 *q++ = '~';
1174 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1175 *q++ = '\033';
1176 *q++ = '[';
1177 *q++ = keysym & 0xff;
1178 } else {
e7f0ad58 1179 *q++ = keysym;
e15d7371 1180 }
e5b0bc44 1181 if (s->chr->chr_read) {
e15d7371
FB
1182 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1183 kbd_send_chars(s);
e7f0ad58
FB
1184 }
1185 break;
1186 }
1187}
1188
4d3b6f6e
AZ
1189static void text_console_invalidate(void *opaque)
1190{
1191 TextConsole *s = (TextConsole *) opaque;
68f00996
AL
1192 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1193 s->g_width = ds_get_width(s->ds);
1194 s->g_height = ds_get_height(s->ds);
1195 text_console_resize(s);
1196 }
4d3b6f6e
AZ
1197 console_refresh(s);
1198}
1199
c227f099 1200static void text_console_update(void *opaque, console_ch_t *chardata)
4d3b6f6e
AZ
1201{
1202 TextConsole *s = (TextConsole *) opaque;
1203 int i, j, src;
1204
1205 if (s->text_x[0] <= s->text_x[1]) {
1206 src = (s->y_base + s->text_y[0]) * s->width;
1207 chardata += s->text_y[0] * s->width;
1208 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1209 for (j = 0; j < s->width; j ++, src ++)
1210 console_write_ch(chardata ++, s->cells[src].ch |
1211 (s->cells[src].t_attrib.fgcol << 12) |
1212 (s->cells[src].t_attrib.bgcol << 8) |
1213 (s->cells[src].t_attrib.bold << 21));
1214 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1215 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1216 s->text_x[0] = s->width;
1217 s->text_y[0] = s->height;
1218 s->text_x[1] = 0;
1219 s->text_y[1] = 0;
1220 }
1221 if (s->cursor_invalidate) {
1222 dpy_cursor(s->ds, s->x, s->y);
1223 s->cursor_invalidate = 0;
1224 }
1225}
1226
42aa98e8 1227static TextConsole *get_graphic_console(DisplayState *ds)
a147d62b 1228{
3023f332
AL
1229 int i;
1230 TextConsole *s;
1231 for (i = 0; i < nb_consoles; i++) {
1232 s = consoles[i];
42aa98e8 1233 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
3023f332
AL
1234 return s;
1235 }
1236 return NULL;
1237}
1238
c227f099 1239static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
e7f0ad58
FB
1240{
1241 TextConsole *s;
95219897 1242 int i;
e7f0ad58
FB
1243
1244 if (nb_consoles >= MAX_CONSOLES)
1245 return NULL;
1246 s = qemu_mallocz(sizeof(TextConsole));
af3a9031
TS
1247 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1248 (console_type == GRAPHIC_CONSOLE))) {
e7f0ad58 1249 active_console = s;
af3a9031 1250 }
e7f0ad58 1251 s->ds = ds;
af3a9031
TS
1252 s->console_type = console_type;
1253 if (console_type != GRAPHIC_CONSOLE) {
95219897
PB
1254 consoles[nb_consoles++] = s;
1255 } else {
1256 /* HACK: Put graphical consoles before text consoles. */
1257 for (i = nb_consoles; i > 0; i--) {
af3a9031 1258 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
95219897
PB
1259 break;
1260 consoles[i] = consoles[i - 1];
1261 }
1262 consoles[i] = s;
3023f332 1263 nb_consoles++;
95219897
PB
1264 }
1265 return s;
1266}
1267
3023f332
AL
1268DisplayState *graphic_console_init(vga_hw_update_ptr update,
1269 vga_hw_invalidate_ptr invalidate,
1270 vga_hw_screen_dump_ptr screen_dump,
1271 vga_hw_text_update_ptr text_update,
1272 void *opaque)
95219897
PB
1273{
1274 TextConsole *s;
3023f332 1275 DisplayState *ds;
f0f2f976 1276
3023f332 1277 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
7b5d76da
AL
1278 ds->allocator = &default_allocator;
1279 ds->surface = qemu_create_displaysurface(ds, 640, 480);
95219897 1280
af3a9031 1281 s = new_console(ds, GRAPHIC_CONSOLE);
3023f332 1282 if (s == NULL) {
7b5d76da 1283 qemu_free_displaysurface(ds);
3023f332
AL
1284 qemu_free(ds);
1285 return NULL;
1286 }
95219897
PB
1287 s->hw_update = update;
1288 s->hw_invalidate = invalidate;
1289 s->hw_screen_dump = screen_dump;
4d3b6f6e 1290 s->hw_text_update = text_update;
95219897 1291 s->hw = opaque;
3023f332 1292
f0f2f976 1293 register_displaystate(ds);
3023f332 1294 return ds;
e7f0ad58
FB
1295}
1296
95219897 1297int is_graphic_console(void)
e7f0ad58 1298{
4d3b6f6e 1299 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
e7f0ad58
FB
1300}
1301
c21bbcfa
AZ
1302int is_fixedsize_console(void)
1303{
1304 return active_console && active_console->console_type != TEXT_CONSOLE;
1305}
1306
a528b80c
AZ
1307void console_color_init(DisplayState *ds)
1308{
1309 int i, j;
1310 for (j = 0; j < 2; j++) {
1311 for (i = 0; i < 8; i++) {
f0f2f976 1312 color_table[j][i] = col_expand(ds,
a528b80c
AZ
1313 vga_get_color(ds, color_table_rgb[j][i]));
1314 }
1315 }
1316}
1317
2796dae0
AL
1318static int n_text_consoles;
1319static CharDriverState *text_consoles[128];
6ea314d9 1320static QemuOpts *text_console_opts[128];
2796dae0 1321
6ea314d9 1322static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
e7f0ad58 1323{
e7f0ad58 1324 TextConsole *s;
af3a9031
TS
1325 unsigned width;
1326 unsigned height;
e7f0ad58 1327 static int color_inited;
6d6f7c28 1328
6ea314d9
GH
1329 width = qemu_opt_get_number(opts, "width", 0);
1330 if (width == 0)
1331 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1332
1333 height = qemu_opt_get_number(opts, "height", 0);
1334 if (height == 0)
1335 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1336
1337 if (width == 0 || height == 0) {
1338 s = new_console(ds, TEXT_CONSOLE);
1339 width = ds_get_width(s->ds);
1340 height = ds_get_height(s->ds);
1341 } else {
1342 s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1343 }
1344
e7f0ad58
FB
1345 if (!s) {
1346 free(chr);
fdb868e4 1347 return;
e7f0ad58 1348 }
e7f0ad58
FB
1349 chr->opaque = s;
1350 chr->chr_write = console_puts;
6fcfafb7
FB
1351 chr->chr_send_event = console_send_event;
1352
e5b0bc44 1353 s->chr = chr;
e15d7371
FB
1354 s->out_fifo.buf = s->out_fifo_buf;
1355 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1356 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
3023f332 1357 s->ds = ds;
3b46e624 1358
e7f0ad58
FB
1359 if (!color_inited) {
1360 color_inited = 1;
a528b80c 1361 console_color_init(s->ds);
e7f0ad58
FB
1362 }
1363 s->y_displayed = 0;
1364 s->y_base = 0;
1365 s->total_height = DEFAULT_BACKSCROLL;
1366 s->x = 0;
1367 s->y = 0;
af3a9031
TS
1368 s->g_width = width;
1369 s->g_height = height;
6d6f7c28 1370
4d3b6f6e
AZ
1371 s->hw_invalidate = text_console_invalidate;
1372 s->hw_text_update = text_console_update;
1373 s->hw = s;
1374
6d6f7c28
PB
1375 /* Set text attribute defaults */
1376 s->t_attrib_default.bold = 0;
1377 s->t_attrib_default.uline = 0;
1378 s->t_attrib_default.blink = 0;
1379 s->t_attrib_default.invers = 0;
1380 s->t_attrib_default.unvisible = 0;
1381 s->t_attrib_default.fgcol = COLOR_WHITE;
1382 s->t_attrib_default.bgcol = COLOR_BLACK;
6d6f7c28
PB
1383 /* set current text attributes to default */
1384 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1385 text_console_resize(s);
1386
25d82d33
GH
1387 if (chr->label) {
1388 char msg[128];
1389 int len;
1390
6ac733bf 1391 s->t_attrib.bgcol = COLOR_BLUE;
25d82d33
GH
1392 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1393 console_puts(chr, (uint8_t*)msg, len);
6ac733bf 1394 s->t_attrib = s->t_attrib_default;
25d82d33
GH
1395 }
1396
127338e6 1397 qemu_chr_generic_open(chr);
ceecf1d1
AJ
1398 if (chr->init)
1399 chr->init(chr);
e7f0ad58 1400}
c60e08d9 1401
6ea314d9 1402CharDriverState *text_console_init(QemuOpts *opts)
2796dae0
AL
1403{
1404 CharDriverState *chr;
1405
1406 chr = qemu_mallocz(sizeof(CharDriverState));
2796dae0
AL
1407
1408 if (n_text_consoles == 128) {
1409 fprintf(stderr, "Too many text consoles\n");
1410 exit(1);
1411 }
1412 text_consoles[n_text_consoles] = chr;
6ea314d9 1413 text_console_opts[n_text_consoles] = opts;
2796dae0
AL
1414 n_text_consoles++;
1415
1416 return chr;
1417}
1418
1419void text_consoles_set_display(DisplayState *ds)
1420{
1421 int i;
1422
1423 for (i = 0; i < n_text_consoles; i++) {
6ea314d9
GH
1424 text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1425 qemu_opts_del(text_console_opts[i]);
1426 text_console_opts[i] = NULL;
2796dae0
AL
1427 }
1428
1429 n_text_consoles = 0;
1430}
1431
3023f332 1432void qemu_console_resize(DisplayState *ds, int width, int height)
c60e08d9 1433{
42aa98e8 1434 TextConsole *s = get_graphic_console(ds);
f497f140
AL
1435 if (!s) return;
1436
3023f332
AL
1437 s->g_width = width;
1438 s->g_height = height;
1439 if (is_graphic_console()) {
7b5d76da 1440 ds->surface = qemu_resize_displaysurface(ds, width, height);
3023f332 1441 dpy_resize(ds);
c60e08d9
PB
1442 }
1443}
38334f76 1444
3023f332
AL
1445void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1446 int dst_x, int dst_y, int w, int h)
c21bbcfa 1447{
3023f332
AL
1448 if (is_graphic_console()) {
1449 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
38334f76
AZ
1450 }
1451}
7d957bd8 1452
0da2ea1b 1453PixelFormat qemu_different_endianness_pixelformat(int bpp)
7d957bd8
AL
1454{
1455 PixelFormat pf;
1456
1457 memset(&pf, 0x00, sizeof(PixelFormat));
1458
1459 pf.bits_per_pixel = bpp;
1460 pf.bytes_per_pixel = bpp / 8;
1461 pf.depth = bpp == 32 ? 24 : bpp;
1462
1463 switch (bpp) {
0da2ea1b 1464 case 24:
1465 pf.rmask = 0x000000FF;
1466 pf.gmask = 0x0000FF00;
1467 pf.bmask = 0x00FF0000;
1468 pf.rmax = 255;
1469 pf.gmax = 255;
1470 pf.bmax = 255;
1471 pf.rshift = 0;
1472 pf.gshift = 8;
1473 pf.bshift = 16;
90a1e3c0
AL
1474 pf.rbits = 8;
1475 pf.gbits = 8;
1476 pf.bbits = 8;
7d957bd8 1477 break;
0da2ea1b 1478 case 32:
1479 pf.rmask = 0x0000FF00;
1480 pf.gmask = 0x00FF0000;
1481 pf.bmask = 0xFF000000;
1482 pf.amask = 0x00000000;
1483 pf.amax = 255;
1484 pf.rmax = 255;
1485 pf.gmax = 255;
1486 pf.bmax = 255;
1487 pf.ashift = 0;
1488 pf.rshift = 8;
1489 pf.gshift = 16;
1490 pf.bshift = 24;
90a1e3c0
AL
1491 pf.rbits = 8;
1492 pf.gbits = 8;
1493 pf.bbits = 8;
1494 pf.abits = 8;
0da2ea1b 1495 break;
1496 default:
1497 break;
1498 }
1499 return pf;
1500}
1501
1502PixelFormat qemu_default_pixelformat(int bpp)
1503{
1504 PixelFormat pf;
1505
1506 memset(&pf, 0x00, sizeof(PixelFormat));
1507
1508 pf.bits_per_pixel = bpp;
1509 pf.bytes_per_pixel = bpp / 8;
1510 pf.depth = bpp == 32 ? 24 : bpp;
1511
1512 switch (bpp) {
7d957bd8
AL
1513 case 16:
1514 pf.rmask = 0x0000F800;
1515 pf.gmask = 0x000007E0;
1516 pf.bmask = 0x0000001F;
1517 pf.rmax = 31;
1518 pf.gmax = 63;
1519 pf.bmax = 31;
1520 pf.rshift = 11;
1521 pf.gshift = 5;
1522 pf.bshift = 0;
90a1e3c0
AL
1523 pf.rbits = 5;
1524 pf.gbits = 6;
1525 pf.bbits = 5;
7d957bd8
AL
1526 break;
1527 case 24:
0da2ea1b 1528 pf.rmask = 0x00FF0000;
1529 pf.gmask = 0x0000FF00;
1530 pf.bmask = 0x000000FF;
1531 pf.rmax = 255;
1532 pf.gmax = 255;
1533 pf.bmax = 255;
1534 pf.rshift = 16;
1535 pf.gshift = 8;
1536 pf.bshift = 0;
90a1e3c0
AL
1537 pf.rbits = 8;
1538 pf.gbits = 8;
1539 pf.bbits = 8;
7d957bd8
AL
1540 case 32:
1541 pf.rmask = 0x00FF0000;
1542 pf.gmask = 0x0000FF00;
1543 pf.bmask = 0x000000FF;
0da2ea1b 1544 pf.amax = 255;
7d957bd8
AL
1545 pf.rmax = 255;
1546 pf.gmax = 255;
1547 pf.bmax = 255;
0da2ea1b 1548 pf.ashift = 24;
7d957bd8
AL
1549 pf.rshift = 16;
1550 pf.gshift = 8;
1551 pf.bshift = 0;
90a1e3c0
AL
1552 pf.rbits = 8;
1553 pf.gbits = 8;
1554 pf.bbits = 8;
1555 pf.abits = 8;
7d957bd8
AL
1556 break;
1557 default:
1558 break;
1559 }
1560 return pf;
1561}
1562
7b5d76da 1563DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
7d957bd8
AL
1564{
1565 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
7d957bd8
AL
1566
1567 surface->width = width;
1568 surface->height = height;
7b5d76da
AL
1569 surface->linesize = width * 4;
1570 surface->pf = qemu_default_pixelformat(32);
e2542fe2 1571#ifdef HOST_WORDS_BIGENDIAN
7d957bd8
AL
1572 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1573#else
1574 surface->flags = QEMU_ALLOCATED_FLAG;
1575#endif
1576 surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
7d957bd8
AL
1577
1578 return surface;
1579}
1580
7b5d76da
AL
1581DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1582 int width, int height)
7d957bd8
AL
1583{
1584 surface->width = width;
1585 surface->height = height;
7b5d76da
AL
1586 surface->linesize = width * 4;
1587 surface->pf = qemu_default_pixelformat(32);
7d957bd8
AL
1588 if (surface->flags & QEMU_ALLOCATED_FLAG)
1589 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1590 else
1591 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
e2542fe2 1592#ifdef HOST_WORDS_BIGENDIAN
7d957bd8
AL
1593 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1594#else
1595 surface->flags = QEMU_ALLOCATED_FLAG;
1596#endif
1597
1598 return surface;
1599}
1600
1601DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1602 int linesize, uint8_t *data)
1603{
1604 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
7d957bd8
AL
1605
1606 surface->width = width;
1607 surface->height = height;
1608 surface->linesize = linesize;
1609 surface->pf = qemu_default_pixelformat(bpp);
e2542fe2 1610#ifdef HOST_WORDS_BIGENDIAN
7d957bd8
AL
1611 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1612#endif
1613 surface->data = data;
1614
1615 return surface;
1616}
1617
7b5d76da 1618void defaultallocator_free_displaysurface(DisplaySurface *surface)
7d957bd8
AL
1619{
1620 if (surface == NULL)
1621 return;
1622 if (surface->flags & QEMU_ALLOCATED_FLAG)
1623 qemu_free(surface->data);
1624 qemu_free(surface);
1625}