vnc fixes and improvements (Stefano Stabellini)
[qemu/mini2440/sniper_sniper_test.git] / console.c
blob68ac970654fe9ec1df5b906d252cd06cfa710bc9
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
31 #define DEFAULT_MONITOR_SIZE "800x600"
33 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
34 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
36 typedef struct TextAttributes {
37 uint8_t fgcol:4;
38 uint8_t bgcol:4;
39 uint8_t bold:1;
40 uint8_t uline:1;
41 uint8_t blink:1;
42 uint8_t invers:1;
43 uint8_t unvisible:1;
44 } TextAttributes;
46 typedef struct TextCell {
47 uint8_t ch;
48 TextAttributes t_attrib;
49 } TextCell;
51 #define MAX_ESC_PARAMS 3
53 enum TTYState {
54 TTY_STATE_NORM,
55 TTY_STATE_ESC,
56 TTY_STATE_CSI,
59 typedef struct QEMUFIFO {
60 uint8_t *buf;
61 int buf_size;
62 int count, wptr, rptr;
63 } QEMUFIFO;
65 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
67 int l, len;
69 l = f->buf_size - f->count;
70 if (len1 > l)
71 len1 = l;
72 len = len1;
73 while (len > 0) {
74 l = f->buf_size - f->wptr;
75 if (l > len)
76 l = len;
77 memcpy(f->buf + f->wptr, buf, l);
78 f->wptr += l;
79 if (f->wptr >= f->buf_size)
80 f->wptr = 0;
81 buf += l;
82 len -= l;
84 f->count += len1;
85 return len1;
88 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
90 int l, len;
92 if (len1 > f->count)
93 len1 = f->count;
94 len = len1;
95 while (len > 0) {
96 l = f->buf_size - f->rptr;
97 if (l > len)
98 l = len;
99 memcpy(buf, f->buf + f->rptr, l);
100 f->rptr += l;
101 if (f->rptr >= f->buf_size)
102 f->rptr = 0;
103 buf += l;
104 len -= l;
106 f->count -= len1;
107 return len1;
110 typedef enum {
111 GRAPHIC_CONSOLE,
112 TEXT_CONSOLE,
113 TEXT_CONSOLE_FIXED_SIZE
114 } console_type_t;
116 /* ??? This is mis-named.
117 It is used for both text and graphical consoles. */
118 struct TextConsole {
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;
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 TextConsole *active_console;
159 static TextConsole *consoles[MAX_CONSOLES];
160 static int nb_consoles = 0;
162 void vga_hw_update(void)
164 if (active_console && active_console->hw_update)
165 active_console->hw_update(active_console->hw);
168 void vga_hw_invalidate(void)
170 if (active_console->hw_invalidate)
171 active_console->hw_invalidate(active_console->hw);
174 void vga_hw_screen_dump(const char *filename)
176 TextConsole *previous_active_console;
178 previous_active_console = active_console;
179 active_console = consoles[0];
180 /* There is currently no way of specifying which screen we want to dump,
181 so always dump the first one. */
182 if (consoles[0]->hw_screen_dump)
183 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
184 active_console = previous_active_console;
187 void vga_hw_text_update(console_ch_t *chardata)
189 if (active_console && active_console->hw_text_update)
190 active_console->hw_text_update(active_console->hw, chardata);
193 /* convert a RGBA color to a color index usable in graphic primitives */
194 static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
196 unsigned int r, g, b, color;
198 switch(ds_get_bits_per_pixel(ds)) {
199 #if 0
200 case 8:
201 r = (rgba >> 16) & 0xff;
202 g = (rgba >> 8) & 0xff;
203 b = (rgba) & 0xff;
204 color = (rgb_to_index[r] * 6 * 6) +
205 (rgb_to_index[g] * 6) +
206 (rgb_to_index[b]);
207 break;
208 #endif
209 case 15:
210 r = (rgba >> 16) & 0xff;
211 g = (rgba >> 8) & 0xff;
212 b = (rgba) & 0xff;
213 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
214 break;
215 case 16:
216 r = (rgba >> 16) & 0xff;
217 g = (rgba >> 8) & 0xff;
218 b = (rgba) & 0xff;
219 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
220 break;
221 case 32:
222 default:
223 color = rgba;
224 break;
226 return color;
229 static void vga_fill_rect (DisplayState *ds,
230 int posx, int posy, int width, int height, uint32_t color)
232 uint8_t *d, *d1;
233 int x, y, bpp;
235 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
236 d1 = ds_get_data(ds) +
237 ds_get_linesize(ds) * posy + bpp * posx;
238 for (y = 0; y < height; y++) {
239 d = d1;
240 switch(bpp) {
241 case 1:
242 for (x = 0; x < width; x++) {
243 *((uint8_t *)d) = color;
244 d++;
246 break;
247 case 2:
248 for (x = 0; x < width; x++) {
249 *((uint16_t *)d) = color;
250 d += 2;
252 break;
253 case 4:
254 for (x = 0; x < width; x++) {
255 *((uint32_t *)d) = color;
256 d += 4;
258 break;
260 d1 += ds_get_linesize(ds);
264 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
265 static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
267 const uint8_t *s;
268 uint8_t *d;
269 int wb, y, bpp;
271 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
272 wb = w * bpp;
273 if (yd <= ys) {
274 s = ds_get_data(ds) +
275 ds_get_linesize(ds) * ys + bpp * xs;
276 d = ds_get_data(ds) +
277 ds_get_linesize(ds) * yd + bpp * xd;
278 for (y = 0; y < h; y++) {
279 memmove(d, s, wb);
280 d += ds_get_linesize(ds);
281 s += ds_get_linesize(ds);
283 } else {
284 s = ds_get_data(ds) +
285 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
286 d = ds_get_data(ds) +
287 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
288 for (y = 0; y < h; y++) {
289 memmove(d, s, wb);
290 d -= ds_get_linesize(ds);
291 s -= ds_get_linesize(ds);
296 /***********************************************************/
297 /* basic char display */
299 #define FONT_HEIGHT 16
300 #define FONT_WIDTH 8
302 #include "vgafont.h"
304 #define cbswap_32(__x) \
305 ((uint32_t)( \
306 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
307 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
308 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
309 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
311 #ifdef WORDS_BIGENDIAN
312 #define PAT(x) x
313 #else
314 #define PAT(x) cbswap_32(x)
315 #endif
317 static const uint32_t dmask16[16] = {
318 PAT(0x00000000),
319 PAT(0x000000ff),
320 PAT(0x0000ff00),
321 PAT(0x0000ffff),
322 PAT(0x00ff0000),
323 PAT(0x00ff00ff),
324 PAT(0x00ffff00),
325 PAT(0x00ffffff),
326 PAT(0xff000000),
327 PAT(0xff0000ff),
328 PAT(0xff00ff00),
329 PAT(0xff00ffff),
330 PAT(0xffff0000),
331 PAT(0xffff00ff),
332 PAT(0xffffff00),
333 PAT(0xffffffff),
336 static const uint32_t dmask4[4] = {
337 PAT(0x00000000),
338 PAT(0x0000ffff),
339 PAT(0xffff0000),
340 PAT(0xffffffff),
343 static uint32_t color_table[2][8];
345 enum color_names {
346 COLOR_BLACK = 0,
347 COLOR_RED = 1,
348 COLOR_GREEN = 2,
349 COLOR_YELLOW = 3,
350 COLOR_BLUE = 4,
351 COLOR_MAGENTA = 5,
352 COLOR_CYAN = 6,
353 COLOR_WHITE = 7
356 static const uint32_t color_table_rgb[2][8] = {
357 { /* dark */
358 QEMU_RGB(0x00, 0x00, 0x00), /* black */
359 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
360 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
361 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
362 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
363 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
364 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
365 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
367 { /* bright */
368 QEMU_RGB(0x00, 0x00, 0x00), /* black */
369 QEMU_RGB(0xff, 0x00, 0x00), /* red */
370 QEMU_RGB(0x00, 0xff, 0x00), /* green */
371 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
372 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
373 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
374 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
375 QEMU_RGB(0xff, 0xff, 0xff), /* white */
379 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
381 switch(ds_get_bits_per_pixel(ds)) {
382 case 8:
383 col |= col << 8;
384 col |= col << 16;
385 break;
386 case 15:
387 case 16:
388 col |= col << 16;
389 break;
390 default:
391 break;
394 return col;
396 #ifdef DEBUG_CONSOLE
397 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
399 if (t_attrib->bold) {
400 printf("b");
401 } else {
402 printf(" ");
404 if (t_attrib->uline) {
405 printf("u");
406 } else {
407 printf(" ");
409 if (t_attrib->blink) {
410 printf("l");
411 } else {
412 printf(" ");
414 if (t_attrib->invers) {
415 printf("i");
416 } else {
417 printf(" ");
419 if (t_attrib->unvisible) {
420 printf("n");
421 } else {
422 printf(" ");
425 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
427 #endif
429 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
430 TextAttributes *t_attrib)
432 uint8_t *d;
433 const uint8_t *font_ptr;
434 unsigned int font_data, linesize, xorcol, bpp;
435 int i;
436 unsigned int fgcol, bgcol;
438 #ifdef DEBUG_CONSOLE
439 printf("x: %2i y: %2i", x, y);
440 console_print_text_attributes(t_attrib, ch);
441 #endif
443 if (t_attrib->invers) {
444 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
445 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
446 } else {
447 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
448 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
451 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
452 d = ds_get_data(ds) +
453 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
454 linesize = ds_get_linesize(ds);
455 font_ptr = vgafont16 + FONT_HEIGHT * ch;
456 xorcol = bgcol ^ fgcol;
457 switch(ds_get_bits_per_pixel(ds)) {
458 case 8:
459 for(i = 0; i < FONT_HEIGHT; i++) {
460 font_data = *font_ptr++;
461 if (t_attrib->uline
462 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
463 font_data = 0xFFFF;
465 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
466 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
467 d += linesize;
469 break;
470 case 16:
471 case 15:
472 for(i = 0; i < FONT_HEIGHT; i++) {
473 font_data = *font_ptr++;
474 if (t_attrib->uline
475 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
476 font_data = 0xFFFF;
478 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
479 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
480 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
482 d += linesize;
484 break;
485 case 32:
486 for(i = 0; i < FONT_HEIGHT; i++) {
487 font_data = *font_ptr++;
488 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
489 font_data = 0xFFFF;
491 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
492 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
493 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
494 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
495 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
496 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
497 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
498 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
499 d += linesize;
501 break;
505 static void text_console_resize(TextConsole *s)
507 TextCell *cells, *c, *c1;
508 int w1, x, y, last_width;
510 last_width = s->width;
511 s->width = s->g_width / FONT_WIDTH;
512 s->height = s->g_height / FONT_HEIGHT;
514 w1 = last_width;
515 if (s->width < w1)
516 w1 = s->width;
518 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
519 for(y = 0; y < s->total_height; y++) {
520 c = &cells[y * s->width];
521 if (w1 > 0) {
522 c1 = &s->cells[y * last_width];
523 for(x = 0; x < w1; x++) {
524 *c++ = *c1++;
527 for(x = w1; x < s->width; x++) {
528 c->ch = ' ';
529 c->t_attrib = s->t_attrib_default;
530 c++;
533 qemu_free(s->cells);
534 s->cells = cells;
537 static inline void text_update_xy(TextConsole *s, int x, int y)
539 s->text_x[0] = MIN(s->text_x[0], x);
540 s->text_x[1] = MAX(s->text_x[1], x);
541 s->text_y[0] = MIN(s->text_y[0], y);
542 s->text_y[1] = MAX(s->text_y[1], y);
545 static void invalidate_xy(TextConsole *s, int x, int y)
547 if (s->update_x0 > x * FONT_WIDTH)
548 s->update_x0 = x * FONT_WIDTH;
549 if (s->update_y0 > y * FONT_HEIGHT)
550 s->update_y0 = y * FONT_HEIGHT;
551 if (s->update_x1 < (x + 1) * FONT_WIDTH)
552 s->update_x1 = (x + 1) * FONT_WIDTH;
553 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
554 s->update_y1 = (y + 1) * FONT_HEIGHT;
557 static void update_xy(TextConsole *s, int x, int y)
559 TextCell *c;
560 int y1, y2;
562 if (s == active_console) {
563 if (!ds_get_bits_per_pixel(s->ds)) {
564 text_update_xy(s, x, y);
565 return;
568 y1 = (s->y_base + y) % s->total_height;
569 y2 = y1 - s->y_displayed;
570 if (y2 < 0)
571 y2 += s->total_height;
572 if (y2 < s->height) {
573 c = &s->cells[y1 * s->width + x];
574 vga_putcharxy(s->ds, x, y2, c->ch,
575 &(c->t_attrib));
576 invalidate_xy(s, x, y2);
581 static void console_show_cursor(TextConsole *s, int show)
583 TextCell *c;
584 int y, y1;
586 if (s == active_console) {
587 int x = s->x;
589 if (!ds_get_bits_per_pixel(s->ds)) {
590 s->cursor_invalidate = 1;
591 return;
594 if (x >= s->width) {
595 x = s->width - 1;
597 y1 = (s->y_base + s->y) % s->total_height;
598 y = y1 - s->y_displayed;
599 if (y < 0)
600 y += s->total_height;
601 if (y < s->height) {
602 c = &s->cells[y1 * s->width + x];
603 if (show) {
604 TextAttributes t_attrib = s->t_attrib_default;
605 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
606 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
607 } else {
608 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
610 invalidate_xy(s, x, y);
615 static void console_refresh(TextConsole *s)
617 TextCell *c;
618 int x, y, y1;
620 if (s != active_console)
621 return;
622 if (!ds_get_bits_per_pixel(s->ds)) {
623 s->text_x[0] = 0;
624 s->text_y[0] = 0;
625 s->text_x[1] = s->width - 1;
626 s->text_y[1] = s->height - 1;
627 s->cursor_invalidate = 1;
628 return;
631 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
632 color_table[0][COLOR_BLACK]);
633 y1 = s->y_displayed;
634 for(y = 0; y < s->height; y++) {
635 c = s->cells + y1 * s->width;
636 for(x = 0; x < s->width; x++) {
637 vga_putcharxy(s->ds, x, y, c->ch,
638 &(c->t_attrib));
639 c++;
641 if (++y1 == s->total_height)
642 y1 = 0;
644 console_show_cursor(s, 1);
645 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
648 static void console_scroll(int ydelta)
650 TextConsole *s;
651 int i, y1;
653 s = active_console;
654 if (!s || (s->console_type == GRAPHIC_CONSOLE))
655 return;
657 if (ydelta > 0) {
658 for(i = 0; i < ydelta; i++) {
659 if (s->y_displayed == s->y_base)
660 break;
661 if (++s->y_displayed == s->total_height)
662 s->y_displayed = 0;
664 } else {
665 ydelta = -ydelta;
666 i = s->backscroll_height;
667 if (i > s->total_height - s->height)
668 i = s->total_height - s->height;
669 y1 = s->y_base - i;
670 if (y1 < 0)
671 y1 += s->total_height;
672 for(i = 0; i < ydelta; i++) {
673 if (s->y_displayed == y1)
674 break;
675 if (--s->y_displayed < 0)
676 s->y_displayed = s->total_height - 1;
679 console_refresh(s);
682 static void console_put_lf(TextConsole *s)
684 TextCell *c;
685 int x, y1;
687 s->y++;
688 if (s->y >= s->height) {
689 s->y = s->height - 1;
691 if (s->y_displayed == s->y_base) {
692 if (++s->y_displayed == s->total_height)
693 s->y_displayed = 0;
695 if (++s->y_base == s->total_height)
696 s->y_base = 0;
697 if (s->backscroll_height < s->total_height)
698 s->backscroll_height++;
699 y1 = (s->y_base + s->height - 1) % s->total_height;
700 c = &s->cells[y1 * s->width];
701 for(x = 0; x < s->width; x++) {
702 c->ch = ' ';
703 c->t_attrib = s->t_attrib_default;
704 c++;
706 if (s == active_console && s->y_displayed == s->y_base) {
707 if (!ds_get_bits_per_pixel(s->ds)) {
708 s->text_x[0] = 0;
709 s->text_y[0] = 0;
710 s->text_x[1] = s->width - 1;
711 s->text_y[1] = s->height - 1;
712 return;
715 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
716 s->width * FONT_WIDTH,
717 (s->height - 1) * FONT_HEIGHT);
718 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
719 s->width * FONT_WIDTH, FONT_HEIGHT,
720 color_table[0][s->t_attrib_default.bgcol]);
721 s->update_x0 = 0;
722 s->update_y0 = 0;
723 s->update_x1 = s->width * FONT_WIDTH;
724 s->update_y1 = s->height * FONT_HEIGHT;
729 /* Set console attributes depending on the current escape codes.
730 * NOTE: I know this code is not very efficient (checking every color for it
731 * self) but it is more readable and better maintainable.
733 static void console_handle_escape(TextConsole *s)
735 int i;
737 for (i=0; i<s->nb_esc_params; i++) {
738 switch (s->esc_params[i]) {
739 case 0: /* reset all console attributes to default */
740 s->t_attrib = s->t_attrib_default;
741 break;
742 case 1:
743 s->t_attrib.bold = 1;
744 break;
745 case 4:
746 s->t_attrib.uline = 1;
747 break;
748 case 5:
749 s->t_attrib.blink = 1;
750 break;
751 case 7:
752 s->t_attrib.invers = 1;
753 break;
754 case 8:
755 s->t_attrib.unvisible = 1;
756 break;
757 case 22:
758 s->t_attrib.bold = 0;
759 break;
760 case 24:
761 s->t_attrib.uline = 0;
762 break;
763 case 25:
764 s->t_attrib.blink = 0;
765 break;
766 case 27:
767 s->t_attrib.invers = 0;
768 break;
769 case 28:
770 s->t_attrib.unvisible = 0;
771 break;
772 /* set foreground color */
773 case 30:
774 s->t_attrib.fgcol=COLOR_BLACK;
775 break;
776 case 31:
777 s->t_attrib.fgcol=COLOR_RED;
778 break;
779 case 32:
780 s->t_attrib.fgcol=COLOR_GREEN;
781 break;
782 case 33:
783 s->t_attrib.fgcol=COLOR_YELLOW;
784 break;
785 case 34:
786 s->t_attrib.fgcol=COLOR_BLUE;
787 break;
788 case 35:
789 s->t_attrib.fgcol=COLOR_MAGENTA;
790 break;
791 case 36:
792 s->t_attrib.fgcol=COLOR_CYAN;
793 break;
794 case 37:
795 s->t_attrib.fgcol=COLOR_WHITE;
796 break;
797 /* set background color */
798 case 40:
799 s->t_attrib.bgcol=COLOR_BLACK;
800 break;
801 case 41:
802 s->t_attrib.bgcol=COLOR_RED;
803 break;
804 case 42:
805 s->t_attrib.bgcol=COLOR_GREEN;
806 break;
807 case 43:
808 s->t_attrib.bgcol=COLOR_YELLOW;
809 break;
810 case 44:
811 s->t_attrib.bgcol=COLOR_BLUE;
812 break;
813 case 45:
814 s->t_attrib.bgcol=COLOR_MAGENTA;
815 break;
816 case 46:
817 s->t_attrib.bgcol=COLOR_CYAN;
818 break;
819 case 47:
820 s->t_attrib.bgcol=COLOR_WHITE;
821 break;
826 static void console_clear_xy(TextConsole *s, int x, int y)
828 int y1 = (s->y_base + y) % s->total_height;
829 TextCell *c = &s->cells[y1 * s->width + x];
830 c->ch = ' ';
831 c->t_attrib = s->t_attrib_default;
832 c++;
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 active_console->g_width = ds_get_width(active_console->ds);
1065 active_console->g_height = ds_get_height(active_console->ds);
1066 s = consoles[index];
1067 if (s) {
1068 DisplayState *ds = s->ds;
1069 active_console = s;
1070 if (ds_get_bits_per_pixel(s->ds)) {
1071 ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
1072 s->g_height, 32, 4 * s->g_width);
1073 } else {
1074 s->ds->surface->width = s->width;
1075 s->ds->surface->height = s->height;
1077 dpy_resize(s->ds);
1078 vga_hw_invalidate();
1082 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1084 TextConsole *s = chr->opaque;
1085 int i;
1087 s->update_x0 = s->width * FONT_WIDTH;
1088 s->update_y0 = s->height * FONT_HEIGHT;
1089 s->update_x1 = 0;
1090 s->update_y1 = 0;
1091 console_show_cursor(s, 0);
1092 for(i = 0; i < len; i++) {
1093 console_putchar(s, buf[i]);
1095 console_show_cursor(s, 1);
1096 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1097 dpy_update(s->ds, s->update_x0, s->update_y0,
1098 s->update_x1 - s->update_x0,
1099 s->update_y1 - s->update_y0);
1101 return len;
1104 static void console_send_event(CharDriverState *chr, int event)
1106 TextConsole *s = chr->opaque;
1107 int i;
1109 if (event == CHR_EVENT_FOCUS) {
1110 for(i = 0; i < nb_consoles; i++) {
1111 if (consoles[i] == s) {
1112 console_select(i);
1113 break;
1119 static void kbd_send_chars(void *opaque)
1121 TextConsole *s = opaque;
1122 int len;
1123 uint8_t buf[16];
1125 len = qemu_chr_can_read(s->chr);
1126 if (len > s->out_fifo.count)
1127 len = s->out_fifo.count;
1128 if (len > 0) {
1129 if (len > sizeof(buf))
1130 len = sizeof(buf);
1131 qemu_fifo_read(&s->out_fifo, buf, len);
1132 qemu_chr_read(s->chr, buf, len);
1134 /* characters are pending: we send them a bit later (XXX:
1135 horrible, should change char device API) */
1136 if (s->out_fifo.count > 0) {
1137 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1141 /* called when an ascii key is pressed */
1142 void kbd_put_keysym(int keysym)
1144 TextConsole *s;
1145 uint8_t buf[16], *q;
1146 int c;
1148 s = active_console;
1149 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1150 return;
1152 switch(keysym) {
1153 case QEMU_KEY_CTRL_UP:
1154 console_scroll(-1);
1155 break;
1156 case QEMU_KEY_CTRL_DOWN:
1157 console_scroll(1);
1158 break;
1159 case QEMU_KEY_CTRL_PAGEUP:
1160 console_scroll(-10);
1161 break;
1162 case QEMU_KEY_CTRL_PAGEDOWN:
1163 console_scroll(10);
1164 break;
1165 default:
1166 /* convert the QEMU keysym to VT100 key string */
1167 q = buf;
1168 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1169 *q++ = '\033';
1170 *q++ = '[';
1171 c = keysym - 0xe100;
1172 if (c >= 10)
1173 *q++ = '0' + (c / 10);
1174 *q++ = '0' + (c % 10);
1175 *q++ = '~';
1176 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1177 *q++ = '\033';
1178 *q++ = '[';
1179 *q++ = keysym & 0xff;
1180 } else {
1181 *q++ = keysym;
1183 if (s->chr->chr_read) {
1184 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1185 kbd_send_chars(s);
1187 break;
1191 static void text_console_invalidate(void *opaque)
1193 TextConsole *s = (TextConsole *) opaque;
1194 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1195 s->g_width = ds_get_width(s->ds);
1196 s->g_height = ds_get_height(s->ds);
1197 text_console_resize(s);
1199 console_refresh(s);
1202 static void text_console_update(void *opaque, console_ch_t *chardata)
1204 TextConsole *s = (TextConsole *) opaque;
1205 int i, j, src;
1207 if (s->text_x[0] <= s->text_x[1]) {
1208 src = (s->y_base + s->text_y[0]) * s->width;
1209 chardata += s->text_y[0] * s->width;
1210 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1211 for (j = 0; j < s->width; j ++, src ++)
1212 console_write_ch(chardata ++, s->cells[src].ch |
1213 (s->cells[src].t_attrib.fgcol << 12) |
1214 (s->cells[src].t_attrib.bgcol << 8) |
1215 (s->cells[src].t_attrib.bold << 21));
1216 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1217 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1218 s->text_x[0] = s->width;
1219 s->text_y[0] = s->height;
1220 s->text_x[1] = 0;
1221 s->text_y[1] = 0;
1223 if (s->cursor_invalidate) {
1224 dpy_cursor(s->ds, s->x, s->y);
1225 s->cursor_invalidate = 0;
1229 static TextConsole *get_graphic_console(DisplayState *ds)
1231 int i;
1232 TextConsole *s;
1233 for (i = 0; i < nb_consoles; i++) {
1234 s = consoles[i];
1235 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1236 return s;
1238 return NULL;
1241 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1243 TextConsole *s;
1244 int i;
1246 if (nb_consoles >= MAX_CONSOLES)
1247 return NULL;
1248 s = qemu_mallocz(sizeof(TextConsole));
1249 if (!s) {
1250 return NULL;
1252 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1253 (console_type == GRAPHIC_CONSOLE))) {
1254 active_console = s;
1256 s->ds = ds;
1257 s->console_type = console_type;
1258 if (console_type != GRAPHIC_CONSOLE) {
1259 consoles[nb_consoles++] = s;
1260 } else {
1261 /* HACK: Put graphical consoles before text consoles. */
1262 for (i = nb_consoles; i > 0; i--) {
1263 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1264 break;
1265 consoles[i] = consoles[i - 1];
1267 consoles[i] = s;
1268 nb_consoles++;
1270 return s;
1273 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1274 vga_hw_invalidate_ptr invalidate,
1275 vga_hw_screen_dump_ptr screen_dump,
1276 vga_hw_text_update_ptr text_update,
1277 void *opaque)
1279 TextConsole *s;
1280 DisplayState *ds;
1282 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1283 if (ds == NULL)
1284 return NULL;
1285 ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
1287 s = new_console(ds, GRAPHIC_CONSOLE);
1288 if (s == NULL) {
1289 qemu_free_displaysurface(ds->surface);
1290 qemu_free(ds);
1291 return NULL;
1293 s->hw_update = update;
1294 s->hw_invalidate = invalidate;
1295 s->hw_screen_dump = screen_dump;
1296 s->hw_text_update = text_update;
1297 s->hw = opaque;
1299 register_displaystate(ds);
1300 return ds;
1303 int is_graphic_console(void)
1305 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1308 int is_fixedsize_console(void)
1310 return active_console && active_console->console_type != TEXT_CONSOLE;
1313 void console_color_init(DisplayState *ds)
1315 int i, j;
1316 for (j = 0; j < 2; j++) {
1317 for (i = 0; i < 8; i++) {
1318 color_table[j][i] = col_expand(ds,
1319 vga_get_color(ds, color_table_rgb[j][i]));
1324 static int n_text_consoles;
1325 static CharDriverState *text_consoles[128];
1326 static char *text_console_strs[128];
1328 static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1330 TextConsole *s;
1331 unsigned width;
1332 unsigned height;
1333 static int color_inited;
1335 s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1336 if (!s) {
1337 free(chr);
1338 return;
1340 chr->opaque = s;
1341 chr->chr_write = console_puts;
1342 chr->chr_send_event = console_send_event;
1344 s->chr = chr;
1345 s->out_fifo.buf = s->out_fifo_buf;
1346 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1347 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1348 s->ds = ds;
1350 if (!color_inited) {
1351 color_inited = 1;
1352 console_color_init(s->ds);
1354 s->y_displayed = 0;
1355 s->y_base = 0;
1356 s->total_height = DEFAULT_BACKSCROLL;
1357 s->x = 0;
1358 s->y = 0;
1359 width = ds_get_width(s->ds);
1360 height = ds_get_height(s->ds);
1361 if (p != 0) {
1362 width = strtoul(p, (char **)&p, 10);
1363 if (*p == 'C') {
1364 p++;
1365 width *= FONT_WIDTH;
1367 if (*p == 'x') {
1368 p++;
1369 height = strtoul(p, (char **)&p, 10);
1370 if (*p == 'C') {
1371 p++;
1372 height *= FONT_HEIGHT;
1376 s->g_width = width;
1377 s->g_height = height;
1379 s->hw_invalidate = text_console_invalidate;
1380 s->hw_text_update = text_console_update;
1381 s->hw = s;
1383 /* Set text attribute defaults */
1384 s->t_attrib_default.bold = 0;
1385 s->t_attrib_default.uline = 0;
1386 s->t_attrib_default.blink = 0;
1387 s->t_attrib_default.invers = 0;
1388 s->t_attrib_default.unvisible = 0;
1389 s->t_attrib_default.fgcol = COLOR_WHITE;
1390 s->t_attrib_default.bgcol = COLOR_BLACK;
1391 /* set current text attributes to default */
1392 s->t_attrib = s->t_attrib_default;
1393 text_console_resize(s);
1395 qemu_chr_reset(chr);
1396 if (chr->init)
1397 chr->init(chr);
1400 CharDriverState *text_console_init(const char *p)
1402 CharDriverState *chr;
1404 chr = qemu_mallocz(sizeof(CharDriverState));
1405 if (!chr)
1406 return NULL;
1408 if (n_text_consoles == 128) {
1409 fprintf(stderr, "Too many text consoles\n");
1410 exit(1);
1412 text_consoles[n_text_consoles] = chr;
1413 text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1414 n_text_consoles++;
1416 return chr;
1419 void text_consoles_set_display(DisplayState *ds)
1421 int i;
1423 for (i = 0; i < n_text_consoles; i++) {
1424 text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1425 qemu_free(text_console_strs[i]);
1428 n_text_consoles = 0;
1431 void qemu_console_resize(DisplayState *ds, int width, int height)
1433 TextConsole *s = get_graphic_console(ds);
1434 if (!s) return;
1436 s->g_width = width;
1437 s->g_height = height;
1438 if (is_graphic_console()) {
1439 ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
1440 dpy_resize(ds);
1444 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1445 int dst_x, int dst_y, int w, int h)
1447 if (is_graphic_console()) {
1448 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1452 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1454 PixelFormat pf;
1456 memset(&pf, 0x00, sizeof(PixelFormat));
1458 pf.bits_per_pixel = bpp;
1459 pf.bytes_per_pixel = bpp / 8;
1460 pf.depth = bpp == 32 ? 24 : bpp;
1462 switch (bpp) {
1463 case 24:
1464 pf.rmask = 0x000000FF;
1465 pf.gmask = 0x0000FF00;
1466 pf.bmask = 0x00FF0000;
1467 pf.rmax = 255;
1468 pf.gmax = 255;
1469 pf.bmax = 255;
1470 pf.rshift = 0;
1471 pf.gshift = 8;
1472 pf.bshift = 16;
1473 pf.rbits = 8;
1474 pf.gbits = 8;
1475 pf.bbits = 8;
1476 break;
1477 case 32:
1478 pf.rmask = 0x0000FF00;
1479 pf.gmask = 0x00FF0000;
1480 pf.bmask = 0xFF000000;
1481 pf.amask = 0x00000000;
1482 pf.amax = 255;
1483 pf.rmax = 255;
1484 pf.gmax = 255;
1485 pf.bmax = 255;
1486 pf.ashift = 0;
1487 pf.rshift = 8;
1488 pf.gshift = 16;
1489 pf.bshift = 24;
1490 pf.rbits = 8;
1491 pf.gbits = 8;
1492 pf.bbits = 8;
1493 pf.abits = 8;
1494 break;
1495 default:
1496 break;
1498 return pf;
1501 PixelFormat qemu_default_pixelformat(int bpp)
1503 PixelFormat pf;
1505 memset(&pf, 0x00, sizeof(PixelFormat));
1507 pf.bits_per_pixel = bpp;
1508 pf.bytes_per_pixel = bpp / 8;
1509 pf.depth = bpp == 32 ? 24 : bpp;
1511 switch (bpp) {
1512 case 16:
1513 pf.rmask = 0x0000F800;
1514 pf.gmask = 0x000007E0;
1515 pf.bmask = 0x0000001F;
1516 pf.rmax = 31;
1517 pf.gmax = 63;
1518 pf.bmax = 31;
1519 pf.rshift = 11;
1520 pf.gshift = 5;
1521 pf.bshift = 0;
1522 pf.rbits = 5;
1523 pf.gbits = 6;
1524 pf.bbits = 5;
1525 break;
1526 case 24:
1527 pf.rmask = 0x00FF0000;
1528 pf.gmask = 0x0000FF00;
1529 pf.bmask = 0x000000FF;
1530 pf.rmax = 255;
1531 pf.gmax = 255;
1532 pf.bmax = 255;
1533 pf.rshift = 16;
1534 pf.gshift = 8;
1535 pf.bshift = 0;
1536 pf.rbits = 8;
1537 pf.gbits = 8;
1538 pf.bbits = 8;
1539 case 32:
1540 pf.rmask = 0x00FF0000;
1541 pf.gmask = 0x0000FF00;
1542 pf.bmask = 0x000000FF;
1543 pf.amax = 255;
1544 pf.rmax = 255;
1545 pf.gmax = 255;
1546 pf.bmax = 255;
1547 pf.ashift = 24;
1548 pf.rshift = 16;
1549 pf.gshift = 8;
1550 pf.bshift = 0;
1551 pf.rbits = 8;
1552 pf.gbits = 8;
1553 pf.bbits = 8;
1554 pf.abits = 8;
1555 break;
1556 default:
1557 break;
1559 return pf;
1562 DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
1564 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1565 if (surface == NULL) {
1566 fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1567 exit(1);
1570 surface->width = width;
1571 surface->height = height;
1572 surface->linesize = linesize;
1573 surface->pf = qemu_default_pixelformat(bpp);
1574 #ifdef WORDS_BIGENDIAN
1575 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1576 #else
1577 surface->flags = QEMU_ALLOCATED_FLAG;
1578 #endif
1579 surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1580 if (surface->data == NULL) {
1581 fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1582 exit(1);
1585 return surface;
1588 DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
1589 int width, int height, int bpp, int linesize)
1591 surface->width = width;
1592 surface->height = height;
1593 surface->linesize = linesize;
1594 surface->pf = qemu_default_pixelformat(bpp);
1595 if (surface->flags & QEMU_ALLOCATED_FLAG)
1596 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1597 else
1598 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1599 if (surface->data == NULL) {
1600 fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n");
1601 exit(1);
1603 #ifdef WORDS_BIGENDIAN
1604 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1605 #else
1606 surface->flags = QEMU_ALLOCATED_FLAG;
1607 #endif
1609 return surface;
1612 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1613 int linesize, uint8_t *data)
1615 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1616 if (surface == NULL) {
1617 fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n");
1618 exit(1);
1621 surface->width = width;
1622 surface->height = height;
1623 surface->linesize = linesize;
1624 surface->pf = qemu_default_pixelformat(bpp);
1625 #ifdef WORDS_BIGENDIAN
1626 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1627 #endif
1628 surface->data = data;
1630 return surface;
1633 void qemu_free_displaysurface(DisplaySurface *surface)
1635 if (surface == NULL)
1636 return;
1637 if (surface->flags & QEMU_ALLOCATED_FLAG)
1638 qemu_free(surface->data);
1639 qemu_free(surface);