Merge remote-tracking branch 'kwolf/for-anthony' into staging
[qemu.git] / console.c
blob6dfcc47940c436fb3d23b6707573b8a9edec79eb
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 int index;
119 console_type_t console_type;
120 DisplayState *ds;
121 /* Graphic console state. */
122 vga_hw_update_ptr hw_update;
123 vga_hw_invalidate_ptr hw_invalidate;
124 vga_hw_screen_dump_ptr hw_screen_dump;
125 vga_hw_text_update_ptr hw_text_update;
126 void *hw;
128 int g_width, g_height;
129 int width;
130 int height;
131 int total_height;
132 int backscroll_height;
133 int x, y;
134 int x_saved, y_saved;
135 int y_displayed;
136 int y_base;
137 TextAttributes t_attrib_default; /* default text attributes */
138 TextAttributes t_attrib; /* currently active text attributes */
139 TextCell *cells;
140 int text_x[2], text_y[2], cursor_invalidate;
141 int echo;
143 int update_x0;
144 int update_y0;
145 int update_x1;
146 int update_y1;
148 enum TTYState state;
149 int esc_params[MAX_ESC_PARAMS];
150 int nb_esc_params;
152 CharDriverState *chr;
153 /* fifo for key pressed */
154 QEMUFIFO out_fifo;
155 uint8_t out_fifo_buf[16];
156 QEMUTimer *kbd_timer;
159 static DisplayState *display_state;
160 static TextConsole *active_console;
161 static TextConsole *consoles[MAX_CONSOLES];
162 static int nb_consoles = 0;
164 void vga_hw_update(void)
166 if (active_console && active_console->hw_update)
167 active_console->hw_update(active_console->hw);
170 void vga_hw_invalidate(void)
172 if (active_console && active_console->hw_invalidate)
173 active_console->hw_invalidate(active_console->hw);
176 void vga_hw_screen_dump(const char *filename)
178 TextConsole *previous_active_console;
180 previous_active_console = active_console;
182 /* There is currently no way of specifying which screen we want to dump,
183 so always dump the first one. */
184 console_select(0);
185 if (consoles[0] && consoles[0]->hw_screen_dump) {
186 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
189 console_select(previous_active_console->index);
192 void vga_hw_text_update(console_ch_t *chardata)
194 if (active_console && active_console->hw_text_update)
195 active_console->hw_text_update(active_console->hw, chardata);
198 /* convert a RGBA color to a color index usable in graphic primitives */
199 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
201 unsigned int r, g, b, color;
203 switch(ds_get_bits_per_pixel(ds)) {
204 #if 0
205 case 8:
206 r = (rgba >> 16) & 0xff;
207 g = (rgba >> 8) & 0xff;
208 b = (rgba) & 0xff;
209 color = (rgb_to_index[r] * 6 * 6) +
210 (rgb_to_index[g] * 6) +
211 (rgb_to_index[b]);
212 break;
213 #endif
214 case 15:
215 r = (rgba >> 16) & 0xff;
216 g = (rgba >> 8) & 0xff;
217 b = (rgba) & 0xff;
218 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
219 break;
220 case 16:
221 r = (rgba >> 16) & 0xff;
222 g = (rgba >> 8) & 0xff;
223 b = (rgba) & 0xff;
224 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
225 break;
226 case 32:
227 default:
228 color = rgba;
229 break;
231 return color;
234 static void vga_fill_rect (DisplayState *ds,
235 int posx, int posy, int width, int height, uint32_t color)
237 uint8_t *d, *d1;
238 int x, y, bpp;
240 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
241 d1 = ds_get_data(ds) +
242 ds_get_linesize(ds) * posy + bpp * posx;
243 for (y = 0; y < height; y++) {
244 d = d1;
245 switch(bpp) {
246 case 1:
247 for (x = 0; x < width; x++) {
248 *((uint8_t *)d) = color;
249 d++;
251 break;
252 case 2:
253 for (x = 0; x < width; x++) {
254 *((uint16_t *)d) = color;
255 d += 2;
257 break;
258 case 4:
259 for (x = 0; x < width; x++) {
260 *((uint32_t *)d) = color;
261 d += 4;
263 break;
265 d1 += ds_get_linesize(ds);
269 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
270 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
272 const uint8_t *s;
273 uint8_t *d;
274 int wb, y, bpp;
276 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
277 wb = w * bpp;
278 if (yd <= ys) {
279 s = ds_get_data(ds) +
280 ds_get_linesize(ds) * ys + bpp * xs;
281 d = ds_get_data(ds) +
282 ds_get_linesize(ds) * yd + bpp * xd;
283 for (y = 0; y < h; y++) {
284 memmove(d, s, wb);
285 d += ds_get_linesize(ds);
286 s += ds_get_linesize(ds);
288 } else {
289 s = ds_get_data(ds) +
290 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
291 d = ds_get_data(ds) +
292 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
293 for (y = 0; y < h; y++) {
294 memmove(d, s, wb);
295 d -= ds_get_linesize(ds);
296 s -= ds_get_linesize(ds);
301 /***********************************************************/
302 /* basic char display */
304 #define FONT_HEIGHT 16
305 #define FONT_WIDTH 8
307 #include "vgafont.h"
309 #define cbswap_32(__x) \
310 ((uint32_t)( \
311 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
312 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
313 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
314 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
316 #ifdef HOST_WORDS_BIGENDIAN
317 #define PAT(x) x
318 #else
319 #define PAT(x) cbswap_32(x)
320 #endif
322 static const uint32_t dmask16[16] = {
323 PAT(0x00000000),
324 PAT(0x000000ff),
325 PAT(0x0000ff00),
326 PAT(0x0000ffff),
327 PAT(0x00ff0000),
328 PAT(0x00ff00ff),
329 PAT(0x00ffff00),
330 PAT(0x00ffffff),
331 PAT(0xff000000),
332 PAT(0xff0000ff),
333 PAT(0xff00ff00),
334 PAT(0xff00ffff),
335 PAT(0xffff0000),
336 PAT(0xffff00ff),
337 PAT(0xffffff00),
338 PAT(0xffffffff),
341 static const uint32_t dmask4[4] = {
342 PAT(0x00000000),
343 PAT(0x0000ffff),
344 PAT(0xffff0000),
345 PAT(0xffffffff),
348 static uint32_t color_table[2][8];
350 #ifndef CONFIG_CURSES
351 enum color_names {
352 COLOR_BLACK = 0,
353 COLOR_RED = 1,
354 COLOR_GREEN = 2,
355 COLOR_YELLOW = 3,
356 COLOR_BLUE = 4,
357 COLOR_MAGENTA = 5,
358 COLOR_CYAN = 6,
359 COLOR_WHITE = 7
361 #endif
363 static const uint32_t color_table_rgb[2][8] = {
364 { /* dark */
365 QEMU_RGB(0x00, 0x00, 0x00), /* black */
366 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
367 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
368 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
369 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
370 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
371 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
372 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
374 { /* bright */
375 QEMU_RGB(0x00, 0x00, 0x00), /* black */
376 QEMU_RGB(0xff, 0x00, 0x00), /* red */
377 QEMU_RGB(0x00, 0xff, 0x00), /* green */
378 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
379 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
380 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
381 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
382 QEMU_RGB(0xff, 0xff, 0xff), /* white */
386 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
388 switch(ds_get_bits_per_pixel(ds)) {
389 case 8:
390 col |= col << 8;
391 col |= col << 16;
392 break;
393 case 15:
394 case 16:
395 col |= col << 16;
396 break;
397 default:
398 break;
401 return col;
403 #ifdef DEBUG_CONSOLE
404 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
406 if (t_attrib->bold) {
407 printf("b");
408 } else {
409 printf(" ");
411 if (t_attrib->uline) {
412 printf("u");
413 } else {
414 printf(" ");
416 if (t_attrib->blink) {
417 printf("l");
418 } else {
419 printf(" ");
421 if (t_attrib->invers) {
422 printf("i");
423 } else {
424 printf(" ");
426 if (t_attrib->unvisible) {
427 printf("n");
428 } else {
429 printf(" ");
432 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
434 #endif
436 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
437 TextAttributes *t_attrib)
439 uint8_t *d;
440 const uint8_t *font_ptr;
441 unsigned int font_data, linesize, xorcol, bpp;
442 int i;
443 unsigned int fgcol, bgcol;
445 #ifdef DEBUG_CONSOLE
446 printf("x: %2i y: %2i", x, y);
447 console_print_text_attributes(t_attrib, ch);
448 #endif
450 if (t_attrib->invers) {
451 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
452 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
453 } else {
454 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
455 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
458 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
459 d = ds_get_data(ds) +
460 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
461 linesize = ds_get_linesize(ds);
462 font_ptr = vgafont16 + FONT_HEIGHT * ch;
463 xorcol = bgcol ^ fgcol;
464 switch(ds_get_bits_per_pixel(ds)) {
465 case 8:
466 for(i = 0; i < FONT_HEIGHT; i++) {
467 font_data = *font_ptr++;
468 if (t_attrib->uline
469 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
470 font_data = 0xFFFF;
472 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
473 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
474 d += linesize;
476 break;
477 case 16:
478 case 15:
479 for(i = 0; i < FONT_HEIGHT; i++) {
480 font_data = *font_ptr++;
481 if (t_attrib->uline
482 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
483 font_data = 0xFFFF;
485 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
486 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
487 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
488 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
489 d += linesize;
491 break;
492 case 32:
493 for(i = 0; i < FONT_HEIGHT; i++) {
494 font_data = *font_ptr++;
495 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
496 font_data = 0xFFFF;
498 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
499 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
500 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
501 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
502 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
503 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
504 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
505 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
506 d += linesize;
508 break;
512 static void text_console_resize(TextConsole *s)
514 TextCell *cells, *c, *c1;
515 int w1, x, y, last_width;
517 last_width = s->width;
518 s->width = s->g_width / FONT_WIDTH;
519 s->height = s->g_height / FONT_HEIGHT;
521 w1 = last_width;
522 if (s->width < w1)
523 w1 = s->width;
525 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
526 for(y = 0; y < s->total_height; y++) {
527 c = &cells[y * s->width];
528 if (w1 > 0) {
529 c1 = &s->cells[y * last_width];
530 for(x = 0; x < w1; x++) {
531 *c++ = *c1++;
534 for(x = w1; x < s->width; x++) {
535 c->ch = ' ';
536 c->t_attrib = s->t_attrib_default;
537 c++;
540 g_free(s->cells);
541 s->cells = cells;
544 static inline void text_update_xy(TextConsole *s, int x, int y)
546 s->text_x[0] = MIN(s->text_x[0], x);
547 s->text_x[1] = MAX(s->text_x[1], x);
548 s->text_y[0] = MIN(s->text_y[0], y);
549 s->text_y[1] = MAX(s->text_y[1], y);
552 static void invalidate_xy(TextConsole *s, int x, int y)
554 if (s->update_x0 > x * FONT_WIDTH)
555 s->update_x0 = x * FONT_WIDTH;
556 if (s->update_y0 > y * FONT_HEIGHT)
557 s->update_y0 = y * FONT_HEIGHT;
558 if (s->update_x1 < (x + 1) * FONT_WIDTH)
559 s->update_x1 = (x + 1) * FONT_WIDTH;
560 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
561 s->update_y1 = (y + 1) * FONT_HEIGHT;
564 static void update_xy(TextConsole *s, int x, int y)
566 TextCell *c;
567 int y1, y2;
569 if (s == active_console) {
570 if (!ds_get_bits_per_pixel(s->ds)) {
571 text_update_xy(s, x, y);
572 return;
575 y1 = (s->y_base + y) % s->total_height;
576 y2 = y1 - s->y_displayed;
577 if (y2 < 0)
578 y2 += s->total_height;
579 if (y2 < s->height) {
580 c = &s->cells[y1 * s->width + x];
581 vga_putcharxy(s->ds, x, y2, c->ch,
582 &(c->t_attrib));
583 invalidate_xy(s, x, y2);
588 static void console_show_cursor(TextConsole *s, int show)
590 TextCell *c;
591 int y, y1;
593 if (s == active_console) {
594 int x = s->x;
596 if (!ds_get_bits_per_pixel(s->ds)) {
597 s->cursor_invalidate = 1;
598 return;
601 if (x >= s->width) {
602 x = s->width - 1;
604 y1 = (s->y_base + s->y) % s->total_height;
605 y = y1 - s->y_displayed;
606 if (y < 0)
607 y += s->total_height;
608 if (y < s->height) {
609 c = &s->cells[y1 * s->width + x];
610 if (show) {
611 TextAttributes t_attrib = s->t_attrib_default;
612 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
613 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
614 } else {
615 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
617 invalidate_xy(s, x, y);
622 static void console_refresh(TextConsole *s)
624 TextCell *c;
625 int x, y, y1;
627 if (s != active_console)
628 return;
629 if (!ds_get_bits_per_pixel(s->ds)) {
630 s->text_x[0] = 0;
631 s->text_y[0] = 0;
632 s->text_x[1] = s->width - 1;
633 s->text_y[1] = s->height - 1;
634 s->cursor_invalidate = 1;
635 return;
638 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
639 color_table[0][COLOR_BLACK]);
640 y1 = s->y_displayed;
641 for(y = 0; y < s->height; y++) {
642 c = s->cells + y1 * s->width;
643 for(x = 0; x < s->width; x++) {
644 vga_putcharxy(s->ds, x, y, c->ch,
645 &(c->t_attrib));
646 c++;
648 if (++y1 == s->total_height)
649 y1 = 0;
651 console_show_cursor(s, 1);
652 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
655 static void console_scroll(int ydelta)
657 TextConsole *s;
658 int i, y1;
660 s = active_console;
661 if (!s || (s->console_type == GRAPHIC_CONSOLE))
662 return;
664 if (ydelta > 0) {
665 for(i = 0; i < ydelta; i++) {
666 if (s->y_displayed == s->y_base)
667 break;
668 if (++s->y_displayed == s->total_height)
669 s->y_displayed = 0;
671 } else {
672 ydelta = -ydelta;
673 i = s->backscroll_height;
674 if (i > s->total_height - s->height)
675 i = s->total_height - s->height;
676 y1 = s->y_base - i;
677 if (y1 < 0)
678 y1 += s->total_height;
679 for(i = 0; i < ydelta; i++) {
680 if (s->y_displayed == y1)
681 break;
682 if (--s->y_displayed < 0)
683 s->y_displayed = s->total_height - 1;
686 console_refresh(s);
689 static void console_put_lf(TextConsole *s)
691 TextCell *c;
692 int x, y1;
694 s->y++;
695 if (s->y >= s->height) {
696 s->y = s->height - 1;
698 if (s->y_displayed == s->y_base) {
699 if (++s->y_displayed == s->total_height)
700 s->y_displayed = 0;
702 if (++s->y_base == s->total_height)
703 s->y_base = 0;
704 if (s->backscroll_height < s->total_height)
705 s->backscroll_height++;
706 y1 = (s->y_base + s->height - 1) % s->total_height;
707 c = &s->cells[y1 * s->width];
708 for(x = 0; x < s->width; x++) {
709 c->ch = ' ';
710 c->t_attrib = s->t_attrib_default;
711 c++;
713 if (s == active_console && s->y_displayed == s->y_base) {
714 if (!ds_get_bits_per_pixel(s->ds)) {
715 s->text_x[0] = 0;
716 s->text_y[0] = 0;
717 s->text_x[1] = s->width - 1;
718 s->text_y[1] = s->height - 1;
719 return;
722 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
723 s->width * FONT_WIDTH,
724 (s->height - 1) * FONT_HEIGHT);
725 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
726 s->width * FONT_WIDTH, FONT_HEIGHT,
727 color_table[0][s->t_attrib_default.bgcol]);
728 s->update_x0 = 0;
729 s->update_y0 = 0;
730 s->update_x1 = s->width * FONT_WIDTH;
731 s->update_y1 = s->height * FONT_HEIGHT;
736 /* Set console attributes depending on the current escape codes.
737 * NOTE: I know this code is not very efficient (checking every color for it
738 * self) but it is more readable and better maintainable.
740 static void console_handle_escape(TextConsole *s)
742 int i;
744 for (i=0; i<s->nb_esc_params; i++) {
745 switch (s->esc_params[i]) {
746 case 0: /* reset all console attributes to default */
747 s->t_attrib = s->t_attrib_default;
748 break;
749 case 1:
750 s->t_attrib.bold = 1;
751 break;
752 case 4:
753 s->t_attrib.uline = 1;
754 break;
755 case 5:
756 s->t_attrib.blink = 1;
757 break;
758 case 7:
759 s->t_attrib.invers = 1;
760 break;
761 case 8:
762 s->t_attrib.unvisible = 1;
763 break;
764 case 22:
765 s->t_attrib.bold = 0;
766 break;
767 case 24:
768 s->t_attrib.uline = 0;
769 break;
770 case 25:
771 s->t_attrib.blink = 0;
772 break;
773 case 27:
774 s->t_attrib.invers = 0;
775 break;
776 case 28:
777 s->t_attrib.unvisible = 0;
778 break;
779 /* set foreground color */
780 case 30:
781 s->t_attrib.fgcol=COLOR_BLACK;
782 break;
783 case 31:
784 s->t_attrib.fgcol=COLOR_RED;
785 break;
786 case 32:
787 s->t_attrib.fgcol=COLOR_GREEN;
788 break;
789 case 33:
790 s->t_attrib.fgcol=COLOR_YELLOW;
791 break;
792 case 34:
793 s->t_attrib.fgcol=COLOR_BLUE;
794 break;
795 case 35:
796 s->t_attrib.fgcol=COLOR_MAGENTA;
797 break;
798 case 36:
799 s->t_attrib.fgcol=COLOR_CYAN;
800 break;
801 case 37:
802 s->t_attrib.fgcol=COLOR_WHITE;
803 break;
804 /* set background color */
805 case 40:
806 s->t_attrib.bgcol=COLOR_BLACK;
807 break;
808 case 41:
809 s->t_attrib.bgcol=COLOR_RED;
810 break;
811 case 42:
812 s->t_attrib.bgcol=COLOR_GREEN;
813 break;
814 case 43:
815 s->t_attrib.bgcol=COLOR_YELLOW;
816 break;
817 case 44:
818 s->t_attrib.bgcol=COLOR_BLUE;
819 break;
820 case 45:
821 s->t_attrib.bgcol=COLOR_MAGENTA;
822 break;
823 case 46:
824 s->t_attrib.bgcol=COLOR_CYAN;
825 break;
826 case 47:
827 s->t_attrib.bgcol=COLOR_WHITE;
828 break;
833 static void console_clear_xy(TextConsole *s, int x, int y)
835 int y1 = (s->y_base + y) % s->total_height;
836 TextCell *c = &s->cells[y1 * s->width + x];
837 c->ch = ' ';
838 c->t_attrib = s->t_attrib_default;
839 update_xy(s, x, y);
842 static void console_putchar(TextConsole *s, int ch)
844 TextCell *c;
845 int y1, i;
846 int x, y;
848 switch(s->state) {
849 case TTY_STATE_NORM:
850 switch(ch) {
851 case '\r': /* carriage return */
852 s->x = 0;
853 break;
854 case '\n': /* newline */
855 console_put_lf(s);
856 break;
857 case '\b': /* backspace */
858 if (s->x > 0)
859 s->x--;
860 break;
861 case '\t': /* tabspace */
862 if (s->x + (8 - (s->x % 8)) > s->width) {
863 s->x = 0;
864 console_put_lf(s);
865 } else {
866 s->x = s->x + (8 - (s->x % 8));
868 break;
869 case '\a': /* alert aka. bell */
870 /* TODO: has to be implemented */
871 break;
872 case 14:
873 /* SI (shift in), character set 0 (ignored) */
874 break;
875 case 15:
876 /* SO (shift out), character set 1 (ignored) */
877 break;
878 case 27: /* esc (introducing an escape sequence) */
879 s->state = TTY_STATE_ESC;
880 break;
881 default:
882 if (s->x >= s->width) {
883 /* line wrap */
884 s->x = 0;
885 console_put_lf(s);
887 y1 = (s->y_base + s->y) % s->total_height;
888 c = &s->cells[y1 * s->width + s->x];
889 c->ch = ch;
890 c->t_attrib = s->t_attrib;
891 update_xy(s, s->x, s->y);
892 s->x++;
893 break;
895 break;
896 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
897 if (ch == '[') {
898 for(i=0;i<MAX_ESC_PARAMS;i++)
899 s->esc_params[i] = 0;
900 s->nb_esc_params = 0;
901 s->state = TTY_STATE_CSI;
902 } else {
903 s->state = TTY_STATE_NORM;
905 break;
906 case TTY_STATE_CSI: /* handle escape sequence parameters */
907 if (ch >= '0' && ch <= '9') {
908 if (s->nb_esc_params < MAX_ESC_PARAMS) {
909 s->esc_params[s->nb_esc_params] =
910 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
912 } else {
913 s->nb_esc_params++;
914 if (ch == ';')
915 break;
916 #ifdef DEBUG_CONSOLE
917 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
918 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
919 #endif
920 s->state = TTY_STATE_NORM;
921 switch(ch) {
922 case 'A':
923 /* move cursor up */
924 if (s->esc_params[0] == 0) {
925 s->esc_params[0] = 1;
927 s->y -= s->esc_params[0];
928 if (s->y < 0) {
929 s->y = 0;
931 break;
932 case 'B':
933 /* move cursor down */
934 if (s->esc_params[0] == 0) {
935 s->esc_params[0] = 1;
937 s->y += s->esc_params[0];
938 if (s->y >= s->height) {
939 s->y = s->height - 1;
941 break;
942 case 'C':
943 /* move cursor right */
944 if (s->esc_params[0] == 0) {
945 s->esc_params[0] = 1;
947 s->x += s->esc_params[0];
948 if (s->x >= s->width) {
949 s->x = s->width - 1;
951 break;
952 case 'D':
953 /* move cursor left */
954 if (s->esc_params[0] == 0) {
955 s->esc_params[0] = 1;
957 s->x -= s->esc_params[0];
958 if (s->x < 0) {
959 s->x = 0;
961 break;
962 case 'G':
963 /* move cursor to column */
964 s->x = s->esc_params[0] - 1;
965 if (s->x < 0) {
966 s->x = 0;
968 break;
969 case 'f':
970 case 'H':
971 /* move cursor to row, column */
972 s->x = s->esc_params[1] - 1;
973 if (s->x < 0) {
974 s->x = 0;
976 s->y = s->esc_params[0] - 1;
977 if (s->y < 0) {
978 s->y = 0;
980 break;
981 case 'J':
982 switch (s->esc_params[0]) {
983 case 0:
984 /* clear to end of screen */
985 for (y = s->y; y < s->height; y++) {
986 for (x = 0; x < s->width; x++) {
987 if (y == s->y && x < s->x) {
988 continue;
990 console_clear_xy(s, x, y);
993 break;
994 case 1:
995 /* clear from beginning of screen */
996 for (y = 0; y <= s->y; y++) {
997 for (x = 0; x < s->width; x++) {
998 if (y == s->y && x > s->x) {
999 break;
1001 console_clear_xy(s, x, y);
1004 break;
1005 case 2:
1006 /* clear entire screen */
1007 for (y = 0; y <= s->height; y++) {
1008 for (x = 0; x < s->width; x++) {
1009 console_clear_xy(s, x, y);
1012 break;
1014 case 'K':
1015 switch (s->esc_params[0]) {
1016 case 0:
1017 /* clear to eol */
1018 for(x = s->x; x < s->width; x++) {
1019 console_clear_xy(s, x, s->y);
1021 break;
1022 case 1:
1023 /* clear from beginning of line */
1024 for (x = 0; x <= s->x; x++) {
1025 console_clear_xy(s, x, s->y);
1027 break;
1028 case 2:
1029 /* clear entire line */
1030 for(x = 0; x < s->width; x++) {
1031 console_clear_xy(s, x, s->y);
1033 break;
1035 break;
1036 case 'm':
1037 console_handle_escape(s);
1038 break;
1039 case 'n':
1040 /* report cursor position */
1041 /* TODO: send ESC[row;colR */
1042 break;
1043 case 's':
1044 /* save cursor position */
1045 s->x_saved = s->x;
1046 s->y_saved = s->y;
1047 break;
1048 case 'u':
1049 /* restore cursor position */
1050 s->x = s->x_saved;
1051 s->y = s->y_saved;
1052 break;
1053 default:
1054 #ifdef DEBUG_CONSOLE
1055 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1056 #endif
1057 break;
1059 break;
1064 void console_select(unsigned int index)
1066 TextConsole *s;
1068 if (index >= MAX_CONSOLES)
1069 return;
1070 if (active_console) {
1071 active_console->g_width = ds_get_width(active_console->ds);
1072 active_console->g_height = ds_get_height(active_console->ds);
1074 s = consoles[index];
1075 if (s) {
1076 DisplayState *ds = s->ds;
1077 active_console = s;
1078 if (ds_get_bits_per_pixel(s->ds)) {
1079 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1080 } else {
1081 s->ds->surface->width = s->width;
1082 s->ds->surface->height = s->height;
1084 dpy_resize(s->ds);
1085 vga_hw_invalidate();
1089 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1091 TextConsole *s = chr->opaque;
1092 int i;
1094 s->update_x0 = s->width * FONT_WIDTH;
1095 s->update_y0 = s->height * FONT_HEIGHT;
1096 s->update_x1 = 0;
1097 s->update_y1 = 0;
1098 console_show_cursor(s, 0);
1099 for(i = 0; i < len; i++) {
1100 console_putchar(s, buf[i]);
1102 console_show_cursor(s, 1);
1103 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1104 dpy_update(s->ds, s->update_x0, s->update_y0,
1105 s->update_x1 - s->update_x0,
1106 s->update_y1 - s->update_y0);
1108 return len;
1111 static void kbd_send_chars(void *opaque)
1113 TextConsole *s = opaque;
1114 int len;
1115 uint8_t buf[16];
1117 len = qemu_chr_be_can_write(s->chr);
1118 if (len > s->out_fifo.count)
1119 len = s->out_fifo.count;
1120 if (len > 0) {
1121 if (len > sizeof(buf))
1122 len = sizeof(buf);
1123 qemu_fifo_read(&s->out_fifo, buf, len);
1124 qemu_chr_be_write(s->chr, buf, len);
1126 /* characters are pending: we send them a bit later (XXX:
1127 horrible, should change char device API) */
1128 if (s->out_fifo.count > 0) {
1129 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1133 /* called when an ascii key is pressed */
1134 void kbd_put_keysym(int keysym)
1136 TextConsole *s;
1137 uint8_t buf[16], *q;
1138 int c;
1140 s = active_console;
1141 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1142 return;
1144 switch(keysym) {
1145 case QEMU_KEY_CTRL_UP:
1146 console_scroll(-1);
1147 break;
1148 case QEMU_KEY_CTRL_DOWN:
1149 console_scroll(1);
1150 break;
1151 case QEMU_KEY_CTRL_PAGEUP:
1152 console_scroll(-10);
1153 break;
1154 case QEMU_KEY_CTRL_PAGEDOWN:
1155 console_scroll(10);
1156 break;
1157 default:
1158 /* convert the QEMU keysym to VT100 key string */
1159 q = buf;
1160 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1161 *q++ = '\033';
1162 *q++ = '[';
1163 c = keysym - 0xe100;
1164 if (c >= 10)
1165 *q++ = '0' + (c / 10);
1166 *q++ = '0' + (c % 10);
1167 *q++ = '~';
1168 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1169 *q++ = '\033';
1170 *q++ = '[';
1171 *q++ = keysym & 0xff;
1172 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1173 console_puts(s->chr, (const uint8_t *) "\r", 1);
1174 *q++ = '\n';
1175 } else {
1176 *q++ = keysym;
1178 if (s->echo) {
1179 console_puts(s->chr, buf, q - buf);
1181 if (s->chr->chr_read) {
1182 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1183 kbd_send_chars(s);
1185 break;
1189 static void text_console_invalidate(void *opaque)
1191 TextConsole *s = (TextConsole *) opaque;
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);
1197 console_refresh(s);
1200 static void text_console_update(void *opaque, console_ch_t *chardata)
1202 TextConsole *s = (TextConsole *) opaque;
1203 int i, j, src;
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;
1221 if (s->cursor_invalidate) {
1222 dpy_cursor(s->ds, s->x, s->y);
1223 s->cursor_invalidate = 0;
1227 static TextConsole *get_graphic_console(DisplayState *ds)
1229 int i;
1230 TextConsole *s;
1231 for (i = 0; i < nb_consoles; i++) {
1232 s = consoles[i];
1233 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1234 return s;
1236 return NULL;
1239 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1241 TextConsole *s;
1242 int i;
1244 if (nb_consoles >= MAX_CONSOLES)
1245 return NULL;
1246 s = g_malloc0(sizeof(TextConsole));
1247 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1248 (console_type == GRAPHIC_CONSOLE))) {
1249 active_console = s;
1251 s->ds = ds;
1252 s->console_type = console_type;
1253 if (console_type != GRAPHIC_CONSOLE) {
1254 s->index = nb_consoles;
1255 consoles[nb_consoles++] = s;
1256 } else {
1257 /* HACK: Put graphical consoles before text consoles. */
1258 for (i = nb_consoles; i > 0; i--) {
1259 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1260 break;
1261 consoles[i] = consoles[i - 1];
1262 consoles[i]->index = i;
1264 s->index = i;
1265 consoles[i] = s;
1266 nb_consoles++;
1268 return s;
1271 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1273 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1275 int linesize = width * 4;
1276 qemu_alloc_display(surface, width, height, linesize,
1277 qemu_default_pixelformat(32), 0);
1278 return surface;
1281 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1282 int width, int height)
1284 int linesize = width * 4;
1285 qemu_alloc_display(surface, width, height, linesize,
1286 qemu_default_pixelformat(32), 0);
1287 return surface;
1290 void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1291 int linesize, PixelFormat pf, int newflags)
1293 void *data;
1294 surface->width = width;
1295 surface->height = height;
1296 surface->linesize = linesize;
1297 surface->pf = pf;
1298 if (surface->flags & QEMU_ALLOCATED_FLAG) {
1299 data = g_realloc(surface->data,
1300 surface->linesize * surface->height);
1301 } else {
1302 data = g_malloc(surface->linesize * surface->height);
1304 surface->data = (uint8_t *)data;
1305 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1306 #ifdef HOST_WORDS_BIGENDIAN
1307 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1308 #endif
1311 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1312 int linesize, uint8_t *data)
1314 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1316 surface->width = width;
1317 surface->height = height;
1318 surface->linesize = linesize;
1319 surface->pf = qemu_default_pixelformat(bpp);
1320 #ifdef HOST_WORDS_BIGENDIAN
1321 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1322 #endif
1323 surface->data = data;
1325 return surface;
1328 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1330 if (surface == NULL)
1331 return;
1332 if (surface->flags & QEMU_ALLOCATED_FLAG)
1333 g_free(surface->data);
1334 g_free(surface);
1337 static struct DisplayAllocator default_allocator = {
1338 defaultallocator_create_displaysurface,
1339 defaultallocator_resize_displaysurface,
1340 defaultallocator_free_displaysurface
1343 static void dumb_display_init(void)
1345 DisplayState *ds = g_malloc0(sizeof(DisplayState));
1346 int width = 640;
1347 int height = 480;
1349 ds->allocator = &default_allocator;
1350 if (is_fixedsize_console()) {
1351 width = active_console->g_width;
1352 height = active_console->g_height;
1354 ds->surface = qemu_create_displaysurface(ds, width, height);
1355 register_displaystate(ds);
1358 /***********************************************************/
1359 /* register display */
1361 void register_displaystate(DisplayState *ds)
1363 DisplayState **s;
1364 s = &display_state;
1365 while (*s != NULL)
1366 s = &(*s)->next;
1367 ds->next = NULL;
1368 *s = ds;
1371 DisplayState *get_displaystate(void)
1373 if (!display_state) {
1374 dumb_display_init ();
1376 return display_state;
1379 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1381 if(ds->allocator == &default_allocator) {
1382 DisplaySurface *surf;
1383 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1384 defaultallocator_free_displaysurface(ds->surface);
1385 ds->surface = surf;
1386 ds->allocator = da;
1388 return ds->allocator;
1391 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1392 vga_hw_invalidate_ptr invalidate,
1393 vga_hw_screen_dump_ptr screen_dump,
1394 vga_hw_text_update_ptr text_update,
1395 void *opaque)
1397 TextConsole *s;
1398 DisplayState *ds;
1400 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1401 ds->allocator = &default_allocator;
1402 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1404 s = new_console(ds, GRAPHIC_CONSOLE);
1405 if (s == NULL) {
1406 qemu_free_displaysurface(ds);
1407 g_free(ds);
1408 return NULL;
1410 s->hw_update = update;
1411 s->hw_invalidate = invalidate;
1412 s->hw_screen_dump = screen_dump;
1413 s->hw_text_update = text_update;
1414 s->hw = opaque;
1416 register_displaystate(ds);
1417 return ds;
1420 int is_graphic_console(void)
1422 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1425 int is_fixedsize_console(void)
1427 return active_console && active_console->console_type != TEXT_CONSOLE;
1430 void console_color_init(DisplayState *ds)
1432 int i, j;
1433 for (j = 0; j < 2; j++) {
1434 for (i = 0; i < 8; i++) {
1435 color_table[j][i] = col_expand(ds,
1436 vga_get_color(ds, color_table_rgb[j][i]));
1441 static int n_text_consoles;
1442 static CharDriverState *text_consoles[128];
1444 static void text_console_set_echo(CharDriverState *chr, bool echo)
1446 TextConsole *s = chr->opaque;
1448 s->echo = echo;
1451 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1453 TextConsole *s;
1454 static int color_inited;
1456 s = chr->opaque;
1458 chr->chr_write = console_puts;
1460 s->out_fifo.buf = s->out_fifo_buf;
1461 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1462 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1463 s->ds = ds;
1465 if (!color_inited) {
1466 color_inited = 1;
1467 console_color_init(s->ds);
1469 s->y_displayed = 0;
1470 s->y_base = 0;
1471 s->total_height = DEFAULT_BACKSCROLL;
1472 s->x = 0;
1473 s->y = 0;
1474 if (s->console_type == TEXT_CONSOLE) {
1475 s->g_width = ds_get_width(s->ds);
1476 s->g_height = ds_get_height(s->ds);
1479 s->hw_invalidate = text_console_invalidate;
1480 s->hw_text_update = text_console_update;
1481 s->hw = s;
1483 /* Set text attribute defaults */
1484 s->t_attrib_default.bold = 0;
1485 s->t_attrib_default.uline = 0;
1486 s->t_attrib_default.blink = 0;
1487 s->t_attrib_default.invers = 0;
1488 s->t_attrib_default.unvisible = 0;
1489 s->t_attrib_default.fgcol = COLOR_WHITE;
1490 s->t_attrib_default.bgcol = COLOR_BLACK;
1491 /* set current text attributes to default */
1492 s->t_attrib = s->t_attrib_default;
1493 text_console_resize(s);
1495 if (chr->label) {
1496 char msg[128];
1497 int len;
1499 s->t_attrib.bgcol = COLOR_BLUE;
1500 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1501 console_puts(chr, (uint8_t*)msg, len);
1502 s->t_attrib = s->t_attrib_default;
1505 qemu_chr_generic_open(chr);
1506 if (chr->init)
1507 chr->init(chr);
1510 int text_console_init(QemuOpts *opts, CharDriverState **_chr)
1512 CharDriverState *chr;
1513 TextConsole *s;
1514 unsigned width;
1515 unsigned height;
1517 chr = g_malloc0(sizeof(CharDriverState));
1519 if (n_text_consoles == 128) {
1520 fprintf(stderr, "Too many text consoles\n");
1521 exit(1);
1523 text_consoles[n_text_consoles] = chr;
1524 n_text_consoles++;
1526 width = qemu_opt_get_number(opts, "width", 0);
1527 if (width == 0)
1528 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1530 height = qemu_opt_get_number(opts, "height", 0);
1531 if (height == 0)
1532 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1534 if (width == 0 || height == 0) {
1535 s = new_console(NULL, TEXT_CONSOLE);
1536 } else {
1537 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1540 if (!s) {
1541 free(chr);
1542 return -EBUSY;
1545 s->chr = chr;
1546 s->g_width = width;
1547 s->g_height = height;
1548 chr->opaque = s;
1549 chr->chr_set_echo = text_console_set_echo;
1551 *_chr = chr;
1552 return 0;
1555 void text_consoles_set_display(DisplayState *ds)
1557 int i;
1559 for (i = 0; i < n_text_consoles; i++) {
1560 text_console_do_init(text_consoles[i], ds);
1563 n_text_consoles = 0;
1566 void qemu_console_resize(DisplayState *ds, int width, int height)
1568 TextConsole *s = get_graphic_console(ds);
1569 if (!s) return;
1571 s->g_width = width;
1572 s->g_height = height;
1573 if (is_graphic_console()) {
1574 ds->surface = qemu_resize_displaysurface(ds, width, height);
1575 dpy_resize(ds);
1579 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1580 int dst_x, int dst_y, int w, int h)
1582 if (is_graphic_console()) {
1583 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1587 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1589 PixelFormat pf;
1591 memset(&pf, 0x00, sizeof(PixelFormat));
1593 pf.bits_per_pixel = bpp;
1594 pf.bytes_per_pixel = bpp / 8;
1595 pf.depth = bpp == 32 ? 24 : bpp;
1597 switch (bpp) {
1598 case 24:
1599 pf.rmask = 0x000000FF;
1600 pf.gmask = 0x0000FF00;
1601 pf.bmask = 0x00FF0000;
1602 pf.rmax = 255;
1603 pf.gmax = 255;
1604 pf.bmax = 255;
1605 pf.rshift = 0;
1606 pf.gshift = 8;
1607 pf.bshift = 16;
1608 pf.rbits = 8;
1609 pf.gbits = 8;
1610 pf.bbits = 8;
1611 break;
1612 case 32:
1613 pf.rmask = 0x0000FF00;
1614 pf.gmask = 0x00FF0000;
1615 pf.bmask = 0xFF000000;
1616 pf.amask = 0x00000000;
1617 pf.amax = 255;
1618 pf.rmax = 255;
1619 pf.gmax = 255;
1620 pf.bmax = 255;
1621 pf.ashift = 0;
1622 pf.rshift = 8;
1623 pf.gshift = 16;
1624 pf.bshift = 24;
1625 pf.rbits = 8;
1626 pf.gbits = 8;
1627 pf.bbits = 8;
1628 pf.abits = 8;
1629 break;
1630 default:
1631 break;
1633 return pf;
1636 PixelFormat qemu_default_pixelformat(int bpp)
1638 PixelFormat pf;
1640 memset(&pf, 0x00, sizeof(PixelFormat));
1642 pf.bits_per_pixel = bpp;
1643 pf.bytes_per_pixel = bpp / 8;
1644 pf.depth = bpp == 32 ? 24 : bpp;
1646 switch (bpp) {
1647 case 15:
1648 pf.bits_per_pixel = 16;
1649 pf.bytes_per_pixel = 2;
1650 pf.rmask = 0x00007c00;
1651 pf.gmask = 0x000003E0;
1652 pf.bmask = 0x0000001F;
1653 pf.rmax = 31;
1654 pf.gmax = 31;
1655 pf.bmax = 31;
1656 pf.rshift = 10;
1657 pf.gshift = 5;
1658 pf.bshift = 0;
1659 pf.rbits = 5;
1660 pf.gbits = 5;
1661 pf.bbits = 5;
1662 break;
1663 case 16:
1664 pf.rmask = 0x0000F800;
1665 pf.gmask = 0x000007E0;
1666 pf.bmask = 0x0000001F;
1667 pf.rmax = 31;
1668 pf.gmax = 63;
1669 pf.bmax = 31;
1670 pf.rshift = 11;
1671 pf.gshift = 5;
1672 pf.bshift = 0;
1673 pf.rbits = 5;
1674 pf.gbits = 6;
1675 pf.bbits = 5;
1676 break;
1677 case 24:
1678 pf.rmask = 0x00FF0000;
1679 pf.gmask = 0x0000FF00;
1680 pf.bmask = 0x000000FF;
1681 pf.rmax = 255;
1682 pf.gmax = 255;
1683 pf.bmax = 255;
1684 pf.rshift = 16;
1685 pf.gshift = 8;
1686 pf.bshift = 0;
1687 pf.rbits = 8;
1688 pf.gbits = 8;
1689 pf.bbits = 8;
1690 case 32:
1691 pf.rmask = 0x00FF0000;
1692 pf.gmask = 0x0000FF00;
1693 pf.bmask = 0x000000FF;
1694 pf.amax = 255;
1695 pf.rmax = 255;
1696 pf.gmax = 255;
1697 pf.bmax = 255;
1698 pf.ashift = 24;
1699 pf.rshift = 16;
1700 pf.gshift = 8;
1701 pf.bshift = 0;
1702 pf.rbits = 8;
1703 pf.gbits = 8;
1704 pf.bbits = 8;
1705 pf.abits = 8;
1706 break;
1707 default:
1708 break;
1710 return pf;