xref: /qemu/ui/console.c (revision 336d354b)
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 
25 #include "qemu/osdep.h"
26 #include "ui/console.h"
27 #include "hw/qdev-core.h"
28 #include "qapi/error.h"
29 #include "qapi/qapi-commands-ui.h"
30 #include "qemu/fifo8.h"
31 #include "qemu/main-loop.h"
32 #include "qemu/module.h"
33 #include "qemu/option.h"
34 #include "qemu/timer.h"
35 #include "chardev/char.h"
36 #include "trace.h"
37 #include "exec/memory.h"
38 #include "io/channel-file.h"
39 #include "qom/object.h"
40 
41 #define DEFAULT_BACKSCROLL 512
42 #define CONSOLE_CURSOR_PERIOD 500
43 
44 typedef struct TextAttributes {
45     uint8_t fgcol:4;
46     uint8_t bgcol:4;
47     uint8_t bold:1;
48     uint8_t uline:1;
49     uint8_t blink:1;
50     uint8_t invers:1;
51     uint8_t unvisible:1;
52 } TextAttributes;
53 
54 typedef struct TextCell {
55     uint8_t ch;
56     TextAttributes t_attrib;
57 } TextCell;
58 
59 #define MAX_ESC_PARAMS 3
60 
61 enum TTYState {
62     TTY_STATE_NORM,
63     TTY_STATE_ESC,
64     TTY_STATE_CSI,
65 };
66 
67 typedef enum {
68     GRAPHIC_CONSOLE,
69     TEXT_CONSOLE,
70     TEXT_CONSOLE_FIXED_SIZE
71 } console_type_t;
72 
73 struct QemuConsole {
74     Object parent;
75 
76     int index;
77     console_type_t console_type;
78     DisplayState *ds;
79     DisplaySurface *surface;
80     DisplayScanout scanout;
81     int dcls;
82     DisplayGLCtx *gl;
83     int gl_block;
84     QEMUTimer *gl_unblock_timer;
85     int window_id;
86 
87     /* Graphic console state.  */
88     Object *device;
89     uint32_t head;
90     QemuUIInfo ui_info;
91     QEMUTimer *ui_timer;
92     const GraphicHwOps *hw_ops;
93     void *hw;
94 
95     /* Text console state */
96     int width;
97     int height;
98     int total_height;
99     int backscroll_height;
100     int x, y;
101     int x_saved, y_saved;
102     int y_displayed;
103     int y_base;
104     TextAttributes t_attrib_default; /* default text attributes */
105     TextAttributes t_attrib; /* currently active text attributes */
106     TextCell *cells;
107     int text_x[2], text_y[2], cursor_invalidate;
108     int echo;
109 
110     int update_x0;
111     int update_y0;
112     int update_x1;
113     int update_y1;
114 
115     enum TTYState state;
116     int esc_params[MAX_ESC_PARAMS];
117     int nb_esc_params;
118 
119     Chardev *chr;
120     /* fifo for key pressed */
121     Fifo8 out_fifo;
122     CoQueue dump_queue;
123 
124     QTAILQ_ENTRY(QemuConsole) next;
125 };
126 
127 struct DisplayState {
128     QEMUTimer *gui_timer;
129     uint64_t last_update;
130     uint64_t update_interval;
131     bool refreshing;
132     bool have_gfx;
133     bool have_text;
134 
135     QLIST_HEAD(, DisplayChangeListener) listeners;
136 };
137 
138 static DisplayState *display_state;
139 static QemuConsole *active_console;
140 static QTAILQ_HEAD(, QemuConsole) consoles =
141     QTAILQ_HEAD_INITIALIZER(consoles);
142 static bool cursor_visible_phase;
143 static QEMUTimer *cursor_timer;
144 
145 static void text_console_do_init(Chardev *chr, DisplayState *ds);
146 static void dpy_refresh(DisplayState *s);
147 static DisplayState *get_alloc_displaystate(void);
148 static void text_console_update_cursor_timer(void);
149 static void text_console_update_cursor(void *opaque);
150 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
151 static bool console_compatible_with(QemuConsole *con,
152                                     DisplayChangeListener *dcl, Error **errp);
153 
154 static void gui_update(void *opaque)
155 {
156     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
157     uint64_t dcl_interval;
158     DisplayState *ds = opaque;
159     DisplayChangeListener *dcl;
160     QemuConsole *con;
161 
162     ds->refreshing = true;
163     dpy_refresh(ds);
164     ds->refreshing = false;
165 
166     QLIST_FOREACH(dcl, &ds->listeners, next) {
167         dcl_interval = dcl->update_interval ?
168             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
169         if (interval > dcl_interval) {
170             interval = dcl_interval;
171         }
172     }
173     if (ds->update_interval != interval) {
174         ds->update_interval = interval;
175         QTAILQ_FOREACH(con, &consoles, next) {
176             if (con->hw_ops->update_interval) {
177                 con->hw_ops->update_interval(con->hw, interval);
178             }
179         }
180         trace_console_refresh(interval);
181     }
182     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
183     timer_mod(ds->gui_timer, ds->last_update + interval);
184 }
185 
186 static void gui_setup_refresh(DisplayState *ds)
187 {
188     DisplayChangeListener *dcl;
189     bool need_timer = false;
190     bool have_gfx = false;
191     bool have_text = false;
192 
193     QLIST_FOREACH(dcl, &ds->listeners, next) {
194         if (dcl->ops->dpy_refresh != NULL) {
195             need_timer = true;
196         }
197         if (dcl->ops->dpy_gfx_update != NULL) {
198             have_gfx = true;
199         }
200         if (dcl->ops->dpy_text_update != NULL) {
201             have_text = true;
202         }
203     }
204 
205     if (need_timer && ds->gui_timer == NULL) {
206         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
207         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
208     }
209     if (!need_timer && ds->gui_timer != NULL) {
210         timer_free(ds->gui_timer);
211         ds->gui_timer = NULL;
212     }
213 
214     ds->have_gfx = have_gfx;
215     ds->have_text = have_text;
216 }
217 
218 void graphic_hw_update_done(QemuConsole *con)
219 {
220     if (con) {
221         qemu_co_queue_restart_all(&con->dump_queue);
222     }
223 }
224 
225 void graphic_hw_update(QemuConsole *con)
226 {
227     bool async = false;
228     con = con ? con : active_console;
229     if (!con) {
230         return;
231     }
232     if (con->hw_ops->gfx_update) {
233         con->hw_ops->gfx_update(con->hw);
234         async = con->hw_ops->gfx_update_async;
235     }
236     if (!async) {
237         graphic_hw_update_done(con);
238     }
239 }
240 
241 static void graphic_hw_gl_unblock_timer(void *opaque)
242 {
243     warn_report("console: no gl-unblock within one second");
244 }
245 
246 void graphic_hw_gl_block(QemuConsole *con, bool block)
247 {
248     uint64_t timeout;
249     assert(con != NULL);
250 
251     if (block) {
252         con->gl_block++;
253     } else {
254         con->gl_block--;
255     }
256     assert(con->gl_block >= 0);
257     if (!con->hw_ops->gl_block) {
258         return;
259     }
260     if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
261         return;
262     }
263     con->hw_ops->gl_block(con->hw, block);
264 
265     if (block) {
266         timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
267         timeout += 1000; /* one sec */
268         timer_mod(con->gl_unblock_timer, timeout);
269     } else {
270         timer_del(con->gl_unblock_timer);
271     }
272 }
273 
274 int qemu_console_get_window_id(QemuConsole *con)
275 {
276     return con->window_id;
277 }
278 
279 void qemu_console_set_window_id(QemuConsole *con, int window_id)
280 {
281     con->window_id = window_id;
282 }
283 
284 void graphic_hw_invalidate(QemuConsole *con)
285 {
286     if (!con) {
287         con = active_console;
288     }
289     if (con && con->hw_ops->invalidate) {
290         con->hw_ops->invalidate(con->hw);
291     }
292 }
293 
294 static bool ppm_save(int fd, pixman_image_t *image, Error **errp)
295 {
296     int width = pixman_image_get_width(image);
297     int height = pixman_image_get_height(image);
298     g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd));
299     g_autofree char *header = NULL;
300     g_autoptr(pixman_image_t) linebuf = NULL;
301     int y;
302 
303     trace_ppm_save(fd, image);
304 
305     header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255);
306     if (qio_channel_write_all(QIO_CHANNEL(ioc),
307                               header, strlen(header), errp) < 0) {
308         return false;
309     }
310 
311     linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
312     for (y = 0; y < height; y++) {
313         qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
314         if (qio_channel_write_all(QIO_CHANNEL(ioc),
315                                   (char *)pixman_image_get_data(linebuf),
316                                   pixman_image_get_stride(linebuf), errp) < 0) {
317             return false;
318         }
319     }
320 
321     return true;
322 }
323 
324 static void graphic_hw_update_bh(void *con)
325 {
326     graphic_hw_update(con);
327 }
328 
329 /* Safety: coroutine-only, concurrent-coroutine safe, main thread only */
330 void coroutine_fn
331 qmp_screendump(const char *filename, bool has_device, const char *device,
332                bool has_head, int64_t head, Error **errp)
333 {
334     g_autoptr(pixman_image_t) image = NULL;
335     QemuConsole *con;
336     DisplaySurface *surface;
337     int fd;
338 
339     if (has_device) {
340         con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
341                                                  errp);
342         if (!con) {
343             return;
344         }
345     } else {
346         if (has_head) {
347             error_setg(errp, "'head' must be specified together with 'device'");
348             return;
349         }
350         con = qemu_console_lookup_by_index(0);
351         if (!con) {
352             error_setg(errp, "There is no console to take a screendump from");
353             return;
354         }
355     }
356 
357     if (qemu_co_queue_empty(&con->dump_queue)) {
358         /* Defer the update, it will restart the pending coroutines */
359         aio_bh_schedule_oneshot(qemu_get_aio_context(),
360                                 graphic_hw_update_bh, con);
361     }
362     qemu_co_queue_wait(&con->dump_queue, NULL);
363 
364     /*
365      * All pending coroutines are woken up, while the BQL is held.  No
366      * further graphic update are possible until it is released.  Take
367      * an image ref before that.
368      */
369     surface = qemu_console_surface(con);
370     if (!surface) {
371         error_setg(errp, "no surface");
372         return;
373     }
374     image = pixman_image_ref(surface->image);
375 
376     fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
377     if (fd == -1) {
378         error_setg(errp, "failed to open file '%s': %s", filename,
379                    strerror(errno));
380         return;
381     }
382 
383     /*
384      * The image content could potentially be updated as the coroutine
385      * yields and releases the BQL. It could produce corrupted dump, but
386      * it should be otherwise safe.
387      */
388     if (!ppm_save(fd, image, errp)) {
389         qemu_unlink(filename);
390     }
391 }
392 
393 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
394 {
395     if (!con) {
396         con = active_console;
397     }
398     if (con && con->hw_ops->text_update) {
399         con->hw_ops->text_update(con->hw, chardata);
400     }
401 }
402 
403 static void vga_fill_rect(QemuConsole *con,
404                           int posx, int posy, int width, int height,
405                           pixman_color_t color)
406 {
407     DisplaySurface *surface = qemu_console_surface(con);
408     pixman_rectangle16_t rect = {
409         .x = posx, .y = posy, .width = width, .height = height
410     };
411 
412     pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
413                                  &color, 1, &rect);
414 }
415 
416 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
417 static void vga_bitblt(QemuConsole *con,
418                        int xs, int ys, int xd, int yd, int w, int h)
419 {
420     DisplaySurface *surface = qemu_console_surface(con);
421 
422     pixman_image_composite(PIXMAN_OP_SRC,
423                            surface->image, NULL, surface->image,
424                            xs, ys, 0, 0, xd, yd, w, h);
425 }
426 
427 /***********************************************************/
428 /* basic char display */
429 
430 #define FONT_HEIGHT 16
431 #define FONT_WIDTH 8
432 
433 #include "vgafont.h"
434 
435 #define QEMU_RGB(r, g, b)                                               \
436     { .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
437 
438 static const pixman_color_t color_table_rgb[2][8] = {
439     {   /* dark */
440         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
441         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
442         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
443         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
444         [QEMU_COLOR_RED]     = QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
445         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
446         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
447         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
448     },
449     {   /* bright */
450         [QEMU_COLOR_BLACK]   = QEMU_RGB(0x00, 0x00, 0x00),  /* black */
451         [QEMU_COLOR_BLUE]    = QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
452         [QEMU_COLOR_GREEN]   = QEMU_RGB(0x00, 0xff, 0x00),  /* green */
453         [QEMU_COLOR_CYAN]    = QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
454         [QEMU_COLOR_RED]     = QEMU_RGB(0xff, 0x00, 0x00),  /* red */
455         [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
456         [QEMU_COLOR_YELLOW]  = QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
457         [QEMU_COLOR_WHITE]   = QEMU_RGB(0xff, 0xff, 0xff),  /* white */
458     }
459 };
460 
461 static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
462                           TextAttributes *t_attrib)
463 {
464     static pixman_image_t *glyphs[256];
465     DisplaySurface *surface = qemu_console_surface(s);
466     pixman_color_t fgcol, bgcol;
467 
468     if (t_attrib->invers) {
469         bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
470         fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
471     } else {
472         fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
473         bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
474     }
475 
476     if (!glyphs[ch]) {
477         glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
478     }
479     qemu_pixman_glyph_render(glyphs[ch], surface->image,
480                              &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
481 }
482 
483 static void text_console_resize(QemuConsole *s)
484 {
485     TextCell *cells, *c, *c1;
486     int w1, x, y, last_width;
487 
488     assert(s->scanout.kind == SCANOUT_SURFACE);
489 
490     last_width = s->width;
491     s->width = surface_width(s->surface) / FONT_WIDTH;
492     s->height = surface_height(s->surface) / FONT_HEIGHT;
493 
494     w1 = last_width;
495     if (s->width < w1)
496         w1 = s->width;
497 
498     cells = g_new(TextCell, s->width * s->total_height + 1);
499     for(y = 0; y < s->total_height; y++) {
500         c = &cells[y * s->width];
501         if (w1 > 0) {
502             c1 = &s->cells[y * last_width];
503             for(x = 0; x < w1; x++) {
504                 *c++ = *c1++;
505             }
506         }
507         for(x = w1; x < s->width; x++) {
508             c->ch = ' ';
509             c->t_attrib = s->t_attrib_default;
510             c++;
511         }
512     }
513     g_free(s->cells);
514     s->cells = cells;
515 }
516 
517 static inline void text_update_xy(QemuConsole *s, int x, int y)
518 {
519     s->text_x[0] = MIN(s->text_x[0], x);
520     s->text_x[1] = MAX(s->text_x[1], x);
521     s->text_y[0] = MIN(s->text_y[0], y);
522     s->text_y[1] = MAX(s->text_y[1], y);
523 }
524 
525 static void invalidate_xy(QemuConsole *s, int x, int y)
526 {
527     if (!qemu_console_is_visible(s)) {
528         return;
529     }
530     if (s->update_x0 > x * FONT_WIDTH)
531         s->update_x0 = x * FONT_WIDTH;
532     if (s->update_y0 > y * FONT_HEIGHT)
533         s->update_y0 = y * FONT_HEIGHT;
534     if (s->update_x1 < (x + 1) * FONT_WIDTH)
535         s->update_x1 = (x + 1) * FONT_WIDTH;
536     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
537         s->update_y1 = (y + 1) * FONT_HEIGHT;
538 }
539 
540 static void update_xy(QemuConsole *s, int x, int y)
541 {
542     TextCell *c;
543     int y1, y2;
544 
545     if (s->ds->have_text) {
546         text_update_xy(s, x, y);
547     }
548 
549     y1 = (s->y_base + y) % s->total_height;
550     y2 = y1 - s->y_displayed;
551     if (y2 < 0) {
552         y2 += s->total_height;
553     }
554     if (y2 < s->height) {
555         if (x >= s->width) {
556             x = s->width - 1;
557         }
558         c = &s->cells[y1 * s->width + x];
559         vga_putcharxy(s, x, y2, c->ch,
560                       &(c->t_attrib));
561         invalidate_xy(s, x, y2);
562     }
563 }
564 
565 static void console_show_cursor(QemuConsole *s, int show)
566 {
567     TextCell *c;
568     int y, y1;
569     int x = s->x;
570 
571     if (s->ds->have_text) {
572         s->cursor_invalidate = 1;
573     }
574 
575     if (x >= s->width) {
576         x = s->width - 1;
577     }
578     y1 = (s->y_base + s->y) % s->total_height;
579     y = y1 - s->y_displayed;
580     if (y < 0) {
581         y += s->total_height;
582     }
583     if (y < s->height) {
584         c = &s->cells[y1 * s->width + x];
585         if (show && cursor_visible_phase) {
586             TextAttributes t_attrib = s->t_attrib_default;
587             t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
588             vga_putcharxy(s, x, y, c->ch, &t_attrib);
589         } else {
590             vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
591         }
592         invalidate_xy(s, x, y);
593     }
594 }
595 
596 static void console_refresh(QemuConsole *s)
597 {
598     DisplaySurface *surface = qemu_console_surface(s);
599     TextCell *c;
600     int x, y, y1;
601 
602     if (s->ds->have_text) {
603         s->text_x[0] = 0;
604         s->text_y[0] = 0;
605         s->text_x[1] = s->width - 1;
606         s->text_y[1] = s->height - 1;
607         s->cursor_invalidate = 1;
608     }
609 
610     vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
611                   color_table_rgb[0][QEMU_COLOR_BLACK]);
612     y1 = s->y_displayed;
613     for (y = 0; y < s->height; y++) {
614         c = s->cells + y1 * s->width;
615         for (x = 0; x < s->width; x++) {
616             vga_putcharxy(s, x, y, c->ch,
617                           &(c->t_attrib));
618             c++;
619         }
620         if (++y1 == s->total_height) {
621             y1 = 0;
622         }
623     }
624     console_show_cursor(s, 1);
625     dpy_gfx_update(s, 0, 0,
626                    surface_width(surface), surface_height(surface));
627 }
628 
629 static void console_scroll(QemuConsole *s, int ydelta)
630 {
631     int i, y1;
632 
633     if (ydelta > 0) {
634         for(i = 0; i < ydelta; i++) {
635             if (s->y_displayed == s->y_base)
636                 break;
637             if (++s->y_displayed == s->total_height)
638                 s->y_displayed = 0;
639         }
640     } else {
641         ydelta = -ydelta;
642         i = s->backscroll_height;
643         if (i > s->total_height - s->height)
644             i = s->total_height - s->height;
645         y1 = s->y_base - i;
646         if (y1 < 0)
647             y1 += s->total_height;
648         for(i = 0; i < ydelta; i++) {
649             if (s->y_displayed == y1)
650                 break;
651             if (--s->y_displayed < 0)
652                 s->y_displayed = s->total_height - 1;
653         }
654     }
655     console_refresh(s);
656 }
657 
658 static void console_put_lf(QemuConsole *s)
659 {
660     TextCell *c;
661     int x, y1;
662 
663     s->y++;
664     if (s->y >= s->height) {
665         s->y = s->height - 1;
666 
667         if (s->y_displayed == s->y_base) {
668             if (++s->y_displayed == s->total_height)
669                 s->y_displayed = 0;
670         }
671         if (++s->y_base == s->total_height)
672             s->y_base = 0;
673         if (s->backscroll_height < s->total_height)
674             s->backscroll_height++;
675         y1 = (s->y_base + s->height - 1) % s->total_height;
676         c = &s->cells[y1 * s->width];
677         for(x = 0; x < s->width; x++) {
678             c->ch = ' ';
679             c->t_attrib = s->t_attrib_default;
680             c++;
681         }
682         if (s->y_displayed == s->y_base) {
683             if (s->ds->have_text) {
684                 s->text_x[0] = 0;
685                 s->text_y[0] = 0;
686                 s->text_x[1] = s->width - 1;
687                 s->text_y[1] = s->height - 1;
688             }
689 
690             vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
691                        s->width * FONT_WIDTH,
692                        (s->height - 1) * FONT_HEIGHT);
693             vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
694                           s->width * FONT_WIDTH, FONT_HEIGHT,
695                           color_table_rgb[0][s->t_attrib_default.bgcol]);
696             s->update_x0 = 0;
697             s->update_y0 = 0;
698             s->update_x1 = s->width * FONT_WIDTH;
699             s->update_y1 = s->height * FONT_HEIGHT;
700         }
701     }
702 }
703 
704 /* Set console attributes depending on the current escape codes.
705  * NOTE: I know this code is not very efficient (checking every color for it
706  * self) but it is more readable and better maintainable.
707  */
708 static void console_handle_escape(QemuConsole *s)
709 {
710     int i;
711 
712     for (i=0; i<s->nb_esc_params; i++) {
713         switch (s->esc_params[i]) {
714             case 0: /* reset all console attributes to default */
715                 s->t_attrib = s->t_attrib_default;
716                 break;
717             case 1:
718                 s->t_attrib.bold = 1;
719                 break;
720             case 4:
721                 s->t_attrib.uline = 1;
722                 break;
723             case 5:
724                 s->t_attrib.blink = 1;
725                 break;
726             case 7:
727                 s->t_attrib.invers = 1;
728                 break;
729             case 8:
730                 s->t_attrib.unvisible = 1;
731                 break;
732             case 22:
733                 s->t_attrib.bold = 0;
734                 break;
735             case 24:
736                 s->t_attrib.uline = 0;
737                 break;
738             case 25:
739                 s->t_attrib.blink = 0;
740                 break;
741             case 27:
742                 s->t_attrib.invers = 0;
743                 break;
744             case 28:
745                 s->t_attrib.unvisible = 0;
746                 break;
747             /* set foreground color */
748             case 30:
749                 s->t_attrib.fgcol = QEMU_COLOR_BLACK;
750                 break;
751             case 31:
752                 s->t_attrib.fgcol = QEMU_COLOR_RED;
753                 break;
754             case 32:
755                 s->t_attrib.fgcol = QEMU_COLOR_GREEN;
756                 break;
757             case 33:
758                 s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
759                 break;
760             case 34:
761                 s->t_attrib.fgcol = QEMU_COLOR_BLUE;
762                 break;
763             case 35:
764                 s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
765                 break;
766             case 36:
767                 s->t_attrib.fgcol = QEMU_COLOR_CYAN;
768                 break;
769             case 37:
770                 s->t_attrib.fgcol = QEMU_COLOR_WHITE;
771                 break;
772             /* set background color */
773             case 40:
774                 s->t_attrib.bgcol = QEMU_COLOR_BLACK;
775                 break;
776             case 41:
777                 s->t_attrib.bgcol = QEMU_COLOR_RED;
778                 break;
779             case 42:
780                 s->t_attrib.bgcol = QEMU_COLOR_GREEN;
781                 break;
782             case 43:
783                 s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
784                 break;
785             case 44:
786                 s->t_attrib.bgcol = QEMU_COLOR_BLUE;
787                 break;
788             case 45:
789                 s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
790                 break;
791             case 46:
792                 s->t_attrib.bgcol = QEMU_COLOR_CYAN;
793                 break;
794             case 47:
795                 s->t_attrib.bgcol = QEMU_COLOR_WHITE;
796                 break;
797         }
798     }
799 }
800 
801 static void console_clear_xy(QemuConsole *s, int x, int y)
802 {
803     int y1 = (s->y_base + y) % s->total_height;
804     if (x >= s->width) {
805         x = s->width - 1;
806     }
807     TextCell *c = &s->cells[y1 * s->width + x];
808     c->ch = ' ';
809     c->t_attrib = s->t_attrib_default;
810     update_xy(s, x, y);
811 }
812 
813 static void console_put_one(QemuConsole *s, int ch)
814 {
815     TextCell *c;
816     int y1;
817     if (s->x >= s->width) {
818         /* line wrap */
819         s->x = 0;
820         console_put_lf(s);
821     }
822     y1 = (s->y_base + s->y) % s->total_height;
823     c = &s->cells[y1 * s->width + s->x];
824     c->ch = ch;
825     c->t_attrib = s->t_attrib;
826     update_xy(s, s->x, s->y);
827     s->x++;
828 }
829 
830 static void console_respond_str(QemuConsole *s, const char *buf)
831 {
832     while (*buf) {
833         console_put_one(s, *buf);
834         buf++;
835     }
836 }
837 
838 /* set cursor, checking bounds */
839 static void set_cursor(QemuConsole *s, int x, int y)
840 {
841     if (x < 0) {
842         x = 0;
843     }
844     if (y < 0) {
845         y = 0;
846     }
847     if (y >= s->height) {
848         y = s->height - 1;
849     }
850     if (x >= s->width) {
851         x = s->width - 1;
852     }
853 
854     s->x = x;
855     s->y = y;
856 }
857 
858 static void console_putchar(QemuConsole *s, int ch)
859 {
860     int i;
861     int x, y;
862     char response[40];
863 
864     switch(s->state) {
865     case TTY_STATE_NORM:
866         switch(ch) {
867         case '\r':  /* carriage return */
868             s->x = 0;
869             break;
870         case '\n':  /* newline */
871             console_put_lf(s);
872             break;
873         case '\b':  /* backspace */
874             if (s->x > 0)
875                 s->x--;
876             break;
877         case '\t':  /* tabspace */
878             if (s->x + (8 - (s->x % 8)) > s->width) {
879                 s->x = 0;
880                 console_put_lf(s);
881             } else {
882                 s->x = s->x + (8 - (s->x % 8));
883             }
884             break;
885         case '\a':  /* alert aka. bell */
886             /* TODO: has to be implemented */
887             break;
888         case 14:
889             /* SI (shift in), character set 0 (ignored) */
890             break;
891         case 15:
892             /* SO (shift out), character set 1 (ignored) */
893             break;
894         case 27:    /* esc (introducing an escape sequence) */
895             s->state = TTY_STATE_ESC;
896             break;
897         default:
898             console_put_one(s, ch);
899             break;
900         }
901         break;
902     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
903         if (ch == '[') {
904             for(i=0;i<MAX_ESC_PARAMS;i++)
905                 s->esc_params[i] = 0;
906             s->nb_esc_params = 0;
907             s->state = TTY_STATE_CSI;
908         } else {
909             s->state = TTY_STATE_NORM;
910         }
911         break;
912     case TTY_STATE_CSI: /* handle escape sequence parameters */
913         if (ch >= '0' && ch <= '9') {
914             if (s->nb_esc_params < MAX_ESC_PARAMS) {
915                 int *param = &s->esc_params[s->nb_esc_params];
916                 int digit = (ch - '0');
917 
918                 *param = (*param <= (INT_MAX - digit) / 10) ?
919                          *param * 10 + digit : INT_MAX;
920             }
921         } else {
922             if (s->nb_esc_params < MAX_ESC_PARAMS)
923                 s->nb_esc_params++;
924             if (ch == ';' || ch == '?') {
925                 break;
926             }
927             trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
928                                       ch, s->nb_esc_params);
929             s->state = TTY_STATE_NORM;
930             switch(ch) {
931             case 'A':
932                 /* move cursor up */
933                 if (s->esc_params[0] == 0) {
934                     s->esc_params[0] = 1;
935                 }
936                 set_cursor(s, s->x, s->y - s->esc_params[0]);
937                 break;
938             case 'B':
939                 /* move cursor down */
940                 if (s->esc_params[0] == 0) {
941                     s->esc_params[0] = 1;
942                 }
943                 set_cursor(s, s->x, s->y + s->esc_params[0]);
944                 break;
945             case 'C':
946                 /* move cursor right */
947                 if (s->esc_params[0] == 0) {
948                     s->esc_params[0] = 1;
949                 }
950                 set_cursor(s, s->x + s->esc_params[0], s->y);
951                 break;
952             case 'D':
953                 /* move cursor left */
954                 if (s->esc_params[0] == 0) {
955                     s->esc_params[0] = 1;
956                 }
957                 set_cursor(s, s->x - s->esc_params[0], s->y);
958                 break;
959             case 'G':
960                 /* move cursor to column */
961                 set_cursor(s, s->esc_params[0] - 1, s->y);
962                 break;
963             case 'f':
964             case 'H':
965                 /* move cursor to row, column */
966                 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
967                 break;
968             case 'J':
969                 switch (s->esc_params[0]) {
970                 case 0:
971                     /* clear to end of screen */
972                     for (y = s->y; y < s->height; y++) {
973                         for (x = 0; x < s->width; x++) {
974                             if (y == s->y && x < s->x) {
975                                 continue;
976                             }
977                             console_clear_xy(s, x, y);
978                         }
979                     }
980                     break;
981                 case 1:
982                     /* clear from beginning of screen */
983                     for (y = 0; y <= s->y; y++) {
984                         for (x = 0; x < s->width; x++) {
985                             if (y == s->y && x > s->x) {
986                                 break;
987                             }
988                             console_clear_xy(s, x, y);
989                         }
990                     }
991                     break;
992                 case 2:
993                     /* clear entire screen */
994                     for (y = 0; y <= s->height; y++) {
995                         for (x = 0; x < s->width; x++) {
996                             console_clear_xy(s, x, y);
997                         }
998                     }
999                     break;
1000                 }
1001                 break;
1002             case 'K':
1003                 switch (s->esc_params[0]) {
1004                 case 0:
1005                     /* clear to eol */
1006                     for(x = s->x; x < s->width; x++) {
1007                         console_clear_xy(s, x, s->y);
1008                     }
1009                     break;
1010                 case 1:
1011                     /* clear from beginning of line */
1012                     for (x = 0; x <= s->x && x < s->width; x++) {
1013                         console_clear_xy(s, x, s->y);
1014                     }
1015                     break;
1016                 case 2:
1017                     /* clear entire line */
1018                     for(x = 0; x < s->width; x++) {
1019                         console_clear_xy(s, x, s->y);
1020                     }
1021                     break;
1022                 }
1023                 break;
1024             case 'm':
1025                 console_handle_escape(s);
1026                 break;
1027             case 'n':
1028                 switch (s->esc_params[0]) {
1029                 case 5:
1030                     /* report console status (always succeed)*/
1031                     console_respond_str(s, "\033[0n");
1032                     break;
1033                 case 6:
1034                     /* report cursor position */
1035                     sprintf(response, "\033[%d;%dR",
1036                            (s->y_base + s->y) % s->total_height + 1,
1037                             s->x + 1);
1038                     console_respond_str(s, response);
1039                     break;
1040                 }
1041                 break;
1042             case 's':
1043                 /* save cursor position */
1044                 s->x_saved = s->x;
1045                 s->y_saved = s->y;
1046                 break;
1047             case 'u':
1048                 /* restore cursor position */
1049                 s->x = s->x_saved;
1050                 s->y = s->y_saved;
1051                 break;
1052             default:
1053                 trace_console_putchar_unhandled(ch);
1054                 break;
1055             }
1056             break;
1057         }
1058     }
1059 }
1060 
1061 static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl,
1062                                              struct DisplaySurface *new_surface,
1063                                              bool update)
1064 {
1065     if (dcl->ops->dpy_gfx_switch) {
1066         dcl->ops->dpy_gfx_switch(dcl, new_surface);
1067     }
1068 
1069     if (update && dcl->ops->dpy_gfx_update) {
1070         dcl->ops->dpy_gfx_update(dcl, 0, 0,
1071                                  surface_width(new_surface),
1072                                  surface_height(new_surface));
1073     }
1074 }
1075 
1076 static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface)
1077 {
1078     if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) {
1079         con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface);
1080     }
1081 }
1082 
1083 static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface)
1084 {
1085     if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) {
1086         con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface);
1087     }
1088 }
1089 
1090 static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface,
1091                                    int x, int y, int w, int h)
1092 {
1093     if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) {
1094         con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h);
1095     }
1096 }
1097 
1098 static void displaychangelistener_display_console(DisplayChangeListener *dcl,
1099                                                   QemuConsole *con,
1100                                                   Error **errp)
1101 {
1102     static const char nodev[] =
1103         "This VM has no graphic display device.";
1104     static DisplaySurface *dummy;
1105 
1106     if (!con || !console_compatible_with(con, dcl, errp)) {
1107         if (!dummy) {
1108             dummy = qemu_create_placeholder_surface(640, 480, nodev);
1109         }
1110         if (con) {
1111             dpy_gfx_create_texture(con, dummy);
1112         }
1113         displaychangelistener_gfx_switch(dcl, dummy, TRUE);
1114         return;
1115     }
1116 
1117     dpy_gfx_create_texture(con, con->surface);
1118     displaychangelistener_gfx_switch(dcl, con->surface,
1119                                      con->scanout.kind == SCANOUT_SURFACE);
1120 
1121     if (con->scanout.kind == SCANOUT_DMABUF &&
1122         displaychangelistener_has_dmabuf(dcl)) {
1123         dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
1124     } else if (con->scanout.kind == SCANOUT_TEXTURE &&
1125                dcl->ops->dpy_gl_scanout_texture) {
1126         dcl->ops->dpy_gl_scanout_texture(dcl,
1127                                          con->scanout.texture.backing_id,
1128                                          con->scanout.texture.backing_y_0_top,
1129                                          con->scanout.texture.backing_width,
1130                                          con->scanout.texture.backing_height,
1131                                          con->scanout.texture.x,
1132                                          con->scanout.texture.y,
1133                                          con->scanout.texture.width,
1134                                          con->scanout.texture.height);
1135     }
1136 }
1137 
1138 void console_select(unsigned int index)
1139 {
1140     DisplayChangeListener *dcl;
1141     QemuConsole *s;
1142 
1143     trace_console_select(index);
1144     s = qemu_console_lookup_by_index(index);
1145     if (s) {
1146         DisplayState *ds = s->ds;
1147 
1148         active_console = s;
1149         if (ds->have_gfx) {
1150             QLIST_FOREACH(dcl, &ds->listeners, next) {
1151                 if (dcl->con != NULL) {
1152                     continue;
1153                 }
1154                 displaychangelistener_display_console(dcl, s, NULL);
1155             }
1156         }
1157         if (ds->have_text) {
1158             dpy_text_resize(s, s->width, s->height);
1159         }
1160         text_console_update_cursor(NULL);
1161     }
1162 }
1163 
1164 struct VCChardev {
1165     Chardev parent;
1166     QemuConsole *console;
1167 };
1168 typedef struct VCChardev VCChardev;
1169 
1170 #define TYPE_CHARDEV_VC "chardev-vc"
1171 DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
1172                          TYPE_CHARDEV_VC)
1173 
1174 static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
1175 {
1176     VCChardev *drv = VC_CHARDEV(chr);
1177     QemuConsole *s = drv->console;
1178     int i;
1179 
1180     if (!s->ds) {
1181         return 0;
1182     }
1183 
1184     s->update_x0 = s->width * FONT_WIDTH;
1185     s->update_y0 = s->height * FONT_HEIGHT;
1186     s->update_x1 = 0;
1187     s->update_y1 = 0;
1188     console_show_cursor(s, 0);
1189     for(i = 0; i < len; i++) {
1190         console_putchar(s, buf[i]);
1191     }
1192     console_show_cursor(s, 1);
1193     if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1194         dpy_gfx_update(s, s->update_x0, s->update_y0,
1195                        s->update_x1 - s->update_x0,
1196                        s->update_y1 - s->update_y0);
1197     }
1198     return len;
1199 }
1200 
1201 static void kbd_send_chars(QemuConsole *s)
1202 {
1203     uint32_t len, avail;
1204 
1205     len = qemu_chr_be_can_write(s->chr);
1206     avail = fifo8_num_used(&s->out_fifo);
1207     while (len > 0 && avail > 0) {
1208         const uint8_t *buf;
1209         uint32_t size;
1210 
1211         buf = fifo8_pop_buf(&s->out_fifo, MIN(len, avail), &size);
1212         qemu_chr_be_write(s->chr, (uint8_t *)buf, size);
1213         len = qemu_chr_be_can_write(s->chr);
1214         avail -= size;
1215     }
1216 }
1217 
1218 /* called when an ascii key is pressed */
1219 void kbd_put_keysym_console(QemuConsole *s, int keysym)
1220 {
1221     uint8_t buf[16], *q;
1222     int c;
1223     uint32_t num_free;
1224 
1225     if (!s || (s->console_type == GRAPHIC_CONSOLE))
1226         return;
1227 
1228     switch(keysym) {
1229     case QEMU_KEY_CTRL_UP:
1230         console_scroll(s, -1);
1231         break;
1232     case QEMU_KEY_CTRL_DOWN:
1233         console_scroll(s, 1);
1234         break;
1235     case QEMU_KEY_CTRL_PAGEUP:
1236         console_scroll(s, -10);
1237         break;
1238     case QEMU_KEY_CTRL_PAGEDOWN:
1239         console_scroll(s, 10);
1240         break;
1241     default:
1242         /* convert the QEMU keysym to VT100 key string */
1243         q = buf;
1244         if (keysym >= 0xe100 && keysym <= 0xe11f) {
1245             *q++ = '\033';
1246             *q++ = '[';
1247             c = keysym - 0xe100;
1248             if (c >= 10)
1249                 *q++ = '0' + (c / 10);
1250             *q++ = '0' + (c % 10);
1251             *q++ = '~';
1252         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1253             *q++ = '\033';
1254             *q++ = '[';
1255             *q++ = keysym & 0xff;
1256         } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1257             vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
1258             *q++ = '\n';
1259         } else {
1260             *q++ = keysym;
1261         }
1262         if (s->echo) {
1263             vc_chr_write(s->chr, buf, q - buf);
1264         }
1265         num_free = fifo8_num_free(&s->out_fifo);
1266         fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf));
1267         kbd_send_chars(s);
1268         break;
1269     }
1270 }
1271 
1272 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
1273     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
1274     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
1275     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
1276     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
1277     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
1278     [Q_KEY_CODE_END]    = QEMU_KEY_END,
1279     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
1280     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
1281     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
1282     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
1283 };
1284 
1285 static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
1286     [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
1287     [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
1288     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
1289     [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
1290     [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
1291     [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
1292     [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
1293     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
1294 };
1295 
1296 bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
1297 {
1298     int keysym;
1299 
1300     keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
1301     if (keysym == 0) {
1302         return false;
1303     }
1304     kbd_put_keysym_console(s, keysym);
1305     return true;
1306 }
1307 
1308 void kbd_put_string_console(QemuConsole *s, const char *str, int len)
1309 {
1310     int i;
1311 
1312     for (i = 0; i < len && str[i]; i++) {
1313         kbd_put_keysym_console(s, str[i]);
1314     }
1315 }
1316 
1317 void kbd_put_keysym(int keysym)
1318 {
1319     kbd_put_keysym_console(active_console, keysym);
1320 }
1321 
1322 static void text_console_invalidate(void *opaque)
1323 {
1324     QemuConsole *s = (QemuConsole *) opaque;
1325 
1326     if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1327         text_console_resize(s);
1328     }
1329     console_refresh(s);
1330 }
1331 
1332 static void text_console_update(void *opaque, console_ch_t *chardata)
1333 {
1334     QemuConsole *s = (QemuConsole *) opaque;
1335     int i, j, src;
1336 
1337     if (s->text_x[0] <= s->text_x[1]) {
1338         src = (s->y_base + s->text_y[0]) * s->width;
1339         chardata += s->text_y[0] * s->width;
1340         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1341             for (j = 0; j < s->width; j++, src++) {
1342                 console_write_ch(chardata ++,
1343                                  ATTR2CHTYPE(s->cells[src].ch,
1344                                              s->cells[src].t_attrib.fgcol,
1345                                              s->cells[src].t_attrib.bgcol,
1346                                              s->cells[src].t_attrib.bold));
1347             }
1348         dpy_text_update(s, s->text_x[0], s->text_y[0],
1349                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1350         s->text_x[0] = s->width;
1351         s->text_y[0] = s->height;
1352         s->text_x[1] = 0;
1353         s->text_y[1] = 0;
1354     }
1355     if (s->cursor_invalidate) {
1356         dpy_text_cursor(s, s->x, s->y);
1357         s->cursor_invalidate = 0;
1358     }
1359 }
1360 
1361 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
1362                                 uint32_t head)
1363 {
1364     Object *obj;
1365     QemuConsole *s;
1366     int i;
1367 
1368     obj = object_new(TYPE_QEMU_CONSOLE);
1369     s = QEMU_CONSOLE(obj);
1370     qemu_co_queue_init(&s->dump_queue);
1371     s->head = head;
1372     object_property_add_link(obj, "device", TYPE_DEVICE,
1373                              (Object **)&s->device,
1374                              object_property_allow_set_link,
1375                              OBJ_PROP_LINK_STRONG);
1376     object_property_add_uint32_ptr(obj, "head", &s->head,
1377                                    OBJ_PROP_FLAG_READ);
1378 
1379     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1380         (console_type == GRAPHIC_CONSOLE))) {
1381         active_console = s;
1382     }
1383     s->ds = ds;
1384     s->console_type = console_type;
1385     s->window_id = -1;
1386 
1387     if (QTAILQ_EMPTY(&consoles)) {
1388         s->index = 0;
1389         QTAILQ_INSERT_TAIL(&consoles, s, next);
1390     } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) {
1391         QemuConsole *last = QTAILQ_LAST(&consoles);
1392         s->index = last->index + 1;
1393         QTAILQ_INSERT_TAIL(&consoles, s, next);
1394     } else {
1395         /*
1396          * HACK: Put graphical consoles before text consoles.
1397          *
1398          * Only do that for coldplugged devices.  After initial device
1399          * initialization we will not renumber the consoles any more.
1400          */
1401         QemuConsole *c = QTAILQ_FIRST(&consoles);
1402 
1403         while (QTAILQ_NEXT(c, next) != NULL &&
1404                c->console_type == GRAPHIC_CONSOLE) {
1405             c = QTAILQ_NEXT(c, next);
1406         }
1407         if (c->console_type == GRAPHIC_CONSOLE) {
1408             /* have no text consoles */
1409             s->index = c->index + 1;
1410             QTAILQ_INSERT_AFTER(&consoles, c, s, next);
1411         } else {
1412             s->index = c->index;
1413             QTAILQ_INSERT_BEFORE(c, s, next);
1414             /* renumber text consoles */
1415             for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
1416                 c->index = i;
1417             }
1418         }
1419     }
1420     return s;
1421 }
1422 
1423 DisplaySurface *qemu_create_displaysurface(int width, int height)
1424 {
1425     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1426 
1427     trace_displaysurface_create(surface, width, height);
1428     surface->format = PIXMAN_x8r8g8b8;
1429     surface->image = pixman_image_create_bits(surface->format,
1430                                               width, height,
1431                                               NULL, width * 4);
1432     assert(surface->image != NULL);
1433     surface->flags = QEMU_ALLOCATED_FLAG;
1434 
1435     return surface;
1436 }
1437 
1438 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1439                                                 pixman_format_code_t format,
1440                                                 int linesize, uint8_t *data)
1441 {
1442     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1443 
1444     trace_displaysurface_create_from(surface, width, height, format);
1445     surface->format = format;
1446     surface->image = pixman_image_create_bits(surface->format,
1447                                               width, height,
1448                                               (void *)data, linesize);
1449     assert(surface->image != NULL);
1450 
1451     return surface;
1452 }
1453 
1454 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
1455 {
1456     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1457 
1458     trace_displaysurface_create_pixman(surface);
1459     surface->format = pixman_image_get_format(image);
1460     surface->image = pixman_image_ref(image);
1461 
1462     return surface;
1463 }
1464 
1465 DisplaySurface *qemu_create_placeholder_surface(int w, int h,
1466                                                 const char *msg)
1467 {
1468     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1469     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1470     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1471     pixman_image_t *glyph;
1472     int len, x, y, i;
1473 
1474     len = strlen(msg);
1475     x = (w / FONT_WIDTH  - len) / 2;
1476     y = (h / FONT_HEIGHT - 1)   / 2;
1477     for (i = 0; i < len; i++) {
1478         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1479         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1480                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1481         qemu_pixman_image_unref(glyph);
1482     }
1483     surface->flags |= QEMU_PLACEHOLDER_FLAG;
1484     return surface;
1485 }
1486 
1487 void qemu_free_displaysurface(DisplaySurface *surface)
1488 {
1489     if (surface == NULL) {
1490         return;
1491     }
1492     trace_displaysurface_free(surface);
1493     qemu_pixman_image_unref(surface->image);
1494     g_free(surface);
1495 }
1496 
1497 bool console_has_gl(QemuConsole *con)
1498 {
1499     return con->gl != NULL;
1500 }
1501 
1502 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
1503 {
1504     if (dcl->ops->dpy_has_dmabuf) {
1505         return dcl->ops->dpy_has_dmabuf(dcl);
1506     }
1507 
1508     if (dcl->ops->dpy_gl_scanout_dmabuf) {
1509         return true;
1510     }
1511 
1512     return false;
1513 }
1514 
1515 static bool console_compatible_with(QemuConsole *con,
1516                                     DisplayChangeListener *dcl, Error **errp)
1517 {
1518     int flags;
1519 
1520     flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
1521 
1522     if (console_has_gl(con) &&
1523         !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
1524         error_setg(errp, "Display %s is incompatible with the GL context",
1525                    dcl->ops->dpy_name);
1526         return false;
1527     }
1528 
1529     if (flags & GRAPHIC_FLAGS_GL &&
1530         !console_has_gl(con)) {
1531         error_setg(errp, "The console requires a GL context.");
1532         return false;
1533 
1534     }
1535 
1536     if (flags & GRAPHIC_FLAGS_DMABUF &&
1537         !displaychangelistener_has_dmabuf(dcl)) {
1538         error_setg(errp, "The console requires display DMABUF support.");
1539         return false;
1540     }
1541 
1542     return true;
1543 }
1544 
1545 void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
1546 {
1547     /* display has opengl support */
1548     assert(con);
1549     if (con->gl) {
1550         error_report("The console already has an OpenGL context.");
1551         exit(1);
1552     }
1553     con->gl = gl;
1554 }
1555 
1556 void register_displaychangelistener(DisplayChangeListener *dcl)
1557 {
1558     QemuConsole *con;
1559 
1560     assert(!dcl->ds);
1561 
1562     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1563     dcl->ds = get_alloc_displaystate();
1564     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1565     gui_setup_refresh(dcl->ds);
1566     if (dcl->con) {
1567         dcl->con->dcls++;
1568         con = dcl->con;
1569     } else {
1570         con = active_console;
1571     }
1572     displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL);
1573     text_console_update_cursor(NULL);
1574 }
1575 
1576 void update_displaychangelistener(DisplayChangeListener *dcl,
1577                                   uint64_t interval)
1578 {
1579     DisplayState *ds = dcl->ds;
1580 
1581     dcl->update_interval = interval;
1582     if (!ds->refreshing && ds->update_interval > interval) {
1583         timer_mod(ds->gui_timer, ds->last_update + interval);
1584     }
1585 }
1586 
1587 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1588 {
1589     DisplayState *ds = dcl->ds;
1590     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1591     if (dcl->con) {
1592         dcl->con->dcls--;
1593     }
1594     QLIST_REMOVE(dcl, next);
1595     dcl->ds = NULL;
1596     gui_setup_refresh(ds);
1597 }
1598 
1599 static void dpy_set_ui_info_timer(void *opaque)
1600 {
1601     QemuConsole *con = opaque;
1602 
1603     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1604 }
1605 
1606 bool dpy_ui_info_supported(QemuConsole *con)
1607 {
1608     if (con == NULL) {
1609         con = active_console;
1610     }
1611 
1612     return con->hw_ops->ui_info != NULL;
1613 }
1614 
1615 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
1616 {
1617     if (con == NULL) {
1618         con = active_console;
1619     }
1620 
1621     return &con->ui_info;
1622 }
1623 
1624 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
1625 {
1626     if (con == NULL) {
1627         con = active_console;
1628     }
1629 
1630     if (!dpy_ui_info_supported(con)) {
1631         return -1;
1632     }
1633     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1634         /* nothing changed -- ignore */
1635         return 0;
1636     }
1637 
1638     /*
1639      * Typically we get a flood of these as the user resizes the window.
1640      * Wait until the dust has settled (one second without updates), then
1641      * go notify the guest.
1642      */
1643     con->ui_info = *info;
1644     timer_mod(con->ui_timer,
1645               qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
1646     return 0;
1647 }
1648 
1649 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1650 {
1651     DisplayState *s = con->ds;
1652     DisplayChangeListener *dcl;
1653     int width = qemu_console_get_width(con, x + w);
1654     int height = qemu_console_get_height(con, y + h);
1655 
1656     x = MAX(x, 0);
1657     y = MAX(y, 0);
1658     x = MIN(x, width);
1659     y = MIN(y, height);
1660     w = MIN(w, width - x);
1661     h = MIN(h, height - y);
1662 
1663     if (!qemu_console_is_visible(con)) {
1664         return;
1665     }
1666     dpy_gfx_update_texture(con, con->surface, x, y, w, h);
1667     QLIST_FOREACH(dcl, &s->listeners, next) {
1668         if (con != (dcl->con ? dcl->con : active_console)) {
1669             continue;
1670         }
1671         if (dcl->ops->dpy_gfx_update) {
1672             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1673         }
1674     }
1675 }
1676 
1677 void dpy_gfx_update_full(QemuConsole *con)
1678 {
1679     int w = qemu_console_get_width(con, 0);
1680     int h = qemu_console_get_height(con, 0);
1681 
1682     dpy_gfx_update(con, 0, 0, w, h);
1683 }
1684 
1685 void dpy_gfx_replace_surface(QemuConsole *con,
1686                              DisplaySurface *surface)
1687 {
1688     static const char placeholder_msg[] = "Display output is not active.";
1689     DisplayState *s = con->ds;
1690     DisplaySurface *old_surface = con->surface;
1691     DisplayChangeListener *dcl;
1692     int width;
1693     int height;
1694 
1695     if (!surface) {
1696         if (old_surface) {
1697             width = surface_width(old_surface);
1698             height = surface_height(old_surface);
1699         } else {
1700             width = 640;
1701             height = 480;
1702         }
1703 
1704         surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
1705     }
1706 
1707     assert(old_surface != surface);
1708 
1709     con->scanout.kind = SCANOUT_SURFACE;
1710     con->surface = surface;
1711     dpy_gfx_create_texture(con, surface);
1712     QLIST_FOREACH(dcl, &s->listeners, next) {
1713         if (con != (dcl->con ? dcl->con : active_console)) {
1714             continue;
1715         }
1716         displaychangelistener_gfx_switch(dcl, surface, FALSE);
1717     }
1718     dpy_gfx_destroy_texture(con, old_surface);
1719     qemu_free_displaysurface(old_surface);
1720 }
1721 
1722 bool dpy_gfx_check_format(QemuConsole *con,
1723                           pixman_format_code_t format)
1724 {
1725     DisplayChangeListener *dcl;
1726     DisplayState *s = con->ds;
1727 
1728     QLIST_FOREACH(dcl, &s->listeners, next) {
1729         if (dcl->con && dcl->con != con) {
1730             /* dcl bound to another console -> skip */
1731             continue;
1732         }
1733         if (dcl->ops->dpy_gfx_check_format) {
1734             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1735                 return false;
1736             }
1737         } else {
1738             /* default is to allow native 32 bpp only */
1739             if (format != qemu_default_pixman_format(32, true)) {
1740                 return false;
1741             }
1742         }
1743     }
1744     return true;
1745 }
1746 
1747 static void dpy_refresh(DisplayState *s)
1748 {
1749     DisplayChangeListener *dcl;
1750 
1751     QLIST_FOREACH(dcl, &s->listeners, next) {
1752         if (dcl->ops->dpy_refresh) {
1753             dcl->ops->dpy_refresh(dcl);
1754         }
1755     }
1756 }
1757 
1758 void dpy_text_cursor(QemuConsole *con, int x, int y)
1759 {
1760     DisplayState *s = con->ds;
1761     DisplayChangeListener *dcl;
1762 
1763     if (!qemu_console_is_visible(con)) {
1764         return;
1765     }
1766     QLIST_FOREACH(dcl, &s->listeners, next) {
1767         if (con != (dcl->con ? dcl->con : active_console)) {
1768             continue;
1769         }
1770         if (dcl->ops->dpy_text_cursor) {
1771             dcl->ops->dpy_text_cursor(dcl, x, y);
1772         }
1773     }
1774 }
1775 
1776 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1777 {
1778     DisplayState *s = con->ds;
1779     DisplayChangeListener *dcl;
1780 
1781     if (!qemu_console_is_visible(con)) {
1782         return;
1783     }
1784     QLIST_FOREACH(dcl, &s->listeners, next) {
1785         if (con != (dcl->con ? dcl->con : active_console)) {
1786             continue;
1787         }
1788         if (dcl->ops->dpy_text_update) {
1789             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1790         }
1791     }
1792 }
1793 
1794 void dpy_text_resize(QemuConsole *con, int w, int h)
1795 {
1796     DisplayState *s = con->ds;
1797     DisplayChangeListener *dcl;
1798 
1799     if (!qemu_console_is_visible(con)) {
1800         return;
1801     }
1802     QLIST_FOREACH(dcl, &s->listeners, next) {
1803         if (con != (dcl->con ? dcl->con : active_console)) {
1804             continue;
1805         }
1806         if (dcl->ops->dpy_text_resize) {
1807             dcl->ops->dpy_text_resize(dcl, w, h);
1808         }
1809     }
1810 }
1811 
1812 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1813 {
1814     DisplayState *s = con->ds;
1815     DisplayChangeListener *dcl;
1816 
1817     if (!qemu_console_is_visible(con)) {
1818         return;
1819     }
1820     QLIST_FOREACH(dcl, &s->listeners, next) {
1821         if (con != (dcl->con ? dcl->con : active_console)) {
1822             continue;
1823         }
1824         if (dcl->ops->dpy_mouse_set) {
1825             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1826         }
1827     }
1828 }
1829 
1830 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1831 {
1832     DisplayState *s = con->ds;
1833     DisplayChangeListener *dcl;
1834 
1835     if (!qemu_console_is_visible(con)) {
1836         return;
1837     }
1838     QLIST_FOREACH(dcl, &s->listeners, next) {
1839         if (con != (dcl->con ? dcl->con : active_console)) {
1840             continue;
1841         }
1842         if (dcl->ops->dpy_cursor_define) {
1843             dcl->ops->dpy_cursor_define(dcl, cursor);
1844         }
1845     }
1846 }
1847 
1848 bool dpy_cursor_define_supported(QemuConsole *con)
1849 {
1850     DisplayState *s = con->ds;
1851     DisplayChangeListener *dcl;
1852 
1853     QLIST_FOREACH(dcl, &s->listeners, next) {
1854         if (dcl->ops->dpy_cursor_define) {
1855             return true;
1856         }
1857     }
1858     return false;
1859 }
1860 
1861 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1862                                 struct QEMUGLParams *qparams)
1863 {
1864     assert(con->gl);
1865     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1866 }
1867 
1868 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1869 {
1870     assert(con->gl);
1871     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1872 }
1873 
1874 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1875 {
1876     assert(con->gl);
1877     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1878 }
1879 
1880 void dpy_gl_scanout_disable(QemuConsole *con)
1881 {
1882     DisplayState *s = con->ds;
1883     DisplayChangeListener *dcl;
1884 
1885     if (con->scanout.kind != SCANOUT_SURFACE) {
1886         con->scanout.kind = SCANOUT_NONE;
1887     }
1888     QLIST_FOREACH(dcl, &s->listeners, next) {
1889         if (dcl->ops->dpy_gl_scanout_disable) {
1890             dcl->ops->dpy_gl_scanout_disable(dcl);
1891         }
1892     }
1893 }
1894 
1895 void dpy_gl_scanout_texture(QemuConsole *con,
1896                             uint32_t backing_id,
1897                             bool backing_y_0_top,
1898                             uint32_t backing_width,
1899                             uint32_t backing_height,
1900                             uint32_t x, uint32_t y,
1901                             uint32_t width, uint32_t height)
1902 {
1903     DisplayState *s = con->ds;
1904     DisplayChangeListener *dcl;
1905 
1906     con->scanout.kind = SCANOUT_TEXTURE;
1907     con->scanout.texture = (ScanoutTexture) {
1908         backing_id, backing_y_0_top, backing_width, backing_height,
1909         x, y, width, height
1910     };
1911     QLIST_FOREACH(dcl, &s->listeners, next) {
1912         if (dcl->ops->dpy_gl_scanout_texture) {
1913             dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
1914                                              backing_y_0_top,
1915                                              backing_width, backing_height,
1916                                              x, y, width, height);
1917         }
1918     }
1919 }
1920 
1921 void dpy_gl_scanout_dmabuf(QemuConsole *con,
1922                            QemuDmaBuf *dmabuf)
1923 {
1924     DisplayState *s = con->ds;
1925     DisplayChangeListener *dcl;
1926 
1927     con->scanout.kind = SCANOUT_DMABUF;
1928     con->scanout.dmabuf = dmabuf;
1929     QLIST_FOREACH(dcl, &s->listeners, next) {
1930         if (dcl->ops->dpy_gl_scanout_dmabuf) {
1931             dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
1932         }
1933     }
1934 }
1935 
1936 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
1937                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
1938 {
1939     DisplayState *s = con->ds;
1940     DisplayChangeListener *dcl;
1941 
1942     QLIST_FOREACH(dcl, &s->listeners, next) {
1943         if (dcl->ops->dpy_gl_cursor_dmabuf) {
1944             dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
1945                                            have_hot, hot_x, hot_y);
1946         }
1947     }
1948 }
1949 
1950 void dpy_gl_cursor_position(QemuConsole *con,
1951                             uint32_t pos_x, uint32_t pos_y)
1952 {
1953     DisplayState *s = con->ds;
1954     DisplayChangeListener *dcl;
1955 
1956     QLIST_FOREACH(dcl, &s->listeners, next) {
1957         if (dcl->ops->dpy_gl_cursor_position) {
1958             dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
1959         }
1960     }
1961 }
1962 
1963 void dpy_gl_release_dmabuf(QemuConsole *con,
1964                           QemuDmaBuf *dmabuf)
1965 {
1966     DisplayState *s = con->ds;
1967     DisplayChangeListener *dcl;
1968 
1969     QLIST_FOREACH(dcl, &s->listeners, next) {
1970         if (dcl->ops->dpy_gl_release_dmabuf) {
1971             dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
1972         }
1973     }
1974 }
1975 
1976 void dpy_gl_update(QemuConsole *con,
1977                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1978 {
1979     DisplayState *s = con->ds;
1980     DisplayChangeListener *dcl;
1981 
1982     assert(con->gl);
1983 
1984     graphic_hw_gl_block(con, true);
1985     QLIST_FOREACH(dcl, &s->listeners, next) {
1986         if (dcl->ops->dpy_gl_update) {
1987             dcl->ops->dpy_gl_update(dcl, x, y, w, h);
1988         }
1989     }
1990     graphic_hw_gl_block(con, false);
1991 }
1992 
1993 /***********************************************************/
1994 /* register display */
1995 
1996 /* console.c internal use only */
1997 static DisplayState *get_alloc_displaystate(void)
1998 {
1999     if (!display_state) {
2000         display_state = g_new0(DisplayState, 1);
2001         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
2002                                     text_console_update_cursor, NULL);
2003     }
2004     return display_state;
2005 }
2006 
2007 /*
2008  * Called by main(), after creating QemuConsoles
2009  * and before initializing ui (sdl/vnc/...).
2010  */
2011 DisplayState *init_displaystate(void)
2012 {
2013     gchar *name;
2014     QemuConsole *con;
2015 
2016     get_alloc_displaystate();
2017     QTAILQ_FOREACH(con, &consoles, next) {
2018         if (con->console_type != GRAPHIC_CONSOLE &&
2019             con->ds == NULL) {
2020             text_console_do_init(con->chr, display_state);
2021         }
2022 
2023         /* Hook up into the qom tree here (not in new_console()), once
2024          * all QemuConsoles are created and the order / numbering
2025          * doesn't change any more */
2026         name = g_strdup_printf("console[%d]", con->index);
2027         object_property_add_child(container_get(object_get_root(), "/backend"),
2028                                   name, OBJECT(con));
2029         g_free(name);
2030     }
2031 
2032     return display_state;
2033 }
2034 
2035 void graphic_console_set_hwops(QemuConsole *con,
2036                                const GraphicHwOps *hw_ops,
2037                                void *opaque)
2038 {
2039     con->hw_ops = hw_ops;
2040     con->hw = opaque;
2041 }
2042 
2043 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
2044                                   const GraphicHwOps *hw_ops,
2045                                   void *opaque)
2046 {
2047     static const char noinit[] =
2048         "Guest has not initialized the display (yet).";
2049     int width = 640;
2050     int height = 480;
2051     QemuConsole *s;
2052     DisplayState *ds;
2053     DisplaySurface *surface;
2054 
2055     ds = get_alloc_displaystate();
2056     s = qemu_console_lookup_unused();
2057     if (s) {
2058         trace_console_gfx_reuse(s->index);
2059         width = qemu_console_get_width(s, 0);
2060         height = qemu_console_get_height(s, 0);
2061     } else {
2062         trace_console_gfx_new();
2063         s = new_console(ds, GRAPHIC_CONSOLE, head);
2064         s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
2065                                    dpy_set_ui_info_timer, s);
2066     }
2067     graphic_console_set_hwops(s, hw_ops, opaque);
2068     if (dev) {
2069         object_property_set_link(OBJECT(s), "device", OBJECT(dev),
2070                                  &error_abort);
2071     }
2072 
2073     surface = qemu_create_placeholder_surface(width, height, noinit);
2074     dpy_gfx_replace_surface(s, surface);
2075     s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
2076                                        graphic_hw_gl_unblock_timer, s);
2077     return s;
2078 }
2079 
2080 static const GraphicHwOps unused_ops = {
2081     /* no callbacks */
2082 };
2083 
2084 void graphic_console_close(QemuConsole *con)
2085 {
2086     static const char unplugged[] =
2087         "Guest display has been unplugged";
2088     DisplaySurface *surface;
2089     int width = qemu_console_get_width(con, 640);
2090     int height = qemu_console_get_height(con, 480);
2091 
2092     trace_console_gfx_close(con->index);
2093     object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
2094     graphic_console_set_hwops(con, &unused_ops, NULL);
2095 
2096     if (con->gl) {
2097         dpy_gl_scanout_disable(con);
2098     }
2099     surface = qemu_create_placeholder_surface(width, height, unplugged);
2100     dpy_gfx_replace_surface(con, surface);
2101 }
2102 
2103 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
2104 {
2105     QemuConsole *con;
2106 
2107     QTAILQ_FOREACH(con, &consoles, next) {
2108         if (con->index == index) {
2109             return con;
2110         }
2111     }
2112     return NULL;
2113 }
2114 
2115 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
2116 {
2117     QemuConsole *con;
2118     Object *obj;
2119     uint32_t h;
2120 
2121     QTAILQ_FOREACH(con, &consoles, next) {
2122         obj = object_property_get_link(OBJECT(con),
2123                                        "device", &error_abort);
2124         if (DEVICE(obj) != dev) {
2125             continue;
2126         }
2127         h = object_property_get_uint(OBJECT(con),
2128                                      "head", &error_abort);
2129         if (h != head) {
2130             continue;
2131         }
2132         return con;
2133     }
2134     return NULL;
2135 }
2136 
2137 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
2138                                                 uint32_t head, Error **errp)
2139 {
2140     DeviceState *dev;
2141     QemuConsole *con;
2142 
2143     dev = qdev_find_recursive(sysbus_get_default(), device_id);
2144     if (dev == NULL) {
2145         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
2146                   "Device '%s' not found", device_id);
2147         return NULL;
2148     }
2149 
2150     con = qemu_console_lookup_by_device(dev, head);
2151     if (con == NULL) {
2152         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
2153                    device_id, head);
2154         return NULL;
2155     }
2156 
2157     return con;
2158 }
2159 
2160 QemuConsole *qemu_console_lookup_unused(void)
2161 {
2162     QemuConsole *con;
2163     Object *obj;
2164 
2165     QTAILQ_FOREACH(con, &consoles, next) {
2166         if (con->hw_ops != &unused_ops) {
2167             continue;
2168         }
2169         obj = object_property_get_link(OBJECT(con),
2170                                        "device", &error_abort);
2171         if (obj != NULL) {
2172             continue;
2173         }
2174         return con;
2175     }
2176     return NULL;
2177 }
2178 
2179 bool qemu_console_is_visible(QemuConsole *con)
2180 {
2181     return (con == active_console) || (con->dcls > 0);
2182 }
2183 
2184 bool qemu_console_is_graphic(QemuConsole *con)
2185 {
2186     if (con == NULL) {
2187         con = active_console;
2188     }
2189     return con && (con->console_type == GRAPHIC_CONSOLE);
2190 }
2191 
2192 bool qemu_console_is_fixedsize(QemuConsole *con)
2193 {
2194     if (con == NULL) {
2195         con = active_console;
2196     }
2197     return con && (con->console_type != TEXT_CONSOLE);
2198 }
2199 
2200 bool qemu_console_is_gl_blocked(QemuConsole *con)
2201 {
2202     assert(con != NULL);
2203     return con->gl_block;
2204 }
2205 
2206 char *qemu_console_get_label(QemuConsole *con)
2207 {
2208     if (con->console_type == GRAPHIC_CONSOLE) {
2209         if (con->device) {
2210             return g_strdup(object_get_typename(con->device));
2211         }
2212         return g_strdup("VGA");
2213     } else {
2214         if (con->chr && con->chr->label) {
2215             return g_strdup(con->chr->label);
2216         }
2217         return g_strdup_printf("vc%d", con->index);
2218     }
2219 }
2220 
2221 int qemu_console_get_index(QemuConsole *con)
2222 {
2223     if (con == NULL) {
2224         con = active_console;
2225     }
2226     return con ? con->index : -1;
2227 }
2228 
2229 uint32_t qemu_console_get_head(QemuConsole *con)
2230 {
2231     if (con == NULL) {
2232         con = active_console;
2233     }
2234     return con ? con->head : -1;
2235 }
2236 
2237 int qemu_console_get_width(QemuConsole *con, int fallback)
2238 {
2239     if (con == NULL) {
2240         con = active_console;
2241     }
2242     if (con == NULL) {
2243         return fallback;
2244     }
2245     switch (con->scanout.kind) {
2246     case SCANOUT_DMABUF:
2247         return con->scanout.dmabuf->width;
2248     case SCANOUT_TEXTURE:
2249         return con->scanout.texture.width;
2250     case SCANOUT_SURFACE:
2251         return surface_width(con->surface);
2252     default:
2253         return fallback;
2254     }
2255 }
2256 
2257 int qemu_console_get_height(QemuConsole *con, int fallback)
2258 {
2259     if (con == NULL) {
2260         con = active_console;
2261     }
2262     if (con == NULL) {
2263         return fallback;
2264     }
2265     switch (con->scanout.kind) {
2266     case SCANOUT_DMABUF:
2267         return con->scanout.dmabuf->height;
2268     case SCANOUT_TEXTURE:
2269         return con->scanout.texture.height;
2270     case SCANOUT_SURFACE:
2271         return surface_height(con->surface);
2272     default:
2273         return fallback;
2274     }
2275 }
2276 
2277 static void vc_chr_accept_input(Chardev *chr)
2278 {
2279     VCChardev *drv = VC_CHARDEV(chr);
2280     QemuConsole *s = drv->console;
2281 
2282     kbd_send_chars(s);
2283 }
2284 
2285 static void vc_chr_set_echo(Chardev *chr, bool echo)
2286 {
2287     VCChardev *drv = VC_CHARDEV(chr);
2288     QemuConsole *s = drv->console;
2289 
2290     s->echo = echo;
2291 }
2292 
2293 static void text_console_update_cursor_timer(void)
2294 {
2295     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
2296               + CONSOLE_CURSOR_PERIOD / 2);
2297 }
2298 
2299 static void text_console_update_cursor(void *opaque)
2300 {
2301     QemuConsole *s;
2302     int count = 0;
2303 
2304     cursor_visible_phase = !cursor_visible_phase;
2305 
2306     QTAILQ_FOREACH(s, &consoles, next) {
2307         if (qemu_console_is_graphic(s) ||
2308             !qemu_console_is_visible(s)) {
2309             continue;
2310         }
2311         count++;
2312         graphic_hw_invalidate(s);
2313     }
2314 
2315     if (count) {
2316         text_console_update_cursor_timer();
2317     }
2318 }
2319 
2320 static const GraphicHwOps text_console_ops = {
2321     .invalidate  = text_console_invalidate,
2322     .text_update = text_console_update,
2323 };
2324 
2325 static void text_console_do_init(Chardev *chr, DisplayState *ds)
2326 {
2327     VCChardev *drv = VC_CHARDEV(chr);
2328     QemuConsole *s = drv->console;
2329     int g_width = 80 * FONT_WIDTH;
2330     int g_height = 24 * FONT_HEIGHT;
2331 
2332     fifo8_create(&s->out_fifo, 16);
2333     s->ds = ds;
2334 
2335     s->y_displayed = 0;
2336     s->y_base = 0;
2337     s->total_height = DEFAULT_BACKSCROLL;
2338     s->x = 0;
2339     s->y = 0;
2340     if (s->scanout.kind != SCANOUT_SURFACE) {
2341         if (active_console && active_console->scanout.kind == SCANOUT_SURFACE) {
2342             g_width = qemu_console_get_width(active_console, g_width);
2343             g_height = qemu_console_get_height(active_console, g_height);
2344         }
2345         s->surface = qemu_create_displaysurface(g_width, g_height);
2346         s->scanout.kind = SCANOUT_SURFACE;
2347     }
2348 
2349     s->hw_ops = &text_console_ops;
2350     s->hw = s;
2351 
2352     /* Set text attribute defaults */
2353     s->t_attrib_default.bold = 0;
2354     s->t_attrib_default.uline = 0;
2355     s->t_attrib_default.blink = 0;
2356     s->t_attrib_default.invers = 0;
2357     s->t_attrib_default.unvisible = 0;
2358     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2359     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2360     /* set current text attributes to default */
2361     s->t_attrib = s->t_attrib_default;
2362     text_console_resize(s);
2363 
2364     if (chr->label) {
2365         char *msg;
2366 
2367         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2368         msg = g_strdup_printf("%s console\r\n", chr->label);
2369         vc_chr_write(chr, (uint8_t *)msg, strlen(msg));
2370         g_free(msg);
2371         s->t_attrib = s->t_attrib_default;
2372     }
2373 
2374     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
2375 }
2376 
2377 static void vc_chr_open(Chardev *chr,
2378                         ChardevBackend *backend,
2379                         bool *be_opened,
2380                         Error **errp)
2381 {
2382     ChardevVC *vc = backend->u.vc.data;
2383     VCChardev *drv = VC_CHARDEV(chr);
2384     QemuConsole *s;
2385     unsigned width = 0;
2386     unsigned height = 0;
2387 
2388     if (vc->has_width) {
2389         width = vc->width;
2390     } else if (vc->has_cols) {
2391         width = vc->cols * FONT_WIDTH;
2392     }
2393 
2394     if (vc->has_height) {
2395         height = vc->height;
2396     } else if (vc->has_rows) {
2397         height = vc->rows * FONT_HEIGHT;
2398     }
2399 
2400     trace_console_txt_new(width, height);
2401     if (width == 0 || height == 0) {
2402         s = new_console(NULL, TEXT_CONSOLE, 0);
2403     } else {
2404         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2405         s->scanout.kind = SCANOUT_SURFACE;
2406         s->surface = qemu_create_displaysurface(width, height);
2407     }
2408 
2409     if (!s) {
2410         error_setg(errp, "cannot create text console");
2411         return;
2412     }
2413 
2414     s->chr = chr;
2415     drv->console = s;
2416 
2417     if (display_state) {
2418         text_console_do_init(chr, display_state);
2419     }
2420 
2421     /* console/chardev init sometimes completes elsewhere in a 2nd
2422      * stage, so defer OPENED events until they are fully initialized
2423      */
2424     *be_opened = false;
2425 }
2426 
2427 void qemu_console_resize(QemuConsole *s, int width, int height)
2428 {
2429     DisplaySurface *surface;
2430 
2431     assert(s->console_type == GRAPHIC_CONSOLE);
2432 
2433     if (qemu_console_get_width(s, -1) == width &&
2434         qemu_console_get_height(s, -1) == height) {
2435         return;
2436     }
2437 
2438     surface = qemu_create_displaysurface(width, height);
2439     dpy_gfx_replace_surface(s, surface);
2440 }
2441 
2442 DisplaySurface *qemu_console_surface(QemuConsole *console)
2443 {
2444     switch (console->scanout.kind) {
2445     case SCANOUT_SURFACE:
2446         return console->surface;
2447     default:
2448         return NULL;
2449     }
2450 }
2451 
2452 PixelFormat qemu_default_pixelformat(int bpp)
2453 {
2454     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2455     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2456     return pf;
2457 }
2458 
2459 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
2460 
2461 void qemu_display_register(QemuDisplay *ui)
2462 {
2463     assert(ui->type < DISPLAY_TYPE__MAX);
2464     dpys[ui->type] = ui;
2465 }
2466 
2467 bool qemu_display_find_default(DisplayOptions *opts)
2468 {
2469     static DisplayType prio[] = {
2470 #if defined(CONFIG_GTK)
2471         DISPLAY_TYPE_GTK,
2472 #endif
2473 #if defined(CONFIG_SDL)
2474         DISPLAY_TYPE_SDL,
2475 #endif
2476 #if defined(CONFIG_COCOA)
2477         DISPLAY_TYPE_COCOA
2478 #endif
2479     };
2480     int i;
2481 
2482     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
2483         if (dpys[prio[i]] == NULL) {
2484             ui_module_load_one(DisplayType_str(prio[i]));
2485         }
2486         if (dpys[prio[i]] == NULL) {
2487             continue;
2488         }
2489         opts->type = prio[i];
2490         return true;
2491     }
2492     return false;
2493 }
2494 
2495 void qemu_display_early_init(DisplayOptions *opts)
2496 {
2497     assert(opts->type < DISPLAY_TYPE__MAX);
2498     if (opts->type == DISPLAY_TYPE_NONE) {
2499         return;
2500     }
2501     if (dpys[opts->type] == NULL) {
2502         ui_module_load_one(DisplayType_str(opts->type));
2503     }
2504     if (dpys[opts->type] == NULL) {
2505         error_report("Display '%s' is not available.",
2506                      DisplayType_str(opts->type));
2507         exit(1);
2508     }
2509     if (dpys[opts->type]->early_init) {
2510         dpys[opts->type]->early_init(opts);
2511     }
2512 }
2513 
2514 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
2515 {
2516     assert(opts->type < DISPLAY_TYPE__MAX);
2517     if (opts->type == DISPLAY_TYPE_NONE) {
2518         return;
2519     }
2520     assert(dpys[opts->type] != NULL);
2521     dpys[opts->type]->init(ds, opts);
2522 }
2523 
2524 void qemu_display_help(void)
2525 {
2526     int idx;
2527 
2528     printf("Available display backend types:\n");
2529     printf("none\n");
2530     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
2531         if (!dpys[idx]) {
2532             ui_module_load_one(DisplayType_str(idx));
2533         }
2534         if (dpys[idx]) {
2535             printf("%s\n",  DisplayType_str(dpys[idx]->type));
2536         }
2537     }
2538 }
2539 
2540 void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
2541 {
2542     int val;
2543     ChardevVC *vc;
2544 
2545     backend->type = CHARDEV_BACKEND_KIND_VC;
2546     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2547     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2548 
2549     val = qemu_opt_get_number(opts, "width", 0);
2550     if (val != 0) {
2551         vc->has_width = true;
2552         vc->width = val;
2553     }
2554 
2555     val = qemu_opt_get_number(opts, "height", 0);
2556     if (val != 0) {
2557         vc->has_height = true;
2558         vc->height = val;
2559     }
2560 
2561     val = qemu_opt_get_number(opts, "cols", 0);
2562     if (val != 0) {
2563         vc->has_cols = true;
2564         vc->cols = val;
2565     }
2566 
2567     val = qemu_opt_get_number(opts, "rows", 0);
2568     if (val != 0) {
2569         vc->has_rows = true;
2570         vc->rows = val;
2571     }
2572 }
2573 
2574 static const TypeInfo qemu_console_info = {
2575     .name = TYPE_QEMU_CONSOLE,
2576     .parent = TYPE_OBJECT,
2577     .instance_size = sizeof(QemuConsole),
2578     .class_size = sizeof(QemuConsoleClass),
2579 };
2580 
2581 static void char_vc_class_init(ObjectClass *oc, void *data)
2582 {
2583     ChardevClass *cc = CHARDEV_CLASS(oc);
2584 
2585     cc->parse = qemu_chr_parse_vc;
2586     cc->open = vc_chr_open;
2587     cc->chr_write = vc_chr_write;
2588     cc->chr_accept_input = vc_chr_accept_input;
2589     cc->chr_set_echo = vc_chr_set_echo;
2590 }
2591 
2592 static const TypeInfo char_vc_type_info = {
2593     .name = TYPE_CHARDEV_VC,
2594     .parent = TYPE_CHARDEV,
2595     .instance_size = sizeof(VCChardev),
2596     .class_init = char_vc_class_init,
2597 };
2598 
2599 void qemu_console_early_init(void)
2600 {
2601     /* set the default vc driver */
2602     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
2603         type_register(&char_vc_type_info);
2604     }
2605 }
2606 
2607 static void register_types(void)
2608 {
2609     type_register_static(&qemu_console_info);
2610 }
2611 
2612 type_init(register_types);
2613