xref: /openbmc/qemu/ui/console.c (revision a9a5c473)
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     object_property_add_uint32_ptr(obj, "head", &s->head,
1302                                    OBJ_PROP_FLAG_READ);
1303 
1304     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1305         (console_type == GRAPHIC_CONSOLE))) {
1306         active_console = s;
1307     }
1308     s->ds = ds;
1309     s->console_type = console_type;
1310 
1311     if (QTAILQ_EMPTY(&consoles)) {
1312         s->index = 0;
1313         QTAILQ_INSERT_TAIL(&consoles, s, next);
1314     } else if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) {
1315         QemuConsole *last = QTAILQ_LAST(&consoles);
1316         s->index = last->index + 1;
1317         QTAILQ_INSERT_TAIL(&consoles, s, next);
1318     } else {
1319         /*
1320          * HACK: Put graphical consoles before text consoles.
1321          *
1322          * Only do that for coldplugged devices.  After initial device
1323          * initialization we will not renumber the consoles any more.
1324          */
1325         QemuConsole *c = QTAILQ_FIRST(&consoles);
1326 
1327         while (QTAILQ_NEXT(c, next) != NULL &&
1328                c->console_type == GRAPHIC_CONSOLE) {
1329             c = QTAILQ_NEXT(c, next);
1330         }
1331         if (c->console_type == GRAPHIC_CONSOLE) {
1332             /* have no text consoles */
1333             s->index = c->index + 1;
1334             QTAILQ_INSERT_AFTER(&consoles, c, s, next);
1335         } else {
1336             s->index = c->index;
1337             QTAILQ_INSERT_BEFORE(c, s, next);
1338             /* renumber text consoles */
1339             for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
1340                 c->index = i;
1341             }
1342         }
1343     }
1344     return s;
1345 }
1346 
1347 static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
1348 {
1349     qemu_pixman_image_unref(surface->image);
1350     surface->image = NULL;
1351 
1352     surface->format = PIXMAN_x8r8g8b8;
1353     surface->image = pixman_image_create_bits(surface->format,
1354                                               width, height,
1355                                               NULL, width * 4);
1356     assert(surface->image != NULL);
1357 
1358     surface->flags = QEMU_ALLOCATED_FLAG;
1359 }
1360 
1361 DisplaySurface *qemu_create_displaysurface(int width, int height)
1362 {
1363     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1364 
1365     trace_displaysurface_create(surface, width, height);
1366     qemu_alloc_display(surface, width, height);
1367     return surface;
1368 }
1369 
1370 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
1371                                                 pixman_format_code_t format,
1372                                                 int linesize, uint8_t *data)
1373 {
1374     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1375 
1376     trace_displaysurface_create_from(surface, width, height, format);
1377     surface->format = format;
1378     surface->image = pixman_image_create_bits(surface->format,
1379                                               width, height,
1380                                               (void *)data, linesize);
1381     assert(surface->image != NULL);
1382 
1383     return surface;
1384 }
1385 
1386 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
1387 {
1388     DisplaySurface *surface = g_new0(DisplaySurface, 1);
1389 
1390     trace_displaysurface_create_pixman(surface);
1391     surface->format = pixman_image_get_format(image);
1392     surface->image = pixman_image_ref(image);
1393 
1394     return surface;
1395 }
1396 
1397 DisplaySurface *qemu_create_message_surface(int w, int h,
1398                                             const char *msg)
1399 {
1400     DisplaySurface *surface = qemu_create_displaysurface(w, h);
1401     pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
1402     pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
1403     pixman_image_t *glyph;
1404     int len, x, y, i;
1405 
1406     len = strlen(msg);
1407     x = (w / FONT_WIDTH  - len) / 2;
1408     y = (h / FONT_HEIGHT - 1)   / 2;
1409     for (i = 0; i < len; i++) {
1410         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
1411         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
1412                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
1413         qemu_pixman_image_unref(glyph);
1414     }
1415     return surface;
1416 }
1417 
1418 void qemu_free_displaysurface(DisplaySurface *surface)
1419 {
1420     if (surface == NULL) {
1421         return;
1422     }
1423     trace_displaysurface_free(surface);
1424     qemu_pixman_image_unref(surface->image);
1425     g_free(surface);
1426 }
1427 
1428 bool console_has_gl(QemuConsole *con)
1429 {
1430     return con->gl != NULL;
1431 }
1432 
1433 bool console_has_gl_dmabuf(QemuConsole *con)
1434 {
1435     return con->gl != NULL && con->gl->ops->dpy_gl_scanout_dmabuf != NULL;
1436 }
1437 
1438 void register_displaychangelistener(DisplayChangeListener *dcl)
1439 {
1440     static const char nodev[] =
1441         "This VM has no graphic display device.";
1442     static DisplaySurface *dummy;
1443     QemuConsole *con;
1444 
1445     assert(!dcl->ds);
1446 
1447     if (dcl->ops->dpy_gl_ctx_create) {
1448         /* display has opengl support */
1449         assert(dcl->con);
1450         if (dcl->con->gl) {
1451             fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
1452                     dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
1453             exit(1);
1454         }
1455         dcl->con->gl = dcl;
1456     }
1457 
1458     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1459     dcl->ds = get_alloc_displaystate();
1460     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
1461     gui_setup_refresh(dcl->ds);
1462     if (dcl->con) {
1463         dcl->con->dcls++;
1464         con = dcl->con;
1465     } else {
1466         con = active_console;
1467     }
1468     if (dcl->ops->dpy_gfx_switch) {
1469         if (con) {
1470             dcl->ops->dpy_gfx_switch(dcl, con->surface);
1471         } else {
1472             if (!dummy) {
1473                 dummy = qemu_create_message_surface(640, 480, nodev);
1474             }
1475             dcl->ops->dpy_gfx_switch(dcl, dummy);
1476         }
1477     }
1478     text_console_update_cursor(NULL);
1479 }
1480 
1481 void update_displaychangelistener(DisplayChangeListener *dcl,
1482                                   uint64_t interval)
1483 {
1484     DisplayState *ds = dcl->ds;
1485 
1486     dcl->update_interval = interval;
1487     if (!ds->refreshing && ds->update_interval > interval) {
1488         timer_mod(ds->gui_timer, ds->last_update + interval);
1489     }
1490 }
1491 
1492 void unregister_displaychangelistener(DisplayChangeListener *dcl)
1493 {
1494     DisplayState *ds = dcl->ds;
1495     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1496     if (dcl->con) {
1497         dcl->con->dcls--;
1498     }
1499     QLIST_REMOVE(dcl, next);
1500     dcl->ds = NULL;
1501     gui_setup_refresh(ds);
1502 }
1503 
1504 static void dpy_set_ui_info_timer(void *opaque)
1505 {
1506     QemuConsole *con = opaque;
1507 
1508     con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
1509 }
1510 
1511 bool dpy_ui_info_supported(QemuConsole *con)
1512 {
1513     return con->hw_ops->ui_info != NULL;
1514 }
1515 
1516 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
1517 {
1518     assert(con != NULL);
1519 
1520     if (!dpy_ui_info_supported(con)) {
1521         return -1;
1522     }
1523     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
1524         /* nothing changed -- ignore */
1525         return 0;
1526     }
1527 
1528     /*
1529      * Typically we get a flood of these as the user resizes the window.
1530      * Wait until the dust has settled (one second without updates), then
1531      * go notify the guest.
1532      */
1533     con->ui_info = *info;
1534     timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
1535     return 0;
1536 }
1537 
1538 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1539 {
1540     DisplayState *s = con->ds;
1541     DisplayChangeListener *dcl;
1542     int width = w;
1543     int height = h;
1544 
1545     if (con->surface) {
1546         width = surface_width(con->surface);
1547         height = surface_height(con->surface);
1548     }
1549     x = MAX(x, 0);
1550     y = MAX(y, 0);
1551     x = MIN(x, width);
1552     y = MIN(y, height);
1553     w = MIN(w, width - x);
1554     h = MIN(h, height - y);
1555 
1556     if (!qemu_console_is_visible(con)) {
1557         return;
1558     }
1559     QLIST_FOREACH(dcl, &s->listeners, next) {
1560         if (con != (dcl->con ? dcl->con : active_console)) {
1561             continue;
1562         }
1563         if (dcl->ops->dpy_gfx_update) {
1564             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1565         }
1566     }
1567 }
1568 
1569 void dpy_gfx_update_full(QemuConsole *con)
1570 {
1571     if (!con->surface) {
1572         return;
1573     }
1574     dpy_gfx_update(con, 0, 0,
1575                    surface_width(con->surface),
1576                    surface_height(con->surface));
1577 }
1578 
1579 void dpy_gfx_replace_surface(QemuConsole *con,
1580                              DisplaySurface *surface)
1581 {
1582     DisplayState *s = con->ds;
1583     DisplaySurface *old_surface = con->surface;
1584     DisplayChangeListener *dcl;
1585 
1586     assert(old_surface != surface || surface == NULL);
1587 
1588     con->surface = surface;
1589     QLIST_FOREACH(dcl, &s->listeners, next) {
1590         if (con != (dcl->con ? dcl->con : active_console)) {
1591             continue;
1592         }
1593         if (dcl->ops->dpy_gfx_switch) {
1594             dcl->ops->dpy_gfx_switch(dcl, surface);
1595         }
1596     }
1597     qemu_free_displaysurface(old_surface);
1598 }
1599 
1600 bool dpy_gfx_check_format(QemuConsole *con,
1601                           pixman_format_code_t format)
1602 {
1603     DisplayChangeListener *dcl;
1604     DisplayState *s = con->ds;
1605 
1606     QLIST_FOREACH(dcl, &s->listeners, next) {
1607         if (dcl->con && dcl->con != con) {
1608             /* dcl bound to another console -> skip */
1609             continue;
1610         }
1611         if (dcl->ops->dpy_gfx_check_format) {
1612             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
1613                 return false;
1614             }
1615         } else {
1616             /* default is to whitelist native 32 bpp only */
1617             if (format != qemu_default_pixman_format(32, true)) {
1618                 return false;
1619             }
1620         }
1621     }
1622     return true;
1623 }
1624 
1625 static void dpy_refresh(DisplayState *s)
1626 {
1627     DisplayChangeListener *dcl;
1628 
1629     QLIST_FOREACH(dcl, &s->listeners, next) {
1630         if (dcl->ops->dpy_refresh) {
1631             dcl->ops->dpy_refresh(dcl);
1632         }
1633     }
1634 }
1635 
1636 void dpy_text_cursor(QemuConsole *con, int x, int y)
1637 {
1638     DisplayState *s = con->ds;
1639     DisplayChangeListener *dcl;
1640 
1641     if (!qemu_console_is_visible(con)) {
1642         return;
1643     }
1644     QLIST_FOREACH(dcl, &s->listeners, next) {
1645         if (con != (dcl->con ? dcl->con : active_console)) {
1646             continue;
1647         }
1648         if (dcl->ops->dpy_text_cursor) {
1649             dcl->ops->dpy_text_cursor(dcl, x, y);
1650         }
1651     }
1652 }
1653 
1654 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1655 {
1656     DisplayState *s = con->ds;
1657     DisplayChangeListener *dcl;
1658 
1659     if (!qemu_console_is_visible(con)) {
1660         return;
1661     }
1662     QLIST_FOREACH(dcl, &s->listeners, next) {
1663         if (con != (dcl->con ? dcl->con : active_console)) {
1664             continue;
1665         }
1666         if (dcl->ops->dpy_text_update) {
1667             dcl->ops->dpy_text_update(dcl, x, y, w, h);
1668         }
1669     }
1670 }
1671 
1672 void dpy_text_resize(QemuConsole *con, int w, int h)
1673 {
1674     DisplayState *s = con->ds;
1675     DisplayChangeListener *dcl;
1676 
1677     if (!qemu_console_is_visible(con)) {
1678         return;
1679     }
1680     QLIST_FOREACH(dcl, &s->listeners, next) {
1681         if (con != (dcl->con ? dcl->con : active_console)) {
1682             continue;
1683         }
1684         if (dcl->ops->dpy_text_resize) {
1685             dcl->ops->dpy_text_resize(dcl, w, h);
1686         }
1687     }
1688 }
1689 
1690 void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1691 {
1692     DisplayState *s = con->ds;
1693     DisplayChangeListener *dcl;
1694 
1695     if (!qemu_console_is_visible(con)) {
1696         return;
1697     }
1698     QLIST_FOREACH(dcl, &s->listeners, next) {
1699         if (con != (dcl->con ? dcl->con : active_console)) {
1700             continue;
1701         }
1702         if (dcl->ops->dpy_mouse_set) {
1703             dcl->ops->dpy_mouse_set(dcl, x, y, on);
1704         }
1705     }
1706 }
1707 
1708 void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1709 {
1710     DisplayState *s = con->ds;
1711     DisplayChangeListener *dcl;
1712 
1713     if (!qemu_console_is_visible(con)) {
1714         return;
1715     }
1716     QLIST_FOREACH(dcl, &s->listeners, next) {
1717         if (con != (dcl->con ? dcl->con : active_console)) {
1718             continue;
1719         }
1720         if (dcl->ops->dpy_cursor_define) {
1721             dcl->ops->dpy_cursor_define(dcl, cursor);
1722         }
1723     }
1724 }
1725 
1726 bool dpy_cursor_define_supported(QemuConsole *con)
1727 {
1728     DisplayState *s = con->ds;
1729     DisplayChangeListener *dcl;
1730 
1731     QLIST_FOREACH(dcl, &s->listeners, next) {
1732         if (dcl->ops->dpy_cursor_define) {
1733             return true;
1734         }
1735     }
1736     return false;
1737 }
1738 
1739 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1740                                 struct QEMUGLParams *qparams)
1741 {
1742     assert(con->gl);
1743     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1744 }
1745 
1746 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1747 {
1748     assert(con->gl);
1749     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1750 }
1751 
1752 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1753 {
1754     assert(con->gl);
1755     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1756 }
1757 
1758 QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
1759 {
1760     assert(con->gl);
1761     return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
1762 }
1763 
1764 void dpy_gl_scanout_disable(QemuConsole *con)
1765 {
1766     assert(con->gl);
1767     if (con->gl->ops->dpy_gl_scanout_disable) {
1768         con->gl->ops->dpy_gl_scanout_disable(con->gl);
1769     } else {
1770         con->gl->ops->dpy_gl_scanout_texture(con->gl, 0, false, 0, 0,
1771                                              0, 0, 0, 0);
1772     }
1773 }
1774 
1775 void dpy_gl_scanout_texture(QemuConsole *con,
1776                             uint32_t backing_id,
1777                             bool backing_y_0_top,
1778                             uint32_t backing_width,
1779                             uint32_t backing_height,
1780                             uint32_t x, uint32_t y,
1781                             uint32_t width, uint32_t height)
1782 {
1783     assert(con->gl);
1784     con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
1785                                          backing_y_0_top,
1786                                          backing_width, backing_height,
1787                                          x, y, width, height);
1788 }
1789 
1790 void dpy_gl_scanout_dmabuf(QemuConsole *con,
1791                            QemuDmaBuf *dmabuf)
1792 {
1793     assert(con->gl);
1794     con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
1795 }
1796 
1797 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
1798                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
1799 {
1800     assert(con->gl);
1801 
1802     if (con->gl->ops->dpy_gl_cursor_dmabuf) {
1803         con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
1804                                            have_hot, hot_x, hot_y);
1805     }
1806 }
1807 
1808 void dpy_gl_cursor_position(QemuConsole *con,
1809                             uint32_t pos_x, uint32_t pos_y)
1810 {
1811     assert(con->gl);
1812 
1813     if (con->gl->ops->dpy_gl_cursor_position) {
1814         con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
1815     }
1816 }
1817 
1818 void dpy_gl_release_dmabuf(QemuConsole *con,
1819                           QemuDmaBuf *dmabuf)
1820 {
1821     assert(con->gl);
1822 
1823     if (con->gl->ops->dpy_gl_release_dmabuf) {
1824         con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
1825     }
1826 }
1827 
1828 void dpy_gl_update(QemuConsole *con,
1829                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1830 {
1831     assert(con->gl);
1832     con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
1833 }
1834 
1835 /***********************************************************/
1836 /* register display */
1837 
1838 /* console.c internal use only */
1839 static DisplayState *get_alloc_displaystate(void)
1840 {
1841     if (!display_state) {
1842         display_state = g_new0(DisplayState, 1);
1843         cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1844                                     text_console_update_cursor, NULL);
1845     }
1846     return display_state;
1847 }
1848 
1849 /*
1850  * Called by main(), after creating QemuConsoles
1851  * and before initializing ui (sdl/vnc/...).
1852  */
1853 DisplayState *init_displaystate(void)
1854 {
1855     gchar *name;
1856     QemuConsole *con;
1857 
1858     get_alloc_displaystate();
1859     QTAILQ_FOREACH(con, &consoles, next) {
1860         if (con->console_type != GRAPHIC_CONSOLE &&
1861             con->ds == NULL) {
1862             text_console_do_init(con->chr, display_state);
1863         }
1864 
1865         /* Hook up into the qom tree here (not in new_console()), once
1866          * all QemuConsoles are created and the order / numbering
1867          * doesn't change any more */
1868         name = g_strdup_printf("console[%d]", con->index);
1869         object_property_add_child(container_get(object_get_root(), "/backend"),
1870                                   name, OBJECT(con));
1871         g_free(name);
1872     }
1873 
1874     return display_state;
1875 }
1876 
1877 void graphic_console_set_hwops(QemuConsole *con,
1878                                const GraphicHwOps *hw_ops,
1879                                void *opaque)
1880 {
1881     con->hw_ops = hw_ops;
1882     con->hw = opaque;
1883 }
1884 
1885 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1886                                   const GraphicHwOps *hw_ops,
1887                                   void *opaque)
1888 {
1889     static const char noinit[] =
1890         "Guest has not initialized the display (yet).";
1891     int width = 640;
1892     int height = 480;
1893     QemuConsole *s;
1894     DisplayState *ds;
1895     DisplaySurface *surface;
1896 
1897     ds = get_alloc_displaystate();
1898     s = qemu_console_lookup_unused();
1899     if (s) {
1900         trace_console_gfx_reuse(s->index);
1901         if (s->surface) {
1902             width = surface_width(s->surface);
1903             height = surface_height(s->surface);
1904         }
1905     } else {
1906         trace_console_gfx_new();
1907         s = new_console(ds, GRAPHIC_CONSOLE, head);
1908         s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1909                                    dpy_set_ui_info_timer, s);
1910     }
1911     graphic_console_set_hwops(s, hw_ops, opaque);
1912     if (dev) {
1913         object_property_set_link(OBJECT(s), OBJECT(dev), "device",
1914                                  &error_abort);
1915     }
1916 
1917     surface = qemu_create_message_surface(width, height, noinit);
1918     dpy_gfx_replace_surface(s, surface);
1919     return s;
1920 }
1921 
1922 static const GraphicHwOps unused_ops = {
1923     /* no callbacks */
1924 };
1925 
1926 void graphic_console_close(QemuConsole *con)
1927 {
1928     static const char unplugged[] =
1929         "Guest display has been unplugged";
1930     DisplaySurface *surface;
1931     int width = 640;
1932     int height = 480;
1933 
1934     if (con->surface) {
1935         width = surface_width(con->surface);
1936         height = surface_height(con->surface);
1937     }
1938 
1939     trace_console_gfx_close(con->index);
1940     object_property_set_link(OBJECT(con), NULL, "device", &error_abort);
1941     graphic_console_set_hwops(con, &unused_ops, NULL);
1942 
1943     if (con->gl) {
1944         dpy_gl_scanout_disable(con);
1945     }
1946     surface = qemu_create_message_surface(width, height, unplugged);
1947     dpy_gfx_replace_surface(con, surface);
1948 }
1949 
1950 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1951 {
1952     QemuConsole *con;
1953 
1954     QTAILQ_FOREACH(con, &consoles, next) {
1955         if (con->index == index) {
1956             return con;
1957         }
1958     }
1959     return NULL;
1960 }
1961 
1962 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1963 {
1964     QemuConsole *con;
1965     Object *obj;
1966     uint32_t h;
1967 
1968     QTAILQ_FOREACH(con, &consoles, next) {
1969         obj = object_property_get_link(OBJECT(con),
1970                                        "device", &error_abort);
1971         if (DEVICE(obj) != dev) {
1972             continue;
1973         }
1974         h = object_property_get_uint(OBJECT(con),
1975                                      "head", &error_abort);
1976         if (h != head) {
1977             continue;
1978         }
1979         return con;
1980     }
1981     return NULL;
1982 }
1983 
1984 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
1985                                                 uint32_t head, Error **errp)
1986 {
1987     DeviceState *dev;
1988     QemuConsole *con;
1989 
1990     dev = qdev_find_recursive(sysbus_get_default(), device_id);
1991     if (dev == NULL) {
1992         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
1993                   "Device '%s' not found", device_id);
1994         return NULL;
1995     }
1996 
1997     con = qemu_console_lookup_by_device(dev, head);
1998     if (con == NULL) {
1999         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
2000                    device_id, head);
2001         return NULL;
2002     }
2003 
2004     return con;
2005 }
2006 
2007 QemuConsole *qemu_console_lookup_unused(void)
2008 {
2009     QemuConsole *con;
2010     Object *obj;
2011 
2012     QTAILQ_FOREACH(con, &consoles, next) {
2013         if (con->hw_ops != &unused_ops) {
2014             continue;
2015         }
2016         obj = object_property_get_link(OBJECT(con),
2017                                        "device", &error_abort);
2018         if (obj != NULL) {
2019             continue;
2020         }
2021         return con;
2022     }
2023     return NULL;
2024 }
2025 
2026 bool qemu_console_is_visible(QemuConsole *con)
2027 {
2028     return (con == active_console) || (con->dcls > 0);
2029 }
2030 
2031 bool qemu_console_is_graphic(QemuConsole *con)
2032 {
2033     if (con == NULL) {
2034         con = active_console;
2035     }
2036     return con && (con->console_type == GRAPHIC_CONSOLE);
2037 }
2038 
2039 bool qemu_console_is_fixedsize(QemuConsole *con)
2040 {
2041     if (con == NULL) {
2042         con = active_console;
2043     }
2044     return con && (con->console_type != TEXT_CONSOLE);
2045 }
2046 
2047 bool qemu_console_is_gl_blocked(QemuConsole *con)
2048 {
2049     assert(con != NULL);
2050     return con->gl_block;
2051 }
2052 
2053 char *qemu_console_get_label(QemuConsole *con)
2054 {
2055     if (con->console_type == GRAPHIC_CONSOLE) {
2056         if (con->device) {
2057             return g_strdup(object_get_typename(con->device));
2058         }
2059         return g_strdup("VGA");
2060     } else {
2061         if (con->chr && con->chr->label) {
2062             return g_strdup(con->chr->label);
2063         }
2064         return g_strdup_printf("vc%d", con->index);
2065     }
2066 }
2067 
2068 int qemu_console_get_index(QemuConsole *con)
2069 {
2070     if (con == NULL) {
2071         con = active_console;
2072     }
2073     return con ? con->index : -1;
2074 }
2075 
2076 uint32_t qemu_console_get_head(QemuConsole *con)
2077 {
2078     if (con == NULL) {
2079         con = active_console;
2080     }
2081     return con ? con->head : -1;
2082 }
2083 
2084 QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
2085 {
2086     assert(con != NULL);
2087     return &con->ui_info;
2088 }
2089 
2090 int qemu_console_get_width(QemuConsole *con, int fallback)
2091 {
2092     if (con == NULL) {
2093         con = active_console;
2094     }
2095     return con ? surface_width(con->surface) : fallback;
2096 }
2097 
2098 int qemu_console_get_height(QemuConsole *con, int fallback)
2099 {
2100     if (con == NULL) {
2101         con = active_console;
2102     }
2103     return con ? surface_height(con->surface) : fallback;
2104 }
2105 
2106 static void vc_chr_set_echo(Chardev *chr, bool echo)
2107 {
2108     VCChardev *drv = VC_CHARDEV(chr);
2109     QemuConsole *s = drv->console;
2110 
2111     s->echo = echo;
2112 }
2113 
2114 static void text_console_update_cursor_timer(void)
2115 {
2116     timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
2117               + CONSOLE_CURSOR_PERIOD / 2);
2118 }
2119 
2120 static void text_console_update_cursor(void *opaque)
2121 {
2122     QemuConsole *s;
2123     int count = 0;
2124 
2125     cursor_visible_phase = !cursor_visible_phase;
2126 
2127     QTAILQ_FOREACH(s, &consoles, next) {
2128         if (qemu_console_is_graphic(s) ||
2129             !qemu_console_is_visible(s)) {
2130             continue;
2131         }
2132         count++;
2133         graphic_hw_invalidate(s);
2134     }
2135 
2136     if (count) {
2137         text_console_update_cursor_timer();
2138     }
2139 }
2140 
2141 static const GraphicHwOps text_console_ops = {
2142     .invalidate  = text_console_invalidate,
2143     .text_update = text_console_update,
2144 };
2145 
2146 static void text_console_do_init(Chardev *chr, DisplayState *ds)
2147 {
2148     VCChardev *drv = VC_CHARDEV(chr);
2149     QemuConsole *s = drv->console;
2150     int g_width = 80 * FONT_WIDTH;
2151     int g_height = 24 * FONT_HEIGHT;
2152 
2153     s->out_fifo.buf = s->out_fifo_buf;
2154     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
2155     s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
2156     s->ds = ds;
2157 
2158     s->y_displayed = 0;
2159     s->y_base = 0;
2160     s->total_height = DEFAULT_BACKSCROLL;
2161     s->x = 0;
2162     s->y = 0;
2163     if (!s->surface) {
2164         if (active_console && active_console->surface) {
2165             g_width = surface_width(active_console->surface);
2166             g_height = surface_height(active_console->surface);
2167         }
2168         s->surface = qemu_create_displaysurface(g_width, g_height);
2169     }
2170 
2171     s->hw_ops = &text_console_ops;
2172     s->hw = s;
2173 
2174     /* Set text attribute defaults */
2175     s->t_attrib_default.bold = 0;
2176     s->t_attrib_default.uline = 0;
2177     s->t_attrib_default.blink = 0;
2178     s->t_attrib_default.invers = 0;
2179     s->t_attrib_default.unvisible = 0;
2180     s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
2181     s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
2182     /* set current text attributes to default */
2183     s->t_attrib = s->t_attrib_default;
2184     text_console_resize(s);
2185 
2186     if (chr->label) {
2187         char msg[128];
2188         int len;
2189 
2190         s->t_attrib.bgcol = QEMU_COLOR_BLUE;
2191         len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
2192         vc_chr_write(chr, (uint8_t *)msg, len);
2193         s->t_attrib = s->t_attrib_default;
2194     }
2195 
2196     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
2197 }
2198 
2199 static void vc_chr_open(Chardev *chr,
2200                         ChardevBackend *backend,
2201                         bool *be_opened,
2202                         Error **errp)
2203 {
2204     ChardevVC *vc = backend->u.vc.data;
2205     VCChardev *drv = VC_CHARDEV(chr);
2206     QemuConsole *s;
2207     unsigned width = 0;
2208     unsigned height = 0;
2209 
2210     if (vc->has_width) {
2211         width = vc->width;
2212     } else if (vc->has_cols) {
2213         width = vc->cols * FONT_WIDTH;
2214     }
2215 
2216     if (vc->has_height) {
2217         height = vc->height;
2218     } else if (vc->has_rows) {
2219         height = vc->rows * FONT_HEIGHT;
2220     }
2221 
2222     trace_console_txt_new(width, height);
2223     if (width == 0 || height == 0) {
2224         s = new_console(NULL, TEXT_CONSOLE, 0);
2225     } else {
2226         s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
2227         s->surface = qemu_create_displaysurface(width, height);
2228     }
2229 
2230     if (!s) {
2231         error_setg(errp, "cannot create text console");
2232         return;
2233     }
2234 
2235     s->chr = chr;
2236     drv->console = s;
2237 
2238     if (display_state) {
2239         text_console_do_init(chr, display_state);
2240     }
2241 
2242     /* console/chardev init sometimes completes elsewhere in a 2nd
2243      * stage, so defer OPENED events until they are fully initialized
2244      */
2245     *be_opened = false;
2246 }
2247 
2248 void qemu_console_resize(QemuConsole *s, int width, int height)
2249 {
2250     DisplaySurface *surface;
2251 
2252     assert(s->console_type == GRAPHIC_CONSOLE);
2253 
2254     if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
2255         pixman_image_get_width(s->surface->image) == width &&
2256         pixman_image_get_height(s->surface->image) == height) {
2257         return;
2258     }
2259 
2260     surface = qemu_create_displaysurface(width, height);
2261     dpy_gfx_replace_surface(s, surface);
2262 }
2263 
2264 DisplaySurface *qemu_console_surface(QemuConsole *console)
2265 {
2266     return console->surface;
2267 }
2268 
2269 PixelFormat qemu_default_pixelformat(int bpp)
2270 {
2271     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
2272     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
2273     return pf;
2274 }
2275 
2276 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
2277 
2278 void qemu_display_register(QemuDisplay *ui)
2279 {
2280     assert(ui->type < DISPLAY_TYPE__MAX);
2281     dpys[ui->type] = ui;
2282 }
2283 
2284 bool qemu_display_find_default(DisplayOptions *opts)
2285 {
2286     static DisplayType prio[] = {
2287         DISPLAY_TYPE_GTK,
2288         DISPLAY_TYPE_SDL,
2289         DISPLAY_TYPE_COCOA
2290     };
2291     int i;
2292 
2293     for (i = 0; i < ARRAY_SIZE(prio); i++) {
2294         if (dpys[prio[i]] == NULL) {
2295             ui_module_load_one(DisplayType_str(prio[i]));
2296         }
2297         if (dpys[prio[i]] == NULL) {
2298             continue;
2299         }
2300         opts->type = prio[i];
2301         return true;
2302     }
2303     return false;
2304 }
2305 
2306 void qemu_display_early_init(DisplayOptions *opts)
2307 {
2308     assert(opts->type < DISPLAY_TYPE__MAX);
2309     if (opts->type == DISPLAY_TYPE_NONE) {
2310         return;
2311     }
2312     if (dpys[opts->type] == NULL) {
2313         ui_module_load_one(DisplayType_str(opts->type));
2314     }
2315     if (dpys[opts->type] == NULL) {
2316         error_report("Display '%s' is not available.",
2317                      DisplayType_str(opts->type));
2318         exit(1);
2319     }
2320     if (dpys[opts->type]->early_init) {
2321         dpys[opts->type]->early_init(opts);
2322     }
2323 }
2324 
2325 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
2326 {
2327     assert(opts->type < DISPLAY_TYPE__MAX);
2328     if (opts->type == DISPLAY_TYPE_NONE) {
2329         return;
2330     }
2331     assert(dpys[opts->type] != NULL);
2332     dpys[opts->type]->init(ds, opts);
2333 }
2334 
2335 void qemu_display_help(void)
2336 {
2337     int idx;
2338 
2339     printf("Available display backend types:\n");
2340     printf("none\n");
2341     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
2342         if (!dpys[idx]) {
2343             ui_module_load_one(DisplayType_str(idx));
2344         }
2345         if (dpys[idx]) {
2346             printf("%s\n",  DisplayType_str(dpys[idx]->type));
2347         }
2348     }
2349 }
2350 
2351 void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
2352 {
2353     int val;
2354     ChardevVC *vc;
2355 
2356     backend->type = CHARDEV_BACKEND_KIND_VC;
2357     vc = backend->u.vc.data = g_new0(ChardevVC, 1);
2358     qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
2359 
2360     val = qemu_opt_get_number(opts, "width", 0);
2361     if (val != 0) {
2362         vc->has_width = true;
2363         vc->width = val;
2364     }
2365 
2366     val = qemu_opt_get_number(opts, "height", 0);
2367     if (val != 0) {
2368         vc->has_height = true;
2369         vc->height = val;
2370     }
2371 
2372     val = qemu_opt_get_number(opts, "cols", 0);
2373     if (val != 0) {
2374         vc->has_cols = true;
2375         vc->cols = val;
2376     }
2377 
2378     val = qemu_opt_get_number(opts, "rows", 0);
2379     if (val != 0) {
2380         vc->has_rows = true;
2381         vc->rows = val;
2382     }
2383 }
2384 
2385 static const TypeInfo qemu_console_info = {
2386     .name = TYPE_QEMU_CONSOLE,
2387     .parent = TYPE_OBJECT,
2388     .instance_size = sizeof(QemuConsole),
2389     .class_size = sizeof(QemuConsoleClass),
2390 };
2391 
2392 static void char_vc_class_init(ObjectClass *oc, void *data)
2393 {
2394     ChardevClass *cc = CHARDEV_CLASS(oc);
2395 
2396     cc->parse = qemu_chr_parse_vc;
2397     cc->open = vc_chr_open;
2398     cc->chr_write = vc_chr_write;
2399     cc->chr_set_echo = vc_chr_set_echo;
2400 }
2401 
2402 static const TypeInfo char_vc_type_info = {
2403     .name = TYPE_CHARDEV_VC,
2404     .parent = TYPE_CHARDEV,
2405     .instance_size = sizeof(VCChardev),
2406     .class_init = char_vc_class_init,
2407 };
2408 
2409 void qemu_console_early_init(void)
2410 {
2411     /* set the default vc driver */
2412     if (!object_class_by_name(TYPE_CHARDEV_VC)) {
2413         type_register(&char_vc_type_info);
2414     }
2415 }
2416 
2417 static void register_types(void)
2418 {
2419     type_register_static(&qemu_console_info);
2420 }
2421 
2422 type_init(register_types);
2423