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