]> Git Repo - qemu.git/blob - console.c
QMP: Introduce RTC_CHANGE event
[qemu.git] / 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
32 #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33 #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
34
35 typedef struct TextAttributes {
36     uint8_t fgcol:4;
37     uint8_t bgcol:4;
38     uint8_t bold:1;
39     uint8_t uline:1;
40     uint8_t blink:1;
41     uint8_t invers:1;
42     uint8_t unvisible:1;
43 } TextAttributes;
44
45 typedef struct TextCell {
46     uint8_t ch;
47     TextAttributes t_attrib;
48 } TextCell;
49
50 #define MAX_ESC_PARAMS 3
51
52 enum TTYState {
53     TTY_STATE_NORM,
54     TTY_STATE_ESC,
55     TTY_STATE_CSI,
56 };
57
58 typedef struct QEMUFIFO {
59     uint8_t *buf;
60     int buf_size;
61     int count, wptr, rptr;
62 } QEMUFIFO;
63
64 static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
65 {
66     int l, len;
67
68     l = f->buf_size - f->count;
69     if (len1 > l)
70         len1 = l;
71     len = len1;
72     while (len > 0) {
73         l = f->buf_size - f->wptr;
74         if (l > len)
75             l = len;
76         memcpy(f->buf + f->wptr, buf, l);
77         f->wptr += l;
78         if (f->wptr >= f->buf_size)
79             f->wptr = 0;
80         buf += l;
81         len -= l;
82     }
83     f->count += len1;
84     return len1;
85 }
86
87 static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
88 {
89     int l, len;
90
91     if (len1 > f->count)
92         len1 = f->count;
93     len = len1;
94     while (len > 0) {
95         l = f->buf_size - f->rptr;
96         if (l > len)
97             l = len;
98         memcpy(buf, f->buf + f->rptr, l);
99         f->rptr += l;
100         if (f->rptr >= f->buf_size)
101             f->rptr = 0;
102         buf += l;
103         len -= l;
104     }
105     f->count -= len1;
106     return len1;
107 }
108
109 typedef enum {
110     GRAPHIC_CONSOLE,
111     TEXT_CONSOLE,
112     TEXT_CONSOLE_FIXED_SIZE
113 } console_type_t;
114
115 /* ??? This is mis-named.
116    It is used for both text and graphical consoles.  */
117 struct TextConsole {
118     console_type_t console_type;
119     DisplayState *ds;
120     /* Graphic console state.  */
121     vga_hw_update_ptr hw_update;
122     vga_hw_invalidate_ptr hw_invalidate;
123     vga_hw_screen_dump_ptr hw_screen_dump;
124     vga_hw_text_update_ptr hw_text_update;
125     void *hw;
126
127     int g_width, g_height;
128     int width;
129     int height;
130     int total_height;
131     int backscroll_height;
132     int x, y;
133     int x_saved, y_saved;
134     int y_displayed;
135     int y_base;
136     TextAttributes t_attrib_default; /* default text attributes */
137     TextAttributes t_attrib; /* currently active text attributes */
138     TextCell *cells;
139     int text_x[2], text_y[2], cursor_invalidate;
140
141     int update_x0;
142     int update_y0;
143     int update_x1;
144     int update_y1;
145
146     enum TTYState state;
147     int esc_params[MAX_ESC_PARAMS];
148     int nb_esc_params;
149
150     CharDriverState *chr;
151     /* fifo for key pressed */
152     QEMUFIFO out_fifo;
153     uint8_t out_fifo_buf[16];
154     QEMUTimer *kbd_timer;
155 };
156
157 static DisplayState *display_state;
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 HOST_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, s->g_width, s->g_height);
1072         } else {
1073             s->ds->surface->width = s->width;
1074             s->ds->surface->height = s->height;
1075         }
1076         dpy_resize(s->ds);
1077         vga_hw_invalidate();
1078     }
1079 }
1080
1081 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1082 {
1083     TextConsole *s = chr->opaque;
1084     int i;
1085
1086     s->update_x0 = s->width * FONT_WIDTH;
1087     s->update_y0 = s->height * FONT_HEIGHT;
1088     s->update_x1 = 0;
1089     s->update_y1 = 0;
1090     console_show_cursor(s, 0);
1091     for(i = 0; i < len; i++) {
1092         console_putchar(s, buf[i]);
1093     }
1094     console_show_cursor(s, 1);
1095     if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1096         dpy_update(s->ds, s->update_x0, s->update_y0,
1097                    s->update_x1 - s->update_x0,
1098                    s->update_y1 - s->update_y0);
1099     }
1100     return len;
1101 }
1102
1103 static void console_send_event(CharDriverState *chr, int event)
1104 {
1105     TextConsole *s = chr->opaque;
1106     int i;
1107
1108     if (event == CHR_EVENT_FOCUS) {
1109         for(i = 0; i < nb_consoles; i++) {
1110             if (consoles[i] == s) {
1111                 console_select(i);
1112                 break;
1113             }
1114         }
1115     }
1116 }
1117
1118 static void kbd_send_chars(void *opaque)
1119 {
1120     TextConsole *s = opaque;
1121     int len;
1122     uint8_t buf[16];
1123
1124     len = qemu_chr_can_read(s->chr);
1125     if (len > s->out_fifo.count)
1126         len = s->out_fifo.count;
1127     if (len > 0) {
1128         if (len > sizeof(buf))
1129             len = sizeof(buf);
1130         qemu_fifo_read(&s->out_fifo, buf, len);
1131         qemu_chr_read(s->chr, buf, len);
1132     }
1133     /* characters are pending: we send them a bit later (XXX:
1134        horrible, should change char device API) */
1135     if (s->out_fifo.count > 0) {
1136         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1137     }
1138 }
1139
1140 /* called when an ascii key is pressed */
1141 void kbd_put_keysym(int keysym)
1142 {
1143     TextConsole *s;
1144     uint8_t buf[16], *q;
1145     int c;
1146
1147     s = active_console;
1148     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1149         return;
1150
1151     switch(keysym) {
1152     case QEMU_KEY_CTRL_UP:
1153         console_scroll(-1);
1154         break;
1155     case QEMU_KEY_CTRL_DOWN:
1156         console_scroll(1);
1157         break;
1158     case QEMU_KEY_CTRL_PAGEUP:
1159         console_scroll(-10);
1160         break;
1161     case QEMU_KEY_CTRL_PAGEDOWN:
1162         console_scroll(10);
1163         break;
1164     default:
1165         /* convert the QEMU keysym to VT100 key string */
1166         q = buf;
1167         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1168             *q++ = '\033';
1169             *q++ = '[';
1170             c = keysym - 0xe100;
1171             if (c >= 10)
1172                 *q++ = '0' + (c / 10);
1173             *q++ = '0' + (c % 10);
1174             *q++ = '~';
1175         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1176             *q++ = '\033';
1177             *q++ = '[';
1178             *q++ = keysym & 0xff;
1179         } else {
1180                 *q++ = keysym;
1181         }
1182         if (s->chr->chr_read) {
1183             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1184             kbd_send_chars(s);
1185         }
1186         break;
1187     }
1188 }
1189
1190 static void text_console_invalidate(void *opaque)
1191 {
1192     TextConsole *s = (TextConsole *) opaque;
1193     if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1194         s->g_width = ds_get_width(s->ds);
1195         s->g_height = ds_get_height(s->ds);
1196         text_console_resize(s);
1197     }
1198     console_refresh(s);
1199 }
1200
1201 static void text_console_update(void *opaque, console_ch_t *chardata)
1202 {
1203     TextConsole *s = (TextConsole *) opaque;
1204     int i, j, src;
1205
1206     if (s->text_x[0] <= s->text_x[1]) {
1207         src = (s->y_base + s->text_y[0]) * s->width;
1208         chardata += s->text_y[0] * s->width;
1209         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1210             for (j = 0; j < s->width; j ++, src ++)
1211                 console_write_ch(chardata ++, s->cells[src].ch |
1212                                 (s->cells[src].t_attrib.fgcol << 12) |
1213                                 (s->cells[src].t_attrib.bgcol << 8) |
1214                                 (s->cells[src].t_attrib.bold << 21));
1215         dpy_update(s->ds, s->text_x[0], s->text_y[0],
1216                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1217         s->text_x[0] = s->width;
1218         s->text_y[0] = s->height;
1219         s->text_x[1] = 0;
1220         s->text_y[1] = 0;
1221     }
1222     if (s->cursor_invalidate) {
1223         dpy_cursor(s->ds, s->x, s->y);
1224         s->cursor_invalidate = 0;
1225     }
1226 }
1227
1228 static TextConsole *get_graphic_console(DisplayState *ds)
1229 {
1230     int i;
1231     TextConsole *s;
1232     for (i = 0; i < nb_consoles; i++) {
1233         s = consoles[i];
1234         if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1235             return s;
1236     }
1237     return NULL;
1238 }
1239
1240 static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1241 {
1242     TextConsole *s;
1243     int i;
1244
1245     if (nb_consoles >= MAX_CONSOLES)
1246         return NULL;
1247     s = qemu_mallocz(sizeof(TextConsole));
1248     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1249         (console_type == GRAPHIC_CONSOLE))) {
1250         active_console = s;
1251     }
1252     s->ds = ds;
1253     s->console_type = console_type;
1254     if (console_type != GRAPHIC_CONSOLE) {
1255         consoles[nb_consoles++] = s;
1256     } else {
1257         /* HACK: Put graphical consoles before text consoles.  */
1258         for (i = nb_consoles; i > 0; i--) {
1259             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1260                 break;
1261             consoles[i] = consoles[i - 1];
1262         }
1263         consoles[i] = s;
1264         nb_consoles++;
1265     }
1266     return s;
1267 }
1268
1269 static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1270 {
1271     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1272
1273     surface->width = width;
1274     surface->height = height;
1275     surface->linesize = width * 4;
1276     surface->pf = qemu_default_pixelformat(32);
1277 #ifdef HOST_WORDS_BIGENDIAN
1278     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1279 #else
1280     surface->flags = QEMU_ALLOCATED_FLAG;
1281 #endif
1282     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1283
1284     return surface;
1285 }
1286
1287 static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1288                                           int width, int height)
1289 {
1290     surface->width = width;
1291     surface->height = height;
1292     surface->linesize = width * 4;
1293     surface->pf = qemu_default_pixelformat(32);
1294     if (surface->flags & QEMU_ALLOCATED_FLAG)
1295         surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1296     else
1297         surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1298 #ifdef HOST_WORDS_BIGENDIAN
1299     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1300 #else
1301     surface->flags = QEMU_ALLOCATED_FLAG;
1302 #endif
1303
1304     return surface;
1305 }
1306
1307 DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1308                                               int linesize, uint8_t *data)
1309 {
1310     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1311
1312     surface->width = width;
1313     surface->height = height;
1314     surface->linesize = linesize;
1315     surface->pf = qemu_default_pixelformat(bpp);
1316 #ifdef HOST_WORDS_BIGENDIAN
1317     surface->flags = QEMU_BIG_ENDIAN_FLAG;
1318 #endif
1319     surface->data = data;
1320
1321     return surface;
1322 }
1323
1324 static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1325 {
1326     if (surface == NULL)
1327         return;
1328     if (surface->flags & QEMU_ALLOCATED_FLAG)
1329         qemu_free(surface->data);
1330     qemu_free(surface);
1331 }
1332
1333 static struct DisplayAllocator default_allocator = {
1334     defaultallocator_create_displaysurface,
1335     defaultallocator_resize_displaysurface,
1336     defaultallocator_free_displaysurface
1337 };
1338
1339 static void dumb_display_init(void)
1340 {
1341     DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1342     ds->allocator = &default_allocator;
1343     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1344     register_displaystate(ds);
1345 }
1346
1347 /***********************************************************/
1348 /* register display */
1349
1350 void register_displaystate(DisplayState *ds)
1351 {
1352     DisplayState **s;
1353     s = &display_state;
1354     while (*s != NULL)
1355         s = &(*s)->next;
1356     ds->next = NULL;
1357     *s = ds;
1358 }
1359
1360 DisplayState *get_displaystate(void)
1361 {
1362     if (!display_state) {
1363         dumb_display_init ();
1364     }
1365     return display_state;
1366 }
1367
1368 DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1369 {
1370     if(ds->allocator ==  &default_allocator) {
1371         DisplaySurface *surf;
1372         surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1373         defaultallocator_free_displaysurface(ds->surface);
1374         ds->surface = surf;
1375         ds->allocator = da;
1376     }
1377     return ds->allocator;
1378 }
1379
1380 DisplayState *graphic_console_init(vga_hw_update_ptr update,
1381                                    vga_hw_invalidate_ptr invalidate,
1382                                    vga_hw_screen_dump_ptr screen_dump,
1383                                    vga_hw_text_update_ptr text_update,
1384                                    void *opaque)
1385 {
1386     TextConsole *s;
1387     DisplayState *ds;
1388
1389     ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1390     ds->allocator = &default_allocator; 
1391     ds->surface = qemu_create_displaysurface(ds, 640, 480);
1392
1393     s = new_console(ds, GRAPHIC_CONSOLE);
1394     if (s == NULL) {
1395         qemu_free_displaysurface(ds);
1396         qemu_free(ds);
1397         return NULL;
1398     }
1399     s->hw_update = update;
1400     s->hw_invalidate = invalidate;
1401     s->hw_screen_dump = screen_dump;
1402     s->hw_text_update = text_update;
1403     s->hw = opaque;
1404
1405     register_displaystate(ds);
1406     return ds;
1407 }
1408
1409 int is_graphic_console(void)
1410 {
1411     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1412 }
1413
1414 int is_fixedsize_console(void)
1415 {
1416     return active_console && active_console->console_type != TEXT_CONSOLE;
1417 }
1418
1419 void console_color_init(DisplayState *ds)
1420 {
1421     int i, j;
1422     for (j = 0; j < 2; j++) {
1423         for (i = 0; i < 8; i++) {
1424             color_table[j][i] = col_expand(ds,
1425                    vga_get_color(ds, color_table_rgb[j][i]));
1426         }
1427     }
1428 }
1429
1430 static int n_text_consoles;
1431 static CharDriverState *text_consoles[128];
1432 static QemuOpts *text_console_opts[128];
1433
1434 static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
1435 {
1436     TextConsole *s;
1437     unsigned width;
1438     unsigned height;
1439     static int color_inited;
1440
1441     width = qemu_opt_get_number(opts, "width", 0);
1442     if (width == 0)
1443         width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1444
1445     height = qemu_opt_get_number(opts, "height", 0);
1446     if (height == 0)
1447         height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1448
1449     if (width == 0 || height == 0) {
1450         s = new_console(ds, TEXT_CONSOLE);
1451         width = ds_get_width(s->ds);
1452         height = ds_get_height(s->ds);
1453     } else {
1454         s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1455     }
1456
1457     if (!s) {
1458         free(chr);
1459         return;
1460     }
1461     chr->opaque = s;
1462     chr->chr_write = console_puts;
1463     chr->chr_send_event = console_send_event;
1464
1465     s->chr = chr;
1466     s->out_fifo.buf = s->out_fifo_buf;
1467     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1468     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1469     s->ds = ds;
1470
1471     if (!color_inited) {
1472         color_inited = 1;
1473         console_color_init(s->ds);
1474     }
1475     s->y_displayed = 0;
1476     s->y_base = 0;
1477     s->total_height = DEFAULT_BACKSCROLL;
1478     s->x = 0;
1479     s->y = 0;
1480     s->g_width = width;
1481     s->g_height = height;
1482
1483     s->hw_invalidate = text_console_invalidate;
1484     s->hw_text_update = text_console_update;
1485     s->hw = s;
1486
1487     /* Set text attribute defaults */
1488     s->t_attrib_default.bold = 0;
1489     s->t_attrib_default.uline = 0;
1490     s->t_attrib_default.blink = 0;
1491     s->t_attrib_default.invers = 0;
1492     s->t_attrib_default.unvisible = 0;
1493     s->t_attrib_default.fgcol = COLOR_WHITE;
1494     s->t_attrib_default.bgcol = COLOR_BLACK;
1495     /* set current text attributes to default */
1496     s->t_attrib = s->t_attrib_default;
1497     text_console_resize(s);
1498
1499     if (chr->label) {
1500         char msg[128];
1501         int len;
1502
1503         s->t_attrib.bgcol = COLOR_BLUE;
1504         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1505         console_puts(chr, (uint8_t*)msg, len);
1506         s->t_attrib = s->t_attrib_default;
1507     }
1508
1509     qemu_chr_generic_open(chr);
1510     if (chr->init)
1511         chr->init(chr);
1512 }
1513
1514 CharDriverState *text_console_init(QemuOpts *opts)
1515 {
1516     CharDriverState *chr;
1517
1518     chr = qemu_mallocz(sizeof(CharDriverState));
1519
1520     if (n_text_consoles == 128) {
1521         fprintf(stderr, "Too many text consoles\n");
1522         exit(1);
1523     }
1524     text_consoles[n_text_consoles] = chr;
1525     text_console_opts[n_text_consoles] = opts;
1526     n_text_consoles++;
1527
1528     return chr;
1529 }
1530
1531 void text_consoles_set_display(DisplayState *ds)
1532 {
1533     int i;
1534
1535     for (i = 0; i < n_text_consoles; i++) {
1536         text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1537         qemu_opts_del(text_console_opts[i]);
1538         text_console_opts[i] = NULL;
1539     }
1540
1541     n_text_consoles = 0;
1542 }
1543
1544 void qemu_console_resize(DisplayState *ds, int width, int height)
1545 {
1546     TextConsole *s = get_graphic_console(ds);
1547     if (!s) return;
1548
1549     s->g_width = width;
1550     s->g_height = height;
1551     if (is_graphic_console()) {
1552         ds->surface = qemu_resize_displaysurface(ds, width, height);
1553         dpy_resize(ds);
1554     }
1555 }
1556
1557 void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1558                        int dst_x, int dst_y, int w, int h)
1559 {
1560     if (is_graphic_console()) {
1561         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1562     }
1563 }
1564
1565 PixelFormat qemu_different_endianness_pixelformat(int bpp)
1566 {
1567     PixelFormat pf;
1568
1569     memset(&pf, 0x00, sizeof(PixelFormat));
1570
1571     pf.bits_per_pixel = bpp;
1572     pf.bytes_per_pixel = bpp / 8;
1573     pf.depth = bpp == 32 ? 24 : bpp;
1574
1575     switch (bpp) {
1576         case 24:
1577             pf.rmask = 0x000000FF;
1578             pf.gmask = 0x0000FF00;
1579             pf.bmask = 0x00FF0000;
1580             pf.rmax = 255;
1581             pf.gmax = 255;
1582             pf.bmax = 255;
1583             pf.rshift = 0;
1584             pf.gshift = 8;
1585             pf.bshift = 16;
1586             pf.rbits = 8;
1587             pf.gbits = 8;
1588             pf.bbits = 8;
1589             break;
1590         case 32:
1591             pf.rmask = 0x0000FF00;
1592             pf.gmask = 0x00FF0000;
1593             pf.bmask = 0xFF000000;
1594             pf.amask = 0x00000000;
1595             pf.amax = 255;
1596             pf.rmax = 255;
1597             pf.gmax = 255;
1598             pf.bmax = 255;
1599             pf.ashift = 0;
1600             pf.rshift = 8;
1601             pf.gshift = 16;
1602             pf.bshift = 24;
1603             pf.rbits = 8;
1604             pf.gbits = 8;
1605             pf.bbits = 8;
1606             pf.abits = 8;
1607             break;
1608         default:
1609             break;
1610     }
1611     return pf;
1612 }
1613
1614 PixelFormat qemu_default_pixelformat(int bpp)
1615 {
1616     PixelFormat pf;
1617
1618     memset(&pf, 0x00, sizeof(PixelFormat));
1619
1620     pf.bits_per_pixel = bpp;
1621     pf.bytes_per_pixel = bpp / 8;
1622     pf.depth = bpp == 32 ? 24 : bpp;
1623
1624     switch (bpp) {
1625         case 16:
1626             pf.rmask = 0x0000F800;
1627             pf.gmask = 0x000007E0;
1628             pf.bmask = 0x0000001F;
1629             pf.rmax = 31;
1630             pf.gmax = 63;
1631             pf.bmax = 31;
1632             pf.rshift = 11;
1633             pf.gshift = 5;
1634             pf.bshift = 0;
1635             pf.rbits = 5;
1636             pf.gbits = 6;
1637             pf.bbits = 5;
1638             break;
1639         case 24:
1640             pf.rmask = 0x00FF0000;
1641             pf.gmask = 0x0000FF00;
1642             pf.bmask = 0x000000FF;
1643             pf.rmax = 255;
1644             pf.gmax = 255;
1645             pf.bmax = 255;
1646             pf.rshift = 16;
1647             pf.gshift = 8;
1648             pf.bshift = 0;
1649             pf.rbits = 8;
1650             pf.gbits = 8;
1651             pf.bbits = 8;
1652         case 32:
1653             pf.rmask = 0x00FF0000;
1654             pf.gmask = 0x0000FF00;
1655             pf.bmask = 0x000000FF;
1656             pf.amax = 255;
1657             pf.rmax = 255;
1658             pf.gmax = 255;
1659             pf.bmax = 255;
1660             pf.ashift = 24;
1661             pf.rshift = 16;
1662             pf.gshift = 8;
1663             pf.bshift = 0;
1664             pf.rbits = 8;
1665             pf.gbits = 8;
1666             pf.bbits = 8;
1667             pf.abits = 8;
1668             break;
1669         default:
1670             break;
1671     }
1672     return pf;
1673 }
This page took 0.114874 seconds and 4 git commands to generate.