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