]> Git Repo - qemu.git/blob - ui/console.c
dma: remove now useless DMA_* functions
[qemu.git] / ui / 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 "ui/console.h"
26 #include "hw/qdev-core.h"
27 #include "qemu/timer.h"
28 #include "qmp-commands.h"
29 #include "sysemu/char.h"
30 #include "trace.h"
31 #include "exec/memory.h"
32
33 #define DEFAULT_BACKSCROLL 512
34 #define CONSOLE_CURSOR_PERIOD 500
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 struct QemuConsole {
117     Object parent;
118
119     int index;
120     console_type_t console_type;
121     DisplayState *ds;
122     DisplaySurface *surface;
123     int dcls;
124     DisplayChangeListener *gl;
125
126     /* Graphic console state.  */
127     Object *device;
128     uint32_t head;
129     QemuUIInfo ui_info;
130     QEMUTimer *ui_timer;
131     const GraphicHwOps *hw_ops;
132     void *hw;
133
134     /* Text console state */
135     int width;
136     int height;
137     int total_height;
138     int backscroll_height;
139     int x, y;
140     int x_saved, y_saved;
141     int y_displayed;
142     int y_base;
143     TextAttributes t_attrib_default; /* default text attributes */
144     TextAttributes t_attrib; /* currently active text attributes */
145     TextCell *cells;
146     int text_x[2], text_y[2], cursor_invalidate;
147     int echo;
148
149     int update_x0;
150     int update_y0;
151     int update_x1;
152     int update_y1;
153
154     enum TTYState state;
155     int esc_params[MAX_ESC_PARAMS];
156     int nb_esc_params;
157
158     CharDriverState *chr;
159     /* fifo for key pressed */
160     QEMUFIFO out_fifo;
161     uint8_t out_fifo_buf[16];
162     QEMUTimer *kbd_timer;
163 };
164
165 struct DisplayState {
166     QEMUTimer *gui_timer;
167     uint64_t last_update;
168     uint64_t update_interval;
169     bool refreshing;
170     bool have_gfx;
171     bool have_text;
172
173     QLIST_HEAD(, DisplayChangeListener) listeners;
174 };
175
176 static DisplayState *display_state;
177 static QemuConsole *active_console;
178 static QemuConsole **consoles;
179 static int nb_consoles = 0;
180 static bool cursor_visible_phase;
181 static QEMUTimer *cursor_timer;
182
183 static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
184 static void dpy_refresh(DisplayState *s);
185 static DisplayState *get_alloc_displaystate(void);
186 static void text_console_update_cursor_timer(void);
187 static void text_console_update_cursor(void *opaque);
188
189 static void gui_update(void *opaque)
190 {
191     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
192     uint64_t dcl_interval;
193     DisplayState *ds = opaque;
194     DisplayChangeListener *dcl;
195     int i;
196
197     ds->refreshing = true;
198     dpy_refresh(ds);
199     ds->refreshing = false;
200
201     QLIST_FOREACH(dcl, &ds->listeners, next) {
202         dcl_interval = dcl->update_interval ?
203             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
204         if (interval > dcl_interval) {
205             interval = dcl_interval;
206         }
207     }
208     if (ds->update_interval != interval) {
209         ds->update_interval = interval;
210         for (i = 0; i < nb_consoles; i++) {
211             if (consoles[i]->hw_ops->update_interval) {
212                 consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
213             }
214         }
215         trace_console_refresh(interval);
216     }
217     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
218     timer_mod(ds->gui_timer, ds->last_update + interval);
219 }
220
221 static void gui_setup_refresh(DisplayState *ds)
222 {
223     DisplayChangeListener *dcl;
224     bool need_timer = false;
225     bool have_gfx = false;
226     bool have_text = false;
227
228     QLIST_FOREACH(dcl, &ds->listeners, next) {
229         if (dcl->ops->dpy_refresh != NULL) {
230             need_timer = true;
231         }
232         if (dcl->ops->dpy_gfx_update != NULL) {
233             have_gfx = true;
234         }
235         if (dcl->ops->dpy_text_update != NULL) {
236             have_text = true;
237         }
238     }
239
240     if (need_timer && ds->gui_timer == NULL) {
241         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
242         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
243     }
244     if (!need_timer && ds->gui_timer != NULL) {
245         timer_del(ds->gui_timer);
246         timer_free(ds->gui_timer);
247         ds->gui_timer = NULL;
248     }
249
250     ds->have_gfx = have_gfx;
251     ds->have_text = have_text;
252 }
253
254 void graphic_hw_update(QemuConsole *con)
255 {
256     if (!con) {
257         con = active_console;
258     }
259     if (con && con->hw_ops->gfx_update) {
260         con->hw_ops->gfx_update(con->hw);
261     }
262 }
263
264 void graphic_hw_gl_block(QemuConsole *con, bool block)
265 {
266     if (!con) {
267         con = active_console;
268     }
269     if (con && con->hw_ops->gl_block) {
270         con->hw_ops->gl_block(con->hw, block);
271     }
272 }
273
274 void graphic_hw_invalidate(QemuConsole *con)
275 {
276     if (!con) {
277         con = active_console;
278     }
279     if (con && con->hw_ops->invalidate) {
280         con->hw_ops->invalidate(con->hw);
281     }
282 }
283
284 static void ppm_save(const char *filename, DisplaySurface *ds,
285                      Error **errp)
286 {
287     int width = pixman_image_get_width(ds->image);
288     int height = pixman_image_get_height(ds->image);
289     int fd;
290     FILE *f;
291     int y;
292     int ret;
293     pixman_image_t *linebuf;
294
295     trace_ppm_save(filename, ds);
296     fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
297     if (fd == -1) {
298         error_setg(errp, "failed to open file '%s': %s", filename,
299                    strerror(errno));
300         return;
301     }
302     f = fdopen(fd, "wb");
303     ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
304     if (ret < 0) {
305         linebuf = NULL;
306         goto write_err;
307     }
308     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
309     for (y = 0; y < height; y++) {
310         qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
311         clearerr(f);
312         ret = fwrite(pixman_image_get_data(linebuf), 1,
313                      pixman_image_get_stride(linebuf), f);
314         (void)ret;
315         if (ferror(f)) {
316             goto write_err;
317         }
318     }
319
320 out:
321     qemu_pixman_image_unref(linebuf);
322     fclose(f);
323     return;
324
325 write_err:
326     error_setg(errp, "failed to write to file '%s': %s", filename,
327                strerror(errno));
328     unlink(filename);
329     goto out;
330 }
331
332 void qmp_screendump(const char *filename, Error **errp)
333 {
334     QemuConsole *con = qemu_console_lookup_by_index(0);
335     DisplaySurface *surface;
336
337     if (con == NULL) {
338         error_setg(errp, "There is no QemuConsole I can screendump from.");
339         return;
340     }
341
342     graphic_hw_update(con);
343     surface = qemu_console_surface(con);
344     ppm_save(filename, surface, errp);
345 }
346
347 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
348 {
349     if (!con) {
350         con = active_console;
351     }
352     if (con && con->hw_ops->text_update) {
353         con->hw_ops->text_update(con->hw, chardata);
354     }
355 }
356
357 static void vga_fill_rect(QemuConsole *con,
358                           int posx, int posy, int width, int height,
359                           pixman_color_t color)
360 {
361     DisplaySurface *surface = qemu_console_surface(con);
362     pixman_rectangle16_t rect = {
363         .x = posx, .y = posy, .width = width, .height = height
364     };
365
366     pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
367                                  &color, 1, &rect);
368 }
369
370 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
371 static void vga_bitblt(QemuConsole *con,
372                        int xs, int ys, int xd, int yd, int w, int h)
373 {
374     DisplaySurface *surface = qemu_console_surface(con);
375
376     pixman_image_composite(PIXMAN_OP_SRC,
377                            surface->image, NULL, surface->image,
378                            xs, ys, 0, 0, xd, yd, w, h);
379 }
380
381 /***********************************************************/
382 /* basic char display */
383
384 #define FONT_HEIGHT 16
385 #define FONT_WIDTH 8
386
387 #include "vgafont.h"
388
389 #define QEMU_RGB(r, g, b)                                               \
390     { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
391
392 static const pixman_color_t color_table_rgb[2][8] = {
393     {   /* dark */
394         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
395         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
396         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
397         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
398         [QEMU_COLOR_RED]     = QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
399         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
400         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
401         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
402     },
403     {   /* bright */
404         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
405         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
406         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xff, 0x00),  /* green */
407         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
408         [QEMU_COLOR_RED]     = QEMU_RGB(0xff, 0x00, 0x00),  /* red */
409         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
410         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
411         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xff, 0xff, 0xff),  /* white */
412     }
413 };
414
415 static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
416                           TextAttributes *t_attrib)
417 {
418     static pixman_image_t *glyphs[256];
419     DisplaySurface *surface = qemu_console_surface(s);
420     pixman_color_t fgcol, bgcol;
421
422     if (t_attrib->invers) {
423         bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
424         fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
425     } else {
426         fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
427         bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
428     }
429
430     if (!glyphs[ch]) {
431         glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
432     }
433     qemu_pixman_glyph_render(glyphs[ch], surface->image,
434                              &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
435 }
436
437 static void text_console_resize(QemuConsole *s)
438 {
439     TextCell *cells, *c, *c1;
440     int w1, x, y, last_width;
441
442     last_width = s->width;
443     s->width = surface_width(s->surface) / FONT_WIDTH;
444     s->height = surface_height(s->surface) / FONT_HEIGHT;
445
446     w1 = last_width;
447     if (s->width < w1)
448         w1 = s->width;
449
450     cells = g_new(TextCell, s->width * s->total_height);
451     for(y = 0; y < s->total_height; y++) {
452         c = &cells[y * s->width];
453         if (w1 > 0) {
454             c1 = &s->cells[y * last_width];
455             for(x = 0; x < w1; x++) {
456                 *c++ = *c1++;
457             }
458         }
459         for(x = w1; x < s->width; x++) {
460             c->ch = ' ';
461             c->t_attrib = s->t_attrib_default;
462             c++;
463         }
464     }
465     g_free(s->cells);
466     s->cells = cells;
467 }
468
469 static inline void text_update_xy(QemuConsole *s, int x, int y)
470 {
471     s->text_x[0] = MIN(s->text_x[0], x);
472     s->text_x[1] = MAX(s->text_x[1], x);
473     s->text_y[0] = MIN(s->text_y[0], y);
474     s->text_y[1] = MAX(s->text_y[1], y);
475 }
476
477 static void invalidate_xy(QemuConsole *s, int x, int y)
478 {
479     if (!qemu_console_is_visible(s)) {
480         return;
481     }
482     if (s->update_x0 > x * FONT_WIDTH)
483         s->update_x0 = x * FONT_WIDTH;
484     if (s->update_y0 > y * FONT_HEIGHT)
485         s->update_y0 = y * FONT_HEIGHT;
486     if (s->update_x1 < (x + 1) * FONT_WIDTH)
487         s->update_x1 = (x + 1) * FONT_WIDTH;
488     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
489         s->update_y1 = (y + 1) * FONT_HEIGHT;
490 }
491
492 static void update_xy(QemuConsole *s, int x, int y)
493 {
494     TextCell *c;
495     int y1, y2;
496
497     if (s->ds->have_text) {
498         text_update_xy(s, x, y);
499     }
500
501     y1 = (s->y_base + y) % s->total_height;
502     y2 = y1 - s->y_displayed;
503     if (y2 < 0) {
504         y2 += s->total_height;
505     }
506     if (y2 < s->height) {
507         c = &s->cells[y1 * s->width + x];
508         vga_putcharxy(s, x, y2, c->ch,
509                       &(c->t_attrib));
510         invalidate_xy(s, x, y2);
511     }
512 }
513
514 static void console_show_cursor(QemuConsole *s, int show)
515 {
516     TextCell *c;
517     int y, y1;
518     int x = s->x;
519
520     if (s->ds->have_text) {
521         s->cursor_invalidate = 1;
522     }
523
524     if (x >= s->width) {
525         x = s->width - 1;
526     }
527     y1 = (s->y_base + s->y) % s->total_height;
528     y = y1 - s->y_displayed;
529     if (y < 0) {
530         y += s->total_height;
531     }
532     if (y < s->height) {
533         c = &s->cells[y1 * s->width + x];
534         if (show && cursor_visible_phase) {
535             TextAttributes t_attrib = s->t_attrib_default;
536             t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
537             vga_putcharxy(s, x, y, c->ch, &t_attrib);
538         } else {
539             vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
540         }
541         invalidate_xy(s, x, y);
542     }
543 }
544
545 static void console_refresh(QemuConsole *s)
546 {
547     DisplaySurface *surface = qemu_console_surface(s);
548     TextCell *c;
549     int x, y, y1;
550
551     if (s->ds->have_text) {
552         s->text_x[0] = 0;
553         s->text_y[0] = 0;
554         s->text_x[1] = s->width - 1;
555         s->text_y[1] = s->height - 1;
556         s->cursor_invalidate = 1;
557     }
558
559     vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
560                   color_table_rgb[0][QEMU_COLOR_BLACK]);
561     y1 = s->y_displayed;
562     for (y = 0; y < s->height; y++) {
563         c = s->cells + y1 * s->width;
564         for (x = 0; x < s->width; x++) {
565             vga_putcharxy(s, x, y, c->ch,
566                           &(c->t_attrib));
567             c++;
568         }
569         if (++y1 == s->total_height) {
570             y1 = 0;
571         }
572     }
573     console_show_cursor(s, 1);
574     dpy_gfx_update(s, 0, 0,
575                    surface_width(surface), surface_height(surface));
576 }
577
578 static void console_scroll(QemuConsole *s, int ydelta)
579 {
580     int i, y1;
581
582     if (ydelta > 0) {
583         for(i = 0; i < ydelta; i++) {
584             if (s->y_displayed == s->y_base)
585                 break;
586             if (++s->y_displayed == s->total_height)
587                 s->y_displayed = 0;
588         }
589     } else {
590         ydelta = -ydelta;
591         i = s->backscroll_height;
592         if (i > s->total_height - s->height)
593             i = s->total_height - s->height;
594         y1 = s->y_base - i;
595         if (y1 < 0)
596             y1 += s->total_height;
597         for(i = 0; i < ydelta; i++) {
598             if (s->y_displayed == y1)
599                 break;
600             if (--s->y_displayed < 0)
601                 s->y_displayed = s->total_height - 1;
602         }
603     }
604     console_refresh(s);
605 }
606
607 static void console_put_lf(QemuConsole *s)
608 {
609     TextCell *c;
610     int x, y1;
611
612     s->y++;
613     if (s->y >= s->height) {
614         s->y = s->height - 1;
615
616         if (s->y_displayed == s->y_base) {
617             if (++s->y_displayed == s->total_height)
618                 s->y_displayed = 0;
619         }
620         if (++s->y_base == s->total_height)
621             s->y_base = 0;
622         if (s->backscroll_height < s->total_height)
623             s->backscroll_height++;
624         y1 = (s->y_base + s->height - 1) % s->total_height;
625         c = &s->cells[y1 * s->width];
626         for(x = 0; x < s->width; x++) {
627             c->ch = ' ';
628             c->t_attrib = s->t_attrib_default;
629             c++;
630         }
631         if (s->y_displayed == s->y_base) {
632             if (s->ds->have_text) {
633                 s->text_x[0] = 0;
634                 s->text_y[0] = 0;
635                 s->text_x[1] = s->width - 1;
636                 s->text_y[1] = s->height - 1;
637             }
638
639             vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
640                        s->width * FONT_WIDTH,
641                        (s->height - 1) * FONT_HEIGHT);
642             vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
643                           s->width * FONT_WIDTH, FONT_HEIGHT,
644                           color_table_rgb[0][s->t_attrib_default.bgcol]);
645             s->update_x0 = 0;
646             s->update_y0 = 0;
647             s->update_x1 = s->width * FONT_WIDTH;
648             s->update_y1 = s->height * FONT_HEIGHT;
649         }
650     }
651 }
652
653 /* Set console attributes depending on the current escape codes.
654  * NOTE: I know this code is not very efficient (checking every color for it
655  * self) but it is more readable and better maintainable.
656  */
657 static void console_handle_escape(QemuConsole *s)
658 {
659     int i;
660
661     for (i=0; i<s->nb_esc_params; i++) {
662         switch (s->esc_params[i]) {
663             case 0: /* reset all console attributes to default */
664                 s->t_attrib = s->t_attrib_default;
665                 break;
666             case 1:
667                 s->t_attrib.bold = 1;
668                 break;
669             case 4:
670                 s->t_attrib.uline = 1;
671                 break;
672             case 5:
673                 s->t_attrib.blink = 1;
674                 break;
675             case 7:
676                 s->t_attrib.invers = 1;
677                 break;
678             case 8:
679                 s->t_attrib.unvisible = 1;
680                 break;
681             case 22:
682                 s->t_attrib.bold = 0;
683                 break;
684             case 24:
685                 s->t_attrib.uline = 0;
686                 break;
687             case 25:
688                 s->t_attrib.blink = 0;
689                 break;
690             case 27:
691                 s->t_attrib.invers = 0;
692                 break;
693             case 28:
694                 s->t_attrib.unvisible = 0;
695                 break;
696             /* set foreground color */
697             case 30:
698                 s->t_attrib.fgcol = QEMU_COLOR_BLACK;
699                 break;
700             case 31:
701                 s->t_attrib.fgcol = QEMU_COLOR_RED;
702                 break;
703             case 32:
704                 s->t_attrib.fgcol = QEMU_COLOR_GREEN;
705                 break;
706             case 33:
707                 s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
708                 break;
709             case 34:
710                 s->t_attrib.fgcol = QEMU_COLOR_BLUE;
711                 break;
712             case 35:
713                 s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
714                 break;
715             case 36:
716                 s->t_attrib.fgcol = QEMU_COLOR_CYAN;
717                 break;
718             case 37:
719                 s->t_attrib.fgcol = QEMU_COLOR_WHITE;
720                 break;
721             /* set background color */
722             case 40:
723                 s->t_attrib.bgcol = QEMU_COLOR_BLACK;
724                 break;
725             case 41:
726                 s->t_attrib.bgcol = QEMU_COLOR_RED;
727                 break;
728             case 42:
729                 s->t_attrib.bgcol = QEMU_COLOR_GREEN;
730                 break;
731             case 43:
732                 s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
733                 break;
734             case 44:
735                 s->t_attrib.bgcol = QEMU_COLOR_BLUE;
736                 break;
737             case 45:
738                 s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
739                 break;
740             case 46:
741                 s->t_attrib.bgcol = QEMU_COLOR_CYAN;
742                 break;
743             case 47:
744                 s->t_attrib.bgcol = QEMU_COLOR_WHITE;
745                 break;
746         }
747     }
748 }
749
750 static void console_clear_xy(QemuConsole *s, int x, int y)
751 {
752     int y1 = (s->y_base + y) % s->total_height;
753     TextCell *c = &s->cells[y1 * s->width + x];
754     c->ch = ' ';
755     c->t_attrib = s->t_attrib_default;
756     update_xy(s, x, y);
757 }
758
759 /* set cursor, checking bounds */
760 static void set_cursor(QemuConsole *s, int x, int y)
761 {
762     if (x < 0) {
763         x = 0;
764     }
765     if (y < 0) {
766         y = 0;
767     }
768     if (y >= s->height) {
769         y = s->height - 1;
770     }
771     if (x >= s->width) {
772         x = s->width - 1;
773     }
774
775     s->x = x;
776     s->y = y;
777 }
778
779 static void console_putchar(QemuConsole *s, int ch)
780 {
781     TextCell *c;
782     int y1, i;
783     int x, y;
784
785     switch(s->state) {
786     case TTY_STATE_NORM:
787         switch(ch) {
788         case '\r':  /* carriage return */
789             s->x = 0;
790             break;
791         case '\n':  /* newline */
792             console_put_lf(s);
793             break;
794         case '\b':  /* backspace */
795             if (s->x > 0)
796                 s->x--;
797             break;
798         case '\t':  /* tabspace */
799             if (s->x + (8 - (s->x % 8)) > s->width) {
800                 s->x = 0;
801                 console_put_lf(s);
802             } else {
803                 s->x = s->x + (8 - (s->x % 8));
804             }
805             break;
806         case '\a':  /* alert aka. bell */
807             /* TODO: has to be implemented */
808             break;
809         case 14:
810             /* SI (shift in), character set 0 (ignored) */
811             break;
812         case 15:
813             /* SO (shift out), character set 1 (ignored) */
814             break;
815         case 27:    /* esc (introducing an escape sequence) */
816             s->state = TTY_STATE_ESC;
817             break;
818         default:
819             if (s->x >= s->width) {
820                 /* line wrap */
821                 s->x = 0;
822                 console_put_lf(s);
823             }
824             y1 = (s->y_base + s->y) % s->total_height;
825             c = &s->cells[y1 * s->width + s->x];
826             c->ch = ch;
827             c->t_attrib = s->t_attrib;
828             update_xy(s, s->x, s->y);
829             s->x++;
830             break;
831         }
832         break;
833     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
834         if (ch == '[') {
835             for(i=0;i<MAX_ESC_PARAMS;i++)
836                 s->esc_params[i] = 0;
837             s->nb_esc_params = 0;
838             s->state = TTY_STATE_CSI;
839         } else {
840             s->state = TTY_STATE_NORM;
841         }
842         break;
843     case TTY_STATE_CSI: /* handle escape sequence parameters */
844         if (ch >= '0' && ch <= '9') {
845             if (s->nb_esc_params < MAX_ESC_PARAMS) {
846                 int *param = &s->esc_params[s->nb_esc_params];
847                 int digit = (ch - '0');
848
849                 *param = (*param <= (INT_MAX - digit) / 10) ?
850                          *param * 10 + digit : INT_MAX;
851             }
852         } else {
853             if (s->nb_esc_params < MAX_ESC_PARAMS)
854                 s->nb_esc_params++;
855             if (ch == ';')
856                 break;
857             trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
858                                       ch, s->nb_esc_params);
859             s->state = TTY_STATE_NORM;
860             switch(ch) {
861             case 'A':
862                 /* move cursor up */
863                 if (s->esc_params[0] == 0) {
864                     s->esc_params[0] = 1;
865                 }
866                 set_cursor(s, s->x, s->y - s->esc_params[0]);
867                 break;
868             case 'B':
869                 /* move cursor down */
870                 if (s->esc_params[0] == 0) {
871                     s->esc_params[0] = 1;
872                 }
873                 set_cursor(s, s->x, s->y + s->esc_params[0]);
874                 break;
875             case 'C':
876                 /* move cursor right */
877                 if (s->esc_params[0] == 0) {
878                     s->esc_params[0] = 1;
879                 }
880                 set_cursor(s, s->x + s->esc_params[0], s->y);
881                 break;
882             case 'D':
883                 /* move cursor left */
884                 if (s->esc_params[0] == 0) {
885                     s->esc_params[0] = 1;
886                 }
887                 set_cursor(s, s->x - s->esc_params[0], s->y);
888                 break;
889             case 'G':
890                 /* move cursor to column */
891                 set_cursor(s, s->esc_params[0] - 1, s->y);
892                 break;
893             case 'f':
894             case 'H':
895                 /* move cursor to row, column */
896                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
897                 break;
898             case 'J':
899                 switch (s->esc_params[0]) {
900                 case 0:
901                     /* clear to end of screen */
902                     for (y = s->y; y < s->height; y++) {
903                         for (x = 0; x < s->width; x++) {
904                             if (y == s->y && x < s->x) {
905                                 continue;
906                             }
907                             console_clear_xy(s, x, y);
908                         }
909                     }
910                     break;
911                 case 1:
912                     /* clear from beginning of screen */
913                     for (y = 0; y <= s->y; y++) {
914                         for (x = 0; x < s->width; x++) {
915                             if (y == s->y && x > s->x) {
916                                 break;
917                             }
918                             console_clear_xy(s, x, y);
919                         }
920                     }
921                     break;
922                 case 2:
923                     /* clear entire screen */
924                     for (y = 0; y <= s->height; y++) {
925                         for (x = 0; x < s->width; x++) {
926                             console_clear_xy(s, x, y);
927                         }
928                     }
929                     break;
930                 }
931                 break;
932             case 'K':
933                 switch (s->esc_params[0]) {
934                 case 0:
935                     /* clear to eol */
936                     for(x = s->x; x < s->width; x++) {
937                         console_clear_xy(s, x, s->y);
938                     }
939                     break;
940                 case 1:
941                     /* clear from beginning of line */
942                     for (x = 0; x <= s->x; x++) {
943                         console_clear_xy(s, x, s->y);
944                     }
945                     break;
946                 case 2:
947                     /* clear entire line */
948                     for(x = 0; x < s->width; x++) {
949                         console_clear_xy(s, x, s->y);
950                     }
951                     break;
952                 }
953                 break;
954             case 'm':
955                 console_handle_escape(s);
956                 break;
957             case 'n':
958                 /* report cursor position */
959                 /* TODO: send ESC[row;colR */
960                 break;
961             case 's':
962                 /* save cursor position */
963                 s->x_saved = s->x;
964                 s->y_saved = s->y;
965                 break;
966             case 'u':
967                 /* restore cursor position */
968                 s->x = s->x_saved;
969                 s->y = s->y_saved;
970                 break;
971             default:
972                 trace_console_putchar_unhandled(ch);
973                 break;
974             }
975             break;
976         }
977     }
978 }
979
980 void console_select(unsigned int index)
981 {
982     DisplayChangeListener *dcl;
983     QemuConsole *s;
984
985     trace_console_select(index);
986     s = qemu_console_lookup_by_index(index);
987     if (s) {
988         DisplayState *ds = s->ds;
989
990         active_console = s;
991         if (ds->have_gfx) {
992             QLIST_FOREACH(dcl, &ds->listeners, next) {
993                 if (dcl->con != NULL) {
994                     continue;
995                 }
996                 if (dcl->ops->dpy_gfx_switch) {
997                     dcl->ops->dpy_gfx_switch(dcl, s->surface);
998                 }
999             }
1000             dpy_gfx_update(s, 0, 0, surface_width(s->surface),
1001                            surface_height(s->surface));
1002         }
1003         if (ds->have_text) {
1004             dpy_text_resize(s, s->width, s->height);
1005         }
1006         text_console_update_cursor(NULL);
1007     }
1008 }
1009
1010 static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1011 {
1012     QemuConsole *s = chr->opaque;
1013     int i;
1014
1015     s->update_x0 = s->width * FONT_WIDTH;
1016     s->update_y0 = s->height * FONT_HEIGHT;
1017     s->update_x1 = 0;
1018     s->update_y1 = 0;
1019     console_show_cursor(s, 0);
1020     for(i = 0; i < len; i++) {
1021         console_putchar(s, buf[i]);
1022     }
1023     console_show_cursor(s, 1);
1024     if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1025         dpy_gfx_update(s, s->update_x0, s->update_y0,
1026                        s->update_x1 - s->update_x0,
1027                        s->update_y1 - s->update_y0);
1028     }
1029     return len;
1030 }
1031
1032 static void kbd_send_chars(void *opaque)
1033 {
1034     QemuConsole *s = opaque;
1035     int len;
1036     uint8_t buf[16];
1037
1038     len = qemu_chr_be_can_write(s->chr);
1039     if (len > s->out_fifo.count)
1040         len = s->out_fifo.count;
1041     if (len > 0) {
1042         if (len > sizeof(buf))
1043             len = sizeof(buf);
1044         qemu_fifo_read(&s->out_fifo, buf, len);
1045         qemu_chr_be_write(s->chr, buf, len);
1046     }
1047     /* characters are pending: we send them a bit later (XXX:
1048        horrible, should change char device API) */
1049     if (s->out_fifo.count > 0) {
1050         timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
1051     }
1052 }
1053
1054 /* called when an ascii key is pressed */
1055 void kbd_put_keysym_console(QemuConsole *s, int keysym)
1056 {
1057     uint8_t buf[16], *q;
1058     int c;
1059
1060     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1061         return;
1062
1063     switch(keysym) {
1064     case QEMU_KEY_CTRL_UP:
1065         console_scroll(s, -1);
1066         break;
1067     case QEMU_KEY_CTRL_DOWN:
1068         console_scroll(s, 1);
1069         break;
1070     case QEMU_KEY_CTRL_PAGEUP:
1071         console_scroll(s, -10);
1072         break;
1073     case QEMU_KEY_CTRL_PAGEDOWN:
1074         console_scroll(s, 10);
1075         break;
1076     default:
1077         /* convert the QEMU keysym to VT100 key string */
1078         q = buf;
1079         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1080             *q++ = '\033';
1081             *q++ = '[';
1082             c = keysym - 0xe100;
1083             if (c >= 10)
1084                 *q++ = '0' + (c / 10);
1085             *q++ = '0' + (c % 10);
1086             *q++ = '~';
1087         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1088             *q++ = '\033';
1089             *q++ = '[';
1090             *q++ = keysym & 0xff;
1091         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1092             console_puts(s->chr, (const uint8_t *) "\r", 1);
1093             *q++ = '\n';
1094         } else {
1095             *q++ = keysym;
1096         }
1097         if (s->echo) {
1098             console_puts(s->chr, buf, q - buf);
1099         }
1100         if (s->chr->chr_read) {
1101             qemu_fifo_write(&s->out_fifo, buf, q - buf);
1102             kbd_send_chars(s);
1103         }
1104         break;
1105     }
1106 }
1107
1108 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
1109     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
1110     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
1111     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
1112     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
1113     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
1114     [Q_KEY_CODE_END]    = QEMU_KEY_END,
1115     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
1116     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
1117     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
1118 };
1119
1120 bool kbd_put_qcode_console(QemuConsole *s, int qcode)
1121 {
1122     int keysym;
1123
1124     keysym = qcode_to_keysym[qcode];
1125     if (keysym == 0) {
1126         return false;
1127     }
1128     kbd_put_keysym_console(s, keysym);
1129     return true;
1130 }
1131
1132 void kbd_put_string_console(QemuConsole *s, const char *str, int len)
1133 {
1134     int i;
1135
1136     for (i = 0; i < len && str[i]; i++) {
1137         kbd_put_keysym_console(s, str[i]);
1138     }
1139 }
1140
1141 void kbd_put_keysym(int keysym)
1142 {
1143     kbd_put_keysym_console(active_console, keysym);
1144 }
1145
1146 static void text_console_invalidate(void *opaque)
1147 {
1148     QemuConsole *s = (QemuConsole *) opaque;
1149
1150     if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1151         text_console_resize(s);
1152     }
1153     console_refresh(s);
1154 }
1155
1156 static void text_console_update(void *opaque, console_ch_t *chardata)
1157 {
1158     QemuConsole *s = (QemuConsole *) opaque;
1159     int i, j, src;
1160
1161     if (s->text_x[0] <= s->text_x[1]) {
1162         src = (s->y_base + s->text_y[0]) * s->width;
1163         chardata += s->text_y[0] * s->width;
1164         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1165             for (j = 0; j < s->width; j++, src++) {
1166                 console_write_ch(chardata ++,
1167                                  ATTR2CHTYPE(s->cells[src].ch,
1168                                              s->cells[src].t_attrib.fgcol,
1169                                              s->cells[src].t_attrib.bgcol,
1170                                              s->cells[src].t_attrib.bold));
1171             }
1172         dpy_text_update(s, s->text_x[0], s->text_y[0],
1173                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1174         s->text_x[0] = s->width;
1175         s->text_y[0] = s->height;
1176         s->text_x[1] = 0;
1177         s->text_y[1] = 0;
1178     }
1179     if (s->cursor_invalidate) {
1180         dpy_text_cursor(s, s->x, s->y);
1181         s->cursor_invalidate = 0;
1182     }
1183 }
1184
1185 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
1186                                 uint32_t head)
1187 {
1188     Object *obj;
1189     QemuConsole *s;
1190     int i;
1191
1192     obj = object_new(TYPE_QEMU_CONSOLE);
1193     s = QEMU_CONSOLE(obj);
1194     s->head = head;
1195     object_property_add_link(obj, "device", TYPE_DEVICE,
1196                              (Object **)&s->device,
1197                              object_property_allow_set_link,
1198                              OBJ_PROP_LINK_UNREF_ON_RELEASE,
1199                              &error_abort);
1200     object_property_add_uint32_ptr(obj, "head",
1201                                    &s->head, &error_abort);
1202
1203     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1204         (console_type == GRAPHIC_CONSOLE))) {
1205         active_console = s;
1206     }
1207     s->ds = ds;
1208     s->console_type = console_type;
1209
1210     consoles = g_realloc(consoles, sizeof(*consoles) * (nb_consoles+1));
1211     if (console_type != GRAPHIC_CONSOLE) {
1212         s->index = nb_consoles;
1213         consoles[nb_consoles++] = s;
1214     } else {
1215         /* HACK: Put graphical consoles before text consoles.  */
1216         for (i = nb_consoles; i > 0; i--) {
1217             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1218                 break;
1219             consoles[i] = consoles[i - 1];
1220             consoles[i]->index = i;
1221         }
1222         s->index = i;
1223         consoles[i] = s;
1224         nb_consoles++;
1225     }
1226     return s;
1227 }
1228
1229 static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
1230 {
1231     qemu_pixman_image_unref(surface->image);
1232     surface->image = NULL;
1233
1234     surface->format = PIXMAN_x8r8g8b8;
1235     surface->image = pixman_image_create_bits(surface->format,
1236                                               width, height,
1237                                               NULL, width * 4);
1238     assert(surface->image != NULL);
1239
1240     surface->flags = QEMU_ALLOCATED_FLAG;
1241 }
1242
1243 DisplaySurface *qemu_create_displaysurface(int width, int height)
1244 {
1245     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1246
1247     trace_displaysurface_create(surface, width, height);
1248     qemu_alloc_display(surface, width, height);
1249     return surface;
1250 }
1251
1252 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1253                                                 pixman_format_code_t format,
1254                                                 int linesize, uint8_t *data)
1255 {
1256     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1257
1258     trace_displaysurface_create_from(surface, width, height, format);
1259     surface->format = format;
1260     surface->image = pixman_image_create_bits(surface->format,
1261                                               width, height,
1262                                               (void *)data, linesize);
1263     assert(surface->image != NULL);
1264
1265     return surface;
1266 }
1267
1268 static void qemu_unmap_displaysurface_guestmem(pixman_image_t *image,
1269                                                void *unused)
1270 {
1271     void *data = pixman_image_get_data(image);
1272     uint32_t size = pixman_image_get_stride(image) *
1273         pixman_image_get_height(image);
1274     cpu_physical_memory_unmap(data, size, 0, 0);
1275 }
1276
1277 DisplaySurface *qemu_create_displaysurface_guestmem(int width, int height,
1278                                                     pixman_format_code_t format,
1279                                                     int linesize, uint64_t addr)
1280 {
1281     DisplaySurface *surface;
1282     hwaddr size;
1283     void *data;
1284
1285     if (linesize == 0) {
1286         linesize = width * PIXMAN_FORMAT_BPP(format) / 8;
1287     }
1288
1289     size = (hwaddr)linesize * height;
1290     data = cpu_physical_memory_map(addr, &size, 0);
1291     if (size != (hwaddr)linesize * height) {
1292         cpu_physical_memory_unmap(data, size, 0, 0);
1293         return NULL;
1294     }
1295
1296     surface = qemu_create_displaysurface_from
1297         (width, height, format, linesize, data);
1298     pixman_image_set_destroy_function
1299         (surface->image, qemu_unmap_displaysurface_guestmem, NULL);
1300
1301     return surface;
1302 }
1303
1304 static DisplaySurface *qemu_create_message_surface(int w, int h,
1305                                                    const char *msg)
1306 {
1307     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1308     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1309     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1310     pixman_image_t *glyph;
1311     int len, x, y, i;
1312
1313     len = strlen(msg);
1314     x = (w / FONT_WIDTH  - len) / 2;
1315     y = (h / FONT_HEIGHT - 1)   / 2;
1316     for (i = 0; i < len; i++) {
1317         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1318         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1319                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1320         qemu_pixman_image_unref(glyph);
1321     }
1322     return surface;
1323 }
1324
1325 void qemu_free_displaysurface(DisplaySurface *surface)
1326 {
1327     if (surface == NULL) {
1328         return;
1329     }
1330     trace_displaysurface_free(surface);
1331     qemu_pixman_image_unref(surface->image);
1332     g_free(surface);
1333 }
1334
1335 bool console_has_gl(QemuConsole *con)
1336 {
1337     return con->gl != NULL;
1338 }
1339
1340 void register_displaychangelistener(DisplayChangeListener *dcl)
1341 {
1342     static const char nodev[] =
1343         "This VM has no graphic display device.";
1344     static DisplaySurface *dummy;
1345     QemuConsole *con;
1346
1347     if (dcl->ops->dpy_gl_ctx_create) {
1348         /* display has opengl support */
1349         assert(dcl->con);
1350         if (dcl->con->gl) {
1351             fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
1352                     dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
1353             exit(1);
1354         }
1355         dcl->con->gl = dcl;
1356     }
1357
1358     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1359     dcl->ds = get_alloc_displaystate();
1360     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1361     gui_setup_refresh(dcl->ds);
1362     if (dcl->con) {
1363         dcl->con->dcls++;
1364         con = dcl->con;
1365     } else {
1366         con = active_console;
1367     }
1368     if (dcl->ops->dpy_gfx_switch) {
1369         if (con) {
1370             dcl->ops->dpy_gfx_switch(dcl, con->surface);
1371         } else {
1372             if (!dummy) {
1373                 dummy = qemu_create_message_surface(640, 480, nodev);
1374             }
1375             dcl->ops->dpy_gfx_switch(dcl, dummy);
1376         }
1377     }
1378     text_console_update_cursor(NULL);
1379 }
1380
1381 void update_displaychangelistener(DisplayChangeListener *dcl,
1382                                   uint64_t interval)
1383 {
1384     DisplayState *ds = dcl->ds;
1385
1386     dcl->update_interval = interval;
1387     if (!ds->refreshing && ds->update_interval > interval) {
1388         timer_mod(ds->gui_timer, ds->last_update + interval);
1389     }
1390 }
1391
1392 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1393 {
1394     DisplayState *ds = dcl->ds;
1395     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1396     if (dcl->con) {
1397         dcl->con->dcls--;
1398     }
1399     QLIST_REMOVE(dcl, next);
1400     gui_setup_refresh(ds);
1401 }
1402
1403 static void dpy_set_ui_info_timer(void *opaque)
1404 {
1405     QemuConsole *con = opaque;
1406
1407     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1408 }
1409
1410 bool dpy_ui_info_supported(QemuConsole *con)
1411 {
1412     return con->hw_ops->ui_info != NULL;
1413 }
1414
1415 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
1416 {
1417     assert(con != NULL);
1418     con->ui_info = *info;
1419     if (!dpy_ui_info_supported(con)) {
1420         return -1;
1421     }
1422
1423     /*
1424      * Typically we get a flood of these as the user resizes the window.
1425      * Wait until the dust has settled (one second without updates), then
1426      * go notify the guest.
1427      */
1428     timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
1429     return 0;
1430 }
1431
1432 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1433 {
1434     DisplayState *s = con->ds;
1435     DisplayChangeListener *dcl;
1436     int width = w;
1437     int height = h;
1438
1439     if (con->surface) {
1440         width = surface_width(con->surface);
1441         height = surface_height(con->surface);
1442     }
1443     x = MAX(x, 0);
1444     y = MAX(y, 0);
1445     x = MIN(x, width);
1446     y = MIN(y, height);
1447     w = MIN(w, width - x);
1448     h = MIN(h, height - y);
1449
1450     if (!qemu_console_is_visible(con)) {
1451         return;
1452     }
1453     QLIST_FOREACH(dcl, &s->listeners, next) {
1454         if (con != (dcl->con ? dcl->con : active_console)) {
1455             continue;
1456         }
1457         if (dcl->ops->dpy_gfx_update) {
1458             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1459         }
1460     }
1461 }
1462
1463 void dpy_gfx_replace_surface(QemuConsole *con,
1464                              DisplaySurface *surface)
1465 {
1466     DisplayState *s = con->ds;
1467     DisplaySurface *old_surface = con->surface;
1468     DisplayChangeListener *dcl;
1469
1470     con->surface = surface;
1471     QLIST_FOREACH(dcl, &s->listeners, next) {
1472         if (con != (dcl->con ? dcl->con : active_console)) {
1473             continue;
1474         }
1475         if (dcl->ops->dpy_gfx_switch) {
1476             dcl->ops->dpy_gfx_switch(dcl, surface);
1477         }
1478     }
1479     qemu_free_displaysurface(old_surface);
1480 }
1481
1482 bool dpy_gfx_check_format(QemuConsole *con,
1483                           pixman_format_code_t format)
1484 {
1485     DisplayChangeListener *dcl;
1486     DisplayState *s = con->ds;
1487
1488     QLIST_FOREACH(dcl, &s->listeners, next) {
1489         if (dcl->con && dcl->con != con) {
1490             /* dcl bound to another console -> skip */
1491             continue;
1492         }
1493         if (dcl->ops->dpy_gfx_check_format) {
1494             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1495                 return false;
1496             }
1497         } else {
1498             /* default is to whitelist native 32 bpp only */
1499             if (format != qemu_default_pixman_format(32, true)) {
1500                 return false;
1501             }
1502         }
1503     }
1504     return true;
1505 }
1506
1507 static void dpy_refresh(DisplayState *s)
1508 {
1509     DisplayChangeListener *dcl;
1510
1511     QLIST_FOREACH(dcl, &s->listeners, next) {
1512         if (dcl->ops->dpy_refresh) {
1513             dcl->ops->dpy_refresh(dcl);
1514         }
1515     }
1516 }
1517
1518 void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
1519                   int dst_x, int dst_y, int w, int h)
1520 {
1521     DisplayState *s = con->ds;
1522     DisplayChangeListener *dcl;
1523
1524     if (!qemu_console_is_visible(con)) {
1525         return;
1526     }
1527     QLIST_FOREACH(dcl, &s->listeners, next) {
1528         if (con != (dcl->con ? dcl->con : active_console)) {
1529             continue;
1530         }
1531         if (dcl->ops->dpy_gfx_copy) {
1532             dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
1533         } else { /* TODO */
1534             dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
1535         }
1536     }
1537 }
1538
1539 void dpy_text_cursor(QemuConsole *con, int x, int y)
1540 {
1541     DisplayState *s = con->ds;
1542     DisplayChangeListener *dcl;
1543
1544     if (!qemu_console_is_visible(con)) {
1545         return;
1546     }
1547     QLIST_FOREACH(dcl, &s->listeners, next) {
1548         if (con != (dcl->con ? dcl->con : active_console)) {
1549             continue;
1550         }
1551         if (dcl->ops->dpy_text_cursor) {
1552             dcl->ops->dpy_text_cursor(dcl, x, y);
1553         }
1554     }
1555 }
1556
1557 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1558 {
1559     DisplayState *s = con->ds;
1560     DisplayChangeListener *dcl;
1561
1562     if (!qemu_console_is_visible(con)) {
1563         return;
1564     }
1565     QLIST_FOREACH(dcl, &s->listeners, next) {
1566         if (con != (dcl->con ? dcl->con : active_console)) {
1567             continue;
1568         }
1569         if (dcl->ops->dpy_text_update) {
1570             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1571         }
1572     }
1573 }
1574
1575 void dpy_text_resize(QemuConsole *con, int w, int h)
1576 {
1577     DisplayState *s = con->ds;
1578     DisplayChangeListener *dcl;
1579
1580     if (!qemu_console_is_visible(con)) {
1581         return;
1582     }
1583     QLIST_FOREACH(dcl, &s->listeners, next) {
1584         if (con != (dcl->con ? dcl->con : active_console)) {
1585             continue;
1586         }
1587         if (dcl->ops->dpy_text_resize) {
1588             dcl->ops->dpy_text_resize(dcl, w, h);
1589         }
1590     }
1591 }
1592
1593 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1594 {
1595     DisplayState *s = con->ds;
1596     DisplayChangeListener *dcl;
1597
1598     if (!qemu_console_is_visible(con)) {
1599         return;
1600     }
1601     QLIST_FOREACH(dcl, &s->listeners, next) {
1602         if (con != (dcl->con ? dcl->con : active_console)) {
1603             continue;
1604         }
1605         if (dcl->ops->dpy_mouse_set) {
1606             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1607         }
1608     }
1609 }
1610
1611 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1612 {
1613     DisplayState *s = con->ds;
1614     DisplayChangeListener *dcl;
1615
1616     if (!qemu_console_is_visible(con)) {
1617         return;
1618     }
1619     QLIST_FOREACH(dcl, &s->listeners, next) {
1620         if (con != (dcl->con ? dcl->con : active_console)) {
1621             continue;
1622         }
1623         if (dcl->ops->dpy_cursor_define) {
1624             dcl->ops->dpy_cursor_define(dcl, cursor);
1625         }
1626     }
1627 }
1628
1629 bool dpy_cursor_define_supported(QemuConsole *con)
1630 {
1631     DisplayState *s = con->ds;
1632     DisplayChangeListener *dcl;
1633
1634     QLIST_FOREACH(dcl, &s->listeners, next) {
1635         if (dcl->ops->dpy_cursor_define) {
1636             return true;
1637         }
1638     }
1639     return false;
1640 }
1641
1642 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1643                                 struct QEMUGLParams *qparams)
1644 {
1645     assert(con->gl);
1646     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1647 }
1648
1649 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1650 {
1651     assert(con->gl);
1652     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1653 }
1654
1655 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1656 {
1657     assert(con->gl);
1658     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1659 }
1660
1661 QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
1662 {
1663     assert(con->gl);
1664     return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
1665 }
1666
1667 void dpy_gl_scanout(QemuConsole *con,
1668                     uint32_t backing_id, bool backing_y_0_top,
1669                     uint32_t x, uint32_t y, uint32_t width, uint32_t height)
1670 {
1671     assert(con->gl);
1672     con->gl->ops->dpy_gl_scanout(con->gl, backing_id,
1673                                  backing_y_0_top,
1674                                  x, y, width, height);
1675 }
1676
1677 void dpy_gl_update(QemuConsole *con,
1678                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1679 {
1680     assert(con->gl);
1681     con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
1682 }
1683
1684 /***********************************************************/
1685 /* register display */
1686
1687 /* console.c internal use only */
1688 static DisplayState *get_alloc_displaystate(void)
1689 {
1690     if (!display_state) {
1691         display_state = g_new0(DisplayState, 1);
1692         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1693                                     text_console_update_cursor, NULL);
1694     }
1695     return display_state;
1696 }
1697
1698 /*
1699  * Called by main(), after creating QemuConsoles
1700  * and before initializing ui (sdl/vnc/...).
1701  */
1702 DisplayState *init_displaystate(void)
1703 {
1704     gchar *name;
1705     int i;
1706
1707     get_alloc_displaystate();
1708     for (i = 0; i < nb_consoles; i++) {
1709         if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
1710             consoles[i]->ds == NULL) {
1711             text_console_do_init(consoles[i]->chr, display_state);
1712         }
1713
1714         /* Hook up into the qom tree here (not in new_console()), once
1715          * all QemuConsoles are created and the order / numbering
1716          * doesn't change any more */
1717         name = g_strdup_printf("console[%d]", i);
1718         object_property_add_child(container_get(object_get_root(), "/backend"),
1719                                   name, OBJECT(consoles[i]), &error_abort);
1720         g_free(name);
1721     }
1722
1723     return display_state;
1724 }
1725
1726 void graphic_console_set_hwops(QemuConsole *con,
1727                                const GraphicHwOps *hw_ops,
1728                                void *opaque)
1729 {
1730     con->hw_ops = hw_ops;
1731     con->hw = opaque;
1732 }
1733
1734 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1735                                   const GraphicHwOps *hw_ops,
1736                                   void *opaque)
1737 {
1738     static const char noinit[] =
1739         "Guest has not initialized the display (yet).";
1740     int width = 640;
1741     int height = 480;
1742     QemuConsole *s;
1743     DisplayState *ds;
1744
1745     ds = get_alloc_displaystate();
1746     trace_console_gfx_new();
1747     s = new_console(ds, GRAPHIC_CONSOLE, head);
1748     s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, dpy_set_ui_info_timer, s);
1749     graphic_console_set_hwops(s, hw_ops, opaque);
1750     if (dev) {
1751         object_property_set_link(OBJECT(s), OBJECT(dev), "device",
1752                                  &error_abort);
1753     }
1754
1755     s->surface = qemu_create_message_surface(width, height, noinit);
1756     return s;
1757 }
1758
1759 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1760 {
1761     if (index >= nb_consoles) {
1762         return NULL;
1763     }
1764     return consoles[index];
1765 }
1766
1767 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1768 {
1769     Object *obj;
1770     uint32_t h;
1771     int i;
1772
1773     for (i = 0; i < nb_consoles; i++) {
1774         if (!consoles[i]) {
1775             continue;
1776         }
1777         obj = object_property_get_link(OBJECT(consoles[i]),
1778                                        "device", &error_abort);
1779         if (DEVICE(obj) != dev) {
1780             continue;
1781         }
1782         h = object_property_get_int(OBJECT(consoles[i]),
1783                                     "head", &error_abort);
1784         if (h != head) {
1785             continue;
1786         }
1787         return consoles[i];
1788     }
1789     return NULL;
1790 }
1791
1792 bool qemu_console_is_visible(QemuConsole *con)
1793 {
1794     return (con == active_console) || (con->dcls > 0);
1795 }
1796
1797 bool qemu_console_is_graphic(QemuConsole *con)
1798 {
1799     if (con == NULL) {
1800         con = active_console;
1801     }
1802     return con && (con->console_type == GRAPHIC_CONSOLE);
1803 }
1804
1805 bool qemu_console_is_fixedsize(QemuConsole *con)
1806 {
1807     if (con == NULL) {
1808         con = active_console;
1809     }
1810     return con && (con->console_type != TEXT_CONSOLE);
1811 }
1812
1813 char *qemu_console_get_label(QemuConsole *con)
1814 {
1815     if (con->console_type == GRAPHIC_CONSOLE) {
1816         if (con->device) {
1817             return g_strdup(object_get_typename(con->device));
1818         }
1819         return g_strdup("VGA");
1820     } else {
1821         if (con->chr && con->chr->label) {
1822             return g_strdup(con->chr->label);
1823         }
1824         return g_strdup_printf("vc%d", con->index);
1825     }
1826 }
1827
1828 int qemu_console_get_index(QemuConsole *con)
1829 {
1830     if (con == NULL) {
1831         con = active_console;
1832     }
1833     return con ? con->index : -1;
1834 }
1835
1836 uint32_t qemu_console_get_head(QemuConsole *con)
1837 {
1838     if (con == NULL) {
1839         con = active_console;
1840     }
1841     return con ? con->head : -1;
1842 }
1843
1844 QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
1845 {
1846     assert(con != NULL);
1847     return &con->ui_info;
1848 }
1849
1850 int qemu_console_get_width(QemuConsole *con, int fallback)
1851 {
1852     if (con == NULL) {
1853         con = active_console;
1854     }
1855     return con ? surface_width(con->surface) : fallback;
1856 }
1857
1858 int qemu_console_get_height(QemuConsole *con, int fallback)
1859 {
1860     if (con == NULL) {
1861         con = active_console;
1862     }
1863     return con ? surface_height(con->surface) : fallback;
1864 }
1865
1866 static void text_console_set_echo(CharDriverState *chr, bool echo)
1867 {
1868     QemuConsole *s = chr->opaque;
1869
1870     s->echo = echo;
1871 }
1872
1873 static void text_console_update_cursor_timer(void)
1874 {
1875     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
1876               + CONSOLE_CURSOR_PERIOD / 2);
1877 }
1878
1879 static void text_console_update_cursor(void *opaque)
1880 {
1881     QemuConsole *s;
1882     int i, count = 0;
1883
1884     cursor_visible_phase = !cursor_visible_phase;
1885
1886     for (i = 0; i < nb_consoles; i++) {
1887         s = consoles[i];
1888         if (qemu_console_is_graphic(s) ||
1889             !qemu_console_is_visible(s)) {
1890             continue;
1891         }
1892         count++;
1893         graphic_hw_invalidate(s);
1894     }
1895
1896     if (count) {
1897         text_console_update_cursor_timer();
1898     }
1899 }
1900
1901 static const GraphicHwOps text_console_ops = {
1902     .invalidate  = text_console_invalidate,
1903     .text_update = text_console_update,
1904 };
1905
1906 static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1907 {
1908     QemuConsole *s;
1909     int g_width = 80 * FONT_WIDTH;
1910     int g_height = 24 * FONT_HEIGHT;
1911
1912     s = chr->opaque;
1913
1914     chr->chr_write = console_puts;
1915
1916     s->out_fifo.buf = s->out_fifo_buf;
1917     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1918     s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
1919     s->ds = ds;
1920
1921     s->y_displayed = 0;
1922     s->y_base = 0;
1923     s->total_height = DEFAULT_BACKSCROLL;
1924     s->x = 0;
1925     s->y = 0;
1926     if (!s->surface) {
1927         if (active_console && active_console->surface) {
1928             g_width = surface_width(active_console->surface);
1929             g_height = surface_height(active_console->surface);
1930         }
1931         s->surface = qemu_create_displaysurface(g_width, g_height);
1932     }
1933
1934     s->hw_ops = &text_console_ops;
1935     s->hw = s;
1936
1937     /* Set text attribute defaults */
1938     s->t_attrib_default.bold = 0;
1939     s->t_attrib_default.uline = 0;
1940     s->t_attrib_default.blink = 0;
1941     s->t_attrib_default.invers = 0;
1942     s->t_attrib_default.unvisible = 0;
1943     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
1944     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
1945     /* set current text attributes to default */
1946     s->t_attrib = s->t_attrib_default;
1947     text_console_resize(s);
1948
1949     if (chr->label) {
1950         char msg[128];
1951         int len;
1952
1953         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
1954         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1955         console_puts(chr, (uint8_t*)msg, len);
1956         s->t_attrib = s->t_attrib_default;
1957     }
1958
1959     qemu_chr_be_generic_open(chr);
1960     if (chr->init)
1961         chr->init(chr);
1962 }
1963
1964 static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
1965 {
1966     ChardevCommon *common = qapi_ChardevVC_base(vc);
1967     CharDriverState *chr;
1968     QemuConsole *s;
1969     unsigned width = 0;
1970     unsigned height = 0;
1971
1972     chr = qemu_chr_alloc(common, errp);
1973     if (!chr) {
1974         return NULL;
1975     }
1976
1977     if (vc->has_width) {
1978         width = vc->width;
1979     } else if (vc->has_cols) {
1980         width = vc->cols * FONT_WIDTH;
1981     }
1982
1983     if (vc->has_height) {
1984         height = vc->height;
1985     } else if (vc->has_rows) {
1986         height = vc->rows * FONT_HEIGHT;
1987     }
1988
1989     trace_console_txt_new(width, height);
1990     if (width == 0 || height == 0) {
1991         s = new_console(NULL, TEXT_CONSOLE, 0);
1992     } else {
1993         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
1994         s->surface = qemu_create_displaysurface(width, height);
1995     }
1996
1997     if (!s) {
1998         g_free(chr);
1999         error_setg(errp, "cannot create text console");
2000         return NULL;
2001     }
2002
2003     s->chr = chr;
2004     chr->opaque = s;
2005     chr->chr_set_echo = text_console_set_echo;
2006     /* console/chardev init sometimes completes elsewhere in a 2nd
2007      * stage, so defer OPENED events until they are fully initialized
2008      */
2009     chr->explicit_be_open = true;
2010
2011     if (display_state) {
2012         text_console_do_init(chr, display_state);
2013     }
2014     return chr;
2015 }
2016
2017 static VcHandler *vc_handler = text_console_init;
2018
2019 static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
2020                                 ChardevReturn *ret, Error **errp)
2021 {
2022     return vc_handler(backend->u.vc, errp);
2023 }
2024
2025 void register_vc_handler(VcHandler *handler)
2026 {
2027     vc_handler = handler;
2028 }
2029
2030 void qemu_console_resize(QemuConsole *s, int width, int height)
2031 {
2032     DisplaySurface *surface;
2033
2034     assert(s->console_type == GRAPHIC_CONSOLE);
2035     surface = qemu_create_displaysurface(width, height);
2036     dpy_gfx_replace_surface(s, surface);
2037 }
2038
2039 void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
2040                        int dst_x, int dst_y, int w, int h)
2041 {
2042     assert(con->console_type == GRAPHIC_CONSOLE);
2043     dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
2044 }
2045
2046 DisplaySurface *qemu_console_surface(QemuConsole *console)
2047 {
2048     return console->surface;
2049 }
2050
2051 PixelFormat qemu_default_pixelformat(int bpp)
2052 {
2053     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2054     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2055     return pf;
2056 }
2057
2058 static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
2059                               Error **errp)
2060 {
2061     int val;
2062
2063     backend->u.vc = g_new0(ChardevVC, 1);
2064
2065     val = qemu_opt_get_number(opts, "width", 0);
2066     if (val != 0) {
2067         backend->u.vc->has_width = true;
2068         backend->u.vc->width = val;
2069     }
2070
2071     val = qemu_opt_get_number(opts, "height", 0);
2072     if (val != 0) {
2073         backend->u.vc->has_height = true;
2074         backend->u.vc->height = val;
2075     }
2076
2077     val = qemu_opt_get_number(opts, "cols", 0);
2078     if (val != 0) {
2079         backend->u.vc->has_cols = true;
2080         backend->u.vc->cols = val;
2081     }
2082
2083     val = qemu_opt_get_number(opts, "rows", 0);
2084     if (val != 0) {
2085         backend->u.vc->has_rows = true;
2086         backend->u.vc->rows = val;
2087     }
2088 }
2089
2090 static const TypeInfo qemu_console_info = {
2091     .name = TYPE_QEMU_CONSOLE,
2092     .parent = TYPE_OBJECT,
2093     .instance_size = sizeof(QemuConsole),
2094     .class_size = sizeof(QemuConsoleClass),
2095 };
2096
2097
2098 static void register_types(void)
2099 {
2100     type_register_static(&qemu_console_info);
2101     register_char_driver("vc", CHARDEV_BACKEND_KIND_VC, qemu_chr_parse_vc,
2102                          vc_init);
2103 }
2104
2105 type_init(register_types);
This page took 0.137687 seconds and 4 git commands to generate.