xref: /openbmc/qemu/ui/console.c (revision e1324ec9465efbd7ca95c4ad29d3d3cf102d05c3)
128ecbaeeSPaolo Bonzini /*
228ecbaeeSPaolo Bonzini  * QEMU graphical console
328ecbaeeSPaolo Bonzini  *
428ecbaeeSPaolo Bonzini  * Copyright (c) 2004 Fabrice Bellard
528ecbaeeSPaolo Bonzini  *
628ecbaeeSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
728ecbaeeSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
828ecbaeeSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
928ecbaeeSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1028ecbaeeSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1128ecbaeeSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1228ecbaeeSPaolo Bonzini  *
1328ecbaeeSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1428ecbaeeSPaolo Bonzini  * all copies or substantial portions of the Software.
1528ecbaeeSPaolo Bonzini  *
1628ecbaeeSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1728ecbaeeSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1828ecbaeeSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1928ecbaeeSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2028ecbaeeSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2128ecbaeeSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2228ecbaeeSPaolo Bonzini  * THE SOFTWARE.
2328ecbaeeSPaolo Bonzini  */
24e688df6bSMarkus Armbruster 
25e16f4c87SPeter Maydell #include "qemu/osdep.h"
2628ecbaeeSPaolo Bonzini #include "ui/console.h"
27aa2beaa1SGerd Hoffmann #include "hw/qdev-core.h"
28e688df6bSMarkus Armbruster #include "qapi/error.h"
299af23989SMarkus Armbruster #include "qapi/qapi-commands-ui.h"
30098d57e7SMarc-André Lureau #include "qapi/visitor.h"
3168ba85ceSMarkus Armbruster #include "qemu/coroutine.h"
324f2c765bSMarc-André Lureau #include "qemu/error-report.h"
33014b00ccSVolker Rümelin #include "qemu/main-loop.h"
340b8fa32fSMarkus Armbruster #include "qemu/module.h"
35922a01a0SMarkus Armbruster #include "qemu/option.h"
36014b00ccSVolker Rümelin #include "chardev/char.h"
37ac86048bSStefan Weil #include "trace.h"
38a77549b3SGerd Hoffmann #include "exec/memory.h"
39db1015e9SEduardo Habkost #include "qom/object.h"
4028ecbaeeSPaolo Bonzini #include "qemu/memfd.h"
416f110819SMarc-André Lureau 
4228ecbaeeSPaolo Bonzini #include "console-priv.h"
43c105d60fSMarc-André Lureau 
44e265917cSMarc-André Lureau OBJECT_DEFINE_ABSTRACT_TYPE(QemuConsole, qemu_console, QEMU_CONSOLE, OBJECT)
45b208f745SMarc-André Lureau 
46b208f745SMarc-André Lureau typedef struct QemuGraphicConsole {
4758d58708SMarc-André Lureau     QemuConsole parent;
4858d58708SMarc-André Lureau 
4958d58708SMarc-André Lureau     Object *device;
5058d58708SMarc-André Lureau     uint32_t head;
5158d58708SMarc-André Lureau 
52a418e7aeSAkihiko Odaki     QEMUCursor *cursor;
53a418e7aeSAkihiko Odaki     int cursor_x, cursor_y;
54b208f745SMarc-André Lureau     bool cursor_on;
55b208f745SMarc-André Lureau } QemuGraphicConsole;
56b208f745SMarc-André Lureau 
57b208f745SMarc-André Lureau typedef QemuConsoleClass QemuGraphicConsoleClass;
58b208f745SMarc-André Lureau 
59b208f745SMarc-André Lureau OBJECT_DEFINE_TYPE(QemuGraphicConsole, qemu_graphic_console, QEMU_GRAPHIC_CONSOLE, QEMU_CONSOLE)
6027be5587SGerd Hoffmann 
611246b259SStefan Weil struct DisplayState {
620f7b2864SGerd Hoffmann     QEMUTimer *gui_timer;
630f7b2864SGerd Hoffmann     uint64_t last_update;
640f7b2864SGerd Hoffmann     uint64_t update_interval;
6527be5587SGerd Hoffmann     bool refreshing;
6627be5587SGerd Hoffmann 
6727be5587SGerd Hoffmann     QLIST_HEAD(, DisplayChangeListener) listeners;
6827be5587SGerd Hoffmann };
6928ecbaeeSPaolo Bonzini 
70eae3eb3eSPaolo Bonzini static DisplayState *display_state;
71cd6cd8faSGerd Hoffmann static QTAILQ_HEAD(, QemuConsole) consoles =
7228ecbaeeSPaolo Bonzini     QTAILQ_HEAD_INITIALIZER(consoles);
730f7b2864SGerd Hoffmann 
745209089fSGerd Hoffmann static void dpy_refresh(DisplayState *s);
75ebced091SMarc-André Lureau static DisplayState *get_alloc_displaystate(void);
764b7b661dSMarc-André Lureau static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl);
774b7b661dSMarc-André Lureau static bool console_compatible_with(QemuConsole *con,
78f9411aaeSMarc-André Lureau                                     DisplayChangeListener *dcl, Error **errp);
79cfde05d1SMarc-André Lureau static QemuConsole *qemu_graphic_console_lookup_unused(void);
8064840c66SGerd Hoffmann static void dpy_set_ui_info_timer(void *opaque);
8198a9ad90SGerd Hoffmann 
gui_update(void * opaque)8298a9ad90SGerd Hoffmann static void gui_update(void *opaque)
830f7b2864SGerd Hoffmann {
840f7b2864SGerd Hoffmann     uint64_t interval = GUI_REFRESH_INTERVAL_IDLE;
8598a9ad90SGerd Hoffmann     uint64_t dcl_interval;
8698a9ad90SGerd Hoffmann     DisplayState *ds = opaque;
8798a9ad90SGerd Hoffmann     DisplayChangeListener *dcl;
880f7b2864SGerd Hoffmann 
8998a9ad90SGerd Hoffmann     ds->refreshing = true;
900f7b2864SGerd Hoffmann     dpy_refresh(ds);
9198a9ad90SGerd Hoffmann     ds->refreshing = false;
9298a9ad90SGerd Hoffmann 
930f7b2864SGerd Hoffmann     QLIST_FOREACH(dcl, &ds->listeners, next) {
940f7b2864SGerd Hoffmann         dcl_interval = dcl->update_interval ?
950f7b2864SGerd Hoffmann             dcl->update_interval : GUI_REFRESH_INTERVAL_DEFAULT;
960f7b2864SGerd Hoffmann         if (interval > dcl_interval) {
9798a9ad90SGerd Hoffmann             interval = dcl_interval;
9898a9ad90SGerd Hoffmann         }
990f7b2864SGerd Hoffmann     }
1000f7b2864SGerd Hoffmann     if (ds->update_interval != interval) {
1010f7b2864SGerd Hoffmann         ds->update_interval = interval;
1020f7b2864SGerd Hoffmann         trace_console_refresh(interval);
103bc72ad67SAlex Bligh     }
104bc72ad67SAlex Bligh     ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
10598a9ad90SGerd Hoffmann     timer_mod(ds->gui_timer, ds->last_update + interval);
10698a9ad90SGerd Hoffmann }
10798a9ad90SGerd Hoffmann 
gui_setup_refresh(DisplayState * ds)10898a9ad90SGerd Hoffmann static void gui_setup_refresh(DisplayState *ds)
10998a9ad90SGerd Hoffmann {
11098a9ad90SGerd Hoffmann     DisplayChangeListener *dcl;
11198a9ad90SGerd Hoffmann     bool need_timer = false;
11298a9ad90SGerd Hoffmann 
11398a9ad90SGerd Hoffmann     QLIST_FOREACH(dcl, &ds->listeners, next) {
11498a9ad90SGerd Hoffmann         if (dcl->ops->dpy_refresh != NULL) {
11598a9ad90SGerd Hoffmann             need_timer = true;
11698a9ad90SGerd Hoffmann         }
11798a9ad90SGerd Hoffmann     }
11898a9ad90SGerd Hoffmann 
119bc72ad67SAlex Bligh     if (need_timer && ds->gui_timer == NULL) {
120bc72ad67SAlex Bligh         ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
12198a9ad90SGerd Hoffmann         timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
12298a9ad90SGerd Hoffmann     }
123bc72ad67SAlex Bligh     if (!need_timer && ds->gui_timer != NULL) {
12498a9ad90SGerd Hoffmann         timer_free(ds->gui_timer);
12598a9ad90SGerd Hoffmann         ds->gui_timer = NULL;
12698a9ad90SGerd Hoffmann     }
12798a9ad90SGerd Hoffmann }
1284d631621SMarc-André Lureau 
graphic_hw_update_done(QemuConsole * con)1294d631621SMarc-André Lureau void graphic_hw_update_done(QemuConsole *con)
1306fc5183aSGerd Hoffmann {
131d6ee15adSPaolo Bonzini     if (con) {
1324d631621SMarc-André Lureau         qemu_co_enter_all(&con->dump_queue, NULL);
1336fc5183aSGerd Hoffmann     }
1344d631621SMarc-André Lureau }
1351dbfa005SGerd Hoffmann 
graphic_hw_update(QemuConsole * con)13628ecbaeeSPaolo Bonzini void graphic_hw_update(QemuConsole *con)
1374d631621SMarc-André Lureau {
1381dbfa005SGerd Hoffmann     bool async = false;
1391cd8b948Slichun     if (!con) {
1401dbfa005SGerd Hoffmann         return;
1411cd8b948Slichun     }
142380cd056SGerd Hoffmann     if (con->hw_ops->gfx_update) {
1434d631621SMarc-André Lureau         con->hw_ops->gfx_update(con->hw);
1444d631621SMarc-André Lureau         async = con->hw_ops->gfx_update_async;
1454d631621SMarc-André Lureau     }
1464d631621SMarc-André Lureau     if (!async) {
1471dbfa005SGerd Hoffmann         graphic_hw_update_done(con);
14828ecbaeeSPaolo Bonzini     }
14928ecbaeeSPaolo Bonzini }
1504f2c765bSMarc-André Lureau 
graphic_hw_update_bh(void * con)1514f2c765bSMarc-André Lureau static void graphic_hw_update_bh(void *con)
1524f2c765bSMarc-André Lureau {
1534f2c765bSMarc-André Lureau     graphic_hw_update(con);
1544f2c765bSMarc-André Lureau }
1554f2c765bSMarc-André Lureau 
qemu_console_co_wait_update(QemuConsole * con)1564f2c765bSMarc-André Lureau void qemu_console_co_wait_update(QemuConsole *con)
1574f2c765bSMarc-André Lureau {
1584f2c765bSMarc-André Lureau     if (qemu_co_queue_empty(&con->dump_queue)) {
1594f2c765bSMarc-André Lureau         /* Defer the update, it will restart the pending coroutines */
1604f2c765bSMarc-André Lureau         aio_bh_schedule_oneshot(qemu_get_aio_context(),
1614f2c765bSMarc-André Lureau                                 graphic_hw_update_bh, con);
1624f2c765bSMarc-André Lureau     }
1634f2c765bSMarc-André Lureau     qemu_co_queue_wait(&con->dump_queue, NULL);
1644f2c765bSMarc-André Lureau 
1654f2c765bSMarc-André Lureau }
166a9b1e471SMarc-André Lureau 
graphic_hw_gl_unblock_timer(void * opaque)167a9b1e471SMarc-André Lureau static void graphic_hw_gl_unblock_timer(void *opaque)
168a9b1e471SMarc-André Lureau {
169a9b1e471SMarc-André Lureau     warn_report("console: no gl-unblock within one second");
170a9b1e471SMarc-André Lureau }
171bba19b88SGerd Hoffmann 
graphic_hw_gl_block(QemuConsole * con,bool block)172bba19b88SGerd Hoffmann void graphic_hw_gl_block(QemuConsole *con, bool block)
173a9b1e471SMarc-André Lureau {
174f607867cSGerd Hoffmann     uint64_t timeout;
175f607867cSGerd Hoffmann     assert(con != NULL);
176a4ddc314SMarc-André Lureau 
177a4ddc314SMarc-André Lureau     if (block) {
178a4ddc314SMarc-André Lureau         con->gl_block++;
179a4ddc314SMarc-André Lureau     } else {
180bba19b88SGerd Hoffmann         con->gl_block--;
181a4ddc314SMarc-André Lureau     }
182a4ddc314SMarc-André Lureau     assert(con->gl_block >= 0);
183a4ddc314SMarc-André Lureau     if (!con->hw_ops->gl_block) {
184a4ddc314SMarc-André Lureau         return;
185a4ddc314SMarc-André Lureau     }
186a4ddc314SMarc-André Lureau     if ((block && con->gl_block != 1) || (!block && con->gl_block != 0)) {
187a4ddc314SMarc-André Lureau         return;
188a4ddc314SMarc-André Lureau     }
189a9b1e471SMarc-André Lureau     con->hw_ops->gl_block(con->hw, block);
190a9b1e471SMarc-André Lureau 
191a9b1e471SMarc-André Lureau     if (block) {
192a9b1e471SMarc-André Lureau         timeout = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
193a9b1e471SMarc-André Lureau         timeout += 1000; /* one sec */
194a9b1e471SMarc-André Lureau         timer_mod(con->gl_unblock_timer, timeout);
195a9b1e471SMarc-André Lureau     } else {
196a9b1e471SMarc-André Lureau         timer_del(con->gl_unblock_timer);
197bba19b88SGerd Hoffmann     }
198bba19b88SGerd Hoffmann }
199b3cb21b9SSamuel Thibault 
qemu_console_get_window_id(QemuConsole * con)200b3cb21b9SSamuel Thibault int qemu_console_get_window_id(QemuConsole *con)
201b3cb21b9SSamuel Thibault {
202b3cb21b9SSamuel Thibault     return con->window_id;
203b3cb21b9SSamuel Thibault }
204b3cb21b9SSamuel Thibault 
qemu_console_set_window_id(QemuConsole * con,int window_id)205b3cb21b9SSamuel Thibault void qemu_console_set_window_id(QemuConsole *con, int window_id)
206b3cb21b9SSamuel Thibault {
207b3cb21b9SSamuel Thibault     con->window_id = window_id;
208b3cb21b9SSamuel Thibault }
2091dbfa005SGerd Hoffmann 
graphic_hw_invalidate(QemuConsole * con)21028ecbaeeSPaolo Bonzini void graphic_hw_invalidate(QemuConsole *con)
211380cd056SGerd Hoffmann {
212380cd056SGerd Hoffmann     if (con && con->hw_ops->invalidate) {
2131dbfa005SGerd Hoffmann         con->hw_ops->invalidate(con->hw);
21428ecbaeeSPaolo Bonzini     }
21528ecbaeeSPaolo Bonzini }
2161dbfa005SGerd Hoffmann 
graphic_hw_text_update(QemuConsole * con,console_ch_t * chardata)21728ecbaeeSPaolo Bonzini void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
218380cd056SGerd Hoffmann {
219380cd056SGerd Hoffmann     if (con && con->hw_ops->text_update) {
220380cd056SGerd Hoffmann         con->hw_ops->text_update(con->hw, chardata);
22128ecbaeeSPaolo Bonzini     }
22228ecbaeeSPaolo Bonzini }
22326b032b9SMarc-André Lureau 
displaychangelistener_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface,bool update)224c84ab0a5SMarc-André Lureau static void displaychangelistener_gfx_switch(DisplayChangeListener *dcl,
225c84ab0a5SMarc-André Lureau                                              struct DisplaySurface *new_surface,
22626b032b9SMarc-André Lureau                                              bool update)
22726b032b9SMarc-André Lureau {
22826b032b9SMarc-André Lureau     if (dcl->ops->dpy_gfx_switch) {
22926b032b9SMarc-André Lureau         dcl->ops->dpy_gfx_switch(dcl, new_surface);
230c84ab0a5SMarc-André Lureau     }
231c84ab0a5SMarc-André Lureau 
232c84ab0a5SMarc-André Lureau     if (update && dcl->ops->dpy_gfx_update) {
233c84ab0a5SMarc-André Lureau         dcl->ops->dpy_gfx_update(dcl, 0, 0,
234c84ab0a5SMarc-André Lureau                                  surface_width(new_surface),
235c84ab0a5SMarc-André Lureau                                  surface_height(new_surface));
23626b032b9SMarc-André Lureau     }
23726b032b9SMarc-André Lureau }
238589089feSMarc-André Lureau 
dpy_gfx_create_texture(QemuConsole * con,DisplaySurface * surface)239589089feSMarc-André Lureau static void dpy_gfx_create_texture(QemuConsole *con, DisplaySurface *surface)
240589089feSMarc-André Lureau {
241589089feSMarc-André Lureau     if (con->gl && con->gl->ops->dpy_gl_ctx_create_texture) {
242589089feSMarc-André Lureau         con->gl->ops->dpy_gl_ctx_create_texture(con->gl, surface);
243589089feSMarc-André Lureau     }
244589089feSMarc-André Lureau }
245589089feSMarc-André Lureau 
dpy_gfx_destroy_texture(QemuConsole * con,DisplaySurface * surface)246589089feSMarc-André Lureau static void dpy_gfx_destroy_texture(QemuConsole *con, DisplaySurface *surface)
247589089feSMarc-André Lureau {
248589089feSMarc-André Lureau     if (con->gl && con->gl->ops->dpy_gl_ctx_destroy_texture) {
249589089feSMarc-André Lureau         con->gl->ops->dpy_gl_ctx_destroy_texture(con->gl, surface);
250589089feSMarc-André Lureau     }
251589089feSMarc-André Lureau }
252589089feSMarc-André Lureau 
dpy_gfx_update_texture(QemuConsole * con,DisplaySurface * surface,int x,int y,int w,int h)253589089feSMarc-André Lureau static void dpy_gfx_update_texture(QemuConsole *con, DisplaySurface *surface,
254589089feSMarc-André Lureau                                    int x, int y, int w, int h)
255589089feSMarc-André Lureau {
256589089feSMarc-André Lureau     if (con->gl && con->gl->ops->dpy_gl_ctx_update_texture) {
257589089feSMarc-André Lureau         con->gl->ops->dpy_gl_ctx_update_texture(con->gl, surface, x, y, w, h);
258589089feSMarc-André Lureau     }
25926b032b9SMarc-André Lureau }
260ebced091SMarc-André Lureau 
displaychangelistener_display_console(DisplayChangeListener * dcl,Error ** errp)2614b7b661dSMarc-André Lureau static void displaychangelistener_display_console(DisplayChangeListener *dcl,
262ebced091SMarc-André Lureau                                                   Error **errp)
263ebced091SMarc-André Lureau {
264ebced091SMarc-André Lureau     static const char nodev[] =
265ebced091SMarc-André Lureau         "This VM has no graphic display device.";
266e99441a3SAkihiko Odaki     static DisplaySurface *dummy;
267ebced091SMarc-André Lureau     QemuConsole *con = dcl->con;
2684b7b661dSMarc-André Lureau 
269ebced091SMarc-André Lureau     if (!con || !console_compatible_with(con, dcl, errp)) {
270ebced091SMarc-André Lureau         if (!dummy) {
271ebced091SMarc-André Lureau             dummy = qemu_create_placeholder_surface(640, 480, nodev);
272589089feSMarc-André Lureau         }
273589089feSMarc-André Lureau         if (con) {
274589089feSMarc-André Lureau             dpy_gfx_create_texture(con, dummy);
275c84ab0a5SMarc-André Lureau         }
276ebced091SMarc-André Lureau         displaychangelistener_gfx_switch(dcl, dummy, TRUE);
277ebced091SMarc-André Lureau         return;
278ebced091SMarc-André Lureau     }
279e1c676a2SMarc-André Lureau 
280e1c676a2SMarc-André Lureau     dpy_gfx_create_texture(con, con->surface);
281e1c676a2SMarc-André Lureau     displaychangelistener_gfx_switch(dcl, con->surface,
282e1c676a2SMarc-André Lureau                                      con->scanout.kind == SCANOUT_SURFACE);
283ebced091SMarc-André Lureau 
284ebced091SMarc-André Lureau     if (con->scanout.kind == SCANOUT_DMABUF &&
285ebced091SMarc-André Lureau         displaychangelistener_has_dmabuf(dcl)) {
286ebced091SMarc-André Lureau         dcl->ops->dpy_gl_scanout_dmabuf(dcl, con->scanout.dmabuf);
287ebced091SMarc-André Lureau     } else if (con->scanout.kind == SCANOUT_TEXTURE &&
288ebced091SMarc-André Lureau                dcl->ops->dpy_gl_scanout_texture) {
289ebced091SMarc-André Lureau         dcl->ops->dpy_gl_scanout_texture(dcl,
290ebced091SMarc-André Lureau                                          con->scanout.texture.backing_id,
291ebced091SMarc-André Lureau                                          con->scanout.texture.backing_y_0_top,
292ebced091SMarc-André Lureau                                          con->scanout.texture.backing_width,
293ebced091SMarc-André Lureau                                          con->scanout.texture.backing_height,
294ebced091SMarc-André Lureau                                          con->scanout.texture.x,
295ebced091SMarc-André Lureau                                          con->scanout.texture.y,
296bf41ab61SMarc-André Lureau                                          con->scanout.texture.width,
297bf41ab61SMarc-André Lureau                                          con->scanout.texture.height,
298ebced091SMarc-André Lureau                                          con->scanout.texture.d3d_tex2d);
299ebced091SMarc-André Lureau     }
300ebced091SMarc-André Lureau }
301f7ce755dSMarc-André Lureau 
qemu_text_console_put_keysym(QemuTextConsole * s,int keysym)302f7ce755dSMarc-André Lureau void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym)
303f7ce755dSMarc-André Lureau {
304f7ce755dSMarc-André Lureau     qemu_text_console_handle_keysym(s, keysym);
305f7ce755dSMarc-André Lureau }
3067fb1cf16SEric Blake 
30750ef4679SGerd Hoffmann static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
30850ef4679SGerd Hoffmann     [Q_KEY_CODE_UP]     = QEMU_KEY_UP,
30950ef4679SGerd Hoffmann     [Q_KEY_CODE_DOWN]   = QEMU_KEY_DOWN,
31050ef4679SGerd Hoffmann     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_RIGHT,
31150ef4679SGerd Hoffmann     [Q_KEY_CODE_LEFT]   = QEMU_KEY_LEFT,
31250ef4679SGerd Hoffmann     [Q_KEY_CODE_HOME]   = QEMU_KEY_HOME,
31350ef4679SGerd Hoffmann     [Q_KEY_CODE_END]    = QEMU_KEY_END,
31450ef4679SGerd Hoffmann     [Q_KEY_CODE_PGUP]   = QEMU_KEY_PAGEUP,
31550ef4679SGerd Hoffmann     [Q_KEY_CODE_PGDN]   = QEMU_KEY_PAGEDOWN,
316df6322a8SCal Peake     [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
317344aa283SThomas Huth     [Q_KEY_CODE_TAB]    = QEMU_KEY_TAB,
31850ef4679SGerd Hoffmann     [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
31950ef4679SGerd Hoffmann };
320da024b1eSGerd Hoffmann 
321da024b1eSGerd Hoffmann static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
322da024b1eSGerd Hoffmann     [Q_KEY_CODE_UP]     = QEMU_KEY_CTRL_UP,
323da024b1eSGerd Hoffmann     [Q_KEY_CODE_DOWN]   = QEMU_KEY_CTRL_DOWN,
324da024b1eSGerd Hoffmann     [Q_KEY_CODE_RIGHT]  = QEMU_KEY_CTRL_RIGHT,
325da024b1eSGerd Hoffmann     [Q_KEY_CODE_LEFT]   = QEMU_KEY_CTRL_LEFT,
326da024b1eSGerd Hoffmann     [Q_KEY_CODE_HOME]   = QEMU_KEY_CTRL_HOME,
327da024b1eSGerd Hoffmann     [Q_KEY_CODE_END]    = QEMU_KEY_CTRL_END,
328da024b1eSGerd Hoffmann     [Q_KEY_CODE_PGUP]   = QEMU_KEY_CTRL_PAGEUP,
329da024b1eSGerd Hoffmann     [Q_KEY_CODE_PGDN]   = QEMU_KEY_CTRL_PAGEDOWN,
330da024b1eSGerd Hoffmann };
331cc6ba2c6SMarc-André Lureau 
qemu_text_console_put_qcode(QemuTextConsole * s,int qcode,bool ctrl)33250ef4679SGerd Hoffmann bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl)
33350ef4679SGerd Hoffmann {
33450ef4679SGerd Hoffmann     int keysym;
335da024b1eSGerd Hoffmann 
33650ef4679SGerd Hoffmann     keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
33750ef4679SGerd Hoffmann     if (keysym == 0) {
33850ef4679SGerd Hoffmann         return false;
339cc6ba2c6SMarc-André Lureau     }
34050ef4679SGerd Hoffmann     qemu_text_console_put_keysym(s, keysym);
34150ef4679SGerd Hoffmann     return true;
34250ef4679SGerd Hoffmann }
343cc6ba2c6SMarc-André Lureau 
qemu_text_console_put_string(QemuTextConsole * s,const char * str,int len)344bdef9724SGerd Hoffmann void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len)
345bdef9724SGerd Hoffmann {
346bdef9724SGerd Hoffmann     int i;
347bdef9724SGerd Hoffmann 
348cc6ba2c6SMarc-André Lureau     for (i = 0; i < len && str[i]; i++) {
349bdef9724SGerd Hoffmann         qemu_text_console_put_keysym(s, str[i]);
350bdef9724SGerd Hoffmann     }
351bdef9724SGerd Hoffmann }
352098d57e7SMarc-André Lureau 
353c105d60fSMarc-André Lureau static void
qemu_console_register(QemuConsole * c)35428ecbaeeSPaolo Bonzini qemu_console_register(QemuConsole *c)
35528ecbaeeSPaolo Bonzini {
35628ecbaeeSPaolo Bonzini     int i;
357cd6cd8faSGerd Hoffmann 
358098d57e7SMarc-André Lureau     if (QTAILQ_EMPTY(&consoles)) {
359098d57e7SMarc-André Lureau         c->index = 0;
360c105d60fSMarc-André Lureau         QTAILQ_INSERT_TAIL(&consoles, c, next);
361eae3eb3eSPaolo Bonzini     } else if (!QEMU_IS_GRAPHIC_CONSOLE(c) || phase_check(PHASE_MACHINE_READY)) {
362098d57e7SMarc-André Lureau         QemuConsole *last = QTAILQ_LAST(&consoles);
363098d57e7SMarc-André Lureau         c->index = last->index + 1;
36428ecbaeeSPaolo Bonzini         QTAILQ_INSERT_TAIL(&consoles, c, next);
3659588d67eSGerd Hoffmann     } else {
3669588d67eSGerd Hoffmann         /*
3679588d67eSGerd Hoffmann          * HACK: Put graphical consoles before text consoles.
3689588d67eSGerd Hoffmann          *
3699588d67eSGerd Hoffmann          * Only do that for coldplugged devices.  After initial device
3709588d67eSGerd Hoffmann          * initialization we will not renumber the consoles any more.
371098d57e7SMarc-André Lureau          */
372cd6cd8faSGerd Hoffmann         QemuConsole *it = QTAILQ_FIRST(&consoles);
373c105d60fSMarc-André Lureau 
374098d57e7SMarc-André Lureau         while (QTAILQ_NEXT(it, next) != NULL && QEMU_IS_GRAPHIC_CONSOLE(it)) {
37528ecbaeeSPaolo Bonzini             it = QTAILQ_NEXT(it, next);
376c105d60fSMarc-André Lureau         }
377cd6cd8faSGerd Hoffmann         if (QEMU_IS_GRAPHIC_CONSOLE(it)) {
378098d57e7SMarc-André Lureau             /* have no text consoles */
379098d57e7SMarc-André Lureau             c->index = it->index + 1;
380cd6cd8faSGerd Hoffmann             QTAILQ_INSERT_AFTER(&consoles, it, c, next);
381098d57e7SMarc-André Lureau         } else {
382098d57e7SMarc-André Lureau             c->index = it->index;
383cd6cd8faSGerd Hoffmann             QTAILQ_INSERT_BEFORE(it, c, next);
384098d57e7SMarc-André Lureau             /* renumber text consoles */
385098d57e7SMarc-André Lureau             for (i = c->index + 1; it != NULL; it = QTAILQ_NEXT(it, next), i++) {
386cd6cd8faSGerd Hoffmann                 it->index = i;
387cd6cd8faSGerd Hoffmann             }
38828ecbaeeSPaolo Bonzini         }
38928ecbaeeSPaolo Bonzini     }
39028ecbaeeSPaolo Bonzini }
391e265917cSMarc-André Lureau 
392e265917cSMarc-André Lureau static void
qemu_console_finalize(Object * obj)393e265917cSMarc-André Lureau qemu_console_finalize(Object *obj)
394cfde05d1SMarc-André Lureau {
395cfde05d1SMarc-André Lureau     QemuConsole *c = QEMU_CONSOLE(obj);
396463c6b19SMarc-André Lureau 
397463c6b19SMarc-André Lureau     /* TODO: check this code path, and unregister from consoles */
398463c6b19SMarc-André Lureau     g_clear_pointer(&c->surface, qemu_free_displaysurface);
399cfde05d1SMarc-André Lureau     g_clear_pointer(&c->gl_unblock_timer, timer_free);
400098d57e7SMarc-André Lureau     g_clear_pointer(&c->ui_timer, timer_free);
401098d57e7SMarc-André Lureau }
402098d57e7SMarc-André Lureau 
403e265917cSMarc-André Lureau static void
qemu_console_class_init(ObjectClass * oc,void * data)404e265917cSMarc-André Lureau qemu_console_class_init(ObjectClass *oc, void *data)
405e265917cSMarc-André Lureau {
406e265917cSMarc-André Lureau }
407e265917cSMarc-André Lureau 
408e265917cSMarc-André Lureau static void
qemu_console_init(Object * obj)409e265917cSMarc-André Lureau qemu_console_init(Object *obj)
410098d57e7SMarc-André Lureau {
411098d57e7SMarc-André Lureau     QemuConsole *c = QEMU_CONSOLE(obj);
412098d57e7SMarc-André Lureau     DisplayState *ds = get_alloc_displaystate();
413098d57e7SMarc-André Lureau 
414098d57e7SMarc-André Lureau     qemu_co_queue_init(&c->dump_queue);
415098d57e7SMarc-André Lureau     c->ds = ds;
416cfde05d1SMarc-André Lureau     c->window_id = -1;
417cfde05d1SMarc-André Lureau     c->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
418ba0ec5c2SMarc-André Lureau                                dpy_set_ui_info_timer, c);
419098d57e7SMarc-André Lureau     qemu_console_register(c);
420098d57e7SMarc-André Lureau }
421b208f745SMarc-André Lureau 
422b208f745SMarc-André Lureau static void
qemu_graphic_console_finalize(Object * obj)423b208f745SMarc-André Lureau qemu_graphic_console_finalize(Object *obj)
42458d58708SMarc-André Lureau {
42558d58708SMarc-André Lureau     QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
42658d58708SMarc-André Lureau 
42758d58708SMarc-André Lureau     g_clear_pointer(&c->device, object_unref);
42858d58708SMarc-André Lureau }
42958d58708SMarc-André Lureau 
43058d58708SMarc-André Lureau static void
qemu_graphic_console_prop_get_head(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)43158d58708SMarc-André Lureau qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name,
43258d58708SMarc-André Lureau                                    void *opaque, Error **errp)
43358d58708SMarc-André Lureau {
43458d58708SMarc-André Lureau     QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(obj);
43558d58708SMarc-André Lureau 
436b208f745SMarc-André Lureau     visit_type_uint32(v, name, &c->head, errp);
437b208f745SMarc-André Lureau }
438b208f745SMarc-André Lureau 
439b208f745SMarc-André Lureau static void
qemu_graphic_console_class_init(ObjectClass * oc,void * data)440b208f745SMarc-André Lureau qemu_graphic_console_class_init(ObjectClass *oc, void *data)
44158d58708SMarc-André Lureau {
44258d58708SMarc-André Lureau     object_class_property_add_link(oc, "device", TYPE_DEVICE,
44358d58708SMarc-André Lureau                                    offsetof(QemuGraphicConsole, device),
44458d58708SMarc-André Lureau                                    object_property_allow_set_link,
44558d58708SMarc-André Lureau                                    OBJ_PROP_LINK_STRONG);
44658d58708SMarc-André Lureau     object_class_property_add(oc, "head", "uint32",
44758d58708SMarc-André Lureau                               qemu_graphic_console_prop_get_head,
448b208f745SMarc-André Lureau                               NULL, NULL, NULL);
449b208f745SMarc-André Lureau }
450b208f745SMarc-André Lureau 
451b208f745SMarc-André Lureau static void
qemu_graphic_console_init(Object * obj)452b208f745SMarc-André Lureau qemu_graphic_console_init(Object *obj)
453b208f745SMarc-André Lureau {
454b208f745SMarc-André Lureau }
45509b4c198SMarc-André Lureau 
qemu_displaysurface_set_share_handle(DisplaySurface * surface,qemu_pixman_shareable handle,uint32_t offset)45609b4c198SMarc-André Lureau void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
45709b4c198SMarc-André Lureau                                           qemu_pixman_shareable handle,
45809b4c198SMarc-André Lureau                                           uint32_t offset)
45909b4c198SMarc-André Lureau {
46009b4c198SMarc-André Lureau     assert(surface->share_handle == SHAREABLE_NONE);
46109b4c198SMarc-André Lureau 
46209b4c198SMarc-André Lureau     surface->share_handle = handle;
46309b4c198SMarc-André Lureau     surface->share_handle_offset = offset;
46409b4c198SMarc-André Lureau 
46509b4c198SMarc-André Lureau }
466da229ef3SGerd Hoffmann 
qemu_create_displaysurface(int width,int height)46728ecbaeeSPaolo Bonzini DisplaySurface *qemu_create_displaysurface(int width, int height)
46809b4c198SMarc-André Lureau {
46909b4c198SMarc-André Lureau     trace_displaysurface_create(width, height);
47009b4c198SMarc-André Lureau 
47109b4c198SMarc-André Lureau     return qemu_create_displaysurface_from(
47209b4c198SMarc-André Lureau         width, height,
473da229ef3SGerd Hoffmann         PIXMAN_x8r8g8b8,
47409b4c198SMarc-André Lureau         width * 4, NULL
47509b4c198SMarc-André Lureau     );
47609b4c198SMarc-André Lureau }
47709b4c198SMarc-André Lureau 
qemu_create_displaysurface_from(int width,int height,pixman_format_code_t format,int linesize,uint8_t * data)47809b4c198SMarc-André Lureau DisplaySurface *qemu_create_displaysurface_from(int width, int height,
47909b4c198SMarc-André Lureau                                                 pixman_format_code_t format,
48009b4c198SMarc-André Lureau                                                 int linesize, uint8_t *data)
481eb69442aSMarc-André Lureau {
48209b4c198SMarc-André Lureau     DisplaySurface *surface = g_new0(DisplaySurface, 1);
48309b4c198SMarc-André Lureau 
48409b4c198SMarc-André Lureau     trace_displaysurface_create_from(surface, width, height, format);
485eb69442aSMarc-André Lureau     surface->share_handle = SHAREABLE_NONE;
486eb69442aSMarc-André Lureau 
48709b4c198SMarc-André Lureau     if (data) {
48809b4c198SMarc-André Lureau         surface->image = pixman_image_create_bits(format,
489*e1324ec9SMarc-André Lureau                                                   width, height,
490*e1324ec9SMarc-André Lureau                                                   (void *)data, linesize);
49109b4c198SMarc-André Lureau     } else {
49228ecbaeeSPaolo Bonzini         qemu_pixman_image_new_shareable(&surface->image,
49328ecbaeeSPaolo Bonzini                                         &surface->share_handle,
49428ecbaeeSPaolo Bonzini                                         "displaysurface",
49530f1e661SGerd Hoffmann                                         format,
49630f1e661SGerd Hoffmann                                         width,
49730f1e661SGerd Hoffmann                                         height,
49828ecbaeeSPaolo Bonzini                                         linesize,
49928ecbaeeSPaolo Bonzini                                         &error_abort);
50028ecbaeeSPaolo Bonzini         surface->flags = QEMU_ALLOCATED_FLAG;
50130f1e661SGerd Hoffmann     }
502ff174c67SMarc-André Lureau 
50328ecbaeeSPaolo Bonzini     assert(surface->image != NULL);
50428ecbaeeSPaolo Bonzini     return surface;
50528ecbaeeSPaolo Bonzini }
50628ecbaeeSPaolo Bonzini 
qemu_create_displaysurface_pixman(pixman_image_t * image)50728ecbaeeSPaolo Bonzini DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
50828ecbaeeSPaolo Bonzini {
50928ecbaeeSPaolo Bonzini     DisplaySurface *surface = g_new0(DisplaySurface, 1);
510ca58b45fSGerd Hoffmann 
511ca58b45fSGerd Hoffmann     trace_displaysurface_create_pixman(surface);
512ca58b45fSGerd Hoffmann     surface->share_handle = SHAREABLE_NONE;
513ca58b45fSGerd Hoffmann     surface->image = pixman_image_ref(image);
514ca58b45fSGerd Hoffmann 
515ca58b45fSGerd Hoffmann     return surface;
516ca58b45fSGerd Hoffmann }
517ca58b45fSGerd Hoffmann 
qemu_create_placeholder_surface(int w,int h,const char * msg)518ca58b45fSGerd Hoffmann DisplaySurface *qemu_create_placeholder_surface(int w, int h,
519ca58b45fSGerd Hoffmann                                                 const char *msg)
520b5a087b0SAkihiko Odaki {
521521a580dSGerd Hoffmann     DisplaySurface *surface = qemu_create_displaysurface(w, h);
522d3002b04SGerd Hoffmann #ifdef CONFIG_PIXMAN
523521a580dSGerd Hoffmann     pixman_color_t bg = QEMU_PIXMAN_COLOR_BLACK;
524d7e94796SMarc-André Lureau     pixman_color_t fg = QEMU_PIXMAN_COLOR_GRAY;
5251ece6777SMarc-André Lureau     pixman_image_t *glyph;
5261ece6777SMarc-André Lureau     int len, x, y, i;
527d3002b04SGerd Hoffmann 
528d3002b04SGerd Hoffmann     len = strlen(msg);
529d3002b04SGerd Hoffmann     x = (w / FONT_WIDTH  - len) / 2;
530d3002b04SGerd Hoffmann     y = (h / FONT_HEIGHT - 1)   / 2;
531521a580dSGerd Hoffmann     for (i = 0; i < len; i++) {
532521a580dSGerd Hoffmann         glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
533d3002b04SGerd Hoffmann         qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
534d3002b04SGerd Hoffmann                                  x+i, y, FONT_WIDTH, FONT_HEIGHT);
535d3002b04SGerd Hoffmann         qemu_pixman_image_unref(glyph);
536d3002b04SGerd Hoffmann     }
537d3002b04SGerd Hoffmann #endif
538d3002b04SGerd Hoffmann     surface->flags |= QEMU_PLACEHOLDER_FLAG;
539d7e94796SMarc-André Lureau     return surface;
540b5a087b0SAkihiko Odaki }
541d3002b04SGerd Hoffmann 
qemu_free_displaysurface(DisplaySurface * surface)542d3002b04SGerd Hoffmann void qemu_free_displaysurface(DisplaySurface *surface)
543d3002b04SGerd Hoffmann {
544da229ef3SGerd Hoffmann     if (surface == NULL) {
54528ecbaeeSPaolo Bonzini         return;
546da229ef3SGerd Hoffmann     }
54728ecbaeeSPaolo Bonzini     trace_displaysurface_free(surface);
54828ecbaeeSPaolo Bonzini     qemu_pixman_image_unref(surface->image);
549da229ef3SGerd Hoffmann     g_free(surface);
550da229ef3SGerd Hoffmann }
551da229ef3SGerd Hoffmann 
console_has_gl(QemuConsole * con)55228ecbaeeSPaolo Bonzini bool console_has_gl(QemuConsole *con)
55328ecbaeeSPaolo Bonzini {
55406020b95SGerd Hoffmann     return con->gl != NULL;
55506020b95SGerd Hoffmann }
55606020b95SGerd Hoffmann 
displaychangelistener_has_dmabuf(DisplayChangeListener * dcl)55706020b95SGerd Hoffmann static bool displaychangelistener_has_dmabuf(DisplayChangeListener *dcl)
55806020b95SGerd Hoffmann {
559d0e137bcSMarc-André Lureau     if (dcl->ops->dpy_has_dmabuf) {
560d0e137bcSMarc-André Lureau         return dcl->ops->dpy_has_dmabuf(dcl);
561d0e137bcSMarc-André Lureau     }
562d0e137bcSMarc-André Lureau 
563d0e137bcSMarc-André Lureau     if (dcl->ops->dpy_gl_scanout_dmabuf) {
564d0e137bcSMarc-André Lureau         return true;
565d0e137bcSMarc-André Lureau     }
566d0e137bcSMarc-André Lureau 
567d0e137bcSMarc-André Lureau     return false;
568d0e137bcSMarc-André Lureau }
569d0e137bcSMarc-André Lureau 
console_compatible_with(QemuConsole * con,DisplayChangeListener * dcl,Error ** errp)570d0e137bcSMarc-André Lureau static bool console_compatible_with(QemuConsole *con,
571d0e137bcSMarc-André Lureau                                     DisplayChangeListener *dcl, Error **errp)
5724b7b661dSMarc-André Lureau {
5735983fdf1SMarc-André Lureau     int flags;
5745983fdf1SMarc-André Lureau 
5755983fdf1SMarc-André Lureau     flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
5765983fdf1SMarc-André Lureau 
5775983fdf1SMarc-André Lureau     if (console_has_gl(con) &&
5785983fdf1SMarc-André Lureau         !con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
579a62c4a17SMarc-André Lureau         error_setg(errp, "Display %s is incompatible with the GL context",
580a62c4a17SMarc-André Lureau                    dcl->ops->dpy_name);
581398d1c91SMarc-André Lureau         return false;
582398d1c91SMarc-André Lureau     }
583398d1c91SMarc-André Lureau 
584398d1c91SMarc-André Lureau     if (flags & GRAPHIC_FLAGS_GL &&
585398d1c91SMarc-André Lureau         !console_has_gl(con)) {
5865983fdf1SMarc-André Lureau         error_setg(errp, "The console requires a GL context.");
5875983fdf1SMarc-André Lureau         return false;
5885983fdf1SMarc-André Lureau 
5895983fdf1SMarc-André Lureau     }
5905983fdf1SMarc-André Lureau 
5915983fdf1SMarc-André Lureau     if (flags & GRAPHIC_FLAGS_DMABUF &&
5925983fdf1SMarc-André Lureau         !displaychangelistener_has_dmabuf(dcl)) {
5935983fdf1SMarc-André Lureau         error_setg(errp, "The console requires display DMABUF support.");
5945983fdf1SMarc-André Lureau         return false;
5955983fdf1SMarc-André Lureau     }
5965983fdf1SMarc-André Lureau 
5975983fdf1SMarc-André Lureau     return true;
5985983fdf1SMarc-André Lureau }
5995983fdf1SMarc-André Lureau 
console_handle_touch_event(QemuConsole * con,struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],uint64_t num_slot,int width,int height,double x,double y,InputMultiTouchType type,Error ** errp)6005983fdf1SMarc-André Lureau void console_handle_touch_event(QemuConsole *con,
6015983fdf1SMarc-André Lureau                                 struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
602b6596785SBilal Elmoussaoui                                 uint64_t num_slot,
603b6596785SBilal Elmoussaoui                                 int width, int height,
604b6596785SBilal Elmoussaoui                                 double x, double y,
605b6596785SBilal Elmoussaoui                                 InputMultiTouchType type,
606b6596785SBilal Elmoussaoui                                 Error **errp)
607b6596785SBilal Elmoussaoui {
608b6596785SBilal Elmoussaoui     struct touch_slot *slot;
609b6596785SBilal Elmoussaoui     bool needs_sync = false;
610b6596785SBilal Elmoussaoui     int update;
611b6596785SBilal Elmoussaoui     int i;
612b6596785SBilal Elmoussaoui 
613b6596785SBilal Elmoussaoui     if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
614b6596785SBilal Elmoussaoui         error_setg(errp,
615b6596785SBilal Elmoussaoui                    "Unexpected touch slot number: % " PRId64" >= %d",
616b6596785SBilal Elmoussaoui                    num_slot, INPUT_EVENT_SLOTS_MAX);
617b6596785SBilal Elmoussaoui         return;
618b6596785SBilal Elmoussaoui     }
619b6596785SBilal Elmoussaoui 
620b6596785SBilal Elmoussaoui     slot = &touch_slots[num_slot];
621b6596785SBilal Elmoussaoui     slot->x = x;
622b6596785SBilal Elmoussaoui     slot->y = y;
623b6596785SBilal Elmoussaoui 
624b6596785SBilal Elmoussaoui     if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
625b6596785SBilal Elmoussaoui         slot->tracking_id = num_slot;
626b6596785SBilal Elmoussaoui     }
627b6596785SBilal Elmoussaoui 
628b6596785SBilal Elmoussaoui     for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
629b6596785SBilal Elmoussaoui         if (i == num_slot) {
630b6596785SBilal Elmoussaoui             update = type;
631b6596785SBilal Elmoussaoui         } else {
632b6596785SBilal Elmoussaoui             update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
633b6596785SBilal Elmoussaoui         }
634b6596785SBilal Elmoussaoui 
635b6596785SBilal Elmoussaoui         slot = &touch_slots[i];
636b6596785SBilal Elmoussaoui 
637b6596785SBilal Elmoussaoui         if (slot->tracking_id == -1) {
638b6596785SBilal Elmoussaoui             continue;
639b6596785SBilal Elmoussaoui         }
640b6596785SBilal Elmoussaoui 
641b6596785SBilal Elmoussaoui         if (update == INPUT_MULTI_TOUCH_TYPE_END) {
642b6596785SBilal Elmoussaoui             slot->tracking_id = -1;
643b6596785SBilal Elmoussaoui             qemu_input_queue_mtt(con, update, i, slot->tracking_id);
644b6596785SBilal Elmoussaoui             needs_sync = true;
645b6596785SBilal Elmoussaoui         } else {
646b6596785SBilal Elmoussaoui             qemu_input_queue_mtt(con, update, i, slot->tracking_id);
647b6596785SBilal Elmoussaoui             qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
648b6596785SBilal Elmoussaoui             qemu_input_queue_mtt_abs(con,
649b6596785SBilal Elmoussaoui                                     INPUT_AXIS_X, (int) slot->x,
650b6596785SBilal Elmoussaoui                                     0, width,
651b6596785SBilal Elmoussaoui                                     i, slot->tracking_id);
652b6596785SBilal Elmoussaoui             qemu_input_queue_mtt_abs(con,
653b6596785SBilal Elmoussaoui                                     INPUT_AXIS_Y, (int) slot->y,
654b6596785SBilal Elmoussaoui                                     0, height,
655b6596785SBilal Elmoussaoui                                     i, slot->tracking_id);
656b6596785SBilal Elmoussaoui             needs_sync = true;
657b6596785SBilal Elmoussaoui         }
658b6596785SBilal Elmoussaoui     }
659b6596785SBilal Elmoussaoui 
660b6596785SBilal Elmoussaoui     if (needs_sync) {
661b6596785SBilal Elmoussaoui         qemu_input_event_sync();
662b6596785SBilal Elmoussaoui     }
663b6596785SBilal Elmoussaoui }
664b6596785SBilal Elmoussaoui 
qemu_console_set_display_gl_ctx(QemuConsole * con,DisplayGLCtx * gl)665b6596785SBilal Elmoussaoui void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
666b6596785SBilal Elmoussaoui {
6675e79d516SMarc-André Lureau     /* display has opengl support */
6684f418149SMarc-André Lureau     assert(con);
6694f418149SMarc-André Lureau     if (con->gl) {
6705e79d516SMarc-André Lureau         error_report("The console already has an OpenGL context.");
6715e79d516SMarc-André Lureau         exit(1);
6725e79d516SMarc-André Lureau     }
6734f418149SMarc-André Lureau     con->gl = gl;
6744f418149SMarc-André Lureau }
6755e79d516SMarc-André Lureau 
6765e79d516SMarc-André Lureau static void
dcl_set_graphic_cursor(DisplayChangeListener * dcl,QemuGraphicConsole * con)6775e79d516SMarc-André Lureau dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
67858d58708SMarc-André Lureau {
67958d58708SMarc-André Lureau     if (con && con->cursor && dcl->ops->dpy_cursor_define) {
68058d58708SMarc-André Lureau         dcl->ops->dpy_cursor_define(dcl, con->cursor);
68158d58708SMarc-André Lureau     }
68258d58708SMarc-André Lureau     if (con && dcl->ops->dpy_mouse_set) {
68358d58708SMarc-André Lureau         dcl->ops->dpy_mouse_set(dcl, con->cursor_x, con->cursor_y, con->cursor_on);
68458d58708SMarc-André Lureau     }
68558d58708SMarc-André Lureau }
68658d58708SMarc-André Lureau 
register_displaychangelistener(DisplayChangeListener * dcl)68758d58708SMarc-André Lureau void register_displaychangelistener(DisplayChangeListener *dcl)
6886f110819SMarc-André Lureau {
6895209089fSGerd Hoffmann     assert(!dcl->ds);
6907c20b4a3SGerd Hoffmann 
691e0665c3bSMarc-André Lureau     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
692e0665c3bSMarc-André Lureau     dcl->ds = get_alloc_displaystate();
6937c20b4a3SGerd Hoffmann     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
6945209089fSGerd Hoffmann     gui_setup_refresh(dcl->ds);
6955209089fSGerd Hoffmann     if (dcl->con) {
6965209089fSGerd Hoffmann         dcl->con->dcls++;
697284d1c6bSGerd Hoffmann     }
698284d1c6bSGerd Hoffmann     displaychangelistener_display_console(dcl, &error_fatal);
699284d1c6bSGerd Hoffmann     if (QEMU_IS_GRAPHIC_CONSOLE(dcl->con)) {
700e99441a3SAkihiko Odaki         dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(dcl->con));
701e99441a3SAkihiko Odaki     } else if (QEMU_IS_TEXT_CONSOLE(dcl->con)) {
702e99441a3SAkihiko Odaki         qemu_text_console_update_size(QEMU_TEXT_CONSOLE(dcl->con));
703e99441a3SAkihiko Odaki     }
704e99441a3SAkihiko Odaki     qemu_text_console_update_cursor();
7056effaa16SMarc-André Lureau }
7066f110819SMarc-André Lureau 
update_displaychangelistener(DisplayChangeListener * dcl,uint64_t interval)7077c20b4a3SGerd Hoffmann void update_displaychangelistener(DisplayChangeListener *dcl,
7087c20b4a3SGerd Hoffmann                                   uint64_t interval)
7090f7b2864SGerd Hoffmann {
7100f7b2864SGerd Hoffmann     DisplayState *ds = dcl->ds;
7110f7b2864SGerd Hoffmann 
7120f7b2864SGerd Hoffmann     dcl->update_interval = interval;
7130f7b2864SGerd Hoffmann     if (!ds->refreshing && ds->update_interval > interval) {
7140f7b2864SGerd Hoffmann         timer_mod(ds->gui_timer, ds->last_update + interval);
7150f7b2864SGerd Hoffmann     }
716bc72ad67SAlex Bligh }
7170f7b2864SGerd Hoffmann 
unregister_displaychangelistener(DisplayChangeListener * dcl)7180f7b2864SGerd Hoffmann void unregister_displaychangelistener(DisplayChangeListener *dcl)
7190f7b2864SGerd Hoffmann {
7207c20b4a3SGerd Hoffmann     DisplayState *ds = dcl->ds;
7217c20b4a3SGerd Hoffmann     trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
7227c20b4a3SGerd Hoffmann     if (dcl->con) {
7237c20b4a3SGerd Hoffmann         dcl->con->dcls--;
724284d1c6bSGerd Hoffmann     }
725284d1c6bSGerd Hoffmann     QLIST_REMOVE(dcl, next);
726284d1c6bSGerd Hoffmann     dcl->ds = NULL;
7277c20b4a3SGerd Hoffmann     gui_setup_refresh(ds);
728777c5f1eSGerd Hoffmann }
7297c20b4a3SGerd Hoffmann 
dpy_set_ui_info_timer(void * opaque)7307c20b4a3SGerd Hoffmann static void dpy_set_ui_info_timer(void *opaque)
7317c20b4a3SGerd Hoffmann {
732cf1ecc82SGerd Hoffmann     QemuConsole *con = opaque;
733cf1ecc82SGerd Hoffmann     uint32_t head = qemu_console_get_head(con);
734cf1ecc82SGerd Hoffmann 
73558d58708SMarc-André Lureau     con->hw_ops->ui_info(con->hw, head, &con->ui_info);
736cf1ecc82SGerd Hoffmann }
73758d58708SMarc-André Lureau 
dpy_ui_info_supported(const QemuConsole * con)738cf1ecc82SGerd Hoffmann bool dpy_ui_info_supported(const QemuConsole *con)
739cf1ecc82SGerd Hoffmann {
740a92e7bb4SMarc-André Lureau     if (con == NULL) {
741b7fb49f0SGerd Hoffmann         return false;
7425c4b107fSGerd Hoffmann     }
74348a35e12SMarc-André Lureau 
74448a35e12SMarc-André Lureau     return con->hw_ops->ui_info != NULL;
7455c4b107fSGerd Hoffmann }
746b7fb49f0SGerd Hoffmann 
dpy_get_ui_info(const QemuConsole * con)747b7fb49f0SGerd Hoffmann const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
748b7fb49f0SGerd Hoffmann {
7495eaf1e48SMarc-André Lureau     assert(dpy_ui_info_supported(con));
7505eaf1e48SMarc-André Lureau 
751a92e7bb4SMarc-André Lureau     return &con->ui_info;
752a92e7bb4SMarc-André Lureau }
7535eaf1e48SMarc-André Lureau 
dpy_set_ui_info(QemuConsole * con,QemuUIInfo * info,bool delay)7545eaf1e48SMarc-André Lureau int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
7555eaf1e48SMarc-André Lureau {
756ca19ef52SMarc-André Lureau     if (!dpy_ui_info_supported(con)) {
7576f90f3d7SGerd Hoffmann         return -1;
758b7fb49f0SGerd Hoffmann     }
7596f90f3d7SGerd Hoffmann     if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
7606f90f3d7SGerd Hoffmann         /* nothing changed -- ignore */
7611185fde4SGerd Hoffmann         return 0;
7621185fde4SGerd Hoffmann     }
7631185fde4SGerd Hoffmann 
7641185fde4SGerd Hoffmann     /*
7656f90f3d7SGerd Hoffmann      * Typically we get a flood of these as the user resizes the window.
766cf1ecc82SGerd Hoffmann      * Wait until the dust has settled (one second without updates), then
767cf1ecc82SGerd Hoffmann      * go notify the guest.
768cf1ecc82SGerd Hoffmann      */
769cf1ecc82SGerd Hoffmann     con->ui_info = *info;
770cf1ecc82SGerd Hoffmann     timer_mod(con->ui_timer,
7711185fde4SGerd Hoffmann               qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + (delay ? 1000 : 0));
772ca19ef52SMarc-André Lureau     return 0;
773ca19ef52SMarc-André Lureau }
774cf1ecc82SGerd Hoffmann 
dpy_gfx_update(QemuConsole * con,int x,int y,int w,int h)775cf1ecc82SGerd Hoffmann void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
776cf1ecc82SGerd Hoffmann {
777c78f7137SGerd Hoffmann     DisplayState *s = con->ds;
7787c20b4a3SGerd Hoffmann     DisplayChangeListener *dcl;
779c78f7137SGerd Hoffmann     int width = qemu_console_get_width(con, x + w);
780284d1c6bSGerd Hoffmann     int height = qemu_console_get_height(con, y + h);
781ebced091SMarc-André Lureau 
782ebced091SMarc-André Lureau     x = MAX(x, 0);
7837c20b4a3SGerd Hoffmann     y = MAX(y, 0);
7847c20b4a3SGerd Hoffmann     x = MIN(x, width);
7857c20b4a3SGerd Hoffmann     y = MIN(y, height);
7867c20b4a3SGerd Hoffmann     w = MIN(w, width - x);
7877c20b4a3SGerd Hoffmann     h = MIN(h, height - y);
7887c20b4a3SGerd Hoffmann 
7897c20b4a3SGerd Hoffmann     if (!qemu_console_is_visible(con)) {
7907c20b4a3SGerd Hoffmann         return;
79181c0d5a6SGerd Hoffmann     }
792321f048dSGerd Hoffmann     dpy_gfx_update_texture(con, con->surface, x, y, w, h);
793321f048dSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
794589089feSMarc-André Lureau         if (con != dcl->con) {
7957c20b4a3SGerd Hoffmann             continue;
796e99441a3SAkihiko Odaki         }
797284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_gfx_update) {
798284d1c6bSGerd Hoffmann             dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
7997c20b4a3SGerd Hoffmann         }
800bc2ed970SGerd Hoffmann     }
8017c20b4a3SGerd Hoffmann }
8027c20b4a3SGerd Hoffmann 
dpy_gfx_update_full(QemuConsole * con)8037c20b4a3SGerd Hoffmann void dpy_gfx_update_full(QemuConsole *con)
8047c20b4a3SGerd Hoffmann {
8057cd0afe6STina Zhang     int w = qemu_console_get_width(con, 0);
8067cd0afe6STina Zhang     int h = qemu_console_get_height(con, 0);
807ebced091SMarc-André Lureau 
808ebced091SMarc-André Lureau     dpy_gfx_update(con, 0, 0, w, h);
809ebced091SMarc-André Lureau }
810ebced091SMarc-André Lureau 
dpy_gfx_replace_surface(QemuConsole * con,DisplaySurface * surface)8117cd0afe6STina Zhang void dpy_gfx_replace_surface(QemuConsole *con,
8127cd0afe6STina Zhang                              DisplaySurface *surface)
813c78f7137SGerd Hoffmann {
814da229ef3SGerd Hoffmann     static const char placeholder_msg[] = "Display output is not active.";
8157c20b4a3SGerd Hoffmann     DisplayState *s = con->ds;
816c821a58eSAkihiko Odaki     DisplaySurface *old_surface = con->surface;
817c78f7137SGerd Hoffmann     DisplaySurface *new_surface = surface;
818321f048dSGerd Hoffmann     DisplayChangeListener *dcl;
8190d0be876SDongwon Kim     int width;
820284d1c6bSGerd Hoffmann     int height;
821c821a58eSAkihiko Odaki 
822c821a58eSAkihiko Odaki     if (!surface) {
823da229ef3SGerd Hoffmann         if (old_surface) {
824c821a58eSAkihiko Odaki             width = surface_width(old_surface);
825c821a58eSAkihiko Odaki             height = surface_height(old_surface);
826c821a58eSAkihiko Odaki         } else {
827c821a58eSAkihiko Odaki             width = 640;
828c821a58eSAkihiko Odaki             height = 480;
829c821a58eSAkihiko Odaki         }
830c821a58eSAkihiko Odaki 
831c821a58eSAkihiko Odaki         new_surface = qemu_create_placeholder_surface(width, height, placeholder_msg);
832c821a58eSAkihiko Odaki     }
8330d0be876SDongwon Kim 
834c821a58eSAkihiko Odaki     assert(old_surface != new_surface);
835c821a58eSAkihiko Odaki 
8360d0be876SDongwon Kim     con->scanout.kind = SCANOUT_SURFACE;
8376905b934SMarc-André Lureau     con->surface = new_surface;
838ebced091SMarc-André Lureau     dpy_gfx_create_texture(con, new_surface);
8390d0be876SDongwon Kim     QLIST_FOREACH(dcl, &s->listeners, next) {
8400d0be876SDongwon Kim         if (con != dcl->con) {
841284d1c6bSGerd Hoffmann             continue;
842e99441a3SAkihiko Odaki         }
843284d1c6bSGerd Hoffmann         displaychangelistener_gfx_switch(dcl, new_surface, surface ? FALSE : TRUE);
844284d1c6bSGerd Hoffmann     }
8450d0be876SDongwon Kim     dpy_gfx_destroy_texture(con, old_surface);
8467c20b4a3SGerd Hoffmann     qemu_free_displaysurface(old_surface);
847589089feSMarc-André Lureau }
848da229ef3SGerd Hoffmann 
dpy_gfx_check_format(QemuConsole * con,pixman_format_code_t format)8497c20b4a3SGerd Hoffmann bool dpy_gfx_check_format(QemuConsole *con,
8507c20b4a3SGerd Hoffmann                           pixman_format_code_t format)
85149743df3SBenjamin Herrenschmidt {
85249743df3SBenjamin Herrenschmidt     DisplayChangeListener *dcl;
85349743df3SBenjamin Herrenschmidt     DisplayState *s = con->ds;
85449743df3SBenjamin Herrenschmidt 
85549743df3SBenjamin Herrenschmidt     QLIST_FOREACH(dcl, &s->listeners, next) {
85649743df3SBenjamin Herrenschmidt         if (dcl->con && dcl->con != con) {
85749743df3SBenjamin Herrenschmidt             /* dcl bound to another console -> skip */
85849743df3SBenjamin Herrenschmidt             continue;
85949743df3SBenjamin Herrenschmidt         }
86049743df3SBenjamin Herrenschmidt         if (dcl->ops->dpy_gfx_check_format) {
86149743df3SBenjamin Herrenschmidt             if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
86249743df3SBenjamin Herrenschmidt                 return false;
86349743df3SBenjamin Herrenschmidt             }
86449743df3SBenjamin Herrenschmidt         } else {
86549743df3SBenjamin Herrenschmidt             /* default is to allow native 32 bpp only */
86649743df3SBenjamin Herrenschmidt             if (format != qemu_default_pixman_format(32, true)) {
86775ae7c46SPhilippe Mathieu-Daudé                 return false;
86849743df3SBenjamin Herrenschmidt             }
86949743df3SBenjamin Herrenschmidt         }
87049743df3SBenjamin Herrenschmidt     }
87149743df3SBenjamin Herrenschmidt     return true;
87249743df3SBenjamin Herrenschmidt }
87349743df3SBenjamin Herrenschmidt 
dpy_refresh(DisplayState * s)87449743df3SBenjamin Herrenschmidt static void dpy_refresh(DisplayState *s)
87549743df3SBenjamin Herrenschmidt {
8766075137dSStefan Weil     DisplayChangeListener *dcl;
8777c20b4a3SGerd Hoffmann 
878284d1c6bSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
879284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_refresh) {
8807c20b4a3SGerd Hoffmann             dcl->ops->dpy_refresh(dcl);
8817c20b4a3SGerd Hoffmann         }
882bc2ed970SGerd Hoffmann     }
8837c20b4a3SGerd Hoffmann }
8847c20b4a3SGerd Hoffmann 
dpy_text_cursor(QemuConsole * con,int x,int y)8857c20b4a3SGerd Hoffmann void dpy_text_cursor(QemuConsole *con, int x, int y)
8867c20b4a3SGerd Hoffmann {
887c78f7137SGerd Hoffmann     DisplayState *s = con->ds;
8887c20b4a3SGerd Hoffmann     DisplayChangeListener *dcl;
889c78f7137SGerd Hoffmann 
890284d1c6bSGerd Hoffmann     if (!qemu_console_is_visible(con)) {
891321f048dSGerd Hoffmann         return;
89281c0d5a6SGerd Hoffmann     }
893321f048dSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
894321f048dSGerd Hoffmann         if (con != dcl->con) {
8957c20b4a3SGerd Hoffmann             continue;
896e99441a3SAkihiko Odaki         }
897284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_text_cursor) {
898284d1c6bSGerd Hoffmann             dcl->ops->dpy_text_cursor(dcl, x, y);
8997c20b4a3SGerd Hoffmann         }
900bc2ed970SGerd Hoffmann     }
9017c20b4a3SGerd Hoffmann }
9027c20b4a3SGerd Hoffmann 
dpy_text_update(QemuConsole * con,int x,int y,int w,int h)9037c20b4a3SGerd Hoffmann void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
9047c20b4a3SGerd Hoffmann {
905c78f7137SGerd Hoffmann     DisplayState *s = con->ds;
9067c20b4a3SGerd Hoffmann     DisplayChangeListener *dcl;
907c78f7137SGerd Hoffmann 
908284d1c6bSGerd Hoffmann     if (!qemu_console_is_visible(con)) {
909321f048dSGerd Hoffmann         return;
91081c0d5a6SGerd Hoffmann     }
911321f048dSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
912321f048dSGerd Hoffmann         if (con != dcl->con) {
9137c20b4a3SGerd Hoffmann             continue;
914e99441a3SAkihiko Odaki         }
915284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_text_update) {
916284d1c6bSGerd Hoffmann             dcl->ops->dpy_text_update(dcl, x, y, w, h);
9177c20b4a3SGerd Hoffmann         }
918bc2ed970SGerd Hoffmann     }
9197c20b4a3SGerd Hoffmann }
9207c20b4a3SGerd Hoffmann 
dpy_text_resize(QemuConsole * con,int w,int h)9217c20b4a3SGerd Hoffmann void dpy_text_resize(QemuConsole *con, int w, int h)
9227c20b4a3SGerd Hoffmann {
923c78f7137SGerd Hoffmann     DisplayState *s = con->ds;
9247c20b4a3SGerd Hoffmann     DisplayChangeListener *dcl;
925c78f7137SGerd Hoffmann 
9269425c004SChih-Min Chao     if (!qemu_console_is_visible(con)) {
927321f048dSGerd Hoffmann         return;
92881c0d5a6SGerd Hoffmann     }
929321f048dSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
930321f048dSGerd Hoffmann         if (con != dcl->con) {
9317c20b4a3SGerd Hoffmann             continue;
932e99441a3SAkihiko Odaki         }
933284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_text_resize) {
934284d1c6bSGerd Hoffmann             dcl->ops->dpy_text_resize(dcl, w, h);
9357c20b4a3SGerd Hoffmann         }
936bc2ed970SGerd Hoffmann     }
9377c20b4a3SGerd Hoffmann }
9387c20b4a3SGerd Hoffmann 
dpy_mouse_set(QemuConsole * c,int x,int y,bool on)9397c20b4a3SGerd Hoffmann void dpy_mouse_set(QemuConsole *c, int x, int y, bool on)
9407c20b4a3SGerd Hoffmann {
941a418e7aeSAkihiko Odaki     QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
9427c20b4a3SGerd Hoffmann     DisplayState *s = c->ds;
94358d58708SMarc-André Lureau     DisplayChangeListener *dcl;
94458d58708SMarc-André Lureau 
945284d1c6bSGerd Hoffmann     con->cursor_x = x;
946321f048dSGerd Hoffmann     con->cursor_y = y;
9476effaa16SMarc-André Lureau     con->cursor_on = on;
9486effaa16SMarc-André Lureau     if (!qemu_console_is_visible(c)) {
9496effaa16SMarc-André Lureau         return;
95058d58708SMarc-André Lureau     }
951321f048dSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
952321f048dSGerd Hoffmann         if (c != dcl->con) {
9537c20b4a3SGerd Hoffmann             continue;
954e99441a3SAkihiko Odaki         }
955284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_mouse_set) {
956284d1c6bSGerd Hoffmann             dcl->ops->dpy_mouse_set(dcl, x, y, on);
9577c20b4a3SGerd Hoffmann         }
958bc2ed970SGerd Hoffmann     }
9597c20b4a3SGerd Hoffmann }
9607c20b4a3SGerd Hoffmann 
dpy_cursor_define(QemuConsole * c,QEMUCursor * cursor)9617c20b4a3SGerd Hoffmann void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
9627c20b4a3SGerd Hoffmann {
96358d58708SMarc-André Lureau     QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
9647c20b4a3SGerd Hoffmann     DisplayState *s = c->ds;
96558d58708SMarc-André Lureau     DisplayChangeListener *dcl;
96658d58708SMarc-André Lureau 
967284d1c6bSGerd Hoffmann     cursor_unref(con->cursor);
968321f048dSGerd Hoffmann     con->cursor = cursor_ref(cursor);
969385ac97fSMarc-André Lureau     if (!qemu_console_is_visible(c)) {
970385ac97fSMarc-André Lureau         return;
97158d58708SMarc-André Lureau     }
972321f048dSGerd Hoffmann     QLIST_FOREACH(dcl, &s->listeners, next) {
973321f048dSGerd Hoffmann         if (c != dcl->con) {
9747c20b4a3SGerd Hoffmann             continue;
975e99441a3SAkihiko Odaki         }
976284d1c6bSGerd Hoffmann         if (dcl->ops->dpy_cursor_define) {
977284d1c6bSGerd Hoffmann             dcl->ops->dpy_cursor_define(dcl, cursor);
9787c20b4a3SGerd Hoffmann         }
979bc2ed970SGerd Hoffmann     }
9807c20b4a3SGerd Hoffmann }
9817c20b4a3SGerd Hoffmann 
dpy_gl_ctx_create(QemuConsole * con,struct QEMUGLParams * qparams)9827c20b4a3SGerd Hoffmann QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
9837c20b4a3SGerd Hoffmann                                 struct QEMUGLParams *qparams)
98406020b95SGerd Hoffmann {
98506020b95SGerd Hoffmann     assert(con->gl);
98606020b95SGerd Hoffmann     return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
98706020b95SGerd Hoffmann }
98806020b95SGerd Hoffmann 
dpy_gl_ctx_destroy(QemuConsole * con,QEMUGLContext ctx)98906020b95SGerd Hoffmann void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
99006020b95SGerd Hoffmann {
99106020b95SGerd Hoffmann     assert(con->gl);
99206020b95SGerd Hoffmann     con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
99306020b95SGerd Hoffmann }
99406020b95SGerd Hoffmann 
dpy_gl_ctx_make_current(QemuConsole * con,QEMUGLContext ctx)99506020b95SGerd Hoffmann int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
99606020b95SGerd Hoffmann {
99706020b95SGerd Hoffmann     assert(con->gl);
99806020b95SGerd Hoffmann     return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
99906020b95SGerd Hoffmann }
100006020b95SGerd Hoffmann 
dpy_gl_scanout_disable(QemuConsole * con)100106020b95SGerd Hoffmann void dpy_gl_scanout_disable(QemuConsole *con)
100206020b95SGerd Hoffmann {
1003eaa92c76SGerd Hoffmann     DisplayState *s = con->ds;
1004eaa92c76SGerd Hoffmann     DisplayChangeListener *dcl;
10057cc712e9SMarc-André Lureau 
10067cc712e9SMarc-André Lureau     if (con->scanout.kind != SCANOUT_SURFACE) {
10077cc712e9SMarc-André Lureau         con->scanout.kind = SCANOUT_NONE;
1008ebced091SMarc-André Lureau     }
1009ebced091SMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
1010ebced091SMarc-André Lureau         if (con != dcl->con) {
10117cc712e9SMarc-André Lureau             continue;
1012e99441a3SAkihiko Odaki         }
10131699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_scanout_disable) {
10141699d00eSAkihiko Odaki             dcl->ops->dpy_gl_scanout_disable(dcl);
1015a9fbce5eSMarc-André Lureau         }
10167cc712e9SMarc-André Lureau     }
10177cc712e9SMarc-André Lureau }
1018eaa92c76SGerd Hoffmann 
dpy_gl_scanout_texture(QemuConsole * con,uint32_t backing_id,bool backing_y_0_top,uint32_t backing_width,uint32_t backing_height,uint32_t x,uint32_t y,uint32_t width,uint32_t height,void * d3d_tex2d)1019a9fbce5eSMarc-André Lureau void dpy_gl_scanout_texture(QemuConsole *con,
1020eaa92c76SGerd Hoffmann                             uint32_t backing_id,
1021f4c36bdaSGerd Hoffmann                             bool backing_y_0_top,
1022f4c36bdaSGerd Hoffmann                             uint32_t backing_width,
1023f4c36bdaSGerd Hoffmann                             uint32_t backing_height,
1024f4c36bdaSGerd Hoffmann                             uint32_t x, uint32_t y,
1025f4c36bdaSGerd Hoffmann                             uint32_t width, uint32_t height,
1026f4c36bdaSGerd Hoffmann                             void *d3d_tex2d)
1027bf41ab61SMarc-André Lureau {
1028bf41ab61SMarc-André Lureau     DisplayState *s = con->ds;
102906020b95SGerd Hoffmann     DisplayChangeListener *dcl;
10307cc712e9SMarc-André Lureau 
10317cc712e9SMarc-André Lureau     con->scanout.kind = SCANOUT_TEXTURE;
10327cc712e9SMarc-André Lureau     con->scanout.texture = (ScanoutTexture) {
1033ebced091SMarc-André Lureau         backing_id, backing_y_0_top, backing_width, backing_height,
1034ebced091SMarc-André Lureau         x, y, width, height, d3d_tex2d,
1035ebced091SMarc-André Lureau     };
1036bf41ab61SMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
1037ebced091SMarc-André Lureau         if (con != dcl->con) {
10387cc712e9SMarc-André Lureau             continue;
1039e99441a3SAkihiko Odaki         }
10401699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_scanout_texture) {
10411699d00eSAkihiko Odaki             dcl->ops->dpy_gl_scanout_texture(dcl, backing_id,
1042a9fbce5eSMarc-André Lureau                                              backing_y_0_top,
10437cc712e9SMarc-André Lureau                                              backing_width, backing_height,
104406020b95SGerd Hoffmann                                              x, y, width, height,
10459d8256ebSMarc-André Lureau                                              d3d_tex2d);
1046bf41ab61SMarc-André Lureau         }
1047bf41ab61SMarc-André Lureau     }
104806020b95SGerd Hoffmann }
10497cc712e9SMarc-André Lureau 
dpy_gl_scanout_dmabuf(QemuConsole * con,QemuDmaBuf * dmabuf)1050a9fbce5eSMarc-André Lureau void dpy_gl_scanout_dmabuf(QemuConsole *con,
105106020b95SGerd Hoffmann                            QemuDmaBuf *dmabuf)
10524133fa71SGerd Hoffmann {
10534133fa71SGerd Hoffmann     DisplayState *s = con->ds;
10544133fa71SGerd Hoffmann     DisplayChangeListener *dcl;
10557cc712e9SMarc-André Lureau 
10567cc712e9SMarc-André Lureau     con->scanout.kind = SCANOUT_DMABUF;
10577cc712e9SMarc-André Lureau     con->scanout.dmabuf = dmabuf;
1058ebced091SMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
1059ebced091SMarc-André Lureau         if (con != dcl->con) {
10607cc712e9SMarc-André Lureau             continue;
1061e99441a3SAkihiko Odaki         }
10621699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_scanout_dmabuf) {
10631699d00eSAkihiko Odaki             dcl->ops->dpy_gl_scanout_dmabuf(dcl, dmabuf);
1064a9fbce5eSMarc-André Lureau         }
10657cc712e9SMarc-André Lureau     }
10667cc712e9SMarc-André Lureau }
10674133fa71SGerd Hoffmann 
dpy_gl_cursor_dmabuf(QemuConsole * con,QemuDmaBuf * dmabuf,bool have_hot,uint32_t hot_x,uint32_t hot_y)1068a9fbce5eSMarc-André Lureau void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
10694133fa71SGerd Hoffmann                           bool have_hot, uint32_t hot_x, uint32_t hot_y)
10706e1f2cb5SGerd Hoffmann {
10716e1f2cb5SGerd Hoffmann     DisplayState *s = con->ds;
10724133fa71SGerd Hoffmann     DisplayChangeListener *dcl;
10737cc712e9SMarc-André Lureau 
10747cc712e9SMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
10754133fa71SGerd Hoffmann         if (con != dcl->con) {
10767cc712e9SMarc-André Lureau             continue;
1077e99441a3SAkihiko Odaki         }
10781699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_cursor_dmabuf) {
10791699d00eSAkihiko Odaki             dcl->ops->dpy_gl_cursor_dmabuf(dcl, dmabuf,
10807cc712e9SMarc-André Lureau                                            have_hot, hot_x, hot_y);
10817cc712e9SMarc-André Lureau         }
10826e1f2cb5SGerd Hoffmann     }
10836e1f2cb5SGerd Hoffmann }
10846e1f2cb5SGerd Hoffmann 
dpy_gl_cursor_position(QemuConsole * con,uint32_t pos_x,uint32_t pos_y)10857cc712e9SMarc-André Lureau void dpy_gl_cursor_position(QemuConsole *con,
10866e1f2cb5SGerd Hoffmann                             uint32_t pos_x, uint32_t pos_y)
10876e1f2cb5SGerd Hoffmann {
10886e1f2cb5SGerd Hoffmann     DisplayState *s = con->ds;
10896e1f2cb5SGerd Hoffmann     DisplayChangeListener *dcl;
10907cc712e9SMarc-André Lureau 
10917cc712e9SMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
10926e1f2cb5SGerd Hoffmann         if (con != dcl->con) {
10937cc712e9SMarc-André Lureau             continue;
1094e99441a3SAkihiko Odaki         }
10951699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_cursor_position) {
10961699d00eSAkihiko Odaki             dcl->ops->dpy_gl_cursor_position(dcl, pos_x, pos_y);
10977cc712e9SMarc-André Lureau         }
10987cc712e9SMarc-André Lureau     }
10997cc712e9SMarc-André Lureau }
11004133fa71SGerd Hoffmann 
dpy_gl_release_dmabuf(QemuConsole * con,QemuDmaBuf * dmabuf)11014133fa71SGerd Hoffmann void dpy_gl_release_dmabuf(QemuConsole *con,
11024133fa71SGerd Hoffmann                           QemuDmaBuf *dmabuf)
11034133fa71SGerd Hoffmann {
11044133fa71SGerd Hoffmann     DisplayState *s = con->ds;
11054133fa71SGerd Hoffmann     DisplayChangeListener *dcl;
11067cc712e9SMarc-André Lureau 
11077cc712e9SMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
11084133fa71SGerd Hoffmann         if (con != dcl->con) {
11097cc712e9SMarc-André Lureau             continue;
1110e99441a3SAkihiko Odaki         }
11111699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_release_dmabuf) {
11121699d00eSAkihiko Odaki             dcl->ops->dpy_gl_release_dmabuf(dcl, dmabuf);
11137cc712e9SMarc-André Lureau         }
11147cc712e9SMarc-André Lureau     }
11157cc712e9SMarc-André Lureau }
11164133fa71SGerd Hoffmann 
dpy_gl_update(QemuConsole * con,uint32_t x,uint32_t y,uint32_t w,uint32_t h)11174133fa71SGerd Hoffmann void dpy_gl_update(QemuConsole *con,
11184133fa71SGerd Hoffmann                    uint32_t x, uint32_t y, uint32_t w, uint32_t h)
111906020b95SGerd Hoffmann {
112006020b95SGerd Hoffmann     DisplayState *s = con->ds;
112106020b95SGerd Hoffmann     DisplayChangeListener *dcl;
11227cc712e9SMarc-André Lureau 
11237cc712e9SMarc-André Lureau     assert(con->gl);
11247cc712e9SMarc-André Lureau 
112506020b95SGerd Hoffmann     graphic_hw_gl_block(con, true);
1126f6413cbfSMarc-André Lureau     QLIST_FOREACH(dcl, &s->listeners, next) {
1127f6413cbfSMarc-André Lureau         if (con != dcl->con) {
11287cc712e9SMarc-André Lureau             continue;
1129e99441a3SAkihiko Odaki         }
11301699d00eSAkihiko Odaki         if (dcl->ops->dpy_gl_update) {
11311699d00eSAkihiko Odaki             dcl->ops->dpy_gl_update(dcl, x, y, w, h);
1132a9fbce5eSMarc-André Lureau         }
11337cc712e9SMarc-André Lureau     }
11347cc712e9SMarc-André Lureau     graphic_hw_gl_block(con, false);
1135a9fbce5eSMarc-André Lureau }
1136f6413cbfSMarc-André Lureau 
113706020b95SGerd Hoffmann /***********************************************************/
113806020b95SGerd Hoffmann /* register display */
113928ecbaeeSPaolo Bonzini 
114028ecbaeeSPaolo Bonzini /* console.c internal use only */
get_alloc_displaystate(void)114128ecbaeeSPaolo Bonzini static DisplayState *get_alloc_displaystate(void)
114264840c66SGerd Hoffmann {
114364840c66SGerd Hoffmann     if (!display_state) {
114428ecbaeeSPaolo Bonzini         display_state = g_new0(DisplayState, 1);
114528ecbaeeSPaolo Bonzini     }
114664840c66SGerd Hoffmann     return display_state;
114728ecbaeeSPaolo Bonzini }
114828ecbaeeSPaolo Bonzini 
114928ecbaeeSPaolo Bonzini /*
115028ecbaeeSPaolo Bonzini  * Called by main(), after creating QemuConsoles
115164840c66SGerd Hoffmann  * and before initializing ui (sdl/vnc/...).
115264840c66SGerd Hoffmann  */
init_displaystate(void)115364840c66SGerd Hoffmann DisplayState *init_displaystate(void)
115464840c66SGerd Hoffmann {
115564840c66SGerd Hoffmann     gchar *name;
115664840c66SGerd Hoffmann     QemuConsole *con;
115743f420f8SGerd Hoffmann 
1158cd6cd8faSGerd Hoffmann     QTAILQ_FOREACH(con, &consoles, next) {
115964840c66SGerd Hoffmann         /* Hook up into the qom tree here (not in object_new()), once
1160cd6cd8faSGerd Hoffmann          * all QemuConsoles are created and the order / numbering
116134b77515SMarc-André Lureau          * doesn't change any more */
116243f420f8SGerd Hoffmann         name = g_strdup_printf("console[%d]", con->index);
116343f420f8SGerd Hoffmann         object_property_add_child(container_get(object_get_root(), "/backend"),
1164cd6cd8faSGerd Hoffmann                                   name, OBJECT(con));
116543f420f8SGerd Hoffmann         g_free(name);
1166d2623129SMarkus Armbruster     }
116743f420f8SGerd Hoffmann 
116864840c66SGerd Hoffmann     return display_state;
116964840c66SGerd Hoffmann }
117064840c66SGerd Hoffmann 
graphic_console_set_hwops(QemuConsole * con,const GraphicHwOps * hw_ops,void * opaque)117164840c66SGerd Hoffmann void graphic_console_set_hwops(QemuConsole *con,
117264840c66SGerd Hoffmann                                const GraphicHwOps *hw_ops,
11731c1f9498SGerd Hoffmann                                void *opaque)
11741c1f9498SGerd Hoffmann {
11751c1f9498SGerd Hoffmann     con->hw_ops = hw_ops;
11761c1f9498SGerd Hoffmann     con->hw = opaque;
11771c1f9498SGerd Hoffmann }
11781c1f9498SGerd Hoffmann 
graphic_console_init(DeviceState * dev,uint32_t head,const GraphicHwOps * hw_ops,void * opaque)11791c1f9498SGerd Hoffmann QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
11801c1f9498SGerd Hoffmann                                   const GraphicHwOps *hw_ops,
11815643706aSGerd Hoffmann                                   void *opaque)
1182aa2beaa1SGerd Hoffmann {
118328ecbaeeSPaolo Bonzini     static const char noinit[] =
118428ecbaeeSPaolo Bonzini         "Guest has not initialized the display (yet).";
1185521a580dSGerd Hoffmann     int width = 640;
1186521a580dSGerd Hoffmann     int height = 480;
118764840c66SGerd Hoffmann     QemuConsole *s;
118864840c66SGerd Hoffmann     DisplaySurface *surface;
118928ecbaeeSPaolo Bonzini 
11909588d67eSGerd Hoffmann     s = qemu_graphic_console_lookup_unused();
119128ecbaeeSPaolo Bonzini     if (s) {
1192f9411aaeSMarc-André Lureau         trace_console_gfx_reuse(s->index);
11939588d67eSGerd Hoffmann         width = qemu_console_get_width(s, 0);
11949588d67eSGerd Hoffmann         height = qemu_console_get_height(s, 0);
1195ebced091SMarc-André Lureau     } else {
1196ebced091SMarc-André Lureau         trace_console_gfx_new();
11979588d67eSGerd Hoffmann         s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE);
1198437fe106SGerd Hoffmann     }
119934b77515SMarc-André Lureau     QEMU_GRAPHIC_CONSOLE(s)->head = head;
12009588d67eSGerd Hoffmann     graphic_console_set_hwops(s, hw_ops, opaque);
120158d58708SMarc-André Lureau     if (dev) {
12021c1f9498SGerd Hoffmann         object_property_set_link(OBJECT(s), "device", OBJECT(dev),
1203aa2beaa1SGerd Hoffmann                                  &error_abort);
12045325cc34SMarkus Armbruster     }
1205afff2b15SKirill Batuzov 
1206aa2beaa1SGerd Hoffmann     surface = qemu_create_placeholder_surface(width, height, noinit);
120728ecbaeeSPaolo Bonzini     dpy_gfx_replace_surface(s, surface);
1208b5a087b0SAkihiko Odaki     s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
12099588d67eSGerd Hoffmann                                        graphic_hw_gl_unblock_timer, s);
1210a9b1e471SMarc-André Lureau     return s;
1211a9b1e471SMarc-André Lureau }
1212c78f7137SGerd Hoffmann 
121328ecbaeeSPaolo Bonzini static const GraphicHwOps unused_ops = {
121428ecbaeeSPaolo Bonzini     /* no callbacks */
12159588d67eSGerd Hoffmann };
12169588d67eSGerd Hoffmann 
graphic_console_close(QemuConsole * con)12179588d67eSGerd Hoffmann void graphic_console_close(QemuConsole *con)
12189588d67eSGerd Hoffmann {
12199588d67eSGerd Hoffmann     static const char unplugged[] =
12209588d67eSGerd Hoffmann         "Guest display has been unplugged";
12219588d67eSGerd Hoffmann     DisplaySurface *surface;
12229588d67eSGerd Hoffmann     int width = qemu_console_get_width(con, 640);
12239588d67eSGerd Hoffmann     int height = qemu_console_get_height(con, 480);
1224ebced091SMarc-André Lureau 
1225ebced091SMarc-André Lureau     trace_console_gfx_close(con->index);
12269588d67eSGerd Hoffmann     object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
12279588d67eSGerd Hoffmann     graphic_console_set_hwops(con, &unused_ops, NULL);
12285325cc34SMarkus Armbruster 
12299588d67eSGerd Hoffmann     if (con->gl) {
12309588d67eSGerd Hoffmann         dpy_gl_scanout_disable(con);
12319588d67eSGerd Hoffmann     }
12329588d67eSGerd Hoffmann     surface = qemu_create_placeholder_surface(width, height, unplugged);
12339588d67eSGerd Hoffmann     dpy_gfx_replace_surface(con, surface);
1234b5a087b0SAkihiko Odaki }
12359588d67eSGerd Hoffmann 
qemu_console_lookup_default(void)12369588d67eSGerd Hoffmann QemuConsole *qemu_console_lookup_default(void)
12379588d67eSGerd Hoffmann {
1238d4c19956SAkihiko Odaki     QemuConsole *con;
1239d4c19956SAkihiko Odaki 
1240d4c19956SAkihiko Odaki     QTAILQ_FOREACH(con, &consoles, next) {
1241d4c19956SAkihiko Odaki         if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
1242d4c19956SAkihiko Odaki             return con;
1243d4c19956SAkihiko Odaki         }
1244d4c19956SAkihiko Odaki     }
1245d4c19956SAkihiko Odaki     return QTAILQ_FIRST(&consoles);
1246d4c19956SAkihiko Odaki }
1247d4c19956SAkihiko Odaki 
qemu_console_lookup_by_index(unsigned int index)1248d4c19956SAkihiko Odaki QemuConsole *qemu_console_lookup_by_index(unsigned int index)
1249d4c19956SAkihiko Odaki {
1250284d1c6bSGerd Hoffmann     QemuConsole *con;
1251284d1c6bSGerd Hoffmann 
1252cd6cd8faSGerd Hoffmann     QTAILQ_FOREACH(con, &consoles, next) {
1253cd6cd8faSGerd Hoffmann         if (con->index == index) {
1254cd6cd8faSGerd Hoffmann             return con;
1255cd6cd8faSGerd Hoffmann         }
1256cd6cd8faSGerd Hoffmann     }
1257284d1c6bSGerd Hoffmann     return NULL;
1258cd6cd8faSGerd Hoffmann }
1259cd6cd8faSGerd Hoffmann 
qemu_console_lookup_by_device(DeviceState * dev,uint32_t head)1260284d1c6bSGerd Hoffmann QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
1261284d1c6bSGerd Hoffmann {
12625643706aSGerd Hoffmann     QemuConsole *con;
126314a93649SGerd Hoffmann     Object *obj;
1264cd6cd8faSGerd Hoffmann     uint32_t h;
126514a93649SGerd Hoffmann 
12665643706aSGerd Hoffmann     QTAILQ_FOREACH(con, &consoles, next) {
126714a93649SGerd Hoffmann         obj = object_property_get_link(OBJECT(con),
1268cd6cd8faSGerd Hoffmann                                        "device", &error_abort);
1269cd6cd8faSGerd Hoffmann         if (DEVICE(obj) != dev) {
1270afff2b15SKirill Batuzov             continue;
12715643706aSGerd Hoffmann         }
12725643706aSGerd Hoffmann         h = object_property_get_uint(OBJECT(con),
127314a93649SGerd Hoffmann                                      "head", &error_abort);
1274cd6cd8faSGerd Hoffmann         if (h != head) {
1275afff2b15SKirill Batuzov             continue;
12765643706aSGerd Hoffmann         }
12775643706aSGerd Hoffmann         return con;
12785643706aSGerd Hoffmann     }
1279cd6cd8faSGerd Hoffmann     return NULL;
128014a93649SGerd Hoffmann }
128114a93649SGerd Hoffmann 
qemu_console_lookup_by_device_name(const char * device_id,uint32_t head,Error ** errp)128214a93649SGerd Hoffmann QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
128314a93649SGerd Hoffmann                                                 uint32_t head, Error **errp)
1284f2c1d54cSGerd Hoffmann {
1285f2c1d54cSGerd Hoffmann     DeviceState *dev;
1286f2c1d54cSGerd Hoffmann     QemuConsole *con;
1287f2c1d54cSGerd Hoffmann 
1288f2c1d54cSGerd Hoffmann     dev = qdev_find_recursive(sysbus_get_default(), device_id);
1289f2c1d54cSGerd Hoffmann     if (dev == NULL) {
1290f2c1d54cSGerd Hoffmann         error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
1291f2c1d54cSGerd Hoffmann                   "Device '%s' not found", device_id);
1292f2c1d54cSGerd Hoffmann         return NULL;
1293f2c1d54cSGerd Hoffmann     }
1294f2c1d54cSGerd Hoffmann 
1295f2c1d54cSGerd Hoffmann     con = qemu_console_lookup_by_device(dev, head);
1296f2c1d54cSGerd Hoffmann     if (con == NULL) {
1297f2c1d54cSGerd Hoffmann         error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
1298f2c1d54cSGerd Hoffmann                    device_id, head);
1299f2c1d54cSGerd Hoffmann         return NULL;
1300f2c1d54cSGerd Hoffmann     }
1301f2c1d54cSGerd Hoffmann 
1302f2c1d54cSGerd Hoffmann     return con;
1303f2c1d54cSGerd Hoffmann }
1304f2c1d54cSGerd Hoffmann 
qemu_graphic_console_lookup_unused(void)1305f2c1d54cSGerd Hoffmann static QemuConsole *qemu_graphic_console_lookup_unused(void)
1306f2c1d54cSGerd Hoffmann {
1307f9411aaeSMarc-André Lureau     QemuConsole *con;
13089588d67eSGerd Hoffmann     Object *obj;
1309cd6cd8faSGerd Hoffmann 
13109588d67eSGerd Hoffmann     QTAILQ_FOREACH(con, &consoles, next) {
13119588d67eSGerd Hoffmann         if (!QEMU_IS_GRAPHIC_CONSOLE(con) || con->hw_ops != &unused_ops) {
1312cd6cd8faSGerd Hoffmann             continue;
1313f9411aaeSMarc-André Lureau         }
13149588d67eSGerd Hoffmann         obj = object_property_get_link(OBJECT(con),
13159588d67eSGerd Hoffmann                                        "device", &error_abort);
1316cd6cd8faSGerd Hoffmann         if (obj != NULL) {
13179588d67eSGerd Hoffmann             continue;
13189588d67eSGerd Hoffmann         }
13199588d67eSGerd Hoffmann         return con;
13209588d67eSGerd Hoffmann     }
1321cd6cd8faSGerd Hoffmann     return NULL;
13229588d67eSGerd Hoffmann }
13239588d67eSGerd Hoffmann 
qemu_console_get_cursor(QemuConsole * con)13249588d67eSGerd Hoffmann QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
13259588d67eSGerd Hoffmann {
1326385ac97fSMarc-André Lureau     return QEMU_IS_GRAPHIC_CONSOLE(con) ? QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
1327385ac97fSMarc-André Lureau }
132858d58708SMarc-André Lureau 
qemu_console_is_visible(QemuConsole * con)1329385ac97fSMarc-André Lureau bool qemu_console_is_visible(QemuConsole *con)
1330385ac97fSMarc-André Lureau {
133181c0d5a6SGerd Hoffmann     return con->dcls > 0;
133228ecbaeeSPaolo Bonzini }
1333e99441a3SAkihiko Odaki 
qemu_console_is_graphic(QemuConsole * con)133428ecbaeeSPaolo Bonzini bool qemu_console_is_graphic(QemuConsole *con)
133528ecbaeeSPaolo Bonzini {
133681c0d5a6SGerd Hoffmann     return con && QEMU_IS_GRAPHIC_CONSOLE(con);
133728ecbaeeSPaolo Bonzini }
1338c105d60fSMarc-André Lureau 
qemu_console_is_fixedsize(QemuConsole * con)133981c0d5a6SGerd Hoffmann bool qemu_console_is_fixedsize(QemuConsole *con)
134081c0d5a6SGerd Hoffmann {
134181c0d5a6SGerd Hoffmann     return con && (QEMU_IS_GRAPHIC_CONSOLE(con) || QEMU_IS_FIXED_TEXT_CONSOLE(con));
134281c0d5a6SGerd Hoffmann }
1343c105d60fSMarc-André Lureau 
qemu_console_is_gl_blocked(QemuConsole * con)134428ecbaeeSPaolo Bonzini bool qemu_console_is_gl_blocked(QemuConsole *con)
134528ecbaeeSPaolo Bonzini {
1346f607867cSGerd Hoffmann     assert(con != NULL);
1347f607867cSGerd Hoffmann     return con->gl_block;
1348f607867cSGerd Hoffmann }
1349f607867cSGerd Hoffmann 
qemu_graphic_console_is_multihead(QemuGraphicConsole * c)1350f607867cSGerd Hoffmann static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c)
1351f607867cSGerd Hoffmann {
13522c0c4c1fSLaszlo Ersek     QemuConsole *con;
1353839a4826SWen, Jianxian 
1354839a4826SWen, Jianxian     QTAILQ_FOREACH(con, &consoles, next) {
1355839a4826SWen, Jianxian         QemuGraphicConsole *candidate;
1356839a4826SWen, Jianxian 
13572c0c4c1fSLaszlo Ersek         if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
13582c0c4c1fSLaszlo Ersek             continue;
13594ce2f97cSLaszlo Ersek         }
13604ce2f97cSLaszlo Ersek 
13614ce2f97cSLaszlo Ersek         candidate = QEMU_GRAPHIC_CONSOLE(con);
13622c0c4c1fSLaszlo Ersek         if (candidate->device != c->device) {
13632c0c4c1fSLaszlo Ersek             continue;
13642c0c4c1fSLaszlo Ersek         }
1365839a4826SWen, Jianxian 
1366839a4826SWen, Jianxian         if (candidate->head != c->head) {
1367839a4826SWen, Jianxian             return true;
136865d7ceb4SLaszlo Ersek         }
1369839a4826SWen, Jianxian     }
1370839a4826SWen, Jianxian     return false;
1371839a4826SWen, Jianxian }
1372839a4826SWen, Jianxian 
qemu_console_get_label(QemuConsole * con)1373839a4826SWen, Jianxian char *qemu_console_get_label(QemuConsole *con)
1374839a4826SWen, Jianxian {
1375779ce88fSGerd Hoffmann     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
1376779ce88fSGerd Hoffmann         QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(con);
1377c105d60fSMarc-André Lureau         if (c->device) {
137858d58708SMarc-André Lureau             DeviceState *dev;
137958d58708SMarc-André Lureau             bool multihead;
1380839a4826SWen, Jianxian 
1381839a4826SWen, Jianxian             dev = DEVICE(c->device);
1382839a4826SWen, Jianxian             multihead = qemu_graphic_console_is_multihead(c);
138358d58708SMarc-André Lureau             if (multihead) {
13842c0c4c1fSLaszlo Ersek                 return g_strdup_printf("%s.%d", dev->id ?
1385839a4826SWen, Jianxian                                        dev->id :
1386839a4826SWen, Jianxian                                        object_get_typename(c->device),
1387839a4826SWen, Jianxian                                        c->head);
138858d58708SMarc-André Lureau             } else {
138958d58708SMarc-André Lureau                 return g_strdup_printf("%s", dev->id ?
1390839a4826SWen, Jianxian                                        dev->id :
1391839a4826SWen, Jianxian                                        object_get_typename(c->device));
1392839a4826SWen, Jianxian             }
139358d58708SMarc-André Lureau         }
1394839a4826SWen, Jianxian         return g_strdup("VGA");
1395779ce88fSGerd Hoffmann     } else if (QEMU_IS_TEXT_CONSOLE(con)) {
1396779ce88fSGerd Hoffmann         const char *label = qemu_text_console_get_label(QEMU_TEXT_CONSOLE(con));
1397b2bb9cc4SMarc-André Lureau         if (label) {
1398f7ce755dSMarc-André Lureau             return g_strdup(label);
1399f7ce755dSMarc-André Lureau         }
1400f7ce755dSMarc-André Lureau     }
1401779ce88fSGerd Hoffmann 
1402b2bb9cc4SMarc-André Lureau     return g_strdup_printf("vc%d", con->index);
1403b2bb9cc4SMarc-André Lureau }
1404779ce88fSGerd Hoffmann 
qemu_console_get_index(QemuConsole * con)1405779ce88fSGerd Hoffmann int qemu_console_get_index(QemuConsole *con)
1406779ce88fSGerd Hoffmann {
1407d4c85337SGerd Hoffmann     return con ? con->index : -1;
1408d4c85337SGerd Hoffmann }
1409d4c85337SGerd Hoffmann 
qemu_console_get_head(QemuConsole * con)1410d4c85337SGerd Hoffmann uint32_t qemu_console_get_head(QemuConsole *con)
1411d4c85337SGerd Hoffmann {
14125643706aSGerd Hoffmann     if (con == NULL) {
14135643706aSGerd Hoffmann         return -1;
14145643706aSGerd Hoffmann     }
141558d58708SMarc-André Lureau     if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
141658d58708SMarc-André Lureau         return QEMU_GRAPHIC_CONSOLE(con)->head;
141758d58708SMarc-André Lureau     }
141858d58708SMarc-André Lureau     return 0;
141958d58708SMarc-André Lureau }
142058d58708SMarc-André Lureau 
qemu_console_get_width(QemuConsole * con,int fallback)14215643706aSGerd Hoffmann int qemu_console_get_width(QemuConsole *con, int fallback)
14225643706aSGerd Hoffmann {
1423d4c85337SGerd Hoffmann     if (con == NULL) {
1424d4c85337SGerd Hoffmann         return fallback;
1425d4c85337SGerd Hoffmann     }
1426ebced091SMarc-André Lureau     switch (con->scanout.kind) {
1427ebced091SMarc-André Lureau     case SCANOUT_DMABUF:
1428ebced091SMarc-André Lureau         return qemu_dmabuf_get_width(con->scanout.dmabuf);
1429ebced091SMarc-André Lureau     case SCANOUT_TEXTURE:
14306779a307SDongwon Kim         return con->scanout.texture.width;
1431ebced091SMarc-André Lureau     case SCANOUT_SURFACE:
1432ebced091SMarc-André Lureau         return surface_width(con->surface);
1433ebced091SMarc-André Lureau     default:
1434ebced091SMarc-André Lureau         return fallback;
1435ebced091SMarc-André Lureau     }
1436ebced091SMarc-André Lureau }
1437ebced091SMarc-André Lureau 
qemu_console_get_height(QemuConsole * con,int fallback)1438d4c85337SGerd Hoffmann int qemu_console_get_height(QemuConsole *con, int fallback)
1439d4c85337SGerd Hoffmann {
1440d4c85337SGerd Hoffmann     if (con == NULL) {
1441d4c85337SGerd Hoffmann         return fallback;
1442d4c85337SGerd Hoffmann     }
1443ebced091SMarc-André Lureau     switch (con->scanout.kind) {
1444ebced091SMarc-André Lureau     case SCANOUT_DMABUF:
1445ebced091SMarc-André Lureau         return qemu_dmabuf_get_height(con->scanout.dmabuf);
1446ebced091SMarc-André Lureau     case SCANOUT_TEXTURE:
14476779a307SDongwon Kim         return con->scanout.texture.height;
1448ebced091SMarc-André Lureau     case SCANOUT_SURFACE:
1449ebced091SMarc-André Lureau         return surface_height(con->surface);
1450ebced091SMarc-André Lureau     default:
1451ebced091SMarc-André Lureau         return fallback;
1452ebced091SMarc-André Lureau     }
1453ebced091SMarc-André Lureau }
1454ebced091SMarc-André Lureau 
qemu_invalidate_text_consoles(void)1455d4c85337SGerd Hoffmann int qemu_invalidate_text_consoles(void)
1456d4c85337SGerd Hoffmann {
1457322dae4bSMarc-André Lureau     QemuConsole *s;
145828ecbaeeSPaolo Bonzini     int count = 0;
1459aea7947cSGerd Hoffmann 
1460cd6cd8faSGerd Hoffmann     QTAILQ_FOREACH(s, &consoles, next) {
146128ecbaeeSPaolo Bonzini         if (qemu_console_is_graphic(s) ||
1462cd6cd8faSGerd Hoffmann             !qemu_console_is_visible(s)) {
1463aea7947cSGerd Hoffmann             continue;
1464aea7947cSGerd Hoffmann         }
1465aea7947cSGerd Hoffmann         count++;
1466aea7947cSGerd Hoffmann         graphic_hw_invalidate(s);
1467aea7947cSGerd Hoffmann     }
14681dbfa005SGerd Hoffmann 
1469aea7947cSGerd Hoffmann     return count;
1470aea7947cSGerd Hoffmann }
1471322dae4bSMarc-André Lureau 
qemu_console_resize(QemuConsole * s,int width,int height)1472322dae4bSMarc-André Lureau void qemu_console_resize(QemuConsole *s, int width, int height)
1473322dae4bSMarc-André Lureau {
1474c78f7137SGerd Hoffmann     DisplaySurface *surface = qemu_console_surface(s);
147528ecbaeeSPaolo Bonzini 
147688738ea4SMarc-André Lureau     assert(QEMU_IS_GRAPHIC_CONSOLE(s));
1477321f048dSGerd Hoffmann 
1478c105d60fSMarc-André Lureau     if ((s->scanout.kind != SCANOUT_SURFACE ||
1479cd958edbSMarc-André Lureau          (surface && surface_is_allocated(surface) &&
148088738ea4SMarc-André Lureau                      !surface_is_placeholder(surface))) &&
1481abd749b5SGerd Hoffmann         qemu_console_get_width(s, -1) == width &&
1482abd749b5SGerd Hoffmann         qemu_console_get_height(s, -1) == height) {
148388738ea4SMarc-André Lureau         return;
1484cb8962c1SMarc-André Lureau     }
1485cd958edbSMarc-André Lureau 
1486cd958edbSMarc-André Lureau     surface = qemu_create_displaysurface(width, height);
1487cd958edbSMarc-André Lureau     dpy_gfx_replace_surface(s, surface);
1488da229ef3SGerd Hoffmann }
1489c78f7137SGerd Hoffmann 
qemu_console_surface(QemuConsole * console)149028ecbaeeSPaolo Bonzini DisplaySurface *qemu_console_surface(QemuConsole *console)
149128ecbaeeSPaolo Bonzini {
1492c78f7137SGerd Hoffmann     switch (console->scanout.kind) {
1493c78f7137SGerd Hoffmann     case SCANOUT_SURFACE:
1494ebced091SMarc-André Lureau         return console->surface;
1495ebced091SMarc-André Lureau     default:
1496321f048dSGerd Hoffmann         return NULL;
1497ebced091SMarc-André Lureau     }
1498ebced091SMarc-André Lureau }
1499ebced091SMarc-André Lureau 
qemu_default_pixelformat(int bpp)1500c78f7137SGerd Hoffmann PixelFormat qemu_default_pixelformat(int bpp)
1501c78f7137SGerd Hoffmann {
150228ecbaeeSPaolo Bonzini     pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
150328ecbaeeSPaolo Bonzini     PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
150456bd9ea1SGerd Hoffmann     return pf;
150556bd9ea1SGerd Hoffmann }
150628ecbaeeSPaolo Bonzini 
150728ecbaeeSPaolo Bonzini static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
150801f45d98SAnthony Liguori 
qemu_display_register(QemuDisplay * ui)1509db71589fSGerd Hoffmann void qemu_display_register(QemuDisplay *ui)
1510db71589fSGerd Hoffmann {
1511db71589fSGerd Hoffmann     assert(ui->type < DISPLAY_TYPE__MAX);
1512db71589fSGerd Hoffmann     dpys[ui->type] = ui;
1513db71589fSGerd Hoffmann }
1514db71589fSGerd Hoffmann 
qemu_display_find_default(DisplayOptions * opts)1515db71589fSGerd Hoffmann bool qemu_display_find_default(DisplayOptions *opts)
1516db71589fSGerd Hoffmann {
1517898f9d41SGerd Hoffmann     static DisplayType prio[] = {
1518898f9d41SGerd Hoffmann #if defined(CONFIG_GTK)
1519898f9d41SGerd Hoffmann         DISPLAY_TYPE_GTK,
152066c2207fSThomas Huth #endif
1521898f9d41SGerd Hoffmann #if defined(CONFIG_SDL)
152266c2207fSThomas Huth         DISPLAY_TYPE_SDL,
152366c2207fSThomas Huth #endif
1524898f9d41SGerd Hoffmann #if defined(CONFIG_COCOA)
152566c2207fSThomas Huth         DISPLAY_TYPE_COCOA
152666c2207fSThomas Huth #endif
1527898f9d41SGerd Hoffmann     };
152866c2207fSThomas Huth     int i;
1529898f9d41SGerd Hoffmann 
1530898f9d41SGerd Hoffmann     for (i = 0; i < (int)ARRAY_SIZE(prio); i++) {
1531898f9d41SGerd Hoffmann         if (dpys[prio[i]] == NULL) {
153266c2207fSThomas Huth             Error *local_err = NULL;
1533898f9d41SGerd Hoffmann             int rv = ui_module_load(DisplayType_str(prio[i]), &local_err);
1534c551fb0bSClaudio Fontana             if (rv < 0) {
1535c551fb0bSClaudio Fontana                 error_report_err(local_err);
1536c551fb0bSClaudio Fontana             }
1537c551fb0bSClaudio Fontana         }
1538c551fb0bSClaudio Fontana         if (dpys[prio[i]] == NULL) {
153961b4d9a2SGerd Hoffmann             continue;
154061b4d9a2SGerd Hoffmann         }
1541898f9d41SGerd Hoffmann         opts->type = prio[i];
1542898f9d41SGerd Hoffmann         return true;
1543898f9d41SGerd Hoffmann     }
1544898f9d41SGerd Hoffmann     return false;
1545898f9d41SGerd Hoffmann }
1546898f9d41SGerd Hoffmann 
qemu_display_early_init(DisplayOptions * opts)1547898f9d41SGerd Hoffmann void qemu_display_early_init(DisplayOptions *opts)
1548898f9d41SGerd Hoffmann {
1549db71589fSGerd Hoffmann     assert(opts->type < DISPLAY_TYPE__MAX);
1550db71589fSGerd Hoffmann     if (opts->type == DISPLAY_TYPE_NONE) {
1551db71589fSGerd Hoffmann         return;
1552db71589fSGerd Hoffmann     }
1553db71589fSGerd Hoffmann     if (dpys[opts->type] == NULL) {
1554db71589fSGerd Hoffmann         Error *local_err = NULL;
1555db71589fSGerd Hoffmann         int rv = ui_module_load(DisplayType_str(opts->type), &local_err);
1556c551fb0bSClaudio Fontana         if (rv < 0) {
1557c551fb0bSClaudio Fontana             error_report_err(local_err);
1558c551fb0bSClaudio Fontana         }
1559c551fb0bSClaudio Fontana     }
1560c551fb0bSClaudio Fontana     if (dpys[opts->type] == NULL) {
156161b4d9a2SGerd Hoffmann         error_report("Display '%s' is not available.",
156261b4d9a2SGerd Hoffmann                      DisplayType_str(opts->type));
1563db71589fSGerd Hoffmann         exit(1);
1564c809d1d2SMarc-André Lureau     }
1565db71589fSGerd Hoffmann     if (dpys[opts->type]->early_init) {
1566db71589fSGerd Hoffmann         dpys[opts->type]->early_init(opts);
1567db71589fSGerd Hoffmann     }
1568db71589fSGerd Hoffmann }
1569db71589fSGerd Hoffmann 
qemu_display_init(DisplayState * ds,DisplayOptions * opts)1570db71589fSGerd Hoffmann void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
1571db71589fSGerd Hoffmann {
1572db71589fSGerd Hoffmann     assert(opts->type < DISPLAY_TYPE__MAX);
1573db71589fSGerd Hoffmann     if (opts->type == DISPLAY_TYPE_NONE) {
1574db71589fSGerd Hoffmann         return;
1575db71589fSGerd Hoffmann     }
1576db71589fSGerd Hoffmann     assert(dpys[opts->type] != NULL);
1577db71589fSGerd Hoffmann     dpys[opts->type]->init(ds, opts);
1578db71589fSGerd Hoffmann }
1579db71589fSGerd Hoffmann 
qemu_display_get_vc(DisplayOptions * opts)1580db71589fSGerd Hoffmann const char *qemu_display_get_vc(DisplayOptions *opts)
1581db71589fSGerd Hoffmann {
15821bec1cc0SMarc-André Lureau #ifdef CONFIG_PIXMAN
15831bec1cc0SMarc-André Lureau     const char *vc = "vc:80Cx24C";
1584600179c3SMarc-André Lureau #else
15850e882307SMarc-André Lureau     const char *vc = NULL;
15860e882307SMarc-André Lureau #endif
15870e882307SMarc-André Lureau 
1588600179c3SMarc-André Lureau     assert(opts->type < DISPLAY_TYPE__MAX);
15890e882307SMarc-André Lureau     if (dpys[opts->type] && dpys[opts->type]->vc) {
15900e882307SMarc-André Lureau         vc = dpys[opts->type]->vc;
15910e882307SMarc-André Lureau     }
15920e882307SMarc-André Lureau     return vc;
15931bec1cc0SMarc-André Lureau }
15940e882307SMarc-André Lureau 
qemu_display_help(void)15951bec1cc0SMarc-André Lureau void qemu_display_help(void)
15961bec1cc0SMarc-André Lureau {
1597c388f408SThomas Huth     int idx;
1598c388f408SThomas Huth 
1599c388f408SThomas Huth     printf("Available display backend types:\n");
1600c388f408SThomas Huth     printf("none\n");
1601c388f408SThomas Huth     for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
1602a1e8853eSPhilippe Mathieu-Daudé         if (!dpys[idx]) {
1603c388f408SThomas Huth             Error *local_err = NULL;
1604c388f408SThomas Huth             int rv = ui_module_load(DisplayType_str(idx), &local_err);
1605c551fb0bSClaudio Fontana             if (rv < 0) {
1606c551fb0bSClaudio Fontana                 error_report_err(local_err);
1607c551fb0bSClaudio Fontana             }
1608c551fb0bSClaudio Fontana         }
1609c551fb0bSClaudio Fontana         if (dpys[idx]) {
1610c388f408SThomas Huth             printf("%s\n",  DisplayType_str(dpys[idx]->type));
1611c388f408SThomas Huth         }
1612c388f408SThomas Huth     }
1613c388f408SThomas Huth     printf("\n"
1614c388f408SThomas Huth            "Some display backends support suboptions, which can be set with\n"
1615ef0a1212SPeter Maydell            "   -display backend,option=value,option=value...\n"
1616ef0a1212SPeter Maydell            "For a short list of the suboptions for each display, see the "
1617ef0a1212SPeter Maydell            "top-level -help output; more detail is in the documentation.\n");
1618ef0a1212SPeter Maydell }
1619ef0a1212SPeter Maydell