open -> new rename fallout
[qemu/aliguori.git] / console.c
blob8fcc7cbcd018be320da1adec7cd1a9b3f04943b9
1 /*
2 * QEMU graphical console
4 * Copyright (c) 2004 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
24 #include "qemu-common.h"
25 #include "console.h"
26 #include "qemu-timer.h"
28 //#define DEBUG_CONSOLE
29 #define DEFAULT_BACKSCROLL 512
30 #define MAX_CONSOLES 12
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)
35 typedef 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;
45 typedef struct TextCell {
46 uint8_t ch;
47 TextAttributes t_attrib;
48 } TextCell;
50 #define MAX_ESC_PARAMS 3
52 enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
58 typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62 } QEMUFIFO;
64 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
66 int l, len;
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;
83 f->count += len1;
84 return len1;
87 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
89 int l, len;
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;
105 f->count -= len1;
106 return len1;
109 typedef enum {
110 GRAPHIC_CONSOLE,
111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
113 } console_type_t;
115 /* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
117 struct TextConsole {
118 console_type_t console_type;
119 DisplayState *ds;
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;
124 vga_hw_text_update_ptr hw_text_update;
125 void *hw;
127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
132 int x, y;
133 int x_saved, y_saved;
134 int y_displayed;
135 int y_base;
136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
138 TextCell *cells;
139 int text_x[2], text_y[2], cursor_invalidate;
140 int echo;
142 int update_x0;
143 int update_y0;
144 int update_x1;
145 int update_y1;
147 enum TTYState state;
148 int esc_params[MAX_ESC_PARAMS];
149 int nb_esc_params;
151 CharDriverState *chr;
152 /* fifo for key pressed */
153 QEMUFIFO out_fifo;
154 uint8_t out_fifo_buf[16];
155 QEMUTimer *kbd_timer;
158 static DisplayState *display_state;
159 static TextConsole *active_console;
160 static TextConsole *consoles[MAX_CONSOLES];
161 static int nb_consoles = 0;
163 void vga_hw_update(void)
165 if (active_console && active_console->hw_update)
166 active_console->hw_update(active_console->hw);
169 void vga_hw_invalidate(void)
171 if (active_console && active_console->hw_invalidate)
172 active_console->hw_invalidate(active_console->hw);
175 void vga_hw_screen_dump(const char *filename)
177 TextConsole *previous_active_console;
179 previous_active_console = active_console;
180 active_console = consoles[0];
181 /* There is currently no way of specifying which screen we want to dump,
182 so always dump the first one. */
183 if (consoles[0] && consoles[0]->hw_screen_dump)
184 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
185 active_console = previous_active_console;
188 void vga_hw_text_update(console_ch_t *chardata)
190 if (active_console && active_console->hw_text_update)
191 active_console->hw_text_update(active_console->hw, chardata);
194 /* convert a RGBA color to a color index usable in graphic primitives */
195 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
197 unsigned int r, g, b, color;
199 switch(ds_get_bits_per_pixel(ds)) {
200 #if 0
201 case 8:
202 r = (rgba >> 16) & 0xff;
203 g = (rgba >> 8) & 0xff;
204 b = (rgba) & 0xff;
205 color = (rgb_to_index[r] * 6 * 6) +
206 (rgb_to_index[g] * 6) +
207 (rgb_to_index[b]);
208 break;
209 #endif
210 case 15:
211 r = (rgba >> 16) & 0xff;
212 g = (rgba >> 8) & 0xff;
213 b = (rgba) & 0xff;
214 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
215 break;
216 case 16:
217 r = (rgba >> 16) & 0xff;
218 g = (rgba >> 8) & 0xff;
219 b = (rgba) & 0xff;
220 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
221 break;
222 case 32:
223 default:
224 color = rgba;
225 break;
227 return color;
230 static void vga_fill_rect (DisplayState *ds,
231 int posx, int posy, int width, int height, uint32_t color)
233 uint8_t *d, *d1;
234 int x, y, bpp;
236 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
237 d1 = ds_get_data(ds) +
238 ds_get_linesize(ds) * posy + bpp * posx;
239 for (y = 0; y < height; y++) {
240 d = d1;
241 switch(bpp) {
242 case 1:
243 for (x = 0; x < width; x++) {
244 *((uint8_t *)d) = color;
245 d++;
247 break;
248 case 2:
249 for (x = 0; x < width; x++) {
250 *((uint16_t *)d) = color;
251 d += 2;
253 break;
254 case 4:
255 for (x = 0; x < width; x++) {
256 *((uint32_t *)d) = color;
257 d += 4;
259 break;
261 d1 += ds_get_linesize(ds);
265 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
266 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
268 const uint8_t *s;
269 uint8_t *d;
270 int wb, y, bpp;
272 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
273 wb = w * bpp;
274 if (yd <= ys) {
275 s = ds_get_data(ds) +
276 ds_get_linesize(ds) * ys + bpp * xs;
277 d = ds_get_data(ds) +
278 ds_get_linesize(ds) * yd + bpp * xd;
279 for (y = 0; y < h; y++) {
280 memmove(d, s, wb);
281 d += ds_get_linesize(ds);
282 s += ds_get_linesize(ds);
284 } else {
285 s = ds_get_data(ds) +
286 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
287 d = ds_get_data(ds) +
288 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
289 for (y = 0; y < h; y++) {
290 memmove(d, s, wb);
291 d -= ds_get_linesize(ds);
292 s -= ds_get_linesize(ds);
297 /***********************************************************/
298 /* basic char display */
300 #define FONT_HEIGHT 16
301 #define FONT_WIDTH 8
303 #include "vgafont.h"
305 #define cbswap_32(__x) \
306 ((uint32_t)( \
307 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
308 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
309 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
310 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
312 #ifdef HOST_WORDS_BIGENDIAN
313 #define PAT(x) x
314 #else
315 #define PAT(x) cbswap_32(x)
316 #endif
318 static const uint32_t dmask16[16] = {
319 PAT(0x00000000),
320 PAT(0x000000ff),
321 PAT(0x0000ff00),
322 PAT(0x0000ffff),
323 PAT(0x00ff0000),
324 PAT(0x00ff00ff),
325 PAT(0x00ffff00),
326 PAT(0x00ffffff),
327 PAT(0xff000000),
328 PAT(0xff0000ff),
329 PAT(0xff00ff00),
330 PAT(0xff00ffff),
331 PAT(0xffff0000),
332 PAT(0xffff00ff),
333 PAT(0xffffff00),
334 PAT(0xffffffff),
337 static const uint32_t dmask4[4] = {
338 PAT(0x00000000),
339 PAT(0x0000ffff),
340 PAT(0xffff0000),
341 PAT(0xffffffff),
344 static uint32_t color_table[2][8];
346 enum color_names {
347 COLOR_BLACK = 0,
348 COLOR_RED = 1,
349 COLOR_GREEN = 2,
350 COLOR_YELLOW = 3,
351 COLOR_BLUE = 4,
352 COLOR_MAGENTA = 5,
353 COLOR_CYAN = 6,
354 COLOR_WHITE = 7
357 static const uint32_t color_table_rgb[2][8] = {
358 { /* dark */
359 QEMU_RGB(0x00, 0x00, 0x00), /* black */
360 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
361 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
362 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
363 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
364 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
365 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
366 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
368 { /* bright */
369 QEMU_RGB(0x00, 0x00, 0x00), /* black */
370 QEMU_RGB(0xff, 0x00, 0x00), /* red */
371 QEMU_RGB(0x00, 0xff, 0x00), /* green */
372 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
373 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
374 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
375 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
376 QEMU_RGB(0xff, 0xff, 0xff), /* white */
380 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
382 switch(ds_get_bits_per_pixel(ds)) {
383 case 8:
384 col |= col << 8;
385 col |= col << 16;
386 break;
387 case 15:
388 case 16:
389 col |= col << 16;
390 break;
391 default:
392 break;
395 return col;
397 #ifdef DEBUG_CONSOLE
398 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
400 if (t_attrib->bold) {
401 printf("b");
402 } else {
403 printf(" ");
405 if (t_attrib->uline) {
406 printf("u");
407 } else {
408 printf(" ");
410 if (t_attrib->blink) {
411 printf("l");
412 } else {
413 printf(" ");
415 if (t_attrib->invers) {
416 printf("i");
417 } else {
418 printf(" ");
420 if (t_attrib->unvisible) {
421 printf("n");
422 } else {
423 printf(" ");
426 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
428 #endif
430 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
431 TextAttributes *t_attrib)
433 uint8_t *d;
434 const uint8_t *font_ptr;
435 unsigned int font_data, linesize, xorcol, bpp;
436 int i;
437 unsigned int fgcol, bgcol;
439 #ifdef DEBUG_CONSOLE
440 printf("x: %2i y: %2i", x, y);
441 console_print_text_attributes(t_attrib, ch);
442 #endif
444 if (t_attrib->invers) {
445 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
446 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
447 } else {
448 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
449 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
452 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
453 d = ds_get_data(ds) +
454 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
455 linesize = ds_get_linesize(ds);
456 font_ptr = vgafont16 + FONT_HEIGHT * ch;
457 xorcol = bgcol ^ fgcol;
458 switch(ds_get_bits_per_pixel(ds)) {
459 case 8:
460 for(i = 0; i < FONT_HEIGHT; i++) {
461 font_data = *font_ptr++;
462 if (t_attrib->uline
463 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
464 font_data = 0xFFFF;
466 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
467 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
468 d += linesize;
470 break;
471 case 16:
472 case 15:
473 for(i = 0; i < FONT_HEIGHT; i++) {
474 font_data = *font_ptr++;
475 if (t_attrib->uline
476 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
477 font_data = 0xFFFF;
479 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
480 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
482 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
483 d += linesize;
485 break;
486 case 32:
487 for(i = 0; i < FONT_HEIGHT; i++) {
488 font_data = *font_ptr++;
489 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
490 font_data = 0xFFFF;
492 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
493 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
494 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
495 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
496 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
497 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
498 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
499 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
500 d += linesize;
502 break;
506 static void text_console_resize(TextConsole *s)
508 TextCell *cells, *c, *c1;
509 int w1, x, y, last_width;
511 last_width = s->width;
512 s->width = s->g_width / FONT_WIDTH;
513 s->height = s->g_height / FONT_HEIGHT;
515 w1 = last_width;
516 if (s->width < w1)
517 w1 = s->width;
519 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
520 for(y = 0; y < s->total_height; y++) {
521 c = &cells[y * s->width];
522 if (w1 > 0) {
523 c1 = &s->cells[y * last_width];
524 for(x = 0; x < w1; x++) {
525 *c++ = *c1++;
528 for(x = w1; x < s->width; x++) {
529 c->ch = ' ';
530 c->t_attrib = s->t_attrib_default;
531 c++;
534 qemu_free(s->cells);
535 s->cells = cells;
538 static inline void text_update_xy(TextConsole *s, int x, int y)
540 s->text_x[0] = MIN(s->text_x[0], x);
541 s->text_x[1] = MAX(s->text_x[1], x);
542 s->text_y[0] = MIN(s->text_y[0], y);
543 s->text_y[1] = MAX(s->text_y[1], y);
546 static void invalidate_xy(TextConsole *s, int x, int y)
548 if (s->update_x0 > x * FONT_WIDTH)
549 s->update_x0 = x * FONT_WIDTH;
550 if (s->update_y0 > y * FONT_HEIGHT)
551 s->update_y0 = y * FONT_HEIGHT;
552 if (s->update_x1 < (x + 1) * FONT_WIDTH)
553 s->update_x1 = (x + 1) * FONT_WIDTH;
554 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
555 s->update_y1 = (y + 1) * FONT_HEIGHT;
558 static void update_xy(TextConsole *s, int x, int y)
560 TextCell *c;
561 int y1, y2;
563 if (s == active_console) {
564 if (!ds_get_bits_per_pixel(s->ds)) {
565 text_update_xy(s, x, y);
566 return;
569 y1 = (s->y_base + y) % s->total_height;
570 y2 = y1 - s->y_displayed;
571 if (y2 < 0)
572 y2 += s->total_height;
573 if (y2 < s->height) {
574 c = &s->cells[y1 * s->width + x];
575 vga_putcharxy(s->ds, x, y2, c->ch,
576 &(c->t_attrib));
577 invalidate_xy(s, x, y2);
582 static void console_show_cursor(TextConsole *s, int show)
584 TextCell *c;
585 int y, y1;
587 if (s == active_console) {
588 int x = s->x;
590 if (!ds_get_bits_per_pixel(s->ds)) {
591 s->cursor_invalidate = 1;
592 return;
595 if (x >= s->width) {
596 x = s->width - 1;
598 y1 = (s->y_base + s->y) % s->total_height;
599 y = y1 - s->y_displayed;
600 if (y < 0)
601 y += s->total_height;
602 if (y < s->height) {
603 c = &s->cells[y1 * s->width + x];
604 if (show) {
605 TextAttributes t_attrib = s->t_attrib_default;
606 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
607 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
608 } else {
609 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
611 invalidate_xy(s, x, y);
616 static void console_refresh(TextConsole *s)
618 TextCell *c;
619 int x, y, y1;
621 if (s != active_console)
622 return;
623 if (!ds_get_bits_per_pixel(s->ds)) {
624 s->text_x[0] = 0;
625 s->text_y[0] = 0;
626 s->text_x[1] = s->width - 1;
627 s->text_y[1] = s->height - 1;
628 s->cursor_invalidate = 1;
629 return;
632 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
633 color_table[0][COLOR_BLACK]);
634 y1 = s->y_displayed;
635 for(y = 0; y < s->height; y++) {
636 c = s->cells + y1 * s->width;
637 for(x = 0; x < s->width; x++) {
638 vga_putcharxy(s->ds, x, y, c->ch,
639 &(c->t_attrib));
640 c++;
642 if (++y1 == s->total_height)
643 y1 = 0;
645 console_show_cursor(s, 1);
646 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
649 static void console_scroll(int ydelta)
651 TextConsole *s;
652 int i, y1;
654 s = active_console;
655 if (!s || (s->console_type == GRAPHIC_CONSOLE))
656 return;
658 if (ydelta > 0) {
659 for(i = 0; i < ydelta; i++) {
660 if (s->y_displayed == s->y_base)
661 break;
662 if (++s->y_displayed == s->total_height)
663 s->y_displayed = 0;
665 } else {
666 ydelta = -ydelta;
667 i = s->backscroll_height;
668 if (i > s->total_height - s->height)
669 i = s->total_height - s->height;
670 y1 = s->y_base - i;
671 if (y1 < 0)
672 y1 += s->total_height;
673 for(i = 0; i < ydelta; i++) {
674 if (s->y_displayed == y1)
675 break;
676 if (--s->y_displayed < 0)
677 s->y_displayed = s->total_height - 1;
680 console_refresh(s);
683 static void console_put_lf(TextConsole *s)
685 TextCell *c;
686 int x, y1;
688 s->y++;
689 if (s->y >= s->height) {
690 s->y = s->height - 1;
692 if (s->y_displayed == s->y_base) {
693 if (++s->y_displayed == s->total_height)
694 s->y_displayed = 0;
696 if (++s->y_base == s->total_height)
697 s->y_base = 0;
698 if (s->backscroll_height < s->total_height)
699 s->backscroll_height++;
700 y1 = (s->y_base + s->height - 1) % s->total_height;
701 c = &s->cells[y1 * s->width];
702 for(x = 0; x < s->width; x++) {
703 c->ch = ' ';
704 c->t_attrib = s->t_attrib_default;
705 c++;
707 if (s == active_console && s->y_displayed == s->y_base) {
708 if (!ds_get_bits_per_pixel(s->ds)) {
709 s->text_x[0] = 0;
710 s->text_y[0] = 0;
711 s->text_x[1] = s->width - 1;
712 s->text_y[1] = s->height - 1;
713 return;
716 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
717 s->width * FONT_WIDTH,
718 (s->height - 1) * FONT_HEIGHT);
719 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
720 s->width * FONT_WIDTH, FONT_HEIGHT,
721 color_table[0][s->t_attrib_default.bgcol]);
722 s->update_x0 = 0;
723 s->update_y0 = 0;
724 s->update_x1 = s->width * FONT_WIDTH;
725 s->update_y1 = s->height * FONT_HEIGHT;
730 /* Set console attributes depending on the current escape codes.
731 * NOTE: I know this code is not very efficient (checking every color for it
732 * self) but it is more readable and better maintainable.
734 static void console_handle_escape(TextConsole *s)
736 int i;
738 for (i=0; i<s->nb_esc_params; i++) {
739 switch (s->esc_params[i]) {
740 case 0: /* reset all console attributes to default */
741 s->t_attrib = s->t_attrib_default;
742 break;
743 case 1:
744 s->t_attrib.bold = 1;
745 break;
746 case 4:
747 s->t_attrib.uline = 1;
748 break;
749 case 5:
750 s->t_attrib.blink = 1;
751 break;
752 case 7:
753 s->t_attrib.invers = 1;
754 break;
755 case 8:
756 s->t_attrib.unvisible = 1;
757 break;
758 case 22:
759 s->t_attrib.bold = 0;
760 break;
761 case 24:
762 s->t_attrib.uline = 0;
763 break;
764 case 25:
765 s->t_attrib.blink = 0;
766 break;
767 case 27:
768 s->t_attrib.invers = 0;
769 break;
770 case 28:
771 s->t_attrib.unvisible = 0;
772 break;
773 /* set foreground color */
774 case 30:
775 s->t_attrib.fgcol=COLOR_BLACK;
776 break;
777 case 31:
778 s->t_attrib.fgcol=COLOR_RED;
779 break;
780 case 32:
781 s->t_attrib.fgcol=COLOR_GREEN;
782 break;
783 case 33:
784 s->t_attrib.fgcol=COLOR_YELLOW;
785 break;
786 case 34:
787 s->t_attrib.fgcol=COLOR_BLUE;
788 break;
789 case 35:
790 s->t_attrib.fgcol=COLOR_MAGENTA;
791 break;
792 case 36:
793 s->t_attrib.fgcol=COLOR_CYAN;
794 break;
795 case 37:
796 s->t_attrib.fgcol=COLOR_WHITE;
797 break;
798 /* set background color */
799 case 40:
800 s->t_attrib.bgcol=COLOR_BLACK;
801 break;
802 case 41:
803 s->t_attrib.bgcol=COLOR_RED;
804 break;
805 case 42:
806 s->t_attrib.bgcol=COLOR_GREEN;
807 break;
808 case 43:
809 s->t_attrib.bgcol=COLOR_YELLOW;
810 break;
811 case 44:
812 s->t_attrib.bgcol=COLOR_BLUE;
813 break;
814 case 45:
815 s->t_attrib.bgcol=COLOR_MAGENTA;
816 break;
817 case 46:
818 s->t_attrib.bgcol=COLOR_CYAN;
819 break;
820 case 47:
821 s->t_attrib.bgcol=COLOR_WHITE;
822 break;
827 static void console_clear_xy(TextConsole *s, int x, int y)
829 int y1 = (s->y_base + y) % s->total_height;
830 TextCell *c = &s->cells[y1 * s->width + x];
831 c->ch = ' ';
832 c->t_attrib = s->t_attrib_default;
833 update_xy(s, x, y);
836 static void console_putchar(TextConsole *s, int ch)
838 TextCell *c;
839 int y1, i;
840 int x, y;
842 switch(s->state) {
843 case TTY_STATE_NORM:
844 switch(ch) {
845 case '\r': /* carriage return */
846 s->x = 0;
847 break;
848 case '\n': /* newline */
849 console_put_lf(s);
850 break;
851 case '\b': /* backspace */
852 if (s->x > 0)
853 s->x--;
854 break;
855 case '\t': /* tabspace */
856 if (s->x + (8 - (s->x % 8)) > s->width) {
857 s->x = 0;
858 console_put_lf(s);
859 } else {
860 s->x = s->x + (8 - (s->x % 8));
862 break;
863 case '\a': /* alert aka. bell */
864 /* TODO: has to be implemented */
865 break;
866 case 14:
867 /* SI (shift in), character set 0 (ignored) */
868 break;
869 case 15:
870 /* SO (shift out), character set 1 (ignored) */
871 break;
872 case 27: /* esc (introducing an escape sequence) */
873 s->state = TTY_STATE_ESC;
874 break;
875 default:
876 if (s->x >= s->width) {
877 /* line wrap */
878 s->x = 0;
879 console_put_lf(s);
881 y1 = (s->y_base + s->y) % s->total_height;
882 c = &s->cells[y1 * s->width + s->x];
883 c->ch = ch;
884 c->t_attrib = s->t_attrib;
885 update_xy(s, s->x, s->y);
886 s->x++;
887 break;
889 break;
890 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
891 if (ch == '[') {
892 for(i=0;i<MAX_ESC_PARAMS;i++)
893 s->esc_params[i] = 0;
894 s->nb_esc_params = 0;
895 s->state = TTY_STATE_CSI;
896 } else {
897 s->state = TTY_STATE_NORM;
899 break;
900 case TTY_STATE_CSI: /* handle escape sequence parameters */
901 if (ch >= '0' && ch <= '9') {
902 if (s->nb_esc_params < MAX_ESC_PARAMS) {
903 s->esc_params[s->nb_esc_params] =
904 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
906 } else {
907 s->nb_esc_params++;
908 if (ch == ';')
909 break;
910 #ifdef DEBUG_CONSOLE
911 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
912 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
913 #endif
914 s->state = TTY_STATE_NORM;
915 switch(ch) {
916 case 'A':
917 /* move cursor up */
918 if (s->esc_params[0] == 0) {
919 s->esc_params[0] = 1;
921 s->y -= s->esc_params[0];
922 if (s->y < 0) {
923 s->y = 0;
925 break;
926 case 'B':
927 /* move cursor down */
928 if (s->esc_params[0] == 0) {
929 s->esc_params[0] = 1;
931 s->y += s->esc_params[0];
932 if (s->y >= s->height) {
933 s->y = s->height - 1;
935 break;
936 case 'C':
937 /* move cursor right */
938 if (s->esc_params[0] == 0) {
939 s->esc_params[0] = 1;
941 s->x += s->esc_params[0];
942 if (s->x >= s->width) {
943 s->x = s->width - 1;
945 break;
946 case 'D':
947 /* move cursor left */
948 if (s->esc_params[0] == 0) {
949 s->esc_params[0] = 1;
951 s->x -= s->esc_params[0];
952 if (s->x < 0) {
953 s->x = 0;
955 break;
956 case 'G':
957 /* move cursor to column */
958 s->x = s->esc_params[0] - 1;
959 if (s->x < 0) {
960 s->x = 0;
962 break;
963 case 'f':
964 case 'H':
965 /* move cursor to row, column */
966 s->x = s->esc_params[1] - 1;
967 if (s->x < 0) {
968 s->x = 0;
970 s->y = s->esc_params[0] - 1;
971 if (s->y < 0) {
972 s->y = 0;
974 break;
975 case 'J':
976 switch (s->esc_params[0]) {
977 case 0:
978 /* clear to end of screen */
979 for (y = s->y; y < s->height; y++) {
980 for (x = 0; x < s->width; x++) {
981 if (y == s->y && x < s->x) {
982 continue;
984 console_clear_xy(s, x, y);
987 break;
988 case 1:
989 /* clear from beginning of screen */
990 for (y = 0; y <= s->y; y++) {
991 for (x = 0; x < s->width; x++) {
992 if (y == s->y && x > s->x) {
993 break;
995 console_clear_xy(s, x, y);
998 break;
999 case 2:
1000 /* clear entire screen */
1001 for (y = 0; y <= s->height; y++) {
1002 for (x = 0; x < s->width; x++) {
1003 console_clear_xy(s, x, y);
1006 break;
1008 case 'K':
1009 switch (s->esc_params[0]) {
1010 case 0:
1011 /* clear to eol */
1012 for(x = s->x; x < s->width; x++) {
1013 console_clear_xy(s, x, s->y);
1015 break;
1016 case 1:
1017 /* clear from beginning of line */
1018 for (x = 0; x <= s->x; x++) {
1019 console_clear_xy(s, x, s->y);
1021 break;
1022 case 2:
1023 /* clear entire line */
1024 for(x = 0; x < s->width; x++) {
1025 console_clear_xy(s, x, s->y);
1027 break;
1029 break;
1030 case 'm':
1031 console_handle_escape(s);
1032 break;
1033 case 'n':
1034 /* report cursor position */
1035 /* TODO: send ESC[row;colR */
1036 break;
1037 case 's':
1038 /* save cursor position */
1039 s->x_saved = s->x;
1040 s->y_saved = s->y;
1041 break;
1042 case 'u':
1043 /* restore cursor position */
1044 s->x = s->x_saved;
1045 s->y = s->y_saved;
1046 break;
1047 default:
1048 #ifdef DEBUG_CONSOLE
1049 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1050 #endif
1051 break;
1053 break;
1058 void console_select(unsigned int index)
1060 TextConsole *s;
1062 if (index >= MAX_CONSOLES)
1063 return;
1064 if (active_console) {
1065 active_console->g_width = ds_get_width(active_console->ds);
1066 active_console->g_height = ds_get_height(active_console->ds);
1068 s = consoles[index];
1069 if (s) {
1070 DisplayState *ds = s->ds;
1071 active_console = s;
1072 if (ds_get_bits_per_pixel(s->ds)) {
1073 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1074 } else {
1075 s->ds->surface->width = s->width;
1076 s->ds->surface->height = s->height;
1078 dpy_resize(s->ds);
1079 vga_hw_invalidate();
1083 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1085 TextConsole *s = chr->opaque;
1086 int i;
1088 s->update_x0 = s->width * FONT_WIDTH;
1089 s->update_y0 = s->height * FONT_HEIGHT;
1090 s->update_x1 = 0;
1091 s->update_y1 = 0;
1092 console_show_cursor(s, 0);
1093 for(i = 0; i < len; i++) {
1094 console_putchar(s, buf[i]);
1096 console_show_cursor(s, 1);
1097 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1098 dpy_update(s->ds, s->update_x0, s->update_y0,
1099 s->update_x1 - s->update_x0,
1100 s->update_y1 - s->update_y0);
1102 return len;
1105 static int console_ioctl(void *opaque, int event, void *data)
1107 TextConsole *s = opaque;
1108 int i;
1110 switch (event) {
1111 case CHR_EVENT_FOCUS:
1112 for (i = 0; i < nb_consoles; i++) {
1113 if (consoles[i] == s) {
1114 console_select(i);
1115 break;
1118 return 0;
1119 default:
1120 break;
1123 return -ENOTSUP;
1126 static void kbd_send_chars(void *opaque)
1128 TextConsole *s = opaque;
1129 int len;
1130 uint8_t buf[16];
1132 len = qemu_chr_be_can_write(s->chr);
1133 if (len > s->out_fifo.count)
1134 len = s->out_fifo.count;
1135 if (len > 0) {
1136 if (len > sizeof(buf))
1137 len = sizeof(buf);
1138 qemu_fifo_read(&s->out_fifo, buf, len);
1139 qemu_chr_be_write(s->chr, buf, len);
1141 /* characters are pending: we send them a bit later (XXX:
1142 horrible, should change char device API) */
1143 if (s->out_fifo.count > 0) {
1144 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1148 /* called when an ascii key is pressed */
1149 void kbd_put_keysym(int keysym)
1151 TextConsole *s;
1152 uint8_t buf[16], *q;
1153 int c;
1155 s = active_console;
1156 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1157 return;
1159 switch(keysym) {
1160 case QEMU_KEY_CTRL_UP:
1161 console_scroll(-1);
1162 break;
1163 case QEMU_KEY_CTRL_DOWN:
1164 console_scroll(1);
1165 break;
1166 case QEMU_KEY_CTRL_PAGEUP:
1167 console_scroll(-10);
1168 break;
1169 case QEMU_KEY_CTRL_PAGEDOWN:
1170 console_scroll(10);
1171 break;
1172 default:
1173 /* convert the QEMU keysym to VT100 key string */
1174 q = buf;
1175 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1176 *q++ = '\033';
1177 *q++ = '[';
1178 c = keysym - 0xe100;
1179 if (c >= 10)
1180 *q++ = '0' + (c / 10);
1181 *q++ = '0' + (c % 10);
1182 *q++ = '~';
1183 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1184 *q++ = '\033';
1185 *q++ = '[';
1186 *q++ = keysym & 0xff;
1187 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1188 console_puts(s->chr, (const uint8_t *) "\r", 1);
1189 *q++ = '\n';
1190 } else {
1191 *q++ = keysym;
1193 if (s->echo) {
1194 console_puts(s->chr, buf, q - buf);
1196 if (s->chr->opened) {
1197 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1198 kbd_send_chars(s);
1200 break;
1204 static void text_console_invalidate(void *opaque)
1206 TextConsole *s = (TextConsole *) opaque;
1207 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1208 s->g_width = ds_get_width(s->ds);
1209 s->g_height = ds_get_height(s->ds);
1210 text_console_resize(s);
1212 console_refresh(s);
1215 static void text_console_update(void *opaque, console_ch_t *chardata)
1217 TextConsole *s = (TextConsole *) opaque;
1218 int i, j, src;
1220 if (s->text_x[0] <= s->text_x[1]) {
1221 src = (s->y_base + s->text_y[0]) * s->width;
1222 chardata += s->text_y[0] * s->width;
1223 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1224 for (j = 0; j < s->width; j ++, src ++)
1225 console_write_ch(chardata ++, s->cells[src].ch |
1226 (s->cells[src].t_attrib.fgcol << 12) |
1227 (s->cells[src].t_attrib.bgcol << 8) |
1228 (s->cells[src].t_attrib.bold << 21));
1229 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1230 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1231 s->text_x[0] = s->width;
1232 s->text_y[0] = s->height;
1233 s->text_x[1] = 0;
1234 s->text_y[1] = 0;
1236 if (s->cursor_invalidate) {
1237 dpy_cursor(s->ds, s->x, s->y);
1238 s->cursor_invalidate = 0;
1242 static TextConsole *get_graphic_console(DisplayState *ds)
1244 int i;
1245 TextConsole *s;
1246 for (i = 0; i < nb_consoles; i++) {
1247 s = consoles[i];
1248 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1249 return s;
1251 return NULL;
1254 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1256 TextConsole *s;
1257 int i;
1259 if (nb_consoles >= MAX_CONSOLES)
1260 return NULL;
1261 s = qemu_mallocz(sizeof(TextConsole));
1262 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1263 (console_type == GRAPHIC_CONSOLE))) {
1264 active_console = s;
1266 s->ds = ds;
1267 s->console_type = console_type;
1268 if (console_type != GRAPHIC_CONSOLE) {
1269 consoles[nb_consoles++] = s;
1270 } else {
1271 /* HACK: Put graphical consoles before text consoles. */
1272 for (i = nb_consoles; i > 0; i--) {
1273 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1274 break;
1275 consoles[i] = consoles[i - 1];
1277 consoles[i] = s;
1278 nb_consoles++;
1280 return s;
1283 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1285 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1287 int linesize = width * 4;
1288 qemu_alloc_display(surface, width, height, linesize,
1289 qemu_default_pixelformat(32), 0);
1290 return surface;
1293 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1294 int width, int height)
1296 int linesize = width * 4;
1297 qemu_alloc_display(surface, width, height, linesize,
1298 qemu_default_pixelformat(32), 0);
1299 return surface;
1302 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1303 int linesize, PixelFormat pf, int newflags)
1305 void *data;
1306 surface->width = width;
1307 surface->height = height;
1308 surface->linesize = linesize;
1309 surface->pf = pf;
1310 if (surface->flags & QEMU_ALLOCATED_FLAG) {
1311 data = qemu_realloc(surface->data,
1312 surface->linesize * surface->height);
1313 } else {
1314 data = qemu_malloc(surface->linesize * surface->height);
1316 surface->data = (uint8_t *)data;
1317 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1318 #ifdef HOST_WORDS_BIGENDIAN
1319 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1320 #endif
1323 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1324 int linesize, uint8_t *data)
1326 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1328 surface->width = width;
1329 surface->height = height;
1330 surface->linesize = linesize;
1331 surface->pf = qemu_default_pixelformat(bpp);
1332 #ifdef HOST_WORDS_BIGENDIAN
1333 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1334 #endif
1335 surface->data = data;
1337 return surface;
1340 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1342 if (surface == NULL)
1343 return;
1344 if (surface->flags & QEMU_ALLOCATED_FLAG)
1345 qemu_free(surface->data);
1346 qemu_free(surface);
1349 static struct DisplayAllocator default_allocator = {
1350 defaultallocator_create_displaysurface,
1351 defaultallocator_resize_displaysurface,
1352 defaultallocator_free_displaysurface
1355 static void dumb_display_init(void)
1357 DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1358 int width = 640;
1359 int height = 480;
1361 ds->allocator = &default_allocator;
1362 if (is_fixedsize_console()) {
1363 width = active_console->g_width;
1364 height = active_console->g_height;
1366 ds->surface = qemu_create_displaysurface(ds, width, height);
1367 register_displaystate(ds);
1370 /***********************************************************/
1371 /* register display */
1373 void register_displaystate(DisplayState *ds)
1375 DisplayState **s;
1376 s = &display_state;
1377 while (*s != NULL)
1378 s = &(*s)->next;
1379 ds->next = NULL;
1380 *s = ds;
1383 DisplayState *get_displaystate(void)
1385 if (!display_state) {
1386 dumb_display_init ();
1388 return display_state;
1391 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1393 if(ds->allocator == &default_allocator) {
1394 DisplaySurface *surf;
1395 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1396 defaultallocator_free_displaysurface(ds->surface);
1397 ds->surface = surf;
1398 ds->allocator = da;
1400 return ds->allocator;
1403 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1404 vga_hw_invalidate_ptr invalidate,
1405 vga_hw_screen_dump_ptr screen_dump,
1406 vga_hw_text_update_ptr text_update,
1407 void *opaque)
1409 TextConsole *s;
1410 DisplayState *ds;
1412 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1413 ds->allocator = &default_allocator;
1414 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1416 s = new_console(ds, GRAPHIC_CONSOLE);
1417 if (s == NULL) {
1418 qemu_free_displaysurface(ds);
1419 qemu_free(ds);
1420 return NULL;
1422 s->hw_update = update;
1423 s->hw_invalidate = invalidate;
1424 s->hw_screen_dump = screen_dump;
1425 s->hw_text_update = text_update;
1426 s->hw = opaque;
1428 register_displaystate(ds);
1429 return ds;
1432 int is_graphic_console(void)
1434 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1437 int is_fixedsize_console(void)
1439 return active_console && active_console->console_type != TEXT_CONSOLE;
1442 void console_color_init(DisplayState *ds)
1444 int i, j;
1445 for (j = 0; j < 2; j++) {
1446 for (i = 0; i < 8; i++) {
1447 color_table[j][i] = col_expand(ds,
1448 vga_get_color(ds, color_table_rgb[j][i]));
1453 static int n_text_consoles;
1454 static CharDriverState *text_consoles[128];
1456 static int text_console_ioctl(void *opaque, int cmd, void *data)
1458 TextConsole *s = opaque;
1459 bool *pecho = data;
1461 if (cmd != CHR_SET_ECHO) {
1462 return console_ioctl(opaque, cmd, data);
1465 s->echo = *pecho;
1466 return 0;
1469 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1471 TextConsole *s;
1472 static int color_inited;
1474 s = chr->opaque;
1476 chr->chr_write = console_puts;
1477 chr->chr_ioctl = console_ioctl;
1479 s->out_fifo.buf = s->out_fifo_buf;
1480 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1481 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1482 s->ds = ds;
1484 if (!color_inited) {
1485 color_inited = 1;
1486 console_color_init(s->ds);
1488 s->y_displayed = 0;
1489 s->y_base = 0;
1490 s->total_height = DEFAULT_BACKSCROLL;
1491 s->x = 0;
1492 s->y = 0;
1493 if (s->console_type == TEXT_CONSOLE) {
1494 s->g_width = ds_get_width(s->ds);
1495 s->g_height = ds_get_height(s->ds);
1498 s->hw_invalidate = text_console_invalidate;
1499 s->hw_text_update = text_console_update;
1500 s->hw = s;
1502 /* Set text attribute defaults */
1503 s->t_attrib_default.bold = 0;
1504 s->t_attrib_default.uline = 0;
1505 s->t_attrib_default.blink = 0;
1506 s->t_attrib_default.invers = 0;
1507 s->t_attrib_default.unvisible = 0;
1508 s->t_attrib_default.fgcol = COLOR_WHITE;
1509 s->t_attrib_default.bgcol = COLOR_BLACK;
1510 /* set current text attributes to default */
1511 s->t_attrib = s->t_attrib_default;
1512 text_console_resize(s);
1514 if (chr->label) {
1515 char msg[128];
1516 int len;
1518 s->t_attrib.bgcol = COLOR_BLUE;
1519 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1520 console_puts(chr, (uint8_t*)msg, len);
1521 s->t_attrib = s->t_attrib_default;
1524 qemu_chr_generic_open(chr);
1525 if (chr->init)
1526 chr->init(chr);
1529 int text_console_init(QemuOpts *opts, CharDriverState **_chr)
1531 CharDriverState *chr;
1532 TextConsole *s;
1533 unsigned width;
1534 unsigned height;
1536 chr = qemu_mallocz(sizeof(CharDriverState));
1538 if (n_text_consoles == 128) {
1539 fprintf(stderr, "Too many text consoles\n");
1540 exit(1);
1542 text_consoles[n_text_consoles] = chr;
1543 n_text_consoles++;
1545 width = qemu_opt_get_number(opts, "width", 0);
1546 if (width == 0)
1547 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1549 height = qemu_opt_get_number(opts, "height", 0);
1550 if (height == 0)
1551 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1553 if (width == 0 || height == 0) {
1554 s = new_console(NULL, TEXT_CONSOLE);
1555 } else {
1556 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1559 if (!s) {
1560 free(chr);
1561 return -EBUSY;
1564 s->chr = chr;
1565 s->g_width = width;
1566 s->g_height = height;
1567 chr->opaque = s;
1568 chr->chr_ioctl = text_console_ioctl;
1570 *_chr = chr;
1571 return 0;
1574 void text_consoles_set_display(DisplayState *ds)
1576 int i;
1578 for (i = 0; i < n_text_consoles; i++) {
1579 text_console_do_init(text_consoles[i], ds);
1582 n_text_consoles = 0;
1585 void qemu_console_resize(DisplayState *ds, int width, int height)
1587 TextConsole *s = get_graphic_console(ds);
1588 if (!s) return;
1590 s->g_width = width;
1591 s->g_height = height;
1592 if (is_graphic_console()) {
1593 ds->surface = qemu_resize_displaysurface(ds, width, height);
1594 dpy_resize(ds);
1598 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1599 int dst_x, int dst_y, int w, int h)
1601 if (is_graphic_console()) {
1602 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1606 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1608 PixelFormat pf;
1610 memset(&pf, 0x00, sizeof(PixelFormat));
1612 pf.bits_per_pixel = bpp;
1613 pf.bytes_per_pixel = bpp / 8;
1614 pf.depth = bpp == 32 ? 24 : bpp;
1616 switch (bpp) {
1617 case 24:
1618 pf.rmask = 0x000000FF;
1619 pf.gmask = 0x0000FF00;
1620 pf.bmask = 0x00FF0000;
1621 pf.rmax = 255;
1622 pf.gmax = 255;
1623 pf.bmax = 255;
1624 pf.rshift = 0;
1625 pf.gshift = 8;
1626 pf.bshift = 16;
1627 pf.rbits = 8;
1628 pf.gbits = 8;
1629 pf.bbits = 8;
1630 break;
1631 case 32:
1632 pf.rmask = 0x0000FF00;
1633 pf.gmask = 0x00FF0000;
1634 pf.bmask = 0xFF000000;
1635 pf.amask = 0x00000000;
1636 pf.amax = 255;
1637 pf.rmax = 255;
1638 pf.gmax = 255;
1639 pf.bmax = 255;
1640 pf.ashift = 0;
1641 pf.rshift = 8;
1642 pf.gshift = 16;
1643 pf.bshift = 24;
1644 pf.rbits = 8;
1645 pf.gbits = 8;
1646 pf.bbits = 8;
1647 pf.abits = 8;
1648 break;
1649 default:
1650 break;
1652 return pf;
1655 PixelFormat qemu_default_pixelformat(int bpp)
1657 PixelFormat pf;
1659 memset(&pf, 0x00, sizeof(PixelFormat));
1661 pf.bits_per_pixel = bpp;
1662 pf.bytes_per_pixel = bpp / 8;
1663 pf.depth = bpp == 32 ? 24 : bpp;
1665 switch (bpp) {
1666 case 15:
1667 pf.bits_per_pixel = 16;
1668 pf.bytes_per_pixel = 2;
1669 pf.rmask = 0x00007c00;
1670 pf.gmask = 0x000003E0;
1671 pf.bmask = 0x0000001F;
1672 pf.rmax = 31;
1673 pf.gmax = 31;
1674 pf.bmax = 31;
1675 pf.rshift = 10;
1676 pf.gshift = 5;
1677 pf.bshift = 0;
1678 pf.rbits = 5;
1679 pf.gbits = 5;
1680 pf.bbits = 5;
1681 break;
1682 case 16:
1683 pf.rmask = 0x0000F800;
1684 pf.gmask = 0x000007E0;
1685 pf.bmask = 0x0000001F;
1686 pf.rmax = 31;
1687 pf.gmax = 63;
1688 pf.bmax = 31;
1689 pf.rshift = 11;
1690 pf.gshift = 5;
1691 pf.bshift = 0;
1692 pf.rbits = 5;
1693 pf.gbits = 6;
1694 pf.bbits = 5;
1695 break;
1696 case 24:
1697 pf.rmask = 0x00FF0000;
1698 pf.gmask = 0x0000FF00;
1699 pf.bmask = 0x000000FF;
1700 pf.rmax = 255;
1701 pf.gmax = 255;
1702 pf.bmax = 255;
1703 pf.rshift = 16;
1704 pf.gshift = 8;
1705 pf.bshift = 0;
1706 pf.rbits = 8;
1707 pf.gbits = 8;
1708 pf.bbits = 8;
1709 case 32:
1710 pf.rmask = 0x00FF0000;
1711 pf.gmask = 0x0000FF00;
1712 pf.bmask = 0x000000FF;
1713 pf.amax = 255;
1714 pf.rmax = 255;
1715 pf.gmax = 255;
1716 pf.bmax = 255;
1717 pf.ashift = 24;
1718 pf.rshift = 16;
1719 pf.gshift = 8;
1720 pf.bshift = 0;
1721 pf.rbits = 8;
1722 pf.gbits = 8;
1723 pf.bbits = 8;
1724 pf.abits = 8;
1725 break;
1726 default:
1727 break;
1729 return pf;