xref: /openbmc/qemu/ui/console.c (revision a418e7ae)
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 "qapi/visitor.h"
31 #include "qemu/coroutine.h"
32 #include "qemu/error-report.h"
33 #include "qemu/main-loop.h"
34 #include "qemu/module.h"
35 #include "qemu/option.h"
36 #include "chardev/char.h"
37 #include "trace.h"
38 #include "exec/memory.h"
39 #include "qom/object.h"
40 
41 #include "console-priv.h"
42 
43 OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT)
44 
45 typedef struct QemuGraphicConsole {
46     QemuConsole parent;
47 
48     Object *device;
49     uint32_t head;
50 
51     QEMUCursor *cursor;
52     int cursor_x, cursor_y;
53     bool cursor_on;
54 } QemuGraphicConsole;
55 
56 typedef QemuConsoleClass QemuGraphicConsoleClass;
57 
58 OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE)
59 
60 struct DisplayState {
61     QEMUTimer *gui_timer;
62     uint64_t last_update;
63     uint64_t update_interval;
64     bool refreshing;
65 
66     QLIST_HEAD(, DisplayChangeListener) listeners;
67 };
68 
69 static DisplayState *display_state;
70 static QTAILQ_HEAD(, QemuConsole) consoles =
71     QTAILQ_HEAD_INITIALIZER(consoles);
72 
73 static void dpy_refresh(DisplayState *s);
74 static DisplayState *get_alloc_displaystate(void);
75 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
76 static bool console_compatible_with(QemuConsole *con,
77                                     DisplayChangeListener *dcl, Error **errp);
78 static QemuConsole *qemu_graphic_console_lookup_unused(void);
79 static void dpy_set_ui_info_timer(void *opaque);
80 
81 static void gui_update(void *opaque)
82 {
83     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
84     uint64_t dcl_interval;
85     DisplayState *ds = opaque;
86     DisplayChangeListener *dcl;
87 
88     ds->refreshing = true;
89     dpy_refresh(ds);
90     ds->refreshing = false;
91 
92     QLIST_FOREACH(dcl, &ds->listeners, next) {
93         dcl_interval = dcl->update_interval ?
94             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
95         if (interval > dcl_interval) {
96             interval = dcl_interval;
97         }
98     }
99     if (ds->update_interval != interval) {
100         ds->update_interval = interval;
101         trace_console_refresh(interval);
102     }
103     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
104     timer_mod(ds->gui_timer, ds->last_update + interval);
105 }
106 
107 static void gui_setup_refresh(DisplayState *ds)
108 {
109     DisplayChangeListener *dcl;
110     bool need_timer = false;
111 
112     QLIST_FOREACH(dcl, &ds->listeners, next) {
113         if (dcl->ops->dpy_refresh != NULL) {
114             need_timer = true;
115         }
116     }
117 
118     if (need_timer && ds->gui_timer == NULL) {
119         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
120         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
121     }
122     if (!need_timer && ds->gui_timer != NULL) {
123         timer_free(ds->gui_timer);
124         ds->gui_timer = NULL;
125     }
126 }
127 
128 void graphic_hw_update_done(QemuConsole *con)
129 {
130     if (con) {
131         qemu_co_enter_all(&con->dump_queue, NULL);
132     }
133 }
134 
135 void graphic_hw_update(QemuConsole *con)
136 {
137     bool async = false;
138     if (!con) {
139         return;
140     }
141     if (con->hw_ops->gfx_update) {
142         con->hw_ops->gfx_update(con->hw);
143         async = con->hw_ops->gfx_update_async;
144     }
145     if (!async) {
146         graphic_hw_update_done(con);
147     }
148 }
149 
150 static void graphic_hw_update_bh(void *con)
151 {
152     graphic_hw_update(con);
153 }
154 
155 void qemu_console_co_wait_update(QemuConsole *con)
156 {
157     if (qemu_co_queue_empty(&con->dump_queue)) {
158         /* Defer the update, it will restart the pending coroutines */
159         aio_bh_schedule_oneshot(qemu_get_aio_context(),
160                                 graphic_hw_update_bh, con);
161     }
162     qemu_co_queue_wait(&con->dump_queue, NULL);
163 
164 }
165 
166 static void graphic_hw_gl_unblock_timer(void *opaque)
167 {
168     warn_report("console: no gl-unblock within one second");
169 }
170 
171 void graphic_hw_gl_block(QemuConsole *con, bool block)
172 {
173     uint64_t timeout;
174     assert(con != NULL);
175 
176     if (block) {
177         con->gl_block++;
178     } else {
179         con->gl_block--;
180     }
181     assert(con->gl_block >= 0);
182     if (!con->hw_ops->gl_block) {
183         return;
184     }
185     if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
186         return;
187     }
188     con->hw_ops->gl_block(con->hw, block);
189 
190     if (block) {
191         timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
192         timeout += 1000; /* one sec */
193         timer_mod(con->gl_unblock_timer, timeout);
194     } else {
195         timer_del(con->gl_unblock_timer);
196     }
197 }
198 
199 int qemu_console_get_window_id(QemuConsole *con)
200 {
201     return con->window_id;
202 }
203 
204 void qemu_console_set_window_id(QemuConsole *con, int window_id)
205 {
206     con->window_id = window_id;
207 }
208 
209 void graphic_hw_invalidate(QemuConsole *con)
210 {
211     if (con && con->hw_ops->invalidate) {
212         con->hw_ops->invalidate(con->hw);
213     }
214 }
215 
216 void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
217 {
218     if (con && con->hw_ops->text_update) {
219         con->hw_ops->text_update(con->hw, chardata);
220     }
221 }
222 
223 static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl,
224                                              struct DisplaySurface *new_surface,
225                                              bool update)
226 {
227     if (dcl->ops->dpy_gfx_switch) {
228         dcl->ops->dpy_gfx_switch(dcl, new_surface);
229     }
230 
231     if (update && dcl->ops->dpy_gfx_update) {
232         dcl->ops->dpy_gfx_update(dcl, 0, 0,
233                                  surface_width(new_surface),
234                                  surface_height(new_surface));
235     }
236 }
237 
238 static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface)
239 {
240     if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) {
241         con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface);
242     }
243 }
244 
245 static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface)
246 {
247     if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) {
248         con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface);
249     }
250 }
251 
252 static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface,
253                                    int x, int y, int w, int h)
254 {
255     if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) {
256         con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h);
257     }
258 }
259 
260 static void displaychangelistener_display_console(DisplayChangeListener *dcl,
261                                                   Error **errp)
262 {
263     static const char nodev[] =
264         "This VM has no graphic display device.";
265     static DisplaySurface *dummy;
266     QemuConsole *con = dcl->con;
267 
268     if (!con || !console_compatible_with(con, dcl, errp)) {
269         if (!dummy) {
270             dummy = qemu_create_placeholder_surface(640, 480, nodev);
271         }
272         if (con) {
273             dpy_gfx_create_texture(con, dummy);
274         }
275         displaychangelistener_gfx_switch(dcl, dummy, TRUE);
276         return;
277     }
278 
279     dpy_gfx_create_texture(con, con->surface);
280     displaychangelistener_gfx_switch(dcl, con->surface,
281                                      con->scanout.kind == SCANOUT_SURFACE);
282 
283     if (con->scanout.kind == SCANOUT_DMABUF &&
284         displaychangelistener_has_dmabuf(dcl)) {
285         dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
286     } else if (con->scanout.kind == SCANOUT_TEXTURE &&
287                dcl->ops->dpy_gl_scanout_texture) {
288         dcl->ops->dpy_gl_scanout_texture(dcl,
289                                          con->scanout.texture.backing_id,
290                                          con->scanout.texture.backing_y_0_top,
291                                          con->scanout.texture.backing_width,
292                                          con->scanout.texture.backing_height,
293                                          con->scanout.texture.x,
294                                          con->scanout.texture.y,
295                                          con->scanout.texture.width,
296                                          con->scanout.texture.height,
297                                          con->scanout.texture.d3d_tex2d);
298     }
299 }
300 
301 void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
302 {
303     qemu_text_console_handle_keysym(s, keysym);
304 }
305 
306 static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
307     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
308     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
309     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
310     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
311     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
312     [Q_KEY_CODE_END]    = QEMU_KEY_END,
313     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
314     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
315     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
316     [Q_KEY_CODE_TAB]    = QEMU_KEY_TAB,
317     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
318 };
319 
320 static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
321     [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
322     [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
323     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
324     [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
325     [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
326     [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
327     [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
328     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
329 };
330 
331 bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl)
332 {
333     int keysym;
334 
335     keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
336     if (keysym == 0) {
337         return false;
338     }
339     qemu_text_console_put_keysym(s, keysym);
340     return true;
341 }
342 
343 void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len)
344 {
345     int i;
346 
347     for (i = 0; i < len && str[i]; i++) {
348         qemu_text_console_put_keysym(s, str[i]);
349     }
350 }
351 
352 static void
353 qemu_console_register(QemuConsole *c)
354 {
355     int i;
356 
357     if (QTAILQ_EMPTY(&consoles)) {
358         c->index = 0;
359         QTAILQ_INSERT_TAIL(&consoles, c, next);
360     } else if (!QEMU_IS_GRAPHIC_CONSOLE(c) || phase_check(PHASE_MACHINE_READY)) {
361         QemuConsole *last = QTAILQ_LAST(&consoles);
362         c->index = last->index + 1;
363         QTAILQ_INSERT_TAIL(&consoles, c, next);
364     } else {
365         /*
366          * HACK: Put graphical consoles before text consoles.
367          *
368          * Only do that for coldplugged devices.  After initial device
369          * initialization we will not renumber the consoles any more.
370          */
371         QemuConsole *it = QTAILQ_FIRST(&consoles);
372 
373         while (QTAILQ_NEXT(it, next) != NULL && QEMU_IS_GRAPHIC_CONSOLE(it)) {
374             it = QTAILQ_NEXT(it, next);
375         }
376         if (QEMU_IS_GRAPHIC_CONSOLE(it)) {
377             /* have no text consoles */
378             c->index = it->index + 1;
379             QTAILQ_INSERT_AFTER(&consoles, it, c, next);
380         } else {
381             c->index = it->index;
382             QTAILQ_INSERT_BEFORE(it, c, next);
383             /* renumber text consoles */
384             for (i = c->index + 1; it != NULL; it = QTAILQ_NEXT(it, next), i++) {
385                 it->index = i;
386             }
387         }
388     }
389 }
390 
391 static void
392 qemu_console_finalize(Object *obj)
393 {
394     QemuConsole *c = QEMU_CONSOLE(obj);
395 
396     /* TODO: check this code path, and unregister from consoles */
397     g_clear_pointer(&c->surface, qemu_free_displaysurface);
398     g_clear_pointer(&c->gl_unblock_timer, timer_free);
399     g_clear_pointer(&c->ui_timer, timer_free);
400 }
401 
402 static void
403 qemu_console_class_init(ObjectClass *oc, void *data)
404 {
405 }
406 
407 static void
408 qemu_console_init(Object *obj)
409 {
410     QemuConsole *c = QEMU_CONSOLE(obj);
411     DisplayState *ds = get_alloc_displaystate();
412 
413     qemu_co_queue_init(&c->dump_queue);
414     c->ds = ds;
415     c->window_id = -1;
416     c->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
417                                dpy_set_ui_info_timer, c);
418     qemu_console_register(c);
419 }
420 
421 static void
422 qemu_graphic_console_finalize(Object *obj)
423 {
424     QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
425 
426     g_clear_pointer(&c->device, object_unref);
427 }
428 
429 static void
430 qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name,
431                                    void *opaque, Error **errp)
432 {
433     QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
434 
435     visit_type_uint32(v, name, &c->head, errp);
436 }
437 
438 static void
439 qemu_graphic_console_class_init(ObjectClass *oc, void *data)
440 {
441     object_class_property_add_link(oc, "device", TYPE_DEVICE,
442                                    offsetof(QemuGraphicConsole, device),
443                                    object_property_allow_set_link,
444                                    OBJ_PROP_LINK_STRONG);
445     object_class_property_add(oc, "head", "uint32",
446                               qemu_graphic_console_prop_get_head,
447                               NULL, NULL, NULL);
448 }
449 
450 static void
451 qemu_graphic_console_init(Object *obj)
452 {
453 }
454 
455 #ifdef WIN32
456 void qemu_displaysurface_win32_set_handle(DisplaySurface *surface,
457                                           HANDLE h, uint32_t offset)
458 {
459     assert(!surface->handle);
460 
461     surface->handle = h;
462     surface->handle_offset = offset;
463 }
464 
465 static void
466 win32_pixman_image_destroy(pixman_image_t *image, void *data)
467 {
468     DisplaySurface *surface = data;
469 
470     if (!surface->handle) {
471         return;
472     }
473 
474     assert(surface->handle_offset == 0);
475 
476     qemu_win32_map_free(
477         pixman_image_get_data(surface->image),
478         surface->handle,
479         &error_warn
480     );
481 }
482 #endif
483 
484 DisplaySurface *qemu_create_displaysurface(int width, int height)
485 {
486     DisplaySurface *surface;
487     void *bits = NULL;
488 #ifdef WIN32
489     HANDLE handle = NULL;
490 #endif
491 
492     trace_displaysurface_create(width, height);
493 
494 #ifdef WIN32
495     bits = qemu_win32_map_alloc(width * height * 4, &handle, &error_abort);
496 #endif
497 
498     surface = qemu_create_displaysurface_from(
499         width, height,
500         PIXMAN_x8r8g8b8,
501         width * 4, bits
502     );
503     surface->flags = QEMU_ALLOCATED_FLAG;
504 
505 #ifdef WIN32
506     qemu_displaysurface_win32_set_handle(surface, handle, 0);
507 #endif
508     return surface;
509 }
510 
511 DisplaySurface *qemu_create_displaysurface_from(int width, int height,
512                                                 pixman_format_code_t format,
513                                                 int linesize, uint8_t *data)
514 {
515     DisplaySurface *surface = g_new0(DisplaySurface, 1);
516 
517     trace_displaysurface_create_from(surface, width, height, format);
518     surface->image = pixman_image_create_bits(format,
519                                               width, height,
520                                               (void *)data, linesize);
521     assert(surface->image != NULL);
522 #ifdef WIN32
523     pixman_image_set_destroy_function(surface->image,
524                                       win32_pixman_image_destroy, surface);
525 #endif
526 
527     return surface;
528 }
529 
530 DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
531 {
532     DisplaySurface *surface = g_new0(DisplaySurface, 1);
533 
534     trace_displaysurface_create_pixman(surface);
535     surface->image = pixman_image_ref(image);
536 
537     return surface;
538 }
539 
540 DisplaySurface *qemu_create_placeholder_surface(int w, int h,
541                                                 const char *msg)
542 {
543     DisplaySurface *surface = qemu_create_displaysurface(w, h);
544 #ifdef CONFIG_PIXMAN
545     pixman_color_t bg = QEMU_PIXMAN_COLOR_BLACK;
546     pixman_color_t fg = QEMU_PIXMAN_COLOR_GRAY;
547     pixman_image_t *glyph;
548     int len, x, y, i;
549 
550     len = strlen(msg);
551     x = (w / FONT_WIDTH  - len) / 2;
552     y = (h / FONT_HEIGHT - 1)   / 2;
553     for (i = 0; i < len; i++) {
554         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
555         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
556                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
557         qemu_pixman_image_unref(glyph);
558     }
559 #endif
560     surface->flags |= QEMU_PLACEHOLDER_FLAG;
561     return surface;
562 }
563 
564 void qemu_free_displaysurface(DisplaySurface *surface)
565 {
566     if (surface == NULL) {
567         return;
568     }
569     trace_displaysurface_free(surface);
570     qemu_pixman_image_unref(surface->image);
571     g_free(surface);
572 }
573 
574 bool console_has_gl(QemuConsole *con)
575 {
576     return con->gl != NULL;
577 }
578 
579 static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
580 {
581     if (dcl->ops->dpy_has_dmabuf) {
582         return dcl->ops->dpy_has_dmabuf(dcl);
583     }
584 
585     if (dcl->ops->dpy_gl_scanout_dmabuf) {
586         return true;
587     }
588 
589     return false;
590 }
591 
592 static bool console_compatible_with(QemuConsole *con,
593                                     DisplayChangeListener *dcl, Error **errp)
594 {
595     int flags;
596 
597     flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
598 
599     if (console_has_gl(con) &&
600         !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
601         error_setg(errp, "Display %s is incompatible with the GL context",
602                    dcl->ops->dpy_name);
603         return false;
604     }
605 
606     if (flags & GRAPHIC_FLAGS_GL &&
607         !console_has_gl(con)) {
608         error_setg(errp, "The console requires a GL context.");
609         return false;
610 
611     }
612 
613     if (flags & GRAPHIC_FLAGS_DMABUF &&
614         !displaychangelistener_has_dmabuf(dcl)) {
615         error_setg(errp, "The console requires display DMABUF support.");
616         return false;
617     }
618 
619     return true;
620 }
621 
622 void console_handle_touch_event(QemuConsole *con,
623                                 struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
624                                 uint64_t num_slot,
625                                 int width, int height,
626                                 double x, double y,
627                                 InputMultiTouchType type,
628                                 Error **errp)
629 {
630     struct touch_slot *slot;
631     bool needs_sync = false;
632     int update;
633     int i;
634 
635     if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
636         error_setg(errp,
637                    "Unexpected touch slot number: % " PRId64" >= %d",
638                    num_slot, INPUT_EVENT_SLOTS_MAX);
639         return;
640     }
641 
642     slot = &touch_slots[num_slot];
643     slot->x = x;
644     slot->y = y;
645 
646     if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
647         slot->tracking_id = num_slot;
648     }
649 
650     for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
651         if (i == num_slot) {
652             update = type;
653         } else {
654             update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
655         }
656 
657         slot = &touch_slots[i];
658 
659         if (slot->tracking_id == -1) {
660             continue;
661         }
662 
663         if (update == INPUT_MULTI_TOUCH_TYPE_END) {
664             slot->tracking_id = -1;
665             qemu_input_queue_mtt(con, update, i, slot->tracking_id);
666             needs_sync = true;
667         } else {
668             qemu_input_queue_mtt(con, update, i, slot->tracking_id);
669             qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
670             qemu_input_queue_mtt_abs(con,
671                                     INPUT_AXIS_X, (int) slot->x,
672                                     0, width,
673                                     i, slot->tracking_id);
674             qemu_input_queue_mtt_abs(con,
675                                     INPUT_AXIS_Y, (int) slot->y,
676                                     0, height,
677                                     i, slot->tracking_id);
678             needs_sync = true;
679         }
680     }
681 
682     if (needs_sync) {
683         qemu_input_event_sync();
684     }
685 }
686 
687 void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
688 {
689     /* display has opengl support */
690     assert(con);
691     if (con->gl) {
692         error_report("The console already has an OpenGL context.");
693         exit(1);
694     }
695     con->gl = gl;
696 }
697 
698 static void
699 dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
700 {
701     if (con && con->cursor && dcl->ops->dpy_cursor_define) {
702         dcl->ops->dpy_cursor_define(dcl, con->cursor);
703     }
704     if (con && dcl->ops->dpy_mouse_set) {
705         dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
706     }
707 }
708 
709 void register_displaychangelistener(DisplayChangeListener *dcl)
710 {
711     assert(!dcl->ds);
712 
713     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
714     dcl->ds = get_alloc_displaystate();
715     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
716     gui_setup_refresh(dcl->ds);
717     if (dcl->con) {
718         dcl->con->dcls++;
719     }
720     displaychangelistener_display_console(dcl, &error_fatal);
721     if (QEMU_IS_GRAPHIC_CONSOLE(dcl->con)) {
722         dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(dcl->con));
723     } else if (QEMU_IS_TEXT_CONSOLE(dcl->con)) {
724         qemu_text_console_update_size(QEMU_TEXT_CONSOLE(dcl->con));
725     }
726     qemu_text_console_update_cursor();
727 }
728 
729 void update_displaychangelistener(DisplayChangeListener *dcl,
730                                   uint64_t interval)
731 {
732     DisplayState *ds = dcl->ds;
733 
734     dcl->update_interval = interval;
735     if (!ds->refreshing && ds->update_interval > interval) {
736         timer_mod(ds->gui_timer, ds->last_update + interval);
737     }
738 }
739 
740 void unregister_displaychangelistener(DisplayChangeListener *dcl)
741 {
742     DisplayState *ds = dcl->ds;
743     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
744     if (dcl->con) {
745         dcl->con->dcls--;
746     }
747     QLIST_REMOVE(dcl, next);
748     dcl->ds = NULL;
749     gui_setup_refresh(ds);
750 }
751 
752 static void dpy_set_ui_info_timer(void *opaque)
753 {
754     QemuConsole *con = opaque;
755     uint32_t head = qemu_console_get_head(con);
756 
757     con->hw_ops->ui_info(con->hw, head, &con->ui_info);
758 }
759 
760 bool dpy_ui_info_supported(const QemuConsole *con)
761 {
762     if (con == NULL) {
763         return false;
764     }
765 
766     return con->hw_ops->ui_info != NULL;
767 }
768 
769 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
770 {
771     assert(dpy_ui_info_supported(con));
772 
773     return &con->ui_info;
774 }
775 
776 int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
777 {
778     if (!dpy_ui_info_supported(con)) {
779         return -1;
780     }
781     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
782         /* nothing changed -- ignore */
783         return 0;
784     }
785 
786     /*
787      * Typically we get a flood of these as the user resizes the window.
788      * Wait until the dust has settled (one second without updates), then
789      * go notify the guest.
790      */
791     con->ui_info = *info;
792     timer_mod(con->ui_timer,
793               qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
794     return 0;
795 }
796 
797 void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
798 {
799     DisplayState *s = con->ds;
800     DisplayChangeListener *dcl;
801     int width = qemu_console_get_width(con, x + w);
802     int height = qemu_console_get_height(con, y + h);
803 
804     x = MAX(x, 0);
805     y = MAX(y, 0);
806     x = MIN(x, width);
807     y = MIN(y, height);
808     w = MIN(w, width - x);
809     h = MIN(h, height - y);
810 
811     if (!qemu_console_is_visible(con)) {
812         return;
813     }
814     dpy_gfx_update_texture(con, con->surface, x, y, w, h);
815     QLIST_FOREACH(dcl, &s->listeners, next) {
816         if (con != dcl->con) {
817             continue;
818         }
819         if (dcl->ops->dpy_gfx_update) {
820             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
821         }
822     }
823 }
824 
825 void dpy_gfx_update_full(QemuConsole *con)
826 {
827     int w = qemu_console_get_width(con, 0);
828     int h = qemu_console_get_height(con, 0);
829 
830     dpy_gfx_update(con, 0, 0, w, h);
831 }
832 
833 void dpy_gfx_replace_surface(QemuConsole *con,
834                              DisplaySurface *surface)
835 {
836     static const char placeholder_msg[] = "Display output is not active.";
837     DisplayState *s = con->ds;
838     DisplaySurface *old_surface = con->surface;
839     DisplaySurface *new_surface = surface;
840     DisplayChangeListener *dcl;
841     int width;
842     int height;
843 
844     if (!surface) {
845         if (old_surface) {
846             width = surface_width(old_surface);
847             height = surface_height(old_surface);
848         } else {
849             width = 640;
850             height = 480;
851         }
852 
853         new_surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
854     }
855 
856     assert(old_surface != new_surface);
857 
858     con->scanout.kind = SCANOUT_SURFACE;
859     con->surface = new_surface;
860     dpy_gfx_create_texture(con, new_surface);
861     QLIST_FOREACH(dcl, &s->listeners, next) {
862         if (con != dcl->con) {
863             continue;
864         }
865         displaychangelistener_gfx_switch(dcl, new_surface, surface ? FALSE : TRUE);
866     }
867     dpy_gfx_destroy_texture(con, old_surface);
868     qemu_free_displaysurface(old_surface);
869 }
870 
871 bool dpy_gfx_check_format(QemuConsole *con,
872                           pixman_format_code_t format)
873 {
874     DisplayChangeListener *dcl;
875     DisplayState *s = con->ds;
876 
877     QLIST_FOREACH(dcl, &s->listeners, next) {
878         if (dcl->con && dcl->con != con) {
879             /* dcl bound to another console -> skip */
880             continue;
881         }
882         if (dcl->ops->dpy_gfx_check_format) {
883             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
884                 return false;
885             }
886         } else {
887             /* default is to allow native 32 bpp only */
888             if (format != qemu_default_pixman_format(32, true)) {
889                 return false;
890             }
891         }
892     }
893     return true;
894 }
895 
896 static void dpy_refresh(DisplayState *s)
897 {
898     DisplayChangeListener *dcl;
899 
900     QLIST_FOREACH(dcl, &s->listeners, next) {
901         if (dcl->ops->dpy_refresh) {
902             dcl->ops->dpy_refresh(dcl);
903         }
904     }
905 }
906 
907 void dpy_text_cursor(QemuConsole *con, int x, int y)
908 {
909     DisplayState *s = con->ds;
910     DisplayChangeListener *dcl;
911 
912     if (!qemu_console_is_visible(con)) {
913         return;
914     }
915     QLIST_FOREACH(dcl, &s->listeners, next) {
916         if (con != dcl->con) {
917             continue;
918         }
919         if (dcl->ops->dpy_text_cursor) {
920             dcl->ops->dpy_text_cursor(dcl, x, y);
921         }
922     }
923 }
924 
925 void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
926 {
927     DisplayState *s = con->ds;
928     DisplayChangeListener *dcl;
929 
930     if (!qemu_console_is_visible(con)) {
931         return;
932     }
933     QLIST_FOREACH(dcl, &s->listeners, next) {
934         if (con != dcl->con) {
935             continue;
936         }
937         if (dcl->ops->dpy_text_update) {
938             dcl->ops->dpy_text_update(dcl, x, y, w, h);
939         }
940     }
941 }
942 
943 void dpy_text_resize(QemuConsole *con, int w, int h)
944 {
945     DisplayState *s = con->ds;
946     DisplayChangeListener *dcl;
947 
948     if (!qemu_console_is_visible(con)) {
949         return;
950     }
951     QLIST_FOREACH(dcl, &s->listeners, next) {
952         if (con != dcl->con) {
953             continue;
954         }
955         if (dcl->ops->dpy_text_resize) {
956             dcl->ops->dpy_text_resize(dcl, w, h);
957         }
958     }
959 }
960 
961 void dpy_mouse_set(QemuConsole *c, int x, int y, bool on)
962 {
963     QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
964     DisplayState *s = c->ds;
965     DisplayChangeListener *dcl;
966 
967     con->cursor_x = x;
968     con->cursor_y = y;
969     con->cursor_on = on;
970     if (!qemu_console_is_visible(c)) {
971         return;
972     }
973     QLIST_FOREACH(dcl, &s->listeners, next) {
974         if (c != dcl->con) {
975             continue;
976         }
977         if (dcl->ops->dpy_mouse_set) {
978             dcl->ops->dpy_mouse_set(dcl, x, y, on);
979         }
980     }
981 }
982 
983 void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
984 {
985     QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
986     DisplayState *s = c->ds;
987     DisplayChangeListener *dcl;
988 
989     cursor_unref(con->cursor);
990     con->cursor = cursor_ref(cursor);
991     if (!qemu_console_is_visible(c)) {
992         return;
993     }
994     QLIST_FOREACH(dcl, &s->listeners, next) {
995         if (c != dcl->con) {
996             continue;
997         }
998         if (dcl->ops->dpy_cursor_define) {
999             dcl->ops->dpy_cursor_define(dcl, cursor);
1000         }
1001     }
1002 }
1003 
1004 bool dpy_cursor_define_supported(QemuConsole *con)
1005 {
1006     DisplayState *s = con->ds;
1007     DisplayChangeListener *dcl;
1008 
1009     QLIST_FOREACH(dcl, &s->listeners, next) {
1010         if (dcl->ops->dpy_cursor_define) {
1011             return true;
1012         }
1013     }
1014     return false;
1015 }
1016 
1017 QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
1018                                 struct QEMUGLParams *qparams)
1019 {
1020     assert(con->gl);
1021     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
1022 }
1023 
1024 void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
1025 {
1026     assert(con->gl);
1027     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
1028 }
1029 
1030 int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
1031 {
1032     assert(con->gl);
1033     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
1034 }
1035 
1036 void dpy_gl_scanout_disable(QemuConsole *con)
1037 {
1038     DisplayState *s = con->ds;
1039     DisplayChangeListener *dcl;
1040 
1041     if (con->scanout.kind != SCANOUT_SURFACE) {
1042         con->scanout.kind = SCANOUT_NONE;
1043     }
1044     QLIST_FOREACH(dcl, &s->listeners, next) {
1045         if (con != dcl->con) {
1046             continue;
1047         }
1048         if (dcl->ops->dpy_gl_scanout_disable) {
1049             dcl->ops->dpy_gl_scanout_disable(dcl);
1050         }
1051     }
1052 }
1053 
1054 void dpy_gl_scanout_texture(QemuConsole *con,
1055                             uint32_t backing_id,
1056                             bool backing_y_0_top,
1057                             uint32_t backing_width,
1058                             uint32_t backing_height,
1059                             uint32_t x, uint32_t y,
1060                             uint32_t width, uint32_t height,
1061                             void *d3d_tex2d)
1062 {
1063     DisplayState *s = con->ds;
1064     DisplayChangeListener *dcl;
1065 
1066     con->scanout.kind = SCANOUT_TEXTURE;
1067     con->scanout.texture = (ScanoutTexture) {
1068         backing_id, backing_y_0_top, backing_width, backing_height,
1069         x, y, width, height, d3d_tex2d,
1070     };
1071     QLIST_FOREACH(dcl, &s->listeners, next) {
1072         if (con != dcl->con) {
1073             continue;
1074         }
1075         if (dcl->ops->dpy_gl_scanout_texture) {
1076             dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
1077                                              backing_y_0_top,
1078                                              backing_width, backing_height,
1079                                              x, y, width, height,
1080                                              d3d_tex2d);
1081         }
1082     }
1083 }
1084 
1085 void dpy_gl_scanout_dmabuf(QemuConsole *con,
1086                            QemuDmaBuf *dmabuf)
1087 {
1088     DisplayState *s = con->ds;
1089     DisplayChangeListener *dcl;
1090 
1091     con->scanout.kind = SCANOUT_DMABUF;
1092     con->scanout.dmabuf = dmabuf;
1093     QLIST_FOREACH(dcl, &s->listeners, next) {
1094         if (con != dcl->con) {
1095             continue;
1096         }
1097         if (dcl->ops->dpy_gl_scanout_dmabuf) {
1098             dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
1099         }
1100     }
1101 }
1102 
1103 void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
1104                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
1105 {
1106     DisplayState *s = con->ds;
1107     DisplayChangeListener *dcl;
1108 
1109     QLIST_FOREACH(dcl, &s->listeners, next) {
1110         if (con != dcl->con) {
1111             continue;
1112         }
1113         if (dcl->ops->dpy_gl_cursor_dmabuf) {
1114             dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
1115                                            have_hot, hot_x, hot_y);
1116         }
1117     }
1118 }
1119 
1120 void dpy_gl_cursor_position(QemuConsole *con,
1121                             uint32_t pos_x, uint32_t pos_y)
1122 {
1123     DisplayState *s = con->ds;
1124     DisplayChangeListener *dcl;
1125 
1126     QLIST_FOREACH(dcl, &s->listeners, next) {
1127         if (con != dcl->con) {
1128             continue;
1129         }
1130         if (dcl->ops->dpy_gl_cursor_position) {
1131             dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
1132         }
1133     }
1134 }
1135 
1136 void dpy_gl_release_dmabuf(QemuConsole *con,
1137                           QemuDmaBuf *dmabuf)
1138 {
1139     DisplayState *s = con->ds;
1140     DisplayChangeListener *dcl;
1141 
1142     QLIST_FOREACH(dcl, &s->listeners, next) {
1143         if (con != dcl->con) {
1144             continue;
1145         }
1146         if (dcl->ops->dpy_gl_release_dmabuf) {
1147             dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
1148         }
1149     }
1150 }
1151 
1152 void dpy_gl_update(QemuConsole *con,
1153                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
1154 {
1155     DisplayState *s = con->ds;
1156     DisplayChangeListener *dcl;
1157 
1158     assert(con->gl);
1159 
1160     graphic_hw_gl_block(con, true);
1161     QLIST_FOREACH(dcl, &s->listeners, next) {
1162         if (con != dcl->con) {
1163             continue;
1164         }
1165         if (dcl->ops->dpy_gl_update) {
1166             dcl->ops->dpy_gl_update(dcl, x, y, w, h);
1167         }
1168     }
1169     graphic_hw_gl_block(con, false);
1170 }
1171 
1172 /***********************************************************/
1173 /* register display */
1174 
1175 /* console.c internal use only */
1176 static DisplayState *get_alloc_displaystate(void)
1177 {
1178     if (!display_state) {
1179         display_state = g_new0(DisplayState, 1);
1180     }
1181     return display_state;
1182 }
1183 
1184 /*
1185  * Called by main(), after creating QemuConsoles
1186  * and before initializing ui (sdl/vnc/...).
1187  */
1188 DisplayState *init_displaystate(void)
1189 {
1190     gchar *name;
1191     QemuConsole *con;
1192 
1193     QTAILQ_FOREACH(con, &consoles, next) {
1194         /* Hook up into the qom tree here (not in object_new()), once
1195          * all QemuConsoles are created and the order / numbering
1196          * doesn't change any more */
1197         name = g_strdup_printf("console[%d]", con->index);
1198         object_property_add_child(container_get(object_get_root(), "/backend"),
1199                                   name, OBJECT(con));
1200         g_free(name);
1201     }
1202 
1203     return display_state;
1204 }
1205 
1206 void graphic_console_set_hwops(QemuConsole *con,
1207                                const GraphicHwOps *hw_ops,
1208                                void *opaque)
1209 {
1210     con->hw_ops = hw_ops;
1211     con->hw = opaque;
1212 }
1213 
1214 QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
1215                                   const GraphicHwOps *hw_ops,
1216                                   void *opaque)
1217 {
1218     static const char noinit[] =
1219         "Guest has not initialized the display (yet).";
1220     int width = 640;
1221     int height = 480;
1222     QemuConsole *s;
1223     DisplaySurface *surface;
1224 
1225     s = qemu_graphic_console_lookup_unused();
1226     if (s) {
1227         trace_console_gfx_reuse(s->index);
1228         width = qemu_console_get_width(s, 0);
1229         height = qemu_console_get_height(s, 0);
1230     } else {
1231         trace_console_gfx_new();
1232         s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE);
1233     }
1234     QEMU_GRAPHIC_CONSOLE(s)->head = head;
1235     graphic_console_set_hwops(s, hw_ops, opaque);
1236     if (dev) {
1237         object_property_set_link(OBJECT(s), "device", OBJECT(dev),
1238                                  &error_abort);
1239     }
1240 
1241     surface = qemu_create_placeholder_surface(width, height, noinit);
1242     dpy_gfx_replace_surface(s, surface);
1243     s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
1244                                        graphic_hw_gl_unblock_timer, s);
1245     return s;
1246 }
1247 
1248 static const GraphicHwOps unused_ops = {
1249     /* no callbacks */
1250 };
1251 
1252 void graphic_console_close(QemuConsole *con)
1253 {
1254     static const char unplugged[] =
1255         "Guest display has been unplugged";
1256     DisplaySurface *surface;
1257     int width = qemu_console_get_width(con, 640);
1258     int height = qemu_console_get_height(con, 480);
1259 
1260     trace_console_gfx_close(con->index);
1261     object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
1262     graphic_console_set_hwops(con, &unused_ops, NULL);
1263 
1264     if (con->gl) {
1265         dpy_gl_scanout_disable(con);
1266     }
1267     surface = qemu_create_placeholder_surface(width, height, unplugged);
1268     dpy_gfx_replace_surface(con, surface);
1269 }
1270 
1271 QemuConsole *qemu_console_lookup_default(void)
1272 {
1273     QemuConsole *con;
1274 
1275     QTAILQ_FOREACH(con, &consoles, next) {
1276         if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
1277             return con;
1278         }
1279     }
1280     return QTAILQ_FIRST(&consoles);
1281 }
1282 
1283 QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1284 {
1285     QemuConsole *con;
1286 
1287     QTAILQ_FOREACH(con, &consoles, next) {
1288         if (con->index == index) {
1289             return con;
1290         }
1291     }
1292     return NULL;
1293 }
1294 
1295 QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1296 {
1297     QemuConsole *con;
1298     Object *obj;
1299     uint32_t h;
1300 
1301     QTAILQ_FOREACH(con, &consoles, next) {
1302         obj = object_property_get_link(OBJECT(con),
1303                                        "device", &error_abort);
1304         if (DEVICE(obj) != dev) {
1305             continue;
1306         }
1307         h = object_property_get_uint(OBJECT(con),
1308                                      "head", &error_abort);
1309         if (h != head) {
1310             continue;
1311         }
1312         return con;
1313     }
1314     return NULL;
1315 }
1316 
1317 QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
1318                                                 uint32_t head, Error **errp)
1319 {
1320     DeviceState *dev;
1321     QemuConsole *con;
1322 
1323     dev = qdev_find_recursive(sysbus_get_default(), device_id);
1324     if (dev == NULL) {
1325         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
1326                   "Device '%s' not found", device_id);
1327         return NULL;
1328     }
1329 
1330     con = qemu_console_lookup_by_device(dev, head);
1331     if (con == NULL) {
1332         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
1333                    device_id, head);
1334         return NULL;
1335     }
1336 
1337     return con;
1338 }
1339 
1340 static QemuConsole *qemu_graphic_console_lookup_unused(void)
1341 {
1342     QemuConsole *con;
1343     Object *obj;
1344 
1345     QTAILQ_FOREACH(con, &consoles, next) {
1346         if (!QEMU_IS_GRAPHIC_CONSOLE(con) || con->hw_ops != &unused_ops) {
1347             continue;
1348         }
1349         obj = object_property_get_link(OBJECT(con),
1350                                        "device", &error_abort);
1351         if (obj != NULL) {
1352             continue;
1353         }
1354         return con;
1355     }
1356     return NULL;
1357 }
1358 
1359 QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
1360 {
1361     return QEMU_IS_GRAPHIC_CONSOLE(con) ? QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
1362 }
1363 
1364 bool qemu_console_is_visible(QemuConsole *con)
1365 {
1366     return con->dcls > 0;
1367 }
1368 
1369 bool qemu_console_is_graphic(QemuConsole *con)
1370 {
1371     return con && QEMU_IS_GRAPHIC_CONSOLE(con);
1372 }
1373 
1374 bool qemu_console_is_fixedsize(QemuConsole *con)
1375 {
1376     return con && (QEMU_IS_GRAPHIC_CONSOLE(con) || QEMU_IS_FIXED_TEXT_CONSOLE(con));
1377 }
1378 
1379 bool qemu_console_is_gl_blocked(QemuConsole *con)
1380 {
1381     assert(con != NULL);
1382     return con->gl_block;
1383 }
1384 
1385 static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c)
1386 {
1387     QemuConsole *con;
1388 
1389     QTAILQ_FOREACH(con, &consoles, next) {
1390         QemuGraphicConsole *candidate;
1391 
1392         if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
1393             continue;
1394         }
1395 
1396         candidate = QEMU_GRAPHIC_CONSOLE(con);
1397         if (candidate->device != c->device) {
1398             continue;
1399         }
1400 
1401         if (candidate->head != c->head) {
1402             return true;
1403         }
1404     }
1405     return false;
1406 }
1407 
1408 char *qemu_console_get_label(QemuConsole *con)
1409 {
1410     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
1411         QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(con);
1412         if (c->device) {
1413             DeviceState *dev;
1414             bool multihead;
1415 
1416             dev = DEVICE(c->device);
1417             multihead = qemu_graphic_console_is_multihead(c);
1418             if (multihead) {
1419                 return g_strdup_printf("%s.%d", dev->id ?
1420                                        dev->id :
1421                                        object_get_typename(c->device),
1422                                        c->head);
1423             } else {
1424                 return g_strdup_printf("%s", dev->id ?
1425                                        dev->id :
1426                                        object_get_typename(c->device));
1427             }
1428         }
1429         return g_strdup("VGA");
1430     } else if (QEMU_IS_TEXT_CONSOLE(con)) {
1431         const char *label = qemu_text_console_get_label(QEMU_TEXT_CONSOLE(con));
1432         if (label) {
1433             return g_strdup(label);
1434         }
1435     }
1436 
1437     return g_strdup_printf("vc%d", con->index);
1438 }
1439 
1440 int qemu_console_get_index(QemuConsole *con)
1441 {
1442     return con ? con->index : -1;
1443 }
1444 
1445 uint32_t qemu_console_get_head(QemuConsole *con)
1446 {
1447     if (con == NULL) {
1448         return -1;
1449     }
1450     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
1451         return QEMU_GRAPHIC_CONSOLE(con)->head;
1452     }
1453     return 0;
1454 }
1455 
1456 int qemu_console_get_width(QemuConsole *con, int fallback)
1457 {
1458     if (con == NULL) {
1459         return fallback;
1460     }
1461     switch (con->scanout.kind) {
1462     case SCANOUT_DMABUF:
1463         return qemu_dmabuf_get_width(con->scanout.dmabuf);
1464     case SCANOUT_TEXTURE:
1465         return con->scanout.texture.width;
1466     case SCANOUT_SURFACE:
1467         return surface_width(con->surface);
1468     default:
1469         return fallback;
1470     }
1471 }
1472 
1473 int qemu_console_get_height(QemuConsole *con, int fallback)
1474 {
1475     if (con == NULL) {
1476         return fallback;
1477     }
1478     switch (con->scanout.kind) {
1479     case SCANOUT_DMABUF:
1480         return qemu_dmabuf_get_height(con->scanout.dmabuf);
1481     case SCANOUT_TEXTURE:
1482         return con->scanout.texture.height;
1483     case SCANOUT_SURFACE:
1484         return surface_height(con->surface);
1485     default:
1486         return fallback;
1487     }
1488 }
1489 
1490 int qemu_invalidate_text_consoles(void)
1491 {
1492     QemuConsole *s;
1493     int count = 0;
1494 
1495     QTAILQ_FOREACH(s, &consoles, next) {
1496         if (qemu_console_is_graphic(s) ||
1497             !qemu_console_is_visible(s)) {
1498             continue;
1499         }
1500         count++;
1501         graphic_hw_invalidate(s);
1502     }
1503 
1504     return count;
1505 }
1506 
1507 void qemu_console_resize(QemuConsole *s, int width, int height)
1508 {
1509     DisplaySurface *surface = qemu_console_surface(s);
1510 
1511     assert(QEMU_IS_GRAPHIC_CONSOLE(s));
1512 
1513     if ((s->scanout.kind != SCANOUT_SURFACE ||
1514          (surface && surface_is_allocated(surface) &&
1515                      !surface_is_placeholder(surface))) &&
1516         qemu_console_get_width(s, -1) == width &&
1517         qemu_console_get_height(s, -1) == height) {
1518         return;
1519     }
1520 
1521     surface = qemu_create_displaysurface(width, height);
1522     dpy_gfx_replace_surface(s, surface);
1523 }
1524 
1525 DisplaySurface *qemu_console_surface(QemuConsole *console)
1526 {
1527     switch (console->scanout.kind) {
1528     case SCANOUT_SURFACE:
1529         return console->surface;
1530     default:
1531         return NULL;
1532     }
1533 }
1534 
1535 PixelFormat qemu_default_pixelformat(int bpp)
1536 {
1537     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
1538     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
1539     return pf;
1540 }
1541 
1542 static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
1543 
1544 void qemu_display_register(QemuDisplay *ui)
1545 {
1546     assert(ui->type < DISPLAY_TYPE__MAX);
1547     dpys[ui->type] = ui;
1548 }
1549 
1550 bool qemu_display_find_default(DisplayOptions *opts)
1551 {
1552     static DisplayType prio[] = {
1553 #if defined(CONFIG_GTK)
1554         DISPLAY_TYPE_GTK,
1555 #endif
1556 #if defined(CONFIG_SDL)
1557         DISPLAY_TYPE_SDL,
1558 #endif
1559 #if defined(CONFIG_COCOA)
1560         DISPLAY_TYPE_COCOA
1561 #endif
1562     };
1563     int i;
1564 
1565     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
1566         if (dpys[prio[i]] == NULL) {
1567             Error *local_err = NULL;
1568             int rv = ui_module_load(DisplayType_str(prio[i]), &local_err);
1569             if (rv < 0) {
1570                 error_report_err(local_err);
1571             }
1572         }
1573         if (dpys[prio[i]] == NULL) {
1574             continue;
1575         }
1576         opts->type = prio[i];
1577         return true;
1578     }
1579     return false;
1580 }
1581 
1582 void qemu_display_early_init(DisplayOptions *opts)
1583 {
1584     assert(opts->type < DISPLAY_TYPE__MAX);
1585     if (opts->type == DISPLAY_TYPE_NONE) {
1586         return;
1587     }
1588     if (dpys[opts->type] == NULL) {
1589         Error *local_err = NULL;
1590         int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
1591         if (rv < 0) {
1592             error_report_err(local_err);
1593         }
1594     }
1595     if (dpys[opts->type] == NULL) {
1596         error_report("Display '%s' is not available.",
1597                      DisplayType_str(opts->type));
1598         exit(1);
1599     }
1600     if (dpys[opts->type]->early_init) {
1601         dpys[opts->type]->early_init(opts);
1602     }
1603 }
1604 
1605 void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
1606 {
1607     assert(opts->type < DISPLAY_TYPE__MAX);
1608     if (opts->type == DISPLAY_TYPE_NONE) {
1609         return;
1610     }
1611     assert(dpys[opts->type] != NULL);
1612     dpys[opts->type]->init(ds, opts);
1613 }
1614 
1615 const char *qemu_display_get_vc(DisplayOptions *opts)
1616 {
1617 #ifdef CONFIG_PIXMAN
1618     const char *vc = "vc:80Cx24C";
1619 #else
1620     const char *vc = NULL;
1621 #endif
1622 
1623     assert(opts->type < DISPLAY_TYPE__MAX);
1624     if (dpys[opts->type] && dpys[opts->type]->vc) {
1625         vc = dpys[opts->type]->vc;
1626     }
1627     return vc;
1628 }
1629 
1630 void qemu_display_help(void)
1631 {
1632     int idx;
1633 
1634     printf("Available display backend types:\n");
1635     printf("none\n");
1636     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
1637         if (!dpys[idx]) {
1638             Error *local_err = NULL;
1639             int rv = ui_module_load(DisplayType_str(idx), &local_err);
1640             if (rv < 0) {
1641                 error_report_err(local_err);
1642             }
1643         }
1644         if (dpys[idx]) {
1645             printf("%s\n",  DisplayType_str(dpys[idx]->type));
1646         }
1647     }
1648 }
1649