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