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