console: remove DisplayAllocator
[qemu/opensuse.git] / console.c
blob71cc543b7bf3411792e18d4b09a037e669368cd6
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"
27 #include "qmp-commands.h"
29 //#define DEBUG_CONSOLE
30 #define DEFAULT_BACKSCROLL 512
31 #define MAX_CONSOLES 12
32 #define CONSOLE_CURSOR_PERIOD 500
34 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
35 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
37 typedef struct TextAttributes {
38 uint8_t fgcol:4;
39 uint8_t bgcol:4;
40 uint8_t bold:1;
41 uint8_t uline:1;
42 uint8_t blink:1;
43 uint8_t invers:1;
44 uint8_t unvisible:1;
45 } TextAttributes;
47 typedef struct TextCell {
48 uint8_t ch;
49 TextAttributes t_attrib;
50 } TextCell;
52 #define MAX_ESC_PARAMS 3
54 enum TTYState {
55 TTY_STATE_NORM,
56 TTY_STATE_ESC,
57 TTY_STATE_CSI,
60 typedef struct QEMUFIFO {
61 uint8_t *buf;
62 int buf_size;
63 int count, wptr, rptr;
64 } QEMUFIFO;
66 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
68 int l, len;
70 l = f->buf_size - f->count;
71 if (len1 > l)
72 len1 = l;
73 len = len1;
74 while (len > 0) {
75 l = f->buf_size - f->wptr;
76 if (l > len)
77 l = len;
78 memcpy(f->buf + f->wptr, buf, l);
79 f->wptr += l;
80 if (f->wptr >= f->buf_size)
81 f->wptr = 0;
82 buf += l;
83 len -= l;
85 f->count += len1;
86 return len1;
89 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
91 int l, len;
93 if (len1 > f->count)
94 len1 = f->count;
95 len = len1;
96 while (len > 0) {
97 l = f->buf_size - f->rptr;
98 if (l > len)
99 l = len;
100 memcpy(buf, f->buf + f->rptr, l);
101 f->rptr += l;
102 if (f->rptr >= f->buf_size)
103 f->rptr = 0;
104 buf += l;
105 len -= l;
107 f->count -= len1;
108 return len1;
111 typedef enum {
112 GRAPHIC_CONSOLE,
113 TEXT_CONSOLE,
114 TEXT_CONSOLE_FIXED_SIZE
115 } console_type_t;
117 struct QemuConsole {
118 int index;
119 console_type_t console_type;
120 DisplayState *ds;
122 /* Graphic console state. */
123 vga_hw_update_ptr hw_update;
124 vga_hw_invalidate_ptr hw_invalidate;
125 vga_hw_screen_dump_ptr hw_screen_dump;
126 vga_hw_text_update_ptr hw_text_update;
127 void *hw;
128 int g_width, g_height;
130 /* Text console state */
131 int width;
132 int height;
133 int total_height;
134 int backscroll_height;
135 int x, y;
136 int x_saved, y_saved;
137 int y_displayed;
138 int y_base;
139 TextAttributes t_attrib_default; /* default text attributes */
140 TextAttributes t_attrib; /* currently active text attributes */
141 TextCell *cells;
142 int text_x[2], text_y[2], cursor_invalidate;
143 int echo;
144 bool cursor_visible_phase;
145 QEMUTimer *cursor_timer;
147 int update_x0;
148 int update_y0;
149 int update_x1;
150 int update_y1;
152 enum TTYState state;
153 int esc_params[MAX_ESC_PARAMS];
154 int nb_esc_params;
156 CharDriverState *chr;
157 /* fifo for key pressed */
158 QEMUFIFO out_fifo;
159 uint8_t out_fifo_buf[16];
160 QEMUTimer *kbd_timer;
163 static DisplayState *display_state;
164 static QemuConsole *active_console;
165 static QemuConsole *consoles[MAX_CONSOLES];
166 static int nb_consoles = 0;
168 void vga_hw_update(void)
170 if (active_console && active_console->hw_update)
171 active_console->hw_update(active_console->hw);
174 void vga_hw_invalidate(void)
176 if (active_console && active_console->hw_invalidate)
177 active_console->hw_invalidate(active_console->hw);
180 void qmp_screendump(const char *filename, Error **errp)
182 QemuConsole *previous_active_console;
183 bool cswitch;
185 previous_active_console = active_console;
186 cswitch = previous_active_console && previous_active_console->index != 0;
188 /* There is currently no way of specifying which screen we want to dump,
189 so always dump the first one. */
190 if (cswitch) {
191 console_select(0);
193 if (consoles[0] && consoles[0]->hw_screen_dump) {
194 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
195 } else {
196 error_setg(errp, "device doesn't support screendump\n");
199 if (cswitch) {
200 console_select(previous_active_console->index);
204 void vga_hw_text_update(console_ch_t *chardata)
206 if (active_console && active_console->hw_text_update)
207 active_console->hw_text_update(active_console->hw, chardata);
210 /* convert a RGBA color to a color index usable in graphic primitives */
211 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
213 unsigned int r, g, b, color;
215 switch(ds_get_bits_per_pixel(ds)) {
216 #if 0
217 case 8:
218 r = (rgba >> 16) & 0xff;
219 g = (rgba >> 8) & 0xff;
220 b = (rgba) & 0xff;
221 color = (rgb_to_index[r] * 6 * 6) +
222 (rgb_to_index[g] * 6) +
223 (rgb_to_index[b]);
224 break;
225 #endif
226 case 15:
227 r = (rgba >> 16) & 0xff;
228 g = (rgba >> 8) & 0xff;
229 b = (rgba) & 0xff;
230 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
231 break;
232 case 16:
233 r = (rgba >> 16) & 0xff;
234 g = (rgba >> 8) & 0xff;
235 b = (rgba) & 0xff;
236 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
237 break;
238 case 32:
239 default:
240 color = rgba;
241 break;
243 return color;
246 static void vga_fill_rect (DisplayState *ds,
247 int posx, int posy, int width, int height, uint32_t color)
249 uint8_t *d, *d1;
250 int x, y, bpp;
252 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
253 d1 = ds_get_data(ds) +
254 ds_get_linesize(ds) * posy + bpp * posx;
255 for (y = 0; y < height; y++) {
256 d = d1;
257 switch(bpp) {
258 case 1:
259 for (x = 0; x < width; x++) {
260 *((uint8_t *)d) = color;
261 d++;
263 break;
264 case 2:
265 for (x = 0; x < width; x++) {
266 *((uint16_t *)d) = color;
267 d += 2;
269 break;
270 case 4:
271 for (x = 0; x < width; x++) {
272 *((uint32_t *)d) = color;
273 d += 4;
275 break;
277 d1 += ds_get_linesize(ds);
281 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
282 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
284 const uint8_t *s;
285 uint8_t *d;
286 int wb, y, bpp;
288 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
289 wb = w * bpp;
290 if (yd <= ys) {
291 s = ds_get_data(ds) +
292 ds_get_linesize(ds) * ys + bpp * xs;
293 d = ds_get_data(ds) +
294 ds_get_linesize(ds) * yd + bpp * xd;
295 for (y = 0; y < h; y++) {
296 memmove(d, s, wb);
297 d += ds_get_linesize(ds);
298 s += ds_get_linesize(ds);
300 } else {
301 s = ds_get_data(ds) +
302 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
303 d = ds_get_data(ds) +
304 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
305 for (y = 0; y < h; y++) {
306 memmove(d, s, wb);
307 d -= ds_get_linesize(ds);
308 s -= ds_get_linesize(ds);
313 /***********************************************************/
314 /* basic char display */
316 #define FONT_HEIGHT 16
317 #define FONT_WIDTH 8
319 #include "vgafont.h"
321 #define cbswap_32(__x) \
322 ((uint32_t)( \
323 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
324 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
325 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
326 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
328 #ifdef HOST_WORDS_BIGENDIAN
329 #define PAT(x) x
330 #else
331 #define PAT(x) cbswap_32(x)
332 #endif
334 static const uint32_t dmask16[16] = {
335 PAT(0x00000000),
336 PAT(0x000000ff),
337 PAT(0x0000ff00),
338 PAT(0x0000ffff),
339 PAT(0x00ff0000),
340 PAT(0x00ff00ff),
341 PAT(0x00ffff00),
342 PAT(0x00ffffff),
343 PAT(0xff000000),
344 PAT(0xff0000ff),
345 PAT(0xff00ff00),
346 PAT(0xff00ffff),
347 PAT(0xffff0000),
348 PAT(0xffff00ff),
349 PAT(0xffffff00),
350 PAT(0xffffffff),
353 static const uint32_t dmask4[4] = {
354 PAT(0x00000000),
355 PAT(0x0000ffff),
356 PAT(0xffff0000),
357 PAT(0xffffffff),
360 static uint32_t color_table[2][8];
362 #ifndef CONFIG_CURSES
363 enum color_names {
364 COLOR_BLACK = 0,
365 COLOR_RED = 1,
366 COLOR_GREEN = 2,
367 COLOR_YELLOW = 3,
368 COLOR_BLUE = 4,
369 COLOR_MAGENTA = 5,
370 COLOR_CYAN = 6,
371 COLOR_WHITE = 7
373 #endif
375 static const uint32_t color_table_rgb[2][8] = {
376 { /* dark */
377 QEMU_RGB(0x00, 0x00, 0x00), /* black */
378 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
379 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
380 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
381 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
382 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
383 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
384 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
386 { /* bright */
387 QEMU_RGB(0x00, 0x00, 0x00), /* black */
388 QEMU_RGB(0xff, 0x00, 0x00), /* red */
389 QEMU_RGB(0x00, 0xff, 0x00), /* green */
390 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
391 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
392 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
393 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
394 QEMU_RGB(0xff, 0xff, 0xff), /* white */
398 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
400 switch(ds_get_bits_per_pixel(ds)) {
401 case 8:
402 col |= col << 8;
403 col |= col << 16;
404 break;
405 case 15:
406 case 16:
407 col |= col << 16;
408 break;
409 default:
410 break;
413 return col;
415 #ifdef DEBUG_CONSOLE
416 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
418 if (t_attrib->bold) {
419 printf("b");
420 } else {
421 printf(" ");
423 if (t_attrib->uline) {
424 printf("u");
425 } else {
426 printf(" ");
428 if (t_attrib->blink) {
429 printf("l");
430 } else {
431 printf(" ");
433 if (t_attrib->invers) {
434 printf("i");
435 } else {
436 printf(" ");
438 if (t_attrib->unvisible) {
439 printf("n");
440 } else {
441 printf(" ");
444 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
446 #endif
448 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
449 TextAttributes *t_attrib)
451 uint8_t *d;
452 const uint8_t *font_ptr;
453 unsigned int font_data, linesize, xorcol, bpp;
454 int i;
455 unsigned int fgcol, bgcol;
457 #ifdef DEBUG_CONSOLE
458 printf("x: %2i y: %2i", x, y);
459 console_print_text_attributes(t_attrib, ch);
460 #endif
462 if (t_attrib->invers) {
463 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
464 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
465 } else {
466 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
467 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
470 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
471 d = ds_get_data(ds) +
472 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
473 linesize = ds_get_linesize(ds);
474 font_ptr = vgafont16 + FONT_HEIGHT * ch;
475 xorcol = bgcol ^ fgcol;
476 switch(ds_get_bits_per_pixel(ds)) {
477 case 8:
478 for(i = 0; i < FONT_HEIGHT; i++) {
479 font_data = *font_ptr++;
480 if (t_attrib->uline
481 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
482 font_data = 0xFF;
484 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
485 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
486 d += linesize;
488 break;
489 case 16:
490 case 15:
491 for(i = 0; i < FONT_HEIGHT; i++) {
492 font_data = *font_ptr++;
493 if (t_attrib->uline
494 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
495 font_data = 0xFF;
497 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
498 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
499 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
500 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
501 d += linesize;
503 break;
504 case 32:
505 for(i = 0; i < FONT_HEIGHT; i++) {
506 font_data = *font_ptr++;
507 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
508 font_data = 0xFF;
510 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
514 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
515 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
516 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
517 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
518 d += linesize;
520 break;
524 static void text_console_resize(QemuConsole *s)
526 TextCell *cells, *c, *c1;
527 int w1, x, y, last_width;
529 last_width = s->width;
530 s->width = s->g_width / FONT_WIDTH;
531 s->height = s->g_height / FONT_HEIGHT;
533 w1 = last_width;
534 if (s->width < w1)
535 w1 = s->width;
537 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
538 for(y = 0; y < s->total_height; y++) {
539 c = &cells[y * s->width];
540 if (w1 > 0) {
541 c1 = &s->cells[y * last_width];
542 for(x = 0; x < w1; x++) {
543 *c++ = *c1++;
546 for(x = w1; x < s->width; x++) {
547 c->ch = ' ';
548 c->t_attrib = s->t_attrib_default;
549 c++;
552 g_free(s->cells);
553 s->cells = cells;
556 static inline void text_update_xy(QemuConsole *s, int x, int y)
558 s->text_x[0] = MIN(s->text_x[0], x);
559 s->text_x[1] = MAX(s->text_x[1], x);
560 s->text_y[0] = MIN(s->text_y[0], y);
561 s->text_y[1] = MAX(s->text_y[1], y);
564 static void invalidate_xy(QemuConsole *s, int x, int y)
566 if (s->update_x0 > x * FONT_WIDTH)
567 s->update_x0 = x * FONT_WIDTH;
568 if (s->update_y0 > y * FONT_HEIGHT)
569 s->update_y0 = y * FONT_HEIGHT;
570 if (s->update_x1 < (x + 1) * FONT_WIDTH)
571 s->update_x1 = (x + 1) * FONT_WIDTH;
572 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
573 s->update_y1 = (y + 1) * FONT_HEIGHT;
576 static void update_xy(QemuConsole *s, int x, int y)
578 TextCell *c;
579 int y1, y2;
581 if (s == active_console) {
582 if (!ds_get_bits_per_pixel(s->ds)) {
583 text_update_xy(s, x, y);
584 return;
587 y1 = (s->y_base + y) % s->total_height;
588 y2 = y1 - s->y_displayed;
589 if (y2 < 0)
590 y2 += s->total_height;
591 if (y2 < s->height) {
592 c = &s->cells[y1 * s->width + x];
593 vga_putcharxy(s->ds, x, y2, c->ch,
594 &(c->t_attrib));
595 invalidate_xy(s, x, y2);
600 static void console_show_cursor(QemuConsole *s, int show)
602 TextCell *c;
603 int y, y1;
605 if (s == active_console) {
606 int x = s->x;
608 if (!ds_get_bits_per_pixel(s->ds)) {
609 s->cursor_invalidate = 1;
610 return;
613 if (x >= s->width) {
614 x = s->width - 1;
616 y1 = (s->y_base + s->y) % s->total_height;
617 y = y1 - s->y_displayed;
618 if (y < 0)
619 y += s->total_height;
620 if (y < s->height) {
621 c = &s->cells[y1 * s->width + x];
622 if (show && s->cursor_visible_phase) {
623 TextAttributes t_attrib = s->t_attrib_default;
624 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
625 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
626 } else {
627 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
629 invalidate_xy(s, x, y);
634 static void console_refresh(QemuConsole *s)
636 TextCell *c;
637 int x, y, y1;
639 if (s != active_console)
640 return;
642 if (s->ds->have_text) {
643 s->text_x[0] = 0;
644 s->text_y[0] = 0;
645 s->text_x[1] = s->width - 1;
646 s->text_y[1] = s->height - 1;
647 s->cursor_invalidate = 1;
650 if (s->ds->have_gfx) {
651 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
652 color_table[0][COLOR_BLACK]);
653 y1 = s->y_displayed;
654 for (y = 0; y < s->height; y++) {
655 c = s->cells + y1 * s->width;
656 for (x = 0; x < s->width; x++) {
657 vga_putcharxy(s->ds, x, y, c->ch,
658 &(c->t_attrib));
659 c++;
661 if (++y1 == s->total_height) {
662 y1 = 0;
665 console_show_cursor(s, 1);
666 dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
670 static void console_scroll(int ydelta)
672 QemuConsole *s;
673 int i, y1;
675 s = active_console;
676 if (!s || (s->console_type == GRAPHIC_CONSOLE))
677 return;
679 if (ydelta > 0) {
680 for(i = 0; i < ydelta; i++) {
681 if (s->y_displayed == s->y_base)
682 break;
683 if (++s->y_displayed == s->total_height)
684 s->y_displayed = 0;
686 } else {
687 ydelta = -ydelta;
688 i = s->backscroll_height;
689 if (i > s->total_height - s->height)
690 i = s->total_height - s->height;
691 y1 = s->y_base - i;
692 if (y1 < 0)
693 y1 += s->total_height;
694 for(i = 0; i < ydelta; i++) {
695 if (s->y_displayed == y1)
696 break;
697 if (--s->y_displayed < 0)
698 s->y_displayed = s->total_height - 1;
701 console_refresh(s);
704 static void console_put_lf(QemuConsole *s)
706 TextCell *c;
707 int x, y1;
709 s->y++;
710 if (s->y >= s->height) {
711 s->y = s->height - 1;
713 if (s->y_displayed == s->y_base) {
714 if (++s->y_displayed == s->total_height)
715 s->y_displayed = 0;
717 if (++s->y_base == s->total_height)
718 s->y_base = 0;
719 if (s->backscroll_height < s->total_height)
720 s->backscroll_height++;
721 y1 = (s->y_base + s->height - 1) % s->total_height;
722 c = &s->cells[y1 * s->width];
723 for(x = 0; x < s->width; x++) {
724 c->ch = ' ';
725 c->t_attrib = s->t_attrib_default;
726 c++;
728 if (s == active_console && s->y_displayed == s->y_base) {
729 if (!ds_get_bits_per_pixel(s->ds)) {
730 s->text_x[0] = 0;
731 s->text_y[0] = 0;
732 s->text_x[1] = s->width - 1;
733 s->text_y[1] = s->height - 1;
734 return;
737 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
738 s->width * FONT_WIDTH,
739 (s->height - 1) * FONT_HEIGHT);
740 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
741 s->width * FONT_WIDTH, FONT_HEIGHT,
742 color_table[0][s->t_attrib_default.bgcol]);
743 s->update_x0 = 0;
744 s->update_y0 = 0;
745 s->update_x1 = s->width * FONT_WIDTH;
746 s->update_y1 = s->height * FONT_HEIGHT;
751 /* Set console attributes depending on the current escape codes.
752 * NOTE: I know this code is not very efficient (checking every color for it
753 * self) but it is more readable and better maintainable.
755 static void console_handle_escape(QemuConsole *s)
757 int i;
759 for (i=0; i<s->nb_esc_params; i++) {
760 switch (s->esc_params[i]) {
761 case 0: /* reset all console attributes to default */
762 s->t_attrib = s->t_attrib_default;
763 break;
764 case 1:
765 s->t_attrib.bold = 1;
766 break;
767 case 4:
768 s->t_attrib.uline = 1;
769 break;
770 case 5:
771 s->t_attrib.blink = 1;
772 break;
773 case 7:
774 s->t_attrib.invers = 1;
775 break;
776 case 8:
777 s->t_attrib.unvisible = 1;
778 break;
779 case 22:
780 s->t_attrib.bold = 0;
781 break;
782 case 24:
783 s->t_attrib.uline = 0;
784 break;
785 case 25:
786 s->t_attrib.blink = 0;
787 break;
788 case 27:
789 s->t_attrib.invers = 0;
790 break;
791 case 28:
792 s->t_attrib.unvisible = 0;
793 break;
794 /* set foreground color */
795 case 30:
796 s->t_attrib.fgcol=COLOR_BLACK;
797 break;
798 case 31:
799 s->t_attrib.fgcol=COLOR_RED;
800 break;
801 case 32:
802 s->t_attrib.fgcol=COLOR_GREEN;
803 break;
804 case 33:
805 s->t_attrib.fgcol=COLOR_YELLOW;
806 break;
807 case 34:
808 s->t_attrib.fgcol=COLOR_BLUE;
809 break;
810 case 35:
811 s->t_attrib.fgcol=COLOR_MAGENTA;
812 break;
813 case 36:
814 s->t_attrib.fgcol=COLOR_CYAN;
815 break;
816 case 37:
817 s->t_attrib.fgcol=COLOR_WHITE;
818 break;
819 /* set background color */
820 case 40:
821 s->t_attrib.bgcol=COLOR_BLACK;
822 break;
823 case 41:
824 s->t_attrib.bgcol=COLOR_RED;
825 break;
826 case 42:
827 s->t_attrib.bgcol=COLOR_GREEN;
828 break;
829 case 43:
830 s->t_attrib.bgcol=COLOR_YELLOW;
831 break;
832 case 44:
833 s->t_attrib.bgcol=COLOR_BLUE;
834 break;
835 case 45:
836 s->t_attrib.bgcol=COLOR_MAGENTA;
837 break;
838 case 46:
839 s->t_attrib.bgcol=COLOR_CYAN;
840 break;
841 case 47:
842 s->t_attrib.bgcol=COLOR_WHITE;
843 break;
848 static void console_clear_xy(QemuConsole *s, int x, int y)
850 int y1 = (s->y_base + y) % s->total_height;
851 TextCell *c = &s->cells[y1 * s->width + x];
852 c->ch = ' ';
853 c->t_attrib = s->t_attrib_default;
854 update_xy(s, x, y);
857 /* set cursor, checking bounds */
858 static void set_cursor(QemuConsole *s, int x, int y)
860 if (x < 0) {
861 x = 0;
863 if (y < 0) {
864 y = 0;
866 if (y >= s->height) {
867 y = s->height - 1;
869 if (x >= s->width) {
870 x = s->width - 1;
873 s->x = x;
874 s->y = y;
877 static void console_putchar(QemuConsole *s, int ch)
879 TextCell *c;
880 int y1, i;
881 int x, y;
883 switch(s->state) {
884 case TTY_STATE_NORM:
885 switch(ch) {
886 case '\r': /* carriage return */
887 s->x = 0;
888 break;
889 case '\n': /* newline */
890 console_put_lf(s);
891 break;
892 case '\b': /* backspace */
893 if (s->x > 0)
894 s->x--;
895 break;
896 case '\t': /* tabspace */
897 if (s->x + (8 - (s->x % 8)) > s->width) {
898 s->x = 0;
899 console_put_lf(s);
900 } else {
901 s->x = s->x + (8 - (s->x % 8));
903 break;
904 case '\a': /* alert aka. bell */
905 /* TODO: has to be implemented */
906 break;
907 case 14:
908 /* SI (shift in), character set 0 (ignored) */
909 break;
910 case 15:
911 /* SO (shift out), character set 1 (ignored) */
912 break;
913 case 27: /* esc (introducing an escape sequence) */
914 s->state = TTY_STATE_ESC;
915 break;
916 default:
917 if (s->x >= s->width) {
918 /* line wrap */
919 s->x = 0;
920 console_put_lf(s);
922 y1 = (s->y_base + s->y) % s->total_height;
923 c = &s->cells[y1 * s->width + s->x];
924 c->ch = ch;
925 c->t_attrib = s->t_attrib;
926 update_xy(s, s->x, s->y);
927 s->x++;
928 break;
930 break;
931 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
932 if (ch == '[') {
933 for(i=0;i<MAX_ESC_PARAMS;i++)
934 s->esc_params[i] = 0;
935 s->nb_esc_params = 0;
936 s->state = TTY_STATE_CSI;
937 } else {
938 s->state = TTY_STATE_NORM;
940 break;
941 case TTY_STATE_CSI: /* handle escape sequence parameters */
942 if (ch >= '0' && ch <= '9') {
943 if (s->nb_esc_params < MAX_ESC_PARAMS) {
944 int *param = &s->esc_params[s->nb_esc_params];
945 int digit = (ch - '0');
947 *param = (*param <= (INT_MAX - digit) / 10) ?
948 *param * 10 + digit : INT_MAX;
950 } else {
951 if (s->nb_esc_params < MAX_ESC_PARAMS)
952 s->nb_esc_params++;
953 if (ch == ';')
954 break;
955 #ifdef DEBUG_CONSOLE
956 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
957 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
958 #endif
959 s->state = TTY_STATE_NORM;
960 switch(ch) {
961 case 'A':
962 /* move cursor up */
963 if (s->esc_params[0] == 0) {
964 s->esc_params[0] = 1;
966 set_cursor(s, s->x, s->y - s->esc_params[0]);
967 break;
968 case 'B':
969 /* move cursor down */
970 if (s->esc_params[0] == 0) {
971 s->esc_params[0] = 1;
973 set_cursor(s, s->x, s->y + s->esc_params[0]);
974 break;
975 case 'C':
976 /* move cursor right */
977 if (s->esc_params[0] == 0) {
978 s->esc_params[0] = 1;
980 set_cursor(s, s->x + s->esc_params[0], s->y);
981 break;
982 case 'D':
983 /* move cursor left */
984 if (s->esc_params[0] == 0) {
985 s->esc_params[0] = 1;
987 set_cursor(s, s->x - s->esc_params[0], s->y);
988 break;
989 case 'G':
990 /* move cursor to column */
991 set_cursor(s, s->esc_params[0] - 1, s->y);
992 break;
993 case 'f':
994 case 'H':
995 /* move cursor to row, column */
996 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
997 break;
998 case 'J':
999 switch (s->esc_params[0]) {
1000 case 0:
1001 /* clear to end of screen */
1002 for (y = s->y; y < s->height; y++) {
1003 for (x = 0; x < s->width; x++) {
1004 if (y == s->y && x < s->x) {
1005 continue;
1007 console_clear_xy(s, x, y);
1010 break;
1011 case 1:
1012 /* clear from beginning of screen */
1013 for (y = 0; y <= s->y; y++) {
1014 for (x = 0; x < s->width; x++) {
1015 if (y == s->y && x > s->x) {
1016 break;
1018 console_clear_xy(s, x, y);
1021 break;
1022 case 2:
1023 /* clear entire screen */
1024 for (y = 0; y <= s->height; y++) {
1025 for (x = 0; x < s->width; x++) {
1026 console_clear_xy(s, x, y);
1029 break;
1031 break;
1032 case 'K':
1033 switch (s->esc_params[0]) {
1034 case 0:
1035 /* clear to eol */
1036 for(x = s->x; x < s->width; x++) {
1037 console_clear_xy(s, x, s->y);
1039 break;
1040 case 1:
1041 /* clear from beginning of line */
1042 for (x = 0; x <= s->x; x++) {
1043 console_clear_xy(s, x, s->y);
1045 break;
1046 case 2:
1047 /* clear entire line */
1048 for(x = 0; x < s->width; x++) {
1049 console_clear_xy(s, x, s->y);
1051 break;
1053 break;
1054 case 'm':
1055 console_handle_escape(s);
1056 break;
1057 case 'n':
1058 /* report cursor position */
1059 /* TODO: send ESC[row;colR */
1060 break;
1061 case 's':
1062 /* save cursor position */
1063 s->x_saved = s->x;
1064 s->y_saved = s->y;
1065 break;
1066 case 'u':
1067 /* restore cursor position */
1068 s->x = s->x_saved;
1069 s->y = s->y_saved;
1070 break;
1071 default:
1072 #ifdef DEBUG_CONSOLE
1073 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1074 #endif
1075 break;
1077 break;
1082 void console_select(unsigned int index)
1084 QemuConsole *s;
1086 if (index >= MAX_CONSOLES)
1087 return;
1088 if (active_console) {
1089 active_console->g_width = ds_get_width(active_console->ds);
1090 active_console->g_height = ds_get_height(active_console->ds);
1092 s = consoles[index];
1093 if (s) {
1094 DisplayState *ds = s->ds;
1096 if (active_console && active_console->cursor_timer) {
1097 qemu_del_timer(active_console->cursor_timer);
1099 active_console = s;
1100 if (ds->have_gfx) {
1101 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1102 dpy_gfx_resize(ds);
1104 if (ds->have_text) {
1105 dpy_text_resize(ds, s->width, s->height);
1107 if (s->cursor_timer) {
1108 qemu_mod_timer(s->cursor_timer,
1109 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1111 vga_hw_invalidate();
1115 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1117 QemuConsole *s = chr->opaque;
1118 int i;
1120 s->update_x0 = s->width * FONT_WIDTH;
1121 s->update_y0 = s->height * FONT_HEIGHT;
1122 s->update_x1 = 0;
1123 s->update_y1 = 0;
1124 console_show_cursor(s, 0);
1125 for(i = 0; i < len; i++) {
1126 console_putchar(s, buf[i]);
1128 console_show_cursor(s, 1);
1129 if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1130 dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
1131 s->update_x1 - s->update_x0,
1132 s->update_y1 - s->update_y0);
1134 return len;
1137 static void kbd_send_chars(void *opaque)
1139 QemuConsole *s = opaque;
1140 int len;
1141 uint8_t buf[16];
1143 len = qemu_chr_be_can_write(s->chr);
1144 if (len > s->out_fifo.count)
1145 len = s->out_fifo.count;
1146 if (len > 0) {
1147 if (len > sizeof(buf))
1148 len = sizeof(buf);
1149 qemu_fifo_read(&s->out_fifo, buf, len);
1150 qemu_chr_be_write(s->chr, buf, len);
1152 /* characters are pending: we send them a bit later (XXX:
1153 horrible, should change char device API) */
1154 if (s->out_fifo.count > 0) {
1155 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1159 /* called when an ascii key is pressed */
1160 void kbd_put_keysym(int keysym)
1162 QemuConsole *s;
1163 uint8_t buf[16], *q;
1164 int c;
1166 s = active_console;
1167 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1168 return;
1170 switch(keysym) {
1171 case QEMU_KEY_CTRL_UP:
1172 console_scroll(-1);
1173 break;
1174 case QEMU_KEY_CTRL_DOWN:
1175 console_scroll(1);
1176 break;
1177 case QEMU_KEY_CTRL_PAGEUP:
1178 console_scroll(-10);
1179 break;
1180 case QEMU_KEY_CTRL_PAGEDOWN:
1181 console_scroll(10);
1182 break;
1183 default:
1184 /* convert the QEMU keysym to VT100 key string */
1185 q = buf;
1186 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1187 *q++ = '\033';
1188 *q++ = '[';
1189 c = keysym - 0xe100;
1190 if (c >= 10)
1191 *q++ = '0' + (c / 10);
1192 *q++ = '0' + (c % 10);
1193 *q++ = '~';
1194 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1195 *q++ = '\033';
1196 *q++ = '[';
1197 *q++ = keysym & 0xff;
1198 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1199 console_puts(s->chr, (const uint8_t *) "\r", 1);
1200 *q++ = '\n';
1201 } else {
1202 *q++ = keysym;
1204 if (s->echo) {
1205 console_puts(s->chr, buf, q - buf);
1207 if (s->chr->chr_read) {
1208 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1209 kbd_send_chars(s);
1211 break;
1215 static void text_console_invalidate(void *opaque)
1217 QemuConsole *s = (QemuConsole *) opaque;
1218 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1219 s->g_width = ds_get_width(s->ds);
1220 s->g_height = ds_get_height(s->ds);
1221 text_console_resize(s);
1223 console_refresh(s);
1226 static void text_console_update(void *opaque, console_ch_t *chardata)
1228 QemuConsole *s = (QemuConsole *) opaque;
1229 int i, j, src;
1231 if (s->text_x[0] <= s->text_x[1]) {
1232 src = (s->y_base + s->text_y[0]) * s->width;
1233 chardata += s->text_y[0] * s->width;
1234 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1235 for (j = 0; j < s->width; j ++, src ++)
1236 console_write_ch(chardata ++, s->cells[src].ch |
1237 (s->cells[src].t_attrib.fgcol << 12) |
1238 (s->cells[src].t_attrib.bgcol << 8) |
1239 (s->cells[src].t_attrib.bold << 21));
1240 dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
1241 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1242 s->text_x[0] = s->width;
1243 s->text_y[0] = s->height;
1244 s->text_x[1] = 0;
1245 s->text_y[1] = 0;
1247 if (s->cursor_invalidate) {
1248 dpy_text_cursor(s->ds, s->x, s->y);
1249 s->cursor_invalidate = 0;
1253 static QemuConsole *get_graphic_console(DisplayState *ds)
1255 int i;
1256 QemuConsole *s;
1257 for (i = 0; i < nb_consoles; i++) {
1258 s = consoles[i];
1259 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1260 return s;
1262 return NULL;
1265 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
1267 QemuConsole *s;
1268 int i;
1270 if (nb_consoles >= MAX_CONSOLES)
1271 return NULL;
1272 s = g_malloc0(sizeof(QemuConsole));
1273 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1274 (console_type == GRAPHIC_CONSOLE))) {
1275 active_console = s;
1277 s->ds = ds;
1278 s->console_type = console_type;
1279 if (console_type != GRAPHIC_CONSOLE) {
1280 s->index = nb_consoles;
1281 consoles[nb_consoles++] = s;
1282 } else {
1283 /* HACK: Put graphical consoles before text consoles. */
1284 for (i = nb_consoles; i > 0; i--) {
1285 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1286 break;
1287 consoles[i] = consoles[i - 1];
1288 consoles[i]->index = i;
1290 s->index = i;
1291 consoles[i] = s;
1292 nb_consoles++;
1294 return s;
1297 DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
1298 int width, int height)
1300 DisplaySurface *surface = g_new0(DisplaySurface, 1);
1302 int linesize = width * 4;
1303 qemu_alloc_display(surface, width, height, linesize,
1304 qemu_default_pixelformat(32), 0);
1305 return surface;
1308 DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
1309 int width, int height)
1311 int linesize = width * 4;
1313 trace_displaysurface_resize(ds, ds->surface, width, height);
1314 qemu_alloc_display(ds->surface, width, height, linesize,
1315 qemu_default_pixelformat(32), 0);
1316 return ds->surface;
1319 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1320 int linesize, PixelFormat pf, int newflags)
1322 void *data;
1323 surface->width = width;
1324 surface->height = height;
1325 surface->linesize = linesize;
1326 surface->pf = pf;
1327 if (surface->flags & QEMU_ALLOCATED_FLAG) {
1328 data = g_realloc(surface->data,
1329 surface->linesize * surface->height);
1330 } else {
1331 data = g_malloc(surface->linesize * surface->height);
1333 surface->data = (uint8_t *)data;
1334 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1335 #ifdef HOST_WORDS_BIGENDIAN
1336 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1337 #endif
1340 DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
1341 int linesize, uint8_t *data)
1343 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1345 surface->width = width;
1346 surface->height = height;
1347 surface->linesize = linesize;
1348 surface->pf = qemu_default_pixelformat(bpp);
1349 #ifdef HOST_WORDS_BIGENDIAN
1350 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1351 #endif
1352 surface->data = data;
1354 return surface;
1357 void qemu_free_displaysurface(DisplayState *ds)
1359 trace_displaysurface_free(ds, ds->surface);
1360 if (ds->surface == NULL) {
1361 return;
1363 if (ds->surface->flags & QEMU_ALLOCATED_FLAG) {
1364 g_free(ds->surface->data);
1366 g_free(ds->surface);
1369 static void dumb_display_init(void)
1371 DisplayState *ds = g_malloc0(sizeof(DisplayState));
1372 int width = 640;
1373 int height = 480;
1375 if (is_fixedsize_console()) {
1376 width = active_console->g_width;
1377 height = active_console->g_height;
1379 ds->surface = qemu_create_displaysurface(ds, width, height);
1380 register_displaystate(ds);
1383 /***********************************************************/
1384 /* register display */
1386 void register_displaystate(DisplayState *ds)
1388 DisplayState **s;
1389 s = &display_state;
1390 while (*s != NULL)
1391 s = &(*s)->next;
1392 ds->next = NULL;
1393 *s = ds;
1396 DisplayState *get_displaystate(void)
1398 if (!display_state) {
1399 dumb_display_init ();
1401 return display_state;
1404 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1405 vga_hw_invalidate_ptr invalidate,
1406 vga_hw_screen_dump_ptr screen_dump,
1407 vga_hw_text_update_ptr text_update,
1408 void *opaque)
1410 QemuConsole *s;
1411 DisplayState *ds;
1413 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
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 g_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 void text_console_set_echo(CharDriverState *chr, bool echo)
1455 QemuConsole *s = chr->opaque;
1457 s->echo = echo;
1460 static void text_console_update_cursor(void *opaque)
1462 QemuConsole *s = opaque;
1464 s->cursor_visible_phase = !s->cursor_visible_phase;
1465 vga_hw_invalidate();
1466 qemu_mod_timer(s->cursor_timer,
1467 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1470 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1472 QemuConsole *s;
1473 static int color_inited;
1475 s = chr->opaque;
1477 chr->chr_write = console_puts;
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->cursor_timer =
1499 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1501 s->hw_invalidate = text_console_invalidate;
1502 s->hw_text_update = text_console_update;
1503 s->hw = s;
1505 /* Set text attribute defaults */
1506 s->t_attrib_default.bold = 0;
1507 s->t_attrib_default.uline = 0;
1508 s->t_attrib_default.blink = 0;
1509 s->t_attrib_default.invers = 0;
1510 s->t_attrib_default.unvisible = 0;
1511 s->t_attrib_default.fgcol = COLOR_WHITE;
1512 s->t_attrib_default.bgcol = COLOR_BLACK;
1513 /* set current text attributes to default */
1514 s->t_attrib = s->t_attrib_default;
1515 text_console_resize(s);
1517 if (chr->label) {
1518 char msg[128];
1519 int len;
1521 s->t_attrib.bgcol = COLOR_BLUE;
1522 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1523 console_puts(chr, (uint8_t*)msg, len);
1524 s->t_attrib = s->t_attrib_default;
1527 qemu_chr_generic_open(chr);
1528 if (chr->init)
1529 chr->init(chr);
1532 CharDriverState *text_console_init(QemuOpts *opts)
1534 CharDriverState *chr;
1535 QemuConsole *s;
1536 unsigned width;
1537 unsigned height;
1539 chr = g_malloc0(sizeof(CharDriverState));
1541 width = qemu_opt_get_number(opts, "width", 0);
1542 if (width == 0)
1543 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1545 height = qemu_opt_get_number(opts, "height", 0);
1546 if (height == 0)
1547 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1549 if (width == 0 || height == 0) {
1550 s = new_console(NULL, TEXT_CONSOLE);
1551 } else {
1552 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1555 if (!s) {
1556 g_free(chr);
1557 return NULL;
1560 s->chr = chr;
1561 s->g_width = width;
1562 s->g_height = height;
1563 chr->opaque = s;
1564 chr->chr_set_echo = text_console_set_echo;
1565 return chr;
1568 void text_consoles_set_display(DisplayState *ds)
1570 int i;
1572 for (i = 0; i < nb_consoles; i++) {
1573 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1574 text_console_do_init(consoles[i]->chr, ds);
1579 void qemu_console_resize(DisplayState *ds, int width, int height)
1581 QemuConsole *s = get_graphic_console(ds);
1582 if (!s) return;
1584 s->g_width = width;
1585 s->g_height = height;
1586 if (is_graphic_console()) {
1587 ds->surface = qemu_resize_displaysurface(ds, width, height);
1588 dpy_gfx_resize(ds);
1592 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1593 int dst_x, int dst_y, int w, int h)
1595 if (is_graphic_console()) {
1596 dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1600 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1602 PixelFormat pf;
1604 memset(&pf, 0x00, sizeof(PixelFormat));
1606 pf.bits_per_pixel = bpp;
1607 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1608 pf.depth = bpp == 32 ? 24 : bpp;
1610 switch (bpp) {
1611 case 24:
1612 pf.rmask = 0x000000FF;
1613 pf.gmask = 0x0000FF00;
1614 pf.bmask = 0x00FF0000;
1615 pf.rmax = 255;
1616 pf.gmax = 255;
1617 pf.bmax = 255;
1618 pf.rshift = 0;
1619 pf.gshift = 8;
1620 pf.bshift = 16;
1621 pf.rbits = 8;
1622 pf.gbits = 8;
1623 pf.bbits = 8;
1624 break;
1625 case 32:
1626 pf.rmask = 0x0000FF00;
1627 pf.gmask = 0x00FF0000;
1628 pf.bmask = 0xFF000000;
1629 pf.amask = 0x00000000;
1630 pf.amax = 255;
1631 pf.rmax = 255;
1632 pf.gmax = 255;
1633 pf.bmax = 255;
1634 pf.ashift = 0;
1635 pf.rshift = 8;
1636 pf.gshift = 16;
1637 pf.bshift = 24;
1638 pf.rbits = 8;
1639 pf.gbits = 8;
1640 pf.bbits = 8;
1641 pf.abits = 8;
1642 break;
1643 default:
1644 break;
1646 return pf;
1649 PixelFormat qemu_default_pixelformat(int bpp)
1651 PixelFormat pf;
1653 memset(&pf, 0x00, sizeof(PixelFormat));
1655 pf.bits_per_pixel = bpp;
1656 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1657 pf.depth = bpp == 32 ? 24 : bpp;
1659 switch (bpp) {
1660 case 15:
1661 pf.bits_per_pixel = 16;
1662 pf.rmask = 0x00007c00;
1663 pf.gmask = 0x000003E0;
1664 pf.bmask = 0x0000001F;
1665 pf.rmax = 31;
1666 pf.gmax = 31;
1667 pf.bmax = 31;
1668 pf.rshift = 10;
1669 pf.gshift = 5;
1670 pf.bshift = 0;
1671 pf.rbits = 5;
1672 pf.gbits = 5;
1673 pf.bbits = 5;
1674 break;
1675 case 16:
1676 pf.rmask = 0x0000F800;
1677 pf.gmask = 0x000007E0;
1678 pf.bmask = 0x0000001F;
1679 pf.rmax = 31;
1680 pf.gmax = 63;
1681 pf.bmax = 31;
1682 pf.rshift = 11;
1683 pf.gshift = 5;
1684 pf.bshift = 0;
1685 pf.rbits = 5;
1686 pf.gbits = 6;
1687 pf.bbits = 5;
1688 break;
1689 case 24:
1690 pf.rmask = 0x00FF0000;
1691 pf.gmask = 0x0000FF00;
1692 pf.bmask = 0x000000FF;
1693 pf.rmax = 255;
1694 pf.gmax = 255;
1695 pf.bmax = 255;
1696 pf.rshift = 16;
1697 pf.gshift = 8;
1698 pf.bshift = 0;
1699 pf.rbits = 8;
1700 pf.gbits = 8;
1701 pf.bbits = 8;
1702 break;
1703 case 32:
1704 pf.rmask = 0x00FF0000;
1705 pf.gmask = 0x0000FF00;
1706 pf.bmask = 0x000000FF;
1707 pf.amax = 255;
1708 pf.rmax = 255;
1709 pf.gmax = 255;
1710 pf.bmax = 255;
1711 pf.ashift = 24;
1712 pf.rshift = 16;
1713 pf.gshift = 8;
1714 pf.bshift = 0;
1715 pf.rbits = 8;
1716 pf.gbits = 8;
1717 pf.bbits = 8;
1718 pf.abits = 8;
1719 break;
1720 default:
1721 break;
1723 return pf;