Skip to contentSkip to conversation

UI patches

GIT PULL Applied [email protected] 2 participants 35 messages May 9 – May 11

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

From: Marc-André Lureau <[email protected]>

The following changes since commit ee7eb612be8f8886d48c1d0c1f1c65e495138f83:

Merge tag 'single-binary-20260506' of https://github.com/philmd/qemu into staging (2026-05-06 10:45:02 -0400)

are available in the Git repository at:

https://gitlab.com/marcandre.lureau/qemu.git tags/ui-pull-request

for you to fetch changes up to e4c7ebde643811e8dc1f640b50f37ad0a0dd1dac:

qemu-options: document -chardev dbus (2026-05-09 18:54:16 +0400)

----------------------------------------------------------------
- gtk clipboard fixes
- dbus-vmstate test fixes
- vt100 emulator support for utf8
- qemu-vnc tool

----------------------------------------------------------------

Fabiano Rosas (5):
tests/qtest/dbus-vmstate: Bring the test up-to-date tests/qtest/dbus-vmstate: Mute Glib complaints about g_unsetenv
thread-safety
tests/qtest/dbus-vmstate: Honor QTEST_LOG env variable tests/qtest/dbus-vmstate: Stop the daemons explicitly tests/qtest/dbus-vmstate: Re-enable the test

Jindřich Makovička (1):
ui/gtk: Fix GTK assertion failure introduced with clipboard fixes

Marc-André Lureau (26):
ui/input: do not assert() when tracing invalid input qemu-options.hx: document -chardev vc backend-specific behavior
char: error out if given unhandled size options ui/console: add vc encoding=utf8/cp437 option
ui/console: default vc encoding to cp437 for machine < 11.1 ui/dbus: expose vc encoding via D-Bus Chardev.VCEncoding interface ui/console-vc: add UTF-8 input decoding with CP437 rendering ui/console-vc: move VT100 state machine and output FIFO into QemuVT100 ui/console-vc: extract vt100_input() from vc_chr_write() ui/console-vc: extract vt100_keysym() from
qemu_text_console_handle_keysym()
ui/console-vc: extract vt100_init() and vt100_fini() ui/console: remove console_ch_t typedef and console_write_ch() ui/console-vc: move VT100 emulation into separate unit ui/vnc: make the worker thread per-VncDisplay
ui/vnc: vnc_display_init() and vnc_display_open() return bool ui/vnc: merge vnc_display_init() and vnc_display_open() ui/vnc: clean up VNC displays on exit
ui/vnc: defer listener registration until the console is known ui/vnc: add vnc-system unit, to allow different implementations ui/console: simplify registering display/console change listener ui/console: add doc comment for qemu_console_{un}register_listener() ui/console: rename public API to use consistent qemu_console_ prefix ui/vnc: replace VNC_DEBUG with trace-events
ui: extract common sources into a static library tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR
tools/qemu-vnc: add standalone VNC server over D-Bus

uchouT (1):
qemu-options: document -chardev dbus

 MAINTAINERS                      |    5 +
 docs/conf.py                     |    3 +
 docs/interop/dbus-display.rst    |    2 +
 docs/interop/dbus-vnc.rst        |   26 +
 docs/interop/index.rst           |    1 +
 docs/meson.build                 |    1 +
 docs/tools/index.rst             |    1 +
 docs/tools/qemu-vnc.rst          |  226 +++++
 meson.build                      |   17 +
 qapi/char.json                   |   30 +-
 include/chardev/char.h           |   21 +
 include/qemu/option.h            |    1 +
 include/ui/console.h             |  124 ++-
 tools/qemu-vnc/qemu-vnc.h        |   49 ++
 tools/qemu-vnc/trace.h           |    4 +
 ui/console-priv.h                |    1 -
 ui/cp437.h                       |   13 +
 ui/dbus.h                        |    1 +
 ui/vnc-jobs.h                    |    3 +-
 ui/vnc.h                         |   17 +-
 ui/vt100.h                       |   95 +++
 chardev/char.c                   |   22 +
 hw/arm/musicpal.c                |    4 +-
 hw/core/machine.c                |    4 +-
 hw/display/artist.c              |    4 +-
 hw/display/ati.c                 |   16 +-
 hw/display/bcm2835_fb.c          |    5 +-
 hw/display/bochs-display.c       |   14 +-
 hw/display/cg3.c                 |    6 +-
 hw/display/cirrus_vga.c          |    8 +-
 hw/display/cirrus_vga_isa.c      |    2 +-
 hw/display/dm163.c               |    6 +-
 hw/display/exynos4210_fimd.c     |    4 +-
 hw/display/g364fb.c              |   10 +-
 hw/display/imx6ul_lcdif.c        |   14 +-
 hw/display/jazz_led.c            |   18 +-
 hw/display/macfb.c               |    6 +-
 hw/display/next-fb.c             |    4 +-
 hw/display/omap_lcdc.c           |    4 +-
 hw/display/pl110.c               |    4 +-
 hw/display/qxl-render.c          |   12 +-
 hw/display/qxl.c                 |   18 +-
 hw/display/ramfb-standalone.c    |    2 +-
 hw/display/ramfb.c               |    4 +-
 hw/display/sm501.c               |    6 +-
 hw/display/ssd0303.c             |    4 +-
 hw/display/ssd0323.c             |    5 +-
 hw/display/tcx.c                 |   16 +-
 hw/display/vga-isa.c             |    2 +-
 hw/display/vga-mmio.c            |    2 +-
 hw/display/vga-pci.c             |    6 +-
 hw/display/vga.c                 |   56 +-
 hw/display/vhost-user-gpu.c      |   22 +-
 hw/display/virtio-gpu-base.c     |    4 +-
 hw/display/virtio-gpu-rutabaga.c |   10 +-
 hw/display/virtio-gpu-udmabuf.c  |    4 +-
 hw/display/virtio-gpu-virgl.c    |   20 +-
 hw/display/virtio-gpu.c          |   26 +-
 hw/display/virtio-vga.c          |    4 +-
 hw/display/vmware_vga.c          |   14 +-
 hw/display/xenfb.c               |    6 +-
 hw/display/xlnx_dp.c             |   10 +-
 hw/vfio/display.c                |   32 +-
 system/runstate.c                |    5 +
 tests/qtest/dbus-vmstate-test.c  |  123 ++-
 tests/qtest/dbus-vnc-test.c      | 1346 ++++++++++++++++++++++++++++++
 tools/qemu-vnc/audio.c           |  308 +++++++
 tools/qemu-vnc/chardev.c         |  148 ++++
 tools/qemu-vnc/clipboard.c       |  376 +++++++++
 tools/qemu-vnc/console.c         |  170 ++++
 tools/qemu-vnc/dbus.c            |  474 +++++++++++
 tools/qemu-vnc/display.c         |  456 ++++++++++
 tools/qemu-vnc/input.c           |  239 ++++++
 tools/qemu-vnc/qemu-vnc.c        |  581 +++++++++++++
 tools/qemu-vnc/stubs.c           |   62 ++
 tools/qemu-vnc/utils.c           |   59 ++
 ui/console-vc-stubs.c            |    1 +
 ui/console-vc.c                  | 1074 ++----------------------
 ui/console.c                     |  173 ++--
 ui/cp437.c                       |  205 +++++
 ui/curses.c                      |   23 +-
 ui/dbus-chardev.c                |   10 +
 ui/dbus-console.c                |   10 +-
 ui/dbus-listener.c               |   37 +-
 ui/dbus.c                        |   59 ++
 ui/egl-headless.c                |    8 +-
 ui/gtk-clipboard.c               |    2 +-
 ui/gtk-egl.c                     |    6 +-
 ui/gtk-gl-area.c                 |    6 +-
 ui/gtk.c                         |   28 +-
 ui/input.c                       |    8 +-
 ui/sdl2-2d.c                     |    2 +-
 ui/sdl2-gl.c                     |    2 +-
 ui/sdl2.c                        |   14 +-
 ui/spice-display.c               |   24 +-
 ui/vnc-auth-sasl.c               |   13 +-
 ui/vnc-enc-tight.c               |    4 +-
 ui/vnc-enc-zlib.c                |    4 +-
 ui/vnc-jobs.c                    |   62 +-
 ui/vnc-system.c                  |   19 +
 ui/vnc-ws.c                      |   10 +-
 ui/vnc.c                         |  232 +++--
 ui/vt100.c                       |  984 ++++++++++++++++++++++
 util/qemu-option.c               |   13 +
 hw/display/apple-gfx.m           |   16 +-
 meson_options.txt                |    2 +
 qemu-options.hx                  |   36 +-
 scripts/meson-buildoptions.sh    |    3 +
 tests/dbus-daemon.sh             |   16 +-
 tests/qtest/meson.build          |   23 +-
 tools/qemu-vnc/meson.build       |   26 +
 tools/qemu-vnc/qemu-vnc1.xml     |  201 +++++
 tools/qemu-vnc/trace-events      |   21 +
 ui/cocoa.m                       |   23 +-
 ui/dbus-display1.xml             |   18 +
 ui/meson.build                   |  103 +--
 ui/trace-events                  |   29 +-
 117 files changed, 7221 insertions(+), 1757 deletions(-)
 create mode 100644 docs/interop/dbus-vnc.rst
 create mode 100644 docs/tools/qemu-vnc.rst
 create mode 100644 tools/qemu-vnc/qemu-vnc.h
 create mode 100644 tools/qemu-vnc/trace.h
 create mode 100644 ui/cp437.h
 create mode 100644 ui/vt100.h
 create mode 100644 tests/qtest/dbus-vnc-test.c
 create mode 100644 tools/qemu-vnc/audio.c
 create mode 100644 tools/qemu-vnc/chardev.c
 create mode 100644 tools/qemu-vnc/clipboard.c
 create mode 100644 tools/qemu-vnc/console.c
 create mode 100644 tools/qemu-vnc/dbus.c
 create mode 100644 tools/qemu-vnc/display.c
 create mode 100644 tools/qemu-vnc/input.c
 create mode 100644 tools/qemu-vnc/qemu-vnc.c
 create mode 100644 tools/qemu-vnc/stubs.c
 create mode 100644 tools/qemu-vnc/utils.c
 create mode 100644 ui/cp437.c
 create mode 100644 ui/vnc-system.c
 create mode 100644 ui/vt100.c
 create mode 100644 tools/qemu-vnc/meson.build
 create mode 100644 tools/qemu-vnc/qemu-vnc1.xml
 create mode 100644 tools/qemu-vnc/trace-events
Signature · 1 line
2.54.0
#1 lore raw

[PULL v2 02/33] tests/qtest/dbus-vmstate: Mute Glib complaints about g_unsetenv thread-safety

From: Fabiano Rosas <[email protected]>

TLDR: GLib is bugged, the dbus-vmstate-test spams debug messages unconditionally. Mute them.

GLib is trying to protect against the lack of thread-safety of setenv/unsetsenv functions by warning when those functions were invoked after a thread has been started.
https://gitlab.gnome.org/GNOME/glib/issues/715

Unfortunately:
1) GLib itself starts a thread pool via _g_dbus_initialize when working around a bug in its type dependency chain. This happens in many places, but the test triggers it via g_dbus_address_get_for_bus_sync.
https://bugzilla.gnome.org/show_bug.cgi?id=627724

2) GLib itself calls g_unsetenv after the test calls g_test_dbus_up.

3) The debug message at g_unsetenv is issued to the G_LOG_DOMAIN defined while compiling the library, i.e "GLib", but this domain is never initialized, so the log functions go into a fallback chain that results in ignoring the G_MESSAGES_DEBUG environment variable, causing the debug messages to not be suppressed when they should.

Mute the messages by implementing a handler for G_LOG_LEVEL_DEBUG in the "GLib" log domain and honoring G_MESSAGES_DEBUG.

Message-ID: <[email protected]>

---
 tests/qtest/dbus-vmstate-test.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
tests/qtest/dbus-vmstate-test.c +21 -0
index 90c050b4480..51c5fdb995a 100644
@@ -357,12 +357,33 @@ test_dbus_vmstate_missing_dst(char *name, MigrateCommon *args)
     g_test_trap_assert_passed();
 }
 
+static void log_func(const gchar *log_domain, GLogLevelFlags log_level,
+                     const gchar *message, gpointer user_data)
+{
+    const gchar *domains;
+
+    assert(log_level & G_LOG_LEVEL_DEBUG);
+
+    domains = getenv("G_MESSAGES_DEBUG");
+    if (!domains || (!strstr(domains, "GLib") && !strstr(domains, "all"))) {
+        return;
+    }
+    g_log_default_handler("GLib", G_LOG_LEVEL_DEBUG, message, NULL);
+}
+
 int
 main(int argc, char **argv)
 {
     GError *err = NULL;
     int ret;
 
+    /*
+     * GLib currently emits debug messages that ignore
+     * G_MESSAGES_DEBUG. Set a custom log handler to work around the
+     * issue.
+     */
+    g_log_set_handler("GLib", G_LOG_LEVEL_DEBUG, log_func, NULL);
+
     g_test_init(&argc, &argv, NULL);
 
     workdir = g_dir_make_tmp("dbus-vmstate-test-XXXXXX", &err);
Signature · 1 line
2.54.0
#2 lore raw

[PULL v2 05/33] tests/qtest/dbus-vmstate: Re-enable the test

In reply to [email protected]

From: Fabiano Rosas <[email protected]>

Back in 2020, the dbus-vmstate test was disabled by commit d46f81cb74 ("tests: Disable dbus-vmstate-test") due to Patchew failures. We don't use Patchew anymore for CI, so re-enable the test.

G_TEST_DBUS_DAEMON=../tests/dbus-vmstate-daemon.sh \
QTEST_QEMU_BINARY=./qemu-system-x86_64 \
./tests/qtest/dbus-vmstate-test

Message-ID: <[email protected]>

---
 tests/qtest/meson.build | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
tests/qtest/meson.build +1 -2
index ba890c2b554..0067f767eea 100644
@@ -125,8 +125,7 @@ endif
 
 dbus_daemon = find_program('dbus-daemon', required: false)
 if dbus_daemon.found() and gdbus_codegen.found()
-  # Temporarily disabled due to Patchew failures:
-  #qtests_i386 += ['dbus-vmstate-test']
+  qtests_i386 += ['dbus-vmstate-test']
   dbus_vmstate1 = custom_target('dbus-vmstate description',
                                 build_by_default: true,
                                 output: [ 'dbus-vmstate1.h', 'dbus-vmstate1.c'],
Signature · 1 line
2.54.0
#3 lore raw

[PULL v2 01/33] tests/qtest/dbus-vmstate: Bring the test up-to-date

In reply to [email protected]

From: Fabiano Rosas <[email protected]>

The dbus-vmstate-test has been disabled for years. Here's the things that have changed in the meantime and how to update the test:

- Migration tests got new headers.
Update the includes.

- migrate_qmp got new parameters.
Update the caller.

- migrate_incoming_qmp is now used instead of -incoming URL. Use -incoming defer.

- Tests expecting failure should not check non-zero return code. Check for failed migration state instead.

- The test result enum was introduced.
Replace the migration_fail flag with the enum.

- The DEVICE state was added.
Replace wait_for_migration_complete with migration_event_wait, which won't trip on intermediary states.

- Migration completion was reworked.
Explicitly wait for the RESUME event before asserting runstate is RUNNING to avoid checking too quickly and seeing FINISH_MIGRATE instead.

- The FAILING state was added.
Wait for it before waiting for the RESUME event.

- Sanity checks were added to migration_get_env(). Start calling that function in main.

- qtest_add_func now has a wrapper.
Replace qtest_add_func with migration_test_add. Update tests' signatures to take MigrationCommon, although it's unused.

- meson now sets up G_TEST_DBUS_DAEMON.
Remove the logic around it.

Message-ID: <[email protected]>

---
 tests/qtest/dbus-vmstate-test.c | 71 +++++++++++++++++++--------------
 tests/qtest/meson.build         |  7 +++-
 2 files changed, 46 insertions(+), 32 deletions(-)
tests/qtest/dbus-vmstate-test.c +41 -30
index 0a82cc9f935..90c050b4480 100644
@@ -2,8 +2,8 @@
 #include <glib/gstdio.h>
 #include <gio/gio.h>
 #include "libqtest.h"
+#include "migration/migration-qmp.h"
 #include "dbus-vmstate1.h"
-#include "migration-helpers.h"
 
 static char *workdir;
 
@@ -29,7 +29,7 @@ typedef struct TestServer {
 
 typedef struct Test {
     const char *id_list;
-    bool migrate_fail;
+    int result;
     bool without_dst_b;
     TestServer srcA;
     TestServer dstA;
@@ -190,6 +190,7 @@ test_dbus_vmstate(Test *test)
     g_autofree char *uri = NULL;
     QTestState *src_qemu = NULL, *dst_qemu = NULL;
     guint ownsrcA, ownsrcB, owndstA, owndstB;
+    QTestMigrationState src_state = { };
 
     uri = g_strdup_printf("unix:%s/migsocket", workdir);
 
@@ -224,17 +225,33 @@ test_dbus_vmstate(Test *test)
 
     src_qemu = qtest_init(src_qemu_args);
     dst_qemu = qtest_init(dst_qemu_args);
+
+    migrate_set_capability(src_qemu, "events", true);
+    qtest_qmp_set_event_callback(src_qemu, migrate_watch_for_events,
+                                 &src_state);
+
     set_id_list(test, src_qemu);
     set_id_list(test, dst_qemu);
 
     thread = g_thread_new("dbus-vmstate-thread", dbus_vmstate_thread, loop);
 
     migrate_incoming_qmp(dst_qemu, uri, NULL, "{}");
-    migrate_qmp(src_qemu, uri, "{}");
+    migrate_ensure_converge(src_qemu);
+    migrate_qmp(src_qemu, NULL, uri, NULL, "{}");
     test->src_qemu = src_qemu;
-    if (test->migrate_fail) {
-        wait_for_migration_fail(src_qemu, true);
-        qtest_set_expected_status(dst_qemu, EXIT_FAILURE);
+
+    if (test->result != MIG_TEST_SUCCEED) {
+        QDict *rsp;
+
+        migration_event_wait(src_qemu, "failing");
+        wait_for_resume(src_qemu, &src_state);
+        migration_event_wait(src_qemu, "failed");
+
+        rsp = qtest_qmp_assert_success_ref(src_qemu,
+                                           "{ 'execute': 'query-status' }");
+        g_assert(qdict_haskey(rsp, "running"));
+        g_assert(qdict_get_bool(rsp, "running"));
+        qobject_unref(rsp);
     } else {
         wait_for_migration_complete(src_qemu);
     }
@@ -270,7 +287,7 @@ check_migrated(TestServer *s, TestServer *d)
 }
 
 static void
-test_dbus_vmstate_without_list(void)
+test_dbus_vmstate_without_list(char *name, MigrateCommon *args)
 {
     Test test = { 0, };
 
@@ -281,7 +298,7 @@ test_dbus_vmstate_without_list(void)
 }
 
 static void
-test_dbus_vmstate_with_list(void)
+test_dbus_vmstate_with_list(char *name, MigrateCommon *args)
 {
     Test test = { .id_list = "idA,idB" };
 
@@ -292,7 +309,7 @@ test_dbus_vmstate_with_list(void)
 }
 
 static void
-test_dbus_vmstate_only_a(void)
+test_dbus_vmstate_only_a(char *name, MigrateCommon *args)
 {
     Test test = { .id_list = "idA" };
 
@@ -303,9 +320,10 @@ test_dbus_vmstate_only_a(void)
 }
 
 static void
-test_dbus_vmstate_missing_src(void)
+test_dbus_vmstate_missing_src(char *name, MigrateCommon *args)
 {
-    Test test = { .id_list = "idA,idC", .migrate_fail = true };
+    Test test = { .id_list = "idA,idC",
+        .result = MIG_TEST_FAIL };
 
     /* run in subprocess to silence QEMU error reporting */
     if (g_test_subprocess()) {
@@ -320,11 +338,11 @@ test_dbus_vmstate_missing_src(void)
 }
 
 static void
-test_dbus_vmstate_missing_dst(void)
+test_dbus_vmstate_missing_dst(char *name, MigrateCommon *args)
 {
     Test test = { .id_list = "idA,idB",
                   .without_dst_b = true,
-                  .migrate_fail = true };
+                  .result = MIG_TEST_FAIL };
 
     /* run in subprocess to silence QEMU error reporting */
     if (g_test_subprocess()) {
@@ -343,15 +361,8 @@ int
 main(int argc, char **argv)
 {
     GError *err = NULL;
-    g_autofree char *dbus_daemon = NULL;
     int ret;
 
-    dbus_daemon = g_build_filename(G_STRINGIFY(SRCDIR),
-                                   "tests",
-                                   "dbus-vmstate-daemon.sh",
-                                   NULL);
-    g_setenv("G_TEST_DBUS_DAEMON", dbus_daemon, true);
-
     g_test_init(&argc, &argv, NULL);
 
     workdir = g_dir_make_tmp("dbus-vmstate-test-XXXXXX", &err);
@@ -362,16 +373,16 @@ main(int argc, char **argv)
 
     g_setenv("DBUS_VMSTATE_TEST_TMPDIR", workdir, true);
 
-    qtest_add_func("/dbus-vmstate/without-list",
-                   test_dbus_vmstate_without_list);
-    qtest_add_func("/dbus-vmstate/with-list",
-                   test_dbus_vmstate_with_list);
-    qtest_add_func("/dbus-vmstate/only-a",
-                   test_dbus_vmstate_only_a);
-    qtest_add_func("/dbus-vmstate/missing-src",
-                   test_dbus_vmstate_missing_src);
-    qtest_add_func("/dbus-vmstate/missing-dst",
-                   test_dbus_vmstate_missing_dst);
+    migration_test_add("/dbus-vmstate/without-list",
+                       test_dbus_vmstate_without_list);
+    migration_test_add("/dbus-vmstate/with-list",
+                       test_dbus_vmstate_with_list);
+    migration_test_add("/dbus-vmstate/only-a",
+                       test_dbus_vmstate_only_a);
+    migration_test_add("/dbus-vmstate/missing-src",
+                       test_dbus_vmstate_missing_src);
+    migration_test_add("/dbus-vmstate/missing-dst",
+                       test_dbus_vmstate_missing_dst);
 
     ret = g_test_run();
 
tests/qtest/meson.build +5 -2
index 43f83ffd3aa..ba890c2b554 100644
@@ -128,10 +128,12 @@ if dbus_daemon.found() and gdbus_codegen.found()
   # Temporarily disabled due to Patchew failures:
   #qtests_i386 += ['dbus-vmstate-test']
   dbus_vmstate1 = custom_target('dbus-vmstate description',
-                                output: ['dbus-vmstate1.h', 'dbus-vmstate1.c'],
+                                build_by_default: true,
+                                output: [ 'dbus-vmstate1.h', 'dbus-vmstate1.c'],
                                 input: meson.project_source_root() / 'backends/dbus-vmstate1.xml',
                                 command: [gdbus_codegen, '@INPUT@',
                                           '--interface-prefix', 'org.qemu',
+                                          '--output-directory', meson.current_build_dir(),
                                           '--generate-c-code', '@BASENAME@']).to_list()
 else
   dbus_vmstate1 = []
@@ -387,7 +389,8 @@ qtests = {
   'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'],
   'cdrom-test': files('boot-sector.c'),
   'dbus-vmstate-test': files('migration/migration-qmp.c',
-                             'migration/migration-util.c') + dbus_vmstate1,
+                             'migration/migration-util.c') + dbus_vmstate1 +
+                       [gio],
   'erst-test': files('erst-test.c'),
   'ivshmem-test': [rt, '../../contrib/ivshmem-server/ivshmem-server.c'],
   'migration-test': test_migration_files + migration_tls_files + migration_colo_files,
Signature · 1 line
2.54.0
#4 lore raw

[PULL v2 07/33] ui/gtk: Fix GTK assertion failure introduced with clipboard fixes

In reply to [email protected]

From: Jindřich Makovička <[email protected]>

gtk_clipboard_request_targets actually returns n_targets == -1 when targets == NULL instead of zero. This result in failed assertion within GTK:

qemu: Gtk: gtk_targets_include_text:
assertion 'targets != NULL || n_targets == 0' failed

Extend the check to require non-null targets and positive n_targets.

Message-ID: <[email protected]>

---
 ui/gtk-clipboard.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
ui/gtk-clipboard.c +1 -1
index 463ed4e905b..ea9444be70f 100644
@@ -175,7 +175,7 @@ static void gd_clipboard_owner_change_targets_received_callback(
 {
     QemuClipboardInfo *info = (QemuClipboardInfo *)data;
 
-    if (n_targets) {
+    if (targets && n_targets > 0) {
         if (gtk_targets_include_text(targets, n_targets)) {
             info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
         }
Signature · 1 line
2.54.0
#5 lore raw

[PULL v2 08/33] qemu-options.hx: document -chardev vc backend-specific behavior

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

The -chardev vc documentation only mentioned the built-in console with optional size parameters, but the actual behavior depends on the display backend. Document the GTK (libvte), D-Bus and spice-app cases.

---
 qemu-options.hx | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)
qemu-options.hx +11 -2
index 5566da41a36..e7842b10c8c 100644
@@ -4286,8 +4286,17 @@ The available backends are:
     and hub devices is not supported as well.
 
 ``-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]``
-    Connect to a QEMU text console. ``vc`` may optionally be given a
-    specific size.
+    Connect to a QEMU text console. The implementation and supported feature
+    set depend on the selected display backend.
+
+    - The GTK backend uses libvte for the emulation and display (when available).
+
+    - The D-Bus backend exports the character device as a Chardev object.
+
+    - spice-app backend exports it as a Spice port.
+
+    In other cases, QEMU uses its own emulated VT100, and ``vc`` may optionally be
+    given a specific size.
 
     ``width`` and ``height`` specify the width and height respectively
     of the console, in pixels.
Signature · 1 line
2.54.0
#6 lore raw

[PULL v2 09/33] char: error out if given unhandled size options

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

This is a small help, because in fact all combined chardev options are accepted by qemu_chardev_opts[]. But given that a user may legitimately want to use the size options with a VC backend, we can report an error when we know the backend doesn't support it.

---
 include/chardev/char.h |  1 +
 include/qemu/option.h  |  1 +
 chardev/char.c         | 12 ++++++++++++
 ui/console-vc.c        |  1 +
 util/qemu-option.c     | 13 +++++++++++++
 5 files changed, 28 insertions(+)
include/chardev/char.h +1 -0
index c2c42e4b7a3..51995f06a82 100644
@@ -254,6 +254,7 @@ struct ChardevClass {
 
     bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
     bool supports_yank;
+    bool supports_size_opts;
 
     /* parse command line options and populate QAPI @backend */
     void (*chr_parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
include/qemu/option.h +1 -0
index 01e673ae03f..9a00ac0a356 100644
@@ -73,6 +73,7 @@ struct QemuOptsList {
 
 const char *qemu_opt_get(QemuOpts *opts, const char *name);
 char *qemu_opt_get_del(QemuOpts *opts, const char *name);
+bool qemu_opt_has_any(QemuOpts *opts, const char * const *names);
 /**
  * qemu_opt_has_help_opt:
  * @opts: options to search for a help request
chardev/char.c +12 -0
index 48b326d57b9..55dce9725e8 100644
@@ -639,6 +639,18 @@ ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
         return NULL;
     }
 
+    if (!cc->supports_size_opts) {
+        const char * const invalid_opts[] = {
+            "width", "height", "cols", "rows", NULL
+        };
+
+        if (qemu_opt_has_any(opts, invalid_opts)) {
+            error_setg(errp, "chardev '%s' does not support size options",
+                       qemu_opts_id(opts));
+            return NULL;
+        }
+    }
+
     backend = g_new0(ChardevBackend, 1);
     backend->type = CHARDEV_BACKEND_KIND_NULL;
 
ui/console-vc.c +1 -0
index 6163e21d2c6..62a5e3caf57 100644
@@ -1251,6 +1251,7 @@ static void char_vc_class_init(ObjectClass *oc, const void *data)
     cc->chr_write = vc_chr_write;
     cc->chr_accept_input = vc_chr_accept_input;
     cc->chr_set_echo = vc_chr_set_echo;
+    cc->supports_size_opts = true;
 }
 
 static const TypeInfo char_vc_type_info = {
util/qemu-option.c +13 -0
index 770300dff12..9fbf425f86e 100644
@@ -271,6 +271,19 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name)
     return opt->str;
 }
 
+bool qemu_opt_has_any(QemuOpts *opts, const char * const *names)
+{
+    int it;
+
+    for (it = 0; names[it]; it++) {
+        if (qemu_opt_get(opts, names[it])) {
+            return true;
+        }
+    }
+    return false;
+}
+
+
 void qemu_opt_iter_init(QemuOptsIter *iter, QemuOpts *opts, const char *name)
 {
     iter->opts = opts;
Signature · 1 line
2.54.0
#7 lore raw

[PULL v2 04/33] tests/qtest/dbus-vmstate: Stop the daemons explicitly

In reply to [email protected]

From: Fabiano Rosas <[email protected]>

The dbus-vmstate test is currently non-deterministically emitting a "cleaning up pid" message, followed by the PID of one of the dbus-daemon processes used during the test. This is due to a race between the GTestDBus g_autoptr destructor and a child process that does cleanup when the program ends.

Add calls to g_test_dbus_down() to make the issuance of the SIGTERM to the dbus-daemon deterministic.

Message-ID: <[email protected]>

---
 tests/qtest/dbus-vmstate-test.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
tests/qtest/dbus-vmstate-test.c +2 -1
index 05e598a3e3c..15c35e7c0fa 100644
@@ -260,11 +260,12 @@ test_dbus_vmstate(Test *test)
     qtest_quit(src_qemu);
     g_bus_unown_name(ownsrcA);
     g_bus_unown_name(ownsrcB);
+    g_test_dbus_down(srcbus);
     g_bus_unown_name(owndstA);
     if (!test->without_dst_b) {
         g_bus_unown_name(owndstB);
     }
-
+    g_test_dbus_down(dstbus);
     g_main_loop_quit(test->loop);
 }
 
Signature · 1 line
2.54.0
#8 lore raw

[PULL v2 11/33] ui/console: default vc encoding to cp437 for machine < 11.1

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Add a QOM "encoding" enum property to some chardev-vc backends (console-vc & dbus - gtk and spice don't make use of it) so that the machine compat mechanism can override the default. For machine versions prior to 11.1, the charset defaults to cp437 (raw 8-bit VGA) instead of utf8, preserving the historical behaviour.

The following commits are going to wire this to VT100 emulation code and an extra exported D-Bus property.

Note that GTK libvte uses utf8 unconditionally, and Spice doesn't have a way to set the encoding, and typically just use libvte in client too.

---
 include/chardev/char.h | 19 +++++++++++++++++++
 hw/core/machine.c      |  4 +++-
 ui/console-vc.c        | 18 ++++++++++++++++++
 ui/dbus.c              | 40 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 80 insertions(+), 1 deletion(-)
include/chardev/char.h +19 -0
index f05e8dba0a9..7377d8e60a0 100644
@@ -332,4 +332,23 @@ void resume_mux_open(void);
 char *qemu_chr_get_pty_name(Chardev *chr);
 char *qemu_chr_get_filename(Chardev *chr);
 
+#define CHARDEV_VC_ENCODING_PROPERTY_DEFINE(cast_func)          \
+static int get_encoding(Object *obj, Error **errp)              \
+{                                                               \
+    return cast_func(obj)->encoding;                            \
+}                                                               \
+                                                                \
+static void set_encoding(Object *obj, int value, Error **errp)  \
+{                                                               \
+    cast_func(obj)->encoding = value;                           \
+}
+
+static inline void chardev_vc_add_encoding_prop(ObjectClass *oc,
+    int (*get)(Object *, Error **),
+    void (*set)(Object *, int, Error **))
+{
+    object_class_property_add_enum(oc, "encoding", "ChardevVCEncoding",
+                                   &ChardevVCEncoding_lookup, get, set);
+}
+
 #endif
hw/core/machine.c +3 -1
index 1b661fd36ae..63baff859f3 100644
@@ -39,7 +39,9 @@
 #include "hw/acpi/generic_event_device.h"
 #include "qemu/audio.h"
 
-GlobalProperty hw_compat_11_0[] = {};
+GlobalProperty hw_compat_11_0[] = {
+    { "chardev-vc", "encoding", "cp437" },
+};
 const size_t hw_compat_11_0_len = G_N_ELEMENTS(hw_compat_11_0);
 
 GlobalProperty hw_compat_10_2[] = {
ui/console-vc.c +18 -0
index 7bb6a483753..fd7e6fb7b06 100644
@@ -9,6 +9,7 @@
 #include "qemu/fifo8.h"
 #include "qemu/option.h"
 #include "qemu/queue.h"
+#include "qom/compat-properties.h"
 #include "ui/console.h"
 #include "ui/vgafont.h"
 
@@ -109,6 +110,7 @@ struct VCChardev {
     TextAttributes t_attrib; /* currently active text attributes */
     TextAttributes t_attrib_saved;
     int x_saved, y_saved;
+    ChardevVCEncoding encoding;
 };
 typedef struct VCChardev VCChardev;
 
@@ -1189,6 +1191,9 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
 
     s->chr = chr;
     drv->console = s;
+    if (vc->has_encoding) {
+        drv->encoding = vc->encoding;
+    }
 
     /* set current text attributes to default */
     drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
@@ -1253,6 +1258,8 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
     }
 }
 
+CHARDEV_VC_ENCODING_PROPERTY_DEFINE(VC_CHARDEV)
+
 static void char_vc_class_init(ObjectClass *oc, const void *data)
 {
     ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1264,12 +1271,23 @@ static void char_vc_class_init(ObjectClass *oc, const void *data)
     cc->chr_set_echo = vc_chr_set_echo;
     cc->supports_size_opts = true;
     cc->supports_encoding_opts = true;
+
+    chardev_vc_add_encoding_prop(oc, get_encoding, set_encoding);
+}
+
+static void char_vc_init(Object *obj)
+{
+    VCChardev *vc = VC_CHARDEV(obj);
+
+    vc->encoding = CHARDEV_VC_ENCODING_UTF8;
 }
 
 static const TypeInfo char_vc_type_info = {
     .name = TYPE_CHARDEV_VC,
     .parent = TYPE_CHARDEV,
     .instance_size = sizeof(VCChardev),
+    .instance_init = char_vc_init,
+    .instance_post_init = object_apply_compat_props,
     .class_init = char_vc_class_init,
 };
 
ui/dbus.c +40 -0
index 721cc71d39b..59b73e0aa94 100644
@@ -28,6 +28,7 @@
 #include "qemu/main-loop.h"
 #include "qemu/option.h"
 #include "qom/object_interfaces.h"
+#include "qapi-types-char.h"
 #include "system/system.h"
 #include "ui/dbus-module.h"
 #ifdef CONFIG_OPENGL
@@ -455,12 +456,20 @@ dbus_display_class_init(ObjectClass *oc, const void *data)
 
 #define TYPE_CHARDEV_VC "chardev-vc"
 
+typedef struct DBusVCChardev {
+    DBusChardev parent;
+
+    ChardevVCEncoding encoding;
+} DBusVCChardev;
+
 typedef struct DBusVCClass {
     DBusChardevClass parent_class;
 
     void (*parent_parse)(QemuOpts *opts, ChardevBackend *b, Error **errp);
 } DBusVCClass;
 
+DECLARE_INSTANCE_CHECKER(DBusVCChardev, DBUS_VC_CHARDEV,
+                         TYPE_CHARDEV_VC)
 DECLARE_CLASS_CHECKERS(DBusVCClass, DBUS_VC,
                        TYPE_CHARDEV_VC)
 
@@ -500,6 +509,23 @@ dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend,
     }
 }
 
+CHARDEV_VC_ENCODING_PROPERTY_DEFINE(DBUS_VC_CHARDEV)
+
+static bool
+dbus_vc_open(Chardev *chr, ChardevBackend *backend, Error **errp)
+{
+    DBusVCChardev *vc = DBUS_VC_CHARDEV(chr);
+    ChardevClass *parent =
+        CHARDEV_CLASS(object_class_by_name(TYPE_CHARDEV_DBUS));
+    ChardevDBus *be = backend->u.dbus.data;
+
+    if (be->has_encoding) {
+        vc->encoding = be->encoding;
+    }
+
+    return parent->chr_open(chr, backend, errp);
+}
+
 static void
 dbus_vc_class_init(ObjectClass *oc, const void *data)
 {
@@ -508,12 +534,26 @@ dbus_vc_class_init(ObjectClass *oc, const void *data)
 
     klass->parent_parse = cc->chr_parse;
     cc->chr_parse = dbus_vc_parse;
+    cc->chr_open = dbus_vc_open;
     cc->supports_encoding_opts = true;
+
+    chardev_vc_add_encoding_prop(oc, get_encoding, set_encoding);
+}
+
+static void
+dbus_vc_init(Object *obj)
+{
+    DBusVCChardev *vc = DBUS_VC_CHARDEV(obj);
+
+    vc->encoding = CHARDEV_VC_ENCODING_UTF8;
 }
 
 static const TypeInfo dbus_vc_type_info = {
     .name = TYPE_CHARDEV_VC,
     .parent = TYPE_CHARDEV_DBUS,
+    .instance_size = sizeof(DBusVCChardev),
+    .instance_init = dbus_vc_init,
+    .instance_post_init = object_apply_compat_props,
     .class_size = sizeof(DBusVCClass),
     .class_init = dbus_vc_class_init,
 };
Signature · 1 line
2.54.0
#9 lore raw

[PULL v2 15/33] ui/console-vc: extract vt100_input() from vc_chr_write()

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Move the VT100 input processing logic out of vc_chr_write() into a new vt100_input() function that operates on QemuVT100 directly, rather than going through the Chardev/VCChardev layers. This continues the effort to decouple the VT100 emulation from the chardev backend, making the VT100 layer self-contained and reusable.

vc_chr_write() becomes a thin wrapper that extracts the QemuVT100 from the chardev and delegates to vt100_input().

---
 ui/console-vc.c | 34 ++++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)
ui/console-vc.c +20 -14
index cf1adfc3c71..024ab277e0b 100644
@@ -1059,29 +1059,35 @@ static void vt100_putchar(QemuVT100 *vt, int ch)
 DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
                          TYPE_CHARDEV_VC)
 
-static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
+static size_t vt100_input(QemuVT100 *vt, const uint8_t *buf, size_t len)
 {
-    VCChardev *drv = VC_CHARDEV(chr);
-    QemuTextConsole *s = drv->console;
     int i;
 
-    s->vt.update_x0 = s->vt.width * FONT_WIDTH;
-    s->vt.update_y0 = s->vt.height * FONT_HEIGHT;
-    s->vt.update_x1 = 0;
-    s->vt.update_y1 = 0;
-    vt100_show_cursor(&s->vt, 0);
+    vt->update_x0 = vt->width * FONT_WIDTH;
+    vt->update_y0 = vt->height * FONT_HEIGHT;
+    vt->update_x1 = 0;
+    vt->update_y1 = 0;
+    vt100_show_cursor(vt, 0);
     for(i = 0; i < len; i++) {
-        vt100_putchar(&s->vt, buf[i]);
+        vt100_putchar(vt, buf[i]);
     }
-    vt100_show_cursor(&s->vt, 1);
-    if (s->vt.update_x0 < s->vt.update_x1) {
-        vt100_image_update(&s->vt, s->vt.update_x0, s->vt.update_y0,
-                           s->vt.update_x1 - s->vt.update_x0,
-                           s->vt.update_y1 - s->vt.update_y0);
+    vt100_show_cursor(vt, 1);
+    if (vt->update_x0 < vt->update_x1) {
+        vt100_image_update(vt, vt->update_x0, vt->update_y0,
+                           vt->update_x1 - vt->update_x0,
+                           vt->update_y1 - vt->update_y0);
     }
     return len;
 }
 
+static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
+{
+    VCChardev *drv = VC_CHARDEV(chr);
+    QemuTextConsole *s = drv->console;
+
+    return vt100_input(&s->vt, buf, len);
+}
+
 void vt100_update_cursor(void)
 {
     QemuVT100 *vt;
Signature · 1 line
2.54.0
#10 lore raw

[PULL v2 03/33] tests/qtest/dbus-vmstate: Honor QTEST_LOG env variable

In reply to [email protected]

From: Fabiano Rosas <[email protected]>

Don't hide QEMU error messages unconditionally, make the tests that expect to fail honor QTEST_LOG and show every output if the variable is set.

Message-ID: <[email protected]>

---
 tests/qtest/dbus-vmstate-test.c | 28 +++++++++++++++-------------
 1 file changed, 15 insertions(+), 13 deletions(-)
tests/qtest/dbus-vmstate-test.c +15 -13
index 51c5fdb995a..05e598a3e3c 100644
@@ -324,17 +324,18 @@ test_dbus_vmstate_missing_src(char *name, MigrateCommon *args)
 {
     Test test = { .id_list = "idA,idC",
         .result = MIG_TEST_FAIL };
+    bool silent = !getenv("QTEST_LOG");
 
     /* run in subprocess to silence QEMU error reporting */
-    if (g_test_subprocess()) {
-        test_dbus_vmstate(&test);
-        check_not_migrated(&test.srcA, &test.dstA);
-        check_not_migrated(&test.srcB, &test.dstB);
+    if (silent && !g_test_subprocess()) {
+        g_test_trap_subprocess(NULL, 0, 0);
+        g_test_trap_assert_passed();
         return;
     }
 
-    g_test_trap_subprocess(NULL, 0, 0);
-    g_test_trap_assert_passed();
+    test_dbus_vmstate(&test);
+    check_not_migrated(&test.srcA, &test.dstA);
+    check_not_migrated(&test.srcB, &test.dstB);
 }
 
 static void
@@ -343,18 +344,19 @@ test_dbus_vmstate_missing_dst(char *name, MigrateCommon *args)
     Test test = { .id_list = "idA,idB",
                   .without_dst_b = true,
                   .result = MIG_TEST_FAIL };
+    bool silent = !getenv("QTEST_LOG");
 
     /* run in subprocess to silence QEMU error reporting */
-    if (g_test_subprocess()) {
-        test_dbus_vmstate(&test);
-        assert(test.srcA.save_called);
-        assert(test.srcB.save_called);
-        assert(!test.dstB.save_called);
+    if (silent && !g_test_subprocess()) {
+        g_test_trap_subprocess(NULL, 0, 0);
+        g_test_trap_assert_passed();
         return;
     }
 
-    g_test_trap_subprocess(NULL, 0, 0);
-    g_test_trap_assert_passed();
+    test_dbus_vmstate(&test);
+    assert(test.srcA.save_called);
+    assert(test.srcB.save_called);
+    assert(!test.dstB.save_called);
 }
 
 static void log_func(const gchar *log_domain, GLogLevelFlags log_level,
Signature · 1 line
2.54.0
#11 lore raw

[PULL v2 12/33] ui/dbus: expose vc encoding via D-Bus Chardev.VCEncoding interface

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

When a D-Bus VC chardev is instantiated, export an extra org.qemu.Display1.Chardev.VCEncoding interface on the chardev object. This lets D-Bus display clients discover the encoding (cp437 or utf8) in use by the virtual console.

---
 ui/dbus.h            |  1 +
 ui/dbus-chardev.c    | 10 ++++++++++
 ui/dbus.c            |  6 ++++++
 ui/dbus-display1.xml | 18 ++++++++++++++++++
 4 files changed, 35 insertions(+)
ui/dbus.h +1 -0
index 986d7774601..e4e78590b49 100644
@@ -126,6 +126,7 @@ typedef struct DBusChardev {
 
     bool exported;
     QemuDBusDisplay1Chardev *iface;
+    QemuDBusDisplay1ChardevVCEncoding *iface_vc_encoding;
 } DBusChardev;
 
 DECLARE_INSTANCE_CHECKER(DBusChardev, DBUS_CHARDEV, TYPE_CHARDEV_DBUS)
ui/dbus-chardev.c +10 -0
index 9442b475517..55117029acc 100644
@@ -53,6 +53,15 @@ dbus_display_chardev_export(DBusDisplay *dpy, DBusChardev *chr)
     sk = g_dbus_object_skeleton_new(path);
     g_dbus_object_skeleton_add_interface(
         sk, G_DBUS_INTERFACE_SKELETON(chr->iface));
+    if (chr->iface_vc_encoding) {
+        const char *interfaces[] = {
+            "org.qemu.Display1.Chardev.VCEncoding",
+            NULL
+        };
+        g_dbus_object_skeleton_add_interface(
+            sk, G_DBUS_INTERFACE_SKELETON(chr->iface_vc_encoding));
+        g_object_set(chr->iface, "interfaces", interfaces, NULL);
+    }
     g_dbus_object_manager_server_export(dpy->server, sk);
     chr->exported = true;
 }
@@ -290,6 +299,7 @@ char_dbus_finalize(Object *obj)
     };
 
     dbus_display_notify(&event);
+    g_clear_object(&dc->iface_vc_encoding);
     g_clear_object(&dc->iface);
 }
 
ui/dbus.c +6 -0
index 59b73e0aa94..e02a94df2f3 100644
@@ -514,6 +514,7 @@ CHARDEV_VC_ENCODING_PROPERTY_DEFINE(DBUS_VC_CHARDEV)
 static bool
 dbus_vc_open(Chardev *chr, ChardevBackend *backend, Error **errp)
 {
+    DBusChardev *dc = DBUS_CHARDEV(chr);
     DBusVCChardev *vc = DBUS_VC_CHARDEV(chr);
     ChardevClass *parent =
         CHARDEV_CLASS(object_class_by_name(TYPE_CHARDEV_DBUS));
@@ -522,6 +523,11 @@ dbus_vc_open(Chardev *chr, ChardevBackend *backend, Error **errp)
     if (be->has_encoding) {
         vc->encoding = be->encoding;
     }
+    dc->iface_vc_encoding =
+        qemu_dbus_display1_chardev_vcencoding_skeleton_new();
+    qemu_dbus_display1_chardev_vcencoding_set_encoding(
+        dc->iface_vc_encoding,
+        qapi_enum_lookup(&ChardevVCEncoding_lookup, vc->encoding));
 
     return parent->chr_open(chr, backend, errp);
 }
ui/dbus-display1.xml +18 -0
index 4a41a7e0f34..d96bae2ed64 100644
@@ -1141,4 +1141,22 @@
     -->
     <property name="Interfaces" type="as" access="read"/>
   </interface>
+
+  <!--
+      org.qemu.Display1.Chardev.VCEncoding:
+
+      Provides encoding information for virtual console chardevs.
+
+      This interface is present on chardev objects that are virtual
+      consoles, and exposes the character encoding used by the guest.
+  -->
+  <interface name="org.qemu.Display1.Chardev.VCEncoding">
+    <!--
+        Encoding:
+
+        The character encoding used by the virtual console
+        (matching ``ChardevVCEncoding``): ``cp437`` or ``utf8``.
+    -->
+    <property name="Encoding" type="s" access="read"/>
+  </interface>
 </node>
Signature · 1 line
2.54.0
#12 lore raw

[PULL v2 17/33] ui/console-vc: extract vt100_init() and vt100_fini()

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Consolidate VT100 initialization and finalization into dedicated functions, continuing the extraction of the VT100 layer from the console/chardev code.

vt100_init() gathers the scattered setup (cursor timer, list insertion, FIFO creation, default attributes, and image) that was previously spread across vc_chr_open() and qemu_text_console_class_init().

vt100_fini() pairs with it by handling list removal, FIFO destruction, and cells cleanup, replacing the open-coded QTAILQ_REMOVE in qemu_text_console_finalize().

---
 ui/console-vc.c | 55 +++++++++++++++++++++++++++++++++----------------
 1 file changed, 37 insertions(+), 18 deletions(-)
ui/console-vc.c +37 -18
index 9f5f49413d2..b58fe5de827 100644
@@ -331,7 +331,7 @@ static void vt100_write(QemuVT100 *vt, const void *buf, size_t len)
     vt->out_flush(vt);
 }
 
-static int vt100_input(QemuVT100 *vt, const uint8_t *buf, int len);
+static size_t vt100_input(QemuVT100 *vt, const uint8_t *buf, size_t len);
 
 static void vt100_keysym(QemuVT100 *vt, int keysym)
 {
@@ -1129,12 +1129,19 @@ static void text_console_invalidate(void *opaque)
     vt100_refresh(&s->vt);
 }
 
+static void vt100_fini(QemuVT100 *vt)
+{
+    QTAILQ_REMOVE(&vt100s, vt, list);
+    fifo8_destroy(&vt->out_fifo);
+    g_free(vt->cells);
+}
+
 static void
 qemu_text_console_finalize(Object *obj)
 {
     QemuTextConsole *s = QEMU_TEXT_CONSOLE(obj);
 
-    QTAILQ_REMOVE(&vt100s, &s->vt, list);
+    vt100_fini(&s->vt);
 }
 
 static void
@@ -1142,10 +1149,6 @@ qemu_text_console_class_init(ObjectClass *oc, const void *data)
 {
     QemuConsoleClass *cc = QEMU_CONSOLE_CLASS(oc);
 
-    if (!cursor_timer) {
-        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cursor_timer_cb, NULL);
-    }
-
     cc->get_label = qemu_text_console_get_label;
 }
 
@@ -1211,6 +1214,27 @@ static void text_console_out_flush(QemuVT100 *vt)
     qemu_text_console_out_flush(console);
 }
 
+static void vt100_init(QemuVT100 *vt,
+                       pixman_image_t *image,
+                       ChardevVCEncoding encoding,
+                       void (*image_update)(QemuVT100 *vt, int x, int y, int w, int h),
+                       void (*out_flush)(QemuVT100 *vt))
+{
+    if (!cursor_timer) {
+        cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cursor_timer_cb, NULL);
+    }
+
+    vt->encoding = encoding;
+    QTAILQ_INSERT_HEAD(&vt100s, vt, list);
+    fifo8_create(&vt->out_fifo, 16);
+    vt->total_height = DEFAULT_BACKSCROLL;
+    vt->image_update = image_update;
+    vt->out_flush = out_flush;
+    /* set current text attributes to default */
+    vt->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+    vt100_set_image(vt, image);
+}
+
 static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
 {
     ChardevVC *vc = backend->u.vc.data;
@@ -1240,22 +1264,17 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
         s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
     }
 
-    QTAILQ_INSERT_HEAD(&vt100s, &s->vt, list);
-    fifo8_create(&s->vt.out_fifo, 16);
-    s->vt.total_height = DEFAULT_BACKSCROLL;
     dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
-    s->vt.image_update = text_console_image_update;
-    s->vt.out_flush = text_console_out_flush;
-
-    s->chr = chr;
-    drv->console = s;
     if (vc->has_encoding) {
-        drv->encoding = s->vt.encoding = vc->encoding;
+        drv->encoding = vc->encoding;
     }
+    vt100_init(&s->vt, QEMU_CONSOLE(s)->surface->image,
+               drv->encoding,
+               text_console_image_update,
+               text_console_out_flush);
 
-    /* set current text attributes to default */
-    s->vt.t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-    vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
+    s->chr = chr;
+    drv->console = s;
 
     if (chr->label) {
         char *msg;
Signature · 1 line
2.54.0
#13 lore raw

[PULL v2 18/33] ui/console: remove console_ch_t typedef and console_write_ch()

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Since commit e2f82e924d05 ("console: purge curses bits from console.h"), console_ch_t is a plain uint32_t typedef and console_write_ch() is a trivial assignment (*dest = ch). These abstractions were originally needed because console_ch_t was the curses chtype when CONFIG_CURSES was enabled, and console_write_ch() handled VGA-to-curses character translation. That commit moved the curses logic into curses_update(), making the typedef and helper dead abstractions.

Replace console_ch_t with uint32_t and console_write_ch() calls with direct assignments.

---
 include/ui/console.h         |  9 +--------
 hw/display/jazz_led.c        | 10 +++++-----
 hw/display/vga.c             | 16 ++++++++--------
 hw/display/virtio-gpu-base.c |  2 +-
 hw/display/virtio-vga.c      |  2 +-
 hw/display/vmware_vga.c      |  2 +-
 ui/console-vc.c              | 11 +++++------
 ui/console.c                 |  2 +-
 ui/curses.c                  |  6 +++---
 9 files changed, 26 insertions(+), 34 deletions(-)
include/ui/console.h +1 -8
index 27eacc39cc0..2bf768ed482 100644
@@ -336,13 +336,6 @@ int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx);
 
 bool console_has_gl(QemuConsole *con);
 
-typedef uint32_t console_ch_t;
-
-static inline void console_write_ch(console_ch_t *dest, uint32_t ch)
-{
-    *dest = ch;
-}
-
 enum {
     GRAPHIC_FLAGS_NONE     = 0,
     /* require a console/display with GL callbacks */
@@ -377,7 +370,7 @@ void graphic_console_close(QemuConsole *con);
 void graphic_hw_update(QemuConsole *con);
 void graphic_hw_update_done(QemuConsole *con);
 void graphic_hw_invalidate(QemuConsole *con);
-void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata);
+void graphic_hw_text_update(QemuConsole *con, uint32_t *chardata);
 void graphic_hw_gl_block(QemuConsole *con, bool block);
 
 void qemu_console_early_init(void);
hw/display/jazz_led.c +5 -5
index 7d1a020d4d9..ee9758a94b5 100644
@@ -228,7 +228,7 @@ static void jazz_led_invalidate_display(void *opaque)
     s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
 }
 
-static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
+static void jazz_led_text_update(void *opaque, uint32_t *chardata)
 {
     LedState *s = opaque;
     char buf[3];
@@ -238,10 +238,10 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
 
     /* TODO: draw the segments */
     snprintf(buf, 3, "%02hhx", s->segments);
-    console_write_ch(chardata++, ATTR2CHTYPE(buf[0], QEMU_COLOR_BLUE,
-                                             QEMU_COLOR_BLACK, 1));
-    console_write_ch(chardata++, ATTR2CHTYPE(buf[1], QEMU_COLOR_BLUE,
-                                             QEMU_COLOR_BLACK, 1));
+    *chardata++ = ATTR2CHTYPE(buf[0], QEMU_COLOR_BLUE,
+                              QEMU_COLOR_BLACK, 1);
+    *chardata++ = ATTR2CHTYPE(buf[1], QEMU_COLOR_BLUE,
+                              QEMU_COLOR_BLACK, 1);
 
     dpy_text_update(s->con, 0, 0, 2, 1);
 }
hw/display/vga.c +8 -8
index 776aa443246..2f266f47a39 100644
@@ -1901,13 +1901,13 @@ static void vga_reset(void *opaque)
         ((v & 0x00000800) << 10) | ((v & 0x00007000) >> 1))
 /* relay text rendering to the display driver
  * instead of doing a full vga_update_display() */
-static void vga_update_text(void *opaque, console_ch_t *chardata)
+static void vga_update_text(void *opaque, uint32_t *chardata)
 {
     VGACommonState *s =  opaque;
     int graphic_mode, i, cursor_offset, cursor_visible;
     int cw, cheight, width, height, size, c_min, c_max;
     uint32_t *src;
-    console_ch_t *dst, val;
+    uint32_t *dst, val;
     char msg_buffer[80];
     int full_update = 0;
 
@@ -2007,14 +2007,14 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
 
         if (full_update) {
             for (i = 0; i < size; src ++, dst ++, i ++)
-                console_write_ch(dst, VMEM2CHTYPE(le32_to_cpu(*src)));
+                *dst = VMEM2CHTYPE(le32_to_cpu(*src));
 
             dpy_text_update(s->con, 0, 0, width, height);
         } else {
             c_max = 0;
 
             for (i = 0; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                val = VMEM2CHTYPE(le32_to_cpu(*src));
                 if (*dst != val) {
                     *dst = val;
                     c_max = i;
@@ -2023,7 +2023,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
             }
             c_min = i;
             for (; i < size; src ++, dst ++, i ++) {
-                console_write_ch(&val, VMEM2CHTYPE(le32_to_cpu(*src)));
+                val = VMEM2CHTYPE(le32_to_cpu(*src));
                 if (*dst != val) {
                     *dst = val;
                     c_max = i;
@@ -2061,14 +2061,14 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
     dpy_text_resize(s->con, s->last_width, height);
 
     for (dst = chardata, i = 0; i < s->last_width * height; i ++)
-        console_write_ch(dst ++, ' ');
+        *dst++ = ' ';
 
     size = strlen(msg_buffer);
     width = (s->last_width - size) / 2;
     dst = chardata + s->last_width + width;
     for (i = 0; i < size; i ++)
-        console_write_ch(dst ++, ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
-                                             QEMU_COLOR_BLACK, 1));
+        *dst++ = ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
+                             QEMU_COLOR_BLACK, 1);
 
     dpy_text_update(s->con, 0, 0, s->last_width, height);
 }
hw/display/virtio-gpu-base.c +1 -1
index 94cf362d152..bdc24492850 100644
@@ -88,7 +88,7 @@ static bool virtio_gpu_update_display(void *opaque)
     return true;
 }
 
-static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
+static void virtio_gpu_text_update(void *opaque, uint32_t *chardata)
 {
 }
 
hw/display/virtio-vga.c +1 -1
index f4713b91a66..efd4858f3d0 100644
@@ -31,7 +31,7 @@ static bool virtio_vga_base_update_display(void *opaque)
     }
 }
 
-static void virtio_vga_base_text_update(void *opaque, console_ch_t *chardata)
+static void virtio_vga_base_text_update(void *opaque, uint32_t *chardata)
 {
     VirtIOVGABase *vvga = opaque;
     VirtIOGPUBase *g = vvga->vgpu;
hw/display/vmware_vga.c +1 -1
index c84c84a445e..11f13c98d7a 100644
@@ -1184,7 +1184,7 @@ static void vmsvga_invalidate_display(void *opaque)
     s->invalidated = 1;
 }
 
-static void vmsvga_text_update(void *opaque, console_ch_t *chardata)
+static void vmsvga_text_update(void *opaque, uint32_t *chardata)
 {
     struct vmsvga_state_s *s = opaque;
 
ui/console-vc.c +5 -6
index b58fe5de827..b9da9ddf30d 100644
@@ -386,7 +386,7 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
     vt100_keysym(&s->vt, keysym);
 }
 
-static void text_console_update(void *opaque, console_ch_t *chardata)
+static void text_console_update(void *opaque, uint32_t *chardata)
 {
     QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
     int i, j, src;
@@ -396,11 +396,10 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
         chardata += s->vt.text_y[0] * s->vt.width;
         for (i = s->vt.text_y[0]; i <= s->vt.text_y[1]; i ++)
             for (j = 0; j < s->vt.width; j++, src++) {
-                console_write_ch(chardata ++,
-                                 ATTR2CHTYPE(s->vt.cells[src].ch,
-                                             s->vt.cells[src].t_attrib.fgcol,
-                                             s->vt.cells[src].t_attrib.bgcol,
-                                             s->vt.cells[src].t_attrib.bold));
+                *chardata++ = ATTR2CHTYPE(s->vt.cells[src].ch,
+                                          s->vt.cells[src].t_attrib.fgcol,
+                                          s->vt.cells[src].t_attrib.bgcol,
+                                          s->vt.cells[src].t_attrib.bold);
             }
         dpy_text_update(QEMU_CONSOLE(s), s->vt.text_x[0], s->vt.text_y[0],
                         s->vt.text_x[1] - s->vt.text_x[0], i - s->vt.text_y[0]);
ui/console.c +1 -1
index 799d61ec1a5..1c75b1a355b 100644
@@ -210,7 +210,7 @@ void graphic_hw_invalidate(QemuConsole *con)
     }
 }
 
-void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
+void graphic_hw_text_update(QemuConsole *con, uint32_t *chardata)
 {
     if (con && con->hw_ops->text_update) {
         con->hw_ops->text_update(con->hw, chardata);
ui/curses.c +3 -3
index af4ccb4227d..96427aa6bb9 100644
@@ -57,7 +57,7 @@ enum maybe_keycode {
 };
 
 static DisplayChangeListener *dcl;
-static console_ch_t *screen;
+static uint32_t *screen;
 static WINDOW *screenpad = NULL;
 static int width, height, gwidth, gheight, invalidate;
 static int px, py, sminx, sminy, smaxx, smaxy;
@@ -68,7 +68,7 @@ static cchar_t *vga_to_curses;
 static void curses_update(DisplayChangeListener *dcl,
                           int x, int y, int w, int h)
 {
-    console_ch_t *line;
+    uint32_t *line;
     g_autofree cchar_t *curses_line = g_new(cchar_t, width);
     wchar_t wch[CCHARW_MAX];
     attr_t attrs;
@@ -796,7 +796,7 @@ static void curses_display_init(DisplayState *ds, DisplayOptions *opts)
     if (opts->u.curses.charset) {
         font_charset = opts->u.curses.charset;
     }
-    screen = g_new0(console_ch_t, 160 * 100);
+    screen = g_new0(uint32_t, 160 * 100);
     vga_to_curses = g_new0(cchar_t, 256);
     curses_setup();
     curses_keyboard_setup();
Signature · 1 line
2.54.0
#14 lore raw

[PULL v2 16/33] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym()

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Move the keysym handling logic out of qemu_text_console_handle_keysym() into a new vt100_keysym() helper that operates on QemuVT100 directly, continuing the effort to decouple the VT100 layer from the console layer.

The echo path is updated to call vt100_input() instead of qemu_chr_write(), since the function no longer has direct access to the chardev.

---
 ui/console-vc.c | 29 ++++++++++++++++++-----------
 1 file changed, 18 insertions(+), 11 deletions(-)
ui/console-vc.c +18 -11
index 024ab277e0b..9f5f49413d2 100644
@@ -331,24 +331,25 @@ static void vt100_write(QemuVT100 *vt, const void *buf, size_t len)
     vt->out_flush(vt);
 }
 
-/* called when an ascii key is pressed */
-void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
+static int vt100_input(QemuVT100 *vt, const uint8_t *buf, int len);
+
+static void vt100_keysym(QemuVT100 *vt, int keysym)
 {
     uint8_t buf[16], *q;
     int c;
 
     switch(keysym) {
     case QEMU_KEY_CTRL_UP:
-        vt100_scroll(&s->vt, -1);
+        vt100_scroll(vt, -1);
         break;
     case QEMU_KEY_CTRL_DOWN:
-        vt100_scroll(&s->vt, 1);
+        vt100_scroll(vt, 1);
         break;
     case QEMU_KEY_CTRL_PAGEUP:
-        vt100_scroll(&s->vt, -10);
+        vt100_scroll(vt, -10);
         break;
     case QEMU_KEY_CTRL_PAGEDOWN:
-        vt100_scroll(&s->vt, 10);
+        vt100_scroll(vt, 10);
         break;
     default:
         /* convert the QEMU keysym to VT100 key string */
@@ -365,18 +366,24 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
             *q++ = '\033';
             *q++ = '[';
             *q++ = keysym & 0xff;
-        } else if (s->vt.echo && (keysym == '\r' || keysym == '\n')) {
-            qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true);
+        } else if (vt->echo && (keysym == '\r' || keysym == '\n')) {
+            vt100_input(vt, (uint8_t *)"\r", 1);
             *q++ = '\n';
         } else {
             *q++ = keysym;
         }
-        if (s->vt.echo) {
-            qemu_chr_write(s->chr, buf, q - buf, true);
+        if (vt->echo) {
+            vt100_input(vt, buf, q - buf);
         }
-        vt100_write(&s->vt, buf, q - buf);
+        vt100_write(vt, buf, q - buf);
         break;
     }
+
+}
+/* called when an ascii key is pressed */
+void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
+{
+    vt100_keysym(&s->vt, keysym);
 }
 
 static void text_console_update(void *opaque, console_ch_t *chardata)
Signature · 1 line
2.54.0
#15 lore raw

[PULL v2 13/33] ui/console-vc: add UTF-8 input decoding with CP437 rendering

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

The text console receives bytes that may be UTF-8 encoded (e.g. from a guest running a modern distro), but currently treats each byte as a raw character index into the VGA/CP437 font, producing garbled output for any multi-byte sequence.

Add a UTF-8 decoder using Bjoern Hoehrmann's DFA. The DFA inherently rejects overlong encodings, surrogates, and codepoints above U+10FFFF. Completed codepoints are then mapped to CP437, unmappable characters are displayed as '?'.

Note that QEMU has a "buffered" utf8 decoder in util/unicode.c, but it is not a good fit for byte-per-byte decoding.

---
 ui/cp437.h      |  13 +++
 ui/console-vc.c |  59 ++++++++++++++
 ui/cp437.c      | 205 ++++++++++++++++++++++++++++++++++++++++++++++++
 ui/meson.build  |   2 +-
 4 files changed, 278 insertions(+), 1 deletion(-)
 create mode 100644 ui/cp437.h
 create mode 100644 ui/cp437.c
ui/cp437.h new file +13 -0
new file mode 100644
index 00000000000..81ace8317c7
@@ -0,0 +1,13 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) QEMU contributors
+ */
+#ifndef QEMU_CP437_H
+#define QEMU_CP437_H
+
+#include <stdint.h>
+
+int unicode_to_cp437(uint32_t codepoint);
+
+#endif /* QEMU_CP437_H */
ui/console-vc.c +59 -0

83 lines not on this page · raw message

ui/cp437.c new file +205 -0

205 lines not on this page · raw message

ui/meson.build +1 -1
index ceaf110683d..d69eebfdaf1 100644
@@ -18,7 +18,7 @@ system_ss.add(files(
   'util.c',
   'vgafont.c',
 ))
-system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c'))
+system_ss.add(when: pixman, if_true: files('console-vc.c', 'cp437.c'), if_false: files('console-vc-stubs.c'))
 if dbus_display
   system_ss.add(files('dbus-module.c'))
 endif
Signature · 1 line
2.54.0
#16 lore raw

[PULL v2 14/33] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Move the terminal escape sequence parser state (TTYState, esc_params, text attributes, saved cursor position) and the output FIFO from VCChardev/QemuTextConsole into QemuVT100. Rename the corresponding functions from vc_* to vt100_* to reflect they now operate on the VT100 layer directly, removing the indirection through vc->console->vt.

Add an out_flush callback to QemuVT100 so vt100_write() can flush output without knowing about QemuTextConsole, and move FIFO/VT100 initialization from qemu_text_console_init() to vc_chr_open() where the callback can be wired up.

This continues the decoupling of VT100 terminal emulation from the chardev layer, making QemuVT100 a self-contained terminal emulator.

---
 ui/console-vc.c | 382 +++++++++++++++++++++++-------------------------
 1 file changed, 184 insertions(+), 198 deletions(-)
ui/console-vc.c +184 -198
index 42d642afebb..cf1adfc3c71 100644
@@ -58,6 +58,7 @@ struct QemuVT100 {
     pixman_image_t *image;
     void (*image_update)(QemuVT100 *vt, int x, int y, int width, int height);
 
+    ChardevVCEncoding encoding;
     int width;
     int height;
     int total_height;
@@ -74,6 +75,18 @@ struct QemuVT100 {
     int update_x1;
     int update_y1;
 
+    enum TTYState state;
+    int esc_params[MAX_ESC_PARAMS];
+    int nb_esc_params;
+    uint32_t utf8_state;     /* UTF-8 DFA decoder state */
+    uint32_t utf8_codepoint; /* accumulated UTF-8 code point */
+    TextAttributes t_attrib; /* currently active text attributes */
+    TextAttributes t_attrib_saved;
+    int x_saved, y_saved;
+    /* fifo for key pressed */
+    Fifo8 out_fifo;
+    void (*out_flush)(QemuVT100 *vt);
+
     QTAILQ_ENTRY(QemuVT100) list;
 };
 
@@ -85,8 +98,6 @@ typedef struct QemuTextConsole {
 
     QemuVT100 vt;
     Chardev *chr;
-    /* fifo for key pressed */
-    Fifo8 out_fifo;
 } QemuTextConsole;
 
 typedef QemuConsoleClass QemuTextConsoleClass;
@@ -103,17 +114,9 @@ OBJECT_DEFINE_TYPE(QemuFixedTextConsole, qemu_fixed_text_console, QEMU_FIXED_TEX
 
 struct VCChardev {
     Chardev parent;
-    QemuTextConsole *console;
 
-    enum TTYState state;
-    int esc_params[MAX_ESC_PARAMS];
-    int nb_esc_params;
-    uint32_t utf8_state;     /* UTF-8 DFA decoder state */
-    uint32_t utf8_codepoint; /* accumulated UTF-8 code point */
-    TextAttributes t_attrib; /* currently active text attributes */
-    TextAttributes t_attrib_saved;
-    int x_saved, y_saved;
     ChardevVCEncoding encoding;
+    QemuTextConsole *console;
 };
 typedef struct VCChardev VCChardev;
 
@@ -302,36 +305,35 @@ static void vt100_scroll(QemuVT100 *vt, int ydelta)
     vt100_refresh(vt);
 }
 
-static void qemu_text_console_flush(QemuTextConsole *s)
+static void qemu_text_console_out_flush(QemuTextConsole *s)
 {
     uint32_t len, avail;
 
     len = qemu_chr_be_can_write(s->chr);
-    avail = fifo8_num_used(&s->out_fifo);
+    avail = fifo8_num_used(&s->vt.out_fifo);
     while (len > 0 && avail > 0) {
         const uint8_t *buf;
         uint32_t size;
 
-        buf = fifo8_pop_bufptr(&s->out_fifo, MIN(len, avail), &size);
+        buf = fifo8_pop_bufptr(&s->vt.out_fifo, MIN(len, avail), &size);
         qemu_chr_be_write(s->chr, buf, size);
         len = qemu_chr_be_can_write(s->chr);
         avail -= size;
     }
 }
 
-static void qemu_text_console_write(QemuTextConsole *s, const void *buf, size_t len)
+static void vt100_write(QemuVT100 *vt, const void *buf, size_t len)
 {
     uint32_t num_free;
 
-    num_free = fifo8_num_free(&s->out_fifo);
-    fifo8_push_all(&s->out_fifo, buf, MIN(num_free, len));
-    qemu_text_console_flush(s);
+    num_free = fifo8_num_free(&vt->out_fifo);
+    fifo8_push_all(&vt->out_fifo, buf, MIN(num_free, len));
+    vt->out_flush(vt);
 }
 
 /* called when an ascii key is pressed */
 void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
 {
-    QemuVT100 *vt = &s->vt;
     uint8_t buf[16], *q;
     int c;
 
@@ -363,16 +365,16 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
             *q++ = '\033';
             *q++ = '[';
             *q++ = keysym & 0xff;
-        } else if (vt->echo && (keysym == '\r' || keysym == '\n')) {
+        } else if (s->vt.echo && (keysym == '\r' || keysym == '\n')) {
             qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true);
             *q++ = '\n';
         } else {
             *q++ = keysym;
         }
-        if (vt->echo) {
+        if (s->vt.echo) {
             qemu_chr_write(s->chr, buf, q - buf, true);
         }
-        qemu_text_console_write(s, buf, q - buf);
+        vt100_write(&s->vt, buf, q - buf);
         break;
     }
 }
@@ -380,30 +382,29 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
 static void text_console_update(void *opaque, console_ch_t *chardata)
 {
     QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
-    QemuVT100 *vt = &s->vt;
     int i, j, src;
 
-    if (vt->text_x[0] <= vt->text_x[1]) {
-        src = (vt->y_base + vt->text_y[0]) * vt->width;
-        chardata += vt->text_y[0] * vt->width;
-        for (i = vt->text_y[0]; i <= vt->text_y[1]; i ++)
-            for (j = 0; j < vt->width; j++, src++) {
+    if (s->vt.text_x[0] <= s->vt.text_x[1]) {
+        src = (s->vt.y_base + s->vt.text_y[0]) * s->vt.width;
+        chardata += s->vt.text_y[0] * s->vt.width;
+        for (i = s->vt.text_y[0]; i <= s->vt.text_y[1]; i ++)
+            for (j = 0; j < s->vt.width; j++, src++) {
                 console_write_ch(chardata ++,
-                                 ATTR2CHTYPE(vt->cells[src].ch,
-                                             vt->cells[src].t_attrib.fgcol,
-                                             vt->cells[src].t_attrib.bgcol,
-                                             vt->cells[src].t_attrib.bold));
+                                 ATTR2CHTYPE(s->vt.cells[src].ch,
+                                             s->vt.cells[src].t_attrib.fgcol,
+                                             s->vt.cells[src].t_attrib.bgcol,
+                                             s->vt.cells[src].t_attrib.bold));
             }
-        dpy_text_update(QEMU_CONSOLE(s), vt->text_x[0], vt->text_y[0],
-                        vt->text_x[1] - vt->text_x[0], i - vt->text_y[0]);
-        vt->text_x[0] = vt->width;
-        vt->text_y[0] = vt->height;
-        vt->text_x[1] = 0;
-        vt->text_y[1] = 0;
+        dpy_text_update(QEMU_CONSOLE(s), s->vt.text_x[0], s->vt.text_y[0],
+                        s->vt.text_x[1] - s->vt.text_x[0], i - s->vt.text_y[0]);
+        s->vt.text_x[0] = s->vt.width;
+        s->vt.text_y[0] = s->vt.height;
+        s->vt.text_x[1] = 0;
+        s->vt.text_y[1] = 0;
     }
-    if (vt->cursor_invalidate) {
-        dpy_text_cursor(QEMU_CONSOLE(s), vt->x, vt->y);
-        vt->cursor_invalidate = 0;
+    if (s->vt.cursor_invalidate) {
+        dpy_text_cursor(QEMU_CONSOLE(s), s->vt.x, s->vt.y);
+        s->vt.cursor_invalidate = 0;
     }
 }
 
@@ -492,103 +493,101 @@ static void vt100_put_lf(QemuVT100 *vt)
  * NOTE: I know this code is not very efficient (checking every color for it
  * self) but it is more readable and better maintainable.
  */
-static void vc_handle_escape(VCChardev *vc)
+static void vt100_handle_escape(QemuVT100 *vt)
 {
     int i;
 
-    for (i = 0; i < vc->nb_esc_params; i++) {
-        switch (vc->esc_params[i]) {
+    for (i = 0; i < vt->nb_esc_params; i++) {
+        switch (vt->esc_params[i]) {
             case 0: /* reset all console attributes to default */
-                vc->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+                vt->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
                 break;
             case 1:
-                vc->t_attrib.bold = 1;
+                vt->t_attrib.bold = 1;
                 break;
             case 4:
-                vc->t_attrib.uline = 1;
+                vt->t_attrib.uline = 1;
                 break;
             case 5:
-                vc->t_attrib.blink = 1;
+                vt->t_attrib.blink = 1;
                 break;
             case 7:
-                vc->t_attrib.invers = 1;
+                vt->t_attrib.invers = 1;
                 break;
             case 8:
-                vc->t_attrib.unvisible = 1;
+                vt->t_attrib.unvisible = 1;
                 break;
             case 22:
-                vc->t_attrib.bold = 0;
+                vt->t_attrib.bold = 0;
                 break;
             case 24:
-                vc->t_attrib.uline = 0;
+                vt->t_attrib.uline = 0;
                 break;
             case 25:
-                vc->t_attrib.blink = 0;
+                vt->t_attrib.blink = 0;
                 break;
             case 27:
-                vc->t_attrib.invers = 0;
+                vt->t_attrib.invers = 0;
                 break;
             case 28:
-                vc->t_attrib.unvisible = 0;
+                vt->t_attrib.unvisible = 0;
                 break;
             /* set foreground color */
             case 30:
-                vc->t_attrib.fgcol = QEMU_COLOR_BLACK;
+                vt->t_attrib.fgcol = QEMU_COLOR_BLACK;
                 break;
             case 31:
-                vc->t_attrib.fgcol = QEMU_COLOR_RED;
+                vt->t_attrib.fgcol = QEMU_COLOR_RED;
                 break;
             case 32:
-                vc->t_attrib.fgcol = QEMU_COLOR_GREEN;
+                vt->t_attrib.fgcol = QEMU_COLOR_GREEN;
                 break;
             case 33:
-                vc->t_attrib.fgcol = QEMU_COLOR_YELLOW;
+                vt->t_attrib.fgcol = QEMU_COLOR_YELLOW;
                 break;
             case 34:
-                vc->t_attrib.fgcol = QEMU_COLOR_BLUE;
+                vt->t_attrib.fgcol = QEMU_COLOR_BLUE;
                 break;
             case 35:
-                vc->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
+                vt->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
                 break;
             case 36:
-                vc->t_attrib.fgcol = QEMU_COLOR_CYAN;
+                vt->t_attrib.fgcol = QEMU_COLOR_CYAN;
                 break;
             case 37:
-                vc->t_attrib.fgcol = QEMU_COLOR_WHITE;
+                vt->t_attrib.fgcol = QEMU_COLOR_WHITE;
                 break;
             /* set background color */
             case 40:
-                vc->t_attrib.bgcol = QEMU_COLOR_BLACK;
+                vt->t_attrib.bgcol = QEMU_COLOR_BLACK;
                 break;
             case 41:
-                vc->t_attrib.bgcol = QEMU_COLOR_RED;
+                vt->t_attrib.bgcol = QEMU_COLOR_RED;
                 break;
             case 42:
-                vc->t_attrib.bgcol = QEMU_COLOR_GREEN;
+                vt->t_attrib.bgcol = QEMU_COLOR_GREEN;
                 break;
             case 43:
-                vc->t_attrib.bgcol = QEMU_COLOR_YELLOW;
+                vt->t_attrib.bgcol = QEMU_COLOR_YELLOW;
                 break;
             case 44:
-                vc->t_attrib.bgcol = QEMU_COLOR_BLUE;
+                vt->t_attrib.bgcol = QEMU_COLOR_BLUE;
                 break;
             case 45:
-                vc->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
+                vt->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
                 break;
             case 46:
-                vc->t_attrib.bgcol = QEMU_COLOR_CYAN;
+                vt->t_attrib.bgcol = QEMU_COLOR_CYAN;
                 break;
             case 47:
-                vc->t_attrib.bgcol = QEMU_COLOR_WHITE;
+                vt->t_attrib.bgcol = QEMU_COLOR_WHITE;
                 break;
         }
     }
 }
 
-static void vc_update_xy(VCChardev *vc, int x, int y)
+static void vt100_update_xy(QemuVT100 *vt, int x, int y)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
     TextCell *c;
     int y1, y2;
 
@@ -609,14 +608,12 @@ static void vc_update_xy(VCChardev *vc, int x, int y)
         c = &vt->cells[y1 * vt->width + x];
         vt100_putcharxy(vt, x, y2, c->ch,
                       &(c->t_attrib));
-        vt100_invalidate_xy(&s->vt, x, y2);
+        vt100_invalidate_xy(vt, x, y2);
     }
 }
 
-static void vc_clear_xy(VCChardev *vc, int x, int y)
+static void vt100_clear_xy(QemuVT100 *vt, int x, int y)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
     int y1 = (vt->y_base + y) % vt->total_height;
     if (x >= vt->width) {
         x = vt->width - 1;
@@ -624,7 +621,7 @@ static void vc_clear_xy(VCChardev *vc, int x, int y)
     TextCell *c = &vt->cells[y1 * vt->width + x];
     c->ch = ' ';
     c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
-    vc_update_xy(vc, x, y);
+    vt100_update_xy(vt, x, y);
 }
 
 /*
@@ -667,10 +664,8 @@ static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
     return *state;
 }
 
-static void vc_put_one(VCChardev *vc, int ch)
+static void vt100_put_one(QemuVT100 *vt, int ch)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
     TextCell *c;
     int y1;
     if (vt->x >= vt->width) {
@@ -681,17 +676,14 @@ static void vc_put_one(VCChardev *vc, int ch)
     y1 = (vt->y_base + vt->y) % vt->total_height;
     c = &vt->cells[y1 * vt->width + vt->x];
     c->ch = ch;
-    c->t_attrib = vc->t_attrib;
-    vc_update_xy(vc, vt->x, vt->y);
+    c->t_attrib = vt->t_attrib;
+    vt100_update_xy(vt, vt->x, vt->y);
     vt->x++;
 }
 
 /* set cursor, checking bounds */
-static void vc_set_cursor(VCChardev *vc, int x, int y)
+static void vt100_set_cursor(QemuVT100 *vt, int x, int y)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
-
     if (x < 0) {
         x = 0;
     }
@@ -715,10 +707,8 @@ static void vc_set_cursor(VCChardev *vc, int x, int y)
  * characters between the cursor and right margin move to the
  * left. Character attributes move with the characters.
  */
-static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
+static void vt100_csi_P(QemuVT100 *vt, unsigned int nr)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
     TextCell *c1, *c2;
     unsigned int x1, x2, y;
     unsigned int end, len;
@@ -742,12 +732,12 @@ static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
         c2 = &vt->cells[y * vt->width + x2];
         memmove(c1, c2, len * sizeof(*c1));
         for (end = x1 + len; x1 < end; x1++) {
-            vc_update_xy(vc, x1, vt->y);
+            vt100_update_xy(vt, x1, vt->y);
         }
     }
     /* Clear the rest */
     for (; x1 < vt->width; x1++) {
-        vc_clear_xy(vc, x1, vt->y);
+        vt100_clear_xy(vt, x1, vt->y);
     }
 }
 
@@ -757,10 +747,8 @@ static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
  * blank characters. Text between the cursor and right margin moves to
  * the right. Characters scrolled past the right margin are lost.
  */
-static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
+static void vt100_csi_at(QemuVT100 *vt, unsigned int nr)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
     TextCell *c1, *c2;
     unsigned int x1, x2, y;
     unsigned int end, len;
@@ -784,59 +772,51 @@ static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
         c2 = &vt->cells[y * vt->width + x2];
         memmove(c1, c2, len * sizeof(*c1));
         for (end = x1 + len; x1 < end; x1++) {
-            vc_update_xy(vc, x1, vt->y);
+            vt100_update_xy(vt, x1, vt->y);
         }
     }
     /* Insert blanks */
     for (x1 = vt->x; x1 < vt->x + nr; x1++) {
-        vc_clear_xy(vc, x1, vt->y);
+        vt100_clear_xy(vt, x1, vt->y);
     }
 }
 
 /**
- * vc_save_cursor() - saves cursor position and character attributes.
+ * vt100_save_cursor() - saves cursor position and character attributes.
  */
-static void vc_save_cursor(VCChardev *vc)
+static void vt100_save_cursor(QemuVT100 *vt)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
-
-    vc->x_saved = vt->x;
-    vc->y_saved = vt->y;
-    vc->t_attrib_saved = vc->t_attrib;
+    vt->x_saved = vt->x;
+    vt->y_saved = vt->y;
+    vt->t_attrib_saved = vt->t_attrib;
 }
 
 /**
- * vc_restore_cursor() - restores cursor position and character
+ * vt100_restore_cursor() - restores cursor position and character
  * attributes from saved state.
  */
-static void vc_restore_cursor(VCChardev *vc)
+static void vt100_restore_cursor(QemuVT100 *vt)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
-
-    vt->x = vc->x_saved;
-    vt->y = vc->y_saved;
-    vc->t_attrib = vc->t_attrib_saved;
+    vt->x = vt->x_saved;
+    vt->y = vt->y_saved;
+    vt->t_attrib = vt->t_attrib_saved;
 }
 
-static void vc_putchar(VCChardev *vc, int ch)
+static void vt100_putchar(QemuVT100 *vt, int ch)
 {
-    QemuTextConsole *s = vc->console;
-    QemuVT100 *vt = &s->vt;
     int i;
     int x, y;
     g_autofree char *response = NULL;
 
-    switch(vc->state) {
+    switch (vt->state) {
     case TTY_STATE_NORM:
-        if (ch >= 0x80 && vc->encoding == CHARDEV_VC_ENCODING_UTF8) {
-            switch (bh_utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
+        if (ch >= 0x80 && vt->encoding == CHARDEV_VC_ENCODING_UTF8) {
+            switch (bh_utf8_decode(&vt->utf8_state, &vt->utf8_codepoint, ch)) {
             case BH_UTF8_ACCEPT:
-                vc_put_one(vc, unicode_to_cp437(vc->utf8_codepoint));
+                vt100_put_one(vt, unicode_to_cp437(vt->utf8_codepoint));
                 break;
             case BH_UTF8_REJECT:
-                vc->utf8_state = BH_UTF8_ACCEPT;
+                vt->utf8_state = BH_UTF8_ACCEPT;
                 break;
             default:
                 /* Need more bytes */
@@ -844,14 +824,13 @@ static void vc_putchar(VCChardev *vc, int ch)
             }
             break;
         }
-        /* ASCII byte: abort any pending UTF-8 sequence */
-        vc->utf8_state = BH_UTF8_ACCEPT;
+        vt->utf8_state = BH_UTF8_ACCEPT;
         switch(ch) {
         case '\r':  /* carriage return */
             vt->x = 0;
             break;
         case '\n':  /* newline */
-            vt100_put_lf(&s->vt);
+            vt100_put_lf(vt);
             break;
         case '\b':  /* backspace */
             if (vt->x > 0)
@@ -875,95 +854,95 @@ static void vc_putchar(VCChardev *vc, int ch)
             /* SI (shift in), character set 0 (ignored) */
             break;
         case 27:    /* esc (introducing an escape sequence) */
-            vc->state = TTY_STATE_ESC;
+            vt->state = TTY_STATE_ESC;
             break;
         default:
-            vc_put_one(vc, ch);
+            vt100_put_one(vt, ch);
             break;
         }
         break;
     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
         if (ch == '[') {
             for(i=0;i<MAX_ESC_PARAMS;i++)
-                vc->esc_params[i] = 0;
-            vc->nb_esc_params = 0;
-            vc->state = TTY_STATE_CSI;
+                vt->esc_params[i] = 0;
+            vt->nb_esc_params = 0;
+            vt->state = TTY_STATE_CSI;
         } else if (ch == '(') {
-            vc->state = TTY_STATE_G0;
+            vt->state = TTY_STATE_G0;
         } else if (ch == ')') {
-            vc->state = TTY_STATE_G1;
+            vt->state = TTY_STATE_G1;
         } else if (ch == ']' || ch == 'P' || ch == 'X'
                    || ch == '^' || ch == '_') {
             /* String sequences: OSC, DCS, SOS, PM, APC */
-            vc->state = TTY_STATE_OSC;
+            vt->state = TTY_STATE_OSC;
         } else if (ch == '7') {
-            vc_save_cursor(vc);
-            vc->state = TTY_STATE_NORM;
+            vt100_save_cursor(vt);
+            vt->state = TTY_STATE_NORM;
         } else if (ch == '8') {
-            vc_restore_cursor(vc);
-            vc->state = TTY_STATE_NORM;
+            vt100_restore_cursor(vt);
+            vt->state = TTY_STATE_NORM;
         } else {
-            vc->state = TTY_STATE_NORM;
+            vt->state = TTY_STATE_NORM;
         }
         break;
     case TTY_STATE_CSI: /* handle escape sequence parameters */
         if (ch >= '0' && ch <= '9') {
-            if (vc->nb_esc_params < MAX_ESC_PARAMS) {
-                int *param = &vc->esc_params[vc->nb_esc_params];
+            if (vt->nb_esc_params < MAX_ESC_PARAMS) {
+                int *param = &vt->esc_params[vt->nb_esc_params];
                 int digit = (ch - '0');
 
                 *param = (*param <= (INT_MAX - digit) / 10) ?
                          *param * 10 + digit : INT_MAX;
             }
         } else {
-            if (vc->nb_esc_params < MAX_ESC_PARAMS)
-                vc->nb_esc_params++;
+            if (vt->nb_esc_params < MAX_ESC_PARAMS)
+                vt->nb_esc_params++;
             if (ch == ';' || ch == '?') {
                 break;
             }
-            trace_console_putchar_csi(vc->esc_params[0], vc->esc_params[1],
-                                      ch, vc->nb_esc_params);
-            vc->state = TTY_STATE_NORM;
+            trace_console_putchar_csi(vt->esc_params[0], vt->esc_params[1],
+                                      ch, vt->nb_esc_params);
+            vt->state = TTY_STATE_NORM;
             switch(ch) {
             case 'A':
                 /* move cursor up */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
+                if (vt->esc_params[0] == 0) {
+                    vt->esc_params[0] = 1;
                 }
-                vc_set_cursor(vc, vt->x, vt->y - vc->esc_params[0]);
+                vt100_set_cursor(vt, vt->x, vt->y - vt->esc_params[0]);
                 break;
             case 'B':
                 /* move cursor down */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
+                if (vt->esc_params[0] == 0) {
+                    vt->esc_params[0] = 1;
                 }
-                vc_set_cursor(vc, vt->x, vt->y + vc->esc_params[0]);
+                vt100_set_cursor(vt, vt->x, vt->y + vt->esc_params[0]);
                 break;
             case 'C':
                 /* move cursor right */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
+                if (vt->esc_params[0] == 0) {
+                    vt->esc_params[0] = 1;
                 }
-                vc_set_cursor(vc, vt->x + vc->esc_params[0], vt->y);
+                vt100_set_cursor(vt, vt->x + vt->esc_params[0], vt->y);
                 break;
             case 'D':
                 /* move cursor left */
-                if (vc->esc_params[0] == 0) {
-                    vc->esc_params[0] = 1;
+                if (vt->esc_params[0] == 0) {
+                    vt->esc_params[0] = 1;
                 }
-                vc_set_cursor(vc, vt->x - vc->esc_params[0], vt->y);
+                vt100_set_cursor(vt, vt->x - vt->esc_params[0], vt->y);
                 break;
             case 'G':
                 /* move cursor to column */
-                vc_set_cursor(vc, vc->esc_params[0] - 1, vt->y);
+                vt100_set_cursor(vt, vt->esc_params[0] - 1, vt->y);
                 break;
             case 'f':
             case 'H':
                 /* move cursor to row, column */
-                vc_set_cursor(vc, vc->esc_params[1] - 1, vc->esc_params[0] - 1);
+                vt100_set_cursor(vt, vt->esc_params[1] - 1, vt->esc_params[0] - 1);
                 break;
             case 'J':
-                switch (vc->esc_params[0]) {
+                switch (vt->esc_params[0]) {
                 case 0:
                     /* clear to end of screen */
                     for (y = vt->y; y < vt->height; y++) {
@@ -971,7 +950,7 @@ static void vc_putchar(VCChardev *vc, int ch)
                             if (y == vt->y && x < vt->x) {
                                 continue;
                             }
-                            vc_clear_xy(vc, x, y);
+                            vt100_clear_xy(vt, x, y);
                         }
                     }
                     break;
@@ -982,7 +961,7 @@ static void vc_putchar(VCChardev *vc, int ch)
                             if (y == vt->y && x > vt->x) {
                                 break;
                             }
-                            vc_clear_xy(vc, x, y);
+                            vt100_clear_xy(vt, x, y);
                         }
                     }
                     break;
@@ -990,62 +969,62 @@ static void vc_putchar(VCChardev *vc, int ch)
                     /* clear entire screen */
                     for (y = 0; y < vt->height; y++) {
                         for (x = 0; x < vt->width; x++) {
-                            vc_clear_xy(vc, x, y);
+                            vt100_clear_xy(vt, x, y);
                         }
                     }
                     break;
                 }
                 break;
             case 'K':
-                switch (vc->esc_params[0]) {
+                switch (vt->esc_params[0]) {
                 case 0:
                     /* clear to eol */
                     for(x = vt->x; x < vt->width; x++) {
-                        vc_clear_xy(vc, x, vt->y);
+                        vt100_clear_xy(vt, x, vt->y);
                     }
                     break;
                 case 1:
                     /* clear from beginning of line */
                     for (x = 0; x <= vt->x && x < vt->width; x++) {
-                        vc_clear_xy(vc, x, vt->y);
+                        vt100_clear_xy(vt, x, vt->y);
                     }
                     break;
                 case 2:
                     /* clear entire line */
                     for(x = 0; x < vt->width; x++) {
-                        vc_clear_xy(vc, x, vt->y);
+                        vt100_clear_xy(vt, x, vt->y);
                     }
                     break;
                 }
                 break;
             case 'P':
-                vc_csi_P(vc, vc->esc_params[0]);
+                vt100_csi_P(vt, vt->esc_params[0]);
                 break;
             case 'm':
-                vc_handle_escape(vc);
+                vt100_handle_escape(vt);
                 break;
             case 'n':
-                switch (vc->esc_params[0]) {
+                switch (vt->esc_params[0]) {
                 case 5:
                     /* report console status (always succeed)*/
-                    qemu_text_console_write(s, "\033[0n", 4);
+                    vt100_write(vt, "\033[0n", 4);
                     break;
                 case 6:
                     /* report cursor position */
                     response = g_strdup_printf("\033[%d;%dR",
                                                vt->y + 1, vt->x + 1);
-                    qemu_text_console_write(s, response, strlen(response));
+                    vt100_write(vt, response, strlen(response));
                     break;
                 }
                 break;
             case 's':
-                vc_save_cursor(vc);
+                vt100_save_cursor(vt);
                 break;
             case 'u':
-                vc_restore_cursor(vc);
+                vt100_restore_cursor(vt);
                 break;
             case '@':
-                vc_csi_at(vc, vc->esc_params[0]);
+                vt100_csi_at(vt, vt->esc_params[0]);
                 break;
             default:
                 trace_console_putchar_unhandled(ch);
@@ -1057,10 +1036,10 @@ static void vc_putchar(VCChardev *vc, int ch)
     case TTY_STATE_OSC: /* Operating System Command: ESC ] ... BEL/ST */
         if (ch == '\a') {
             /* BEL terminates OSC */
-            vc->state = TTY_STATE_NORM;
+            vt->state = TTY_STATE_NORM;
         } else if (ch == 27) {
             /* ESC might start ST (ESC \) */
-            vc->state = TTY_STATE_ESC;
+            vt->state = TTY_STATE_ESC;
         }
         /* All other bytes are silently consumed */
         break;
@@ -1071,7 +1050,7 @@ static void vc_putchar(VCChardev *vc, int ch)
             /* Latin-1 map */
             break;
         }
-        vc->state = TTY_STATE_NORM;
+        vt->state = TTY_STATE_NORM;
         break;
     }
 }
@@ -1084,22 +1063,21 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
 {
     VCChardev *drv = VC_CHARDEV(chr);
     QemuTextConsole *s = drv->console;
-    QemuVT100 *vt = &s->vt;
     int i;
 
-    vt->update_x0 = vt->width * FONT_WIDTH;
-    vt->update_y0 = vt->height * FONT_HEIGHT;
-    vt->update_x1 = 0;
-    vt->update_y1 = 0;
-    vt100_show_cursor(vt, 0);
+    s->vt.update_x0 = s->vt.width * FONT_WIDTH;
+    s->vt.update_y0 = s->vt.height * FONT_HEIGHT;
+    s->vt.update_x1 = 0;
+    s->vt.update_y1 = 0;
+    vt100_show_cursor(&s->vt, 0);
     for(i = 0; i < len; i++) {
-        vc_putchar(drv, buf[i]);
+        vt100_putchar(&s->vt, buf[i]);
     }
-    vt100_show_cursor(vt, 1);
-    if (vt->update_x0 < vt->update_x1) {
-        vt100_image_update(vt, vt->update_x0, vt->update_y0,
-                           vt->update_x1 - vt->update_x0,
-                           vt->update_y1 - vt->update_y0);
+    vt100_show_cursor(&s->vt, 1);
+    if (s->vt.update_x0 < s->vt.update_x1) {
+        vt100_image_update(&s->vt, s->vt.update_x0, s->vt.update_y0,
+                           s->vt.update_x1 - s->vt.update_x0,
+                           s->vt.update_y1 - s->vt.update_y0);
     }
     return len;
 }
@@ -1168,9 +1146,6 @@ qemu_text_console_init(Object *obj)
 {
     QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
 
-    QTAILQ_INSERT_HEAD(&vt100s, &c->vt, list);
-    fifo8_create(&c->out_fifo, 16);
-    c->vt.total_height = DEFAULT_BACKSCROLL;
     QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
     QEMU_CONSOLE(c)->hw = c;
 }
@@ -1194,7 +1169,7 @@ static void vc_chr_accept_input(Chardev *chr)
 {
     VCChardev *drv = VC_CHARDEV(chr);
 
-    qemu_text_console_flush(drv->console);
+    qemu_text_console_out_flush(drv->console);
 }
 
 static void vc_chr_set_echo(Chardev *chr, bool echo)
@@ -1216,6 +1191,13 @@ static void text_console_image_update(QemuVT100 *vt, int x, int y, int width, in
     dpy_gfx_update(QEMU_CONSOLE(console), x, y, width, height);
 }
 
+static void text_console_out_flush(QemuVT100 *vt)
+{
+    QemuTextConsole *console = container_of(vt, QemuTextConsole, vt);
+
+    qemu_text_console_out_flush(console);
+}
+
 static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
 {
     ChardevVC *vc = backend->u.vc.data;
@@ -1245,27 +1227,31 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
         s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
     }
 
+    QTAILQ_INSERT_HEAD(&vt100s, &s->vt, list);
+    fifo8_create(&s->vt.out_fifo, 16);
+    s->vt.total_height = DEFAULT_BACKSCROLL;
     dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
     s->vt.image_update = text_console_image_update;
+    s->vt.out_flush = text_console_out_flush;
 
     s->chr = chr;
     drv->console = s;
     if (vc->has_encoding) {
-        drv->encoding = vc->encoding;
+        drv->encoding = s->vt.encoding = vc->encoding;
     }
 
     /* set current text attributes to default */
-    drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+    s->vt.t_attrib = TEXT_ATTRIBUTES_DEFAULT;
     vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
 
     if (chr->label) {
         char *msg;
 
-        drv->t_attrib.bgcol = QEMU_COLOR_BLUE;
+        s->vt.t_attrib.bgcol = QEMU_COLOR_BLUE;
         msg = g_strdup_printf("%s console\r\n", chr->label);
         qemu_chr_write(chr, (uint8_t *)msg, strlen(msg), true);
         g_free(msg);
-        drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+        s->vt.t_attrib = TEXT_ATTRIBUTES_DEFAULT;
     }
 
     qemu_chr_be_event(chr, CHR_EVENT_OPENED);
Signature · 1 line
2.54.0
#17 lore raw

[PULL v2 25/33] ui/vnc: add vnc-system unit, to allow different implementations

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

The qemu-vnc server will want to signal the XVP requests, let it have its own implementation.

---
 ui/vnc.h        |  4 ++++
 ui/vnc-system.c | 19 +++++++++++++++++++
 ui/vnc.c        |  4 ++--
 ui/meson.build  |  2 +-
 4 files changed, 26 insertions(+), 3 deletions(-)
 create mode 100644 ui/vnc-system.c
ui/vnc.h +4 -0
index d2ebb0f7f45..0b345246c8e 100644
@@ -648,4 +648,8 @@ void vnc_server_cut_text_caps(VncState *vs);
 void vnc_client_cut_text(VncState *vs, size_t len, uint8_t *text);
 void vnc_client_cut_text_ext(VncState *vs, int32_t len, uint32_t flags, uint8_t *data);
 
+/* XVP events */
+void vnc_action_shutdown(VncState *vs);
+void vnc_action_reset(VncState *vs);
+
 #endif /* QEMU_VNC_H */
ui/vnc-system.c new file +19 -0
new file mode 100644
index 00000000000..0632885f655
@@ -0,0 +1,19 @@
+/*
+ * QEMU VNC display driver
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "qemu/osdep.h"
+
+#include "ui/vnc.h"
+#include "system/runstate.h"
+
+void vnc_action_shutdown(VncState *vs)
+{
+    qemu_system_powerdown_request();
+}
+
+void vnc_action_reset(VncState *vs)
+{
+    qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
+}
ui/vnc.c +2 -2
index ea1579135b8..154b07e2e4e 100644
@@ -2522,13 +2522,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
 
             switch (action) {
             case VNC_XVP_ACTION_SHUTDOWN:
-                qemu_system_powerdown_request();
+                vnc_action_shutdown(vs);
                 break;
             case VNC_XVP_ACTION_REBOOT:
                 send_xvp_message(vs, VNC_XVP_CODE_FAIL);
                 break;
             case VNC_XVP_ACTION_RESET:
-                qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
+                vnc_action_reset(vs);
                 break;
             default:
                 send_xvp_message(vs, VNC_XVP_CODE_FAIL);
ui/meson.build +1 -1
index 7b6e867d3af..74151b05033 100644
@@ -48,7 +48,7 @@ vnc_ss.add(files(
 vnc_ss.add(zlib, jpeg, png)
 vnc_ss.add(when: sasl, if_true: files('vnc-auth-sasl.c'))
 system_ss.add_all(when: [vnc, pixman], if_true: vnc_ss)
-system_ss.add(when: vnc, if_false: files('vnc-stubs.c'))
+system_ss.add(when: vnc, if_true: files('vnc-system.c'), if_false: files('vnc-stubs.c'))
 
 ui_modules = {}
 
Signature · 1 line
2.54.0
#18 lore raw

[PULL v2 24/33] ui/vnc: defer listener registration until the console is known

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Previously, the display change listener was registered early in vnc_display_new() without a console, requiring vnc_display_open() to conditionally unregister and re-register it when the actual console was resolved. Since vnc_display_new() and vnc_display_open() were merged in the previous commit, simply delay the registration and keyboard state initialization to vnc_display_open(), after the console has been looked up. This removes the conditional re-registration and simplifies the code.

---
 ui/vnc.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)
ui/vnc.c +3 -9
index d65153a5001..ea1579135b8 100644
@@ -3457,8 +3457,6 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
 
     vnc_start_worker_thread(vd);
 
-    register_displaychangelistener(&vd->dcl);
-    vd->kbd = qkbd_state_init(vd->dcl.con);
     vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
         &vmstate_change_handler, vd);
 
@@ -4269,13 +4267,9 @@ static bool vnc_display_open(VncDisplay *vd, Error **errp)
         con = qemu_console_lookup_default();
     }
 
-    if (con != vd->dcl.con) {
-        qkbd_state_free(vd->kbd);
-        unregister_displaychangelistener(&vd->dcl);
-        vd->dcl.con = con;
-        register_displaychangelistener(&vd->dcl);
-        vd->kbd = qkbd_state_init(vd->dcl.con);
-    }
+    vd->dcl.con = con;
+    register_displaychangelistener(&vd->dcl);
+    vd->kbd = qkbd_state_init(vd->dcl.con);
     qkbd_state_set_delay(vd->kbd, key_delay_ms);
 
     if (saddr_list == NULL) {
Signature · 1 line
2.54.0
#19 lore raw

[PULL v2 20/33] ui/vnc: make the worker thread per-VncDisplay

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

The VNC encoding worker thread was using a single global queue shared across all VNC displays, with no way to stop it. This made it impossible to properly clean up resources when a VncDisplay is freed.

Move the VncJobQueue from a file-scoped global to a per-VncDisplay member, so each display owns its worker thread and queue. Add vnc_stop_worker_thread() to perform an orderly shutdown: signal the thread to exit, join it, and destroy the queue. The thread is now created as QEMU_THREAD_JOINABLE instead of QEMU_THREAD_DETACHED.

---
 ui/vnc-jobs.h |  3 ++-
 ui/vnc.h      |  2 ++
 ui/vnc-jobs.c | 62 +++++++++++++++++++++++++++++++++------------------
 ui/vnc.c      |  3 ++-
 4 files changed, 46 insertions(+), 24 deletions(-)
ui/vnc-jobs.h +2 -1
index 59f66bcc353..e5ab55c1da6 100644
@@ -37,7 +37,8 @@ void vnc_job_push(VncJob *job);
 void vnc_jobs_join(VncState *vs);
 
 void vnc_jobs_consume_buffer(VncState *vs);
-void vnc_start_worker_thread(void);
+void vnc_start_worker_thread(VncDisplay *vd);
+void vnc_stop_worker_thread(VncDisplay *vd);
 
 /* Locks */
 static inline int vnc_trylock_display(VncDisplay *vd)
ui/vnc.h +2 -0
index 472a55f7b5f..780fd39469f 100644
@@ -62,6 +62,7 @@
 
 typedef struct VncState VncState;
 typedef struct VncJob VncJob;
+typedef struct VncJobQueue VncJobQueue;
 typedef struct VncRect VncRect;
 typedef struct VncRectEntry VncRectEntry;
 
@@ -158,6 +159,7 @@ struct VncDisplay
     int ledstate;
     QKbdState *kbd;
     QemuMutex mutex;
+    VncJobQueue *queue;
 
     int cursor_msize;
     uint8_t *cursor_mask;
ui/vnc-jobs.c +40 -22

134 lines not on this page · raw message

ui/vnc.c +2 -1
index c87d1f61a0a..3a908670ab9 100644
@@ -3457,7 +3457,7 @@ void vnc_display_init(const char *id, Error **errp)
     vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
     vd->connections_limit = 32;
 
-    vnc_start_worker_thread();
+    vnc_start_worker_thread(vd);
 
     register_displaychangelistener(&vd->dcl);
     vd->kbd = qkbd_state_init(vd->dcl.con);
@@ -3513,6 +3513,7 @@ static void vnc_display_free(VncDisplay *vd)
 
     assert(QTAILQ_EMPTY(&vd->clients));
 
+    vnc_stop_worker_thread(vd);
     vnc_display_close(vd);
     unregister_displaychangelistener(&vd->dcl);
     qkbd_state_free(vd->kbd);
Signature · 1 line
2.54.0
#20 lore raw

[PULL v2 26/33] ui/console: simplify registering display/console change listener

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Introduce qemu_console_register_listener() which combines setting dcl->con, dcl->ops and calling register_displaychangelistener() into a single call. This removes repetitive boilerplate across all display backends and makes it harder to forget setting one of the fields.

Also move the early-return check in unregister_displaychangelistener() before the trace call, so that unregistering a never-registered listener (e.g. on error paths) does not dereference a NULL ops pointer.

---
 include/ui/console.h |  6 ++++--
 hw/display/qxl.c     |  4 +---
 ui/console.c         | 11 ++++++++---
 ui/curses.c          |  9 +++------
 ui/dbus-console.c    |  6 ++----
 ui/dbus-listener.c   | 27 ++++++++-------------------
 ui/egl-headless.c    |  4 +---
 ui/gtk.c             | 10 ++++------
 ui/sdl2.c            |  8 +++-----
 ui/spice-display.c   |  8 +++-----
 ui/vnc.c             | 11 ++++-------
 ui/cocoa.m           | 13 ++++---------
 12 files changed, 45 insertions(+), 72 deletions(-)
include/ui/console.h +4 -2
index 89fb4c1942a..69ac7b01b33 100644
@@ -291,10 +291,12 @@ struct DisplayGLCtx {
 
 DisplayState *init_displaystate(void);
 
-void register_displaychangelistener(DisplayChangeListener *dcl);
+void qemu_console_register_listener(QemuConsole *con,
+                                    DisplayChangeListener *dcl,
+                                    const DisplayChangeListenerOps *ops);
 void update_displaychangelistener(DisplayChangeListener *dcl,
                                   uint64_t interval);
-void unregister_displaychangelistener(DisplayChangeListener *dcl);
+void qemu_console_unregister_listener(DisplayChangeListener *dcl);
 
 bool dpy_ui_info_supported(const QemuConsole *con);
 const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con);
hw/display/qxl.c +1 -3
index 0a3c42c8ec2..4244ebe51d2 100644
@@ -2251,9 +2251,7 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp)
         return;
     }
 
-    qxl->ssd.dcl.ops = &display_listener_ops;
-    qxl->ssd.dcl.con = vga->con;
-    register_displaychangelistener(&qxl->ssd.dcl);
+    qemu_console_register_listener(vga->con, &qxl->ssd.dcl, &display_listener_ops);
 }
 
 static void qxl_realize_secondary(PCIDevice *dev, Error **errp)
ui/console.c +8 -3
index b837ce1c9fc..4f3b4394268 100644
@@ -572,10 +572,15 @@ dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
     }
 }
 
-void register_displaychangelistener(DisplayChangeListener *dcl)
+void qemu_console_register_listener(QemuConsole *con,
+                                    DisplayChangeListener *dcl,
+                                    const DisplayChangeListenerOps *ops)
 {
     assert(!dcl->ds);
 
+    dcl->con = con;
+    dcl->ops = ops;
+
     trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
     dcl->ds = get_alloc_displaystate();
     QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
@@ -600,10 +605,10 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
     }
 }
 
-void unregister_displaychangelistener(DisplayChangeListener *dcl)
+void qemu_console_unregister_listener(DisplayChangeListener *dcl)
 {
     DisplayState *ds = dcl->ds;
-    trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
+    trace_displaychangelistener_unregister(dcl, dcl->ops ? dcl->ops->dpy_name : NULL);
     if (!ds) {
         return;
     }
ui/curses.c +3 -6
index 96427aa6bb9..dbb5992981c 100644
@@ -324,9 +324,8 @@ static void curses_refresh(DisplayChangeListener *dcl)
                         if (con) {
                             erase();
                             wnoutrefresh(stdscr);
-                            unregister_displaychangelistener(dcl);
-                            dcl->con = con;
-                            register_displaychangelistener(dcl);
+                            qemu_console_unregister_listener(dcl);
+                            qemu_console_register_listener(con, dcl, dcl->ops);
 
                             invalidate = 1;
                         }
@@ -805,9 +804,7 @@ static void curses_display_init(DisplayState *ds, DisplayOptions *opts)
     curses_winch_init();
 
     dcl = g_new0(DisplayChangeListener, 1);
-    dcl->con = qemu_console_lookup_default();
-    dcl->ops = &dcl_ops;
-    register_displaychangelistener(dcl);
+    qemu_console_register_listener(qemu_console_lookup_default(), dcl, &dcl_ops);
 
     invalidate = 1;
 }
ui/dbus-console.c +2 -4
index 564f004bd86..23f547a673d 100644
@@ -143,7 +143,6 @@ dbus_display_console_init(DBusDisplayConsole *object)
     DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
 
     ddc->listeners = g_ptr_array_new_with_free_func(g_object_unref);
-    ddc->dcl.ops = &dbus_console_dcl_ops;
 }
 
 static void
@@ -151,7 +150,7 @@ dbus_display_console_dispose(GObject *object)
 {
     DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
 
-    unregister_displaychangelistener(&ddc->dcl);
+    qemu_console_unregister_listener(&ddc->dcl);
     g_clear_object(&ddc->iface_touch);
     g_clear_object(&ddc->iface_mouse);
     g_clear_object(&ddc->iface_kbd);
@@ -553,7 +552,6 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
                         "g-object-path", path,
                         NULL);
     ddc->display = display;
-    ddc->dcl.con = con;
     /* handle errors, and skip non graphics? */
     qemu_console_fill_device_address(
         con, device_addr, sizeof(device_addr), NULL);
@@ -611,7 +609,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
         slot->tracking_id = -1;
     }
 
-    register_displaychangelistener(&ddc->dcl);
+    qemu_console_register_listener(con, &ddc->dcl, &dbus_console_dcl_ops);
     ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
     qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
     dbus_mouse_update_is_absolute(ddc);
ui/dbus-listener.c +8 -19
index e5ce92d1257..cc2c969686e 100644
@@ -957,7 +957,7 @@ dbus_display_listener_dispose(GObject *object)
 {
     DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
 
-    unregister_displaychangelistener(&ddl->dcl);
+    qemu_console_unregister_listener(&ddl->dcl);
     g_clear_object(&ddl->conn);
     g_clear_pointer(&ddl->bus_name, g_free);
     g_clear_object(&ddl->proxy);
@@ -978,28 +978,12 @@ dbus_display_listener_dispose(GObject *object)
     G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
 }
 
-static void
-dbus_display_listener_constructed(GObject *object)
-{
-    DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
-
-    ddl->dcl.ops = &dbus_dcl_ops;
-#ifdef CONFIG_OPENGL
-    if (display_opengl) {
-        ddl->dcl.ops = &dbus_gl_dcl_ops;
-    }
-#endif
-
-    G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object);
-}
-
 static void
 dbus_display_listener_class_init(DBusDisplayListenerClass *klass)
 {
     GObjectClass *object_class = G_OBJECT_CLASS(klass);
 
     object_class->dispose = dbus_display_listener_dispose;
-    object_class->constructed = dbus_display_listener_constructed;
 }
 
 static void
@@ -1258,6 +1242,7 @@ dbus_display_listener_new(const char *bus_name,
                           GDBusConnection *conn,
                           DBusDisplayConsole *console)
 {
+    const DisplayChangeListenerOps *ops = &dbus_dcl_ops;
     DBusDisplayListener *ddl;
     QemuConsole *con;
     g_autoptr(GError) err = NULL;
@@ -1290,8 +1275,12 @@ dbus_display_listener_new(const char *bus_name,
 
     con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
     assert(con);
-    ddl->dcl.con = con;
-    register_displaychangelistener(&ddl->dcl);
+#ifdef CONFIG_OPENGL
+    if (display_opengl) {
+        ops = &dbus_gl_dcl_ops;
+    }
+#endif
+    qemu_console_register_listener(con, &ddl->dcl, ops);
 
     return ddl;
 }
ui/egl-headless.c +1 -3
index 352b30b43fb..4f046c975a9 100644
@@ -229,13 +229,11 @@ static void egl_headless_init(DisplayState *ds, DisplayOptions *opts)
         }
 
         edpy = g_new0(egl_dpy, 1);
-        edpy->dcl.con = con;
-        edpy->dcl.ops = &egl_ops;
         edpy->gls = qemu_gl_init_shader();
         ctx = g_new0(DisplayGLCtx, 1);
         ctx->ops = &eglctx_ops;
         qemu_console_set_display_gl_ctx(con, ctx);
-        register_displaychangelistener(&edpy->dcl);
+        qemu_console_register_listener(con, &edpy->dcl, &egl_ops);
     }
 }
 
ui/gtk.c +4 -6
index ec95f0f294a..ef3707b3634 100644
@@ -2251,6 +2251,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
                               QemuConsole *con, int idx,
                               GSList *group, GtkWidget *view_menu)
 {
+    const DisplayChangeListenerOps *ops = &dcl_ops;
     bool zoom_to_fit = false;
     int i;
 
@@ -2275,7 +2276,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
             vc->gfx.drawing_area = gtk_gl_area_new();
             g_signal_connect(vc->gfx.drawing_area, "realize",
                              G_CALLBACK(gl_area_realize), vc);
-            vc->gfx.dcl.ops = &dcl_gl_area_ops;
+            ops = &dcl_gl_area_ops;
             vc->gfx.dgc.ops = &gl_area_ctx_ops;
         } else {
 #ifdef CONFIG_X11
@@ -2290,7 +2291,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
             gtk_widget_set_double_buffered(vc->gfx.drawing_area, FALSE);
 #pragma GCC diagnostic pop
-            vc->gfx.dcl.ops = &dcl_egl_ops;
+            ops = &dcl_egl_ops;
             vc->gfx.dgc.ops = &egl_ctx_ops;
             vc->gfx.has_dmabuf = qemu_egl_has_dmabuf();
 #else
@@ -2301,7 +2302,6 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
 #endif
     {
         vc->gfx.drawing_area = gtk_drawing_area_new();
-        vc->gfx.dcl.ops = &dcl_ops;
     }
 
 
@@ -2325,12 +2325,10 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
                              vc->tab_item, gtk_label_new(vc->label));
 
     vc->gfx.kbd = qkbd_state_init(con);
-    vc->gfx.dcl.con = con;
-
     if (display_opengl) {
         qemu_console_set_display_gl_ctx(con, &vc->gfx.dgc);
     }
-    register_displaychangelistener(&vc->gfx.dcl);
+    qemu_console_register_listener(con, &vc->gfx.dcl, ops);
 
     gd_connect_vc_gfx_signals(vc);
     group = gd_vc_menu_init(s, vc, idx, group, view_menu);
ui/sdl2.c +3 -5
index 5dd612d9a6a..89516f95c41 100644
@@ -934,6 +934,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
     sdl2_console = g_new0(struct sdl2_console, sdl2_num_outputs);
     for (i = 0; i < sdl2_num_outputs; i++) {
         QemuConsole *con = qemu_console_lookup_by_index(i);
+        const DisplayChangeListenerOps *ops = &dcl_2d_ops;
         assert(con != NULL);
         if (!qemu_console_is_graphic(con) &&
             qemu_console_get_index(con) != 0) {
@@ -943,13 +944,11 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
         sdl2_console[i].opts = o;
 #ifdef CONFIG_OPENGL
         sdl2_console[i].opengl = display_opengl;
-        sdl2_console[i].dcl.ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops;
         sdl2_console[i].dgc.ops = display_opengl ? &gl_ctx_ops : NULL;
+        ops = display_opengl ? &dcl_gl_ops : &dcl_2d_ops;
 #else
         sdl2_console[i].opengl = 0;
-        sdl2_console[i].dcl.ops = &dcl_2d_ops;
 #endif
-        sdl2_console[i].dcl.con = con;
         sdl2_console[i].kbd = qkbd_state_init(con);
 #ifdef CONFIG_OPENGL
         if (display_opengl) {
@@ -957,8 +956,7 @@ static void sdl2_display_init(DisplayState *ds, DisplayOptions *o)
             sdl2_gl_console_init(&sdl2_console[i]);
         }
 #endif
-        register_displaychangelistener(&sdl2_console[i].dcl);
-
+        qemu_console_register_listener(con, &sdl2_console[i].dcl, ops);
 #if defined(SDL_VIDEO_DRIVER_WINDOWS) || defined(SDL_VIDEO_DRIVER_X11)
         if (SDL_GetWindowWMInfo(sdl2_console[i].real_window, &info)) {
 #if defined(SDL_VIDEO_DRIVER_WINDOWS)
ui/spice-display.c +3 -5
index 87cc193cdee..56d8140fad8 100644
@@ -1387,13 +1387,13 @@ static void qemu_spice_display_init_one(QemuConsole *con)
     SimpleSpiceDisplay *ssd = g_new0(SimpleSpiceDisplay, 1);
     Error *err = NULL;
     char device_address[256] = "";
+    const DisplayChangeListenerOps *ops = &display_listener_ops;
 
     qemu_spice_display_init_common(ssd);
 
-    ssd->dcl.ops = &display_listener_ops;
 #ifdef HAVE_SPICE_GL
     if (spice_opengl) {
-        ssd->dcl.ops = &display_listener_gl_ops;
+        ops = &display_listener_gl_ops;
         ssd->dgc.ops = &gl_ctx_ops;
         ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd);
         ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
@@ -1403,8 +1403,6 @@ static void qemu_spice_display_init_one(QemuConsole *con)
         ssd->have_scanout = false;
     }
 #endif
-    ssd->dcl.con = con;
-
     ssd->qxl.base.sif = &dpy_interface.base;
     qemu_spice_add_display_interface(&ssd->qxl, con);
 
@@ -1422,7 +1420,7 @@ static void qemu_spice_display_init_one(QemuConsole *con)
     if (spice_opengl) {
         qemu_console_set_display_gl_ctx(con, &ssd->dgc);
     }
-    register_displaychangelistener(&ssd->dcl);
+    qemu_console_register_listener(con, &ssd->dcl, ops);
 }
 
 void qemu_spice_display_init(void)
ui/vnc.c +4 -7
index 154b07e2e4e..e8c8773a36e 100644
@@ -1860,10 +1860,9 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
             qkbd_state_modifier_get(vs->vd->kbd, QKBD_MOD_ALT)) {
             QemuConsole *con = qemu_console_lookup_by_index(qcode - Q_KEY_CODE_1);
             if (con) {
-                unregister_displaychangelistener(&vs->vd->dcl);
+                qemu_console_unregister_listener(&vs->vd->dcl);
                 qkbd_state_switch_console(vs->vd->kbd, con);
-                vs->vd->dcl.con = con;
-                register_displaychangelistener(&vs->vd->dcl);
+                qemu_console_register_listener(con, &vs->vd->dcl, vs->vd->dcl.ops);
             }
             return;
         }
@@ -3434,7 +3433,6 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
     vd = g_new0(VncDisplay, 1);
     qemu_mutex_init(&vd->mutex);
     vd->id = g_strdup(id);
-    vd->dcl.ops = &dcl_ops;
 
     QTAILQ_INIT(&vd->clients);
     vd->expires = TIME_MAX;
@@ -3524,7 +3522,7 @@ void vnc_display_free(VncDisplay *vd)
     }
 
     vnc_stop_worker_thread(vd);
-    unregister_displaychangelistener(&vd->dcl);
+    qemu_console_unregister_listener(&vd->dcl);
     qkbd_state_free(vd->kbd);
     qemu_del_vm_change_state_handler(vd->vmstate_handler_entry);
     kbd_layout_free(vd->kbd_layout);
@@ -4267,8 +4265,7 @@ static bool vnc_display_open(VncDisplay *vd, Error **errp)
         con = qemu_console_lookup_default();
     }
 
-    vd->dcl.con = con;
-    register_displaychangelistener(&vd->dcl);
+    qemu_console_register_listener(con, &vd->dcl, &dcl_ops);
     vd->kbd = qkbd_state_init(vd->dcl.con);
     qkbd_state_set_delay(vd->kbd, key_delay_ms);
 
ui/cocoa.m +4 -9
index 9093d1e408f..aaf82421589 100644
@@ -93,9 +93,7 @@ static void cocoa_switch(DisplayChangeListener *dcl,
     .dpy_mouse_set = cocoa_mouse_set,
     .dpy_cursor_define = cocoa_cursor_define,
 };
-static DisplayChangeListener dcl = {
-    .ops = &dcl_ops,
-};
+static DisplayChangeListener dcl;
 static QKbdState *kbd;
 static int cursor_hide = 1;
 static int left_command_key_enabled = 1;
@@ -425,8 +423,7 @@ - (void) selectConsoleLocked:(unsigned int)index
 
     unregister_displaychangelistener(&dcl);
     qkbd_state_switch_console(kbd, con);
-    dcl.con = con;
-    register_displaychangelistener(&dcl);
+    qemu_console_register_listener(con, &dcl, &dcl_ops);
     [self notifyMouseModeChange];
     [self updateUIInfo];
 }
@@ -2145,11 +2142,9 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
     add_console_menu_entries();
     addRemovableDevicesMenuItems();
 
-    dcl.con = qemu_console_lookup_default();
+    qemu_console_register_listener(qemu_console_lookup_default(),
+                                   &dcl, &dcl_ops);
     kbd = qkbd_state_init(dcl.con);
-
-    // register vga output callbacks
-    register_displaychangelistener(&dcl);
     qemu_add_mouse_mode_change_notifier(&mouse_mode_change_notifier);
     [cocoaView notifyMouseModeChange];
     [cocoaView updateUIInfo];
Signature · 1 line
2.54.0
#21 lore raw

[PULL v2 22/33] ui/vnc: merge vnc_display_init() and vnc_display_open()

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Combine the two-step vnc_display_init()/vnc_display_open() sequence into a single vnc_display_new() function that returns VncDisplay*. This simplifies the API by making vnc_display_open() an internal detail and will allow further code simplification.

vnc_display_new() is moved to vnc.h, since it returns VncDisplay* now. Add vnc_display_free() for consistency, and it will be later used.

---
 include/ui/console.h |  2 --
 ui/vnc.h             |  3 ++
 ui/vnc.c             | 79 ++++++++++++++++++--------------------------
 3 files changed, 36 insertions(+), 48 deletions(-)
include/ui/console.h +0 -2
index 7224b8142f3..550a5e08e46 100644
@@ -438,8 +438,6 @@ const char *qemu_display_get_vc(DisplayOptions *opts);
 void qemu_display_help(void);
 
 /* vnc.c */
-bool vnc_display_init(const char *id, Error **errp);
-bool vnc_display_open(const char *id, Error **errp);
 void vnc_display_add_client(const char *id, int csock, bool skipauth);
 int vnc_display_password(const char *id, const char *password, Error **errp);
 int vnc_display_pw_expire(const char *id, time_t expires);
ui/vnc.h +3 -0
index 780fd39469f..d2ebb0f7f45 100644
@@ -549,6 +549,9 @@ enum VncFeatures {
 #define VNC_CLIPBOARD_NOTIFY   (1 << 27)
 #define VNC_CLIPBOARD_PROVIDE  (1 << 28)
 
+VncDisplay *vnc_display_new(const char *id, Error **errp);
+void vnc_display_free(VncDisplay *vd);
+
 /*****************************************************************************
  *
  * Internal APIs
ui/vnc.c +33 -46

239 lines not on this page · raw message

Signature · 1 line
2.54.0
#22 lore raw

[PULL v2 28/33] ui/console: rename public API to use consistent qemu_console_ prefix

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Rename the display and graphic console public functions to follow a consistent qemu_console_ (or qemu_graphic_console_) naming convention.

The previous API used a mix of prefixes: dpy_, graphic_hw_, graphic_console_, console_has_, and update_displaychangelistener(). Unify them under a common qemu_console_ namespace for better discoverability and consistency.

The main renames are:
- dpy_gfx_*() / dpy_text_*() / dpy_gl_*() → qemu_console_*()
- dpy_{get,set}_ui_info() → qemu_console_{get,set}_ui_info()
- graphic_hw_*() → qemu_console_hw_*()
- graphic_console_*() → qemu_graphic_console_*()
- console_has_gl() → qemu_console_has_gl()
- update_displaychangelistener() → qemu_console_listener_set_refresh()

No functional changes.

---
 include/ui/console.h             | 108 ++++++++++++------------
 hw/arm/musicpal.c                |   4 +-
 hw/display/artist.c              |   4 +-
 hw/display/ati.c                 |  16 ++--
 hw/display/bcm2835_fb.c          |   5 +-
 hw/display/bochs-display.c       |  14 ++--
 hw/display/cg3.c                 |   6 +-
 hw/display/cirrus_vga.c          |   8 +-
 hw/display/cirrus_vga_isa.c      |   2 +-
 hw/display/dm163.c               |   6 +-
 hw/display/exynos4210_fimd.c     |   4 +-
 hw/display/g364fb.c              |  10 +--
 hw/display/imx6ul_lcdif.c        |  14 ++--
 hw/display/jazz_led.c            |   8 +-
 hw/display/macfb.c               |   6 +-
 hw/display/next-fb.c             |   4 +-
 hw/display/omap_lcdc.c           |   4 +-
 hw/display/pl110.c               |   4 +-
 hw/display/qxl-render.c          |  12 +--
 hw/display/qxl.c                 |  14 ++--
 hw/display/ramfb-standalone.c    |   2 +-
 hw/display/ramfb.c               |   4 +-
 hw/display/sm501.c               |   6 +-
 hw/display/ssd0303.c             |   4 +-
 hw/display/ssd0323.c             |   5 +-
 hw/display/tcx.c                 |  16 ++--
 hw/display/vga-isa.c             |   2 +-
 hw/display/vga-mmio.c            |   2 +-
 hw/display/vga-pci.c             |   6 +-
 hw/display/vga.c                 |  40 +++++----
 hw/display/vhost-user-gpu.c      |  22 ++---
 hw/display/virtio-gpu-base.c     |   2 +-
 hw/display/virtio-gpu-rutabaga.c |  10 +--
 hw/display/virtio-gpu-udmabuf.c  |   4 +-
 hw/display/virtio-gpu-virgl.c    |  20 ++---
 hw/display/virtio-gpu.c          |  26 +++---
 hw/display/virtio-vga.c          |   2 +-
 hw/display/vmware_vga.c          |  12 +--
 hw/display/xenfb.c               |   6 +-
 hw/display/xlnx_dp.c             |  10 +--
 hw/vfio/display.c                |  32 +++----
 ui/console-vc.c                  |  12 +--
 ui/console.c                     | 140 +++++++++++++++----------------
 ui/curses.c                      |   8 +-
 ui/dbus-console.c                |   4 +-
 ui/dbus-listener.c               |  10 +--
 ui/egl-headless.c                |   4 +-
 ui/gtk-egl.c                     |   6 +-
 ui/gtk-gl-area.c                 |   6 +-
 ui/gtk.c                         |  18 ++--
 ui/sdl2-2d.c                     |   2 +-
 ui/sdl2-gl.c                     |   2 +-
 ui/sdl2.c                        |   6 +-
 ui/spice-display.c               |  16 ++--
 ui/vnc.c                         |  22 ++---
 hw/display/apple-gfx.m           |  16 ++--
 ui/cocoa.m                       |  10 +--
 57 files changed, 379 insertions(+), 389 deletions(-)
include/ui/console.h +54 -54
index 69ac7b01b33..cfa940d4c66 100644
@@ -294,49 +294,49 @@ DisplayState *init_displaystate(void);
 void qemu_console_register_listener(QemuConsole *con,
                                     DisplayChangeListener *dcl,
                                     const DisplayChangeListenerOps *ops);
-void update_displaychangelistener(DisplayChangeListener *dcl,
-                                  uint64_t interval);
+void qemu_console_listener_set_refresh(DisplayChangeListener *dcl,
+                                       uint64_t interval);
 void qemu_console_unregister_listener(DisplayChangeListener *dcl);
 
-bool dpy_ui_info_supported(const QemuConsole *con);
-const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con);
-int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay);
-
-void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h);
-void dpy_gfx_update_full(QemuConsole *con);
-void dpy_gfx_replace_surface(QemuConsole *con,
-                             DisplaySurface *surface);
-void dpy_text_cursor(QemuConsole *con, int x, int y);
-void dpy_text_update(QemuConsole *con, int x, int y, int w, int h);
-void dpy_text_resize(QemuConsole *con, int w, int h);
-void dpy_mouse_set(QemuConsole *con, int x, int y, bool on);
-void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor);
-bool dpy_gfx_check_format(QemuConsole *con,
-                          pixman_format_code_t format);
-
-void dpy_gl_scanout_disable(QemuConsole *con);
-void dpy_gl_scanout_texture(QemuConsole *con,
-                            uint32_t backing_id, bool backing_y_0_top,
-                            uint32_t backing_width, uint32_t backing_height,
-                            uint32_t x, uint32_t y, uint32_t w, uint32_t h,
-                            void *d3d_tex2d);
-void dpy_gl_scanout_dmabuf(QemuConsole *con,
-                           QemuDmaBuf *dmabuf);
-void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
-                          bool have_hot, uint32_t hot_x, uint32_t hot_y);
-void dpy_gl_cursor_position(QemuConsole *con,
-                            uint32_t pos_x, uint32_t pos_y);
-void dpy_gl_release_dmabuf(QemuConsole *con,
-                           QemuDmaBuf *dmabuf);
-void dpy_gl_update(QemuConsole *con,
-                   uint32_t x, uint32_t y, uint32_t w, uint32_t h);
-
-QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
-                                QEMUGLParams *params);
-void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx);
-int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx);
-
-bool console_has_gl(QemuConsole *con);
+bool qemu_console_ui_info_supported(const QemuConsole *con);
+const QemuUIInfo *qemu_console_get_ui_info(const QemuConsole *con);
+int qemu_console_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay);
+
+void qemu_console_update(QemuConsole *con, int x, int y, int w, int h);
+void qemu_console_update_full(QemuConsole *con);
+void qemu_console_set_surface(QemuConsole *con,
+                              DisplaySurface *surface);
+void qemu_console_text_set_cursor(QemuConsole *con, int x, int y);
+void qemu_console_text_update(QemuConsole *con, int x, int y, int w, int h);
+void qemu_console_text_resize(QemuConsole *con, int w, int h);
+void qemu_console_set_mouse(QemuConsole *con, int x, int y, bool on);
+void qemu_console_set_cursor(QemuConsole *con, QEMUCursor *cursor);
+bool qemu_console_check_format(QemuConsole *con,
+                               pixman_format_code_t format);
+
+void qemu_console_gl_scanout_disable(QemuConsole *con);
+void qemu_console_gl_scanout_texture(QemuConsole *con,
+                                     uint32_t backing_id, bool backing_y_0_top,
+                                     uint32_t backing_width, uint32_t backing_height,
+                                     uint32_t x, uint32_t y, uint32_t w, uint32_t h,
+                                     void *d3d_tex2d);
+void qemu_console_gl_scanout_dmabuf(QemuConsole *con,
+                                    QemuDmaBuf *dmabuf);
+void qemu_console_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
+                                   bool have_hot, uint32_t hot_x, uint32_t hot_y);
+void qemu_console_gl_cursor_position(QemuConsole *con,
+                                     uint32_t pos_x, uint32_t pos_y);
+void qemu_console_gl_release_dmabuf(QemuConsole *con,
+                                    QemuDmaBuf *dmabuf);
+void qemu_console_gl_update(QemuConsole *con,
+                            uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+
+QEMUGLContext qemu_console_gl_ctx_create(QemuConsole *con,
+                                         QEMUGLParams *params);
+void qemu_console_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx);
+int qemu_console_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx);
+
+bool qemu_console_has_gl(QemuConsole *con);
 
 enum {
     GRAPHIC_FLAGS_NONE     = 0,
@@ -361,19 +361,19 @@ typedef struct GraphicHwOps {
     void (*gl_block)(void *opaque, bool block);
 } GraphicHwOps;
 
-QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
-                                  const GraphicHwOps *ops,
-                                  void *opaque);
-void graphic_console_set_hwops(QemuConsole *con,
-                               const GraphicHwOps *hw_ops,
-                               void *opaque);
-void graphic_console_close(QemuConsole *con);
-
-void graphic_hw_update(QemuConsole *con);
-void graphic_hw_update_done(QemuConsole *con);
-void graphic_hw_invalidate(QemuConsole *con);
-void graphic_hw_text_update(QemuConsole *con, uint32_t *chardata);
-void graphic_hw_gl_block(QemuConsole *con, bool block);
+QemuConsole *qemu_graphic_console_create(DeviceState *dev, uint32_t head,
+                                         const GraphicHwOps *ops,
+                                         void *opaque);
+void qemu_graphic_console_set_hwops(QemuConsole *con,
+                                    const GraphicHwOps *hw_ops,
+                                    void *opaque);
+void qemu_graphic_console_close(QemuConsole *con);
+
+void qemu_console_hw_update(QemuConsole *con);
+void qemu_console_hw_update_done(QemuConsole *con);
+void qemu_console_hw_invalidate(QemuConsole *con);
+void qemu_console_hw_text_update(QemuConsole *con, uint32_t *chardata);
+void qemu_console_hw_gl_block(QemuConsole *con, bool block);
 
 void qemu_console_early_init(void);
 
hw/arm/musicpal.c +2 -2
index ba88ed756e2..83676eb7fea 100644
@@ -170,7 +170,7 @@ static bool lcd_refresh(void *opaque)
         }
     }
 
-    dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
+    qemu_console_update(s->con, 0, 0, 128*3, 64*3);
     return true;
 }
 
@@ -253,7 +253,7 @@ static const GraphicHwOps musicpal_gfx_ops = {
 static void musicpal_lcd_realize(DeviceState *dev, Error **errp)
 {
     musicpal_lcd_state *s = MUSICPAL_LCD(dev);
-    s->con = graphic_console_init(dev, 0, &musicpal_gfx_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &musicpal_gfx_ops, s);
     qemu_console_resize(s->con, 128 * 3, 64 * 3);
 }
 
hw/display/artist.c +2 -2
index a07508378c7..288d466ec64 100644
@@ -1324,7 +1324,7 @@ static bool artist_update_display(void *opaque)
     artist_draw_cursor(s);
 
     if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, s->width, last - first + 1);
+        qemu_console_update(s->con, 0, first, s->width, last - first + 1);
     }
 
     return true;
@@ -1424,7 +1424,7 @@ static void artist_realizefn(DeviceState *dev, Error **errp)
     s->misc_video |= 0x0A000000;
     s->misc_ctrl  |= 0x00800000;
 
-    s->con = graphic_console_init(dev, 0, &artist_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &artist_ops, s);
     qemu_console_resize(s->con, s->width, s->height);
 }
 
hw/display/ati.c +8 -8
index 3a7d45a8820..d77589df67a 100644
@@ -161,7 +161,7 @@ static void ati_cursor_define(ATIVGAState *s)
     }
     cursor_set_mono(s->cursor, s->regs.cur_color1, s->regs.cur_color0,
                     (uint8_t *)&data[64], 1, (uint8_t *)&data[0]);
-    dpy_cursor_define(s->vga.con, s->cursor);
+    qemu_console_set_cursor(s->vga.con, s->cursor);
 }
 
 /* Alternatively support guest rendered hardware cursor */
@@ -626,9 +626,9 @@ static void ati_mm_write(void *opaque, hwaddr addr,
                 if (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) {
                     ati_cursor_define(s);
                 }
-                dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
-                              s->regs.cur_hv_pos & 0xffff,
-                              (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) != 0);
+                qemu_console_set_mouse(s->vga.con, s->regs.cur_hv_pos >> 16,
+                                       s->regs.cur_hv_pos & 0xffff,
+                                       (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) != 0);
             }
         }
         if ((val & (CRTC2_EXT_DISP_EN | CRTC2_EN)) !=
@@ -780,8 +780,8 @@ static void ati_mm_write(void *opaque, hwaddr addr,
         }
         if (!s->cursor_guest_mode &&
             (s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(t & BIT(31))) {
-            dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
-                          s->regs.cur_hv_pos & 0xffff, true);
+            qemu_console_set_mouse(s->vga.con, s->regs.cur_hv_pos >> 16,
+                                   s->regs.cur_hv_pos & 0xffff, true);
         }
         break;
     }
@@ -1094,7 +1094,7 @@ static void ati_vga_realize(PCIDevice *dev, Error **errp)
     }
     vga_init(vga, OBJECT(s), pci_address_space(dev),
              pci_address_space_io(dev), true);
-    vga->con = graphic_console_init(DEVICE(s), 0, s->vga.hw_ops, vga);
+    vga->con = qemu_graphic_console_create(DEVICE(s), 0, s->vga.hw_ops, vga);
     if (s->cursor_guest_mode) {
         vga->cursor_invalidate = ati_cursor_invalidate;
         vga->cursor_draw_line = ati_cursor_draw_line;
@@ -1167,7 +1167,7 @@ static void ati_vga_exit(PCIDevice *dev)
     ATIVGAState *s = ATI_VGA(dev);
 
     timer_del(&s->vblank_timer);
-    graphic_console_close(s->vga.con);
+    qemu_graphic_console_close(s->vga.con);
 }
 
 static const Property ati_vga_properties[] = {
hw/display/bcm2835_fb.c +2 -3
index 83c4c03c7ca..bd58f625fcd 100644
@@ -207,8 +207,7 @@ static bool fb_update_display(void *opaque)
                                draw_line_src16, s, &first, &last);
 
     if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, s->config.xres,
-                       last - first + 1);
+        qemu_console_update(s->con, 0, first, s->config.xres, last - first + 1);
     }
 
     s->invalidate = false;
@@ -427,7 +426,7 @@ static void bcm2835_fb_realize(DeviceState *dev, Error **errp)
 
     bcm2835_fb_reset(dev);
 
-    s->con = graphic_console_init(dev, 0, &vgafb_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &vgafb_ops, s);
     qemu_console_resize(s->con, s->config.xres, s->config.yres);
 }
 
hw/display/bochs-display.c +6 -8
index 8ef9b76cf85..64e669429c4 100644
@@ -224,12 +224,12 @@ static bool bochs_display_update(void *opaque)
                                              mode.format,
                                              mode.stride,
                                              ptr + mode.offset);
-        dpy_gfx_replace_surface(s->con, ds);
+        qemu_console_set_surface(s->con, ds);
         full_update = true;
     }
 
     if (full_update) {
-        dpy_gfx_update_full(s->con);
+        qemu_console_update_full(s->con);
     } else {
         snap = memory_region_snapshot_and_clear_dirty(&s->vram,
                                                       mode.offset, mode.size,
@@ -243,14 +243,12 @@ static bool bochs_display_update(void *opaque)
                 ys = y;
             }
             if (!dirty && ys >= 0) {
-                dpy_gfx_update(s->con, 0, ys,
-                               mode.width, y - ys);
+                qemu_console_update(s->con, 0, ys, mode.width, y - ys);
                 ys = -1;
             }
         }
         if (ys >= 0) {
-            dpy_gfx_update(s->con, 0, ys,
-                           mode.width, y - ys);
+            qemu_console_update(s->con, 0, ys, mode.width, y - ys);
         }
 
         g_free(snap);
@@ -279,7 +277,7 @@ static void bochs_display_realize(PCIDevice *dev, Error **errp)
     }
     s->vgamem = pow2ceil(s->vgamem);
 
-    s->con = graphic_console_init(DEVICE(dev), 0, &bochs_display_gfx_ops, s);
+    s->con = qemu_graphic_console_create(DEVICE(dev), 0, &bochs_display_gfx_ops, s);
 
     memory_region_init_ram(&s->vram, obj, "bochs-display-vram", s->vgamem,
                            &error_fatal);
@@ -344,7 +342,7 @@ static void bochs_display_exit(PCIDevice *dev)
 {
     BochsDisplayState *s = BOCHS_DISPLAY(dev);
 
-    graphic_console_close(s->con);
+    qemu_graphic_console_close(s->con);
 }
 
 static const Property bochs_display_properties[] = {
hw/display/cg3.c +3 -3
index 963bb3427a6..f9dda1549dd 100644
@@ -137,7 +137,7 @@ static bool cg3_update_display(void *opaque)
             }
         } else {
             if (y_start >= 0) {
-                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+                qemu_console_update(s->con, 0, y_start, width, y - y_start);
                 y_start = -1;
             }
             pix += width;
@@ -146,7 +146,7 @@ static bool cg3_update_display(void *opaque)
     }
     s->full_update = 0;
     if (y_start >= 0) {
-        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+        qemu_console_update(s->con, 0, y_start, width, y - y_start);
     }
     /* vsync interrupt? */
     if (s->regs[0] & CG3_CR_ENABLE_INTS) {
@@ -311,7 +311,7 @@ static void cg3_realizefn(DeviceState *dev, Error **errp)
 
     sysbus_init_irq(sbd, &s->irq);
 
-    s->con = graphic_console_init(dev, 0, &cg3_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &cg3_ops, s);
     qemu_console_resize(s->con, s->width, s->height);
 }
 
hw/display/cirrus_vga.c +4 -4
index 48be3c8a932..0a8c74e1374 100644
@@ -779,9 +779,9 @@ static int cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
                       s->cirrus_blt_width, s->cirrus_blt_height);
 
     if (notify) {
-        dpy_gfx_update(s->vga.con, dx, dy,
-                       s->cirrus_blt_width / depth,
-                       s->cirrus_blt_height);
+        qemu_console_update(s->vga.con, dx, dy,
+                            s->cirrus_blt_width / depth,
+                            s->cirrus_blt_height);
     }
 
     /* we don't have to notify the display that this portion has
@@ -2964,7 +2964,7 @@ static void pci_cirrus_vga_realize(PCIDevice *dev, Error **errp)
     }
     cirrus_init_common(s, OBJECT(dev), device_id, 1, pci_address_space(dev),
                        pci_address_space_io(dev));
-    s->vga.con = graphic_console_init(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
+    s->vga.con = qemu_graphic_console_create(DEVICE(dev), 0, s->vga.hw_ops, &s->vga);
 
     /* setup PCI */
     memory_region_init(&s->pci_bar, OBJECT(dev), "cirrus-pci-bar0", 0x2000000);
hw/display/cirrus_vga_isa.c +1 -1
index 76034a88605..b8052d1d8ed 100644
@@ -62,7 +62,7 @@ static void isa_cirrus_vga_realizefn(DeviceState *dev, Error **errp)
     cirrus_init_common(&d->cirrus_vga, OBJECT(dev), CIRRUS_ID_CLGD5430, 0,
                        isa_address_space(isadev),
                        isa_address_space_io(isadev));
-    s->con = graphic_console_init(dev, 0, s->hw_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, s->hw_ops, s);
     rom_add_vga(VGABIOS_CIRRUS_FILENAME);
     /* XXX ISA-LFB support */
     /* FIXME not qdev yet */
hw/display/dm163.c +3 -3
index 9ea62cb4f76..afade0b98c3 100644
@@ -277,8 +277,8 @@ static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
         }
     }
 
-    dpy_gfx_update(s->console, 0, LED_SQUARE_SIZE * row,
-                    RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE, LED_SQUARE_SIZE);
+    qemu_console_update(s->console, 0, LED_SQUARE_SIZE * row,
+                        RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE, LED_SQUARE_SIZE);
     s->redraw &= ~(1 << row);
     trace_dm163_redraw(s->redraw);
 
@@ -322,7 +322,7 @@ static void dm163_realize(DeviceState *dev, Error **errp)
     qdev_init_gpio_in(dev, dm163_en_b_gpio_handler, 1);
     qdev_init_gpio_out_named(dev, &s->sout, "sout", 1);
 
-    s->console = graphic_console_init(dev, 0, &dm163_ops, s);
+    s->console = qemu_graphic_console_create(dev, 0, &dm163_ops, s);
     qemu_console_resize(s->console, RGB_MATRIX_NUM_COLS * LED_SQUARE_SIZE,
                         RGB_MATRIX_NUM_ROWS * LED_SQUARE_SIZE);
 }
hw/display/exynos4210_fimd.c +2 -2
index a91f04aaf79..5133623ee2e 100644
@@ -1340,7 +1340,7 @@ static bool exynos4210_fimd_update(void *opaque)
             fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
                     RGBA_SIZE, d + global_width * line * bpp);
         }
-        dpy_gfx_update_full(s->console);
+        qemu_console_update_full(s->console);
     }
     s->invalidate = false;
     s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
@@ -1964,7 +1964,7 @@ static void exynos4210_fimd_realize(DeviceState *dev, Error **errp)
         return;
     }
 
-    s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s);
+    s->console = qemu_graphic_console_create(dev, 0, &exynos4210_fimd_ops, s);
 }
 
 static void exynos4210_fimd_class_init(ObjectClass *klass, const void *data)
hw/display/g364fb.c +5 -5
index bd15f6f0acc..af54f1f9005 100644
@@ -191,8 +191,8 @@ static void g364fb_draw_graphic8(G364State *s)
         } else {
             int dy;
             if (xmax || ymax) {
-                dpy_gfx_update(s->con, xmin, ymin,
-                               xmax - xmin + 1, ymax - ymin + 1);
+                qemu_console_update(s->con, xmin, ymin,
+                                   xmax - xmin + 1, ymax - ymin + 1);
                 xmin = s->width;
                 xmax = 0;
                 ymin = s->height;
@@ -211,7 +211,7 @@ static void g364fb_draw_graphic8(G364State *s)
 
 done:
     if (xmax || ymax) {
-        dpy_gfx_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
+        qemu_console_update(s->con, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1);
     }
     g_free(snap);
 }
@@ -234,7 +234,7 @@ static void g364fb_draw_blank(G364State *s)
         d += surface_stride(surface);
     }
 
-    dpy_gfx_update_full(s->con);
+    qemu_console_update_full(s->con);
     s->blanked = 1;
 }
 
@@ -478,7 +478,7 @@ static const GraphicHwOps g364fb_ops = {
 
 static void g364fb_init(DeviceState *dev, G364State *s)
 {
-    s->con = graphic_console_init(dev, 0, &g364fb_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &g364fb_ops, s);
 
     memory_region_init_io(&s->mem_ctrl, OBJECT(dev), &g364fb_ctrl_ops, s,
                           "ctrl", 0x180000);
hw/display/imx6ul_lcdif.c +7 -7
index afcd0805ca4..7b5be2b5a75 100644
@@ -203,7 +203,7 @@ static bool imx6ul_lcdif_update_display(void *opaque)
                                src_width, surface_stride(surface), 0,
                                s->invalidate, fn, s, &first, &last);
     if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, width, last - first + 1);
+        qemu_console_update(s->con, 0, first, width, last - first + 1);
     }
 
     s->invalidate = false;
@@ -301,7 +301,7 @@ static void imx6ul_lcdif_write(void *opaque, hwaddr offset,
         if (!FIELD_EX32(oldv, CTRL, RUN) &&
             FIELD_EX32(s->regs[idx], CTRL, RUN)) {
             s->invalidate = true;
-            graphic_hw_invalidate(s->con);
+            qemu_console_hw_invalidate(s->con);
             imx6ul_lcdif_maybe_schedule_frame(s);
             break;
         }
@@ -318,17 +318,17 @@ static void imx6ul_lcdif_write(void *opaque, hwaddr offset,
         break;
     case A_V4_TRANSFER_COUNT:
         s->invalidate = true;
-        graphic_hw_invalidate(s->con);
+        qemu_console_hw_invalidate(s->con);
         break;
     case A_V4_CUR_BUF:
         s->invalidate = true;
-        graphic_hw_invalidate(s->con);
+        qemu_console_hw_invalidate(s->con);
         break;
     case A_V4_NEXT_BUF:
         s->regs[IMX6UL_LCDIF_REG_V4_CUR_BUF] = s->regs[idx];
         imx6ul_lcdif_frame_done(s);
         s->invalidate = true;
-        graphic_hw_invalidate(s->con);
+        qemu_console_hw_invalidate(s->con);
         imx6ul_lcdif_maybe_schedule_frame(s);
         return;
     case A_AS_NEXT_BUF:
@@ -411,7 +411,7 @@ static void imx6ul_lcdif_realize(DeviceState *dev, Error **errp)
                           TYPE_IMX6UL_LCDIF, LCDIF_MMIO_SIZE);
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
     sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
-    s->con = graphic_console_init(dev, 0, &imx6ul_lcdif_graphic_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &imx6ul_lcdif_graphic_ops, s);
 }
 
 static void imx6ul_lcdif_unrealize(DeviceState *dev)
@@ -423,7 +423,7 @@ static void imx6ul_lcdif_unrealize(DeviceState *dev)
     s->frame_timer = NULL;
 
     if (s->con) {
-        graphic_console_close(s->con);
+        qemu_graphic_console_close(s->con);
         s->con = NULL;
     }
 }
hw/display/jazz_led.c +4 -4
index ee9758a94b5..84fe1058406 100644
@@ -217,7 +217,7 @@ static bool jazz_led_update_display(void *opaque)
     }
 
     s->state = REDRAW_NONE;
-    dpy_gfx_update_full(s->con);
+    qemu_console_update_full(s->con);
 
     return true;
 }
@@ -233,7 +233,7 @@ static void jazz_led_text_update(void *opaque, uint32_t *chardata)
     LedState *s = opaque;
     char buf[3];
 
-    dpy_text_cursor(s->con, -1, -1);
+    qemu_console_text_set_cursor(s->con, -1, -1);
     qemu_console_resize(s->con, 2, 1);
 
     /* TODO: draw the segments */
@@ -243,7 +243,7 @@ static void jazz_led_text_update(void *opaque, uint32_t *chardata)
     *chardata++ = ATTR2CHTYPE(buf[1], QEMU_COLOR_BLUE,
                               QEMU_COLOR_BLACK, 1);
 
-    dpy_text_update(s->con, 0, 0, 2, 1);
+    qemu_console_text_update(s->con, 0, 0, 2, 1);
 }
 
 static int jazz_led_post_load(void *opaque, int version_id)
@@ -284,7 +284,7 @@ static void jazz_led_realize(DeviceState *dev, Error **errp)
 {
     LedState *s = JAZZ_LED(dev);
 
-    s->con = graphic_console_init(dev, 0, &jazz_led_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &jazz_led_ops, s);
 }
 
 static void jazz_led_reset(DeviceState *d)
hw/display/macfb.c +3 -3
index 848c3c282bd..f40a7ed9f52 100644
@@ -320,14 +320,14 @@ static void macfb_draw_graphic(MacfbState *s)
             }
         } else {
             if (ymin >= 0) {
-                dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
+                qemu_console_update(s->con, 0, ymin, s->width, y - ymin);
                 ymin = -1;
             }
         }
     }
 
     if (ymin >= 0) {
-        dpy_gfx_update(s->con, 0, ymin, s->width, y - ymin);
+        qemu_console_update(s->con, 0, ymin, s->width, y - ymin);
     }
 
     g_free(snap);
@@ -671,7 +671,7 @@ static bool macfb_common_realize(DeviceState *dev, MacfbState *s, Error **errp)
     s->regs[DAFB_MODE_CTRL1 >> 2] = s->mode->mode_ctrl1;
     s->regs[DAFB_MODE_CTRL2 >> 2] = s->mode->mode_ctrl2;
 
-    s->con = graphic_console_init(dev, 0, &macfb_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &macfb_ops, s);
     surface = qemu_console_surface(s->con);
 
     if (surface_bits_per_pixel(surface) != 32) {
hw/display/next-fb.c +2 -2
index e758b223ef7..fa2e0d0da80 100644
@@ -89,7 +89,7 @@ static bool nextfb_update(void *opaque)
                                src_width, dest_width, 0, 1, nextfb_draw_line,
                                s, &first, &last);
 
-    dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
+    qemu_console_update(s->con, 0, 0, s->cols, s->rows);
 
     return true;
 }
@@ -117,7 +117,7 @@ static void nextfb_realize(DeviceState *dev, Error **errp)
     s->cols = 1120;
     s->rows = 832;
 
-    s->con = graphic_console_init(dev, 0, &nextfb_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &nextfb_ops, s);
     qemu_console_resize(s->con, s->cols, s->rows);
 }
 
hw/display/omap_lcdc.c +2 -2
index 1e8385ebffb..2a8d5ffdd57 100644
@@ -320,7 +320,7 @@ static bool omap_update_display(void *opaque)
                                &first, &last);
 
     if (first >= 0) {
-        dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
+        qemu_console_update(omap_lcd->con, 0, first, width, last - first + 1);
     }
     omap_lcd->invalidate = 0;
 
@@ -504,7 +504,7 @@ struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem,
     memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100);
     memory_region_add_subregion(sysmem, base, &s->iomem);
 
-    s->con = graphic_console_init(NULL, 0, &omap_ops, s);
+    s->con = qemu_graphic_console_create(NULL, 0, &omap_ops, s);
 
     return s;
 }
hw/display/pl110.c +2 -2
index e134ac28eb6..4a93cf4cda9 100644
@@ -303,7 +303,7 @@ static bool pl110_update_display(void *opaque)
                                &first, &last);
 
     if (first >= 0) {
-        dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
+        qemu_console_update(s->con, 0, first, s->cols, last - first + 1);
     }
     s->invalidate = 0;
     return true;
@@ -557,7 +557,7 @@ static void pl110_realize(DeviceState *dev, Error **errp)
     s->vblank_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
                                    pl110_vblank_interrupt, s);
     qdev_init_gpio_in(dev, pl110_mux_ctrl_set, 1);
-    s->con = graphic_console_init(dev, 0, &pl110_gfx_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &pl110_gfx_ops, s);
 }
 
 static void pl110_init(Object *obj)
hw/display/qxl-render.c +6 -6
index 5b4f8842011..7b692d5a854 100644
@@ -135,7 +135,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
                 (width,
                  height);
         }
-        dpy_gfx_replace_surface(vga->con, surface);
+        qemu_console_set_surface(vga->con, surface);
     }
 
     if (!qxl->guest_primary.data) {
@@ -154,16 +154,16 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
             continue;
         }
         qxl_blit(qxl, qxl->dirty+i);
-        dpy_gfx_update(vga->con,
-                       qxl->dirty[i].left, qxl->dirty[i].top,
-                       qxl->dirty[i].right - qxl->dirty[i].left,
-                       qxl->dirty[i].bottom - qxl->dirty[i].top);
+        qemu_console_update(vga->con,
+                            qxl->dirty[i].left, qxl->dirty[i].top,
+                            qxl->dirty[i].right - qxl->dirty[i].left,
+                            qxl->dirty[i].bottom - qxl->dirty[i].top);
     }
     qxl->num_dirty_rects = 0;
 
 end:
     if (qxl->render_update_cookie_num == 0) {
-        graphic_hw_update_done(qxl->ssd.dcl.con);
+        qemu_console_hw_update_done(qxl->ssd.dcl.con);
     }
 }
 
hw/display/qxl.c +7 -7
index 4244ebe51d2..74258afa582 100644
@@ -1153,13 +1153,13 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d)
     }
     trace_qxl_enter_vga_mode(d->id);
     spice_qxl_driver_unload(&d->ssd.qxl);
-    graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
-    update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
+    qemu_graphic_console_set_hwops(d->ssd.dcl.con, d->vga.hw_ops, &d->vga);
+    qemu_console_listener_set_refresh(&d->ssd.dcl, GUI_REFRESH_INTERVAL_DEFAULT);
     qemu_spice_create_host_primary(&d->ssd);
     d->mode = QXL_MODE_VGA;
     qemu_spice_display_switch(&d->ssd, d->ssd.ds);
     vga_dirty_log_start(&d->vga);
-    graphic_hw_update(d->vga.con);
+    qemu_console_hw_update(d->vga.con);
 }
 
 static void qxl_exit_vga_mode(PCIQXLDevice *d)
@@ -1168,8 +1168,8 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d)
         return;
     }
     trace_qxl_exit_vga_mode(d->id);
-    graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
-    update_displaychangelistener(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
+    qemu_graphic_console_set_hwops(d->ssd.dcl.con, &qxl_ops, d);
+    qemu_console_listener_set_refresh(&d->ssd.dcl, GUI_REFRESH_INTERVAL_IDLE);
     vga_dirty_log_stop(&d->vga);
     qxl_destroy_primary(d, QXL_SYNC);
 }
@@ -2237,7 +2237,7 @@ static void qxl_realize_primary(PCIDevice *dev, Error **errp)
     portio_list_add(&qxl->vga_port_list, pci_address_space_io(dev), 0x3b0);
     qxl->have_vga = true;
 
-    vga->con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
+    vga->con = qemu_graphic_console_create(DEVICE(dev), 0, &qxl_ops, qxl);
     qxl->id = qemu_console_get_index(vga->con); /* == channel_id */
     if (qxl->id != 0) {
         error_setg(errp, "primary qxl-vga device must be console 0 "
@@ -2262,7 +2262,7 @@ static void qxl_realize_secondary(PCIDevice *dev, Error **errp)
     memory_region_init_ram(&qxl->vga.vram, OBJECT(dev), "qxl.vgavram",
                            qxl->vga.vram_size, &error_fatal);
     qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram);
-    qxl->vga.con = graphic_console_init(DEVICE(dev), 0, &qxl_ops, qxl);
+    qxl->vga.con = qemu_graphic_console_create(DEVICE(dev), 0, &qxl_ops, qxl);
     qxl->ssd.dcl.con = qxl->vga.con;
     qxl->id = qemu_console_get_index(qxl->vga.con); /* == channel_id */
 
hw/display/ramfb-standalone.c +1 -1
index 27f0ba19f90..8e8ba37514a 100644
@@ -41,7 +41,7 @@ static void ramfb_realizefn(DeviceState *dev, Error **errp)
 {
     RAMFBStandaloneState *ramfb = RAMFB(dev);
 
-    ramfb->con = graphic_console_init(dev, 0, &wrapper_ops, dev);
+    ramfb->con = qemu_graphic_console_create(dev, 0, &wrapper_ops, dev);
     ramfb->state = ramfb_setup(ramfb->use_legacy_x86_rom, errp);
 }
 
hw/display/ramfb.c +2 -2
index 50c25706a52..7a88f934e11 100644
@@ -111,12 +111,12 @@ void ramfb_display_update(QemuConsole *con, RAMFBState *s)
     }
 
     if (s->ds) {
-        dpy_gfx_replace_surface(con, s->ds);
+        qemu_console_set_surface(con, s->ds);
         s->ds = NULL;
     }
 
     /* simple full screen update */
-    dpy_gfx_update_full(con);
+    qemu_console_update_full(con);
 }
 
 static int ramfb_post_load(void *opaque, int version_id)
hw/display/sm501.c +3 -3
index a3993ceba29..af870048372 100644
@@ -1822,7 +1822,7 @@ static bool sm501_update_display(void *opaque)
         } else {
             if (y_start >= 0) {
                 /* flush to display */
-                dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+                qemu_console_update(s->con, 0, y_start, width, y - y_start);
                 y_start = -1;
             }
         }
@@ -1831,7 +1831,7 @@ static bool sm501_update_display(void *opaque)
 
     /* complete flush to display */
     if (y_start >= 0) {
-        dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
+        qemu_console_update(s->con, 0, y_start, width, y - y_start);
     }
 
     return true;
@@ -1936,7 +1936,7 @@ static void sm501_init(SM501State *s, DeviceState *dev,
                                 &s->twoD_engine_region);
 
     /* create qemu graphic console */
-    s->con = graphic_console_init(dev, 0, &sm501_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &sm501_ops, s);
 }
 
 static const VMStateDescription vmstate_sm501_state = {
hw/display/ssd0303.c +2 -2
index 229856cc427..4e3dede33f1 100644
@@ -268,7 +268,7 @@ static bool ssd0303_update_display(void *opaque)
         }
     }
     s->redraw = 0;
-    dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
+    qemu_console_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
 
     return true;
 }
@@ -309,7 +309,7 @@ static void ssd0303_realize(DeviceState *dev, Error **errp)
 {
     ssd0303_state *s = SSD0303(dev);
 
-    s->con = graphic_console_init(dev, 0, &ssd0303_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &ssd0303_ops, s);
     qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY);
 }
 
hw/display/ssd0323.c +3 -2
index 67db16086c8..9309d4d10c4 100644
@@ -270,7 +270,8 @@ static bool ssd0323_update_display(void *opaque)
         }
     }
     s->redraw = 0;
-    dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
+    qemu_console_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
+
     return true;
 }
 
@@ -356,7 +357,7 @@ static void ssd0323_realize(SSIPeripheral *d, Error **errp)
 
     s->col_end = 63;
     s->row_end = 79;
-    s->con = graphic_console_init(dev, 0, &ssd0323_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &ssd0323_ops, s);
     qemu_console_resize(s->con, 128 * MAGNIFY, 64 * MAGNIFY);
 
     qdev_init_gpio_in(dev, ssd0323_cd, 1);
hw/display/tcx.c +6 -10
index cedbf5c7acd..2c33a9c4a32 100644
@@ -243,8 +243,7 @@ static bool tcx_update_display(void *opaque)
         } else {
             if (y_start >= 0) {
                 /* flush to display */
-                dpy_gfx_update(ts->con, 0, y_start,
-                               ts->width, y - y_start);
+                qemu_console_update(ts->con, 0, y_start, ts->width, y - y_start);
                 y_start = -1;
             }
         }
@@ -253,8 +252,7 @@ static bool tcx_update_display(void *opaque)
     }
     if (y_start >= 0) {
         /* flush to display */
-        dpy_gfx_update(ts->con, 0, y_start,
-                       ts->width, y - y_start);
+        qemu_console_update(ts->con, 0, y_start, ts->width, y - y_start);
     }
     g_free(snap);
     return true;
@@ -297,8 +295,7 @@ static bool tcx24_update_display(void *opaque)
         } else {
             if (y_start >= 0) {
                 /* flush to display */
-                dpy_gfx_update(ts->con, 0, y_start,
-                               ts->width, y - y_start);
+                qemu_console_update(ts->con, 0, y_start, ts->width, y - y_start);
                 y_start = -1;
             }
         }
@@ -309,8 +306,7 @@ static bool tcx24_update_display(void *opaque)
     }
     if (y_start >= 0) {
         /* flush to display */
-        dpy_gfx_update(ts->con, 0, y_start,
-                       ts->width, y - y_start);
+        qemu_console_update(ts->con, 0, y_start, ts->width, y - y_start);
     }
     g_free(snap);
     return true;
@@ -864,9 +860,9 @@ static void tcx_realize(DeviceState *dev, Error **errp)
     sysbus_init_irq(sbd, &s->irq);
 
     if (s->depth == 8) {
-        s->con = graphic_console_init(dev, 0, &tcx_ops, s);
+        s->con = qemu_graphic_console_create(dev, 0, &tcx_ops, s);
     } else {
-        s->con = graphic_console_init(dev, 0, &tcx24_ops, s);
+        s->con = qemu_graphic_console_create(dev, 0, &tcx24_ops, s);
     }
     s->thcmisc = 0;
 
hw/display/vga-isa.c +1 -1
index 5f55c884a1b..2cccb0ef12e 100644
@@ -79,7 +79,7 @@ static void vga_isa_realizefn(DeviceState *dev, Error **errp)
                                         0x000a0000,
                                         vga_io_memory, 1);
     memory_region_set_coalescing(vga_io_memory);
-    s->con = graphic_console_init(dev, 0, s->hw_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, s->hw_ops, s);
 
     memory_region_add_subregion(isa_address_space(isadev),
                                 VBE_DISPI_LFB_PHYSICAL_ADDRESS,
hw/display/vga-mmio.c +1 -1
index 1a9608d865f..3cd64951c09 100644
@@ -108,7 +108,7 @@ static void vga_mmio_realizefn(DeviceState *dev, Error **errp)
     }
 
     sysbus_init_mmio(sbd, &s->vga.vram);
-    s->vga.con = graphic_console_init(dev, 0, s->vga.hw_ops, &s->vga);
+    s->vga.con = qemu_graphic_console_create(dev, 0, s->vga.hw_ops, &s->vga);
 }
 
 static const Property vga_mmio_properties[] = {
hw/display/vga-pci.c +3 -3
index 4e68dd57a17..d089847bdae 100644
@@ -247,7 +247,7 @@ static void pci_std_vga_realize(PCIDevice *dev, Error **errp)
     vga_init(s, OBJECT(dev), pci_address_space(dev), pci_address_space_io(dev),
              true);
 
-    s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
+    s->con = qemu_graphic_console_create(DEVICE(dev), 0, s->hw_ops, s);
 
     /* XXX: VGA_RAM_SIZE must be a power of two */
     pci_register_bar(&d->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->vram);
@@ -282,7 +282,7 @@ static void pci_secondary_vga_realize(PCIDevice *dev, Error **errp)
     if (!vga_common_init(s, OBJECT(dev), errp)) {
         return;
     }
-    s->con = graphic_console_init(DEVICE(dev), 0, s->hw_ops, s);
+    s->con = qemu_graphic_console_create(DEVICE(dev), 0, s->hw_ops, s);
 
     /* mmio bar */
     memory_region_init_io(&d->mmio, OBJECT(dev), &unassigned_io_ops, NULL,
@@ -306,7 +306,7 @@ static void pci_secondary_vga_exit(PCIDevice *dev)
     PCIVGAState *d = PCI_VGA(dev);
     VGACommonState *s = &d->vga;
 
-    graphic_console_close(s->con);
+    qemu_graphic_console_close(s->con);
     memory_region_del_subregion(&d->mmio, &d->mrs[0]);
     memory_region_del_subregion(&d->mmio, &d->mrs[1]);
     if (d->flags & (1 << PCI_VGA_FLAG_ENABLE_QEXT)) {
hw/display/vga.c +19 -21
index 2f266f47a39..0ac4bf37310 100644
@@ -1246,7 +1246,7 @@ static void vga_draw_text(VGACommonState *s, int full_update)
         s->last_scr_height = height * cheight;
         qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
         surface = qemu_console_surface(s->con);
-        dpy_text_resize(s->con, width, height);
+        qemu_console_text_resize(s->con, width, height);
         s->last_depth = 0;
         s->last_width = width;
         s->last_height = height;
@@ -1365,8 +1365,8 @@ static void vga_draw_text(VGACommonState *s, int full_update)
             ch_attr_ptr++;
         }
         if (cx_max != -1) {
-            dpy_gfx_update(s->con, cx_min * cw, cy * cheight,
-                           (cx_max - cx_min + 1) * cw, cheight);
+            qemu_console_update(s->con, cx_min * cw, cy * cheight,
+                                (cx_max - cx_min + 1) * cw, cheight);
         }
         dest += linesize * cheight;
         line1 = line + cheight;
@@ -1610,7 +1610,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
      */
     format = qemu_default_pixman_format(depth, !byteswap);
     if (format) {
-        allocate_surface = !dpy_gfx_check_format(s->con, format)
+        allocate_surface = !qemu_console_check_format(s->con, format)
             || s->force_shadow || force_shadow;
     } else {
         allocate_surface = true;
@@ -1647,7 +1647,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
             surface = qemu_create_displaysurface_from(disp_width,
                     height, format, s->params.line_offset,
                     s->vram_ptr + (s->params.start_addr * 4));
-            dpy_gfx_replace_surface(s->con, surface);
+            qemu_console_set_surface(s->con, surface);
         } else {
             qemu_console_resize(s->con, disp_width, height);
             surface = qemu_console_surface(s->con);
@@ -1720,8 +1720,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
         } else {
             if (y_start >= 0) {
                 /* flush to display */
-                dpy_gfx_update(s->con, 0, y_start,
-                               disp_width, y - y_start);
+                qemu_console_update(s->con, 0, y_start, disp_width, y - y_start);
                 y_start = -1;
             }
         }
@@ -1745,8 +1744,7 @@ static void vga_draw_graphic(VGACommonState *s, int full_update)
     }
     if (y_start >= 0) {
         /* flush to display */
-        dpy_gfx_update(s->con, 0, y_start,
-                       disp_width, y - y_start);
+        qemu_console_update(s->con, 0, y_start, disp_width, y - y_start);
     }
     g_free(snap);
     memset(s->invalidated_y_table, 0, sizeof(s->invalidated_y_table));
@@ -1767,7 +1765,7 @@ static void vga_draw_blank(VGACommonState *s, int full_update)
         /* unshare buffer, otherwise the blanking corrupts vga vram */
         surface = qemu_create_displaysurface(s->last_scr_width,
                                              s->last_scr_height);
-        dpy_gfx_replace_surface(s->con, surface);
+        qemu_console_set_surface(s->con, surface);
     }
 
     w = s->last_scr_width * surface_bytes_per_pixel(surface);
@@ -1776,7 +1774,7 @@ static void vga_draw_blank(VGACommonState *s, int full_update)
         memset(d, 0, w);
         d += surface_stride(surface);
     }
-    dpy_gfx_update_full(s->con);
+    qemu_console_update_full(s->con);
 }
 
 #define GMODE_TEXT     0
@@ -1967,7 +1965,7 @@ static void vga_update_text(void *opaque, uint32_t *chardata)
             s->last_scr_width = width * cw;
             s->last_scr_height = height * cheight;
             qemu_console_resize(s->con, s->last_scr_width, s->last_scr_height);
-            dpy_text_resize(s->con, width, height);
+            qemu_console_text_resize(s->con, width, height);
             s->last_depth = 0;
             s->last_width = width;
             s->last_height = height;
@@ -1992,11 +1990,11 @@ static void vga_update_text(void *opaque, uint32_t *chardata)
             s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
             cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
             if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
-                dpy_text_cursor(s->con,
-                                TEXTMODE_X(cursor_offset),
-                                TEXTMODE_Y(cursor_offset));
+                qemu_console_text_set_cursor(s->con,
+                                             TEXTMODE_X(cursor_offset),
+                                             TEXTMODE_Y(cursor_offset));
             else
-                dpy_text_cursor(s->con, -1, -1);
+                qemu_console_text_set_cursor(s->con, -1, -1);
             s->cursor_offset = cursor_offset;
             s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
             s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
@@ -2009,7 +2007,7 @@ static void vga_update_text(void *opaque, uint32_t *chardata)
             for (i = 0; i < size; src ++, dst ++, i ++)
                 *dst = VMEM2CHTYPE(le32_to_cpu(*src));
 
-            dpy_text_update(s->con, 0, 0, width, height);
+            qemu_console_text_update(s->con, 0, 0, width, height);
         } else {
             c_max = 0;
 
@@ -2032,7 +2030,7 @@ static void vga_update_text(void *opaque, uint32_t *chardata)
 
             if (c_min <= c_max) {
                 i = TEXTMODE_Y(c_min);
-                dpy_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
+                qemu_console_text_update(s->con, 0, i, width, TEXTMODE_Y(c_max) - i + 1);
             }
         }
 
@@ -2057,8 +2055,8 @@ static void vga_update_text(void *opaque, uint32_t *chardata)
     /* Display a message */
     s->last_width = 60;
     s->last_height = height = 3;
-    dpy_text_cursor(s->con, -1, -1);
-    dpy_text_resize(s->con, s->last_width, height);
+    qemu_console_text_set_cursor(s->con, -1, -1);
+    qemu_console_text_resize(s->con, s->last_width, height);
 
     for (dst = chardata, i = 0; i < s->last_width * height; i ++)
         *dst++ = ' ';
@@ -2070,7 +2068,7 @@ static void vga_update_text(void *opaque, uint32_t *chardata)
         *dst++ = ATTR2CHTYPE(msg_buffer[i], QEMU_COLOR_BLUE,
                              QEMU_COLOR_BLACK, 1);
 
-    dpy_text_update(s->con, 0, 0, s->last_width, height);
+    qemu_console_text_update(s->con, 0, 0, s->last_width, height);
 }
 
 static uint64_t vga_mem_read(void *opaque, hwaddr addr,
hw/display/vhost-user-gpu.c +11 -11
index 3f6fb7a8033..6e5e6540a46 100644
@@ -142,11 +142,11 @@ vhost_user_gpu_handle_cursor(VhostUserGPU *g, VhostUserGpuMsg *msg)
         memcpy(s->current_cursor->data, up->data,
                64 * 64 * sizeof(uint32_t));
 
-        dpy_cursor_define(s->con, s->current_cursor);
+        qemu_console_set_cursor(s->con, s->current_cursor);
     }
 
-    dpy_mouse_set(s->con, pos->x, pos->y,
-                  msg->request != VHOST_USER_GPU_CURSOR_POS_HIDE);
+    qemu_console_set_mouse(s->con, pos->x, pos->y,
+                           msg->request != VHOST_USER_GPU_CURSOR_POS_HIDE);
 }
 
 static void
@@ -238,7 +238,7 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
         con = s->con;
 
         if (m->width == 0) {
-            dpy_gfx_replace_surface(con, NULL);
+            qemu_console_set_surface(con, NULL);
         } else {
             s->ds = qemu_create_displaysurface(m->width, m->height);
             /* replace surface on next update */
@@ -269,12 +269,12 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
 
         if (dmabuf) {
             qemu_dmabuf_close(dmabuf);
-            dpy_gl_release_dmabuf(con, dmabuf);
+            qemu_console_gl_release_dmabuf(con, dmabuf);
             g_clear_pointer(&dmabuf, qemu_dmabuf_free);
         }
 
         if (fd == -1) {
-            dpy_gl_scanout_disable(con);
+            qemu_console_gl_scanout_disable(con);
             g->dmabuf[m->scanout_id] = NULL;
             break;
         }
@@ -291,7 +291,7 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
                                  &fd, 1, false, m->fd_flags &
                                  VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP);
 
-        dpy_gl_scanout_dmabuf(con, dmabuf);
+        qemu_console_gl_scanout_dmabuf(con, dmabuf);
         g->dmabuf[m->scanout_id] = dmabuf;
         break;
     }
@@ -306,13 +306,13 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
         }
 
         con = g->parent_obj.scanout[m->scanout_id].con;
-        if (!console_has_gl(con)) {
+        if (!qemu_console_has_gl(con)) {
             error_report("console doesn't support GL!");
             vhost_user_gpu_unblock(g);
             break;
         }
         g->backend_blocked = true;
-        dpy_gl_update(con, m->x, m->y, m->width, m->height);
+        qemu_console_gl_update(con, m->x, m->y, m->width, m->height);
         break;
     }
 #ifdef CONFIG_PIXMAN
@@ -337,9 +337,9 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
 
         pixman_image_unref(image);
         if (qemu_console_surface(con) != s->ds) {
-            dpy_gfx_replace_surface(con, s->ds);
+            qemu_console_set_surface(con, s->ds);
         } else {
-            dpy_gfx_update(con, m->x, m->y, m->width, m->height);
+            qemu_console_update(con, m->x, m->y, m->width, m->height);
         }
         break;
     }
hw/display/virtio-gpu-base.c +1 -1
index bdc24492850..a68b1848295 100644
@@ -253,7 +253,7 @@ virtio_gpu_base_device_realize(DeviceState *qdev,
     g->hw_ops = &virtio_gpu_ops;
     for (i = 0; i < g->conf.max_outputs; i++) {
         g->scanout[i].con =
-            graphic_console_init(DEVICE(g), i, &virtio_gpu_ops, g);
+            qemu_graphic_console_create(DEVICE(g), i, &virtio_gpu_ops, g);
     }
 
     return true;
hw/display/virtio-gpu-rutabaga.c +5 -5
index ebb6c783fb0..6ff12639012 100644
@@ -282,7 +282,7 @@ rutabaga_cmd_resource_flush(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
                                              rf.resource_id, &transfer,
                                              &transfer_iovec);
     CHECK(!result, cmd);
-    dpy_gfx_update_full(scanout->con);
+    qemu_console_update_full(scanout->con);
 }
 
 static void
@@ -306,8 +306,8 @@ rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
     scanout = &vb->scanout[ss.scanout_id];
 
     if (ss.resource_id == 0) {
-        dpy_gfx_replace_surface(scanout->con, NULL);
-        dpy_gl_scanout_disable(scanout->con);
+        qemu_console_set_surface(scanout->con, NULL);
+        qemu_console_gl_scanout_disable(scanout->con);
         return;
     }
 
@@ -331,8 +331,8 @@ rutabaga_cmd_set_scanout(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd)
 
     /* realloc the surface ptr */
     scanout->ds = qemu_create_displaysurface_pixman(res->image);
-    dpy_gfx_replace_surface(scanout->con, NULL);
-    dpy_gfx_replace_surface(scanout->con, scanout->ds);
+    qemu_console_set_surface(scanout->con, NULL);
+    qemu_console_set_surface(scanout->con, scanout->ds);
     res->scanout_bitmask = ss.scanout_id;
 }
 
hw/display/virtio-gpu-udmabuf.c +2 -2
index 74b6a7766af..d5ac1cfca0e 100644
@@ -156,7 +156,7 @@ static void virtio_gpu_free_dmabuf(VirtIOGPU *g, VGPUDMABuf *dmabuf)
     struct virtio_gpu_scanout *scanout;
 
     scanout = &g->parent_obj.scanout[dmabuf->scanout_id];
-    dpy_gl_release_dmabuf(scanout->con, dmabuf->buf);
+    qemu_console_gl_release_dmabuf(scanout->con, dmabuf->buf);
     g_clear_pointer(&dmabuf->buf, qemu_dmabuf_free);
     QTAILQ_REMOVE(&g->dmabuf.bufs, dmabuf, next);
     g_free(dmabuf);
@@ -232,7 +232,7 @@ int virtio_gpu_update_dmabuf(VirtIOGPU *g,
     height = qemu_dmabuf_get_height(new_primary->buf);
     g->dmabuf.primary[scanout_id] = new_primary;
     qemu_console_resize(scanout->con, width, height);
-    dpy_gl_scanout_dmabuf(scanout->con, new_primary->buf);
+    qemu_console_gl_scanout_dmabuf(scanout->con, new_primary->buf);
 
     if (old_primary) {
         virtio_gpu_free_dmabuf(g, old_primary);
hw/display/virtio-gpu-virgl.c +9 -11
index add85bd4e61..60c78af06a4 100644
@@ -521,7 +521,7 @@ static void virtio_gpu_rect_update(VirtIOGPU *g, int idx, int x, int y,
         return;
     }
 
-    dpy_gl_update(g->parent_obj.scanout[idx].con, x, y, width, height);
+    qemu_console_gl_update(g->parent_obj.scanout[idx].con, x, y, width, height);
 }
 
 static void virgl_cmd_resource_flush(VirtIOGPU *g,
@@ -584,16 +584,15 @@ static void virgl_cmd_set_scanout(VirtIOGPU *g,
         qemu_console_resize(g->parent_obj.scanout[ss.scanout_id].con,
                             ss.r.width, ss.r.height);
         virgl_renderer_force_ctx_0();
-        dpy_gl_scanout_texture(
+        qemu_console_gl_scanout_texture(
             g->parent_obj.scanout[ss.scanout_id].con, info.tex_id,
             info.flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP,
             info.width, info.height,
             ss.r.x, ss.r.y, ss.r.width, ss.r.height,
             d3d_tex2d);
     } else {
-        dpy_gfx_replace_surface(
-            g->parent_obj.scanout[ss.scanout_id].con, NULL);
-        dpy_gl_scanout_disable(g->parent_obj.scanout[ss.scanout_id].con);
+        qemu_console_set_surface(g->parent_obj.scanout[ss.scanout_id].con, NULL);
+        qemu_console_gl_scanout_disable(g->parent_obj.scanout[ss.scanout_id].con);
     }
     g->parent_obj.scanout[ss.scanout_id].resource_id = ss.resource_id;
 }
@@ -1315,7 +1314,7 @@ virgl_create_context(void *opaque, int scanout_idx,
     qparams.major_ver = params->major_ver;
     qparams.minor_ver = params->minor_ver;
 
-    ctx = dpy_gl_ctx_create(g->parent_obj.scanout[scanout_idx].con, &qparams);
+    ctx = qemu_console_gl_ctx_create(g->parent_obj.scanout[scanout_idx].con, &qparams);
     return (virgl_renderer_gl_context)ctx;
 }
 
@@ -1324,7 +1323,7 @@ static void virgl_destroy_context(void *opaque, virgl_renderer_gl_context ctx)
     VirtIOGPU *g = opaque;
     QEMUGLContext qctx = (QEMUGLContext)ctx;
 
-    dpy_gl_ctx_destroy(g->parent_obj.scanout[0].con, qctx);
+    qemu_console_gl_ctx_destroy(g->parent_obj.scanout[0].con, qctx);
 }
 
 static int virgl_make_context_current(void *opaque, int scanout_idx,
@@ -1333,8 +1332,7 @@ static int virgl_make_context_current(void *opaque, int scanout_idx,
     VirtIOGPU *g = opaque;
     QEMUGLContext qctx = (QEMUGLContext)ctx;
 
-    return dpy_gl_ctx_make_current(g->parent_obj.scanout[scanout_idx].con,
-                                   qctx);
+    return qemu_console_gl_ctx_make_current(g->parent_obj.scanout[scanout_idx].con, qctx);
 }
 
 static struct virgl_renderer_callbacks virtio_gpu_3d_cbs = {
@@ -1399,8 +1397,8 @@ void virtio_gpu_virgl_reset_scanout(VirtIOGPU *g)
     int i;
 
     for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
-        dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL);
-        dpy_gl_scanout_disable(g->parent_obj.scanout[i].con);
+        qemu_console_set_surface(g->parent_obj.scanout[i].con, NULL);
+        qemu_console_gl_scanout_disable(g->parent_obj.scanout[i].con);
     }
 }
 
hw/display/virtio-gpu.c +13 -13
index dbb72bbb22d..88526051a99 100644
@@ -103,14 +103,14 @@ static void update_cursor(VirtIOGPU *g, struct virtio_gpu_update_cursor *cursor)
         if (cursor->resource_id > 0) {
             vgc->update_cursor_data(g, s, cursor->resource_id);
         }
-        dpy_cursor_define(s->con, s->current_cursor);
+        qemu_console_set_cursor(s->con, s->current_cursor);
 
         s->cursor = *cursor;
     } else {
         s->cursor.pos.x = cursor->pos.x;
         s->cursor.pos.y = cursor->pos.y;
     }
-    dpy_mouse_set(s->con, cursor->pos.x, cursor->pos.y, cursor->resource_id);
+    qemu_console_set_mouse(s->con, cursor->pos.x, cursor->pos.y, cursor->resource_id);
 }
 
 struct virtio_gpu_simple_resource *
@@ -390,7 +390,7 @@ void virtio_gpu_disable_scanout(VirtIOGPU *g, int scanout_id)
         res->scanout_bitmask &= ~(1 << scanout_id);
     }
 
-    dpy_gfx_replace_surface(scanout->con, NULL);
+    qemu_console_set_surface(scanout->con, NULL);
     scanout->resource_id = 0;
     scanout->ds = NULL;
     scanout->width = 0;
@@ -531,8 +531,8 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
                 rf.r.y + rf.r.height >= scanout->y) {
                 within_bounds = true;
 
-                if (console_has_gl(scanout->con)) {
-                    dpy_gl_update(scanout->con, 0, 0, scanout->width,
+                if (qemu_console_has_gl(scanout->con)) {
+                    qemu_console_gl_update(scanout->con, 0, 0, scanout->width,
                                   scanout->height);
                     update_submitted = true;
                 }
@@ -582,8 +582,8 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
         /* work out the area we need to update for each console */
         if (qemu_rect_intersect(&flush_rect, &rect, &rect)) {
             qemu_rect_translate(&rect, -scanout->x, -scanout->y);
-            dpy_gfx_update(g->parent_obj.scanout[i].con,
-                           rect.x, rect.y, rect.width, rect.height);
+            qemu_console_update(g->parent_obj.scanout[i].con,
+                                rect.x, rect.y, rect.width, rect.height);
         }
     }
 }
@@ -649,7 +649,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
     g->parent_obj.enable = 1;
 
     if (res->blob) {
-        if (console_has_gl(scanout->con)) {
+        if (qemu_console_has_gl(scanout->con)) {
             if (!virtio_gpu_update_dmabuf(g, scanout_id, res, fb, r)) {
                 virtio_gpu_update_scanout(g, scanout_id, res, fb, r);
             } else {
@@ -665,7 +665,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
     }
 
     /* create a surface for this scanout */
-    if ((res->blob && !console_has_gl(scanout->con)) ||
+    if ((res->blob && !qemu_console_has_gl(scanout->con)) ||
         !scanout->ds ||
         surface_data(scanout->ds) != data + fb->offset ||
         scanout->width != r->width ||
@@ -686,7 +686,7 @@ static bool virtio_gpu_do_set_scanout(VirtIOGPU *g,
         qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, fb->offset);
 
         pixman_image_unref(rect);
-        dpy_gfx_replace_surface(g->parent_obj.scanout[scanout_id].con,
+        qemu_console_set_surface(g->parent_obj.scanout[scanout_id].con,
                                 scanout->ds);
     }
 
@@ -1483,10 +1483,10 @@ static int virtio_gpu_post_load(void *opaque, int version_id)
             }
             scanout->ds = qemu_create_displaysurface_pixman(res->image);
             qemu_displaysurface_set_share_handle(scanout->ds, res->share_handle, 0);
-            dpy_gfx_replace_surface(scanout->con, scanout->ds);
+            qemu_console_set_surface(scanout->con, scanout->ds);
         }
 
-        dpy_gfx_update_full(scanout->con);
+        qemu_console_update_full(scanout->con);
         if (scanout->cursor.resource_id) {
             update_cursor(g, &scanout->cursor);
         }
@@ -1602,7 +1602,7 @@ static void virtio_gpu_reset_bh(void *opaque)
     }
 
     for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
-        dpy_gfx_replace_surface(g->parent_obj.scanout[i].con, NULL);
+        qemu_console_set_surface(g->parent_obj.scanout[i].con, NULL);
     }
 
     g->reset_finished = true;
hw/display/virtio-vga.c +1 -1
index efd4858f3d0..2ae649c91ae 100644
@@ -172,7 +172,7 @@ static void virtio_vga_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
                                  vvga->vga_mrs, true, false);
 
     vga->con = g->scanout[0].con;
-    graphic_console_set_hwops(vga->con, &virtio_vga_base_ops, vvga);
+    qemu_graphic_console_set_hwops(vga->con, &virtio_vga_base_ops, vvga);
 
     for (i = 0; i < g->conf.max_outputs; i++) {
         object_property_set_link(OBJECT(g->scanout[i].con), "device",
hw/display/vmware_vga.c +6 -6
index 11f13c98d7a..f6f9edfd1d9 100644
@@ -378,7 +378,7 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
     for (line = h; line > 0; line--, src += bypl, dst += bypl) {
         memcpy(dst, src, width);
     }
-    dpy_gfx_update(s->vga.con, x, y, w, h);
+    qemu_console_update(s->vga.con, x, y, w, h);
 }
 
 static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
@@ -554,7 +554,7 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
         qc = cursor_builtin_left_ptr();
     }
 
-    dpy_cursor_define(s->vga.con, qc);
+    qemu_console_set_cursor(s->vga.con, qc);
     cursor_unref(qc);
 }
 #endif
@@ -1082,7 +1082,7 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
         s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
 #ifdef HW_MOUSE_ACCEL
         if (value <= SVGA_CURSOR_ON_SHOW) {
-            dpy_mouse_set(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on);
+            qemu_console_set_mouse(s->vga.con, s->cursor.x, s->cursor.y, s->cursor.on);
         }
 #endif
         break;
@@ -1130,7 +1130,7 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s)
         surface = qemu_create_displaysurface_from(s->new_width, s->new_height,
                                                   format, stride,
                                                   s->vga.vram_ptr);
-        dpy_gfx_replace_surface(s->vga.con, surface);
+        qemu_console_set_surface(s->vga.con, surface);
         s->invalidated = 1;
     }
 }
@@ -1151,7 +1151,7 @@ static bool vmsvga_update_display(void *opaque)
 
     if (s->invalidated) {
         s->invalidated = 0;
-        dpy_gfx_update_full(s->vga.con);
+        qemu_console_update_full(s->vga.con);
     }
 
     return true;
@@ -1254,7 +1254,7 @@ static void vmsvga_init(DeviceState *dev, struct vmsvga_state_s *s,
     s->scratch_size = SVGA_SCRATCH_SIZE;
     s->scratch = g_malloc(s->scratch_size * 4);
 
-    s->vga.con = graphic_console_init(dev, 0, &vmsvga_ops, s);
+    s->vga.con = qemu_graphic_console_create(dev, 0, &vmsvga_ops, s);
 
     s->fifo_size = SVGA_FIFO_SIZE;
     memory_region_init_ram(&s->fifo_ram, NULL, "vmsvga.fifo", s->fifo_size,
hw/display/xenfb.c +3 -3
index 2e431e27be6..8e9953bda43 100644
@@ -657,7 +657,7 @@ static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
         xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
                       __func__, xenfb->depth, bpp);
 
-    dpy_gfx_update(xenfb->con, x, y, w, h);
+    qemu_console_update(xenfb->con, x, y, w, h);
 }
 
 #ifdef XENFB_TYPE_REFRESH_PERIOD
@@ -743,7 +743,7 @@ static bool xenfb_update(void *opaque)
             surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
             break;
         }
-        dpy_gfx_replace_surface(xenfb->con, surface);
+        qemu_console_set_surface(xenfb->con, surface);
         xen_pv_printf(&xenfb->c.xendev, 1,
                       "update: resizing: %dx%d @ %d bpp%s\n",
                       xenfb->width, xenfb->height, xenfb->depth,
@@ -903,7 +903,7 @@ static int fb_initialise(struct XenLegacyDevice *xendev)
     if (rc != 0)
         return rc;
 
-    fb->con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
+    fb->con = qemu_graphic_console_create(NULL, 0, &xenfb_ops, fb);
 
     if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
         fb->feature_update = 0;
hw/display/xlnx_dp.c +5 -5
index 50e6ef10984..2486d9e5825 100644
@@ -605,7 +605,7 @@ static void xlnx_dp_recreate_surface(XlnxDPState *s)
 
     if ((width != 0) && (height != 0)) {
         /*
-         * As dpy_gfx_replace_surface calls qemu_free_displaysurface on the
+         * As qemu_console_replace_surface calls qemu_free_displaysurface on the
          * surface we need to be careful and don't free the surface associated
          * to the console or double free will happen.
          */
@@ -631,10 +631,10 @@ static void xlnx_dp_recreate_surface(XlnxDPState *s)
                                                             height,
                                                             s->g_plane.format,
                                                             0, NULL);
-            dpy_gfx_replace_surface(s->console, s->bout_plane.surface);
+            qemu_console_set_surface(s->console, s->bout_plane.surface);
         } else {
             s->bout_plane.surface = NULL;
-            dpy_gfx_replace_surface(s->console, s->g_plane.surface);
+            qemu_console_set_surface(s->console, s->g_plane.surface);
         }
 
         xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL,
@@ -1287,7 +1287,7 @@ static bool xlnx_dp_update_display(void *opaque)
     /*
      * XXX: We might want to update only what changed.
      */
-    dpy_gfx_update_full(s->console);
+    qemu_console_update_full(s->console);
 
     return true;
 }
@@ -1387,7 +1387,7 @@ static void xlnx_dp_realize(DeviceState *dev, Error **errp)
     qdev_realize(DEVICE(s->edid), BUS(aux_get_i2c_bus(s->aux_bus)),
                  &error_fatal);
 
-    s->console = graphic_console_init(dev, 0, &xlnx_dp_gfx_ops, s);
+    s->console = qemu_graphic_console_create(dev, 0, &xlnx_dp_gfx_ops, s);
     surface = qemu_console_surface(s->console);
     xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL,
                                       surface_data(surface));
hw/vfio/display.c +16 -16
index 4a9a58036e3..8f91e83da88 100644
@@ -264,7 +264,7 @@ static void vfio_display_free_one_dmabuf(VFIODisplay *dpy, VFIODMABuf *dmabuf)
     QTAILQ_REMOVE(&dpy->dmabuf.bufs, dmabuf, next);
 
     qemu_dmabuf_close(dmabuf->buf);
-    dpy_gl_release_dmabuf(dpy->con, dmabuf->buf);
+    qemu_console_gl_release_dmabuf(dpy->con, dmabuf->buf);
     g_clear_pointer(&dmabuf->buf, qemu_dmabuf_free);
     g_free(dmabuf);
 }
@@ -307,7 +307,7 @@ static bool vfio_display_dmabuf_update(void *opaque)
     if (dpy->dmabuf.primary != primary) {
         dpy->dmabuf.primary = primary;
         qemu_console_resize(dpy->con, width, height);
-        dpy_gl_scanout_dmabuf(dpy->con, primary->buf);
+        qemu_console_gl_scanout_dmabuf(dpy->con, primary->buf);
         free_bufs = true;
     }
 
@@ -321,21 +321,21 @@ static bool vfio_display_dmabuf_update(void *opaque)
     if (cursor && (new_cursor || cursor->hot_updates)) {
         bool have_hot = (cursor->hot_x != 0xffffffff &&
                          cursor->hot_y != 0xffffffff);
-        dpy_gl_cursor_dmabuf(dpy->con, cursor->buf, have_hot,
-                             cursor->hot_x, cursor->hot_y);
+        qemu_console_gl_cursor_dmabuf(dpy->con, cursor->buf, have_hot,
+                                      cursor->hot_x, cursor->hot_y);
         cursor->hot_updates = 0;
     } else if (!cursor && new_cursor) {
-        dpy_gl_cursor_dmabuf(dpy->con, NULL, false, 0, 0);
+        qemu_console_gl_cursor_dmabuf(dpy->con, NULL, false, 0, 0);
     }
 
     if (cursor && cursor->pos_updates) {
-        dpy_gl_cursor_position(dpy->con,
+        qemu_console_gl_cursor_position(dpy->con,
                                cursor->pos_x,
                                cursor->pos_y);
         cursor->pos_updates = 0;
     }
 
-    dpy_gl_update(dpy->con, 0, 0, width, height);
+    qemu_console_gl_update(dpy->con, 0, 0, width, height);
 
     if (free_bufs) {
         vfio_display_free_dmabufs(vdev);
@@ -363,7 +363,7 @@ static bool vfio_display_dmabuf_init(VFIOPCIDevice *vdev, Error **errp)
     }
 
     vdev->dpy = g_new0(VFIODisplay, 1);
-    vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
+    vdev->dpy->con = qemu_graphic_console_create(DEVICE(vdev), 0,
                                           &vfio_display_dmabuf_ops,
                                           vdev);
     if (vdev->enable_ramfb) {
@@ -396,9 +396,9 @@ void vfio_display_reset(VFIOPCIDevice *vdev)
         return;
     }
 
-    dpy_gl_scanout_disable(vdev->dpy->con);
+    qemu_console_gl_scanout_disable(vdev->dpy->con);
     vfio_display_dmabuf_exit(vdev->dpy);
-    dpy_gfx_update_full(vdev->dpy->con);
+    qemu_console_update_full(vdev->dpy->con);
 }
 
 static bool vfio_display_region_update(void *opaque)
@@ -471,13 +471,13 @@ static bool vfio_display_region_update(void *opaque)
         dpy->region.surface = qemu_create_displaysurface_from
             (plane.width, plane.height, format,
              plane.stride, dpy->region.buffer.mmaps[0].mmap);
-        dpy_gfx_replace_surface(dpy->con, dpy->region.surface);
+        qemu_console_set_surface(dpy->con, dpy->region.surface);
     }
 
     /* full screen update */
-    dpy_gfx_update(dpy->con, 0, 0,
-                   surface_width(dpy->region.surface),
-                   surface_height(dpy->region.surface));
+    qemu_console_update(dpy->con, 0, 0,
+                        surface_width(dpy->region.surface),
+                        surface_height(dpy->region.surface));
     return true;
 
 err:
@@ -493,7 +493,7 @@ static const GraphicHwOps vfio_display_region_ops = {
 static bool vfio_display_region_init(VFIOPCIDevice *vdev, Error **errp)
 {
     vdev->dpy = g_new0(VFIODisplay, 1);
-    vdev->dpy->con = graphic_console_init(DEVICE(vdev), 0,
+    vdev->dpy->con = qemu_graphic_console_create(DEVICE(vdev), 0,
                                           &vfio_display_region_ops,
                                           vdev);
     if (vdev->enable_ramfb) {
@@ -553,7 +553,7 @@ void vfio_display_finalize(VFIOPCIDevice *vdev)
         return;
     }
 
-    graphic_console_close(vdev->dpy->con);
+    qemu_graphic_console_close(vdev->dpy->con);
     vfio_display_dmabuf_exit(vdev->dpy);
     vfio_display_region_exit(vdev->dpy);
     vfio_display_edid_exit(vdev->dpy);
ui/console-vc.c +6 -6
index 99ad6d079df..828e78c41ea 100644
@@ -90,15 +90,15 @@ static void text_console_update(void *opaque, uint32_t *chardata)
                                           s->vt.cells[src].t_attrib.bgcol,
                                           s->vt.cells[src].t_attrib.bold);
             }
-        dpy_text_update(QEMU_CONSOLE(s), s->vt.text_x[0], s->vt.text_y[0],
-                        s->vt.text_x[1] - s->vt.text_x[0], i - s->vt.text_y[0]);
+        qemu_console_text_update(QEMU_CONSOLE(s), s->vt.text_x[0], s->vt.text_y[0],
+                                 s->vt.text_x[1] - s->vt.text_x[0], i - s->vt.text_y[0]);
         s->vt.text_x[0] = s->vt.width;
         s->vt.text_y[0] = s->vt.height;
         s->vt.text_x[1] = 0;
         s->vt.text_y[1] = 0;
     }
     if (s->vt.cursor_invalidate) {
-        dpy_text_cursor(QEMU_CONSOLE(s), s->vt.x, s->vt.y);
+        qemu_console_text_set_cursor(QEMU_CONSOLE(s), s->vt.x, s->vt.y);
         s->vt.cursor_invalidate = 0;
     }
 }
@@ -186,14 +186,14 @@ static void vc_chr_set_echo(Chardev *chr, bool echo)
 
 void qemu_text_console_update_size(QemuTextConsole *c)
 {
-    dpy_text_resize(QEMU_CONSOLE(c), c->vt.width, c->vt.height);
+    qemu_console_text_resize(QEMU_CONSOLE(c), c->vt.width, c->vt.height);
 }
 
 static void text_console_image_update(QemuVT100 *vt, int x, int y, int width, int height)
 {
     QemuTextConsole *console = container_of(vt, QemuTextConsole, vt);
 
-    dpy_gfx_update(QEMU_CONSOLE(console), x, y, width, height);
+    qemu_console_update(QEMU_CONSOLE(console), x, y, width, height);
 }
 
 static void text_console_out_flush(QemuVT100 *vt)
@@ -232,7 +232,7 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
         s = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_FIXED_TEXT_CONSOLE));
     }
 
-    dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
+    qemu_console_set_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
     if (vc->has_encoding) {
         drv->encoding = vc->encoding;
     }
ui/console.c +70 -70

399 lines not on this page · raw message

ui/curses.c +4 -4
index dbb5992981c..24d3713e57d 100644
@@ -1,8 +1,8 @@
 /*
  * QEMU curses/ncurses display driver
- * 
+ *
  * Copyright (c) 2005 Andrzej Zaborowski  <[email protected]>
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -275,11 +275,11 @@ static void curses_refresh(DisplayChangeListener *dcl)
         clear();
         refresh();
         curses_calc_pad();
-        graphic_hw_invalidate(dcl->con);
+        qemu_console_hw_invalidate(dcl->con);
         invalidate = 0;
     }
 
-    graphic_hw_text_update(dcl->con, screen);
+    qemu_console_hw_text_update(dcl->con, screen);
 
     while (1) {
         /* while there are any pending key strokes to process */
ui/dbus-console.c +2 -2
index 23f547a673d..b8e5c57b148 100644
@@ -200,7 +200,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
         .height = arg_height,
     };
 
-    if (!dpy_ui_info_supported(ddc->dcl.con)) {
+    if (!qemu_console_ui_info_supported(ddc->dcl.con)) {
         g_dbus_method_invocation_return_error(invocation,
                                               DBUS_DISPLAY_ERROR,
                                               DBUS_DISPLAY_ERROR_UNSUPPORTED,
@@ -208,7 +208,7 @@ dbus_console_set_ui_info(DBusDisplayConsole *ddc,
         return DBUS_METHOD_INVOCATION_HANDLED;
     }
 
-    dpy_set_ui_info(ddc->dcl.con, &info, false);
+    qemu_console_set_ui_info(ddc->dcl.con, &info, false);
     qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation);
     return DBUS_METHOD_INVOCATION_HANDLED;
 }
ui/dbus-listener.c +5 -5
index cc2c969686e..2e2f6ba4183 100644
@@ -241,7 +241,7 @@ static void dbus_update_gl_cb(GObject *source_object,
     }
 #endif
 
-    graphic_hw_gl_block(ddl->dcl.con, false);
+    qemu_console_hw_gl_block(ddl->dcl.con, false);
     g_object_unref(ddl);
 }
 #endif
@@ -257,7 +257,7 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
 
     glFlush();
 #ifdef CONFIG_GBM
-    graphic_hw_gl_block(ddl->dcl.con, true);
+    qemu_console_hw_gl_block(ddl->dcl.con, true);
     qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy,
         x, y, w, h,
         G_DBUS_CALL_FLAGS_NONE,
@@ -276,7 +276,7 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
         Error *err = NULL;
         assert(ddl->d3d_texture);
 
-        graphic_hw_gl_block(ddl->dcl.con, true);
+        qemu_console_hw_gl_block(ddl->dcl.con, true);
         if (!d3d_texture2d_release0(ddl->d3d_texture, &err)) {
             error_report_err(err);
             return;
@@ -711,7 +711,7 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
 {
     DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
 
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 
     if (!ddl->ds || qemu_console_is_gl_blocked(ddl->dcl.con)) {
         return;
@@ -740,7 +740,7 @@ static void dbus_gl_refresh(DisplayChangeListener *dcl)
 
 static void dbus_refresh(DisplayChangeListener *dcl)
 {
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 }
 
 #ifdef CONFIG_OPENGL
ui/egl-headless.c +2 -2
index 4f046c975a9..878bfebb40c 100644
@@ -23,7 +23,7 @@ typedef struct egl_dpy {
 
 static void egl_refresh(DisplayChangeListener *dcl)
 {
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 }
 
 static void egl_gfx_update(DisplayChangeListener *dcl,
@@ -161,7 +161,7 @@ static void egl_scanout_flush(DisplayChangeListener *dcl,
     }
 
     egl_fb_read(edpy->ds, &edpy->blit_fb);
-    dpy_gfx_update(edpy->dcl.con, x, y, w, h);
+    qemu_console_update(edpy->dcl.con, x, y, w, h);
 }
 
 static const DisplayChangeListenerOps egl_ops = {
ui/gtk-egl.c +3 -3
index fa8fe8970c1..7c5c9b2428c 100644
@@ -108,7 +108,7 @@ void gd_egl_draw(VirtualConsole *vc)
                 qemu_set_fd_handler(fence_fd, gd_hw_gl_flushed, NULL, vc);
                 return;
             }
-            graphic_hw_gl_block(vc->gfx.dcl.con, false);
+            qemu_console_hw_gl_block(vc->gfx.dcl.con, false);
         }
 #endif
     } else {
@@ -176,7 +176,7 @@ void gd_egl_refresh(DisplayChangeListener *dcl)
         return;
     }
 
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 
     if (vc->gfx.glupdates) {
         vc->gfx.glupdates = 0;
@@ -405,7 +405,7 @@ void gd_egl_flush(DisplayChangeListener *dcl,
 
     if (vc->gfx.guest_fb.dmabuf &&
         !qemu_dmabuf_get_draw_submitted(vc->gfx.guest_fb.dmabuf)) {
-        graphic_hw_gl_block(vc->gfx.dcl.con, true);
+        qemu_console_hw_gl_block(vc->gfx.dcl.con, true);
         qemu_dmabuf_set_draw_submitted(vc->gfx.guest_fb.dmabuf, true);
         gtk_egl_set_scanout_mode(vc, true);
         gtk_widget_queue_draw_area(area, x, y, w, h);
ui/gtk-gl-area.c +3 -3
index ce49000d3f1..23806b9d01b 100644
@@ -131,7 +131,7 @@ void gd_gl_area_draw(VirtualConsole *vc)
                 qemu_set_fd_handler(fence_fd, gd_hw_gl_flushed, NULL, vc);
                 return;
             }
-            graphic_hw_gl_block(vc->gfx.dcl.con, false);
+            qemu_console_hw_gl_block(vc->gfx.dcl.con, false);
         }
 #endif
     } else {
@@ -195,7 +195,7 @@ void gd_gl_area_refresh(DisplayChangeListener *dcl)
         }
     }
 
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 
     if (vc->gfx.glupdates) {
         vc->gfx.glupdates = 0;
@@ -347,7 +347,7 @@ void gd_gl_area_scanout_flush(DisplayChangeListener *dcl,
 
     if (vc->gfx.guest_fb.dmabuf &&
         !qemu_dmabuf_get_draw_submitted(vc->gfx.guest_fb.dmabuf)) {
-        graphic_hw_gl_block(vc->gfx.dcl.con, true);
+        qemu_console_hw_gl_block(vc->gfx.dcl.con, true);
         qemu_dmabuf_set_draw_submitted(vc->gfx.guest_fb.dmabuf, true);
         gtk_gl_area_set_scanout_mode(vc, true);
     }
ui/gtk.c +9 -9
index ef3707b3634..2c61b601f78 100644
@@ -436,7 +436,7 @@ static void gd_update(DisplayChangeListener *dcl,
 
 static void gd_refresh(DisplayChangeListener *dcl)
 {
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 }
 
 static GdkDevice *gd_get_pointer(GdkDisplay *dpy)
@@ -602,7 +602,7 @@ void gd_hw_gl_flushed(void *vcon)
         qemu_set_fd_handler(fence_fd, NULL, NULL, NULL);
         close(fence_fd);
         qemu_dmabuf_set_fence_fd(dmabuf, -1);
-        graphic_hw_gl_block(vc->gfx.dcl.con, false);
+        qemu_console_hw_gl_block(vc->gfx.dcl.con, false);
     }
 }
 
@@ -729,27 +729,27 @@ static void gd_set_ui_refresh_rate(VirtualConsole *vc, int refresh_rate)
 {
     QemuUIInfo info;
 
-    if (!dpy_ui_info_supported(vc->gfx.dcl.con)) {
+    if (!qemu_console_ui_info_supported(vc->gfx.dcl.con)) {
         return;
     }
 
-    info = *dpy_get_ui_info(vc->gfx.dcl.con);
+    info = *qemu_console_get_ui_info(vc->gfx.dcl.con);
     info.refresh_rate = refresh_rate;
-    dpy_set_ui_info(vc->gfx.dcl.con, &info, true);
+    qemu_console_set_ui_info(vc->gfx.dcl.con, &info, true);
 }
 
 static void gd_set_ui_size(VirtualConsole *vc, gint width, gint height)
 {
     QemuUIInfo info;
 
-    if (!dpy_ui_info_supported(vc->gfx.dcl.con)) {
+    if (!qemu_console_ui_info_supported(vc->gfx.dcl.con)) {
         return;
     }
 
-    info = *dpy_get_ui_info(vc->gfx.dcl.con);
+    info = *qemu_console_get_ui_info(vc->gfx.dcl.con);
     info.width = width;
     info.height = height;
-    dpy_set_ui_info(vc->gfx.dcl.con, &info, true);
+    qemu_console_set_ui_info(vc->gfx.dcl.con, &info, true);
 }
 
 #if defined(CONFIG_OPENGL)
@@ -2333,7 +2333,7 @@ static GSList *gd_vc_gfx_init(GtkDisplayState *s, VirtualConsole *vc,
     gd_connect_vc_gfx_signals(vc);
     group = gd_vc_menu_init(s, vc, idx, group, view_menu);
 
-    if (dpy_ui_info_supported(vc->gfx.dcl.con)) {
+    if (qemu_console_ui_info_supported(vc->gfx.dcl.con)) {
         zoom_to_fit = true;
     }
     if (s->opts->u.gtk.has_zoom_to_fit) {
ui/sdl2-2d.c +1 -1
index 73052383c2e..68a3aff7151 100644
@@ -129,7 +129,7 @@ void sdl2_2d_refresh(DisplayChangeListener *dcl)
     struct sdl2_console *scon = container_of(dcl, struct sdl2_console, dcl);
 
     assert(!scon->opengl);
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
     sdl2_poll_events(scon);
 }
 
ui/sdl2-gl.c +1 -1
index bb066cdd885..1547ad2f6f8 100644
@@ -115,7 +115,7 @@ void sdl2_gl_refresh(DisplayChangeListener *dcl)
 
     assert(scon->opengl);
 
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
     if (scon->updates && scon->real_window) {
         scon->updates = 0;
         sdl2_gl_render_surface(scon);
ui/sdl2.c +3 -3
index 89516f95c41..4fcdbd79d3c 100644
@@ -604,7 +604,7 @@ static void handle_windowevent(SDL_Event *ev)
                 .width = ev->window.data1,
                 .height = ev->window.data2,
             };
-            dpy_set_ui_info(scon->dcl.con, &info, true);
+            qemu_console_set_ui_info(scon->dcl.con, &info, true);
         }
         sdl2_redraw(scon);
         break;
@@ -632,10 +632,10 @@ static void handle_windowevent(SDL_Event *ev)
         }
         break;
     case SDL_WINDOWEVENT_RESTORED:
-        update_displaychangelistener(&scon->dcl, GUI_REFRESH_INTERVAL_DEFAULT);
+        qemu_console_listener_set_refresh(&scon->dcl, GUI_REFRESH_INTERVAL_DEFAULT);
         break;
     case SDL_WINDOWEVENT_MINIMIZED:
-        update_displaychangelistener(&scon->dcl, 500);
+        qemu_console_listener_set_refresh(&scon->dcl, 500);
         break;
     case SDL_WINDOWEVENT_CLOSE:
         if (qemu_console_is_graphic(scon->dcl.con)) {
ui/spice-display.c +8 -8
index 56d8140fad8..e3716127203 100644
@@ -468,7 +468,7 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
         assert(ssd->dcl.con);
         cursor_ref(c);
         qemu_mutex_unlock(&ssd->lock);
-        dpy_cursor_define(ssd->dcl.con, c);
+        qemu_console_set_cursor(ssd->dcl.con, c);
         qemu_mutex_lock(&ssd->lock);
         cursor_unref(c);
     }
@@ -481,7 +481,7 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
         ssd->mouse_x = -1;
         ssd->mouse_y = -1;
         qemu_mutex_unlock(&ssd->lock);
-        dpy_mouse_set(ssd->dcl.con, x, y, true);
+        qemu_console_set_mouse(ssd->dcl.con, x, y, true);
     } else {
         qemu_mutex_unlock(&ssd->lock);
     }
@@ -489,7 +489,7 @@ void qemu_spice_cursor_refresh_bh(void *opaque)
 
 void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd)
 {
-    graphic_hw_update(ssd->dcl.con);
+    qemu_console_hw_update(ssd->dcl.con);
 
     WITH_QEMU_LOCK_GUARD(&ssd->lock) {
         if (QTAILQ_EMPTY(&ssd->updates) && ssd->ds) {
@@ -668,7 +668,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
     QemuUIInfo info;
     int head;
 
-    if (!dpy_ui_info_supported(ssd->dcl.con)) {
+    if (!qemu_console_ui_info_supported(ssd->dcl.con)) {
         return 0; /* == not supported by guest */
     }
 
@@ -676,7 +676,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
         return 1;
     }
 
-    info = *dpy_get_ui_info(ssd->dcl.con);
+    info = *qemu_console_get_ui_info(ssd->dcl.con);
 
     head = qemu_console_get_index(ssd->dcl.con);
     if (mc->num_of_monitors > head) {
@@ -690,7 +690,7 @@ static int interface_client_monitors_config(QXLInstance *sin,
     }
 
     trace_qemu_spice_ui_info(ssd->qxl.id, info.width, info.height);
-    dpy_set_ui_info(ssd->dcl.con, &info, false);
+    qemu_console_set_ui_info(ssd->dcl.con, &info, false);
     return 1;
 }
 
@@ -817,7 +817,7 @@ static void qemu_spice_gl_block(SimpleSpiceDisplay *ssd, bool block)
     } else {
         timer_del(ssd->gl_unblock_timer);
     }
-    graphic_hw_gl_block(ssd->dcl.con, block);
+    qemu_console_hw_gl_block(ssd->dcl.con, block);
 }
 
 static void qemu_spice_gl_unblock_bh(void *opaque)
@@ -861,7 +861,7 @@ static void spice_gl_refresh(DisplayChangeListener *dcl)
         return;
     }
 
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
     if (ssd->gl_updates && ssd->have_surface) {
         qemu_spice_gl_block(ssd, true);
         glFlush();
ui/vnc.c +11 -11
index e8c8773a36e..d3dfabede03 100644
@@ -2325,8 +2325,8 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
 
     set_pixel_conversion(vs);
 
-    graphic_hw_invalidate(vs->vd->dcl.con);
-    graphic_hw_update(vs->vd->dcl.con);
+    qemu_console_hw_invalidate(vs->vd->dcl.con);
+    qemu_console_hw_update(vs->vd->dcl.con);
 }
 
 static void pixel_format_message (VncState *vs) {
@@ -2384,7 +2384,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
     VncDisplay *vd = vs->vd;
 
     if (data[0] > 3) {
-        update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
+        qemu_console_listener_set_refresh(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
     }
 
     switch (data[0]) {
@@ -2638,9 +2638,9 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
         h = read_u16(data, 4);
 
         trace_vnc_msg_client_set_desktop_size(vs, vs->ioc, w, h, screens);
-        if (dpy_ui_info_supported(vs->vd->dcl.con)) {
+        if (qemu_console_ui_info_supported(vs->vd->dcl.con)) {
             QemuUIInfo info = { .width = w, .height = h };
-            dpy_set_ui_info(vs->vd->dcl.con, &info, false);
+            qemu_console_set_ui_info(vs->vd->dcl.con, &info, false);
             vnc_desktop_resize_ext(vs, 4 /* Request forwarded */);
         } else {
             vnc_desktop_resize_ext(vs, 3 /* Invalid screen layout */);
@@ -3242,14 +3242,14 @@ static void vnc_refresh(DisplayChangeListener *dcl)
     int has_dirty, rects = 0;
 
     if (QTAILQ_EMPTY(&vd->clients)) {
-        update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
+        qemu_console_listener_set_refresh(&vd->dcl, VNC_REFRESH_INTERVAL_MAX);
         return;
     }
 
-    graphic_hw_update(vd->dcl.con);
+    qemu_console_hw_update(vd->dcl.con);
 
     if (vnc_trylock_display(vd)) {
-        update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
+        qemu_console_listener_set_refresh(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
         return;
     }
 
@@ -3323,7 +3323,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
               sioc, websocket, vs->auth, vs->subauth);
 
     VNC_DEBUG("New client on socket %p\n", vs->sioc);
-    update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
+    qemu_console_listener_set_refresh(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
     qio_channel_set_blocking(vs->ioc, false, &error_abort);
     g_clear_handle_id(&vs->ioc_tag, g_source_remove);
     if (websocket) {
@@ -3363,7 +3363,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
         vnc_update_server_surface(vd);
     }
 
-    graphic_hw_update(vd->dcl.con);
+    qemu_console_hw_update(vd->dcl.con);
 
     if (!vs->websocket) {
         vnc_start_protocol(vs);
@@ -3419,7 +3419,7 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
     if (state != RUN_STATE_RUNNING) {
         return;
     }
-    update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
+    qemu_console_listener_set_refresh(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
 }
 
 static bool vnc_display_open(VncDisplay *vd, Error **errp);
hw/display/apple-gfx.m +8 -8
index 77d80fb7cef..be0061b9db2 100644
@@ -317,8 +317,8 @@ static void apple_gfx_render_frame_completed_bh(void *opaque)
             copy_mtl_texture_to_surface_mem(s->texture, surface_data(s->surface));
             if (s->gfx_update_requested) {
                 s->gfx_update_requested = false;
-                dpy_gfx_update_full(s->con);
-                graphic_hw_update_done(s->con);
+                qemu_console_update_full(s->con);
+                qemu_console_hw_update_done(s->con);
                 s->new_frame_ready = false;
             } else {
                 s->new_frame_ready = true;
@@ -337,7 +337,7 @@ static bool apple_gfx_fb_update_display(void *opaque)
 
     assert(bql_locked());
     if (s->new_frame_ready) {
-        dpy_gfx_update_full(s->con);
+        qemu_console_update_full(s->con);
         s->new_frame_ready = false;
     } else if (s->pending_frames > 0) {
         s->gfx_update_requested = true;
@@ -380,14 +380,14 @@ static void set_mode(AppleGFXState *s, uint32_t width, uint32_t height)
             (s->texture.storageMode == MTLStorageModeManaged);
     }
 
-    dpy_gfx_replace_surface(s->con, s->surface);
+    qemu_console_set_surface(s->con, s->surface);
 }
 
 static void update_cursor(AppleGFXState *s)
 {
     assert(bql_locked());
-    dpy_mouse_set(s->con, s->pgdisp.cursorPosition.x,
-                  s->pgdisp.cursorPosition.y, qatomic_read(&s->cursor_show));
+    qemu_console_set_mouse(s->con, s->pgdisp.cursorPosition.x,
+                           s->pgdisp.cursorPosition.y, qatomic_read(&s->cursor_show));
 }
 
 static void update_cursor_bh(void *opaque)
@@ -443,7 +443,7 @@ static void set_cursor_glyph(void *opaque)
             }
             px_data += padding_bytes_per_row;
         }
-        dpy_cursor_define(s->con, s->cursor);
+        qemu_console_set_cursor(s->con, s->cursor);
         update_cursor(s);
     }
     [glyph release];
@@ -792,7 +792,7 @@ bool apple_gfx_common_realize(AppleGFXState *s, DeviceState *dev,
         apple_gfx_create_display_mode_array(display_modes, num_display_modes);
     [mode_array release];
 
-    s->con = graphic_console_init(dev, 0, &apple_gfx_fb_ops, s);
+    s->con = qemu_graphic_console_create(dev, 0, &apple_gfx_fb_ops, s);
     return true;
 }
 
ui/cocoa.m +5 -5
index aaf82421589..98394cdc507 100644
@@ -421,7 +421,7 @@ - (void) selectConsoleLocked:(unsigned int)index
         return;
     }
 
-    unregister_displaychangelistener(&dcl);
+    qemu_console_unregister_listener(&dcl);
     qkbd_state_switch_console(kbd, con);
     qemu_console_register_listener(con, &dcl, &dcl_ops);
     [self notifyMouseModeChange];
@@ -669,8 +669,8 @@ - (void) updateUIInfoLocked
             CVTime period = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(displayLink);
             CVDisplayLinkRelease(displayLink);
             if (!(period.flags & kCVTimeIsIndefinite)) {
-                update_displaychangelistener(&dcl,
-                                             1000 * period.timeValue / period.timeScale);
+                qemu_console_listener_set_refresh(&dcl,
+                                                  1000 * period.timeValue / period.timeScale);
                 info.refresh_rate = (int64_t)1000 * period.timeScale / period.timeValue;
             }
         }
@@ -688,7 +688,7 @@ - (void) updateUIInfoLocked
     info.width = frameSize.width * [[self window] backingScaleFactor];
     info.height = frameSize.height * [[self window] backingScaleFactor];
 
-    dpy_set_ui_info(dcl.con, &info, TRUE);
+    qemu_console_set_ui_info(dcl.con, &info, TRUE);
 }
 
 #pragma clang diagnostic pop
@@ -2056,7 +2056,7 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
 
     COCOA_DEBUG("qemu_cocoa: cocoa_refresh\n");
-    graphic_hw_update(dcl->con);
+    qemu_console_hw_update(dcl->con);
 
     if (cbchangecount != [[NSPasteboard generalPasteboard] changeCount]) {
         qemu_clipboard_info_unref(cbinfo);
Signature · 1 line
2.54.0
#23 lore raw

[PULL v2 19/33] ui/console-vc: move VT100 emulation into separate unit

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Move the VT100 terminal emulation code into dedicated ui/vt100.c and ui/vt100.h files, completing the extraction from console-vc.c started in the previous patches. This makes the VT100 layer a self-contained module that can be reused independently of the chardev/console infrastructure.

The code is moved as-is, with minor coding style fixes (adding missing braces, fixing whitespace) applied during the move.

---
 ui/console-priv.h     |    1 -
 ui/vt100.h            |   95 ++++
 ui/console-vc-stubs.c |    1 +
 ui/console-vc.c       | 1033 +----------------------------------------
 ui/console.c          |    2 +
 ui/vt100.c            |  984 +++++++++++++++++++++++++++++++++++++++
 ui/meson.build        |    4 +-
 7 files changed, 1086 insertions(+), 1034 deletions(-)
 create mode 100644 ui/vt100.h
 create mode 100644 ui/vt100.c
ui/console-priv.h +0 -1
index 2299898984d..4f731b4f9ce 100644
@@ -30,7 +30,6 @@ struct QemuConsole {
 };
 
 void qemu_text_console_update_size(QemuTextConsole *c);
-void vt100_update_cursor(void);
 void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym);
 
 #endif
ui/vt100.h new file +95 -0

95 lines not on this page · raw message

ui/console-vc-stubs.c +1 -0
index d911a82f263..30e4d101197 100644
@@ -9,6 +9,7 @@
 #include "qemu/option.h"
 #include "chardev/char.h"
 #include "ui/console-priv.h"
+#include "vt100.h"
 
 void qemu_text_console_update_size(QemuTextConsole *c)
 {
ui/console-vc.c +1 -1032

1,095 lines not on this page · raw message

ui/console.c +2 -0
index 1c75b1a355b..b837ce1c9fc 100644
@@ -39,6 +39,8 @@
 #include "system/memory.h"
 #include "qom/object.h"
 #include "qemu/memfd.h"
+#include "ui/vt100.h"
+#include "vgafont.h"
 
 #include "console-priv.h"
 
ui/vt100.c new file +984 -0

984 lines not on this page · raw message

ui/meson.build +3 -1
index d69eebfdaf1..7b6e867d3af 100644
@@ -3,6 +3,7 @@ system_ss.add(png)
 system_ss.add(files(
   'clipboard.c',
   'console.c',
+  'cp437.c',
   'cursor.c',
   'display-surface.c',
   'dmabuf.c',
@@ -17,8 +18,9 @@ system_ss.add(files(
   'ui-qmp-cmds.c',
   'util.c',
   'vgafont.c',
+  'vt100.c',
 ))
-system_ss.add(when: pixman, if_true: files('console-vc.c', 'cp437.c'), if_false: files('console-vc-stubs.c'))
+system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c'))
 if dbus_display
   system_ss.add(files('dbus-module.c'))
 endif
Signature · 1 line
2.54.0
#24 lore raw

[PULL v2 06/33] ui/input: do not assert() when tracing invalid input

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

It's possible to reach an assert() in the input tracing code by sending some out of range input values via D-Bus for ex:

  #0  0x00007fec8652186c in __pthread_kill_implementation () at /lib64/libc.so.6
  #1  0x00007fec864c648e in raise () at /lib64/libc.so.6
  #2  0x00007fec864ad7b3 in abort () at /lib64/libc.so.6
  #3  0x00007fec864ae804 in __libc_message_impl.cold () at /lib64/libc.so.6
  #4  0x00007fec864be345 in __assert_fail () at /lib64/libc.so.6
  #5  0x00005597964c551e in qapi_enum_lookup[cold] ()
  #6  0x000055979650514a in qemu_input_event_send_impl ()
  #7  0x0000559796505a4d in qemu_input_queue_btn ()
  #8  0x00007fec85780c19 in dbus_mouse_press () at /usr/bin/../lib64/qemu/ui-dbus.so
  #9  0x00007fec857912fc in _g_dbus_codegen_marshal_BOOLEAN__OBJECT_UINT.part.0 () at /usr/bin/../lib64/qemu/ui-dbus.so

#10 0x00007fec874cce7c in g_closure_invoke () at /lib64/libgobject-2.0.so.0
#11 0x00007fec874eb849 in signal_emit_unlocked_R.isra.0 () at /lib64/libgobject-2.0.so.0
#12 0x00007fec874ec66f in g_signal_emitv () at /lib64/libgobject-2.0.so.0
#13 0x00007fec85797e0a in _qemu_dbus_display1_mouse_skeleton_handle_method_call () at /usr/bin/../lib64/qemu/ui-dbus.so

Other paths in input code accept out-of-range values (qemu_input_key_value_to_number etc). Let it pass tracing.

---
 ui/input.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
ui/input.c +4 -4
index 57e7817878a..966023d4f4d 100644
@@ -207,22 +207,22 @@ static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
         break;
     case INPUT_EVENT_KIND_BTN:
         btn = evt->u.btn.data;
-        name = InputButton_str(btn->button);
+        name = btn->button < INPUT_BUTTON__MAX ? InputButton_str(btn->button) : "invalid";
         trace_input_event_btn(idx, name, btn->down);
         break;
     case INPUT_EVENT_KIND_REL:
         move = evt->u.rel.data;
-        name = InputAxis_str(move->axis);
+        name = move->axis < INPUT_AXIS__MAX ? InputAxis_str(move->axis) : "invalid";
         trace_input_event_rel(idx, name, move->value);
         break;
     case INPUT_EVENT_KIND_ABS:
         move = evt->u.abs.data;
-        name = InputAxis_str(move->axis);
+        name = move->axis < INPUT_AXIS__MAX ? InputAxis_str(move->axis) : "invalid";
         trace_input_event_abs(idx, name, move->value);
         break;
     case INPUT_EVENT_KIND_MTT:
         mtt = evt->u.mtt.data;
-        name = InputAxis_str(mtt->axis);
+        name = mtt->axis < INPUT_AXIS__MAX ? InputAxis_str(mtt->axis) : "invalid";
         trace_input_event_mtt(idx, name, mtt->value);
         break;
     case INPUT_EVENT_KIND__MAX:
Signature · 1 line
2.54.0
#25 lore raw

[PULL v2 27/33] ui/console: add doc comment for qemu_console_{un}register_listener()

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

---
 ui/console.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
ui/console.c +20 -0
index 4f3b4394268..22ca1c35db3 100644
@@ -572,6 +572,17 @@ dcl_set_graphic_cursor(DisplayChangeListener *dcl, QemuGraphicConsole *con)
     }
 }
 
+/*
+ * qemu_console_register_listener:
+ * @con: the console to attach the listener to
+ * @dcl: the display change listener to register
+ * @ops: the listener operations (callbacks for display updates)
+ *
+ * Register a display change listener on a console. The listener
+ * must not already be registered (i.e. @dcl->ds must be NULL).
+ * This sets up the listener, adds it to the display state, triggers
+ * an initial display update, and setup the cursor.
+ */
 void qemu_console_register_listener(QemuConsole *con,
                                     DisplayChangeListener *dcl,
                                     const DisplayChangeListenerOps *ops)
@@ -605,6 +616,15 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
     }
 }
 
+/*
+ * qemu_console_unregister_listener:
+ * @dcl: the display change listener to unregister
+ *
+ * Unregister a display change listener, removing it from the
+ * display state's listener list. If the listener is not currently
+ * registered (@dcl->ds is NULL), this is a no-op. After unregistering,
+ * the display refresh timer is recalculated.
+ */
 void qemu_console_unregister_listener(DisplayChangeListener *dcl)
 {
     DisplayState *ds = dcl->ds;
Signature · 1 line
2.54.0
#26 lore raw

[PULL v2 10/33] ui/console: add vc encoding=utf8/cp437 option

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Expose a new "encoding" QemuOpt option.

Add the corresponding QAPI type and properties.

This is going to be wired in the following commits.

---
 qapi/char.json         | 30 ++++++++++++++++++++++++++++--
 include/chardev/char.h |  1 +
 chardev/char.c         | 10 ++++++++++
 ui/console-vc.c        | 12 ++++++++++++
 ui/dbus.c              | 13 +++++++++++++
 qemu-options.hx        |  7 +++++--
 6 files changed, 69 insertions(+), 4 deletions(-)
qapi/char.json +28 -2
index a4abafa6803..aa5ee9ffcd0 100644
@@ -377,6 +377,24 @@
   'base': 'ChardevCommon',
   'if': 'CONFIG_SPICE' }
 
+##
+# @ChardevVCEncoding:
+#
+# Character encoding expected from the guest on a virtual console.
+#
+# @cp437: CP437 (8-bit Extended ASCII / VGA).  Every byte maps
+#     directly to a glyph; suitable for DOS or other guests that
+#     output raw CP437.
+#
+# @utf8: UTF-8.  Multi-byte sequences are decoded and then mapped
+#     back to CP437 glyphs for display; unmappable codepoints are
+#     shown as '?'.  Suitable for modern Linux guests.
+#
+# Since: 11.1
+##
+{ 'enum': 'ChardevVCEncoding',
+  'data': [ 'cp437', 'utf8' ] }
+
 ##
 # @ChardevDBus:
 #
@@ -384,10 +402,14 @@
 #
 # @name: name of the channel (following docs/spice-port-fqdn.txt)
 #
+# @encoding: character encoding the guest is expected to use
+#     (since 11.1)
+#
 # Since: 7.0
 ##
 { 'struct': 'ChardevDBus',
-  'data': { 'name': 'str' },
+  'data': { 'name': 'str',
+            '*encoding': 'ChardevVCEncoding' },
   'base': 'ChardevCommon',
   'if': 'CONFIG_DBUS_DISPLAY' }
 
@@ -404,6 +426,9 @@
 #
 # @rows: console height, in chars
 #
+# @encoding: character encoding the guest is expected to use
+#     (since 11.1)
+#
 # .. note:: The options are only effective when the VNC or SDL
 #    graphical display backend is active.  They are ignored with the
 #    GTK, Spice, VNC and D-Bus display backends.
@@ -414,7 +439,8 @@
   'data': { '*width': 'int',
             '*height': 'int',
             '*cols': 'int',
-            '*rows': 'int' },
+            '*rows': 'int',
+            '*encoding': 'ChardevVCEncoding' },
   'base': 'ChardevCommon' }
 
 ##
include/chardev/char.h +1 -0
index 51995f06a82..f05e8dba0a9 100644
@@ -255,6 +255,7 @@ struct ChardevClass {
     bool internal; /* TODO: eventually use TYPE_USER_CREATABLE */
     bool supports_yank;
     bool supports_size_opts;
+    bool supports_encoding_opts;
 
     /* parse command line options and populate QAPI @backend */
     void (*chr_parse)(QemuOpts *opts, ChardevBackend *backend, Error **errp);
chardev/char.c +10 -0
index 55dce9725e8..ca8b37ed8d7 100644
@@ -650,6 +650,13 @@ ChardevBackend *qemu_chr_parse_opts(QemuOpts *opts, Error **errp)
             return NULL;
         }
     }
+    if (!cc->supports_encoding_opts) {
+        if (qemu_opt_get(opts, "encoding")) {
+            error_setg(errp, "chardev '%s' does not support encoding option",
+                       qemu_opts_id(opts));
+            return NULL;
+        }
+    }
 
     backend = g_new0(ChardevBackend, 1);
     backend->type = CHARDEV_BACKEND_KIND_NULL;
@@ -972,6 +979,9 @@ QemuOptsList qemu_chardev_opts = {
         },{
             .name = "rows",
             .type = QEMU_OPT_NUMBER,
+        },{
+            .name = "encoding",
+            .type = QEMU_OPT_STRING,
         },{
             .name = "mux",
             .type = QEMU_OPT_BOOL,
ui/console-vc.c +12 -0
index 62a5e3caf57..7bb6a483753 100644
@@ -1211,6 +1211,7 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
 static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
 {
     int val;
+    const char *str;
     ChardevVC *vc;
 
     backend->type = CHARDEV_BACKEND_KIND_VC;
@@ -1240,6 +1241,16 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp)
         vc->has_rows = true;
         vc->rows = val;
     }
+
+    str = qemu_opt_get(opts, "encoding");
+    if (str) {
+        int cs = qapi_enum_parse(&ChardevVCEncoding_lookup, str, -1, errp);
+        if (cs < 0) {
+            return;
+        }
+        vc->has_encoding = true;
+        vc->encoding = cs;
+    }
 }
 
 static void char_vc_class_init(ObjectClass *oc, const void *data)
@@ -1252,6 +1263,7 @@ static void char_vc_class_init(ObjectClass *oc, const void *data)
     cc->chr_accept_input = vc_chr_accept_input;
     cc->chr_set_echo = vc_chr_set_echo;
     cc->supports_size_opts = true;
+    cc->supports_encoding_opts = true;
 }
 
 static const TypeInfo char_vc_type_info = {
ui/dbus.c +13 -0
index 794b65c4ada..721cc71d39b 100644
@@ -471,6 +471,8 @@ dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend,
     DBusVCClass *klass = DBUS_VC_CLASS(object_class_by_name(TYPE_CHARDEV_VC));
     const char *name = qemu_opt_get(opts, "name");
     const char *id = qemu_opts_id(opts);
+    const char *str;
+    ChardevDBus *dbus;
 
     if (name == NULL) {
         if (g_str_has_prefix(id, "compat_monitor")) {
@@ -486,6 +488,16 @@ dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend,
     }
 
     klass->parent_parse(opts, backend, errp);
+    dbus = backend->u.dbus.data;
+    str = qemu_opt_get(opts, "encoding");
+    if (str) {
+        int cs = qapi_enum_parse(&ChardevVCEncoding_lookup, str, -1, errp);
+        if (cs < 0) {
+            return;
+        }
+        dbus->has_encoding = true;
+        dbus->encoding = cs;
+    }
 }
 
 static void
@@ -496,6 +508,7 @@ dbus_vc_class_init(ObjectClass *oc, const void *data)
 
     klass->parent_parse = cc->chr_parse;
     cc->chr_parse = dbus_vc_parse;
+    cc->supports_encoding_opts = true;
 }
 
 static const TypeInfo dbus_vc_type_info = {
qemu-options.hx +5 -2
index e7842b10c8c..5387bcd751b 100644
@@ -4053,7 +4053,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
     "         [,logfile=PATH][,logappend=on|off]\n"
     "-chardev msmouse,id=id[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
     "-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]\n"
-    "         [,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
+    "         [,mux=on|off][,logfile=PATH][,logappend=on|off][,encoding=ENCODING]\n"
     "-chardev ringbuf,id=id[,size=size][,logfile=PATH][,logappend=on|off]\n"
     "-chardev file,id=id,path=path[,input-path=input-file][,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
     "-chardev pipe,id=id,path=path[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
@@ -4285,7 +4285,7 @@ The available backends are:
     Several frontend devices is not supported. Stacking of multiplexers
     and hub devices is not supported as well.
 
-``-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]]``
+``-chardev vc,id=id[[,width=width][,height=height]][[,cols=cols][,rows=rows]][,encoding=ENCODING]``
     Connect to a QEMU text console. The implementation and supported feature
     set depend on the selected display backend.
 
@@ -4304,6 +4304,9 @@ The available backends are:
     ``cols`` and ``rows`` specify that the console be sized to fit a
     text console with the given dimensions.
 
+    ``encoding`` specifies the character set expected from the guest:
+    ``utf8`` or ``cp437`` (8-bit Extended ASCII / VGA).
+
 ``-chardev ringbuf,id=id[,size=size]``
     Create a ring buffer with fixed size ``size``. size must be a power
     of two and defaults to ``64K``.
Signature · 1 line
2.54.0
#27 lore raw

[PULL v2 32/33] tools/qemu-vnc: add standalone VNC server over D-Bus

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Add a standalone VNC server binary that connects to a running QEMU instance via the D-Bus display interface (org.qemu.Display1, via the bus or directly p2p). This allows serving a VNC display without compiling VNC support directly into the QEMU system emulator, and enables running the VNC server as a separate process with independent lifecycle and privilege domain.

Built only when both VNC and D-Bus display support are enabled. If we wanted to have qemu -vnc disabled, and qemu-vnc built, we would need to split CONFIG_VNC. This is left as a future exercise.

Current omissions include some QEMU VNC runtime features (better handled via restart), legacy options, and Windows support.

---
 MAINTAINERS                   |    5 +
 docs/conf.py                  |    3 +
 docs/interop/dbus-display.rst |    2 +
 docs/interop/dbus-vnc.rst     |   26 +
 docs/interop/index.rst        |    1 +
 docs/meson.build              |    1 +
 docs/tools/index.rst          |    1 +
 docs/tools/qemu-vnc.rst       |  226 ++++++
 meson.build                   |   17 +
 tools/qemu-vnc/qemu-vnc.h     |   49 ++
 tools/qemu-vnc/trace.h        |    4 +
 tests/qtest/dbus-vnc-test.c   | 1346 +++++++++++++++++++++++++++++++++
 tools/qemu-vnc/audio.c        |  308 ++++++++
 tools/qemu-vnc/chardev.c      |  148 ++++
 tools/qemu-vnc/clipboard.c    |  376 +++++++++
 tools/qemu-vnc/console.c      |  170 +++++
 tools/qemu-vnc/dbus.c         |  474 ++++++++++++
 tools/qemu-vnc/display.c      |  456 +++++++++++
 tools/qemu-vnc/input.c        |  239 ++++++
 tools/qemu-vnc/qemu-vnc.c     |  581 ++++++++++++++
 tools/qemu-vnc/stubs.c        |   62 ++
 tools/qemu-vnc/utils.c        |   59 ++
 meson_options.txt             |    2 +
 scripts/meson-buildoptions.sh |    3 +
 tests/dbus-daemon.sh          |   14 +-
 tests/qtest/meson.build       |   13 +
 tools/qemu-vnc/meson.build    |   26 +
 tools/qemu-vnc/qemu-vnc1.xml  |  201 +++++
 tools/qemu-vnc/trace-events   |   21 +
 29 files changed, 4831 insertions(+), 3 deletions(-)
 create mode 100644 docs/interop/dbus-vnc.rst
 create mode 100644 docs/tools/qemu-vnc.rst
 create mode 100644 tools/qemu-vnc/qemu-vnc.h
 create mode 100644 tools/qemu-vnc/trace.h
 create mode 100644 tests/qtest/dbus-vnc-test.c
 create mode 100644 tools/qemu-vnc/audio.c
 create mode 100644 tools/qemu-vnc/chardev.c
 create mode 100644 tools/qemu-vnc/clipboard.c
 create mode 100644 tools/qemu-vnc/console.c
 create mode 100644 tools/qemu-vnc/dbus.c
 create mode 100644 tools/qemu-vnc/display.c
 create mode 100644 tools/qemu-vnc/input.c
 create mode 100644 tools/qemu-vnc/qemu-vnc.c
 create mode 100644 tools/qemu-vnc/stubs.c
 create mode 100644 tools/qemu-vnc/utils.c
 create mode 100644 tools/qemu-vnc/meson.build
 create mode 100644 tools/qemu-vnc/qemu-vnc1.xml
 create mode 100644 tools/qemu-vnc/trace-events
MAINTAINERS +5 -0
index 9d3d6459537..93a1e4e4822 100644
@@ -2830,6 +2830,11 @@ F: docs/interop/vhost-user-gpu.rst
 F: contrib/vhost-user-gpu
 F: hw/display/vhost-user-*
 
+qemu-vnc:
+M: Marc-André Lureau <[email protected]>
+S: Maintained
+F: tools/qemu-vnc
+
 Cirrus VGA
 M: Gerd Hoffmann <[email protected]>
 S: Odd Fixes
docs/conf.py +3 -0
index f835904ba1e..7e35d2158d3 100644
@@ -333,6 +333,9 @@
     ('tools/qemu-trace-stap', 'qemu-trace-stap',
      'QEMU SystemTap trace tool',
      [], 1),
+    ('tools/qemu-vnc', 'qemu-vnc',
+     'QEMU standalone VNC server',
+     [], 1),
 ]
 man_make_section_directory = False
 
docs/interop/dbus-display.rst +2 -0
index 8c6e8e0f5a8..87648e91dc0 100644
@@ -1,3 +1,5 @@
+.. _dbus-display:
+
 D-Bus display
 =============
 
docs/interop/dbus-vnc.rst new file +26 -0
new file mode 100644
index 00000000000..d2b77978f63
@@ -0,0 +1,26 @@
+D-Bus VNC
+=========
+
+The ``qemu-vnc`` standalone VNC server exposes a D-Bus interface for management
+and monitoring of VNC connections.
+
+The service is available on the bus under the well-known name ``org.qemu.vnc``.
+Objects are exported under ``/org/qemu/Vnc1/``.
+
+.. contents::
+   :local:
+   :depth: 1
+
+.. only:: sphinx4
+
+   .. dbus-doc:: tools/qemu-vnc/qemu-vnc1.xml
+
+.. only:: not sphinx4
+
+   .. warning::
+      Sphinx 4 is required to build D-Bus documentation.
+
+      This is the content of ``tools/qemu-vnc/qemu-vnc1.xml``:
+
+   .. literalinclude:: ../../tools/qemu-vnc/qemu-vnc1.xml
+      :language: xml
docs/interop/index.rst +1 -0
index d830c5c4104..2cf3a8c9aa3 100644
@@ -13,6 +13,7 @@ are useful for making QEMU interoperate with other software.
    dbus
    dbus-vmstate
    dbus-display
+   dbus-vnc
    live-block-operations
    nbd
    parallels
docs/meson.build +1 -0
index 7e54b01e6a0..c3e9fb05846 100644
@@ -54,6 +54,7 @@ if build_docs
         'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
         'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
         'qemu-trace-stap.1': (stap.found() ? 'man1' : ''),
+        'qemu-vnc.1': (have_qemu_vnc ? 'man1' : ''),
         'qemu.1': 'man1',
         'qemu-block-drivers.7': 'man7',
         'qemu-cpu-models.7': 'man7'
docs/tools/index.rst +1 -0
index 1e88ae48cdc..868c3c4d9d8 100644
@@ -16,3 +16,4 @@ command line utilities and other standalone programs.
    qemu-pr-helper
    qemu-trace-stap
    qemu-vmsr-helper
+   qemu-vnc
docs/tools/qemu-vnc.rst new file +226 -0

226 lines not on this page · raw message

meson.build +17 -0
index 5fbdc75a0fc..d4bbe90e1f8 100644
@@ -2338,6 +2338,17 @@ dbus_display = get_option('dbus_display') \
            error_message: gdbus_codegen_error.format('-display dbus')) \
   .allowed()
 
+have_qemu_vnc = get_option('qemu_vnc') \
+  .require(have_tools,
+           error_message: 'qemu-vnc requires tools support') \
+  .require(dbus_display,
+           error_message: 'qemu-vnc requires dbus-display support') \
+  .require(vnc.found(),
+           error_message: 'qemu-vnc requires vnc support') \
+  .require(host_os != 'windows',
+           error_message: 'qemu-vnc is not currently supported on Windows') \
+  .allowed()
+
 have_virtfs = get_option('virtfs') \
     .require(host_os == 'linux' or host_os == 'darwin' or host_os == 'freebsd',
              error_message: 'virtio-9p (virtfs) requires Linux or macOS or FreeBSD') \
@@ -3591,6 +3602,7 @@ trace_events_subdirs = [
   'monitor',
   'util',
   'gdbstub',
+  'tools/qemu-vnc',
 ]
 if have_linux_user
   trace_events_subdirs += [ 'linux-user' ]
@@ -4580,6 +4592,10 @@ if have_tools
     subdir('contrib/ivshmem-client')
     subdir('contrib/ivshmem-server')
   endif
+
+  if have_qemu_vnc
+    subdir('tools/qemu-vnc')
+  endif
 endif
 
 if stap.found()
@@ -4915,6 +4931,7 @@ if vnc.found()
   summary_info += {'VNC SASL support':  sasl}
   summary_info += {'VNC JPEG support':  jpeg}
 endif
+summary_info += {'VNC D-Bus server (qemu-vnc)': have_qemu_vnc}
 summary_info += {'spice protocol support': spice_protocol}
 if spice_protocol.found()
   summary_info += {'  spice server support': spice}
tools/qemu-vnc/qemu-vnc.h new file +49 -0

49 lines not on this page · raw message

tools/qemu-vnc/trace.h new file +4 -0
new file mode 100644
index 00000000000..5fb7b432359
@@ -0,0 +1,4 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "trace/trace-tools_qemu_vnc.h"
tests/qtest/dbus-vnc-test.c new file +1346 -0

1,346 lines not on this page · raw message

tools/qemu-vnc/audio.c new file +308 -0

308 lines not on this page · raw message

tools/qemu-vnc/chardev.c new file +148 -0

148 lines not on this page · raw message

tools/qemu-vnc/clipboard.c new file +376 -0

376 lines not on this page · raw message

tools/qemu-vnc/console.c new file +170 -0

170 lines not on this page · raw message

tools/qemu-vnc/dbus.c new file +474 -0

263 lines not on this page · raw message

tools/qemu-vnc/display.c new file +456 -0

456 lines not on this page · raw message

tools/qemu-vnc/input.c new file +239 -0

239 lines not on this page · raw message

tools/qemu-vnc/qemu-vnc.c new file +581 -0

581 lines not on this page · raw message

tools/qemu-vnc/stubs.c new file +62 -0

62 lines not on this page · raw message

tools/qemu-vnc/utils.c new file +59 -0

59 lines not on this page · raw message

meson_options.txt +2 -0
index 286461129bd..ae17a3d8830 100644

Lines of this file are not shown. View the raw message.

scripts/meson-buildoptions.sh +3 -0
index 80de8c4af42..23c960b2482 100644

Lines of this file are not shown. View the raw message.

tests/dbus-daemon.sh +11 -3
index c4a50c73774..85f9597db43 100755

Lines of this file are not shown. View the raw message.

tests/qtest/meson.build +13 -0
index 0067f767eea..728dde54b3f 100644

Lines of this file are not shown. View the raw message.

tools/qemu-vnc/meson.build new file +26 -0
new file mode 100644
index 00000000000..08168da0630

Lines of this file are not shown. View the raw message.

tools/qemu-vnc/qemu-vnc1.xml new file +201 -0

201 lines not on this page · raw message

tools/qemu-vnc/trace-events new file +21 -0
new file mode 100644
index 00000000000..e3b550de10e

Lines of this file are not shown. View the raw message.

The rest of this diff is not shown. View the raw message.

Signature · 1 line
2.54.0

Part of the diff is not shown here. View the raw message.

#28 lore raw

[PULL v2 30/33] ui: extract common sources into a static library

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Move clipboard, cursor, display-surface, input-keymap, kbd-state, keymaps, vt100, and qemu-pixman into a separate static library 'qemuui'. This allows these common UI sources to be linked by targets outside of the system emulator build, such as standalone VNC or D-Bus display binaries.

keymaps generation has to be moved earlier, so that header dependency are resolved first.

The library objects are re-exported via a dependency so existing system_ss consumers are unaffected.

---
 ui/meson.build | 103 ++++++++++++++++++++++++++-----------------------
 1 file changed, 55 insertions(+), 48 deletions(-)
ui/meson.build +55 -48
index 74151b05033..1b8f71796e4 100644
@@ -1,25 +1,67 @@
-system_ss.add(pixman)
+keymaps = [
+  ['atset1', 'qcode'],
+  ['linux', 'qcode'],
+  ['qcode', 'atset1'],
+  ['qcode', 'atset2'],
+  ['qcode', 'atset3'],
+  ['qcode', 'linux'],
+  ['qcode', 'qnum'],
+  ['qcode', 'sun'],
+  ['qnum', 'qcode'],
+  ['usb', 'qcode'],
+  ['win32', 'qcode'],
+  ['x11', 'qcode'],
+  ['xorgevdev', 'qcode'],
+  ['xorgkbd', 'qcode'],
+  ['xorgxquartz', 'qcode'],
+  ['xorgxwin', 'qcode'],
+  ['osx', 'qcode'],
+]
+
+if have_system or xkbcommon.found()
+  keycodemapdb_proj = subproject('keycodemapdb', required: true)
+  foreach e : keymaps
+    output = 'input-keymap-@0@-to-@[email protected]'.format(e[0], e[1])
+    genh += custom_target(output,
+                  output: output,
+                  capture: true,
+                  input: keycodemapdb_proj.get_variable('keymaps_csv'),
+                  command: [python, keycodemapdb_proj.get_variable('keymap_gen').full_path(),
+                            'code-map', '--lang', 'glib2',
+                            '--varname', 'qemu_input_map_@0@_to_@1@'.format(e[0], e[1]),
+                            '@INPUT0@', e[0], e[1]])
+  endforeach
+endif
+
+libui_sources = files(
+    'clipboard.c',
+    'console.c',
+    'cursor.c',
+    'dmabuf.c',
+    'display-surface.c',
+    'input-keymap.c',
+    'kbd-state.c',
+    'keymaps.c',
+    'qemu-pixman.c',
+    'vgafont.c',
+  )
+if pixman.found()
+  libui_sources += files('cp437.c', 'vt100.c')
+endif
+libui = static_library('qemuui', libui_sources + genh,
+  dependencies: [pixman],
+  build_by_default: false)
+ui = declare_dependency(objects: libui.extract_all_objects(recursive: false), dependencies: [pixman])
 system_ss.add(png)
 system_ss.add(files(
-  'clipboard.c',
-  'console.c',
-  'cp437.c',
-  'cursor.c',
-  'display-surface.c',
-  'dmabuf.c',
-  'input-keymap.c',
   'input-legacy.c',
   'input-barrier.c',
   'input.c',
-  'kbd-state.c',
-  'keymaps.c',
-  'qemu-pixman.c',
   'ui-hmp-cmds.c',
   'ui-qmp-cmds.c',
   'util.c',
-  'vgafont.c',
-  'vt100.c',
 ))
+system_ss.add(ui)
 system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c'))
 if dbus_display
   system_ss.add(files('dbus-module.c'))
@@ -149,41 +191,6 @@ if spice.found()
   endif
 endif
 
-keymaps = [
-  ['atset1', 'qcode'],
-  ['linux', 'qcode'],
-  ['qcode', 'atset1'],
-  ['qcode', 'atset2'],
-  ['qcode', 'atset3'],
-  ['qcode', 'linux'],
-  ['qcode', 'qnum'],
-  ['qcode', 'sun'],
-  ['qnum', 'qcode'],
-  ['usb', 'qcode'],
-  ['win32', 'qcode'],
-  ['x11', 'qcode'],
-  ['xorgevdev', 'qcode'],
-  ['xorgkbd', 'qcode'],
-  ['xorgxquartz', 'qcode'],
-  ['xorgxwin', 'qcode'],
-  ['osx', 'qcode'],
-]
-
-if have_system or xkbcommon.found()
-  keycodemapdb_proj = subproject('keycodemapdb', required: true)
-  foreach e : keymaps
-    output = 'input-keymap-@0@-to-@[email protected]'.format(e[0], e[1])
-    genh += custom_target(output,
-                  output: output,
-                  capture: true,
-                  input: keycodemapdb_proj.get_variable('keymaps_csv'),
-                  command: [python, keycodemapdb_proj.get_variable('keymap_gen').full_path(),
-                            'code-map', '--lang', 'glib2',
-                            '--varname', 'qemu_input_map_@0@_to_@1@'.format(e[0], e[1]),
-                            '@INPUT0@', e[0], e[1]])
-  endforeach
-endif
-
 subdir('shader')
 
 if have_system
Signature · 1 line
2.54.0
#29 lore raw

[PULL v2 31/33] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

It can rely on the location of the temporary configuration instead, so we don't have to set that environment variable on every test.

---
 tests/qtest/dbus-vmstate-test.c | 2 --
 tests/dbus-daemon.sh            | 2 +-
 2 files changed, 1 insertion(+), 3 deletions(-)
tests/qtest/dbus-vmstate-test.c +0 -2
index 15c35e7c0fa..339b731ceb5 100644
@@ -395,8 +395,6 @@ main(int argc, char **argv)
         exit(1);
     }
 
-    g_setenv("DBUS_VMSTATE_TEST_TMPDIR", workdir, true);
-
     migration_test_add("/dbus-vmstate/without-list",
                        test_dbus_vmstate_without_list);
     migration_test_add("/dbus-vmstate/with-list",
tests/dbus-daemon.sh +1 -1
index 474e2501548..c4a50c73774 100755
@@ -26,7 +26,7 @@ write_config()
     cat > "$CONF" <<EOF
 <busconfig>
   <type>session</type>
-  <listen>unix:tmpdir=$DBUS_VMSTATE_TEST_TMPDIR</listen>
+  <listen>unix:tmpdir=$(dirname "$CONF")</listen>
 
   <policy context="default">
      <!-- Holes must be punched in service configuration files for
Signature · 1 line
2.54.0
#30 lore raw

[PULL v2 33/33] qemu-options: document -chardev dbus

In reply to [email protected]

From: uchouT <[email protected]>

Document the dbus backend introduced in commit 3e301c8d7ef0 ("ui/dbus:
add chardev backend & interface")

Message-ID: <[email protected]>

---
 qemu-options.hx | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
qemu-options.hx +14 -2
index 5387bcd751b..96ae41f787b 100644
@@ -4077,6 +4077,9 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
 #if defined(CONFIG_SPICE)
     "-chardev spicevmc,id=id,name=name[,debug=debug][,logfile=PATH][,logappend=on|off]\n"
     "-chardev spiceport,id=id,name=name[,debug=debug][,logfile=PATH][,logappend=on|off]\n"
+#endif
+#if defined(CONFIG_DBUS_DISPLAY)
+    "-chardev dbus,id=id,name=name[,mux=on|off][,logfile=PATH][,logappend=on|off]\n"
 #endif
     , QEMU_ARCH_ALL
 )
@@ -4088,8 +4091,8 @@ The general form of a character device option is:
     Backend is one of: ``null``, ``socket``, ``udp``, ``msmouse``, ``hub``,
     ``vc``, ``ringbuf``, ``file``, ``pipe``, ``console``, ``serial``,
     ``pty``, ``stdio``, ``braille``, ``parallel``,
-    ``spicevmc``, ``spiceport``. The specific backend will determine the
-    applicable options.
+    ``spicevmc``, ``spiceport``, ``dbus``. The specific backend will
+    determine the applicable options.
 
     Use ``-chardev help`` to print all available chardev backend types.
 
@@ -4408,6 +4411,15 @@ The available backends are:
 
     Connect to a spice port, allowing a Spice client to handle the
     traffic identified by a name (preferably a fqdn).
+
+``-chardev dbus,id=id,name=name``
+    ``dbus`` is only available when D-Bus display support is built in.
+
+    ``name`` name of the chardev as exported on the D-Bus display
+    interface
+
+    Export the character device on the D-Bus display interface, so that
+    a D-Bus client can connect to it.
 ERST
 
 DEFHEADING()
Signature · 1 line
2.54.0
#31 lore raw

[PULL v2 29/33] ui/vnc: replace VNC_DEBUG with trace-events

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Replace #ifdef printf() with run-time trace events.

---
 ui/vnc.h           |  8 -----
 ui/vnc-auth-sasl.c | 13 +++-----
 ui/vnc-enc-tight.c |  4 +--
 ui/vnc-enc-zlib.c  |  4 +--
 ui/vnc-ws.c        | 10 +++---
 ui/vnc.c           | 83 +++++++++++++++++-----------------------------
 ui/trace-events    | 29 +++++++++++++++-
 7 files changed, 73 insertions(+), 78 deletions(-)
ui/vnc.h +0 -8
index 0b345246c8e..0750bf5f72f 100644
@@ -46,14 +46,6 @@
 #include "vnc-enc-zrle.h"
 #include "ui/kbd-state.h"
 
-// #define _VNC_DEBUG 1
-
-#ifdef _VNC_DEBUG
-#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
-#else
-#define VNC_DEBUG(fmt, ...) do { } while (0)
-#endif
-
 /*****************************************************************************
  *
  * Core data structures
ui/vnc-auth-sasl.c +5 -8
index 3f4cfc471d5..9964b969ac2 100644
@@ -73,10 +73,10 @@ size_t vnc_client_write_sasl(VncState *vs)
 {
     size_t ret;
 
-    VNC_DEBUG("Write SASL: Pending output %p size %zd offset %zd "
-              "Encoded: %p size %d offset %d\n",
-              vs->output.buffer, vs->output.capacity, vs->output.offset,
-              vs->sasl.encoded, vs->sasl.encodedLength, vs->sasl.encodedOffset);
+    trace_vnc_sasl_write_pending(vs, vs->output.buffer, vs->output.capacity,
+                                 vs->output.offset, vs->sasl.encoded,
+                                 vs->sasl.encodedLength,
+                                 vs->sasl.encodedOffset);
 
     if (!vs->sasl.encoded) {
         int err;
@@ -157,8 +157,7 @@ size_t vnc_client_read_sasl(VncState *vs)
 
     if (err != SASL_OK)
         return vnc_client_io_error(vs, -1, NULL);
-    VNC_DEBUG("Read SASL Encoded %p size %ld Decoded %p size %d\n",
-              encoded, ret, decoded, decodedLen);
+    trace_vnc_sasl_read_decoded(vs, encoded, ret, decoded, decodedLen);
     buffer_reserve(&vs->input, decodedLen);
     buffer_append(&vs->input, decoded, decodedLen);
     return decodedLen;
@@ -717,5 +716,3 @@ void start_auth_sasl(VncState *vs)
     error_free(local_err);
     vnc_client_error(vs);
 }
-
-
ui/vnc-enc-tight.c +2 -2
index 9dfe6ae5a24..ca671427018 100644
@@ -46,6 +46,7 @@
 #include "vnc.h"
 #include "vnc-enc-tight.h"
 #include "vnc-palette.h"
+#include "trace.h"
 
 /* Compression level stuff. The following array contains various
    encoder parameters for each of 10 compression levels (0..9).
@@ -795,8 +796,7 @@ static int tight_init_stream(VncState *vs, VncTight *tight, int stream_id,
     if (zstream->opaque == NULL) {
         int err;
 
-        VNC_DEBUG("VNC: TIGHT: initializing zlib stream %d\n", stream_id);
-        VNC_DEBUG("VNC: TIGHT: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        trace_vnc_tight_zlib_init(vs, stream_id, zstream->opaque);
         zstream->zalloc = vnc_zlib_zalloc;
         zstream->zfree = vnc_zlib_zfree;
 
ui/vnc-enc-zlib.c +2 -2
index a6d287118aa..657b47ceb2b 100644
@@ -26,6 +26,7 @@
 
 #include "qemu/osdep.h"
 #include "vnc.h"
+#include "trace.h"
 
 #define ZALLOC_ALIGNMENT 16
 
@@ -71,8 +72,7 @@ static int vnc_zlib_stop(VncState *vs, VncWorker *worker)
     if (zstream->opaque != vs) {
         int err;
 
-        VNC_DEBUG("VNC: initializing zlib stream\n");
-        VNC_DEBUG("VNC: opaque = %p | vs = %p\n", zstream->opaque, vs);
+        trace_vnc_zlib_init(vs, zstream->opaque);
         zstream->zalloc = vnc_zlib_zalloc;
         zstream->zfree = vnc_zlib_zfree;
 
ui/vnc-ws.c +5 -5
index 65e8b344b65..fad5dbce342 100644
@@ -32,11 +32,11 @@ static void vncws_tls_handshake_done(QIOTask *task,
     Error *err = NULL;
 
     if (qio_task_propagate_error(task, &err)) {
-        VNC_DEBUG("Handshake failed %s\n", error_get_pretty(err));
+        trace_vnc_ws_tls_handshake_fail(vs, error_get_pretty(err));
         vnc_client_error(vs);
         error_free(err);
     } else {
-        VNC_DEBUG("TLS handshake complete, starting websocket handshake\n");
+        trace_vnc_ws_tls_handshake_complete(vs);
         if (vs->ioc_tag) {
             g_source_remove(vs->ioc_tag);
         }
@@ -67,7 +67,7 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
         vs->vd->tlsauthzid,
         &err);
     if (!tls) {
-        VNC_DEBUG("Failed to setup TLS %s\n", error_get_pretty(err));
+        trace_vnc_ws_tls_setup_fail(vs, error_get_pretty(err));
         error_free(err);
         vnc_client_error(vs);
         return TRUE;
@@ -97,11 +97,11 @@ static void vncws_handshake_done(QIOTask *task,
     Error *err = NULL;
 
     if (qio_task_propagate_error(task, &err)) {
-        VNC_DEBUG("Websock handshake failed %s\n", error_get_pretty(err));
+        trace_vnc_ws_handshake_fail(vs, error_get_pretty(err));
         vnc_client_error(vs);
         error_free(err);
     } else {
-        VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
+        trace_vnc_ws_handshake_complete(vs);
         vnc_start_protocol(vs);
         if (vs->ioc_tag) {
             g_source_remove(vs->ioc_tag);
ui/vnc.c +31 -52

253 lines not on this page · raw message

ui/trace-events +28 -1
index 3eba9ca3a82..c1ea56874ee 100644
@@ -83,7 +83,7 @@ vnc_job_discard_rect(void *state, void *job, int x, int y, int w, int h) "VNC jo
 vnc_job_clamp_rect(void *state, void *job, int x, int y, int w, int h) "VNC job clamp rect state=%p job=%p offset=%d,%d size=%dx%d"
 vnc_job_clamped_rect(void *state, void *job, int x, int y, int w, int h) "VNC job clamp rect state=%p job=%p offset=%d,%d size=%dx%d"
 vnc_job_nrects(void *state, void *job, int nrects) "VNC job state=%p job=%p nrects=%d"
-vnc_auth_init(void *display, int websock, int auth, int subauth) "VNC auth init state=%p websock=%d auth=%d subauth=%d"
+vnc_auth_init(void *display, int websock, int auth, int subauth, const char *name) "VNC auth init state=%p websock=%d auth=%d subauth=%d name=%s"
 vnc_auth_start(void *state, int method) "VNC client auth start state=%p method=%d"
 vnc_auth_pass(void *state, int method) "VNC client auth passed state=%p method=%d"
 vnc_auth_fail(void *state, int method, const char *message, const char *reason) "VNC client auth failed state=%p method=%d message=%s reason=%s"
@@ -97,6 +97,33 @@ vnc_auth_sasl_step(void *state, const void *clientdata, size_t clientlen, const
 vnc_auth_sasl_ssf(void *state, int ssf) "VNC client auth SASL SSF state=%p size=%d"
 vnc_auth_sasl_username(void *state, const char *name) "VNC client auth SASL user state=%p name=%s"
 vnc_auth_sasl_acl(void *state, int allow) "VNC client auth SASL ACL state=%p allow=%d"
+vnc_set_share_mode(void *state, void *ioc, int old_mode, int new_mode) "VNC set share mode state=%p ioc=%p old=%d new=%d"
+vnc_client_protocol_error(void *state) "VNC client protocol error state=%p"
+vnc_client_write_wire(void *state, const void *data, size_t datalen, ssize_t ret) "VNC client write wire state=%p data=%p len=%zu ret=%zd"
+vnc_client_write_plain(void *state, const void *buffer, size_t capacity, size_t offset, int wait_ssf) "VNC client write plain state=%p buffer=%p capacity=%zu offset=%zu wait_ssf=%d"
+vnc_client_read_wire(void *state, const void *data, size_t datalen, ssize_t ret) "VNC client read wire state=%p data=%p len=%zu ret=%zd"
+vnc_client_read_plain(void *state, const void *buffer, size_t capacity, size_t offset) "VNC client read plain state=%p buffer=%p capacity=%zu offset=%zu"
+vnc_client_unknown_encoding(void *state, int index, int encoding) "VNC client unknown encoding state=%p index=%d encoding=0x%x"
+vnc_client_invalid_audio_format(void *state, int fmt) "VNC client invalid audio format state=%p fmt=%d"
+vnc_client_invalid_audio_channels(void *state, int channels) "VNC client invalid audio channel count state=%p channels=%d"
+vnc_client_invalid_audio_freq(void *state, unsigned int freq) "VNC client invalid audio frequency state=%p freq=%u"
+vnc_client_invalid_audio_msg(void *state, int msg) "VNC client invalid audio message state=%p msg=%d"
+vnc_client_unknown_qemu_msg(void *state, int msg) "VNC client unknown QEMU msg state=%p msg=%d"
+vnc_client_unknown_msg(void *state, int msg) "VNC client unknown msg state=%p msg=%d"
+vnc_client_protocol_version(void *state, int major, int minor) "VNC client protocol version state=%p version=%d.%d"
+vnc_client_protocol_version_malformed(void *state, const char *version) "VNC client malformed protocol version state=%p version=%s"
+vnc_client_protocol_version_unsupported(void *state) "VNC client unsupported protocol version state=%p"
+vnc_client_auth_method(void *state, int auth) "VNC client auth method state=%p auth=%d"
+vnc_client_setup(void *state, void *ioc, int websocket, int auth, int subauth) "VNC client setup state=%p ioc=%p websocket=%d auth=%d subauth=%d"
+vnc_ws_tls_handshake_fail(void *state, const char *msg) "VNC WS TLS handshake failed state=%p msg=%s"
+vnc_ws_tls_handshake_complete(void *state) "VNC WS TLS handshake complete state=%p"
+vnc_ws_tls_setup_fail(void *state, const char *msg) "VNC WS TLS setup failed state=%p msg=%s"
+vnc_ws_handshake_fail(void *state, const char *msg) "VNC WS handshake failed state=%p msg=%s"
+vnc_ws_handshake_complete(void *state) "VNC WS handshake complete state=%p"
+vnc_sasl_write_pending(void *state, const void *buffer, size_t capacity, size_t offset, const void *encoded, int encoded_len, int encoded_offset) "VNC SASL write pending state=%p buffer=%p capacity=%zu offset=%zu encoded=%p encoded_len=%d encoded_offset=%d"
+vnc_sasl_read_decoded(void *state, const void *encoded, size_t encoded_len, const void *decoded, unsigned int decoded_len) "VNC SASL read decoded state=%p encoded=%p encoded_len=%zu decoded=%p decoded_len=%u"
+vnc_zlib_init(void *state, const void *opaque) "VNC zlib init state=%p opaque=%p"
+vnc_tight_zlib_init(void *state, int stream_id, const void *opaque) "VNC tight zlib init state=%p stream=%d opaque=%p"
 
 
 # input.c
Signature · 1 line
2.54.0
#32 lore raw

[PULL v2 23/33] ui/vnc: clean up VNC displays on exit

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Previously, VNC displays were never torn down on QEMU exit, leaking resources and leaving connected clients with unclean disconnects.

Add vnc_cleanup() to free all VNC displays during qemu_cleanup(). Make vnc_display_close() initiate disconnection of active clients, and have vnc_display_free() drain the main loop until all clients have completed their teardown, instead of asserting the client list is empty.

---
 include/ui/console.h |  1 +
 system/runstate.c    |  5 +++++
 ui/vnc.c             | 20 ++++++++++++++++++--
 3 files changed, 24 insertions(+), 2 deletions(-)
include/ui/console.h +1 -0
index 550a5e08e46..89fb4c1942a 100644
@@ -445,6 +445,7 @@ void vnc_parse(const char *str);
 int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp);
 bool vnc_display_reload_certs(const char *id,  Error **errp);
 bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp);
+void vnc_cleanup(void);
 
 /* input.c */
 int index_from_key(const char *key, size_t key_length);
system/runstate.c +5 -0
index 770253b467b..0e1cb3b4e67 100644
@@ -61,6 +61,8 @@
 #include "system/confidential-guest-support.h"
 #include "system/system.h"
 #include "system/tpm.h"
+#include "ui/console.h"
+
 #include "trace.h"
 
 static NotifierList exit_notifiers =
@@ -1044,5 +1046,8 @@ void qemu_cleanup(int status)
     monitor_cleanup();
     qemu_chr_cleanup();
     user_creatable_cleanup();
+#ifdef CONFIG_VNC
+    vnc_cleanup();
+#endif
     /* TODO: unref root container, check all devices are ok */
 }
ui/vnc.c +18 -2
index 1c649e7bccf..d65153a5001 100644
@@ -3473,8 +3473,13 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
 
 static void vnc_display_close(VncDisplay *vd)
 {
+    VncState *vs;
+
     assert(vd);
 
+    QTAILQ_FOREACH(vs, &vd->clients, next) {
+        vnc_disconnect_start(vs);
+    }
     if (vd->listener) {
         qio_net_listener_disconnect(vd->listener);
         object_unref(OBJECT(vd->listener));
@@ -3515,10 +3520,12 @@ void vnc_display_free(VncDisplay *vd)
         return;
     }
 
-    assert(QTAILQ_EMPTY(&vd->clients));
+    vnc_display_close(vd);
+    while (!QTAILQ_EMPTY(&vd->clients)) {
+        main_loop_wait(false);
+    }
 
     vnc_stop_worker_thread(vd);
-    vnc_display_close(vd);
     unregister_displaychangelistener(&vd->dcl);
     qkbd_state_free(vd->kbd);
     qemu_del_vm_change_state_handler(vd->vmstate_handler_entry);
@@ -4348,6 +4355,15 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
     return vnc_display_new(id, errp) != NULL ? 0 : -1;
 }
 
+void vnc_cleanup(void)
+{
+    VncDisplay *vd, *vd_next;
+
+    QTAILQ_FOREACH_SAFE(vd, &vnc_displays, next, vd_next) {
+        vnc_display_free(vd);
+    }
+}
+
 static void vnc_register_config(void)
 {
     qemu_add_opts(&qemu_vnc_opts);
Signature · 1 line
2.54.0
#33 lore raw

[PULL v2 21/33] ui/vnc: vnc_display_init() and vnc_display_open() return bool

In reply to [email protected]

From: Marc-André Lureau <[email protected]>

Use the QEMU-style error pattern returning "true" on success.

---
 include/ui/console.h |  4 ++--
 ui/vnc.c             | 20 ++++++++++----------
 2 files changed, 12 insertions(+), 12 deletions(-)
include/ui/console.h +2 -2
index 2bf768ed482..7224b8142f3 100644
@@ -438,8 +438,8 @@ const char *qemu_display_get_vc(DisplayOptions *opts);
 void qemu_display_help(void);
 
 /* vnc.c */
-void vnc_display_init(const char *id, Error **errp);
-void vnc_display_open(const char *id, Error **errp);
+bool vnc_display_init(const char *id, Error **errp);
+bool vnc_display_open(const char *id, Error **errp);
 void vnc_display_add_client(const char *id, int csock, bool skipauth);
 int vnc_display_password(const char *id, const char *password, Error **errp);
 int vnc_display_pw_expire(const char *id, time_t expires);
ui/vnc.c +10 -10
index 3a908670ab9..067f534cf08 100644
@@ -3425,12 +3425,12 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
 
 static void vnc_display_free(VncDisplay *vd);
 
-void vnc_display_init(const char *id, Error **errp)
+bool vnc_display_init(const char *id, Error **errp)
 {
     VncDisplay *vd;
 
     if (vnc_display_find(id) != NULL) {
-        return;
+        return true;
     }
     vd = g_malloc0(sizeof(*vd));
 
@@ -3451,7 +3451,7 @@ void vnc_display_init(const char *id, Error **errp)
 
     if (!vd->kbd_layout) {
         vnc_display_free(vd);
-        return;
+        return false;
     }
 
     vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
@@ -3465,6 +3465,7 @@ void vnc_display_init(const char *id, Error **errp)
         &vmstate_change_handler, vd);
 
     QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
+    return true;
 }
 
 static void vnc_display_close(VncDisplay *vd)
@@ -4070,7 +4071,7 @@ bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp)
     return true;
 }
 
-void vnc_display_open(const char *id, Error **errp)
+bool vnc_display_open(const char *id, Error **errp)
 {
     VncDisplay *vd = vnc_display_find(id);
     QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
@@ -4273,7 +4274,7 @@ void vnc_display_open(const char *id, Error **errp)
     qkbd_state_set_delay(vd->kbd, key_delay_ms);
 
     if (saddr_list == NULL) {
-        return;
+        return true;
     }
 
     if (reverse) {
@@ -4291,10 +4292,11 @@ void vnc_display_open(const char *id, Error **errp)
     }
 
     /* Success */
-    return;
+    return true;
 
 fail:
     vnc_display_close(vd);
+    return false;
 }
 
 void vnc_display_add_client(const char *id, int csock, bool skipauth)
@@ -4350,12 +4352,10 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
         id = vnc_auto_assign_id(opts);
     }
 
-    vnc_display_init(id, errp);
-    if (*errp) {
+    if (!vnc_display_init(id, errp)) {
         return -1;
     }
-    vnc_display_open(id, errp);
-    if (*errp) {
+    if (!vnc_display_open(id, errp)) {
         return -1;
     }
     return 0;
Signature · 1 line
2.54.0