Coalesce virtual console screen updates.
[qemu] / console.c
1 /*
2  * QEMU graphical console
3  *
4  * Copyright (c) 2004 Fabrice Bellard
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include "qemu-common.h"
25 #include "console.h"
26 #include "qemu-timer.h"
27
28 //#define DEBUG_CONSOLE
29 #define DEFAULT_BACKSCROLL 512
30 #define MAX_CONSOLES 12
31 #define DEFAULT_MONITOR_SIZE "800x600"
32
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)
35
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;
45
46 typedef struct TextCell {
47     uint8_t ch;
48     TextAttributes t_attrib;
49 } TextCell;
50
51 #define MAX_ESC_PARAMS 3
52
53 enum TTYState {
54     TTY_STATE_NORM,
55     TTY_STATE_ESC,
56     TTY_STATE_CSI,
57 };
58
59 typedef struct QEMUFIFO {
60     uint8_t *buf;
61     int buf_size;
62     int count, wptr, rptr;
63 } QEMUFIFO;
64
65 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
66 {
67     int l, len;
68
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;
83     }
84     f->count += len1;
85     return len1;
86 }
87
88 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
89 {
90     int l, len;
91
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;
105     }
106     f->count -= len1;
107     return len1;
108 }
109
110 typedef enum {
111     GRAPHIC_CONSOLE,
112     TEXT_CONSOLE,
113     TEXT_CONSOLE_FIXED_SIZE
114 } console_type_t;
115
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;
127
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
142     int update_x0;
143     int update_y0;
144     int update_x1;
145     int update_y1;
146
147     enum TTYState state;
148     int esc_params[MAX_ESC_PARAMS];
149     int nb_esc_params;
150
151     CharDriverState *chr;
152     /* fifo for key pressed */
153     QEMUFIFO out_fifo;
154     uint8_t out_fifo_buf[16];
155     QEMUTimer *kbd_timer;
156 };
157
158 static TextConsole *active_console;
159 static TextConsole *consoles[MAX_CONSOLES];
160 static int nb_consoles = 0;
161
162 void vga_hw_update(void)
163 {
164     if (active_console && active_console->hw_update)
165         active_console->hw_update(active_console->hw);
166 }
167
168 void vga_hw_invalidate(void)
169 {
170     if (active_console->hw_invalidate)
171         active_console->hw_invalidate(active_console->hw);
172 }
173
174 void vga_hw_screen_dump(const char *filename)
175 {
176     TextConsole *previous_active_console;
177
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;
185 }
186
187 void vga_hw_text_update(console_ch_t *chardata)
188 {
189     if (active_console && active_console->hw_text_update)
190         active_console->hw_text_update(active_console->hw, chardata);
191 }
192
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)
195 {
196     unsigned int r, g, b, color;
197
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;
225     }
226     return color;
227 }
228
229 static void vga_fill_rect (DisplayState *ds,
230                            int posx, int posy, int width, int height, uint32_t color)
231 {
232     uint8_t *d, *d1;
233     int x, y, bpp;
234
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++;
245             }
246             break;
247         case 2:
248             for (x = 0; x < width; x++) {
249                 *((uint16_t *)d) = color;
250                 d += 2;
251             }
252             break;
253         case 4:
254             for (x = 0; x < width; x++) {
255                 *((uint32_t *)d) = color;
256                 d += 4;
257             }
258             break;
259         }
260         d1 += ds_get_linesize(ds);
261     }
262 }
263
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)
266 {
267     const uint8_t *s;
268     uint8_t *d;
269     int wb, y, bpp;
270
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);
282         }
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);
292         }
293     }
294 }
295
296 /***********************************************************/
297 /* basic char display */
298
299 #define FONT_HEIGHT 16
300 #define FONT_WIDTH 8
301
302 #include "vgafont.h"
303
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) ))
310
311 #ifdef WORDS_BIGENDIAN
312 #define PAT(x) x
313 #else
314 #define PAT(x) cbswap_32(x)
315 #endif
316
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),
334 };
335
336 static const uint32_t dmask4[4] = {
337     PAT(0x00000000),
338     PAT(0x0000ffff),
339     PAT(0xffff0000),
340     PAT(0xffffffff),
341 };
342
343 static uint32_t color_table[2][8];
344
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
354 };
355
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 */
366     },
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 */
376     }
377 };
378
379 static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
380 {
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;
392     }
393
394     return col;
395 }
396 #ifdef DEBUG_CONSOLE
397 static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
398 {
399     if (t_attrib->bold) {
400         printf("b");
401     } else {
402         printf(" ");
403     }
404     if (t_attrib->uline) {
405         printf("u");
406     } else {
407         printf(" ");
408     }
409     if (t_attrib->blink) {
410         printf("l");
411     } else {
412         printf(" ");
413     }
414     if (t_attrib->invers) {
415         printf("i");
416     } else {
417         printf(" ");
418     }
419     if (t_attrib->unvisible) {
420         printf("n");
421     } else {
422         printf(" ");
423     }
424
425     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
426 }
427 #endif
428
429 static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
430                           TextAttributes *t_attrib)
431 {
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;
437
438 #ifdef DEBUG_CONSOLE
439     printf("x: %2i y: %2i", x, y);
440     console_print_text_attributes(t_attrib, ch);
441 #endif
442
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];
449     }
450
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;
464             }
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;
468         }
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;
477             }
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;
483         }
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;
490             }
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;
500         }
501         break;
502     }
503 }
504
505 static void text_console_resize(TextConsole *s)
506 {
507     TextCell *cells, *c, *c1;
508     int w1, x, y, last_width;
509
510     last_width = s->width;
511     s->width = s->g_width / FONT_WIDTH;
512     s->height = s->g_height / FONT_HEIGHT;
513
514     w1 = last_width;
515     if (s->width < w1)
516         w1 = s->width;
517
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++;
525             }
526         }
527         for(x = w1; x < s->width; x++) {
528             c->ch = ' ';
529             c->t_attrib = s->t_attrib_default;
530             c++;
531         }
532     }
533     qemu_free(s->cells);
534     s->cells = cells;
535 }
536
537 static inline void text_update_xy(TextConsole *s, int x, int y)
538 {
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);
543 }
544
545 static void invalidate_xy(TextConsole *s, int x, int y)
546 {
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;
555 }
556
557 static void update_xy(TextConsole *s, int x, int y)
558 {
559     TextCell *c;
560     int y1, y2;
561
562     if (s == active_console) {
563         if (!ds_get_bits_per_pixel(s->ds)) {
564             text_update_xy(s, x, y);
565             return;
566         }
567
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);
577         }
578     }
579 }
580
581 static void console_show_cursor(TextConsole *s, int show)
582 {
583     TextCell *c;
584     int y, y1;
585
586     if (s == active_console) {
587         int x = s->x;
588
589         if (!ds_get_bits_per_pixel(s->ds)) {
590             s->cursor_invalidate = 1;
591             return;
592         }
593
594         if (x >= s->width) {
595             x = s->width - 1;
596         }
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));
609             }
610             invalidate_xy(s, x, y);
611         }
612     }
613 }
614
615 static void console_refresh(TextConsole *s)
616 {
617     TextCell *c;
618     int x, y, y1;
619
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;
629     }
630
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++;
640         }
641         if (++y1 == s->total_height)
642             y1 = 0;
643     }
644     console_show_cursor(s, 1);
645     dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
646 }
647
648 static void console_scroll(int ydelta)
649 {
650     TextConsole *s;
651     int i, y1;
652
653     s = active_console;
654     if (!s || (s->console_type == GRAPHIC_CONSOLE))
655         return;
656
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;
663         }
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;
677         }
678     }
679     console_refresh(s);
680 }
681
682 static void console_put_lf(TextConsole *s)
683 {
684     TextCell *c;
685     int x, y1;
686
687     s->y++;
688     if (s->y >= s->height) {
689         s->y = s->height - 1;
690
691         if (s->y_displayed == s->y_base) {
692             if (++s->y_displayed == s->total_height)
693                 s->y_displayed = 0;
694         }
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++;
705         }
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;
713             }
714
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;
725         }
726     }
727 }
728
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.
732  */
733 static void console_handle_escape(TextConsole *s)
734 {
735     int i;
736
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;
822         }
823     }
824 }
825
826 static void console_clear_xy(TextConsole *s, int x, int y)
827 {
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);
834 }
835
836 static void console_putchar(TextConsole *s, int ch)
837 {
838     TextCell *c;
839     int y1, i;
840     int x, y;
841
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));
861             }
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);
880             }
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;
888         }
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;
898         }
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';
905             }
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;
920                 }
921                 s->y -= s->esc_params[0];
922                 if (s->y < 0) {
923                     s->y = 0;
924                 }
925                 break;
926             case 'B':
927                 /* move cursor down */
928                 if (s->esc_params[0] == 0) {
929                     s->esc_params[0] = 1;
930                 }
931                 s->y += s->esc_params[0];
932                 if (s->y >= s->height) {
933                     s->y = s->height - 1;
934                 }
935                 break;
936             case 'C':
937                 /* move cursor right */
938                 if (s->esc_params[0] == 0) {
939                     s->esc_params[0] = 1;
940                 }
941                 s->x += s->esc_params[0];
942                 if (s->x >= s->width) {
943                     s->x = s->width - 1;
944                 }
945                 break;
946             case 'D':
947                 /* move cursor left */
948                 if (s->esc_params[0] == 0) {
949                     s->esc_params[0] = 1;
950                 }
951                 s->x -= s->esc_params[0];
952                 if (s->x < 0) {
953                     s->x = 0;
954                 }
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;
961                 }
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;
969                 }
970                 s->y = s->esc_params[0] - 1;
971                 if (s->y < 0) {
972                     s->y = 0;
973                 }
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;
983                             }
984                             console_clear_xy(s, x, y);
985                         }
986                     }
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;
994                             }
995                             console_clear_xy(s, x, y);
996                         }
997                     }
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);
1004                         }
1005                     }
1006                 break;
1007                 }
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);
1014                 }
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);
1020                     }
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);
1026                     }
1027                 break;
1028             }
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;
1052             }
1053             break;
1054         }
1055     }
1056 }
1057
1058 void console_select(unsigned int index)
1059 {
1060     TextConsole *s;
1061
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         ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
1071                                                 s->g_height, 32, 4 * s->g_width);
1072         dpy_resize(s->ds);
1073         vga_hw_invalidate();
1074     }
1075 }
1076
1077 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1078 {
1079     TextConsole *s = chr->opaque;
1080     int i;
1081
1082     s->update_x0 = s->width * FONT_WIDTH;
1083     s->update_y0 = s->height * FONT_HEIGHT;
1084     s->update_x1 = 0;
1085     s->update_y1 = 0;
1086     console_show_cursor(s, 0);
1087     for(i = 0; i < len; i++) {
1088         console_putchar(s, buf[i]);
1089     }
1090     console_show_cursor(s, 1);
1091     if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1092         dpy_update(s->ds, s->update_x0, s->update_y0,
1093                    s->update_x1 - s->update_x0,
1094                    s->update_y1 - s->update_y0);
1095     }
1096     return len;
1097 }
1098
1099 static void console_send_event(CharDriverState *chr, int event)
1100 {
1101     TextConsole *s = chr->opaque;
1102     int i;
1103
1104     if (event == CHR_EVENT_FOCUS) {
1105         for(i = 0; i < nb_consoles; i++) {
1106             if (consoles[i] == s) {
1107                 console_select(i);
1108                 break;
1109             }
1110         }
1111     }
1112 }
1113
1114 static void kbd_send_chars(void *opaque)
1115 {
1116     TextConsole *s = opaque;
1117     int len;
1118     uint8_t buf[16];
1119
1120     len = qemu_chr_can_read(s->chr);
1121     if (len > s->out_fifo.count)
1122         len = s->out_fifo.count;
1123     if (len > 0) {
1124         if (len > sizeof(buf))
1125             len = sizeof(buf);
1126         qemu_fifo_read(&s->out_fifo, buf, len);
1127         qemu_chr_read(s->chr, buf, len);
1128     }
1129     /* characters are pending: we send them a bit later (XXX:
1130        horrible, should change char device API) */
1131     if (s->out_fifo.count > 0) {
1132         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1133     }
1134 }
1135
1136 /* called when an ascii key is pressed */
1137 void kbd_put_keysym(int keysym)
1138 {
1139     TextConsole *s;
1140     uint8_t buf[16], *q;
1141     int c;
1142
1143     s = active_console;
1144     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1145         return;
1146
1147     switch(keysym) {
1148     case QEMU_KEY_CTRL_UP:
1149         console_scroll(-1);
1150         break;
1151     case QEMU_KEY_CTRL_DOWN:
1152         console_scroll(1);
1153         break;
1154     case QEMU_KEY_CTRL_PAGEUP:
1155         console_scroll(-10);
1156         break;
1157     case QEMU_KEY_CTRL_PAGEDOWN:
1158         console_scroll(10);
1159         break;
1160     default:
1161         /* convert the QEMU keysym to VT100 key string */
1162         q = buf;
1163         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1164             *q++ = '\033';
1165             *q++ = '[';
1166             c = keysym - 0xe100;
1167             if (c >= 10)
1168                 *q++ = '0' + (c / 10);
1169             *q++ = '0' + (c % 10);
1170             *q++ = '~';
1171         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1172             *q++ = '\033';
1173             *q++ = '[';
1174             *q++ = keysym & 0xff;
1175         } else {
1176                 *q++ = keysym;
1177         }
1178         if (s->chr->chr_read) {
1179             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1180             kbd_send_chars(s);
1181         }
1182         break;
1183     }
1184 }
1185
1186 static void text_console_invalidate(void *opaque)
1187 {
1188     TextConsole *s = (TextConsole *) opaque;
1189     console_refresh(s);
1190 }
1191
1192 static void text_console_update(void *opaque, console_ch_t *chardata)
1193 {
1194     TextConsole *s = (TextConsole *) opaque;
1195     int i, j, src;
1196
1197     if (s->text_x[0] <= s->text_x[1]) {
1198         src = (s->y_base + s->text_y[0]) * s->width;
1199         chardata += s->text_y[0] * s->width;
1200         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1201             for (j = 0; j < s->width; j ++, src ++)
1202                 console_write_ch(chardata ++, s->cells[src].ch |
1203                                 (s->cells[src].t_attrib.fgcol << 12) |
1204                                 (s->cells[src].t_attrib.bgcol << 8) |
1205                                 (s->cells[src].t_attrib.bold << 21));
1206         dpy_update(s->ds, s->text_x[0], s->text_y[0],
1207                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1208         s->text_x[0] = s->width;
1209         s->text_y[0] = s->height;
1210         s->text_x[1] = 0;
1211         s->text_y[1] = 0;
1212     }
1213     if (s->cursor_invalidate) {
1214         dpy_cursor(s->ds, s->x, s->y);
1215         s->cursor_invalidate = 0;
1216     }
1217 }
1218
1219 static TextConsole *get_graphic_console(DisplayState *ds)
1220 {
1221     int i;
1222     TextConsole *s;
1223     for (i = 0; i < nb_consoles; i++) {
1224         s = consoles[i];
1225         if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1226             return s;
1227     }
1228     return NULL;
1229 }
1230
1231 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1232 {
1233     TextConsole *s;
1234     int i;
1235
1236     if (nb_consoles >= MAX_CONSOLES)
1237         return NULL;
1238     s = qemu_mallocz(sizeof(TextConsole));
1239     if (!s) {
1240         return NULL;
1241     }
1242     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1243         (console_type == GRAPHIC_CONSOLE))) {
1244         active_console = s;
1245     }
1246     s->ds = ds;
1247     s->console_type = console_type;
1248     if (console_type != GRAPHIC_CONSOLE) {
1249         consoles[nb_consoles++] = s;
1250     } else {
1251         /* HACK: Put graphical consoles before text consoles.  */
1252         for (i = nb_consoles; i > 0; i--) {
1253             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1254                 break;
1255             consoles[i] = consoles[i - 1];
1256         }
1257         consoles[i] = s;
1258         nb_consoles++;
1259     }
1260     return s;
1261 }
1262
1263 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1264                                    vga_hw_invalidate_ptr invalidate,
1265                                    vga_hw_screen_dump_ptr screen_dump,
1266                                    vga_hw_text_update_ptr text_update,
1267                                    void *opaque)
1268 {
1269     TextConsole *s;
1270     DisplayState *ds;
1271
1272     ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1273     if (ds == NULL)
1274         return NULL;
1275     ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
1276
1277     s = new_console(ds, GRAPHIC_CONSOLE);
1278     if (s == NULL) {
1279         qemu_free_displaysurface(ds->surface);
1280         qemu_free(ds);
1281         return NULL;
1282     }
1283     s->hw_update = update;
1284     s->hw_invalidate = invalidate;
1285     s->hw_screen_dump = screen_dump;
1286     s->hw_text_update = text_update;
1287     s->hw = opaque;
1288
1289     register_displaystate(ds);
1290     return ds;
1291 }
1292
1293 int is_graphic_console(void)
1294 {
1295     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1296 }
1297
1298 int is_fixedsize_console(void)
1299 {
1300     return active_console && active_console->console_type != TEXT_CONSOLE;
1301 }
1302
1303 void console_color_init(DisplayState *ds)
1304 {
1305     int i, j;
1306     for (j = 0; j < 2; j++) {
1307         for (i = 0; i < 8; i++) {
1308             color_table[j][i] = col_expand(ds,
1309                    vga_get_color(ds, color_table_rgb[j][i]));
1310         }
1311     }
1312 }
1313
1314 static int n_text_consoles;
1315 static CharDriverState *text_consoles[128];
1316 static char *text_console_strs[128];
1317
1318 static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1319 {
1320     TextConsole *s;
1321     unsigned width;
1322     unsigned height;
1323     static int color_inited;
1324
1325     s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1326     if (!s) {
1327         free(chr);
1328         return;
1329     }
1330     chr->opaque = s;
1331     chr->chr_write = console_puts;
1332     chr->chr_send_event = console_send_event;
1333
1334     s->chr = chr;
1335     s->out_fifo.buf = s->out_fifo_buf;
1336     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1337     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1338     s->ds = ds;
1339
1340     if (!color_inited) {
1341         color_inited = 1;
1342         console_color_init(s->ds);
1343     }
1344     s->y_displayed = 0;
1345     s->y_base = 0;
1346     s->total_height = DEFAULT_BACKSCROLL;
1347     s->x = 0;
1348     s->y = 0;
1349     width = ds_get_width(s->ds);
1350     height = ds_get_height(s->ds);
1351     if (p != 0) {
1352         width = strtoul(p, (char **)&p, 10);
1353         if (*p == 'C') {
1354             p++;
1355             width *= FONT_WIDTH;
1356         }
1357         if (*p == 'x') {
1358             p++;
1359             height = strtoul(p, (char **)&p, 10);
1360             if (*p == 'C') {
1361                 p++;
1362                 height *= FONT_HEIGHT;
1363             }
1364         }
1365     }
1366     s->g_width = width;
1367     s->g_height = height;
1368
1369     s->hw_invalidate = text_console_invalidate;
1370     s->hw_text_update = text_console_update;
1371     s->hw = s;
1372
1373     /* Set text attribute defaults */
1374     s->t_attrib_default.bold = 0;
1375     s->t_attrib_default.uline = 0;
1376     s->t_attrib_default.blink = 0;
1377     s->t_attrib_default.invers = 0;
1378     s->t_attrib_default.unvisible = 0;
1379     s->t_attrib_default.fgcol = COLOR_WHITE;
1380     s->t_attrib_default.bgcol = COLOR_BLACK;
1381     /* set current text attributes to default */
1382     s->t_attrib = s->t_attrib_default;
1383     text_console_resize(s);
1384
1385     qemu_chr_reset(chr);
1386     if (chr->init)
1387         chr->init(chr);
1388 }
1389
1390 CharDriverState *text_console_init(const char *p)
1391 {
1392     CharDriverState *chr;
1393
1394     chr = qemu_mallocz(sizeof(CharDriverState));
1395     if (!chr)
1396         return NULL;
1397
1398     if (n_text_consoles == 128) {
1399         fprintf(stderr, "Too many text consoles\n");
1400         exit(1);
1401     }
1402     text_consoles[n_text_consoles] = chr;
1403     text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1404     n_text_consoles++;
1405
1406     return chr;
1407 }
1408
1409 void text_consoles_set_display(DisplayState *ds)
1410 {
1411     int i;
1412
1413     for (i = 0; i < n_text_consoles; i++) {
1414         text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1415         qemu_free(text_console_strs[i]);
1416     }
1417
1418     n_text_consoles = 0;
1419 }
1420
1421 void qemu_console_resize(DisplayState *ds, int width, int height)
1422 {
1423     TextConsole *s = get_graphic_console(ds);
1424     s->g_width = width;
1425     s->g_height = height;
1426     if (is_graphic_console()) {
1427         ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
1428         dpy_resize(ds);
1429     }
1430 }
1431
1432 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1433                        int dst_x, int dst_y, int w, int h)
1434 {
1435     if (is_graphic_console()) {
1436         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1437     }
1438 }
1439
1440 static PixelFormat qemu_default_pixelformat(int bpp)
1441 {
1442     PixelFormat pf;
1443
1444     memset(&pf, 0x00, sizeof(PixelFormat));
1445
1446     pf.bits_per_pixel = bpp;
1447     pf.bytes_per_pixel = bpp / 8;
1448     pf.depth = bpp == 32 ? 24 : bpp;
1449
1450     switch (bpp) {
1451         case 8:
1452             pf.rmask = 0x000000E0;
1453             pf.gmask = 0x0000001C;
1454             pf.bmask = 0x00000003;
1455             pf.rmax = 7;
1456             pf.gmax = 7;
1457             pf.bmax = 3;
1458             pf.rshift = 5;
1459             pf.gshift = 2;
1460             pf.bshift = 0;
1461             break;
1462         case 16:
1463             pf.rmask = 0x0000F800;
1464             pf.gmask = 0x000007E0;
1465             pf.bmask = 0x0000001F;
1466             pf.rmax = 31;
1467             pf.gmax = 63;
1468             pf.bmax = 31;
1469             pf.rshift = 11;
1470             pf.gshift = 5;
1471             pf.bshift = 0;
1472             break;
1473         case 24:
1474         case 32:
1475             pf.rmask = 0x00FF0000;
1476             pf.gmask = 0x0000FF00;
1477             pf.bmask = 0x000000FF;
1478             pf.rmax = 255;
1479             pf.gmax = 255;
1480             pf.bmax = 255;
1481             pf.rshift = 16;
1482             pf.gshift = 8;
1483             pf.bshift = 0;
1484             break;
1485         default:
1486             break;
1487     }
1488     return pf;
1489 }
1490
1491 DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
1492 {
1493     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1494     if (surface == NULL) {
1495         fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1496         exit(1);
1497     }
1498
1499     surface->width = width;
1500     surface->height = height;
1501     surface->linesize = linesize;
1502     surface->pf = qemu_default_pixelformat(bpp);
1503 #ifdef WORDS_BIGENDIAN
1504     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1505 #else
1506     surface->flags = QEMU_ALLOCATED_FLAG;
1507 #endif
1508     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1509     if (surface->data == NULL) {
1510         fprintf(stderr, "qemu_create_displaysurface: malloc failed\n");
1511         exit(1);
1512     }
1513
1514     return surface;
1515 }
1516
1517 DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
1518                                           int width, int height, int bpp, int linesize)
1519 {
1520     surface->width = width;
1521     surface->height = height;
1522     surface->linesize = linesize;
1523     surface->pf = qemu_default_pixelformat(bpp);
1524     if (surface->flags & QEMU_ALLOCATED_FLAG)
1525         surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1526     else
1527         surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1528     if (surface->data == NULL) {
1529         fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n");
1530         exit(1);
1531     }
1532 #ifdef WORDS_BIGENDIAN
1533     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1534 #else
1535     surface->flags = QEMU_ALLOCATED_FLAG;
1536 #endif
1537
1538     return surface;
1539 }
1540
1541 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1542                                               int linesize, uint8_t *data)
1543 {
1544     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1545     if (surface == NULL) {
1546         fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n");
1547         exit(1);
1548     }
1549
1550     surface->width = width;
1551     surface->height = height;
1552     surface->linesize = linesize;
1553     surface->pf = qemu_default_pixelformat(bpp);
1554 #ifdef WORDS_BIGENDIAN
1555     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1556 #endif
1557     surface->data = data;
1558
1559     return surface;
1560 }
1561
1562 void qemu_free_displaysurface(DisplaySurface *surface)
1563 {
1564     if (surface == NULL)
1565         return;
1566     if (surface->flags & QEMU_ALLOCATED_FLAG)
1567         qemu_free(surface->data);
1568     qemu_free(surface);
1569 }