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