packing update
[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         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;
1076         }
1077         dpy_resize(s->ds);
1078         vga_hw_invalidate();
1079     }
1080 }
1081
1082 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1083 {
1084     TextConsole *s = chr->opaque;
1085     int i;
1086
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]);
1094     }
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);
1100     }
1101     return len;
1102 }
1103
1104 static void console_send_event(CharDriverState *chr, int event)
1105 {
1106     TextConsole *s = chr->opaque;
1107     int i;
1108
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;
1114             }
1115         }
1116     }
1117 }
1118
1119 static void kbd_send_chars(void *opaque)
1120 {
1121     TextConsole *s = opaque;
1122     int len;
1123     uint8_t buf[16];
1124
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);
1133     }
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);
1138     }
1139 }
1140
1141 /* called when an ascii key is pressed */
1142 void kbd_put_keysym(int keysym)
1143 {
1144     TextConsole *s;
1145     uint8_t buf[16], *q;
1146     int c;
1147
1148     s = active_console;
1149     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1150         return;
1151
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;
1182         }
1183         if (s->chr->chr_read) {
1184             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1185             kbd_send_chars(s);
1186         }
1187         break;
1188     }
1189 }
1190
1191 static void text_console_invalidate(void *opaque)
1192 {
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);
1198     }
1199     console_refresh(s);
1200 }
1201
1202 static void text_console_update(void *opaque, console_ch_t *chardata)
1203 {
1204     TextConsole *s = (TextConsole *) opaque;
1205     int i, j, src;
1206
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;
1222     }
1223     if (s->cursor_invalidate) {
1224         dpy_cursor(s->ds, s->x, s->y);
1225         s->cursor_invalidate = 0;
1226     }
1227 }
1228
1229 static TextConsole *get_graphic_console(DisplayState *ds)
1230 {
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;
1237     }
1238     return NULL;
1239 }
1240
1241 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1242 {
1243     TextConsole *s;
1244     int i;
1245
1246     if (nb_consoles >= MAX_CONSOLES)
1247         return NULL;
1248     s = qemu_mallocz(sizeof(TextConsole));
1249     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1250         (console_type == GRAPHIC_CONSOLE))) {
1251         active_console = s;
1252     }
1253     s->ds = ds;
1254     s->console_type = console_type;
1255     if (console_type != GRAPHIC_CONSOLE) {
1256         consoles[nb_consoles++] = s;
1257     } else {
1258         /* HACK: Put graphical consoles before text consoles.  */
1259         for (i = nb_consoles; i > 0; i--) {
1260             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1261                 break;
1262             consoles[i] = consoles[i - 1];
1263         }
1264         consoles[i] = s;
1265         nb_consoles++;
1266     }
1267     return s;
1268 }
1269
1270 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1271                                    vga_hw_invalidate_ptr invalidate,
1272                                    vga_hw_screen_dump_ptr screen_dump,
1273                                    vga_hw_text_update_ptr text_update,
1274                                    void *opaque)
1275 {
1276     TextConsole *s;
1277     DisplayState *ds;
1278
1279     ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1280     ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
1281
1282     s = new_console(ds, GRAPHIC_CONSOLE);
1283     if (s == NULL) {
1284         qemu_free_displaysurface(ds->surface);
1285         qemu_free(ds);
1286         return NULL;
1287     }
1288     s->hw_update = update;
1289     s->hw_invalidate = invalidate;
1290     s->hw_screen_dump = screen_dump;
1291     s->hw_text_update = text_update;
1292     s->hw = opaque;
1293
1294     register_displaystate(ds);
1295     return ds;
1296 }
1297
1298 int is_graphic_console(void)
1299 {
1300     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1301 }
1302
1303 int is_fixedsize_console(void)
1304 {
1305     return active_console && active_console->console_type != TEXT_CONSOLE;
1306 }
1307
1308 void console_color_init(DisplayState *ds)
1309 {
1310     int i, j;
1311     for (j = 0; j < 2; j++) {
1312         for (i = 0; i < 8; i++) {
1313             color_table[j][i] = col_expand(ds,
1314                    vga_get_color(ds, color_table_rgb[j][i]));
1315         }
1316     }
1317 }
1318
1319 static int n_text_consoles;
1320 static CharDriverState *text_consoles[128];
1321 static char *text_console_strs[128];
1322
1323 static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
1324 {
1325     TextConsole *s;
1326     unsigned width;
1327     unsigned height;
1328     static int color_inited;
1329
1330     s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1331     if (!s) {
1332         free(chr);
1333         return;
1334     }
1335     chr->opaque = s;
1336     chr->chr_write = console_puts;
1337     chr->chr_send_event = console_send_event;
1338
1339     s->chr = chr;
1340     s->out_fifo.buf = s->out_fifo_buf;
1341     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1342     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1343     s->ds = ds;
1344
1345     if (!color_inited) {
1346         color_inited = 1;
1347         console_color_init(s->ds);
1348     }
1349     s->y_displayed = 0;
1350     s->y_base = 0;
1351     s->total_height = DEFAULT_BACKSCROLL;
1352     s->x = 0;
1353     s->y = 0;
1354     width = ds_get_width(s->ds);
1355     height = ds_get_height(s->ds);
1356     if (p != NULL) {
1357         width = strtoul(p, (char **)&p, 10);
1358         if (*p == 'C') {
1359             p++;
1360             width *= FONT_WIDTH;
1361         }
1362         if (*p == 'x') {
1363             p++;
1364             height = strtoul(p, (char **)&p, 10);
1365             if (*p == 'C') {
1366                 p++;
1367                 height *= FONT_HEIGHT;
1368             }
1369         }
1370     }
1371     s->g_width = width;
1372     s->g_height = height;
1373
1374     s->hw_invalidate = text_console_invalidate;
1375     s->hw_text_update = text_console_update;
1376     s->hw = s;
1377
1378     /* Set text attribute defaults */
1379     s->t_attrib_default.bold = 0;
1380     s->t_attrib_default.uline = 0;
1381     s->t_attrib_default.blink = 0;
1382     s->t_attrib_default.invers = 0;
1383     s->t_attrib_default.unvisible = 0;
1384     s->t_attrib_default.fgcol = COLOR_WHITE;
1385     s->t_attrib_default.bgcol = COLOR_BLACK;
1386     /* set current text attributes to default */
1387     s->t_attrib = s->t_attrib_default;
1388     text_console_resize(s);
1389
1390     qemu_chr_reset(chr);
1391     if (chr->init)
1392         chr->init(chr);
1393 }
1394
1395 CharDriverState *text_console_init(const char *p)
1396 {
1397     CharDriverState *chr;
1398
1399     chr = qemu_mallocz(sizeof(CharDriverState));
1400
1401     if (n_text_consoles == 128) {
1402         fprintf(stderr, "Too many text consoles\n");
1403         exit(1);
1404     }
1405     text_consoles[n_text_consoles] = chr;
1406     text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1407     n_text_consoles++;
1408
1409     return chr;
1410 }
1411
1412 void text_consoles_set_display(DisplayState *ds)
1413 {
1414     int i;
1415
1416     for (i = 0; i < n_text_consoles; i++) {
1417         text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1418         qemu_free(text_console_strs[i]);
1419     }
1420
1421     n_text_consoles = 0;
1422 }
1423
1424 void qemu_console_resize(DisplayState *ds, int width, int height)
1425 {
1426     TextConsole *s = get_graphic_console(ds);
1427     if (!s) return;
1428
1429     s->g_width = width;
1430     s->g_height = height;
1431     if (is_graphic_console()) {
1432         ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
1433         dpy_resize(ds);
1434     }
1435 }
1436
1437 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1438                        int dst_x, int dst_y, int w, int h)
1439 {
1440     if (is_graphic_console()) {
1441         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1442     }
1443 }
1444
1445 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1446 {
1447     PixelFormat pf;
1448
1449     memset(&pf, 0x00, sizeof(PixelFormat));
1450
1451     pf.bits_per_pixel = bpp;
1452     pf.bytes_per_pixel = bpp / 8;
1453     pf.depth = bpp == 32 ? 24 : bpp;
1454
1455     switch (bpp) {
1456         case 24:
1457             pf.rmask = 0x000000FF;
1458             pf.gmask = 0x0000FF00;
1459             pf.bmask = 0x00FF0000;
1460             pf.rmax = 255;
1461             pf.gmax = 255;
1462             pf.bmax = 255;
1463             pf.rshift = 0;
1464             pf.gshift = 8;
1465             pf.bshift = 16;
1466             pf.rbits = 8;
1467             pf.gbits = 8;
1468             pf.bbits = 8;
1469             break;
1470         case 32:
1471             pf.rmask = 0x0000FF00;
1472             pf.gmask = 0x00FF0000;
1473             pf.bmask = 0xFF000000;
1474             pf.amask = 0x00000000;
1475             pf.amax = 255;
1476             pf.rmax = 255;
1477             pf.gmax = 255;
1478             pf.bmax = 255;
1479             pf.ashift = 0;
1480             pf.rshift = 8;
1481             pf.gshift = 16;
1482             pf.bshift = 24;
1483             pf.rbits = 8;
1484             pf.gbits = 8;
1485             pf.bbits = 8;
1486             pf.abits = 8;
1487             break;
1488         default:
1489             break;
1490     }
1491     return pf;
1492 }
1493
1494 PixelFormat qemu_default_pixelformat(int bpp)
1495 {
1496     PixelFormat pf;
1497
1498     memset(&pf, 0x00, sizeof(PixelFormat));
1499
1500     pf.bits_per_pixel = bpp;
1501     pf.bytes_per_pixel = bpp / 8;
1502     pf.depth = bpp == 32 ? 24 : bpp;
1503
1504     switch (bpp) {
1505         case 16:
1506             pf.rmask = 0x0000F800;
1507             pf.gmask = 0x000007E0;
1508             pf.bmask = 0x0000001F;
1509             pf.rmax = 31;
1510             pf.gmax = 63;
1511             pf.bmax = 31;
1512             pf.rshift = 11;
1513             pf.gshift = 5;
1514             pf.bshift = 0;
1515             pf.rbits = 5;
1516             pf.gbits = 6;
1517             pf.bbits = 5;
1518             break;
1519         case 24:
1520             pf.rmask = 0x00FF0000;
1521             pf.gmask = 0x0000FF00;
1522             pf.bmask = 0x000000FF;
1523             pf.rmax = 255;
1524             pf.gmax = 255;
1525             pf.bmax = 255;
1526             pf.rshift = 16;
1527             pf.gshift = 8;
1528             pf.bshift = 0;
1529             pf.rbits = 8;
1530             pf.gbits = 8;
1531             pf.bbits = 8;
1532         case 32:
1533             pf.rmask = 0x00FF0000;
1534             pf.gmask = 0x0000FF00;
1535             pf.bmask = 0x000000FF;
1536             pf.amax = 255;
1537             pf.rmax = 255;
1538             pf.gmax = 255;
1539             pf.bmax = 255;
1540             pf.ashift = 24;
1541             pf.rshift = 16;
1542             pf.gshift = 8;
1543             pf.bshift = 0;
1544             pf.rbits = 8;
1545             pf.gbits = 8;
1546             pf.bbits = 8;
1547             pf.abits = 8;
1548             break;
1549         default:
1550             break;
1551     }
1552     return pf;
1553 }
1554
1555 DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
1556 {
1557     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1558
1559     surface->width = width;
1560     surface->height = height;
1561     surface->linesize = linesize;
1562     surface->pf = qemu_default_pixelformat(bpp);
1563 #ifdef WORDS_BIGENDIAN
1564     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1565 #else
1566     surface->flags = QEMU_ALLOCATED_FLAG;
1567 #endif
1568     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1569
1570     return surface;
1571 }
1572
1573 DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
1574                                           int width, int height, int bpp, int linesize)
1575 {
1576     surface->width = width;
1577     surface->height = height;
1578     surface->linesize = linesize;
1579     surface->pf = qemu_default_pixelformat(bpp);
1580     if (surface->flags & QEMU_ALLOCATED_FLAG)
1581         surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1582     else
1583         surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1584 #ifdef WORDS_BIGENDIAN
1585     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1586 #else
1587     surface->flags = QEMU_ALLOCATED_FLAG;
1588 #endif
1589
1590     return surface;
1591 }
1592
1593 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1594                                               int linesize, uint8_t *data)
1595 {
1596     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1597
1598     surface->width = width;
1599     surface->height = height;
1600     surface->linesize = linesize;
1601     surface->pf = qemu_default_pixelformat(bpp);
1602 #ifdef WORDS_BIGENDIAN
1603     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1604 #endif
1605     surface->data = data;
1606
1607     return surface;
1608 }
1609
1610 void qemu_free_displaysurface(DisplaySurface *surface)
1611 {
1612     if (surface == NULL)
1613         return;
1614     if (surface->flags & QEMU_ALLOCATED_FLAG)
1615         qemu_free(surface->data);
1616     qemu_free(surface);
1617 }