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