xref: /qemu/ui/console.c (revision 29b62a10)
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/coroutine.h"
31 #include "qemu/fifo8.h"
32 #include "qemu/main-loop.h"
33 #include "qemu/module.h"
34 #include "qemu/option.h"
35 #include "qemu/timer.h"
36 #include "chardev/char.h"
37 #include "trace.h"
38 #include "exec/memory.h"
39 #include "io/channel-file.h"
40 #include "qom/object.h"
41 #ifdef CONFIG_PNG
42 #include <png.h>
43 #endif
44 
45 #define DEFAULT_BACKSCROLL 512
46 #define CONSOLE_CURSOR_PERIOD 500
47 
48 typedef struct TextAttributes {
49     uint8_t fgcol:4;
50     uint8_t bgcol:4;
51     uint8_t bold:1;
52     uint8_t uline:1;
53     uint8_t blink:1;
54     uint8_t invers:1;
55     uint8_t unvisible:1;
56 } TextAttributes;
57 
58 typedef struct TextCell {
59     uint8_t ch;
60     TextAttributes t_attrib;
61 } TextCell;
62 
63 #define MAX_ESC_PARAMS 3
64 
65 enum TTYState {
66     TTY_STATE_NORM,
67     TTY_STATE_ESC,
68     TTY_STATE_CSI,
69 };
70 
71 typedef enum {
72     GRAPHIC_CONSOLE,
73     TEXT_CONSOLE,
74     TEXT_CONSOLE_FIXED_SIZE
75 } console_type_t;
76 
77 struct QemuConsole {
78     Object parent;
79 
80     int index;
81     console_type_t console_type;
82     DisplayState *ds;
83     DisplaySurface *surface;
84     DisplayScanout scanout;
85     int dcls;
86     DisplayGLCtx *gl;
87     int gl_block;
88     QEMUTimer *gl_unblock_timer;
89     int window_id;
90 
91     /* Graphic console state.  */
92     Object *device;
93     uint32_t head;
94     QemuUIInfo ui_info;
95     QEMUTimer *ui_timer;
96     const GraphicHwOps *hw_ops;
97     void *hw;
98 
99     /* Text console state */
100     int width;
101     int height;
102     int total_height;
103     int backscroll_height;
104     int x, y;
105     int x_saved, y_saved;
106     int y_displayed;
107     int y_base;
108     TextAttributes t_attrib_default; /* default text attributes */
109     TextAttributes t_attrib; /* currently active text attributes */
110     TextCell *cells;
111     int text_x[2], text_y[2], cursor_invalidate;
112     int echo;
113 
114     int update_x0;
115     int update_y0;
116     int update_x1;
117     int update_y1;
118 
119     enum TTYState state;
120     int esc_params[MAX_ESC_PARAMS];
121     int nb_esc_params;
122 
123     Chardev *chr;
124     /* fifo for key pressed */
125     Fifo8 out_fifo;
126     CoQueue dump_queue;
127 
128     QTAILQ_ENTRY(QemuConsole) next;
129 };
130 
131 struct DisplayState {
132     QEMUTimer *gui_timer;
133     uint64_t last_update;
134     uint64_t update_interval;
135     bool refreshing;
136     bool have_gfx;
137     bool have_text;
138 
139     QLIST_HEAD(, DisplayChangeListener) listeners;
140 };
141 
142 static DisplayState *display_state;
143 static QemuConsole *active_console;
144 static QTAILQ_HEAD(, QemuConsole) consoles =
145     QTAILQ_HEAD_INITIALIZER(consoles);
146 static bool cursor_visible_phase;
147 static QEMUTimer *cursor_timer;
148 
149 static void text_console_do_init(Chardev *chr, DisplayState *ds);
150 static void dpy_refresh(DisplayState *s);
151 static DisplayState *get_alloc_displaystate(void);
152 static void text_console_update_cursor_timer(void);
153 static void text_console_update_cursor(void *opaque);
154 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
155 static bool console_compatible_with(QemuConsole *con,
156                                     DisplayChangeListener *dcl, Error **errp);
157 
158 static void gui_update(void *opaque)
159 {
160     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
161     uint64_t dcl_interval;
162     DisplayState *ds = opaque;
163     DisplayChangeListener *dcl;
164 
165     ds->refreshing = true;
166     dpy_refresh(ds);
167     ds->refreshing = false;
168 
169     QLIST_FOREACH(dcl, &ds->listeners, next) {
170         dcl_interval = dcl->update_interval ?
171             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
172         if (interval > dcl_interval) {
173             interval = dcl_interval;
174         }
175     }
176     if (ds->update_interval != interval) {
177         ds->update_interval = interval;
178         trace_console_refresh(interval);
179     }
180     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
181     timer_mod(ds->gui_timer, ds->last_update + interval);
182 }
183 
184 static void gui_setup_refresh(DisplayState *ds)
185 {
186     DisplayChangeListener *dcl;
187     bool need_timer = false;
188     bool have_gfx = false;
189     bool have_text = false;
190 
191     QLIST_FOREACH(dcl, &ds->listeners, next) {
192         if (dcl->ops->dpy_refresh != NULL) {
193             need_timer = true;
194         }
195         if (dcl->ops->dpy_gfx_update != NULL) {
196             have_gfx = true;
197         }
198         if (dcl->ops->dpy_text_update != NULL) {
199             have_text = true;
200         }
201     }
202 
203     if (need_timer && ds->gui_timer == NULL) {
204         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
205         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
206     }
207     if (!need_timer && ds->gui_timer != NULL) {
208         timer_free(ds->gui_timer);
209         ds->gui_timer = NULL;
210     }
211 
212     ds->have_gfx = have_gfx;
213     ds->have_text = have_text;
214 }
215 
216 void graphic_hw_update_done(QemuConsole *con)
217 {
218     if (con) {
219         qemu_co_enter_all(&con->dump_queue, NULL);
220     }
221 }
222 
223 void graphic_hw_update(QemuConsole *con)
224 {
225     bool async = false;
226     con = con ? con : active_console;
227     if (!con) {
228         return;
229     }
230     if (con->hw_ops->gfx_update) {
231         con->hw_ops->gfx_update(con->hw);
232         async = con->hw_ops->gfx_update_async;
233     }
234     if (!async) {
235         graphic_hw_update_done(con);
236     }
237 }
238 
239 static void graphic_hw_gl_unblock_timer(void *opaque)
240 {
241     warn_report("console: no gl-unblock within one second");
242 }
243 
244 void graphic_hw_gl_block(QemuConsole *con, bool block)
245 {
246     uint64_t timeout;
247     assert(con != NULL);
248 
249     if (block) {
250         con->gl_block++;
251     } else {
252         con->gl_block--;
253     }
254     assert(con->gl_block >= 0);
255     if (!con->hw_ops->gl_block) {
256         return;
257     }
258     if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
259         return;
260     }
261     con->hw_ops->gl_block(con->hw, block);
262 
263     if (block) {
264         timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
265         timeout += 1000; /* one sec */
266         timer_mod(con->gl_unblock_timer, timeout);
267     } else {
268         timer_del(con->gl_unblock_timer);
269     }
270 }
271 
272 int qemu_console_get_window_id(QemuConsole *con)
273 {
274     return con->window_id;
275 }
276 
277 void qemu_console_set_window_id(QemuConsole *con, int window_id)
278 {
279     con->window_id = window_id;
280 }
281 
282 void graphic_hw_invalidate(QemuConsole *con)
283 {
284     if (!con) {
285         con = active_console;
286     }
287     if (con && con->hw_ops->invalidate) {
288         con->hw_ops->invalidate(con->hw);
289     }
290 }
291 
292 #ifdef CONFIG_PNG
293 /**
294  * png_save: Take a screenshot as PNG
295  *
296  * Saves screendump as a PNG file
297  *
298  * Returns true for success or false for error.
299  *
300  * @fd: File descriptor for PNG file.
301  * @image: Image data in pixman format.
302  * @errp: Pointer to an error.
303  */
304 static bool png_save(int fd, pixman_image_t *image, Error **errp)
305 {
306     int width = pixman_image_get_width(image);
307     int height = pixman_image_get_height(image);
308     png_struct *png_ptr;
309     png_info *info_ptr;
310     g_autoptr(pixman_image_t) linebuf =
311                             qemu_pixman_linebuf_create(PIXMAN_a8r8g8b8, width);
312     uint8_t *buf = (uint8_t *)pixman_image_get_data(linebuf);
313     FILE *f = fdopen(fd, "wb");
314     int y;
315     if (!f) {
316         error_setg_errno(errp, errno,
317                          "Failed to create file from file descriptor");
318         return false;
319     }
320 
321     png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
322                                       NULL, NULL);
323     if (!png_ptr) {
324         error_setg(errp, "PNG creation failed. Unable to write struct");
325         fclose(f);
326         return false;
327     }
328 
329     info_ptr = png_create_info_struct(png_ptr);
330 
331     if (!info_ptr) {
332         error_setg(errp, "PNG creation failed. Unable to write info");
333         fclose(f);
334         png_destroy_write_struct(&png_ptr, &info_ptr);
335         return false;
336     }
337 
338     png_init_io(png_ptr, f);
339 
340     png_set_IHDR(png_ptr, info_ptr, width, height, 8,
341                  PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
342                  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
343 
344     png_write_info(png_ptr, info_ptr);
345 
346     for (y = 0; y < height; ++y) {
347         qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
348         png_write_row(png_ptr, buf);
349     }
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, 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 (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, 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_TAB]    = QEMU_KEY_TAB,
1372     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
1373 };
1374 
1375 static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
1376     [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
1377     [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
1378     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
1379     [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
1380     [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
1381     [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
1382     [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
1383     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
1384 };
1385 
1386 bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
1387 {
1388     int keysym;
1389 
1390     keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
1391     if (keysym == 0) {
1392         return false;
1393     }
1394     kbd_put_keysym_console(s, keysym);
1395     return true;
1396 }
1397 
1398 void kbd_put_string_console(QemuConsole *s, const char *str, int len)
1399 {
1400     int i;
1401 
1402     for (i = 0; i < len && str[i]; i++) {
1403         kbd_put_keysym_console(s, str[i]);
1404     }
1405 }
1406 
1407 void kbd_put_keysym(int keysym)
1408 {
1409     kbd_put_keysym_console(active_console, keysym);
1410 }
1411 
1412 static void text_console_invalidate(void *opaque)
1413 {
1414     QemuConsole *s = (QemuConsole *) opaque;
1415 
1416     if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1417         text_console_resize(s);
1418     }
1419     console_refresh(s);
1420 }
1421 
1422 static void text_console_update(void *opaque, console_ch_t *chardata)
1423 {
1424     QemuConsole *s = (QemuConsole *) opaque;
1425     int i, j, src;
1426 
1427     if (s->text_x[0] <= s->text_x[1]) {
1428         src = (s->y_base + s->text_y[0]) * s->width;
1429         chardata += s->text_y[0] * s->width;
1430         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1431             for (j = 0; j < s->width; j++, src++) {
1432                 console_write_ch(chardata ++,
1433                                  ATTR2CHTYPE(s->cells[src].ch,
1434                                              s->cells[src].t_attrib.fgcol,
1435                                              s->cells[src].t_attrib.bgcol,
1436                                              s->cells[src].t_attrib.bold));
1437             }
1438         dpy_text_update(s, s->text_x[0], s->text_y[0],
1439                         s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1440         s->text_x[0] = s->width;
1441         s->text_y[0] = s->height;
1442         s->text_x[1] = 0;
1443         s->text_y[1] = 0;
1444     }
1445     if (s->cursor_invalidate) {
1446         dpy_text_cursor(s, s->x, s->y);
1447         s->cursor_invalidate = 0;
1448     }
1449 }
1450 
1451 static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
1452                                 uint32_t head)
1453 {
1454     Object *obj;
1455     QemuConsole *s;
1456     int i;
1457 
1458     obj = object_new(TYPE_QEMU_CONSOLE);
1459     s = QEMU_CONSOLE(obj);
1460     qemu_co_queue_init(&s->dump_queue);
1461     s->head = head;
1462     object_property_add_link(obj, "device", TYPE_DEVICE,
1463                              (Object **)&s->device,
1464                              object_property_allow_set_link,
1465                              OBJ_PROP_LINK_STRONG);
1466     object_property_add_uint32_ptr(obj, "head", &s->head,
1467                                    OBJ_PROP_FLAG_READ);
1468 
1469     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1470         (console_type == GRAPHIC_CONSOLE))) {
1471         active_console = s;
1472     }
1473     s->ds = ds;
1474     s->console_type = console_type;
1475     s->window_id = -1;
1476 
1477     if (QTAILQ_EMPTY(&consoles)) {
1478         s->index = 0;
1479         QTAILQ_INSERT_TAIL(&consoles, s, next);
1480     } else if (console_type != GRAPHIC_CONSOLE || phase_check(PHASE_MACHINE_READY)) {
1481         QemuConsole *last = QTAILQ_LAST(&consoles);
1482         s->index = last->index + 1;
1483         QTAILQ_INSERT_TAIL(&consoles, s, next);
1484     } else {
1485         /*
1486          * HACK: Put graphical consoles before text consoles.
1487          *
1488          * Only do that for coldplugged devices.  After initial device
1489          * initialization we will not renumber the consoles any more.
1490          */
1491         QemuConsole *c = QTAILQ_FIRST(&consoles);
1492 
1493         while (QTAILQ_NEXT(c, next) != NULL &&
1494                c->console_type == GRAPHIC_CONSOLE) {
1495             c = QTAILQ_NEXT(c, next);
1496         }
1497         if (c->console_type == GRAPHIC_CONSOLE) {
1498             /* have no text consoles */
1499             s->index = c->index + 1;
1500             QTAILQ_INSERT_AFTER(&consoles, c, s, next);
1501         } else {
1502             s->index = c->index;
1503             QTAILQ_INSERT_BEFORE(c, s, next);
1504             /* renumber text consoles */
1505             for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
1506                 c->index = i;
1507             }
1508         }
1509     }
1510     return s;
1511 }
1512 
1513 DisplaySurface *qemu_create_displaysurface(int width, int height)
1514 {
1515     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1516 
1517     trace_displaysurface_create(surface, width, height);
1518     surface->format = PIXMAN_x8r8g8b8;
1519     surface->image = pixman_image_create_bits(surface->format,
1520                                               width, height,
1521                                               NULL, width * 4);
1522     assert(surface->image != NULL);
1523     surface->flags = QEMU_ALLOCATED_FLAG;
1524 
1525     return surface;
1526 }
1527 
1528 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1529                                                 pixman_format_code_t format,
1530                                                 int linesize, uint8_t *data)
1531 {
1532     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1533 
1534     trace_displaysurface_create_from(surface, width, height, format);
1535     surface->format = format;
1536     surface->image = pixman_image_create_bits(surface->format,
1537                                               width, height,
1538                                               (void *)data, linesize);
1539     assert(surface->image != NULL);
1540 
1541     return surface;
1542 }
1543 
1544 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
1545 {
1546     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1547 
1548     trace_displaysurface_create_pixman(surface);
1549     surface->format = pixman_image_get_format(image);
1550     surface->image = pixman_image_ref(image);
1551 
1552     return surface;
1553 }
1554 
1555 DisplaySurface *qemu_create_placeholder_surface(int w, int h,
1556                                                 const char *msg)
1557 {
1558     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1559     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1560     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1561     pixman_image_t *glyph;
1562     int len, x, y, i;
1563 
1564     len = strlen(msg);
1565     x = (w / FONT_WIDTH  - len) / 2;
1566     y = (h / FONT_HEIGHT - 1)   / 2;
1567     for (i = 0; i < len; i++) {
1568         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1569         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1570                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1571         qemu_pixman_image_unref(glyph);
1572     }
1573     surface->flags |= QEMU_PLACEHOLDER_FLAG;
1574     return surface;
1575 }
1576 
1577 void qemu_free_displaysurface(DisplaySurface *surface)
1578 {
1579     if (surface == NULL) {
1580         return;
1581     }
1582     trace_displaysurface_free(surface);
1583     qemu_pixman_image_unref(surface->image);
1584     g_free(surface);
1585 }
1586 
1587 bool console_has_gl(QemuConsole *con)
1588 {
1589     return con->gl != NULL;
1590 }
1591 
1592 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
1593 {
1594     if (dcl->ops->dpy_has_dmabuf) {
1595         return dcl->ops->dpy_has_dmabuf(dcl);
1596     }
1597 
1598     if (dcl->ops->dpy_gl_scanout_dmabuf) {
1599         return true;
1600     }
1601 
1602     return false;
1603 }
1604 
1605 static bool console_compatible_with(QemuConsole *con,
1606                                     DisplayChangeListener *dcl, Error **errp)
1607 {
1608     int flags;
1609 
1610     flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
1611 
1612     if (console_has_gl(con) &&
1613         !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
1614         error_setg(errp, "Display %s is incompatible with the GL context",
1615                    dcl->ops->dpy_name);
1616         return false;
1617     }
1618 
1619     if (flags & GRAPHIC_FLAGS_GL &&
1620         !console_has_gl(con)) {
1621         error_setg(errp, "The console requires a GL context.");
1622         return false;
1623 
1624     }
1625 
1626     if (flags & GRAPHIC_FLAGS_DMABUF &&
1627         !displaychangelistener_has_dmabuf(dcl)) {
1628         error_setg(errp, "The console requires display DMABUF support.");
1629         return false;
1630     }
1631 
1632     return true;
1633 }
1634 
1635 void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
1636 {
1637     /* display has opengl support */
1638     assert(con);
1639     if (con->gl) {
1640         error_report("The console already has an OpenGL context.");
1641         exit(1);
1642     }
1643     con->gl = gl;
1644 }
1645 
1646 void register_displaychangelistener(DisplayChangeListener *dcl)
1647 {
1648     QemuConsole *con;
1649 
1650     assert(!dcl->ds);
1651 
1652     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1653     dcl->ds = get_alloc_displaystate();
1654     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1655     gui_setup_refresh(dcl->ds);
1656     if (dcl->con) {
1657         dcl->con->dcls++;
1658         con = dcl->con;
1659     } else {
1660         con = active_console;
1661     }
1662     displaychangelistener_display_console(dcl, con, dcl->con ? &error_fatal : NULL);
1663     text_console_update_cursor(NULL);
1664 }
1665 
1666 void update_displaychangelistener(DisplayChangeListener *dcl,
1667                                   uint64_t interval)
1668 {
1669     DisplayState *ds = dcl->ds;
1670 
1671     dcl->update_interval = interval;
1672     if (!ds->refreshing && ds->update_interval > interval) {
1673         timer_mod(ds->gui_timer, ds->last_update + interval);
1674     }
1675 }
1676 
1677 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1678 {
1679     DisplayState *ds = dcl->ds;
1680     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1681     if (dcl->con) {
1682         dcl->con->dcls--;
1683     }
1684     QLIST_REMOVE(dcl, next);
1685     dcl->ds = NULL;
1686     gui_setup_refresh(ds);
1687 }
1688 
1689 static void dpy_set_ui_info_timer(void *opaque)
1690 {
1691     QemuConsole *con = opaque;
1692 
1693     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1694 }
1695 
1696 bool dpy_ui_info_supported(QemuConsole *con)
1697 {
1698     if (con == NULL) {
1699         con = active_console;
1700     }
1701 
1702     return con->hw_ops->ui_info != NULL;
1703 }
1704 
1705 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
1706 {
1707     if (con == NULL) {
1708         con = active_console;
1709     }
1710 
1711     return &con->ui_info;
1712 }
1713 
1714 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
1715 {
1716     if (con == NULL) {
1717         con = active_console;
1718     }
1719 
1720     if (!dpy_ui_info_supported(con)) {
1721         return -1;
1722     }
1723     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1724         /* nothing changed -- ignore */
1725         return 0;
1726     }
1727 
1728     /*
1729      * Typically we get a flood of these as the user resizes the window.
1730      * Wait until the dust has settled (one second without updates), then
1731      * go notify the guest.
1732      */
1733     con->ui_info = *info;
1734     timer_mod(con->ui_timer,
1735               qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
1736     return 0;
1737 }
1738 
1739 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1740 {
1741     DisplayState *s = con->ds;
1742     DisplayChangeListener *dcl;
1743     int width = qemu_console_get_width(con, x + w);
1744     int height = qemu_console_get_height(con, y + h);
1745 
1746     x = MAX(x, 0);
1747     y = MAX(y, 0);
1748     x = MIN(x, width);
1749     y = MIN(y, height);
1750     w = MIN(w, width - x);
1751     h = MIN(h, height - y);
1752 
1753     if (!qemu_console_is_visible(con)) {
1754         return;
1755     }
1756     dpy_gfx_update_texture(con, con->surface, x, y, w, h);
1757     QLIST_FOREACH(dcl, &s->listeners, next) {
1758         if (con != (dcl->con ? dcl->con : active_console)) {
1759             continue;
1760         }
1761         if (dcl->ops->dpy_gfx_update) {
1762             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1763         }
1764     }
1765 }
1766 
1767 void dpy_gfx_update_full(QemuConsole *con)
1768 {
1769     int w = qemu_console_get_width(con, 0);
1770     int h = qemu_console_get_height(con, 0);
1771 
1772     dpy_gfx_update(con, 0, 0, w, h);
1773 }
1774 
1775 void dpy_gfx_replace_surface(QemuConsole *con,
1776                              DisplaySurface *surface)
1777 {
1778     static const char placeholder_msg[] = "Display output is not active.";
1779     DisplayState *s = con->ds;
1780     DisplaySurface *old_surface = con->surface;
1781     DisplayChangeListener *dcl;
1782     int width;
1783     int height;
1784 
1785     if (!surface) {
1786         if (old_surface) {
1787             width = surface_width(old_surface);
1788             height = surface_height(old_surface);
1789         } else {
1790             width = 640;
1791             height = 480;
1792         }
1793 
1794         surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
1795     }
1796 
1797     assert(old_surface != surface);
1798 
1799     con->scanout.kind = SCANOUT_SURFACE;
1800     con->surface = surface;
1801     dpy_gfx_create_texture(con, surface);
1802     QLIST_FOREACH(dcl, &s->listeners, next) {
1803         if (con != (dcl->con ? dcl->con : active_console)) {
1804             continue;
1805         }
1806         displaychangelistener_gfx_switch(dcl, surface, FALSE);
1807     }
1808     dpy_gfx_destroy_texture(con, old_surface);
1809     qemu_free_displaysurface(old_surface);
1810 }
1811 
1812 bool dpy_gfx_check_format(QemuConsole *con,
1813                           pixman_format_code_t format)
1814 {
1815     DisplayChangeListener *dcl;
1816     DisplayState *s = con->ds;
1817 
1818     QLIST_FOREACH(dcl, &s->listeners, next) {
1819         if (dcl->con && dcl->con != con) {
1820             /* dcl bound to another console -> skip */
1821             continue;
1822         }
1823         if (dcl->ops->dpy_gfx_check_format) {
1824             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1825                 return false;
1826             }
1827         } else {
1828             /* default is to allow native 32 bpp only */
1829             if (format != qemu_default_pixman_format(32, true)) {
1830                 return false;
1831             }
1832         }
1833     }
1834     return true;
1835 }
1836 
1837 static void dpy_refresh(DisplayState *s)
1838 {
1839     DisplayChangeListener *dcl;
1840 
1841     QLIST_FOREACH(dcl, &s->listeners, next) {
1842         if (dcl->ops->dpy_refresh) {
1843             dcl->ops->dpy_refresh(dcl);
1844         }
1845     }
1846 }
1847 
1848 void dpy_text_cursor(QemuConsole *con, int x, int y)
1849 {
1850     DisplayState *s = con->ds;
1851     DisplayChangeListener *dcl;
1852 
1853     if (!qemu_console_is_visible(con)) {
1854         return;
1855     }
1856     QLIST_FOREACH(dcl, &s->listeners, next) {
1857         if (con != (dcl->con ? dcl->con : active_console)) {
1858             continue;
1859         }
1860         if (dcl->ops->dpy_text_cursor) {
1861             dcl->ops->dpy_text_cursor(dcl, x, y);
1862         }
1863     }
1864 }
1865 
1866 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1867 {
1868     DisplayState *s = con->ds;
1869     DisplayChangeListener *dcl;
1870 
1871     if (!qemu_console_is_visible(con)) {
1872         return;
1873     }
1874     QLIST_FOREACH(dcl, &s->listeners, next) {
1875         if (con != (dcl->con ? dcl->con : active_console)) {
1876             continue;
1877         }
1878         if (dcl->ops->dpy_text_update) {
1879             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1880         }
1881     }
1882 }
1883 
1884 void dpy_text_resize(QemuConsole *con, int w, int h)
1885 {
1886     DisplayState *s = con->ds;
1887     DisplayChangeListener *dcl;
1888 
1889     if (!qemu_console_is_visible(con)) {
1890         return;
1891     }
1892     QLIST_FOREACH(dcl, &s->listeners, next) {
1893         if (con != (dcl->con ? dcl->con : active_console)) {
1894             continue;
1895         }
1896         if (dcl->ops->dpy_text_resize) {
1897             dcl->ops->dpy_text_resize(dcl, w, h);
1898         }
1899     }
1900 }
1901 
1902 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1903 {
1904     DisplayState *s = con->ds;
1905     DisplayChangeListener *dcl;
1906 
1907     if (!qemu_console_is_visible(con)) {
1908         return;
1909     }
1910     QLIST_FOREACH(dcl, &s->listeners, next) {
1911         if (con != (dcl->con ? dcl->con : active_console)) {
1912             continue;
1913         }
1914         if (dcl->ops->dpy_mouse_set) {
1915             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1916         }
1917     }
1918 }
1919 
1920 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1921 {
1922     DisplayState *s = con->ds;
1923     DisplayChangeListener *dcl;
1924 
1925     if (!qemu_console_is_visible(con)) {
1926         return;
1927     }
1928     QLIST_FOREACH(dcl, &s->listeners, next) {
1929         if (con != (dcl->con ? dcl->con : active_console)) {
1930             continue;
1931         }
1932         if (dcl->ops->dpy_cursor_define) {
1933             dcl->ops->dpy_cursor_define(dcl, cursor);
1934         }
1935     }
1936 }
1937 
1938 bool dpy_cursor_define_supported(QemuConsole *con)
1939 {
1940     DisplayState *s = con->ds;
1941     DisplayChangeListener *dcl;
1942 
1943     QLIST_FOREACH(dcl, &s->listeners, next) {
1944         if (dcl->ops->dpy_cursor_define) {
1945             return true;
1946         }
1947     }
1948     return false;
1949 }
1950 
1951 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1952                                 struct QEMUGLParams *qparams)
1953 {
1954     assert(con->gl);
1955     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1956 }
1957 
1958 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1959 {
1960     assert(con->gl);
1961     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1962 }
1963 
1964 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1965 {
1966     assert(con->gl);
1967     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1968 }
1969 
1970 void dpy_gl_scanout_disable(QemuConsole *con)
1971 {
1972     DisplayState *s = con->ds;
1973     DisplayChangeListener *dcl;
1974 
1975     if (con->scanout.kind != SCANOUT_SURFACE) {
1976         con->scanout.kind = SCANOUT_NONE;
1977     }
1978     QLIST_FOREACH(dcl, &s->listeners, next) {
1979         if (con != (dcl->con ? dcl->con : active_console)) {
1980             continue;
1981         }
1982         if (dcl->ops->dpy_gl_scanout_disable) {
1983             dcl->ops->dpy_gl_scanout_disable(dcl);
1984         }
1985     }
1986 }
1987 
1988 void dpy_gl_scanout_texture(QemuConsole *con,
1989                             uint32_t backing_id,
1990                             bool backing_y_0_top,
1991                             uint32_t backing_width,
1992                             uint32_t backing_height,
1993                             uint32_t x, uint32_t y,
1994                             uint32_t width, uint32_t height)
1995 {
1996     DisplayState *s = con->ds;
1997     DisplayChangeListener *dcl;
1998 
1999     con->scanout.kind = SCANOUT_TEXTURE;
2000     con->scanout.texture = (ScanoutTexture) {
2001         backing_id, backing_y_0_top, backing_width, backing_height,
2002         x, y, width, height
2003     };
2004     QLIST_FOREACH(dcl, &s->listeners, next) {
2005         if (con != (dcl->con ? dcl->con : active_console)) {
2006             continue;
2007         }
2008         if (dcl->ops->dpy_gl_scanout_texture) {
2009             dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
2010                                              backing_y_0_top,
2011                                              backing_width, backing_height,
2012                                              x, y, width, height);
2013         }
2014     }
2015 }
2016 
2017 void dpy_gl_scanout_dmabuf(QemuConsole *con,
2018                            QemuDmaBuf *dmabuf)
2019 {
2020     DisplayState *s = con->ds;
2021     DisplayChangeListener *dcl;
2022 
2023     con->scanout.kind = SCANOUT_DMABUF;
2024     con->scanout.dmabuf = dmabuf;
2025     QLIST_FOREACH(dcl, &s->listeners, next) {
2026         if (con != (dcl->con ? dcl->con : active_console)) {
2027             continue;
2028         }
2029         if (dcl->ops->dpy_gl_scanout_dmabuf) {
2030             dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
2031         }
2032     }
2033 }
2034 
2035 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
2036                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
2037 {
2038     DisplayState *s = con->ds;
2039     DisplayChangeListener *dcl;
2040 
2041     QLIST_FOREACH(dcl, &s->listeners, next) {
2042         if (con != (dcl->con ? dcl->con : active_console)) {
2043             continue;
2044         }
2045         if (dcl->ops->dpy_gl_cursor_dmabuf) {
2046             dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
2047                                            have_hot, hot_x, hot_y);
2048         }
2049     }
2050 }
2051 
2052 void dpy_gl_cursor_position(QemuConsole *con,
2053                             uint32_t pos_x, uint32_t pos_y)
2054 {
2055     DisplayState *s = con->ds;
2056     DisplayChangeListener *dcl;
2057 
2058     QLIST_FOREACH(dcl, &s->listeners, next) {
2059         if (con != (dcl->con ? dcl->con : active_console)) {
2060             continue;
2061         }
2062         if (dcl->ops->dpy_gl_cursor_position) {
2063             dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
2064         }
2065     }
2066 }
2067 
2068 void dpy_gl_release_dmabuf(QemuConsole *con,
2069                           QemuDmaBuf *dmabuf)
2070 {
2071     DisplayState *s = con->ds;
2072     DisplayChangeListener *dcl;
2073 
2074     QLIST_FOREACH(dcl, &s->listeners, next) {
2075         if (con != (dcl->con ? dcl->con : active_console)) {
2076             continue;
2077         }
2078         if (dcl->ops->dpy_gl_release_dmabuf) {
2079             dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
2080         }
2081     }
2082 }
2083 
2084 void dpy_gl_update(QemuConsole *con,
2085                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
2086 {
2087     DisplayState *s = con->ds;
2088     DisplayChangeListener *dcl;
2089 
2090     assert(con->gl);
2091 
2092     graphic_hw_gl_block(con, true);
2093     QLIST_FOREACH(dcl, &s->listeners, next) {
2094         if (con != (dcl->con ? dcl->con : active_console)) {
2095             continue;
2096         }
2097         if (dcl->ops->dpy_gl_update) {
2098             dcl->ops->dpy_gl_update(dcl, x, y, w, h);
2099         }
2100     }
2101     graphic_hw_gl_block(con, false);
2102 }
2103 
2104 /***********************************************************/
2105 /* register display */
2106 
2107 /* console.c internal use only */
2108 static DisplayState *get_alloc_displaystate(void)
2109 {
2110     if (!display_state) {
2111         display_state = g_new0(DisplayState, 1);
2112         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
2113                                     text_console_update_cursor, NULL);
2114     }
2115     return display_state;
2116 }
2117 
2118 /*
2119  * Called by main(), after creating QemuConsoles
2120  * and before initializing ui (sdl/vnc/...).
2121  */
2122 DisplayState *init_displaystate(void)
2123 {
2124     gchar *name;
2125     QemuConsole *con;
2126 
2127     get_alloc_displaystate();
2128     QTAILQ_FOREACH(con, &consoles, next) {
2129         if (con->console_type != GRAPHIC_CONSOLE &&
2130             con->ds == NULL) {
2131             text_console_do_init(con->chr, display_state);
2132         }
2133 
2134         /* Hook up into the qom tree here (not in new_console()), once
2135          * all QemuConsoles are created and the order / numbering
2136          * doesn't change any more */
2137         name = g_strdup_printf("console[%d]", con->index);
2138         object_property_add_child(container_get(object_get_root(), "/backend"),
2139                                   name, OBJECT(con));
2140         g_free(name);
2141     }
2142 
2143     return display_state;
2144 }
2145 
2146 void graphic_console_set_hwops(QemuConsole *con,
2147                                const GraphicHwOps *hw_ops,
2148                                void *opaque)
2149 {
2150     con->hw_ops = hw_ops;
2151     con->hw = opaque;
2152 }
2153 
2154 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
2155                                   const GraphicHwOps *hw_ops,
2156                                   void *opaque)
2157 {
2158     static const char noinit[] =
2159         "Guest has not initialized the display (yet).";
2160     int width = 640;
2161     int height = 480;
2162     QemuConsole *s;
2163     DisplayState *ds;
2164     DisplaySurface *surface;
2165 
2166     ds = get_alloc_displaystate();
2167     s = qemu_console_lookup_unused();
2168     if (s) {
2169         trace_console_gfx_reuse(s->index);
2170         width = qemu_console_get_width(s, 0);
2171         height = qemu_console_get_height(s, 0);
2172     } else {
2173         trace_console_gfx_new();
2174         s = new_console(ds, GRAPHIC_CONSOLE, head);
2175         s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
2176                                    dpy_set_ui_info_timer, s);
2177     }
2178     graphic_console_set_hwops(s, hw_ops, opaque);
2179     if (dev) {
2180         object_property_set_link(OBJECT(s), "device", OBJECT(dev),
2181                                  &error_abort);
2182     }
2183 
2184     surface = qemu_create_placeholder_surface(width, height, noinit);
2185     dpy_gfx_replace_surface(s, surface);
2186     s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
2187                                        graphic_hw_gl_unblock_timer, s);
2188     return s;
2189 }
2190 
2191 static const GraphicHwOps unused_ops = {
2192     /* no callbacks */
2193 };
2194 
2195 void graphic_console_close(QemuConsole *con)
2196 {
2197     static const char unplugged[] =
2198         "Guest display has been unplugged";
2199     DisplaySurface *surface;
2200     int width = qemu_console_get_width(con, 640);
2201     int height = qemu_console_get_height(con, 480);
2202 
2203     trace_console_gfx_close(con->index);
2204     object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
2205     graphic_console_set_hwops(con, &unused_ops, NULL);
2206 
2207     if (con->gl) {
2208         dpy_gl_scanout_disable(con);
2209     }
2210     surface = qemu_create_placeholder_surface(width, height, unplugged);
2211     dpy_gfx_replace_surface(con, surface);
2212 }
2213 
2214 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
2215 {
2216     QemuConsole *con;
2217 
2218     QTAILQ_FOREACH(con, &consoles, next) {
2219         if (con->index == index) {
2220             return con;
2221         }
2222     }
2223     return NULL;
2224 }
2225 
2226 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
2227 {
2228     QemuConsole *con;
2229     Object *obj;
2230     uint32_t h;
2231 
2232     QTAILQ_FOREACH(con, &consoles, next) {
2233         obj = object_property_get_link(OBJECT(con),
2234                                        "device", &error_abort);
2235         if (DEVICE(obj) != dev) {
2236             continue;
2237         }
2238         h = object_property_get_uint(OBJECT(con),
2239                                      "head", &error_abort);
2240         if (h != head) {
2241             continue;
2242         }
2243         return con;
2244     }
2245     return NULL;
2246 }
2247 
2248 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
2249                                                 uint32_t head, Error **errp)
2250 {
2251     DeviceState *dev;
2252     QemuConsole *con;
2253 
2254     dev = qdev_find_recursive(sysbus_get_default(), device_id);
2255     if (dev == NULL) {
2256         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
2257                   "Device '%s' not found", device_id);
2258         return NULL;
2259     }
2260 
2261     con = qemu_console_lookup_by_device(dev, head);
2262     if (con == NULL) {
2263         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
2264                    device_id, head);
2265         return NULL;
2266     }
2267 
2268     return con;
2269 }
2270 
2271 QemuConsole *qemu_console_lookup_unused(void)
2272 {
2273     QemuConsole *con;
2274     Object *obj;
2275 
2276     QTAILQ_FOREACH(con, &consoles, next) {
2277         if (con->hw_ops != &unused_ops) {
2278             continue;
2279         }
2280         obj = object_property_get_link(OBJECT(con),
2281                                        "device", &error_abort);
2282         if (obj != NULL) {
2283             continue;
2284         }
2285         return con;
2286     }
2287     return NULL;
2288 }
2289 
2290 bool qemu_console_is_visible(QemuConsole *con)
2291 {
2292     return (con == active_console) || (con->dcls > 0);
2293 }
2294 
2295 bool qemu_console_is_graphic(QemuConsole *con)
2296 {
2297     if (con == NULL) {
2298         con = active_console;
2299     }
2300     return con && (con->console_type == GRAPHIC_CONSOLE);
2301 }
2302 
2303 bool qemu_console_is_fixedsize(QemuConsole *con)
2304 {
2305     if (con == NULL) {
2306         con = active_console;
2307     }
2308     return con && (con->console_type != TEXT_CONSOLE);
2309 }
2310 
2311 bool qemu_console_is_gl_blocked(QemuConsole *con)
2312 {
2313     assert(con != NULL);
2314     return con->gl_block;
2315 }
2316 
2317 bool qemu_console_is_multihead(DeviceState *dev)
2318 {
2319     QemuConsole *con;
2320     Object *obj;
2321     uint32_t f = 0xffffffff;
2322     uint32_t h;
2323 
2324     QTAILQ_FOREACH(con, &consoles, next) {
2325         obj = object_property_get_link(OBJECT(con),
2326                                        "device", &error_abort);
2327         if (DEVICE(obj) != dev) {
2328             continue;
2329         }
2330 
2331         h = object_property_get_uint(OBJECT(con),
2332                                      "head", &error_abort);
2333         if (f == 0xffffffff) {
2334             f = h;
2335         } else if (h != f) {
2336             return true;
2337         }
2338     }
2339     return false;
2340 }
2341 
2342 char *qemu_console_get_label(QemuConsole *con)
2343 {
2344     if (con->console_type == GRAPHIC_CONSOLE) {
2345         if (con->device) {
2346             DeviceState *dev;
2347             bool multihead;
2348 
2349             dev = DEVICE(con->device);
2350             multihead = qemu_console_is_multihead(dev);
2351             if (multihead) {
2352                 return g_strdup_printf("%s.%d", dev->id ?
2353                                        dev->id :
2354                                        object_get_typename(con->device),
2355                                        con->head);
2356             } else {
2357                 return g_strdup_printf("%s", dev->id ?
2358                                        dev->id :
2359                                        object_get_typename(con->device));
2360             }
2361         }
2362         return g_strdup("VGA");
2363     } else {
2364         if (con->chr && con->chr->label) {
2365             return g_strdup(con->chr->label);
2366         }
2367         return g_strdup_printf("vc%d", con->index);
2368     }
2369 }
2370 
2371 int qemu_console_get_index(QemuConsole *con)
2372 {
2373     if (con == NULL) {
2374         con = active_console;
2375     }
2376     return con ? con->index : -1;
2377 }
2378 
2379 uint32_t qemu_console_get_head(QemuConsole *con)
2380 {
2381     if (con == NULL) {
2382         con = active_console;
2383     }
2384     return con ? con->head : -1;
2385 }
2386 
2387 int qemu_console_get_width(QemuConsole *con, int fallback)
2388 {
2389     if (con == NULL) {
2390         con = active_console;
2391     }
2392     if (con == NULL) {
2393         return fallback;
2394     }
2395     switch (con->scanout.kind) {
2396     case SCANOUT_DMABUF:
2397         return con->scanout.dmabuf->width;
2398     case SCANOUT_TEXTURE:
2399         return con->scanout.texture.width;
2400     case SCANOUT_SURFACE:
2401         return surface_width(con->surface);
2402     default:
2403         return fallback;
2404     }
2405 }
2406 
2407 int qemu_console_get_height(QemuConsole *con, int fallback)
2408 {
2409     if (con == NULL) {
2410         con = active_console;
2411     }
2412     if (con == NULL) {
2413         return fallback;
2414     }
2415     switch (con->scanout.kind) {
2416     case SCANOUT_DMABUF:
2417         return con->scanout.dmabuf->height;
2418     case SCANOUT_TEXTURE:
2419         return con->scanout.texture.height;
2420     case SCANOUT_SURFACE:
2421         return surface_height(con->surface);
2422     default:
2423         return fallback;
2424     }
2425 }
2426 
2427 static void vc_chr_accept_input(Chardev *chr)
2428 {
2429     VCChardev *drv = VC_CHARDEV(chr);
2430     QemuConsole *s = drv->console;
2431 
2432     kbd_send_chars(s);
2433 }
2434 
2435 static void vc_chr_set_echo(Chardev *chr, bool echo)
2436 {
2437     VCChardev *drv = VC_CHARDEV(chr);
2438     QemuConsole *s = drv->console;
2439 
2440     s->echo = echo;
2441 }
2442 
2443 static void text_console_update_cursor_timer(void)
2444 {
2445     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
2446               + CONSOLE_CURSOR_PERIOD / 2);
2447 }
2448 
2449 static void text_console_update_cursor(void *opaque)
2450 {
2451     QemuConsole *s;
2452     int count = 0;
2453 
2454     cursor_visible_phase = !cursor_visible_phase;
2455 
2456     QTAILQ_FOREACH(s, &consoles, next) {
2457         if (qemu_console_is_graphic(s) ||
2458             !qemu_console_is_visible(s)) {
2459             continue;
2460         }
2461         count++;
2462         graphic_hw_invalidate(s);
2463     }
2464 
2465     if (count) {
2466         text_console_update_cursor_timer();
2467     }
2468 }
2469 
2470 static const GraphicHwOps text_console_ops = {
2471     .invalidate  = text_console_invalidate,
2472     .text_update = text_console_update,
2473 };
2474 
2475 static void text_console_do_init(Chardev *chr, DisplayState *ds)
2476 {
2477     VCChardev *drv = VC_CHARDEV(chr);
2478     QemuConsole *s = drv->console;
2479     int g_width = 80 * FONT_WIDTH;
2480     int g_height = 24 * FONT_HEIGHT;
2481 
2482     fifo8_create(&s->out_fifo, 16);
2483     s->ds = ds;
2484 
2485     s->y_displayed = 0;
2486     s->y_base = 0;
2487     s->total_height = DEFAULT_BACKSCROLL;
2488     s->x = 0;
2489     s->y = 0;
2490     if (s->scanout.kind != SCANOUT_SURFACE) {
2491         if (active_console && active_console->scanout.kind == SCANOUT_SURFACE) {
2492             g_width = qemu_console_get_width(active_console, g_width);
2493             g_height = qemu_console_get_height(active_console, g_height);
2494         }
2495         s->surface = qemu_create_displaysurface(g_width, g_height);
2496         s->scanout.kind = SCANOUT_SURFACE;
2497     }
2498 
2499     s->hw_ops = &text_console_ops;
2500     s->hw = s;
2501 
2502     /* Set text attribute defaults */
2503     s->t_attrib_default.bold = 0;
2504     s->t_attrib_default.uline = 0;
2505     s->t_attrib_default.blink = 0;
2506     s->t_attrib_default.invers = 0;
2507     s->t_attrib_default.unvisible = 0;
2508     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2509     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2510     /* set current text attributes to default */
2511     s->t_attrib = s->t_attrib_default;
2512     text_console_resize(s);
2513 
2514     if (chr->label) {
2515         char *msg;
2516 
2517         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2518         msg = g_strdup_printf("%s console\r\n", chr->label);
2519         vc_chr_write(chr, (uint8_t *)msg, strlen(msg));
2520         g_free(msg);
2521         s->t_attrib = s->t_attrib_default;
2522     }
2523 
2524     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
2525 }
2526 
2527 static void vc_chr_open(Chardev *chr,
2528                         ChardevBackend *backend,
2529                         bool *be_opened,
2530                         Error **errp)
2531 {
2532     ChardevVC *vc = backend->u.vc.data;
2533     VCChardev *drv = VC_CHARDEV(chr);
2534     QemuConsole *s;
2535     unsigned width = 0;
2536     unsigned height = 0;
2537 
2538     if (vc->has_width) {
2539         width = vc->width;
2540     } else if (vc->has_cols) {
2541         width = vc->cols * FONT_WIDTH;
2542     }
2543 
2544     if (vc->has_height) {
2545         height = vc->height;
2546     } else if (vc->has_rows) {
2547         height = vc->rows * FONT_HEIGHT;
2548     }
2549 
2550     trace_console_txt_new(width, height);
2551     if (width == 0 || height == 0) {
2552         s = new_console(NULL, TEXT_CONSOLE, 0);
2553     } else {
2554         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2555         s->scanout.kind = SCANOUT_SURFACE;
2556         s->surface = qemu_create_displaysurface(width, height);
2557     }
2558 
2559     if (!s) {
2560         error_setg(errp, "cannot create text console");
2561         return;
2562     }
2563 
2564     s->chr = chr;
2565     drv->console = s;
2566 
2567     if (display_state) {
2568         text_console_do_init(chr, display_state);
2569     }
2570 
2571     /* console/chardev init sometimes completes elsewhere in a 2nd
2572      * stage, so defer OPENED events until they are fully initialized
2573      */
2574     *be_opened = false;
2575 }
2576 
2577 void qemu_console_resize(QemuConsole *s, int width, int height)
2578 {
2579     DisplaySurface *surface = qemu_console_surface(s);
2580 
2581     assert(s->console_type == GRAPHIC_CONSOLE);
2582 
2583     if ((s->scanout.kind != SCANOUT_SURFACE ||
2584          (surface && surface->flags & QEMU_ALLOCATED_FLAG)) &&
2585         qemu_console_get_width(s, -1) == width &&
2586         qemu_console_get_height(s, -1) == height) {
2587         return;
2588     }
2589 
2590     surface = qemu_create_displaysurface(width, height);
2591     dpy_gfx_replace_surface(s, surface);
2592 }
2593 
2594 DisplaySurface *qemu_console_surface(QemuConsole *console)
2595 {
2596     switch (console->scanout.kind) {
2597     case SCANOUT_SURFACE:
2598         return console->surface;
2599     default:
2600         return NULL;
2601     }
2602 }
2603 
2604 PixelFormat qemu_default_pixelformat(int bpp)
2605 {
2606     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2607     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2608     return pf;
2609 }
2610 
2611 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
2612 
2613 void qemu_display_register(QemuDisplay *ui)
2614 {
2615     assert(ui->type < DISPLAY_TYPE__MAX);
2616     dpys[ui->type] = ui;
2617 }
2618 
2619 bool qemu_display_find_default(DisplayOptions *opts)
2620 {
2621     static DisplayType prio[] = {
2622 #if defined(CONFIG_GTK)
2623         DISPLAY_TYPE_GTK,
2624 #endif
2625 #if defined(CONFIG_SDL)
2626         DISPLAY_TYPE_SDL,
2627 #endif
2628 #if defined(CONFIG_COCOA)
2629         DISPLAY_TYPE_COCOA
2630 #endif
2631     };
2632     int i;
2633 
2634     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
2635         if (dpys[prio[i]] == NULL) {
2636             Error *local_err = NULL;
2637             int rv = ui_module_load(DisplayType_str(prio[i]), &local_err);
2638             if (rv < 0) {
2639                 error_report_err(local_err);
2640             }
2641         }
2642         if (dpys[prio[i]] == NULL) {
2643             continue;
2644         }
2645         opts->type = prio[i];
2646         return true;
2647     }
2648     return false;
2649 }
2650 
2651 void qemu_display_early_init(DisplayOptions *opts)
2652 {
2653     assert(opts->type < DISPLAY_TYPE__MAX);
2654     if (opts->type == DISPLAY_TYPE_NONE) {
2655         return;
2656     }
2657     if (dpys[opts->type] == NULL) {
2658         Error *local_err = NULL;
2659         int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
2660         if (rv < 0) {
2661             error_report_err(local_err);
2662         }
2663     }
2664     if (dpys[opts->type] == NULL) {
2665         error_report("Display '%s' is not available.",
2666                      DisplayType_str(opts->type));
2667         exit(1);
2668     }
2669     if (dpys[opts->type]->early_init) {
2670         dpys[opts->type]->early_init(opts);
2671     }
2672 }
2673 
2674 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
2675 {
2676     assert(opts->type < DISPLAY_TYPE__MAX);
2677     if (opts->type == DISPLAY_TYPE_NONE) {
2678         return;
2679     }
2680     assert(dpys[opts->type] != NULL);
2681     dpys[opts->type]->init(ds, opts);
2682 }
2683 
2684 void qemu_display_help(void)
2685 {
2686     int idx;
2687 
2688     printf("Available display backend types:\n");
2689     printf("none\n");
2690     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
2691         if (!dpys[idx]) {
2692             Error *local_err = NULL;
2693             int rv = ui_module_load(DisplayType_str(idx), &local_err);
2694             if (rv < 0) {
2695                 error_report_err(local_err);
2696             }
2697         }
2698         if (dpys[idx]) {
2699             printf("%s\n",  DisplayType_str(dpys[idx]->type));
2700         }
2701     }
2702 }
2703 
2704 void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
2705 {
2706     int val;
2707     ChardevVC *vc;
2708 
2709     backend->type = CHARDEV_BACKEND_KIND_VC;
2710     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2711     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2712 
2713     val = qemu_opt_get_number(opts, "width", 0);
2714     if (val != 0) {
2715         vc->has_width = true;
2716         vc->width = val;
2717     }
2718 
2719     val = qemu_opt_get_number(opts, "height", 0);
2720     if (val != 0) {
2721         vc->has_height = true;
2722         vc->height = val;
2723     }
2724 
2725     val = qemu_opt_get_number(opts, "cols", 0);
2726     if (val != 0) {
2727         vc->has_cols = true;
2728         vc->cols = val;
2729     }
2730 
2731     val = qemu_opt_get_number(opts, "rows", 0);
2732     if (val != 0) {
2733         vc->has_rows = true;
2734         vc->rows = val;
2735     }
2736 }
2737 
2738 static const TypeInfo qemu_console_info = {
2739     .name = TYPE_QEMU_CONSOLE,
2740     .parent = TYPE_OBJECT,
2741     .instance_size = sizeof(QemuConsole),
2742     .class_size = sizeof(QemuConsoleClass),
2743 };
2744 
2745 static void char_vc_class_init(ObjectClass *oc, void *data)
2746 {
2747     ChardevClass *cc = CHARDEV_CLASS(oc);
2748 
2749     cc->parse = qemu_chr_parse_vc;
2750     cc->open = vc_chr_open;
2751     cc->chr_write = vc_chr_write;
2752     cc->chr_accept_input = vc_chr_accept_input;
2753     cc->chr_set_echo = vc_chr_set_echo;
2754 }
2755 
2756 static const TypeInfo char_vc_type_info = {
2757     .name = TYPE_CHARDEV_VC,
2758     .parent = TYPE_CHARDEV,
2759     .instance_size = sizeof(VCChardev),
2760     .class_init = char_vc_class_init,
2761 };
2762 
2763 void qemu_console_early_init(void)
2764 {
2765     /* set the default vc driver */
2766     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
2767         type_register(&char_vc_type_info);
2768     }
2769 }
2770 
2771 static void register_types(void)
2772 {
2773     type_register_static(&qemu_console_info);
2774 }
2775 
2776 type_init(register_types);
2777