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