* [PATCH v2 00/67] ui: add standalone VNC server over D-Bus
@ 2026-04-10 19:18 Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 01/67] ui/vnc-jobs: remove needless buffer_reset() before end Marc-André Lureau
` (66 more replies)
0 siblings, 67 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé, Fabrice Bellard
This series adds qemu-vnc, a standalone VNC server that connects to a
running QEMU instance via the D-Bus display interface (org.qemu.Display1).
This allows serving a VNC display as a separate process with an independent
lifecycle and privilege domain, without requiring VNC support compiled into
the QEMU system emulator itself.
The bulk of the series is preparatory refactoring:
- Clean up VNC code: merge init/open, fix leaks, simplify error handling
- Extract and clean up VT100 emulation from console-vc into a reusable unit
- Reorganize ui/ code: move DisplaySurface functions, vgafont, datadir
and other pieces into their own files
- Refactor console APIs: rename methods, simplify listener registration,
return completion status from gfx_update
- Extract common ui sources into a static library that can be linked by
both the system emulator and the new standalone binary
The final patch adds contrib/qemu-vnc, built when both VNC and D-Bus
display support are enabled.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
Changes in v2:
- renamed utf8_ DFA function/symbols with bh_ (Bjoern Hoehrmann) prefix
- use "QemuVT *vt = &s->vt;" to avoid some code churn
- use size_t for vt100_input()
- replace back compound literal usage for QEMUUIInfo, use variable
- add a preliminary patch to convert vnc_display_init/open() to return bool
- add doc comment for qemu_console_{un}register_listener()
- document GraphicsHwOps.gfx_update better
- add "ui/vnc: make the worker thread per-VncDisplay", and free it on vnc_display_free()
- add "ui/vnc: add vnc_cleanup()"
- add "replace VNC_DEBUG with trace-events"
- qemu-vnc: add sasl & authz support, doc updates
- move qemu-vnc under tools/
- rebased, collect trailer tags
- Link to v1: https://lore.kernel.org/qemu-devel/20260317-qemu-vnc-v1-0-48eb1dcf7b76@redhat.com
---
Marc-André Lureau (67):
ui/vnc-jobs: remove needless buffer_reset() before end
ui/vnc: clarify intent using buffer_empty() function
ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL
ui/vnc-jobs: remove dead VncJobQueue.exit
ui/vnc-jobs: remove vnc_queue_clear()
ui/vnc-jobs: narrow taking the queue lock
ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self()
ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen)
ui/console-vc: add UTF-8 input decoding with CP437 rendering
ui/console-vc: ignore string-type escape sequences
ui/console-vc: fix comment shift-out/in comments
ui/console: dispatch get_label() through QOM virtual method
ui/console-vc: introduce QemuVT100
ui/console-vc: set vt100 associated pixman image
ui/console-vc: vga_putcharxy()->vt100_putcharxy()
ui/console-vc: make invalidate_xy() take vt100
ui/console-vc: make show_cursor() take vt100
ui/console-vc: decouple VT100 display updates via function pointer
ui/console-vc: console_refresh() -> vt100_refresh()
ui/console-vc: move cursor blinking logic into VT100 layer
ui/console-vc: console_scroll() -> vt100_scroll()
ui/console-vc: refactor text_console_resize() into vt100_set_image()
ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf()
ui/console-vc: unify the write path
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: avoid duplicating vgafont16 in each translation unit
ui/vgafont: add SPDX license header
ui: move FONT_WIDTH/HEIGHT to vgafont.h
ui/console-vc: move VT100 emulation into separate unit
util: move datadir.c from system/
ui: move DisplaySurface functions to display-surface.c
ui: make qemu_default_pixelformat() static inline
ui: make unregister_displaychangelistener() skip unregistered
ui: minor code simplification
system: make qemu_del_vm_change_state_handler accept NULL
ui/vnc: assert preconditions instead of silently returning
ui/vnc: simplify vnc_init_func error handling
ui/vnc: VncDisplay.id is not const
ui/keymaps: introduce kbd_layout_free()
ui/vnc: fix vnc_display_init() leak on failure
ui/vnc: make vnc_disconnect_finish() private
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: add vnc_cleanup()
ui/vnc: report an error for duplicate display id
ui/vnc: defer listener registration until the console is known
ui/vnc: expose vnc_disconnect_start()
ui/vnc: remove left-over dead code
ui/vnc: explicitly link with png
ui/vnc: add vnc-system unit, to allow different implementations
ui/console: remove qemu_console_is_visible()
ui/console: simplify registering display/console change listener
ui/console: add doc comment for qemu_console_{un}register_listener()
ui/console: return completion status from gfx_update callback
ui/console: rename public API to use consistent qemu_console_ prefix
ui/console: move console_handle_touch_event() to input
ui/vnc: replace VNC_DEBUG with trace-events
ui: extract common sources into a static library
tests: rename the dbus-daemon helper script
tests/qtest: fix dbus-vmstate-test compilation
tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR
tools/qemu-vnc: add standalone VNC server over D-Bus
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 | 222 ++
meson.build | 17 +
hw/display/qxl.h | 2 +-
include/ui/console.h | 153 +-
include/ui/input.h | 15 +
include/ui/qemu-pixman.h | 8 +
include/ui/surface.h | 2 -
tools/qemu-vnc/qemu-vnc.h | 46 +
tools/qemu-vnc/trace.h | 4 +
ui/console-priv.h | 8 -
ui/cp437.h | 13 +
ui/keymaps.h | 1 +
ui/vgafont.h | 4618 +---------------------
ui/vnc-jobs.h | 3 +-
ui/vnc.h | 22 +-
ui/vt100.h | 92 +
hw/arm/musicpal.c | 7 +-
hw/display/artist.c | 8 +-
hw/display/ati.c | 16 +-
hw/display/bcm2835_fb.c | 12 +-
hw/display/bochs-display.c | 20 +-
hw/display/cg3.c | 11 +-
hw/display/cirrus_vga.c | 8 +-
hw/display/cirrus_vga_isa.c | 2 +-
hw/display/dm163.c | 10 +-
hw/display/exynos4210_fimd.c | 10 +-
hw/display/g364fb.c | 19 +-
hw/display/jazz_led.c | 24 +-
hw/display/macfb.c | 12 +-
hw/display/next-fb.c | 8 +-
hw/display/omap_lcdc.c | 18 +-
hw/display/pl110.c | 9 +-
hw/display/qxl-render.c | 18 +-
hw/display/qxl.c | 25 +-
hw/display/ramfb-standalone.c | 6 +-
hw/display/ramfb.c | 4 +-
hw/display/sm501.c | 14 +-
hw/display/ssd0303.c | 14 +-
hw/display/ssd0323.c | 16 +-
hw/display/tcx.c | 22 +-
hw/display/vga-isa.c | 2 +-
hw/display/vga-mmio.c | 2 +-
hw/display/vga-pci.c | 6 +-
hw/display/vga.c | 60 +-
hw/display/vhost-user-gpu.c | 22 +-
hw/display/virtio-gpu-base.c | 7 +-
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 | 10 +-
hw/display/vmware_vga.c | 21 +-
hw/display/xenfb.c | 12 +-
hw/display/xlnx_dp.c | 20 +-
hw/vfio/display.c | 49 +-
system/runstate.c | 8 +
tests/qtest/dbus-vmstate-test.c | 13 +-
tests/qtest/dbus-vnc-test.c | 1342 +++++++
tools/qemu-vnc/audio.c | 307 ++
tools/qemu-vnc/chardev.c | 127 +
tools/qemu-vnc/clipboard.c | 378 ++
tools/qemu-vnc/console.c | 168 +
tools/qemu-vnc/dbus.c | 439 ++
tools/qemu-vnc/display.c | 456 +++
tools/qemu-vnc/input.c | 239 ++
tools/qemu-vnc/qemu-vnc.c | 491 +++
tools/qemu-vnc/stubs.c | 62 +
tools/qemu-vnc/utils.c | 59 +
ui/console-vc-stubs.c | 9 +-
ui/console-vc.c | 1021 +----
ui/console.c | 491 +--
ui/cp437.c | 205 +
ui/curses.c | 23 +-
ui/dbus-console.c | 16 +-
ui/dbus-listener.c | 37 +-
ui/display-surface.c | 107 +
ui/egl-headless.c | 8 +-
ui/gtk-egl.c | 6 +-
ui/gtk-gl-area.c | 6 +-
ui/gtk.c | 36 +-
ui/input.c | 65 +
ui/keymaps.c | 13 +-
ui/sdl2-2d.c | 2 +-
ui/sdl2-gl.c | 2 +-
ui/sdl2.c | 22 +-
ui/spice-display.c | 24 +-
ui/vgafont.c | 4616 +++++++++++++++++++++
ui/vnc-auth-sasl.c | 13 +-
ui/vnc-enc-tight.c | 4 +-
ui/vnc-enc-zlib.c | 4 +-
ui/vnc-jobs.c | 112 +-
ui/vnc-system.c | 19 +
ui/vnc-ws.c | 10 +-
ui/vnc.c | 291 +-
ui/vt100.c | 986 +++++
{system => util}/datadir.c | 0
hw/display/apple-gfx.m | 26 +-
meson_options.txt | 2 +
scripts/meson-buildoptions.sh | 3 +
system/meson.build | 1 -
system/trace-events | 1 -
tests/{dbus-vmstate-daemon.sh => dbus-daemon.sh} | 16 +-
tests/qtest/meson.build | 18 +-
tools/qemu-vnc/meson.build | 26 +
tools/qemu-vnc/qemu-vnc1.xml | 174 +
tools/qemu-vnc/trace-events | 20 +
ui/cocoa.m | 23 +-
ui/meson.build | 103 +-
ui/trace-events | 29 +-
util/meson.build | 1 +
util/trace-events | 3 +
118 files changed, 11819 insertions(+), 6713 deletions(-)
---
base-commit: becd22fdc2a071783d9e04421526633772b3b98c
change-id: 20260312-qemu-vnc-9662fc572262
Best regards,
--
Marc-André Lureau <marcandre.lureau@redhat.com>
^ permalink raw reply [flat|nested] 100+ messages in thread
* [PATCH v2 01/67] ui/vnc-jobs: remove needless buffer_reset() before end
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 02/67] ui/vnc: clarify intent using buffer_empty() function Marc-André Lureau
` (65 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
vnc_async_encoding_end() does buffer_free() next.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index ec90ae6d5fc..a6ab733faa1 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -326,7 +326,6 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
qemu_bh_schedule(job->vs->bh);
} else {
- buffer_reset(&vs.output);
/* Copy persistent encoding data */
vnc_async_encoding_end(job->vs, &vs);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 02/67] ui/vnc: clarify intent using buffer_empty() function
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 01/67] ui/vnc-jobs: remove needless buffer_reset() before end Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 03/67] ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL Marc-André Lureau
` (64 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 2 +-
ui/vnc.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index a6ab733faa1..4dd7ccad969 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -160,7 +160,7 @@ void vnc_jobs_consume_buffer(VncState *vs)
bool flush;
vnc_lock_output(vs);
- if (vs->jobs_buffer.offset) {
+ if (!buffer_empty(&vs->jobs_buffer)) {
if (vs->ioc != NULL && buffer_empty(&vs->output)) {
g_clear_handle_id(&vs->ioc_tag, g_source_remove);
if (vs->disconnecting == FALSE) {
diff --git a/ui/vnc.c b/ui/vnc.c
index ccc73bd7aa4..4aa446a48d7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1718,7 +1718,7 @@ void vnc_write_u8(VncState *vs, uint8_t value)
void vnc_flush(VncState *vs)
{
vnc_lock_output(vs);
- if (vs->ioc != NULL && vs->output.offset) {
+ if (vs->ioc != NULL && !buffer_empty(&vs->output)) {
vnc_client_write_locked(vs);
}
if (vs->disconnecting) {
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 03/67] ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 01/67] ui/vnc-jobs: remove needless buffer_reset() before end Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 02/67] ui/vnc: clarify intent using buffer_empty() function Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 04/67] ui/vnc-jobs: remove dead VncJobQueue.exit Marc-André Lureau
` (63 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
The only caller, vnc_jobs_join() cannot take vs == NULL argument, or it
would later crash.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 4dd7ccad969..8cb30e72276 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -138,7 +138,7 @@ static bool vnc_has_job_locked(VncState *vs)
VncJob *job;
QTAILQ_FOREACH(job, &queue->jobs, next) {
- if (job->vs == vs || !vs) {
+ if (job->vs == vs) {
return true;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 04/67] ui/vnc-jobs: remove dead VncJobQueue.exit
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (2 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 03/67] ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 05/67] ui/vnc-jobs: remove vnc_queue_clear() Marc-André Lureau
` (62 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
Since commit 09526058d0a5 ("ui/vnc: Remove vnc_stop_worker_thread()"),
it's not used anymore. It seems stopping worker thread hasn't been
supported ever.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 8cb30e72276..9e536b07b90 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -56,7 +56,6 @@ struct VncJobQueue {
QemuCond cond;
QemuMutex mutex;
QemuThread thread;
- bool exit;
QTAILQ_HEAD(, VncJob) jobs;
};
@@ -124,7 +123,7 @@ static void vnc_job_free(VncJob *job)
void vnc_job_push(VncJob *job)
{
vnc_lock_queue(queue);
- if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
+ if (QLIST_EMPTY(&job->rectangles)) {
vnc_job_free(job);
} else {
QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
@@ -248,17 +247,12 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
int saved_offset;
vnc_lock_queue(queue);
- while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
+ while (QTAILQ_EMPTY(&queue->jobs)) {
qemu_cond_wait(&queue->cond, &queue->mutex);
}
- /* Here job can only be NULL if queue->exit is true */
job = QTAILQ_FIRST(&queue->jobs);
vnc_unlock_queue(queue);
- if (queue->exit) {
- return -1;
- }
-
assert(job->vs->magic == VNC_MAGIC);
vc = container_of(job->vs, VncConnection, vs);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 05/67] ui/vnc-jobs: remove vnc_queue_clear()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (3 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 04/67] ui/vnc-jobs: remove dead VncJobQueue.exit Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 06/67] ui/vnc-jobs: narrow taking the queue lock Marc-André Lureau
` (61 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
The function was never called, since the worker thread was never
exiting. Also it was incomplete (not clearing pending job list) and
mixing global queue and argument. Let's remove it.
Note: maybe the worker thread could be torn down when vnc_jobs_join()
realizes there is no job left.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 9e536b07b90..28a4738f1ec 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -345,14 +345,6 @@ static VncJobQueue *vnc_queue_init(void)
return queue;
}
-static void vnc_queue_clear(VncJobQueue *q)
-{
- qemu_cond_destroy(&queue->cond);
- qemu_mutex_destroy(&queue->mutex);
- g_free(q);
- queue = NULL; /* Unset global queue */
-}
-
static void *vnc_worker_thread(void *arg)
{
VncJobQueue *queue = arg;
@@ -360,7 +352,7 @@ static void *vnc_worker_thread(void *arg)
qemu_thread_get_self(&queue->thread);
while (!vnc_worker_thread_loop(queue)) ;
- vnc_queue_clear(queue);
+ g_assert_not_reached();
return NULL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 06/67] ui/vnc-jobs: narrow taking the queue lock
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (4 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 05/67] ui/vnc-jobs: remove vnc_queue_clear() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-15 9:17 ` Daniel P. Berrangé
2026-04-10 19:18 ` [PATCH v2 07/67] ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self() Marc-André Lureau
` (60 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
It's not needed unless manipulating the queue.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 28a4738f1ec..9c17d684c9e 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -83,26 +83,26 @@ VncJob *vnc_job_new(VncState *vs)
assert(vs->magic == VNC_MAGIC);
job->vs = vs;
- vnc_lock_queue(queue);
QLIST_INIT(&job->rectangles);
- vnc_unlock_queue(queue);
return job;
}
+/*
+ * Do not call this after pushing the job.
+ */
int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
{
VncRectEntry *entry = g_new0(VncRectEntry, 1);
trace_vnc_job_add_rect(job->vs, job, x, y, w, h);
+ assert(!QTAILQ_IN_USE(job, next));
entry->rect.x = x;
entry->rect.y = y;
entry->rect.w = w;
entry->rect.h = h;
- vnc_lock_queue(queue);
QLIST_INSERT_HEAD(&job->rectangles, entry, next);
- vnc_unlock_queue(queue);
return 1;
}
@@ -120,16 +120,21 @@ static void vnc_job_free(VncJob *job)
g_free(job);
}
+/*
+ * Push a job onto the queue. Ownership of the job is transferred.
+ */
void vnc_job_push(VncJob *job)
{
- vnc_lock_queue(queue);
+ assert(!QTAILQ_IN_USE(job, next));
+
if (QLIST_EMPTY(&job->rectangles)) {
vnc_job_free(job);
} else {
+ vnc_lock_queue(queue);
QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
qemu_cond_broadcast(&queue->cond);
+ vnc_unlock_queue(queue);
}
- vnc_unlock_queue(queue);
}
static bool vnc_has_job_locked(VncState *vs)
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 07/67] ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (5 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 06/67] ui/vnc-jobs: narrow taking the queue lock Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 08/67] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen) Marc-André Lureau
` (59 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
The call is unnecessary, since "thread" is already set at creation time.
Furthermore, the "thread" field is mostly useless as the thread is
created DETACHED and isn't used for anything but perhaps debugging.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 9c17d684c9e..5b17ef54091 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -354,8 +354,6 @@ static void *vnc_worker_thread(void *arg)
{
VncJobQueue *queue = arg;
- qemu_thread_get_self(&queue->thread);
-
while (!vnc_worker_thread_loop(queue)) ;
g_assert_not_reached();
return NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 08/67] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen)
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (6 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 07/67] ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-11 22:42 ` Philippe Mathieu-Daudé
2026-04-10 19:18 ` [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering Marc-André Lureau
` (58 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
The loop condition used `y <= s->height` instead of `y < s->height`,
causing vc_clear_xy() to be called with y == s->height. This clears
a row in the scrollback buffer beyond the visible screen.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index f22806fed79..8dee1f9bd01 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -899,7 +899,7 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
case 2:
/* clear entire screen */
- for (y = 0; y <= s->height; y++) {
+ for (y = 0; y < s->height; y++) {
for (x = 0; x < s->width; x++) {
vc_clear_xy(vc, x, y);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (7 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 08/67] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen) Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-15 11:24 ` Daniel P. Berrangé
2026-04-10 19:18 ` [PATCH v2 10/67] ui/console-vc: ignore string-type escape sequences Marc-André Lureau
` (57 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/cp437.h | 13 ++++
ui/console-vc.c | 61 +++++++++++++++++
ui/cp437.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ui/meson.build | 2 +-
4 files changed, 280 insertions(+), 1 deletion(-)
diff --git a/ui/cp437.h b/ui/cp437.h
new file mode 100644
index 00000000000..81ace8317c7
--- /dev/null
+++ b/ui/cp437.h
@@ -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 */
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 8dee1f9bd01..d9d6966410a 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -9,6 +9,7 @@
#include "qemu/fifo8.h"
#include "qemu/option.h"
#include "ui/console.h"
+#include "ui/cp437.h"
#include "trace.h"
#include "console-priv.h"
@@ -89,6 +90,8 @@ struct VCChardev {
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;
@@ -598,6 +601,46 @@ static void vc_clear_xy(VCChardev *vc, int x, int y)
vc_update_xy(vc, x, y);
}
+/*
+ * UTF-8 DFA decoder by Bjoern Hoehrmann.
+ * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+ * See https://github.com/polijan/utf8_decode for details.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#define BH_UTF8_ACCEPT 0
+#define BH_UTF8_REJECT 12
+
+static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
+{
+ static const uint8_t utf8d[] = {
+ /* character class lookup */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ /* state transition lookup */
+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+ 12,36,12,12,12,12,12,12,12,12,12,12,
+ };
+ uint32_t type = utf8d[byte];
+
+ *codep = (*state != BH_UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xffu >> type) & (byte);
+
+ *state = utf8d[256 + *state + type];
+ return *state;
+}
+
static void vc_put_one(VCChardev *vc, int ch)
{
QemuTextConsole *s = vc->console;
@@ -761,6 +804,24 @@ static void vc_putchar(VCChardev *vc, int ch)
switch(vc->state) {
case TTY_STATE_NORM:
+ /* Feed byte through the UTF-8 DFA decoder */
+ if (ch >= 0x80) {
+ switch (bh_utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
+ case BH_UTF8_ACCEPT:
+ vc_put_one(vc, unicode_to_cp437(vc->utf8_codepoint));
+ break;
+ case BH_UTF8_REJECT:
+ /* Reset state so the decoder can resync */
+ vc->utf8_state = BH_UTF8_ACCEPT;
+ break;
+ default:
+ /* Need more bytes */
+ break;
+ }
+ break;
+ }
+ /* ASCII byte: abort any pending UTF-8 sequence */
+ vc->utf8_state = BH_UTF8_ACCEPT;
switch(ch) {
case '\r': /* carriage return */
s->x = 0;
diff --git a/ui/cp437.c b/ui/cp437.c
new file mode 100644
index 00000000000..8ec38b73419
--- /dev/null
+++ b/ui/cp437.c
@@ -0,0 +1,205 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ *
+ * Copyright (c) QEMU contributors
+ */
+#include "qemu/osdep.h"
+#include "cp437.h"
+
+/*
+ * Unicode to CP437 page tables.
+ *
+ * Borrowed from the Linux kernel (fs/nls/nls_cp437.c, "Dual BSD/GPL"),
+ * generated from the Unicode Organization tables (www.unicode.org).
+ */
+static const unsigned char uni2cp437_page00[256] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
+ 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
+ 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
+ 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
+ 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
+ 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
+ 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
+ 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
+ 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
+};
+
+static const unsigned char uni2cp437_page01[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+};
+
+static const unsigned char uni2cp437_page03[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
+ 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
+ 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
+ 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
+};
+
+static const unsigned char uni2cp437_page20[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
+};
+
+static const unsigned char uni2cp437_page22[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
+ 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
+};
+
+static const unsigned char uni2cp437_page23[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+};
+
+static const unsigned char uni2cp437_page25[256] = {
+ 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
+ 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
+ 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
+ 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
+ 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
+ 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
+ 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
+ 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
+ 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
+ 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
+ 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
+ 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
+
+ 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
+ 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
+ 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
+ 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
+};
+
+static const unsigned char *const uni2cp437_page[256] = {
+ [0x00] = uni2cp437_page00, [0x01] = uni2cp437_page01,
+ [0x03] = uni2cp437_page03, [0x20] = uni2cp437_page20,
+ [0x22] = uni2cp437_page22, [0x23] = uni2cp437_page23,
+ [0x25] = uni2cp437_page25,
+};
+
+/*
+ * Convert a Unicode code point to its CP437 equivalent for
+ * rendering with the VGA font.
+ * Returns '?' for characters that cannot be mapped.
+ */
+int unicode_to_cp437(uint32_t codepoint)
+{
+ const unsigned char *page;
+ unsigned char hi = (codepoint >> 8) & 0xff;
+ unsigned char lo = codepoint & 0xff;
+
+ if (codepoint > 0xffff) {
+ return '?';
+ }
+
+ page = uni2cp437_page[hi];
+ if (page && page[lo]) {
+ return page[lo];
+ }
+
+ return '?';
+}
diff --git a/ui/meson.build b/ui/meson.build
index 69404bca71a..d4d9312b98c 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -16,7 +16,7 @@ system_ss.add(files(
'ui-qmp-cmds.c',
'util.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
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 10/67] ui/console-vc: ignore string-type escape sequences
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (8 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-15 9:19 ` Daniel P. Berrangé
2026-04-10 19:18 ` [PATCH v2 11/67] ui/console-vc: fix comment shift-out/in comments Marc-André Lureau
` (56 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Modern terminals and applications emit OSC (Operating System Command),
DCS, SOS, PM, and APC escape sequences (e.g. for setting window
titles). The text console currently does not recognise these
string-type introducers, so each byte of the payload is interpreted as
a normal character or a new escape, producing garbage on screen.
Add a TTY_STATE_OSC state that silently consumes all bytes until the
sequence is terminated by BEL or ST (ESC \).
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index d9d6966410a..f1d38ee8ada 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -45,6 +45,7 @@ enum TTYState {
TTY_STATE_CSI,
TTY_STATE_G0,
TTY_STATE_G1,
+ TTY_STATE_OSC,
};
typedef struct QemuTextConsole {
@@ -868,6 +869,10 @@ static void vc_putchar(VCChardev *vc, int ch)
vc->state = TTY_STATE_G0;
} else if (ch == ')') {
vc->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;
} else if (ch == '7') {
vc_save_cursor(vc);
vc->state = TTY_STATE_NORM;
@@ -1026,6 +1031,16 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
}
break;
+ case TTY_STATE_OSC: /* Operating System Command: ESC ] ... BEL/ST */
+ if (ch == '\a') {
+ /* BEL terminates OSC */
+ vc->state = TTY_STATE_NORM;
+ } else if (ch == 27) {
+ /* ESC might start ST (ESC \) */
+ vc->state = TTY_STATE_ESC;
+ }
+ /* All other bytes are silently consumed */
+ break;
case TTY_STATE_G0: /* set character sets */
case TTY_STATE_G1: /* set character sets */
switch (ch) {
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 11/67] ui/console-vc: fix comment shift-out/in comments
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (9 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 10/67] ui/console-vc: ignore string-type escape sequences Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method Marc-André Lureau
` (55 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
14 is shift-out
15 is shift-in
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index f1d38ee8ada..bd816d45759 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -846,10 +846,10 @@ static void vc_putchar(VCChardev *vc, int ch)
/* TODO: has to be implemented */
break;
case 14:
- /* SI (shift in), character set 0 (ignored) */
+ /* SO (shift out), character set 1 (ignored) */
break;
case 15:
- /* SO (shift out), character set 1 (ignored) */
+ /* SI (shift in), character set 0 (ignored) */
break;
case 27: /* esc (introducing an escape sequence) */
vc->state = TTY_STATE_ESC;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (10 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 11/67] ui/console-vc: fix comment shift-out/in comments Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-11 22:41 ` Philippe Mathieu-Daudé
2026-04-10 19:18 ` [PATCH v2 13/67] ui/console-vc: introduce QemuVT100 Marc-André Lureau
` (54 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
Replace the type-checking chain in qemu_console_get_label() (using
QEMU_IS_GRAPHIC_CONSOLE/QEMU_IS_TEXT_CONSOLE) with a QemuConsoleClass
virtual method, allowing each console subclass to provide its own
get_label implementation.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 2 +
ui/console-priv.h | 1 -
ui/console-vc-stubs.c | 6 ---
ui/console-vc.c | 12 ++++--
ui/console.c | 101 +++++++++++++++++++++++++++-----------------------
5 files changed, 65 insertions(+), 57 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 08082389f71..395a723e318 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -129,6 +129,8 @@ void console_handle_touch_event(QemuConsole *con,
struct QemuConsoleClass {
ObjectClass parent_class;
+
+ char * (*get_label)(QemuConsole *con);
};
typedef struct ScanoutTexture {
diff --git a/ui/console-priv.h b/ui/console-priv.h
index 43ceb8122f1..2c2cfd99570 100644
--- a/ui/console-priv.h
+++ b/ui/console-priv.h
@@ -36,7 +36,6 @@ struct QemuConsole {
};
void qemu_text_console_update_size(QemuTextConsole *c);
-const char * qemu_text_console_get_label(QemuTextConsole *c);
void qemu_text_console_update_cursor(void);
void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym);
diff --git a/ui/console-vc-stubs.c b/ui/console-vc-stubs.c
index b63e2fb2345..8a7f19c1f44 100644
--- a/ui/console-vc-stubs.c
+++ b/ui/console-vc-stubs.c
@@ -14,12 +14,6 @@ void qemu_text_console_update_size(QemuTextConsole *c)
{
}
-const char *
-qemu_text_console_get_label(QemuTextConsole *c)
-{
- return NULL;
-}
-
void qemu_text_console_update_cursor(void)
{
}
diff --git a/ui/console-vc.c b/ui/console-vc.c
index bd816d45759..7b9acf1adb1 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -125,10 +125,12 @@ static const pixman_color_t color_table_rgb[2][8] = {
static bool cursor_visible_phase;
static QEMUTimer *cursor_timer;
-const char *
-qemu_text_console_get_label(QemuTextConsole *c)
+static char *
+qemu_text_console_get_label(QemuConsole *c)
{
- return c->chr ? c->chr->label : NULL;
+ QemuTextConsole *tc = QEMU_TEXT_CONSOLE(c);
+
+ return tc->chr ? g_strdup(tc->chr->label) : NULL;
}
static void qemu_console_fill_rect(QemuConsole *con, int posx, int posy,
@@ -1114,9 +1116,13 @@ qemu_text_console_finalize(Object *obj)
static void
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;
}
static const GraphicHwOps text_console_ops = {
diff --git a/ui/console.c b/ui/console.c
index f445db11389..24e4761e1f9 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -436,9 +436,58 @@ qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, &c->head, errp);
}
+static bool
+qemu_graphic_console_is_multihead(QemuGraphicConsole *c)
+{
+ QemuConsole *con;
+
+ QTAILQ_FOREACH(con, &consoles, next) {
+ QemuGraphicConsole *candidate;
+
+ if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
+ continue;
+ }
+
+ candidate = QEMU_GRAPHIC_CONSOLE(con);
+ if (candidate->device != c->device) {
+ continue;
+ }
+
+ if (candidate->head != c->head) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static char *
+qemu_graphic_console_get_label(QemuConsole *con)
+{
+ QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(con);
+
+ if (c->device) {
+ DeviceState *dev;
+ bool multihead;
+
+ dev = DEVICE(c->device);
+ multihead = qemu_graphic_console_is_multihead(c);
+ if (multihead) {
+ return g_strdup_printf("%s.%d", dev->id ?
+ dev->id :
+ object_get_typename(c->device),
+ c->head);
+ } else {
+ return g_strdup(dev->id ? : object_get_typename(c->device));
+ }
+ }
+ return g_strdup("VGA");
+}
+
static void
qemu_graphic_console_class_init(ObjectClass *oc, const void *data)
{
+ QemuConsoleClass *cc = QEMU_CONSOLE_CLASS(oc);
+
object_class_property_add_link(oc, "device", TYPE_DEVICE,
offsetof(QemuGraphicConsole, device),
object_property_allow_set_link,
@@ -446,6 +495,8 @@ qemu_graphic_console_class_init(ObjectClass *oc, const void *data)
object_class_property_add(oc, "head", "uint32",
qemu_graphic_console_prop_get_head,
NULL, NULL, NULL);
+
+ cc->get_label = qemu_graphic_console_get_label;
}
static void
@@ -1347,56 +1398,12 @@ bool qemu_console_is_gl_blocked(QemuConsole *con)
return con->gl_block;
}
-static bool qemu_graphic_console_is_multihead(QemuGraphicConsole *c)
-{
- QemuConsole *con;
-
- QTAILQ_FOREACH(con, &consoles, next) {
- QemuGraphicConsole *candidate;
-
- if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
- continue;
- }
-
- candidate = QEMU_GRAPHIC_CONSOLE(con);
- if (candidate->device != c->device) {
- continue;
- }
-
- if (candidate->head != c->head) {
- return true;
- }
- }
- return false;
-}
-
char *qemu_console_get_label(QemuConsole *con)
{
- if (QEMU_IS_GRAPHIC_CONSOLE(con)) {
- QemuGraphicConsole *c = QEMU_GRAPHIC_CONSOLE(con);
- if (c->device) {
- DeviceState *dev;
- bool multihead;
-
- dev = DEVICE(c->device);
- multihead = qemu_graphic_console_is_multihead(c);
- if (multihead) {
- return g_strdup_printf("%s.%d", dev->id ?
- dev->id :
- object_get_typename(c->device),
- c->head);
- } else {
- return g_strdup(dev->id ? : object_get_typename(c->device));
- }
- }
- return g_strdup("VGA");
- } else if (QEMU_IS_TEXT_CONSOLE(con)) {
- const char *label = qemu_text_console_get_label(QEMU_TEXT_CONSOLE(con));
- if (label) {
- return g_strdup(label);
- }
+ char *label = QEMU_CONSOLE_GET_CLASS(con)->get_label(con);
+ if (label) {
+ return label;
}
-
return g_strdup_printf("vc%d", con->index);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 13/67] ui/console-vc: introduce QemuVT100
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (11 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 14/67] ui/console-vc: set vt100 associated pixman image Marc-André Lureau
` (53 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Start moving VT100 emulation specific code in a different structure.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 399 +++++++++++++++++++++++++++++---------------------------
1 file changed, 210 insertions(+), 189 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 7b9acf1adb1..cc061dff769 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -48,9 +48,7 @@ enum TTYState {
TTY_STATE_OSC,
};
-typedef struct QemuTextConsole {
- QemuConsole parent;
-
+typedef struct QemuVT100 {
int width;
int height;
int total_height;
@@ -66,7 +64,12 @@ typedef struct QemuTextConsole {
int update_y0;
int update_x1;
int update_y1;
+} QemuVT100;
+typedef struct QemuTextConsole {
+ QemuConsole parent;
+
+ QemuVT100 vt;
Chardev *chr;
/* fifo for key pressed */
Fifo8 out_fifo;
@@ -183,37 +186,40 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
static void invalidate_xy(QemuTextConsole *s, int x, int y)
{
+ QemuVT100 *vt = &s->vt;
+
if (!qemu_console_is_visible(QEMU_CONSOLE(s))) {
return;
}
- if (s->update_x0 > x * FONT_WIDTH)
- s->update_x0 = x * FONT_WIDTH;
- if (s->update_y0 > y * FONT_HEIGHT)
- s->update_y0 = y * FONT_HEIGHT;
- if (s->update_x1 < (x + 1) * FONT_WIDTH)
- s->update_x1 = (x + 1) * FONT_WIDTH;
- if (s->update_y1 < (y + 1) * FONT_HEIGHT)
- s->update_y1 = (y + 1) * FONT_HEIGHT;
+ if (vt->update_x0 > x * FONT_WIDTH)
+ vt->update_x0 = x * FONT_WIDTH;
+ if (vt->update_y0 > y * FONT_HEIGHT)
+ vt->update_y0 = y * FONT_HEIGHT;
+ if (vt->update_x1 < (x + 1) * FONT_WIDTH)
+ vt->update_x1 = (x + 1) * FONT_WIDTH;
+ if (vt->update_y1 < (y + 1) * FONT_HEIGHT)
+ vt->update_y1 = (y + 1) * FONT_HEIGHT;
}
static void console_show_cursor(QemuTextConsole *s, int show)
{
+ QemuVT100 *vt = &s->vt;
TextCell *c;
int y, y1;
- int x = s->x;
+ int x = vt->x;
- s->cursor_invalidate = 1;
+ vt->cursor_invalidate = 1;
- if (x >= s->width) {
- x = s->width - 1;
+ if (x >= vt->width) {
+ x = vt->width - 1;
}
- y1 = (s->y_base + s->y) % s->total_height;
- y = y1 - s->y_displayed;
+ y1 = (vt->y_base + vt->y) % vt->total_height;
+ y = y1 - vt->y_displayed;
if (y < 0) {
- y += s->total_height;
+ y += vt->total_height;
}
- if (y < s->height) {
- c = &s->cells[y1 * s->width + x];
+ if (y < vt->height) {
+ c = &vt->cells[y1 * vt->width + x];
if (show && cursor_visible_phase) {
TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
@@ -228,27 +234,28 @@ static void console_show_cursor(QemuTextConsole *s, int show)
static void console_refresh(QemuTextConsole *s)
{
DisplaySurface *surface = qemu_console_surface(QEMU_CONSOLE(s));
+ QemuVT100 *vt = &s->vt;
TextCell *c;
int x, y, y1;
assert(surface);
- s->text_x[0] = 0;
- s->text_y[0] = 0;
- s->text_x[1] = s->width - 1;
- s->text_y[1] = s->height - 1;
- s->cursor_invalidate = 1;
+ vt->text_x[0] = 0;
+ vt->text_y[0] = 0;
+ vt->text_x[1] = vt->width - 1;
+ vt->text_y[1] = vt->height - 1;
+ vt->cursor_invalidate = 1;
qemu_console_fill_rect(QEMU_CONSOLE(s), 0, 0, surface_width(surface), surface_height(surface),
color_table_rgb[0][QEMU_COLOR_BLACK]);
- y1 = s->y_displayed;
- for (y = 0; y < s->height; y++) {
- c = s->cells + y1 * s->width;
- for (x = 0; x < s->width; x++) {
+ y1 = vt->y_displayed;
+ for (y = 0; y < vt->height; y++) {
+ c = vt->cells + y1 * vt->width;
+ for (x = 0; x < vt->width; x++) {
vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch,
&(c->t_attrib));
c++;
}
- if (++y1 == s->total_height) {
+ if (++y1 == vt->total_height) {
y1 = 0;
}
}
@@ -259,28 +266,29 @@ static void console_refresh(QemuTextConsole *s)
static void console_scroll(QemuTextConsole *s, int ydelta)
{
+ QemuVT100 *vt = &s->vt;
int i, y1;
if (ydelta > 0) {
for(i = 0; i < ydelta; i++) {
- if (s->y_displayed == s->y_base)
+ if (vt->y_displayed == vt->y_base)
break;
- if (++s->y_displayed == s->total_height)
- s->y_displayed = 0;
+ if (++vt->y_displayed == vt->total_height)
+ vt->y_displayed = 0;
}
} else {
ydelta = -ydelta;
- i = s->backscroll_height;
- if (i > s->total_height - s->height)
- i = s->total_height - s->height;
- y1 = s->y_base - i;
+ i = vt->backscroll_height;
+ if (i > vt->total_height - vt->height)
+ i = vt->total_height - vt->height;
+ y1 = vt->y_base - i;
if (y1 < 0)
- y1 += s->total_height;
+ y1 += vt->total_height;
for(i = 0; i < ydelta; i++) {
- if (s->y_displayed == y1)
+ if (vt->y_displayed == y1)
break;
- if (--s->y_displayed < 0)
- s->y_displayed = s->total_height - 1;
+ if (--vt->y_displayed < 0)
+ vt->y_displayed = vt->total_height - 1;
}
}
console_refresh(s);
@@ -306,6 +314,7 @@ static void kbd_send_chars(QemuTextConsole *s)
/* 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;
uint32_t num_free;
@@ -338,13 +347,13 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
*q++ = '\033';
*q++ = '[';
*q++ = keysym & 0xff;
- } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
+ } else if (vt->echo && (keysym == '\r' || keysym == '\n')) {
qemu_chr_write(s->chr, (uint8_t *)"\r", 1, true);
*q++ = '\n';
} else {
*q++ = keysym;
}
- if (s->echo) {
+ if (vt->echo) {
qemu_chr_write(s->chr, buf, q - buf, true);
}
num_free = fifo8_num_free(&s->out_fifo);
@@ -357,29 +366,30 @@ 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 (s->text_x[0] <= s->text_x[1]) {
- src = (s->y_base + s->text_y[0]) * s->width;
- chardata += s->text_y[0] * s->width;
- for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
- for (j = 0; j < s->width; 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++) {
console_write_ch(chardata ++,
- ATTR2CHTYPE(s->cells[src].ch,
- s->cells[src].t_attrib.fgcol,
- s->cells[src].t_attrib.bgcol,
- s->cells[src].t_attrib.bold));
+ ATTR2CHTYPE(vt->cells[src].ch,
+ vt->cells[src].t_attrib.fgcol,
+ vt->cells[src].t_attrib.bgcol,
+ vt->cells[src].t_attrib.bold));
}
- dpy_text_update(QEMU_CONSOLE(s), s->text_x[0], s->text_y[0],
- s->text_x[1] - s->text_x[0], i - s->text_y[0]);
- s->text_x[0] = s->width;
- s->text_y[0] = s->height;
- s->text_x[1] = 0;
- s->text_y[1] = 0;
+ 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;
}
- if (s->cursor_invalidate) {
- dpy_text_cursor(QEMU_CONSOLE(s), s->x, s->y);
- s->cursor_invalidate = 0;
+ if (vt->cursor_invalidate) {
+ dpy_text_cursor(QEMU_CONSOLE(s), vt->x, vt->y);
+ vt->cursor_invalidate = 0;
}
}
@@ -393,76 +403,77 @@ static void text_console_resize(QemuTextConsole *t)
w = surface_width(s->surface) / FONT_WIDTH;
h = surface_height(s->surface) / FONT_HEIGHT;
- if (w == t->width && h == t->height) {
+ if (w == t->vt.width && h == t->vt.height) {
return;
}
- last_width = t->width;
- t->width = w;
- t->height = h;
+ last_width = t->vt.width;
+ t->vt.width = w;
+ t->vt.height = h;
- w1 = MIN(t->width, last_width);
+ w1 = MIN(t->vt.width, last_width);
- cells = g_new(TextCell, t->width * t->total_height + 1);
- for (y = 0; y < t->total_height; y++) {
- c = &cells[y * t->width];
+ cells = g_new(TextCell, t->vt.width * t->vt.total_height + 1);
+ for (y = 0; y < t->vt.total_height; y++) {
+ c = &cells[y * t->vt.width];
if (w1 > 0) {
- c1 = &t->cells[y * last_width];
+ c1 = &t->vt.cells[y * last_width];
for (x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
- for (x = w1; x < t->width; x++) {
+ for (x = w1; x < t->vt.width; x++) {
c->ch = ' ';
c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
c++;
}
}
- g_free(t->cells);
- t->cells = cells;
+ g_free(t->vt.cells);
+ t->vt.cells = cells;
}
static void vc_put_lf(VCChardev *vc)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
TextCell *c;
int x, y1;
- s->y++;
- if (s->y >= s->height) {
- s->y = s->height - 1;
+ vt->y++;
+ if (vt->y >= vt->height) {
+ vt->y = vt->height - 1;
- if (s->y_displayed == s->y_base) {
- if (++s->y_displayed == s->total_height)
- s->y_displayed = 0;
+ if (vt->y_displayed == vt->y_base) {
+ if (++vt->y_displayed == vt->total_height)
+ vt->y_displayed = 0;
}
- if (++s->y_base == s->total_height)
- s->y_base = 0;
- if (s->backscroll_height < s->total_height)
- s->backscroll_height++;
- y1 = (s->y_base + s->height - 1) % s->total_height;
- c = &s->cells[y1 * s->width];
- for(x = 0; x < s->width; x++) {
+ if (++vt->y_base == vt->total_height)
+ vt->y_base = 0;
+ if (vt->backscroll_height < vt->total_height)
+ vt->backscroll_height++;
+ y1 = (vt->y_base + vt->height - 1) % vt->total_height;
+ c = &vt->cells[y1 * vt->width];
+ for(x = 0; x < vt->width; x++) {
c->ch = ' ';
c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
c++;
}
- if (s->y_displayed == s->y_base) {
- s->text_x[0] = 0;
- s->text_y[0] = 0;
- s->text_x[1] = s->width - 1;
- s->text_y[1] = s->height - 1;
+ if (vt->y_displayed == vt->y_base) {
+ vt->text_x[0] = 0;
+ vt->text_y[0] = 0;
+ vt->text_x[1] = vt->width - 1;
+ vt->text_y[1] = vt->height - 1;
qemu_console_bitblt(QEMU_CONSOLE(s), 0, FONT_HEIGHT, 0, 0,
- s->width * FONT_WIDTH,
- (s->height - 1) * FONT_HEIGHT);
- qemu_console_fill_rect(QEMU_CONSOLE(s), 0, (s->height - 1) * FONT_HEIGHT,
- s->width * FONT_WIDTH, FONT_HEIGHT,
+ vt->width * FONT_WIDTH,
+ (vt->height - 1) * FONT_HEIGHT);
+ qemu_console_fill_rect(QEMU_CONSOLE(s), 0, (vt->height - 1) * FONT_HEIGHT,
+ vt->width * FONT_WIDTH, FONT_HEIGHT,
color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
- s->update_x0 = 0;
- s->update_y0 = 0;
- s->update_x1 = s->width * FONT_WIDTH;
- s->update_y1 = s->height * FONT_HEIGHT;
+ vt->update_x0 = 0;
+ vt->update_y0 = 0;
+ vt->update_x1 = vt->width * FONT_WIDTH;
+ vt->update_y1 = vt->height * FONT_HEIGHT;
}
}
}
@@ -567,24 +578,25 @@ static void vc_handle_escape(VCChardev *vc)
static void vc_update_xy(VCChardev *vc, int x, int y)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
TextCell *c;
int y1, y2;
- s->text_x[0] = MIN(s->text_x[0], x);
- s->text_x[1] = MAX(s->text_x[1], x);
- s->text_y[0] = MIN(s->text_y[0], y);
- s->text_y[1] = MAX(s->text_y[1], y);
+ vt->text_x[0] = MIN(vt->text_x[0], x);
+ vt->text_x[1] = MAX(vt->text_x[1], x);
+ vt->text_y[0] = MIN(vt->text_y[0], y);
+ vt->text_y[1] = MAX(vt->text_y[1], y);
- y1 = (s->y_base + y) % s->total_height;
- y2 = y1 - s->y_displayed;
+ y1 = (vt->y_base + y) % vt->total_height;
+ y2 = y1 - vt->y_displayed;
if (y2 < 0) {
- y2 += s->total_height;
+ y2 += vt->total_height;
}
- if (y2 < s->height) {
- if (x >= s->width) {
- x = s->width - 1;
+ if (y2 < vt->height) {
+ if (x >= vt->width) {
+ x = vt->width - 1;
}
- c = &s->cells[y1 * s->width + x];
+ c = &vt->cells[y1 * vt->width + x];
vga_putcharxy(QEMU_CONSOLE(s), x, y2, c->ch,
&(c->t_attrib));
invalidate_xy(s, x, y2);
@@ -594,11 +606,12 @@ static void vc_update_xy(VCChardev *vc, int x, int y)
static void vc_clear_xy(VCChardev *vc, int x, int y)
{
QemuTextConsole *s = vc->console;
- int y1 = (s->y_base + y) % s->total_height;
- if (x >= s->width) {
- x = s->width - 1;
+ QemuVT100 *vt = &s->vt;
+ int y1 = (vt->y_base + y) % vt->total_height;
+ if (x >= vt->width) {
+ x = vt->width - 1;
}
- TextCell *c = &s->cells[y1 * s->width + x];
+ TextCell *c = &vt->cells[y1 * vt->width + x];
c->ch = ' ';
c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
vc_update_xy(vc, x, y);
@@ -647,19 +660,20 @@ static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
static void vc_put_one(VCChardev *vc, int ch)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
TextCell *c;
int y1;
- if (s->x >= s->width) {
+ if (vt->x >= vt->width) {
/* line wrap */
- s->x = 0;
+ vt->x = 0;
vc_put_lf(vc);
}
- y1 = (s->y_base + s->y) % s->total_height;
- c = &s->cells[y1 * s->width + s->x];
+ 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, s->x, s->y);
- s->x++;
+ vc_update_xy(vc, vt->x, vt->y);
+ vt->x++;
}
static void vc_respond_str(VCChardev *vc, const char *buf)
@@ -673,6 +687,7 @@ static void vc_respond_str(VCChardev *vc, const char *buf)
static void vc_set_cursor(VCChardev *vc, int x, int y)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
if (x < 0) {
x = 0;
@@ -680,15 +695,15 @@ static void vc_set_cursor(VCChardev *vc, int x, int y)
if (y < 0) {
y = 0;
}
- if (y >= s->height) {
- y = s->height - 1;
+ if (y >= vt->height) {
+ y = vt->height - 1;
}
- if (x >= s->width) {
- x = s->width - 1;
+ if (x >= vt->width) {
+ x = vt->width - 1;
}
- s->x = x;
- s->y = y;
+ vt->x = x;
+ vt->y = y;
}
/**
@@ -700,6 +715,7 @@ static void vc_set_cursor(VCChardev *vc, int x, int y)
static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
TextCell *c1, *c2;
unsigned int x1, x2, y;
unsigned int end, len;
@@ -707,28 +723,28 @@ static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
if (!nr) {
nr = 1;
}
- if (nr > s->width - s->x) {
- nr = s->width - s->x;
+ if (nr > vt->width - vt->x) {
+ nr = vt->width - vt->x;
if (!nr) {
return;
}
}
- x1 = s->x;
- x2 = s->x + nr;
- len = s->width - x2;
+ x1 = vt->x;
+ x2 = vt->x + nr;
+ len = vt->width - x2;
if (len) {
- y = (s->y_base + s->y) % s->total_height;
- c1 = &s->cells[y * s->width + x1];
- c2 = &s->cells[y * s->width + x2];
+ y = (vt->y_base + vt->y) % vt->total_height;
+ c1 = &vt->cells[y * vt->width + x1];
+ 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, s->y);
+ vc_update_xy(vc, x1, vt->y);
}
}
/* Clear the rest */
- for (; x1 < s->width; x1++) {
- vc_clear_xy(vc, x1, s->y);
+ for (; x1 < vt->width; x1++) {
+ vc_clear_xy(vc, x1, vt->y);
}
}
@@ -741,6 +757,7 @@ static void vc_csi_P(struct VCChardev *vc, unsigned int nr)
static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
TextCell *c1, *c2;
unsigned int x1, x2, y;
unsigned int end, len;
@@ -748,28 +765,28 @@ static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
if (!nr) {
nr = 1;
}
- if (nr > s->width - s->x) {
- nr = s->width - s->x;
+ if (nr > vt->width - vt->x) {
+ nr = vt->width - vt->x;
if (!nr) {
return;
}
}
- x1 = s->x + nr;
- x2 = s->x;
- len = s->width - x1;
+ x1 = vt->x + nr;
+ x2 = vt->x;
+ len = vt->width - x1;
if (len) {
- y = (s->y_base + s->y) % s->total_height;
- c1 = &s->cells[y * s->width + x1];
- c2 = &s->cells[y * s->width + x2];
+ y = (vt->y_base + vt->y) % vt->total_height;
+ c1 = &vt->cells[y * vt->width + x1];
+ 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, s->y);
+ vc_update_xy(vc, x1, vt->y);
}
}
/* Insert blanks */
- for (x1 = s->x; x1 < s->x + nr; x1++) {
- vc_clear_xy(vc, x1, s->y);
+ for (x1 = vt->x; x1 < vt->x + nr; x1++) {
+ vc_clear_xy(vc, x1, vt->y);
}
}
@@ -779,9 +796,10 @@ static void vc_csi_at(struct VCChardev *vc, unsigned int nr)
static void vc_save_cursor(VCChardev *vc)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
- vc->x_saved = s->x;
- vc->y_saved = s->y;
+ vc->x_saved = vt->x;
+ vc->y_saved = vt->y;
vc->t_attrib_saved = vc->t_attrib;
}
@@ -792,15 +810,17 @@ static void vc_save_cursor(VCChardev *vc)
static void vc_restore_cursor(VCChardev *vc)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
- s->x = vc->x_saved;
- s->y = vc->y_saved;
+ vt->x = vc->x_saved;
+ vt->y = vc->y_saved;
vc->t_attrib = vc->t_attrib_saved;
}
static void vc_putchar(VCChardev *vc, int ch)
{
QemuTextConsole *s = vc->console;
+ QemuVT100 *vt = &s->vt;
int i;
int x, y;
g_autofree char *response = NULL;
@@ -827,21 +847,21 @@ static void vc_putchar(VCChardev *vc, int ch)
vc->utf8_state = BH_UTF8_ACCEPT;
switch(ch) {
case '\r': /* carriage return */
- s->x = 0;
+ vt->x = 0;
break;
case '\n': /* newline */
vc_put_lf(vc);
break;
case '\b': /* backspace */
- if (s->x > 0)
- s->x--;
+ if (vt->x > 0)
+ vt->x--;
break;
case '\t': /* tabspace */
- if (s->x + (8 - (s->x % 8)) > s->width) {
- s->x = 0;
+ if (vt->x + (8 - (vt->x % 8)) > vt->width) {
+ vt->x = 0;
vc_put_lf(vc);
} else {
- s->x = s->x + (8 - (s->x % 8));
+ vt->x = vt->x + (8 - (vt->x % 8));
}
break;
case '\a': /* alert aka. bell */
@@ -909,32 +929,32 @@ static void vc_putchar(VCChardev *vc, int ch)
if (vc->esc_params[0] == 0) {
vc->esc_params[0] = 1;
}
- vc_set_cursor(vc, s->x, s->y - vc->esc_params[0]);
+ vc_set_cursor(vc, vt->x, vt->y - vc->esc_params[0]);
break;
case 'B':
/* move cursor down */
if (vc->esc_params[0] == 0) {
vc->esc_params[0] = 1;
}
- vc_set_cursor(vc, s->x, s->y + vc->esc_params[0]);
+ vc_set_cursor(vc, vt->x, vt->y + vc->esc_params[0]);
break;
case 'C':
/* move cursor right */
if (vc->esc_params[0] == 0) {
vc->esc_params[0] = 1;
}
- vc_set_cursor(vc, s->x + vc->esc_params[0], s->y);
+ vc_set_cursor(vc, vt->x + vc->esc_params[0], vt->y);
break;
case 'D':
/* move cursor left */
if (vc->esc_params[0] == 0) {
vc->esc_params[0] = 1;
}
- vc_set_cursor(vc, s->x - vc->esc_params[0], s->y);
+ vc_set_cursor(vc, vt->x - vc->esc_params[0], vt->y);
break;
case 'G':
/* move cursor to column */
- vc_set_cursor(vc, vc->esc_params[0] - 1, s->y);
+ vc_set_cursor(vc, vc->esc_params[0] - 1, vt->y);
break;
case 'f':
case 'H':
@@ -945,9 +965,9 @@ static void vc_putchar(VCChardev *vc, int ch)
switch (vc->esc_params[0]) {
case 0:
/* clear to end of screen */
- for (y = s->y; y < s->height; y++) {
- for (x = 0; x < s->width; x++) {
- if (y == s->y && x < s->x) {
+ for (y = vt->y; y < vt->height; y++) {
+ for (x = 0; x < vt->width; x++) {
+ if (y == vt->y && x < vt->x) {
continue;
}
vc_clear_xy(vc, x, y);
@@ -956,9 +976,9 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
case 1:
/* clear from beginning of screen */
- for (y = 0; y <= s->y; y++) {
- for (x = 0; x < s->width; x++) {
- if (y == s->y && x > s->x) {
+ for (y = 0; y <= vt->y; y++) {
+ for (x = 0; x < vt->width; x++) {
+ if (y == vt->y && x > vt->x) {
break;
}
vc_clear_xy(vc, x, y);
@@ -967,8 +987,8 @@ static void vc_putchar(VCChardev *vc, int ch)
break;
case 2:
/* clear entire screen */
- for (y = 0; y < s->height; y++) {
- for (x = 0; x < s->width; x++) {
+ for (y = 0; y < vt->height; y++) {
+ for (x = 0; x < vt->width; x++) {
vc_clear_xy(vc, x, y);
}
}
@@ -979,20 +999,20 @@ static void vc_putchar(VCChardev *vc, int ch)
switch (vc->esc_params[0]) {
case 0:
/* clear to eol */
- for(x = s->x; x < s->width; x++) {
- vc_clear_xy(vc, x, s->y);
+ for(x = vt->x; x < vt->width; x++) {
+ vc_clear_xy(vc, x, vt->y);
}
break;
case 1:
/* clear from beginning of line */
- for (x = 0; x <= s->x && x < s->width; x++) {
- vc_clear_xy(vc, x, s->y);
+ for (x = 0; x <= vt->x && x < vt->width; x++) {
+ vc_clear_xy(vc, x, vt->y);
}
break;
case 2:
/* clear entire line */
- for(x = 0; x < s->width; x++) {
- vc_clear_xy(vc, x, s->y);
+ for(x = 0; x < vt->width; x++) {
+ vc_clear_xy(vc, x, vt->y);
}
break;
}
@@ -1012,7 +1032,7 @@ static void vc_putchar(VCChardev *vc, int ch)
case 6:
/* report cursor position */
response = g_strdup_printf("\033[%d;%dR",
- s->y + 1, s->x + 1);
+ vt->y + 1, vt->x + 1);
vc_respond_str(vc, response);
break;
}
@@ -1063,21 +1083,22 @@ 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;
- s->update_x0 = s->width * FONT_WIDTH;
- s->update_y0 = s->height * FONT_HEIGHT;
- s->update_x1 = 0;
- s->update_y1 = 0;
+ vt->update_x0 = vt->width * FONT_WIDTH;
+ vt->update_y0 = vt->height * FONT_HEIGHT;
+ vt->update_x1 = 0;
+ vt->update_y1 = 0;
console_show_cursor(s, 0);
for(i = 0; i < len; i++) {
vc_putchar(drv, buf[i]);
}
console_show_cursor(s, 1);
- if (s->update_x0 < s->update_x1) {
- dpy_gfx_update(QEMU_CONSOLE(s), s->update_x0, s->update_y0,
- s->update_x1 - s->update_x0,
- s->update_y1 - s->update_y0);
+ if (vt->update_x0 < vt->update_x1) {
+ dpy_gfx_update(QEMU_CONSOLE(s), vt->update_x0, vt->update_y0,
+ vt->update_x1 - vt->update_x0,
+ vt->update_y1 - vt->update_y0);
}
return len;
}
@@ -1136,7 +1157,7 @@ qemu_text_console_init(Object *obj)
QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
fifo8_create(&c->out_fifo, 16);
- c->total_height = DEFAULT_BACKSCROLL;
+ c->vt.total_height = DEFAULT_BACKSCROLL;
QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
QEMU_CONSOLE(c)->hw = c;
}
@@ -1167,12 +1188,12 @@ static void vc_chr_set_echo(Chardev *chr, bool echo)
{
VCChardev *drv = VC_CHARDEV(chr);
- drv->console->echo = echo;
+ drv->console->vt.echo = echo;
}
void qemu_text_console_update_size(QemuTextConsole *c)
{
- dpy_text_resize(QEMU_CONSOLE(c), c->width, c->height);
+ dpy_text_resize(QEMU_CONSOLE(c), c->vt.width, c->vt.height);
}
static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 14/67] ui/console-vc: set vt100 associated pixman image
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (12 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 13/67] ui/console-vc: introduce QemuVT100 Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 15/67] ui/console-vc: vga_putcharxy()->vt100_putcharxy() Marc-André Lureau
` (52 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Start removing dependency on DisplaySurface for vt100 handling.
Note that before, the rendering is done on the current DisplaySurface.
It's not obvious the QemuTextConsole associated surface isn't changed
over time, in particular if it was doing resize. But
qemu_console_resize() is only implemented for QemuGraphicConsole.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 54 +++++++++++++++++++++++++-----------------------------
1 file changed, 25 insertions(+), 29 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index cc061dff769..267620689e4 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -49,6 +49,8 @@ enum TTYState {
};
typedef struct QemuVT100 {
+ pixman_image_t *image;
+
int width;
int height;
int total_height;
@@ -136,28 +138,22 @@ qemu_text_console_get_label(QemuConsole *c)
return tc->chr ? g_strdup(tc->chr->label) : NULL;
}
-static void qemu_console_fill_rect(QemuConsole *con, int posx, int posy,
- int width, int height, pixman_color_t color)
+static void image_fill_rect(pixman_image_t *image, int posx, int posy,
+ int width, int height, pixman_color_t color)
{
- DisplaySurface *surface = qemu_console_surface(con);
pixman_rectangle16_t rect = {
.x = posx, .y = posy, .width = width, .height = height
};
- assert(surface);
- pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
- &color, 1, &rect);
+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, image, &color, 1, &rect);
}
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
-static void qemu_console_bitblt(QemuConsole *con,
- int xs, int ys, int xd, int yd, int w, int h)
+static void image_bitblt(pixman_image_t *image,
+ int xs, int ys, int xd, int yd, int w, int h)
{
- DisplaySurface *surface = qemu_console_surface(con);
-
- assert(surface);
pixman_image_composite(PIXMAN_OP_SRC,
- surface->image, NULL, surface->image,
+ image, NULL, image,
xs, ys, 0, 0, xd, yd, w, h);
}
@@ -165,10 +161,10 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
TextAttributes *t_attrib)
{
static pixman_image_t *glyphs[256];
- DisplaySurface *surface = qemu_console_surface(s);
+ pixman_image_t *image = QEMU_TEXT_CONSOLE(s)->vt.image;
pixman_color_t fgcol, bgcol;
- assert(surface);
+ assert(image);
if (t_attrib->invers) {
bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
@@ -180,7 +176,7 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
if (!glyphs[ch]) {
glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
}
- qemu_pixman_glyph_render(glyphs[ch], surface->image,
+ qemu_pixman_glyph_render(glyphs[ch], image,
&fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
}
@@ -233,20 +229,20 @@ static void console_show_cursor(QemuTextConsole *s, int show)
static void console_refresh(QemuTextConsole *s)
{
- DisplaySurface *surface = qemu_console_surface(QEMU_CONSOLE(s));
QemuVT100 *vt = &s->vt;
TextCell *c;
int x, y, y1;
+ int w = pixman_image_get_width(vt->image);
+ int h = pixman_image_get_height(vt->image);
- assert(surface);
vt->text_x[0] = 0;
vt->text_y[0] = 0;
vt->text_x[1] = vt->width - 1;
vt->text_y[1] = vt->height - 1;
vt->cursor_invalidate = 1;
- qemu_console_fill_rect(QEMU_CONSOLE(s), 0, 0, surface_width(surface), surface_height(surface),
- color_table_rgb[0][QEMU_COLOR_BLACK]);
+ image_fill_rect(vt->image, 0, 0, w, h,
+ color_table_rgb[0][QEMU_COLOR_BLACK]);
y1 = vt->y_displayed;
for (y = 0; y < vt->height; y++) {
c = vt->cells + y1 * vt->width;
@@ -260,8 +256,7 @@ static void console_refresh(QemuTextConsole *s)
}
}
console_show_cursor(s, 1);
- dpy_gfx_update(QEMU_CONSOLE(s), 0, 0,
- surface_width(surface), surface_height(surface));
+ dpy_gfx_update(QEMU_CONSOLE(s), 0, 0, w, h);
}
static void console_scroll(QemuTextConsole *s, int ydelta)
@@ -401,8 +396,9 @@ static void text_console_resize(QemuTextConsole *t)
assert(s->scanout.kind == SCANOUT_SURFACE);
- w = surface_width(s->surface) / FONT_WIDTH;
- h = surface_height(s->surface) / FONT_HEIGHT;
+ t->vt.image = s->surface->image;
+ w = pixman_image_get_width(t->vt.image) / FONT_WIDTH;
+ h = pixman_image_get_height(t->vt.image) / FONT_HEIGHT;
if (w == t->vt.width && h == t->vt.height) {
return;
}
@@ -464,12 +460,12 @@ static void vc_put_lf(VCChardev *vc)
vt->text_x[1] = vt->width - 1;
vt->text_y[1] = vt->height - 1;
- qemu_console_bitblt(QEMU_CONSOLE(s), 0, FONT_HEIGHT, 0, 0,
- vt->width * FONT_WIDTH,
- (vt->height - 1) * FONT_HEIGHT);
- qemu_console_fill_rect(QEMU_CONSOLE(s), 0, (vt->height - 1) * FONT_HEIGHT,
- vt->width * FONT_WIDTH, FONT_HEIGHT,
- color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
+ image_bitblt(vt->image, 0, FONT_HEIGHT, 0, 0,
+ vt->width * FONT_WIDTH,
+ (vt->height - 1) * FONT_HEIGHT);
+ image_fill_rect(vt->image, 0, (vt->height - 1) * FONT_HEIGHT,
+ vt->width * FONT_WIDTH, FONT_HEIGHT,
+ color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
vt->update_x0 = 0;
vt->update_y0 = 0;
vt->update_x1 = vt->width * FONT_WIDTH;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 15/67] ui/console-vc: vga_putcharxy()->vt100_putcharxy()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (13 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 14/67] ui/console-vc: set vt100 associated pixman image Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 16/67] ui/console-vc: make invalidate_xy() take vt100 Marc-André Lureau
` (51 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Have the character rendering function operate on QemuVT100 directly
instead of taking a QemuConsole and extracting the VT100 state
internally. This decouples glyph rendering from the console object,
continuing the QemuVT100 abstraction introduced in the previous commits.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 267620689e4..cf087c64fb2 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -157,14 +157,13 @@ static void image_bitblt(pixman_image_t *image,
xs, ys, 0, 0, xd, yd, w, h);
}
-static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
- TextAttributes *t_attrib)
+static void vt100_putcharxy(QemuVT100 *vt, int x, int y, int ch,
+ TextAttributes *t_attrib)
{
static pixman_image_t *glyphs[256];
- pixman_image_t *image = QEMU_TEXT_CONSOLE(s)->vt.image;
pixman_color_t fgcol, bgcol;
- assert(image);
+ assert(vt->image);
if (t_attrib->invers) {
bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
@@ -176,7 +175,7 @@ static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
if (!glyphs[ch]) {
glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
}
- qemu_pixman_glyph_render(glyphs[ch], image,
+ qemu_pixman_glyph_render(glyphs[ch], vt->image,
&fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
}
@@ -219,9 +218,9 @@ static void console_show_cursor(QemuTextConsole *s, int show)
if (show && cursor_visible_phase) {
TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &t_attrib);
+ vt100_putcharxy(&s->vt, x, y, c->ch, &t_attrib);
} else {
- vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch, &(c->t_attrib));
+ vt100_putcharxy(&s->vt, x, y, c->ch, &(c->t_attrib));
}
invalidate_xy(s, x, y);
}
@@ -247,7 +246,7 @@ static void console_refresh(QemuTextConsole *s)
for (y = 0; y < vt->height; y++) {
c = vt->cells + y1 * vt->width;
for (x = 0; x < vt->width; x++) {
- vga_putcharxy(QEMU_CONSOLE(s), x, y, c->ch,
+ vt100_putcharxy(vt, x, y, c->ch,
&(c->t_attrib));
c++;
}
@@ -593,7 +592,7 @@ static void vc_update_xy(VCChardev *vc, int x, int y)
x = vt->width - 1;
}
c = &vt->cells[y1 * vt->width + x];
- vga_putcharxy(QEMU_CONSOLE(s), x, y2, c->ch,
+ vt100_putcharxy(vt, x, y2, c->ch,
&(c->t_attrib));
invalidate_xy(s, x, y2);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 16/67] ui/console-vc: make invalidate_xy() take vt100
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (14 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 15/67] ui/console-vc: vga_putcharxy()->vt100_putcharxy() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 17/67] ui/console-vc: make show_cursor() " Marc-André Lureau
` (50 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
This decouples glyph rendering from the console object, continuing the
QemuVT100 abstraction introduced in the previous commits.
Style fixes.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 23 +++++++++++------------
1 file changed, 11 insertions(+), 12 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index cf087c64fb2..9566ce592f2 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -179,21 +179,20 @@ static void vt100_putcharxy(QemuVT100 *vt, int x, int y, int ch,
&fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
}
-static void invalidate_xy(QemuTextConsole *s, int x, int y)
+static void vt100_invalidate_xy(QemuVT100 *vt, int x, int y)
{
- QemuVT100 *vt = &s->vt;
-
- if (!qemu_console_is_visible(QEMU_CONSOLE(s))) {
- return;
- }
- if (vt->update_x0 > x * FONT_WIDTH)
+ if (vt->update_x0 > x * FONT_WIDTH) {
vt->update_x0 = x * FONT_WIDTH;
- if (vt->update_y0 > y * FONT_HEIGHT)
+ }
+ if (vt->update_y0 > y * FONT_HEIGHT) {
vt->update_y0 = y * FONT_HEIGHT;
- if (vt->update_x1 < (x + 1) * FONT_WIDTH)
+ }
+ if (vt->update_x1 < (x + 1) * FONT_WIDTH) {
vt->update_x1 = (x + 1) * FONT_WIDTH;
- if (vt->update_y1 < (y + 1) * FONT_HEIGHT)
+ }
+ if (vt->update_y1 < (y + 1) * FONT_HEIGHT) {
vt->update_y1 = (y + 1) * FONT_HEIGHT;
+ }
}
static void console_show_cursor(QemuTextConsole *s, int show)
@@ -222,7 +221,7 @@ static void console_show_cursor(QemuTextConsole *s, int show)
} else {
vt100_putcharxy(&s->vt, x, y, c->ch, &(c->t_attrib));
}
- invalidate_xy(s, x, y);
+ vt100_invalidate_xy(&s->vt, x, y);
}
}
@@ -594,7 +593,7 @@ 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));
- invalidate_xy(s, x, y2);
+ vt100_invalidate_xy(&s->vt, x, y2);
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 17/67] ui/console-vc: make show_cursor() take vt100
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (15 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 16/67] ui/console-vc: make invalidate_xy() take vt100 Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 18/67] ui/console-vc: decouple VT100 display updates via function pointer Marc-André Lureau
` (49 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Decouples glyph rendering from the console object,
continuing the QemuVT100 abstraction introduced in the previous commits.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 9566ce592f2..61d72a0cc27 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -195,9 +195,8 @@ static void vt100_invalidate_xy(QemuVT100 *vt, int x, int y)
}
}
-static void console_show_cursor(QemuTextConsole *s, int show)
+static void vt100_show_cursor(QemuVT100 *vt, int show)
{
- QemuVT100 *vt = &s->vt;
TextCell *c;
int y, y1;
int x = vt->x;
@@ -217,11 +216,11 @@ static void console_show_cursor(QemuTextConsole *s, int show)
if (show && cursor_visible_phase) {
TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vt100_putcharxy(&s->vt, x, y, c->ch, &t_attrib);
+ vt100_putcharxy(vt, x, y, c->ch, &t_attrib);
} else {
- vt100_putcharxy(&s->vt, x, y, c->ch, &(c->t_attrib));
+ vt100_putcharxy(vt, x, y, c->ch, &(c->t_attrib));
}
- vt100_invalidate_xy(&s->vt, x, y);
+ vt100_invalidate_xy(vt, x, y);
}
}
@@ -253,7 +252,7 @@ static void console_refresh(QemuTextConsole *s)
y1 = 0;
}
}
- console_show_cursor(s, 1);
+ vt100_show_cursor(&s->vt, 1);
dpy_gfx_update(QEMU_CONSOLE(s), 0, 0, w, h);
}
@@ -1084,11 +1083,11 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
vt->update_y0 = vt->height * FONT_HEIGHT;
vt->update_x1 = 0;
vt->update_y1 = 0;
- console_show_cursor(s, 0);
+ vt100_show_cursor(vt, 0);
for(i = 0; i < len; i++) {
vc_putchar(drv, buf[i]);
}
- console_show_cursor(s, 1);
+ vt100_show_cursor(vt, 1);
if (vt->update_x0 < vt->update_x1) {
dpy_gfx_update(QEMU_CONSOLE(s), vt->update_x0, vt->update_y0,
vt->update_x1 - vt->update_x0,
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 18/67] ui/console-vc: decouple VT100 display updates via function pointer
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (16 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 17/67] ui/console-vc: make show_cursor() " Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 19/67] ui/console-vc: console_refresh() -> vt100_refresh() Marc-André Lureau
` (48 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Replace direct dpy_gfx_update() calls from the VT100 emulation code
with an indirect call through a new image_update function pointer in
QemuVT100. This decouples the VT100 terminal emulation from the
QEMU display layer, allowing different backends to provide their own
image update implementation.
The QemuVT100 typedef is changed to a forward-declared struct so the
function pointer signature can reference QemuVT100 itself.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 61d72a0cc27..f8682d2d1dc 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -48,8 +48,11 @@ enum TTYState {
TTY_STATE_OSC,
};
-typedef struct QemuVT100 {
+typedef struct QemuVT100 QemuVT100;
+
+struct QemuVT100 {
pixman_image_t *image;
+ void (*image_update)(QemuVT100 *vt, int x, int y, int width, int height);
int width;
int height;
@@ -66,7 +69,7 @@ typedef struct QemuVT100 {
int update_y0;
int update_x1;
int update_y1;
-} QemuVT100;
+};
typedef struct QemuTextConsole {
QemuConsole parent;
@@ -224,6 +227,11 @@ static void vt100_show_cursor(QemuVT100 *vt, int show)
}
}
+static void vt100_image_update(QemuVT100 *vt, int x, int y, int width, int height)
+{
+ vt->image_update(vt, x, y, width, height);
+}
+
static void console_refresh(QemuTextConsole *s)
{
QemuVT100 *vt = &s->vt;
@@ -253,7 +261,7 @@ static void console_refresh(QemuTextConsole *s)
}
}
vt100_show_cursor(&s->vt, 1);
- dpy_gfx_update(QEMU_CONSOLE(s), 0, 0, w, h);
+ vt100_image_update(&s->vt, 0, 0, w, h);
}
static void console_scroll(QemuTextConsole *s, int ydelta)
@@ -1089,9 +1097,9 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
}
vt100_show_cursor(vt, 1);
if (vt->update_x0 < vt->update_x1) {
- dpy_gfx_update(QEMU_CONSOLE(s), vt->update_x0, vt->update_y0,
- vt->update_x1 - vt->update_x0,
- vt->update_y1 - vt->update_y0);
+ vt100_image_update(vt, vt->update_x0, vt->update_y0,
+ vt->update_x1 - vt->update_x0,
+ vt->update_y1 - vt->update_y0);
}
return len;
}
@@ -1189,6 +1197,13 @@ void qemu_text_console_update_size(QemuTextConsole *c)
dpy_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);
+}
+
static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
{
ChardevVC *vc = backend->u.vc.data;
@@ -1219,6 +1234,7 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
}
dpy_gfx_replace_surface(QEMU_CONSOLE(s), qemu_create_displaysurface(width, height));
+ s->vt.image_update = text_console_image_update;
s->chr = chr;
drv->console = s;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 19/67] ui/console-vc: console_refresh() -> vt100_refresh()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (17 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 18/67] ui/console-vc: decouple VT100 display updates via function pointer Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 20/67] ui/console-vc: move cursor blinking logic into VT100 layer Marc-André Lureau
` (47 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
This decouples glyph rendering from the console object, continuing the
QemuVT100 abstraction introduced in the previous commits.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index f8682d2d1dc..d46dcb6a678 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -232,9 +232,8 @@ static void vt100_image_update(QemuVT100 *vt, int x, int y, int width, int heigh
vt->image_update(vt, x, y, width, height);
}
-static void console_refresh(QemuTextConsole *s)
+static void vt100_refresh(QemuVT100 *vt)
{
- QemuVT100 *vt = &s->vt;
TextCell *c;
int x, y, y1;
int w = pixman_image_get_width(vt->image);
@@ -260,8 +259,8 @@ static void console_refresh(QemuTextConsole *s)
y1 = 0;
}
}
- vt100_show_cursor(&s->vt, 1);
- vt100_image_update(&s->vt, 0, 0, w, h);
+ vt100_show_cursor(vt, 1);
+ vt100_image_update(vt, 0, 0, w, h);
}
static void console_scroll(QemuTextConsole *s, int ydelta)
@@ -291,7 +290,7 @@ static void console_scroll(QemuTextConsole *s, int ydelta)
vt->y_displayed = vt->total_height - 1;
}
}
- console_refresh(s);
+ vt100_refresh(&s->vt);
}
static void kbd_send_chars(QemuTextConsole *s)
@@ -1127,7 +1126,7 @@ static void text_console_invalidate(void *opaque)
if (!QEMU_IS_FIXED_TEXT_CONSOLE(s)) {
text_console_resize(QEMU_TEXT_CONSOLE(s));
}
- console_refresh(s);
+ vt100_refresh(&s->vt);
}
static void
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 20/67] ui/console-vc: move cursor blinking logic into VT100 layer
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (18 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 19/67] ui/console-vc: console_refresh() -> vt100_refresh() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 21/67] ui/console-vc: console_scroll() -> vt100_scroll() Marc-André Lureau
` (46 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Maintain a list of QemuVT100 instances so the cursor timer can directly
iterate over them and call vt100_refresh(), instead of going through
qemu_invalidate_text_consoles() which iterated over all consoles
(including graphic ones) and called back into the generic display layer.
This removes the qemu_invalidate_text_consoles() function from
console.c, further decoupling VT100 text rendering from the console
core.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 1 -
ui/console-priv.h | 2 +-
ui/console-vc-stubs.c | 2 +-
ui/console-vc.c | 28 +++++++++++++++++++++++-----
ui/console.c | 19 +------------------
5 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 395a723e318..5b5bba46ec2 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -416,7 +416,6 @@ void qemu_console_set_window_id(QemuConsole *con, int window_id);
void qemu_console_resize(QemuConsole *con, int width, int height);
DisplaySurface *qemu_console_surface(QemuConsole *con);
void coroutine_fn qemu_console_co_wait_update(QemuConsole *con);
-int qemu_invalidate_text_consoles(void);
/* console-gl.c */
#ifdef CONFIG_OPENGL
diff --git a/ui/console-priv.h b/ui/console-priv.h
index 2c2cfd99570..8bcdb79d914 100644
--- a/ui/console-priv.h
+++ b/ui/console-priv.h
@@ -36,7 +36,7 @@ struct QemuConsole {
};
void qemu_text_console_update_size(QemuTextConsole *c);
-void qemu_text_console_update_cursor(void);
+void vt100_update_cursor(void);
void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym);
#endif
diff --git a/ui/console-vc-stubs.c b/ui/console-vc-stubs.c
index 8a7f19c1f44..d911a82f263 100644
--- a/ui/console-vc-stubs.c
+++ b/ui/console-vc-stubs.c
@@ -14,7 +14,7 @@ void qemu_text_console_update_size(QemuTextConsole *c)
{
}
-void qemu_text_console_update_cursor(void)
+void vt100_update_cursor(void)
{
}
diff --git a/ui/console-vc.c b/ui/console-vc.c
index d46dcb6a678..6694c5082f8 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -8,6 +8,7 @@
#include "qapi/error.h"
#include "qemu/fifo8.h"
#include "qemu/option.h"
+#include "qemu/queue.h"
#include "ui/console.h"
#include "ui/cp437.h"
@@ -69,8 +70,13 @@ struct QemuVT100 {
int update_y0;
int update_x1;
int update_y1;
+
+ QTAILQ_ENTRY(QemuVT100) list;
};
+static QTAILQ_HEAD(QemuVT100Head, QemuVT100) vt100s =
+ QTAILQ_HEAD_INITIALIZER(vt100s);
+
typedef struct QemuTextConsole {
QemuConsole parent;
@@ -1103,20 +1109,28 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
return len;
}
-void qemu_text_console_update_cursor(void)
+void vt100_update_cursor(void)
{
+ QemuVT100 *vt;
+
cursor_visible_phase = !cursor_visible_phase;
- if (qemu_invalidate_text_consoles()) {
- timer_mod(cursor_timer,
- qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
+ if (QTAILQ_EMPTY(&vt100s)) {
+ return;
+ }
+
+ QTAILQ_FOREACH(vt, &vt100s, list) {
+ vt100_refresh(vt);
}
+
+ timer_mod(cursor_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
}
static void
cursor_timer_cb(void *opaque)
{
- qemu_text_console_update_cursor();
+ vt100_update_cursor();
}
static void text_console_invalidate(void *opaque)
@@ -1132,6 +1146,9 @@ static void text_console_invalidate(void *opaque)
static void
qemu_text_console_finalize(Object *obj)
{
+ QemuTextConsole *s = QEMU_TEXT_CONSOLE(obj);
+
+ QTAILQ_REMOVE(&vt100s, &s->vt, list);
}
static void
@@ -1156,6 +1173,7 @@ 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;
diff --git a/ui/console.c b/ui/console.c
index 24e4761e1f9..8af1dee0e22 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -752,7 +752,7 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
} else if (QEMU_IS_TEXT_CONSOLE(dcl->con)) {
qemu_text_console_update_size(QEMU_TEXT_CONSOLE(dcl->con));
}
- qemu_text_console_update_cursor();
+ vt100_update_cursor();
}
void update_displaychangelistener(DisplayChangeListener *dcl,
@@ -1457,23 +1457,6 @@ int qemu_console_get_height(QemuConsole *con, int fallback)
}
}
-int qemu_invalidate_text_consoles(void)
-{
- QemuConsole *s;
- int count = 0;
-
- QTAILQ_FOREACH(s, &consoles, next) {
- if (qemu_console_is_graphic(s) ||
- !qemu_console_is_visible(s)) {
- continue;
- }
- count++;
- graphic_hw_invalidate(s);
- }
-
- return count;
-}
-
void qemu_console_resize(QemuConsole *s, int width, int height)
{
DisplaySurface *surface = qemu_console_surface(s);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 21/67] ui/console-vc: console_scroll() -> vt100_scroll()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (19 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 20/67] ui/console-vc: move cursor blinking logic into VT100 layer Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 22/67] ui/console-vc: refactor text_console_resize() into vt100_set_image() Marc-André Lureau
` (45 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
This decouples glyph rendering from the console object, continuing the
QemuVT100 abstraction introduced in the previous commits.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 6694c5082f8..c6846af3697 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -269,9 +269,8 @@ static void vt100_refresh(QemuVT100 *vt)
vt100_image_update(vt, 0, 0, w, h);
}
-static void console_scroll(QemuTextConsole *s, int ydelta)
+static void vt100_scroll(QemuVT100 *vt, int ydelta)
{
- QemuVT100 *vt = &s->vt;
int i, y1;
if (ydelta > 0) {
@@ -296,7 +295,7 @@ static void console_scroll(QemuTextConsole *s, int ydelta)
vt->y_displayed = vt->total_height - 1;
}
}
- vt100_refresh(&s->vt);
+ vt100_refresh(vt);
}
static void kbd_send_chars(QemuTextConsole *s)
@@ -326,16 +325,16 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
switch(keysym) {
case QEMU_KEY_CTRL_UP:
- console_scroll(s, -1);
+ vt100_scroll(&s->vt, -1);
break;
case QEMU_KEY_CTRL_DOWN:
- console_scroll(s, 1);
+ vt100_scroll(&s->vt, 1);
break;
case QEMU_KEY_CTRL_PAGEUP:
- console_scroll(s, -10);
+ vt100_scroll(&s->vt, -10);
break;
case QEMU_KEY_CTRL_PAGEDOWN:
- console_scroll(s, 10);
+ vt100_scroll(&s->vt, 10);
break;
default:
/* convert the QEMU keysym to VT100 key string */
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 22/67] ui/console-vc: refactor text_console_resize() into vt100_set_image()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (20 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 21/67] ui/console-vc: console_scroll() -> vt100_scroll() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 23/67] ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf() Marc-André Lureau
` (44 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Decouple the resize logic from QemuTextConsole by operating on
QemuVT100 and taking a pixman_image_t directly, instead of reaching
into the console's scanout surface. The callers now pass the image
explicitly, which makes the VT100 layer independent of the console
object hierarchy.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 40 +++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 21 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index c6846af3697..85c794062fc 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -12,6 +12,7 @@
#include "ui/console.h"
#include "ui/cp437.h"
+#include "pixman.h"
#include "trace.h"
#include "console-priv.h"
@@ -397,44 +398,41 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
}
}
-static void text_console_resize(QemuTextConsole *t)
+static void vt100_set_image(QemuVT100 *vt, pixman_image_t *image)
{
- QemuConsole *s = QEMU_CONSOLE(t);
TextCell *cells, *c, *c1;
int w1, x, y, last_width, w, h;
- assert(s->scanout.kind == SCANOUT_SURFACE);
-
- t->vt.image = s->surface->image;
- w = pixman_image_get_width(t->vt.image) / FONT_WIDTH;
- h = pixman_image_get_height(t->vt.image) / FONT_HEIGHT;
- if (w == t->vt.width && h == t->vt.height) {
+ vt->image = image;
+ w = pixman_image_get_width(image) / FONT_WIDTH;
+ h = pixman_image_get_height(image) / FONT_HEIGHT;
+ if (w == vt->width && h == vt->height) {
return;
}
- last_width = t->vt.width;
- t->vt.width = w;
- t->vt.height = h;
+ last_width = vt->width;
+ vt->width = w;
+ vt->height = h;
- w1 = MIN(t->vt.width, last_width);
+ w1 = MIN(vt->width, last_width);
- cells = g_new(TextCell, t->vt.width * t->vt.total_height + 1);
- for (y = 0; y < t->vt.total_height; y++) {
- c = &cells[y * t->vt.width];
+ cells = g_new(TextCell, vt->width * vt->total_height + 1);
+ for (y = 0; y < vt->total_height; y++) {
+ c = &cells[y * vt->width];
if (w1 > 0) {
- c1 = &t->vt.cells[y * last_width];
+ c1 = &vt->cells[y * last_width];
for (x = 0; x < w1; x++) {
*c++ = *c1++;
}
}
- for (x = w1; x < t->vt.width; x++) {
+ for (x = w1; x < vt->width; x++) {
c->ch = ' ';
c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
c++;
}
}
- g_free(t->vt.cells);
- t->vt.cells = cells;
+ g_free(vt->cells);
+ vt->cells = cells;
}
static void vc_put_lf(VCChardev *vc)
@@ -1137,7 +1135,7 @@ static void text_console_invalidate(void *opaque)
QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
if (!QEMU_IS_FIXED_TEXT_CONSOLE(s)) {
- text_console_resize(QEMU_TEXT_CONSOLE(s));
+ vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
}
vt100_refresh(&s->vt);
}
@@ -1257,7 +1255,7 @@ static bool vc_chr_open(Chardev *chr, ChardevBackend *backend, Error **errp)
/* set current text attributes to default */
drv->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- text_console_resize(s);
+ vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
if (chr->label) {
char *msg;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 23/67] ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (21 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 22/67] ui/console-vc: refactor text_console_resize() into vt100_set_image() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 24/67] ui/console-vc: unify the write path Marc-André Lureau
` (43 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Decouple the line-feed handling from VCChardev by operating on
QemuVT100 directly. The function no longer needs the chardev or
console pointers — callers pass &s->vt instead. This continues the
effort to make the VT100 terminal emulation self-contained.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 85c794062fc..a367622d819 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -435,10 +435,8 @@ static void vt100_set_image(QemuVT100 *vt, pixman_image_t *image)
vt->cells = cells;
}
-static void vc_put_lf(VCChardev *vc)
+static void vt100_put_lf(QemuVT100 *vt)
{
- QemuTextConsole *s = vc->console;
- QemuVT100 *vt = &s->vt;
TextCell *c;
int x, y1;
@@ -669,7 +667,7 @@ static void vc_put_one(VCChardev *vc, int ch)
if (vt->x >= vt->width) {
/* line wrap */
vt->x = 0;
- vc_put_lf(vc);
+ vt100_put_lf(vt);
}
y1 = (vt->y_base + vt->y) % vt->total_height;
c = &vt->cells[y1 * vt->width + vt->x];
@@ -853,7 +851,7 @@ static void vc_putchar(VCChardev *vc, int ch)
vt->x = 0;
break;
case '\n': /* newline */
- vc_put_lf(vc);
+ vt100_put_lf(&s->vt);
break;
case '\b': /* backspace */
if (vt->x > 0)
@@ -862,7 +860,7 @@ static void vc_putchar(VCChardev *vc, int ch)
case '\t': /* tabspace */
if (vt->x + (8 - (vt->x % 8)) > vt->width) {
vt->x = 0;
- vc_put_lf(vc);
+ vt100_put_lf(vt);
} else {
vt->x = vt->x + (8 - (vt->x % 8));
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 24/67] ui/console-vc: unify the write path
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (22 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 23/67] ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 25/67] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100 Marc-André Lureau
` (42 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
VT100 escape responses (DSR) used qemu_chr_be_write() to write directly
to the chardev backend, bypassing the output FIFO, while keyboard input
went through the FIFO and flush path. This inconsistency could lead to
out-of-order delivery when both paths are active.
Introduce qemu_text_console_write() that pushes data into the output
FIFO and flushes it, and use it for both keyboard input and VT100
responses. Remove the now-unnecessary vc_respond_str() helper. Rename
kbd_send_chars() to qemu_text_console_flush() to better reflect its
purpose.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 29 ++++++++++++++---------------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index a367622d819..bba1fe614ef 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -299,7 +299,7 @@ static void vt100_scroll(QemuVT100 *vt, int ydelta)
vt100_refresh(vt);
}
-static void kbd_send_chars(QemuTextConsole *s)
+static void qemu_text_console_flush(QemuTextConsole *s)
{
uint32_t len, avail;
@@ -316,13 +316,21 @@ static void kbd_send_chars(QemuTextConsole *s)
}
}
+static void qemu_text_console_write(QemuTextConsole *s, 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);
+}
+
/* 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;
- uint32_t num_free;
switch(keysym) {
case QEMU_KEY_CTRL_UP:
@@ -361,9 +369,7 @@ void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
if (vt->echo) {
qemu_chr_write(s->chr, buf, q - buf, true);
}
- num_free = fifo8_num_free(&s->out_fifo);
- fifo8_push_all(&s->out_fifo, buf, MIN(num_free, q - buf));
- kbd_send_chars(s);
+ qemu_text_console_write(s, buf, q - buf);
break;
}
}
@@ -677,13 +683,6 @@ static void vc_put_one(VCChardev *vc, int ch)
vt->x++;
}
-static void vc_respond_str(VCChardev *vc, const char *buf)
-{
- QemuTextConsole *s = vc->console;
-
- qemu_chr_be_write(s->chr, (const uint8_t *)buf, strlen(buf));
-}
-
/* set cursor, checking bounds */
static void vc_set_cursor(VCChardev *vc, int x, int y)
{
@@ -1028,13 +1027,13 @@ static void vc_putchar(VCChardev *vc, int ch)
switch (vc->esc_params[0]) {
case 5:
/* report console status (always succeed)*/
- vc_respond_str(vc, "\033[0n");
+ qemu_text_console_write(s, "\033[0n", 4);
break;
case 6:
/* report cursor position */
response = g_strdup_printf("\033[%d;%dR",
vt->y + 1, vt->x + 1);
- vc_respond_str(vc, response);
+ qemu_text_console_write(s, response, strlen(response));
break;
}
break;
@@ -1194,7 +1193,7 @@ static void vc_chr_accept_input(Chardev *chr)
{
VCChardev *drv = VC_CHARDEV(chr);
- kbd_send_chars(drv->console);
+ qemu_text_console_flush(drv->console);
}
static void vc_chr_set_echo(Chardev *chr, bool echo)
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 25/67] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (23 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 24/67] ui/console-vc: unify the write path Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 26/67] ui/console-vc: extract vt100_input() from vc_chr_write() Marc-André Lureau
` (41 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 375 +++++++++++++++++++++++++++-----------------------------
1 file changed, 180 insertions(+), 195 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index bba1fe614ef..5cfb3dfcf72 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -72,6 +72,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;
};
@@ -83,8 +95,6 @@ typedef struct QemuTextConsole {
QemuVT100 vt;
Chardev *chr;
- /* fifo for key pressed */
- Fifo8 out_fifo;
} QemuTextConsole;
typedef QemuConsoleClass QemuTextConsoleClass;
@@ -102,15 +112,6 @@ 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;
};
typedef struct VCChardev VCChardev;
@@ -299,36 +300,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;
@@ -360,16 +360,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;
}
}
@@ -377,30 +377,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;
}
}
@@ -489,103 +488,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;
@@ -606,14 +603,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;
@@ -621,7 +616,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);
}
/*
@@ -664,10 +659,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) {
@@ -678,17 +671,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;
}
@@ -712,10 +702,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;
@@ -739,12 +727,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);
}
}
@@ -754,10 +742,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;
@@ -781,61 +767,53 @@ 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:
/* Feed byte through the UTF-8 DFA decoder */
if (ch >= 0x80) {
- switch (bh_utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
+ 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:
/* Reset state so the decoder can resync */
- vc->utf8_state = BH_UTF8_ACCEPT;
+ vt->utf8_state = BH_UTF8_ACCEPT;
break;
default:
/* Need more bytes */
@@ -844,13 +822,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)
@@ -874,95 +852,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++) {
@@ -970,7 +948,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;
@@ -981,7 +959,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;
@@ -989,62 +967,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);
@@ -1056,10 +1034,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;
@@ -1070,7 +1048,7 @@ static void vc_putchar(VCChardev *vc, int ch)
/* Latin-1 map */
break;
}
- vc->state = TTY_STATE_NORM;
+ vt->state = TTY_STATE_NORM;
break;
}
}
@@ -1083,22 +1061,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;
}
@@ -1167,9 +1144,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;
}
@@ -1193,7 +1167,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)
@@ -1215,6 +1189,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;
@@ -1244,24 +1225,28 @@ 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;
/* 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);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 26/67] ui/console-vc: extract vt100_input() from vc_chr_write()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (24 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 25/67] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100 Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 27/67] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym() Marc-André Lureau
` (40 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
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().
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 34 ++++++++++++++++++++--------------
1 file changed, 20 insertions(+), 14 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 5cfb3dfcf72..15600128380 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -1057,29 +1057,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;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 27/67] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (25 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 26/67] ui/console-vc: extract vt100_input() from vc_chr_write() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 28/67] ui/console-vc: extract vt100_init() and vt100_fini() Marc-André Lureau
` (39 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
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.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 29 ++++++++++++++++++-----------
1 file changed, 18 insertions(+), 11 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 15600128380..194233f41df 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -326,24 +326,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 */
@@ -360,18 +361,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)
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 28/67] ui/console-vc: extract vt100_init() and vt100_fini()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (26 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 27/67] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 29/67] ui/console: remove console_ch_t typedef and console_write_ch() Marc-André Lureau
` (38 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
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().
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-vc.c | 44 ++++++++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 194233f41df..84944f845e1 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -1127,12 +1127,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
@@ -1140,10 +1147,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;
}
@@ -1209,6 +1212,25 @@ static void text_console_out_flush(QemuVT100 *vt)
qemu_text_console_out_flush(console);
}
+static void vt100_init(QemuVT100 *vt,
+ pixman_image_t *image,
+ 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);
+ }
+
+ 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;
@@ -1238,20 +1260,14 @@ 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;
+ vt100_init(&s->vt, QEMU_CONSOLE(s)->surface->image,
+ text_console_image_update,
+ text_console_out_flush);
s->chr = chr;
drv->console = s;
- /* set current text attributes to default */
- s->vt.t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
-
if (chr->label) {
char *msg;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 29/67] ui/console: remove console_ch_t typedef and console_write_ch()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (27 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 28/67] ui/console-vc: extract vt100_init() and vt100_fini() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-11 22:24 ` Philippe Mathieu-Daudé
2026-04-10 19:18 ` [PATCH v2 30/67] ui: avoid duplicating vgafont16 in each translation unit Marc-André Lureau
` (37 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 11 ++---------
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, 27 insertions(+), 35 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 5b5bba46ec2..75cd48ed7ad 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -350,13 +350,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 */
@@ -370,7 +363,7 @@ typedef struct GraphicHwOps {
void (*invalidate)(void *opaque);
void (*gfx_update)(void *opaque);
bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
- void (*text_update)(void *opaque, console_ch_t *text);
+ void (*text_update)(void *opaque, uint32_t *text);
void (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
void (*gl_block)(void *opaque, bool block);
} GraphicHwOps;
@@ -386,7 +379,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);
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index 9d62e51bed9..d5783982950 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -226,7 +226,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];
@@ -236,10 +236,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);
}
diff --git a/hw/display/vga.c b/hw/display/vga.c
index ee7d97b5c21..36cfc59a74e 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1899,13 +1899,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;
@@ -2005,14 +2005,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;
@@ -2021,7 +2021,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;
@@ -2059,14 +2059,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);
}
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index cb76302e2d8..7b107509510 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -87,7 +87,7 @@ static void virtio_gpu_update_display(void *opaque)
{
}
-static void virtio_gpu_text_update(void *opaque, console_ch_t *chardata)
+static void virtio_gpu_text_update(void *opaque, uint32_t *chardata)
{
}
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 5e087169f2f..02fb36b31fc 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -31,7 +31,7 @@ static void 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;
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index c2c6bc76e90..1e154e7f99e 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1183,7 +1183,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;
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 84944f845e1..d58917c1850 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -381,7 +381,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;
@@ -391,11 +391,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]);
diff --git a/ui/console.c b/ui/console.c
index 8af1dee0e22..b2b879e8533 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -214,7 +214,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);
diff --git a/ui/curses.c b/ui/curses.c
index 161f78c35c3..78f21d940e3 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -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();
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 30/67] ui: avoid duplicating vgafont16 in each translation unit
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (28 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 29/67] ui/console: remove console_ch_t typedef and console_write_ch() Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 31/67] ui/vgafont: add SPDX license header Marc-André Lureau
` (36 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
vgafont.h defined vgafont16 as a static const array, so every .c file
that included it (via console-priv.h) got its own 4 KiB copy, that
the linker may or not deduplicate?
Move the array definition into a new vgafont.c compilation unit and
turn the header into a proper extern declaration with an include guard.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vgafont.h | 4613 +-------------------------------------------------------
ui/vgafont.c | 4613 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ui/meson.build | 1 +
3 files changed, 4619 insertions(+), 4608 deletions(-)
diff --git a/ui/vgafont.h b/ui/vgafont.h
index 7e1fc473f75..4498ac4e07b 100644
--- a/ui/vgafont.h
+++ b/ui/vgafont.h
@@ -1,4611 +1,8 @@
-static const uint8_t vgafont16[256 * 16] = {
+#ifndef VGAFONT_H
+#define VGAFONT_H
- /* 0 0x00 '^@' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
+#include <stdint.h>
- /* 1 0x01 '^A' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x81, /* 10000001 */
- 0xa5, /* 10100101 */
- 0x81, /* 10000001 */
- 0x81, /* 10000001 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0x81, /* 10000001 */
- 0x81, /* 10000001 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
+extern const uint8_t vgafont16[256 * 16];
- /* 2 0x02 '^B' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xdb, /* 11011011 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 3 0x03 '^C' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 4 0x04 '^D' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 5 0x05 '^E' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0xe7, /* 11100111 */
- 0xe7, /* 11100111 */
- 0xe7, /* 11100111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 6 0x06 '^F' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 7 0x07 '^G' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 8 0x08 '^H' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xe7, /* 11100111 */
- 0xc3, /* 11000011 */
- 0xc3, /* 11000011 */
- 0xe7, /* 11100111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 9 0x09 '^I' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x42, /* 01000010 */
- 0x42, /* 01000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 10 0x0a '^J' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xc3, /* 11000011 */
- 0x99, /* 10011001 */
- 0xbd, /* 10111101 */
- 0xbd, /* 10111101 */
- 0x99, /* 10011001 */
- 0xc3, /* 11000011 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 11 0x0b '^K' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1e, /* 00011110 */
- 0x0e, /* 00001110 */
- 0x1a, /* 00011010 */
- 0x32, /* 00110010 */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 12 0x0c '^L' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 13 0x0d '^M' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x33, /* 00110011 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x70, /* 01110000 */
- 0xf0, /* 11110000 */
- 0xe0, /* 11100000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 14 0x0e '^N' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x7f, /* 01111111 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x63, /* 01100011 */
- 0x67, /* 01100111 */
- 0xe7, /* 11100111 */
- 0xe6, /* 11100110 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 15 0x0f '^O' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xdb, /* 11011011 */
- 0x3c, /* 00111100 */
- 0xe7, /* 11100111 */
- 0x3c, /* 00111100 */
- 0xdb, /* 11011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 16 0x10 '^P' */
- 0x00, /* 00000000 */
- 0x80, /* 10000000 */
- 0xc0, /* 11000000 */
- 0xe0, /* 11100000 */
- 0xf0, /* 11110000 */
- 0xf8, /* 11111000 */
- 0xfe, /* 11111110 */
- 0xf8, /* 11111000 */
- 0xf0, /* 11110000 */
- 0xe0, /* 11100000 */
- 0xc0, /* 11000000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 17 0x11 '^Q' */
- 0x00, /* 00000000 */
- 0x02, /* 00000010 */
- 0x06, /* 00000110 */
- 0x0e, /* 00001110 */
- 0x1e, /* 00011110 */
- 0x3e, /* 00111110 */
- 0xfe, /* 11111110 */
- 0x3e, /* 00111110 */
- 0x1e, /* 00011110 */
- 0x0e, /* 00001110 */
- 0x06, /* 00000110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 18 0x12 '^R' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 19 0x13 '^S' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 20 0x14 '^T' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7f, /* 01111111 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7b, /* 01111011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 21 0x15 '^U' */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 22 0x16 '^V' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 23 0x17 '^W' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 24 0x18 '^X' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 25 0x19 '^Y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 26 0x1a '^Z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 27 0x1b '^[' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xfe, /* 11111110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 28 0x1c '^\' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 29 0x1d '^]' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x28, /* 00101000 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x28, /* 00101000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 30 0x1e '^^' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0x7c, /* 01111100 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 31 0x1f '^_' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0x7c, /* 01111100 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 32 0x20 ' ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 33 0x21 '!' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 34 0x22 '"' */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x24, /* 00100100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 35 0x23 '#' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 36 0x24 '$' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x86, /* 10000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 37 0x25 '%' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc2, /* 11000010 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0x86, /* 10000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 38 0x26 '&' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 39 0x27 ''' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 40 0x28 '(' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 41 0x29 ')' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 42 0x2a '*' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0xff, /* 11111111 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 43 0x2b '+' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 44 0x2c ',' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 45 0x2d '-' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 46 0x2e '.' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 47 0x2f '/' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x02, /* 00000010 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x80, /* 10000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 48 0x30 '0' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 49 0x31 '1' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x38, /* 00111000 */
- 0x78, /* 01111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 50 0x32 '2' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 51 0x33 '3' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x3c, /* 00111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 52 0x34 '4' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x1c, /* 00011100 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 53 0x35 '5' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 54 0x36 '6' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xfc, /* 11111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 55 0x37 '7' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 56 0x38 '8' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 57 0x39 '9' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 58 0x3a ':' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 59 0x3b ';' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 60 0x3c '<' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 61 0x3d '=' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 62 0x3e '>' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 63 0x3f '?' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 64 0x40 '@' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xde, /* 11011110 */
- 0xdc, /* 11011100 */
- 0xc0, /* 11000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 65 0x41 'A' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 66 0x42 'B' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 67 0x43 'C' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc2, /* 11000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 68 0x44 'D' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 69 0x45 'E' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x66, /* 01100110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x60, /* 01100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 70 0x46 'F' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x66, /* 01100110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 71 0x47 'G' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xde, /* 11011110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x66, /* 01100110 */
- 0x3a, /* 00111010 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 72 0x48 'H' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 73 0x49 'I' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 74 0x4a 'J' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1e, /* 00011110 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 75 0x4b 'K' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe6, /* 11100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x78, /* 01111000 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 76 0x4c 'L' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 77 0x4d 'M' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xee, /* 11101110 */
- 0xfe, /* 11111110 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 78 0x4e 'N' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xfe, /* 11111110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 79 0x4f 'O' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 80 0x50 'P' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 81 0x51 'Q' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xde, /* 11011110 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x0e, /* 00001110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 82 0x52 'R' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfc, /* 11111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 83 0x53 'S' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 84 0x54 'T' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x5a, /* 01011010 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 85 0x55 'U' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 86 0x56 'V' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 87 0x57 'W' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0xee, /* 11101110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 88 0x58 'X' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x7c, /* 01111100 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x7c, /* 01111100 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 89 0x59 'Y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 90 0x5a 'Z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x86, /* 10000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc2, /* 11000010 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 91 0x5b '[' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 92 0x5c '\' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x80, /* 10000000 */
- 0xc0, /* 11000000 */
- 0xe0, /* 11100000 */
- 0x70, /* 01110000 */
- 0x38, /* 00111000 */
- 0x1c, /* 00011100 */
- 0x0e, /* 00001110 */
- 0x06, /* 00000110 */
- 0x02, /* 00000010 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 93 0x5d ']' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 94 0x5e '^' */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 95 0x5f '_' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 96 0x60 '`' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 97 0x61 'a' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 98 0x62 'b' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 99 0x63 'c' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 100 0x64 'd' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1c, /* 00011100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 101 0x65 'e' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 102 0x66 'f' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1c, /* 00011100 */
- 0x36, /* 00110110 */
- 0x32, /* 00110010 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 103 0x67 'g' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0xcc, /* 11001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 104 0x68 'h' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x6c, /* 01101100 */
- 0x76, /* 01110110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 105 0x69 'i' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 106 0x6a 'j' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
-
- /* 107 0x6b 'k' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xe0, /* 11100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x78, /* 01111000 */
- 0x78, /* 01111000 */
- 0x6c, /* 01101100 */
- 0x66, /* 01100110 */
- 0xe6, /* 11100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 108 0x6c 'l' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 109 0x6d 'm' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xec, /* 11101100 */
- 0xfe, /* 11111110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 110 0x6e 'n' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 111 0x6f 'o' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 112 0x70 'p' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
-
- /* 113 0x71 'q' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x7c, /* 01111100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x1e, /* 00011110 */
- 0x00, /* 00000000 */
-
- /* 114 0x72 'r' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x66, /* 01100110 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 115 0x73 's' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x38, /* 00111000 */
- 0x0c, /* 00001100 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 116 0x74 't' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0xfc, /* 11111100 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x36, /* 00110110 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 117 0x75 'u' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 118 0x76 'v' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 119 0x77 'w' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xd6, /* 11010110 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 120 0x78 'x' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 121 0x79 'y' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
-
- /* 122 0x7a 'z' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xcc, /* 11001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 123 0x7b '{' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 124 0x7c '|' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 125 0x7d '}' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x70, /* 01110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x0e, /* 00001110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 126 0x7e '~' */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 127 0x7f '\x7f' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 128 0x80 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0xc2, /* 11000010 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc2, /* 11000010 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 129 0x81 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 130 0x82 '' */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 131 0x83 '' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 132 0x84 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 133 0x85 '
' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 134 0x86 '' */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 135 0x87 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 136 0x88 '' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 137 0x89 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 138 0x8a '' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 139 0x8b '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 140 0x8c '' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 141 0x8d '' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 142 0x8e '' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 143 0x8f '' */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 144 0x90 '' */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x66, /* 01100110 */
- 0x62, /* 01100010 */
- 0x68, /* 01101000 */
- 0x78, /* 01111000 */
- 0x68, /* 01101000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 145 0x91 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xec, /* 11101100 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x6e, /* 01101110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 146 0x92 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3e, /* 00111110 */
- 0x6c, /* 01101100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xfe, /* 11111110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xce, /* 11001110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 147 0x93 '' */
- 0x00, /* 00000000 */
- 0x10, /* 00010000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 148 0x94 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 149 0x95 '' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 150 0x96 '' */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 151 0x97 '' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 152 0x98 '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7e, /* 01111110 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x78, /* 01111000 */
- 0x00, /* 00000000 */
-
- /* 153 0x99 '' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 154 0x9a '' */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 155 0x9b '' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 156 0x9c '' */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x64, /* 01100100 */
- 0x60, /* 01100000 */
- 0xf0, /* 11110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xe6, /* 11100110 */
- 0xfc, /* 11111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 157 0x9d '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 158 0x9e '' */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xf8, /* 11111000 */
- 0xc4, /* 11000100 */
- 0xcc, /* 11001100 */
- 0xde, /* 11011110 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 159 0x9f '' */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 160 0xa0 ' ' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0x0c, /* 00001100 */
- 0x7c, /* 01111100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 161 0xa1 '¡' */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 162 0xa2 '¢' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 163 0xa3 '£' */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x00, /* 00000000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 164 0xa4 '¤' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xdc, /* 11011100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 165 0xa5 '¥' */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0xc6, /* 11000110 */
- 0xe6, /* 11100110 */
- 0xf6, /* 11110110 */
- 0xfe, /* 11111110 */
- 0xde, /* 11011110 */
- 0xce, /* 11001110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 166 0xa6 '¦' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 167 0xa7 '§' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 168 0xa8 '¨' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x7c, /* 01111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 169 0xa9 '©' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 170 0xaa 'ª' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 171 0xab '«' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0xe0, /* 11100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xdc, /* 11011100 */
- 0x86, /* 10000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x3e, /* 00111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 172 0xac '¬' */
- 0x00, /* 00000000 */
- 0x60, /* 01100000 */
- 0xe0, /* 11100000 */
- 0x62, /* 01100010 */
- 0x66, /* 01100110 */
- 0x6c, /* 01101100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x66, /* 01100110 */
- 0xce, /* 11001110 */
- 0x9a, /* 10011010 */
- 0x3f, /* 00111111 */
- 0x06, /* 00000110 */
- 0x06, /* 00000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 173 0xad '' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 174 0xae '®' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x36, /* 00110110 */
- 0x6c, /* 01101100 */
- 0xd8, /* 11011000 */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 175 0xaf '¯' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xd8, /* 11011000 */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x6c, /* 01101100 */
- 0xd8, /* 11011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 176 0xb0 '°' */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
- 0x11, /* 00010001 */
- 0x44, /* 01000100 */
-
- /* 177 0xb1 '±' */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
- 0x55, /* 01010101 */
- 0xaa, /* 10101010 */
-
- /* 178 0xb2 '²' */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
- 0xdd, /* 11011101 */
- 0x77, /* 01110111 */
-
- /* 179 0xb3 '³' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 180 0xb4 '´' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 181 0xb5 'µ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 182 0xb6 '¶' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 183 0xb7 '·' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 184 0xb8 '¸' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 185 0xb9 '¹' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 186 0xba 'º' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 187 0xbb '»' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x06, /* 00000110 */
- 0xf6, /* 11110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 188 0xbc '¼' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf6, /* 11110110 */
- 0x06, /* 00000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 189 0xbd '½' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 190 0xbe '¾' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 191 0xbf '¿' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xf8, /* 11111000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 192 0xc0 'À' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 193 0xc1 'Á' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 194 0xc2 'Â' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 195 0xc3 'Ã' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 196 0xc4 'Ä' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 197 0xc5 'Å' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 198 0xc6 'Æ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 199 0xc7 'Ç' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 200 0xc8 'È' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 201 0xc9 'É' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 202 0xca 'Ê' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 203 0xcb 'Ë' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 204 0xcc 'Ì' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x37, /* 00110111 */
- 0x30, /* 00110000 */
- 0x37, /* 00110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 205 0xcd 'Í' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 206 0xce 'Î' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xf7, /* 11110111 */
- 0x00, /* 00000000 */
- 0xf7, /* 11110111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 207 0xcf 'Ï' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 208 0xd0 'Ð' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 209 0xd1 'Ñ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 210 0xd2 'Ò' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 211 0xd3 'Ó' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x3f, /* 00111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 212 0xd4 'Ô' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 213 0xd5 'Õ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 214 0xd6 'Ö' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x3f, /* 00111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 215 0xd7 '×' */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0xff, /* 11111111 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
-
- /* 216 0xd8 'Ø' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0xff, /* 11111111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 217 0xd9 'Ù' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xf8, /* 11111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 218 0xda 'Ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1f, /* 00011111 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 219 0xdb 'Û' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 220 0xdc 'Ü' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
-
- /* 221 0xdd 'Ý' */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
- 0xf0, /* 11110000 */
-
- /* 222 0xde 'Þ' */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
- 0x0f, /* 00001111 */
-
- /* 223 0xdf 'ß' */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0xff, /* 11111111 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 224 0xe0 'à' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xdc, /* 11011100 */
- 0x76, /* 01110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 225 0xe1 'á' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x78, /* 01111000 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xcc, /* 11001100 */
- 0xd8, /* 11011000 */
- 0xcc, /* 11001100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xcc, /* 11001100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 226 0xe2 'â' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 227 0xe3 'ã' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 228 0xe4 'ä' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 229 0xe5 'å' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 230 0xe6 'æ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
-
- /* 231 0xe7 'ç' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 232 0xe8 'è' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 233 0xe9 'é' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xfe, /* 11111110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 234 0xea 'ê' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0xee, /* 11101110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 235 0xeb 'ë' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1e, /* 00011110 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x3e, /* 00111110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x66, /* 01100110 */
- 0x3c, /* 00111100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 236 0xec 'ì' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 237 0xed 'í' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x03, /* 00000011 */
- 0x06, /* 00000110 */
- 0x7e, /* 01111110 */
- 0xdb, /* 11011011 */
- 0xdb, /* 11011011 */
- 0xf3, /* 11110011 */
- 0x7e, /* 01111110 */
- 0x60, /* 01100000 */
- 0xc0, /* 11000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 238 0xee 'î' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x1c, /* 00011100 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x7c, /* 01111100 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 239 0xef 'ï' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7c, /* 01111100 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0xc6, /* 11000110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 240 0xf0 'ð' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0xfe, /* 11111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 241 0xf1 'ñ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x7e, /* 01111110 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 242 0xf2 'ò' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x06, /* 00000110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 243 0xf3 'ó' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x30, /* 00110000 */
- 0x60, /* 01100000 */
- 0x30, /* 00110000 */
- 0x18, /* 00011000 */
- 0x0c, /* 00001100 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 244 0xf4 'ô' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x0e, /* 00001110 */
- 0x1b, /* 00011011 */
- 0x1b, /* 00011011 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
-
- /* 245 0xf5 'õ' */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0xd8, /* 11011000 */
- 0x70, /* 01110000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 246 0xf6 'ö' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 247 0xf7 '÷' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x76, /* 01110110 */
- 0xdc, /* 11011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 248 0xf8 'ø' */
- 0x00, /* 00000000 */
- 0x38, /* 00111000 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x38, /* 00111000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 249 0xf9 'ù' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 250 0xfa 'ú' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x18, /* 00011000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 251 0xfb 'û' */
- 0x00, /* 00000000 */
- 0x0f, /* 00001111 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0x0c, /* 00001100 */
- 0xec, /* 11101100 */
- 0x6c, /* 01101100 */
- 0x6c, /* 01101100 */
- 0x3c, /* 00111100 */
- 0x1c, /* 00011100 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 252 0xfc 'ü' */
- 0x00, /* 00000000 */
- 0x6c, /* 01101100 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x36, /* 00110110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 253 0xfd 'ý' */
- 0x00, /* 00000000 */
- 0x3c, /* 00111100 */
- 0x66, /* 01100110 */
- 0x0c, /* 00001100 */
- 0x18, /* 00011000 */
- 0x32, /* 00110010 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 254 0xfe 'þ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x7e, /* 01111110 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
- /* 255 0xff 'ÿ' */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
- 0x00, /* 00000000 */
-
-};
+#endif
diff --git a/ui/vgafont.c b/ui/vgafont.c
new file mode 100644
index 00000000000..708c845a6bf
--- /dev/null
+++ b/ui/vgafont.c
@@ -0,0 +1,4613 @@
+#include "vgafont.h"
+
+const uint8_t vgafont16[256 * 16] = {
+
+ /* 0 0x00 '^@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 1 0x01 '^A' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x81, /* 10000001 */
+ 0xa5, /* 10100101 */
+ 0x81, /* 10000001 */
+ 0x81, /* 10000001 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0x81, /* 10000001 */
+ 0x81, /* 10000001 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 2 0x02 '^B' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xdb, /* 11011011 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 3 0x03 '^C' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 4 0x04 '^D' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 5 0x05 '^E' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0xe7, /* 11100111 */
+ 0xe7, /* 11100111 */
+ 0xe7, /* 11100111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 6 0x06 '^F' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 7 0x07 '^G' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 8 0x08 '^H' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xe7, /* 11100111 */
+ 0xc3, /* 11000011 */
+ 0xc3, /* 11000011 */
+ 0xe7, /* 11100111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 9 0x09 '^I' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x42, /* 01000010 */
+ 0x42, /* 01000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 10 0x0a '^J' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xc3, /* 11000011 */
+ 0x99, /* 10011001 */
+ 0xbd, /* 10111101 */
+ 0xbd, /* 10111101 */
+ 0x99, /* 10011001 */
+ 0xc3, /* 11000011 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 11 0x0b '^K' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1e, /* 00011110 */
+ 0x0e, /* 00001110 */
+ 0x1a, /* 00011010 */
+ 0x32, /* 00110010 */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 12 0x0c '^L' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 13 0x0d '^M' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x33, /* 00110011 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x70, /* 01110000 */
+ 0xf0, /* 11110000 */
+ 0xe0, /* 11100000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 14 0x0e '^N' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x7f, /* 01111111 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x63, /* 01100011 */
+ 0x67, /* 01100111 */
+ 0xe7, /* 11100111 */
+ 0xe6, /* 11100110 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 15 0x0f '^O' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xdb, /* 11011011 */
+ 0x3c, /* 00111100 */
+ 0xe7, /* 11100111 */
+ 0x3c, /* 00111100 */
+ 0xdb, /* 11011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 16 0x10 '^P' */
+ 0x00, /* 00000000 */
+ 0x80, /* 10000000 */
+ 0xc0, /* 11000000 */
+ 0xe0, /* 11100000 */
+ 0xf0, /* 11110000 */
+ 0xf8, /* 11111000 */
+ 0xfe, /* 11111110 */
+ 0xf8, /* 11111000 */
+ 0xf0, /* 11110000 */
+ 0xe0, /* 11100000 */
+ 0xc0, /* 11000000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 17 0x11 '^Q' */
+ 0x00, /* 00000000 */
+ 0x02, /* 00000010 */
+ 0x06, /* 00000110 */
+ 0x0e, /* 00001110 */
+ 0x1e, /* 00011110 */
+ 0x3e, /* 00111110 */
+ 0xfe, /* 11111110 */
+ 0x3e, /* 00111110 */
+ 0x1e, /* 00011110 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 18 0x12 '^R' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 19 0x13 '^S' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 20 0x14 '^T' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7f, /* 01111111 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7b, /* 01111011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 21 0x15 '^U' */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x0c, /* 00001100 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 22 0x16 '^V' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 23 0x17 '^W' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 24 0x18 '^X' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 25 0x19 '^Y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 26 0x1a '^Z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 27 0x1b '^[' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xfe, /* 11111110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 28 0x1c '^\' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 29 0x1d '^]' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x28, /* 00101000 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x28, /* 00101000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 30 0x1e '^^' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0x7c, /* 01111100 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 31 0x1f '^_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0x7c, /* 01111100 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 32 0x20 ' ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 33 0x21 '!' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 34 0x22 '"' */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x24, /* 00100100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 35 0x23 '#' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 36 0x24 '$' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x86, /* 10000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 37 0x25 '%' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc2, /* 11000010 */
+ 0xc6, /* 11000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0x86, /* 10000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 38 0x26 '&' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 39 0x27 ''' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 40 0x28 '(' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 41 0x29 ')' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 42 0x2a '*' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0xff, /* 11111111 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 43 0x2b '+' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 44 0x2c ',' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 45 0x2d '-' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 46 0x2e '.' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 47 0x2f '/' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x02, /* 00000010 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x80, /* 10000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 48 0x30 '0' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 49 0x31 '1' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x38, /* 00111000 */
+ 0x78, /* 01111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 50 0x32 '2' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 51 0x33 '3' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x3c, /* 00111100 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 52 0x34 '4' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x1c, /* 00011100 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xfe, /* 11111110 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x1e, /* 00011110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 53 0x35 '5' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfc, /* 11111100 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 54 0x36 '6' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xfc, /* 11111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 55 0x37 '7' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 56 0x38 '8' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 57 0x39 '9' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 58 0x3a ':' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 59 0x3b ';' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 60 0x3c '<' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 61 0x3d '=' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 62 0x3e '>' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 63 0x3f '?' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 64 0x40 '@' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xde, /* 11011110 */
+ 0xde, /* 11011110 */
+ 0xde, /* 11011110 */
+ 0xdc, /* 11011100 */
+ 0xc0, /* 11000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 65 0x41 'A' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 66 0x42 'B' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 67 0x43 'C' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc2, /* 11000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 68 0x44 'D' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 69 0x45 'E' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x66, /* 01100110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x60, /* 01100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 70 0x46 'F' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x66, /* 01100110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 71 0x47 'G' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xde, /* 11011110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x66, /* 01100110 */
+ 0x3a, /* 00111010 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 72 0x48 'H' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 73 0x49 'I' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 74 0x4a 'J' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1e, /* 00011110 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 75 0x4b 'K' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe6, /* 11100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x78, /* 01111000 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 76 0x4c 'L' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf0, /* 11110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 77 0x4d 'M' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xee, /* 11101110 */
+ 0xfe, /* 11111110 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 78 0x4e 'N' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xe6, /* 11100110 */
+ 0xf6, /* 11110110 */
+ 0xfe, /* 11111110 */
+ 0xde, /* 11011110 */
+ 0xce, /* 11001110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 79 0x4f 'O' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 80 0x50 'P' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 81 0x51 'Q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xde, /* 11011110 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0x0e, /* 00001110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 82 0x52 'R' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfc, /* 11111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 83 0x53 'S' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x38, /* 00111000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 84 0x54 'T' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x5a, /* 01011010 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 85 0x55 'U' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 86 0x56 'V' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 87 0x57 'W' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xfe, /* 11111110 */
+ 0xee, /* 11101110 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 88 0x58 'X' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x7c, /* 01111100 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x7c, /* 01111100 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 89 0x59 'Y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 90 0x5a 'Z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x86, /* 10000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc2, /* 11000010 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 91 0x5b '[' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 92 0x5c '\' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x80, /* 10000000 */
+ 0xc0, /* 11000000 */
+ 0xe0, /* 11100000 */
+ 0x70, /* 01110000 */
+ 0x38, /* 00111000 */
+ 0x1c, /* 00011100 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x02, /* 00000010 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 93 0x5d ']' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 94 0x5e '^' */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 95 0x5f '_' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 96 0x60 '`' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 97 0x61 'a' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 98 0x62 'b' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 99 0x63 'c' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 100 0x64 'd' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 00011100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 101 0x65 'e' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 102 0x66 'f' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 00011100 */
+ 0x36, /* 00110110 */
+ 0x32, /* 00110010 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 103 0x67 'g' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0xcc, /* 11001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 104 0x68 'h' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x6c, /* 01101100 */
+ 0x76, /* 01110110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 105 0x69 'i' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 106 0x6a 'j' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+
+ /* 107 0x6b 'k' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xe0, /* 11100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x78, /* 01111000 */
+ 0x78, /* 01111000 */
+ 0x6c, /* 01101100 */
+ 0x66, /* 01100110 */
+ 0xe6, /* 11100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 108 0x6c 'l' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 109 0x6d 'm' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xec, /* 11101100 */
+ 0xfe, /* 11111110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 110 0x6e 'n' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 111 0x6f 'o' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 112 0x70 'p' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+
+ /* 113 0x71 'q' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x7c, /* 01111100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x1e, /* 00011110 */
+ 0x00, /* 00000000 */
+
+ /* 114 0x72 'r' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x76, /* 01110110 */
+ 0x66, /* 01100110 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 115 0x73 's' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x38, /* 00111000 */
+ 0x0c, /* 00001100 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 116 0x74 't' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0xfc, /* 11111100 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x36, /* 00110110 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 117 0x75 'u' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 118 0x76 'v' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 119 0x77 'w' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xd6, /* 11010110 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 120 0x78 'x' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 121 0x79 'y' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+
+ /* 122 0x7a 'z' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xcc, /* 11001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 123 0x7b '{' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x0e, /* 00001110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 124 0x7c '|' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 125 0x7d '}' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x70, /* 01110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x0e, /* 00001110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 126 0x7e '~' */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 127 0x7f '\x7f' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 128 0x80 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0xc2, /* 11000010 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc2, /* 11000010 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 129 0x81 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 130 0x82 '' */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 131 0x83 '' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 132 0x84 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 133 0x85 '
' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 134 0x86 '' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 135 0x87 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 136 0x88 '' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 137 0x89 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 138 0x8a '' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 139 0x8b '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 140 0x8c '' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 141 0x8d '' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 142 0x8e '' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 143 0x8f '' */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 144 0x90 '' */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x66, /* 01100110 */
+ 0x62, /* 01100010 */
+ 0x68, /* 01101000 */
+ 0x78, /* 01111000 */
+ 0x68, /* 01101000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 145 0x91 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xec, /* 11101100 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x7e, /* 01111110 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x6e, /* 01101110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 146 0x92 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3e, /* 00111110 */
+ 0x6c, /* 01101100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xfe, /* 11111110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xce, /* 11001110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 147 0x93 '' */
+ 0x00, /* 00000000 */
+ 0x10, /* 00010000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 148 0x94 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 149 0x95 '' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 150 0x96 '' */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 151 0x97 '' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 152 0x98 '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7e, /* 01111110 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x78, /* 01111000 */
+ 0x00, /* 00000000 */
+
+ /* 153 0x99 '' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 154 0x9a '' */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 155 0x9b '' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 156 0x9c '' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x64, /* 01100100 */
+ 0x60, /* 01100000 */
+ 0xf0, /* 11110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xe6, /* 11100110 */
+ 0xfc, /* 11111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 157 0x9d '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 158 0x9e '' */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xf8, /* 11111000 */
+ 0xc4, /* 11000100 */
+ 0xcc, /* 11001100 */
+ 0xde, /* 11011110 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 159 0x9f '' */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x1b, /* 00011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 160 0xa0 ' ' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0x0c, /* 00001100 */
+ 0x7c, /* 01111100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 161 0xa1 '¡' */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 162 0xa2 '¢' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 163 0xa3 '£' */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x00, /* 00000000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 164 0xa4 '¤' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0xdc, /* 11011100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 165 0xa5 '¥' */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0xc6, /* 11000110 */
+ 0xe6, /* 11100110 */
+ 0xf6, /* 11110110 */
+ 0xfe, /* 11111110 */
+ 0xde, /* 11011110 */
+ 0xce, /* 11001110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 166 0xa6 '¦' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x3e, /* 00111110 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 167 0xa7 '§' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 168 0xa8 '¨' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x7c, /* 01111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 169 0xa9 '©' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 170 0xaa 'ª' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 171 0xab '«' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0xe0, /* 11100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xdc, /* 11011100 */
+ 0x86, /* 10000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x3e, /* 00111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 172 0xac '¬' */
+ 0x00, /* 00000000 */
+ 0x60, /* 01100000 */
+ 0xe0, /* 11100000 */
+ 0x62, /* 01100010 */
+ 0x66, /* 01100110 */
+ 0x6c, /* 01101100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x66, /* 01100110 */
+ 0xce, /* 11001110 */
+ 0x9a, /* 10011010 */
+ 0x3f, /* 00111111 */
+ 0x06, /* 00000110 */
+ 0x06, /* 00000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 173 0xad '' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 174 0xae '®' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x36, /* 00110110 */
+ 0x6c, /* 01101100 */
+ 0xd8, /* 11011000 */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 175 0xaf '¯' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xd8, /* 11011000 */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x6c, /* 01101100 */
+ 0xd8, /* 11011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 176 0xb0 '°' */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+ 0x11, /* 00010001 */
+ 0x44, /* 01000100 */
+
+ /* 177 0xb1 '±' */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+ 0x55, /* 01010101 */
+ 0xaa, /* 10101010 */
+
+ /* 178 0xb2 '²' */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+ 0xdd, /* 11011101 */
+ 0x77, /* 01110111 */
+
+ /* 179 0xb3 '³' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 180 0xb4 '´' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 181 0xb5 'µ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 182 0xb6 '¶' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 183 0xb7 '·' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 184 0xb8 '¸' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 185 0xb9 '¹' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x06, /* 00000110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 186 0xba 'º' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 187 0xbb '»' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x06, /* 00000110 */
+ 0xf6, /* 11110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 188 0xbc '¼' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf6, /* 11110110 */
+ 0x06, /* 00000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 189 0xbd '½' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 190 0xbe '¾' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 191 0xbf '¿' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xf8, /* 11111000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 192 0xc0 'À' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 193 0xc1 'Á' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 194 0xc2 'Â' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 195 0xc3 'Ã' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 196 0xc4 'Ä' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 197 0xc5 'Å' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 198 0xc6 'Æ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 199 0xc7 'Ç' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 200 0xc8 'È' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x30, /* 00110000 */
+ 0x3f, /* 00111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 201 0xc9 'É' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x30, /* 00110000 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 202 0xca 'Ê' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf7, /* 11110111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 203 0xcb 'Ë' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xf7, /* 11110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 204 0xcc 'Ì' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x37, /* 00110111 */
+ 0x30, /* 00110000 */
+ 0x37, /* 00110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 205 0xcd 'Í' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 206 0xce 'Î' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xf7, /* 11110111 */
+ 0x00, /* 00000000 */
+ 0xf7, /* 11110111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 207 0xcf 'Ï' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 208 0xd0 'Ð' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 209 0xd1 'Ñ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 210 0xd2 'Ò' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 211 0xd3 'Ó' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x3f, /* 00111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 212 0xd4 'Ô' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 213 0xd5 'Õ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 214 0xd6 'Ö' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x3f, /* 00111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 215 0xd7 '×' */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0xff, /* 11111111 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+
+ /* 216 0xd8 'Ø' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0xff, /* 11111111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 217 0xd9 'Ù' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xf8, /* 11111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 218 0xda 'Ú' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1f, /* 00011111 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 219 0xdb 'Û' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 220 0xdc 'Ü' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+
+ /* 221 0xdd 'Ý' */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+ 0xf0, /* 11110000 */
+
+ /* 222 0xde 'Þ' */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+ 0x0f, /* 00001111 */
+
+ /* 223 0xdf 'ß' */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0xff, /* 11111111 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 224 0xe0 'à' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xdc, /* 11011100 */
+ 0x76, /* 01110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 225 0xe1 'á' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x78, /* 01111000 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xcc, /* 11001100 */
+ 0xd8, /* 11011000 */
+ 0xcc, /* 11001100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xcc, /* 11001100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 226 0xe2 'â' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 227 0xe3 'ã' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 228 0xe4 'ä' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 229 0xe5 'å' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 230 0xe6 'æ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+
+ /* 231 0xe7 'ç' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 232 0xe8 'è' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 233 0xe9 'é' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xfe, /* 11111110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 234 0xea 'ê' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0xee, /* 11101110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 235 0xeb 'ë' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1e, /* 00011110 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x3e, /* 00111110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x66, /* 01100110 */
+ 0x3c, /* 00111100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 236 0xec 'ì' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 237 0xed 'í' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x03, /* 00000011 */
+ 0x06, /* 00000110 */
+ 0x7e, /* 01111110 */
+ 0xdb, /* 11011011 */
+ 0xdb, /* 11011011 */
+ 0xf3, /* 11110011 */
+ 0x7e, /* 01111110 */
+ 0x60, /* 01100000 */
+ 0xc0, /* 11000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 238 0xee 'î' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x1c, /* 00011100 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x7c, /* 01111100 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 239 0xef 'ï' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7c, /* 01111100 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0xc6, /* 11000110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 240 0xf0 'ð' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0xfe, /* 11111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 241 0xf1 'ñ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x7e, /* 01111110 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 242 0xf2 'ò' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x06, /* 00000110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 243 0xf3 'ó' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x30, /* 00110000 */
+ 0x60, /* 01100000 */
+ 0x30, /* 00110000 */
+ 0x18, /* 00011000 */
+ 0x0c, /* 00001100 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 244 0xf4 'ô' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x0e, /* 00001110 */
+ 0x1b, /* 00011011 */
+ 0x1b, /* 00011011 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+
+ /* 245 0xf5 'õ' */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0xd8, /* 11011000 */
+ 0x70, /* 01110000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 246 0xf6 'ö' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 247 0xf7 '÷' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x76, /* 01110110 */
+ 0xdc, /* 11011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 248 0xf8 'ø' */
+ 0x00, /* 00000000 */
+ 0x38, /* 00111000 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x38, /* 00111000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 249 0xf9 'ù' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 250 0xfa 'ú' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x18, /* 00011000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 251 0xfb 'û' */
+ 0x00, /* 00000000 */
+ 0x0f, /* 00001111 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0x0c, /* 00001100 */
+ 0xec, /* 11101100 */
+ 0x6c, /* 01101100 */
+ 0x6c, /* 01101100 */
+ 0x3c, /* 00111100 */
+ 0x1c, /* 00011100 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 252 0xfc 'ü' */
+ 0x00, /* 00000000 */
+ 0x6c, /* 01101100 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x36, /* 00110110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 253 0xfd 'ý' */
+ 0x00, /* 00000000 */
+ 0x3c, /* 00111100 */
+ 0x66, /* 01100110 */
+ 0x0c, /* 00001100 */
+ 0x18, /* 00011000 */
+ 0x32, /* 00110010 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 254 0xfe 'þ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x7e, /* 01111110 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+ /* 255 0xff 'ÿ' */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+ 0x00, /* 00000000 */
+
+};
diff --git a/ui/meson.build b/ui/meson.build
index d4d9312b98c..25657af50e7 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -15,6 +15,7 @@ system_ss.add(files(
'ui-hmp-cmds.c',
'ui-qmp-cmds.c',
'util.c',
+ 'vgafont.c',
))
system_ss.add(when: pixman, if_true: files('console-vc.c', 'cp437.c'), if_false: files('console-vc-stubs.c'))
if dbus_display
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 31/67] ui/vgafont: add SPDX license header
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (29 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 30/67] ui: avoid duplicating vgafont16 in each translation unit Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 32/67] ui: move FONT_WIDTH/HEIGHT to vgafont.h Marc-André Lureau
` (35 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Fabrice Bellard, Daniel P. Berrangé
The vgafont was added without source origin, but it can be traced back
to Linux kernel, which used
GPL-2 (https://github.com/mpe/linux-fullhistory/blob/master/lib/fonts/font_8x16.c).
commit c6f37d0e4feeb264a699eda289d3cc69405100b0
Author: Fabrice Bellard <fabrice@bellard.org>
Date: Wed Jul 14 17:39:50 2004 +0000
virtual console
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vgafont.h | 3 +++
ui/vgafont.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/ui/vgafont.h b/ui/vgafont.h
index 4498ac4e07b..54aeeb7d192 100644
--- a/ui/vgafont.h
+++ b/ui/vgafont.h
@@ -1,3 +1,6 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#ifndef VGAFONT_H
#define VGAFONT_H
diff --git a/ui/vgafont.c b/ui/vgafont.c
index 708c845a6bf..b9b9a7016f0 100644
--- a/ui/vgafont.c
+++ b/ui/vgafont.c
@@ -1,3 +1,6 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
#include "vgafont.h"
const uint8_t vgafont16[256 * 16] = {
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 32/67] ui: move FONT_WIDTH/HEIGHT to vgafont.h
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (30 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 31/67] ui/vgafont: add SPDX license header Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 33/67] ui/console-vc: move VT100 emulation into separate unit Marc-André Lureau
` (34 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
Since those values are related to the VGA font, it make sense to move
them here.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-priv.h | 5 -----
ui/vgafont.h | 6 +++++-
ui/console-vc.c | 1 +
ui/console.c | 1 +
4 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/ui/console-priv.h b/ui/console-priv.h
index 8bcdb79d914..39798c3e9d7 100644
--- a/ui/console-priv.h
+++ b/ui/console-priv.h
@@ -9,11 +9,6 @@
#include "qemu/coroutine.h"
#include "qemu/timer.h"
-#include "vgafont.h"
-
-#define FONT_HEIGHT 16
-#define FONT_WIDTH 8
-
struct QemuConsole {
Object parent;
diff --git a/ui/vgafont.h b/ui/vgafont.h
index 54aeeb7d192..d24b5d47a95 100644
--- a/ui/vgafont.h
+++ b/ui/vgafont.h
@@ -6,6 +6,10 @@
#include <stdint.h>
-extern const uint8_t vgafont16[256 * 16];
+/* supports only vga 8x16 */
+#define FONT_WIDTH 8
+#define FONT_HEIGHT 16
+
+extern const uint8_t vgafont16[256 * FONT_HEIGHT];
#endif
diff --git a/ui/console-vc.c b/ui/console-vc.c
index d58917c1850..0d7b943fdc7 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -11,6 +11,7 @@
#include "qemu/queue.h"
#include "ui/console.h"
#include "ui/cp437.h"
+#include "ui/vgafont.h"
#include "pixman.h"
#include "trace.h"
diff --git a/ui/console.c b/ui/console.c
index b2b879e8533..c997e8df572 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -24,6 +24,7 @@
#include "qemu/osdep.h"
#include "ui/console.h"
+#include "ui/vgafont.h"
#include "hw/core/qdev.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-ui.h"
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 33/67] ui/console-vc: move VT100 emulation into separate unit
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (31 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 32/67] ui: move FONT_WIDTH/HEIGHT to vgafont.h Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 34/67] util: move datadir.c from system/ Marc-André Lureau
` (33 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
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.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console-priv.h | 1 -
ui/vt100.h | 92 +++++
ui/console-vc-stubs.c | 1 +
ui/console-vc.c | 1034 +------------------------------------------------
ui/console.c | 2 +
ui/vt100.c | 986 ++++++++++++++++++++++++++++++++++++++++++++++
ui/meson.build | 4 +-
7 files changed, 1085 insertions(+), 1035 deletions(-)
diff --git a/ui/console-priv.h b/ui/console-priv.h
index 39798c3e9d7..f8855753e30 100644
--- a/ui/console-priv.h
+++ b/ui/console-priv.h
@@ -31,7 +31,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
diff --git a/ui/vt100.h b/ui/vt100.h
new file mode 100644
index 00000000000..79cf8c23b2f
--- /dev/null
+++ b/ui/vt100.h
@@ -0,0 +1,92 @@
+/*
+ * SPDX-License-Identifier: MIT
+ * QEMU vt100
+ */
+#ifndef VT100_H
+#define VT100_H
+
+#include "ui/console.h"
+#include "qemu/fifo8.h"
+#include "qemu/queue.h"
+
+typedef struct TextAttributes {
+ uint8_t fgcol:4;
+ uint8_t bgcol:4;
+ uint8_t bold:1;
+ uint8_t uline:1;
+ uint8_t blink:1;
+ uint8_t invers:1;
+ uint8_t unvisible:1;
+} TextAttributes;
+
+#define TEXT_ATTRIBUTES_DEFAULT ((TextAttributes) { \
+ .fgcol = QEMU_COLOR_WHITE, \
+ .bgcol = QEMU_COLOR_BLACK \
+})
+
+typedef struct TextCell {
+ uint8_t ch;
+ TextAttributes t_attrib;
+} TextCell;
+
+#define MAX_ESC_PARAMS 3
+
+enum TTYState {
+ TTY_STATE_NORM,
+ TTY_STATE_ESC,
+ TTY_STATE_CSI,
+ TTY_STATE_G0,
+ TTY_STATE_G1,
+ TTY_STATE_OSC,
+};
+
+typedef struct QemuVT100 QemuVT100;
+
+struct QemuVT100 {
+ pixman_image_t *image;
+ void (*image_update)(QemuVT100 *vt, int x, int y, int width, int height);
+
+ int width;
+ int height;
+ int total_height;
+ int backscroll_height;
+ int x, y;
+ int y_displayed;
+ int y_base;
+ TextCell *cells;
+ int text_x[2], text_y[2], cursor_invalidate;
+ int echo;
+
+ int update_x0;
+ int update_y0;
+ 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;
+};
+
+void vt100_init(QemuVT100 *vt,
+ pixman_image_t *image,
+ void (*image_update)(QemuVT100 *vt, int x, int y, int width, int height),
+ void (*out_flush)(QemuVT100 *vt));
+void vt100_fini(QemuVT100 *vt);
+
+void vt100_update_cursor(void);
+size_t vt100_input(QemuVT100 *vt, const uint8_t *buf, size_t len);
+void vt100_keysym(QemuVT100 *vt, int keysym);
+void vt100_set_image(QemuVT100 *vt, pixman_image_t *image);
+void vt100_refresh(QemuVT100 *vt);
+
+#endif
diff --git a/ui/console-vc-stubs.c b/ui/console-vc-stubs.c
index d911a82f263..30e4d101197 100644
--- a/ui/console-vc-stubs.c
+++ b/ui/console-vc-stubs.c
@@ -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)
{
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 0d7b943fdc7..6e8f2552e41 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -6,91 +6,15 @@
#include "chardev/char.h"
#include "qapi/error.h"
-#include "qemu/fifo8.h"
#include "qemu/option.h"
-#include "qemu/queue.h"
#include "ui/console.h"
-#include "ui/cp437.h"
#include "ui/vgafont.h"
+#include "ui/vt100.h"
#include "pixman.h"
#include "trace.h"
#include "console-priv.h"
-#define DEFAULT_BACKSCROLL 512
-#define CONSOLE_CURSOR_PERIOD 500
-
-typedef struct TextAttributes {
- uint8_t fgcol:4;
- uint8_t bgcol:4;
- uint8_t bold:1;
- uint8_t uline:1;
- uint8_t blink:1;
- uint8_t invers:1;
- uint8_t unvisible:1;
-} TextAttributes;
-
-#define TEXT_ATTRIBUTES_DEFAULT ((TextAttributes) { \
- .fgcol = QEMU_COLOR_WHITE, \
- .bgcol = QEMU_COLOR_BLACK \
-})
-
-typedef struct TextCell {
- uint8_t ch;
- TextAttributes t_attrib;
-} TextCell;
-
-#define MAX_ESC_PARAMS 3
-
-enum TTYState {
- TTY_STATE_NORM,
- TTY_STATE_ESC,
- TTY_STATE_CSI,
- TTY_STATE_G0,
- TTY_STATE_G1,
- TTY_STATE_OSC,
-};
-
-typedef struct QemuVT100 QemuVT100;
-
-struct QemuVT100 {
- pixman_image_t *image;
- void (*image_update)(QemuVT100 *vt, int x, int y, int width, int height);
-
- int width;
- int height;
- int total_height;
- int backscroll_height;
- int x, y;
- int y_displayed;
- int y_base;
- TextCell *cells;
- int text_x[2], text_y[2], cursor_invalidate;
- int echo;
-
- int update_x0;
- int update_y0;
- 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;
-};
-
-static QTAILQ_HEAD(QemuVT100Head, QemuVT100) vt100s =
- QTAILQ_HEAD_INITIALIZER(vt100s);
-
typedef struct QemuTextConsole {
QemuConsole parent;
@@ -116,32 +40,6 @@ struct VCChardev {
};
typedef struct VCChardev VCChardev;
-static const pixman_color_t color_table_rgb[2][8] = {
- { /* dark */
- [QEMU_COLOR_BLACK] = QEMU_PIXMAN_COLOR_BLACK,
- [QEMU_COLOR_BLUE] = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xaa), /* blue */
- [QEMU_COLOR_GREEN] = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0x00), /* green */
- [QEMU_COLOR_CYAN] = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0xaa), /* cyan */
- [QEMU_COLOR_RED] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0x00), /* red */
- [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0xaa), /* magenta */
- [QEMU_COLOR_YELLOW] = QEMU_PIXMAN_COLOR(0xaa, 0xaa, 0x00), /* yellow */
- [QEMU_COLOR_WHITE] = QEMU_PIXMAN_COLOR_GRAY,
- },
- { /* bright */
- [QEMU_COLOR_BLACK] = QEMU_PIXMAN_COLOR_BLACK,
- [QEMU_COLOR_BLUE] = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xff), /* blue */
- [QEMU_COLOR_GREEN] = QEMU_PIXMAN_COLOR(0x00, 0xff, 0x00), /* green */
- [QEMU_COLOR_CYAN] = QEMU_PIXMAN_COLOR(0x00, 0xff, 0xff), /* cyan */
- [QEMU_COLOR_RED] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0x00), /* red */
- [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0xff), /* magenta */
- [QEMU_COLOR_YELLOW] = QEMU_PIXMAN_COLOR(0xff, 0xff, 0x00), /* yellow */
- [QEMU_COLOR_WHITE] = QEMU_PIXMAN_COLOR(0xff, 0xff, 0xff), /* white */
- }
-};
-
-static bool cursor_visible_phase;
-static QEMUTimer *cursor_timer;
-
static char *
qemu_text_console_get_label(QemuConsole *c)
{
@@ -150,157 +48,6 @@ qemu_text_console_get_label(QemuConsole *c)
return tc->chr ? g_strdup(tc->chr->label) : NULL;
}
-static void image_fill_rect(pixman_image_t *image, int posx, int posy,
- int width, int height, pixman_color_t color)
-{
- pixman_rectangle16_t rect = {
- .x = posx, .y = posy, .width = width, .height = height
- };
-
- pixman_image_fill_rectangles(PIXMAN_OP_SRC, image, &color, 1, &rect);
-}
-
-/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
-static void image_bitblt(pixman_image_t *image,
- int xs, int ys, int xd, int yd, int w, int h)
-{
- pixman_image_composite(PIXMAN_OP_SRC,
- image, NULL, image,
- xs, ys, 0, 0, xd, yd, w, h);
-}
-
-static void vt100_putcharxy(QemuVT100 *vt, int x, int y, int ch,
- TextAttributes *t_attrib)
-{
- static pixman_image_t *glyphs[256];
- pixman_color_t fgcol, bgcol;
-
- assert(vt->image);
- if (t_attrib->invers) {
- bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
- fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
- } else {
- fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
- bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
- }
-
- if (!glyphs[ch]) {
- glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
- }
- qemu_pixman_glyph_render(glyphs[ch], vt->image,
- &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
-}
-
-static void vt100_invalidate_xy(QemuVT100 *vt, int x, int y)
-{
- if (vt->update_x0 > x * FONT_WIDTH) {
- vt->update_x0 = x * FONT_WIDTH;
- }
- if (vt->update_y0 > y * FONT_HEIGHT) {
- vt->update_y0 = y * FONT_HEIGHT;
- }
- if (vt->update_x1 < (x + 1) * FONT_WIDTH) {
- vt->update_x1 = (x + 1) * FONT_WIDTH;
- }
- if (vt->update_y1 < (y + 1) * FONT_HEIGHT) {
- vt->update_y1 = (y + 1) * FONT_HEIGHT;
- }
-}
-
-static void vt100_show_cursor(QemuVT100 *vt, int show)
-{
- TextCell *c;
- int y, y1;
- int x = vt->x;
-
- vt->cursor_invalidate = 1;
-
- if (x >= vt->width) {
- x = vt->width - 1;
- }
- y1 = (vt->y_base + vt->y) % vt->total_height;
- y = y1 - vt->y_displayed;
- if (y < 0) {
- y += vt->total_height;
- }
- if (y < vt->height) {
- c = &vt->cells[y1 * vt->width + x];
- if (show && cursor_visible_phase) {
- TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vt100_putcharxy(vt, x, y, c->ch, &t_attrib);
- } else {
- vt100_putcharxy(vt, x, y, c->ch, &(c->t_attrib));
- }
- vt100_invalidate_xy(vt, x, y);
- }
-}
-
-static void vt100_image_update(QemuVT100 *vt, int x, int y, int width, int height)
-{
- vt->image_update(vt, x, y, width, height);
-}
-
-static void vt100_refresh(QemuVT100 *vt)
-{
- TextCell *c;
- int x, y, y1;
- int w = pixman_image_get_width(vt->image);
- int h = pixman_image_get_height(vt->image);
-
- vt->text_x[0] = 0;
- vt->text_y[0] = 0;
- vt->text_x[1] = vt->width - 1;
- vt->text_y[1] = vt->height - 1;
- vt->cursor_invalidate = 1;
-
- image_fill_rect(vt->image, 0, 0, w, h,
- color_table_rgb[0][QEMU_COLOR_BLACK]);
- y1 = vt->y_displayed;
- for (y = 0; y < vt->height; y++) {
- c = vt->cells + y1 * vt->width;
- for (x = 0; x < vt->width; x++) {
- vt100_putcharxy(vt, x, y, c->ch,
- &(c->t_attrib));
- c++;
- }
- if (++y1 == vt->total_height) {
- y1 = 0;
- }
- }
- vt100_show_cursor(vt, 1);
- vt100_image_update(vt, 0, 0, w, h);
-}
-
-static void vt100_scroll(QemuVT100 *vt, int ydelta)
-{
- int i, y1;
-
- if (ydelta > 0) {
- for(i = 0; i < ydelta; i++) {
- if (vt->y_displayed == vt->y_base)
- break;
- if (++vt->y_displayed == vt->total_height)
- vt->y_displayed = 0;
- }
- } else {
- ydelta = -ydelta;
- i = vt->backscroll_height;
- if (i > vt->total_height - vt->height)
- i = vt->total_height - vt->height;
- y1 = vt->y_base - i;
- if (y1 < 0)
- y1 += vt->total_height;
- for(i = 0; i < ydelta; i++) {
- if (vt->y_displayed == y1)
- break;
- if (--vt->y_displayed < 0)
- vt->y_displayed = vt->total_height - 1;
- }
- }
- vt100_refresh(vt);
-}
-
static void qemu_text_console_out_flush(QemuTextConsole *s)
{
uint32_t len, avail;
@@ -318,64 +65,6 @@ static void qemu_text_console_out_flush(QemuTextConsole *s)
}
}
-static void vt100_write(QemuVT100 *vt, const void *buf, size_t len)
-{
- uint32_t num_free;
-
- num_free = fifo8_num_free(&vt->out_fifo);
- fifo8_push_all(&vt->out_fifo, buf, MIN(num_free, len));
- vt->out_flush(vt);
-}
-
-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(vt, -1);
- break;
- case QEMU_KEY_CTRL_DOWN:
- vt100_scroll(vt, 1);
- break;
- case QEMU_KEY_CTRL_PAGEUP:
- vt100_scroll(vt, -10);
- break;
- case QEMU_KEY_CTRL_PAGEDOWN:
- vt100_scroll(vt, 10);
- break;
- default:
- /* convert the QEMU keysym to VT100 key string */
- q = buf;
- if (keysym >= 0xe100 && keysym <= 0xe11f) {
- *q++ = '\033';
- *q++ = '[';
- c = keysym - 0xe100;
- if (c >= 10)
- *q++ = '0' + (c / 10);
- *q++ = '0' + (c % 10);
- *q++ = '~';
- } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
- *q++ = '\033';
- *q++ = '[';
- *q++ = keysym & 0xff;
- } else if (vt->echo && (keysym == '\r' || keysym == '\n')) {
- vt100_input(vt, (uint8_t *)"\r", 1);
- *q++ = '\n';
- } else {
- *q++ = keysym;
- }
- if (vt->echo) {
- vt100_input(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)
{
@@ -410,681 +99,10 @@ static void text_console_update(void *opaque, uint32_t *chardata)
}
}
-static void vt100_set_image(QemuVT100 *vt, pixman_image_t *image)
-{
- TextCell *cells, *c, *c1;
- int w1, x, y, last_width, w, h;
-
- vt->image = image;
- w = pixman_image_get_width(image) / FONT_WIDTH;
- h = pixman_image_get_height(image) / FONT_HEIGHT;
- if (w == vt->width && h == vt->height) {
- return;
- }
-
- last_width = vt->width;
- vt->width = w;
- vt->height = h;
-
- w1 = MIN(vt->width, last_width);
-
- cells = g_new(TextCell, vt->width * vt->total_height + 1);
- for (y = 0; y < vt->total_height; y++) {
- c = &cells[y * vt->width];
- if (w1 > 0) {
- c1 = &vt->cells[y * last_width];
- for (x = 0; x < w1; x++) {
- *c++ = *c1++;
- }
- }
- for (x = w1; x < vt->width; x++) {
- c->ch = ' ';
- c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- c++;
- }
- }
- g_free(vt->cells);
- vt->cells = cells;
-}
-
-static void vt100_put_lf(QemuVT100 *vt)
-{
- TextCell *c;
- int x, y1;
-
- vt->y++;
- if (vt->y >= vt->height) {
- vt->y = vt->height - 1;
-
- if (vt->y_displayed == vt->y_base) {
- if (++vt->y_displayed == vt->total_height)
- vt->y_displayed = 0;
- }
- if (++vt->y_base == vt->total_height)
- vt->y_base = 0;
- if (vt->backscroll_height < vt->total_height)
- vt->backscroll_height++;
- y1 = (vt->y_base + vt->height - 1) % vt->total_height;
- c = &vt->cells[y1 * vt->width];
- for(x = 0; x < vt->width; x++) {
- c->ch = ' ';
- c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- c++;
- }
- if (vt->y_displayed == vt->y_base) {
- vt->text_x[0] = 0;
- vt->text_y[0] = 0;
- vt->text_x[1] = vt->width - 1;
- vt->text_y[1] = vt->height - 1;
-
- image_bitblt(vt->image, 0, FONT_HEIGHT, 0, 0,
- vt->width * FONT_WIDTH,
- (vt->height - 1) * FONT_HEIGHT);
- image_fill_rect(vt->image, 0, (vt->height - 1) * FONT_HEIGHT,
- vt->width * FONT_WIDTH, FONT_HEIGHT,
- color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
- vt->update_x0 = 0;
- vt->update_y0 = 0;
- vt->update_x1 = vt->width * FONT_WIDTH;
- vt->update_y1 = vt->height * FONT_HEIGHT;
- }
- }
-}
-
-/* Set console attributes depending on the current escape codes.
- * 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 vt100_handle_escape(QemuVT100 *vt)
-{
- int i;
-
- for (i = 0; i < vt->nb_esc_params; i++) {
- switch (vt->esc_params[i]) {
- case 0: /* reset all console attributes to default */
- vt->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- break;
- case 1:
- vt->t_attrib.bold = 1;
- break;
- case 4:
- vt->t_attrib.uline = 1;
- break;
- case 5:
- vt->t_attrib.blink = 1;
- break;
- case 7:
- vt->t_attrib.invers = 1;
- break;
- case 8:
- vt->t_attrib.unvisible = 1;
- break;
- case 22:
- vt->t_attrib.bold = 0;
- break;
- case 24:
- vt->t_attrib.uline = 0;
- break;
- case 25:
- vt->t_attrib.blink = 0;
- break;
- case 27:
- vt->t_attrib.invers = 0;
- break;
- case 28:
- vt->t_attrib.unvisible = 0;
- break;
- /* set foreground color */
- case 30:
- vt->t_attrib.fgcol = QEMU_COLOR_BLACK;
- break;
- case 31:
- vt->t_attrib.fgcol = QEMU_COLOR_RED;
- break;
- case 32:
- vt->t_attrib.fgcol = QEMU_COLOR_GREEN;
- break;
- case 33:
- vt->t_attrib.fgcol = QEMU_COLOR_YELLOW;
- break;
- case 34:
- vt->t_attrib.fgcol = QEMU_COLOR_BLUE;
- break;
- case 35:
- vt->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
- break;
- case 36:
- vt->t_attrib.fgcol = QEMU_COLOR_CYAN;
- break;
- case 37:
- vt->t_attrib.fgcol = QEMU_COLOR_WHITE;
- break;
- /* set background color */
- case 40:
- vt->t_attrib.bgcol = QEMU_COLOR_BLACK;
- break;
- case 41:
- vt->t_attrib.bgcol = QEMU_COLOR_RED;
- break;
- case 42:
- vt->t_attrib.bgcol = QEMU_COLOR_GREEN;
- break;
- case 43:
- vt->t_attrib.bgcol = QEMU_COLOR_YELLOW;
- break;
- case 44:
- vt->t_attrib.bgcol = QEMU_COLOR_BLUE;
- break;
- case 45:
- vt->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
- break;
- case 46:
- vt->t_attrib.bgcol = QEMU_COLOR_CYAN;
- break;
- case 47:
- vt->t_attrib.bgcol = QEMU_COLOR_WHITE;
- break;
- }
- }
-}
-
-static void vt100_update_xy(QemuVT100 *vt, int x, int y)
-{
- TextCell *c;
- int y1, y2;
-
- vt->text_x[0] = MIN(vt->text_x[0], x);
- vt->text_x[1] = MAX(vt->text_x[1], x);
- vt->text_y[0] = MIN(vt->text_y[0], y);
- vt->text_y[1] = MAX(vt->text_y[1], y);
-
- y1 = (vt->y_base + y) % vt->total_height;
- y2 = y1 - vt->y_displayed;
- if (y2 < 0) {
- y2 += vt->total_height;
- }
- if (y2 < vt->height) {
- if (x >= vt->width) {
- x = vt->width - 1;
- }
- c = &vt->cells[y1 * vt->width + x];
- vt100_putcharxy(vt, x, y2, c->ch,
- &(c->t_attrib));
- vt100_invalidate_xy(vt, x, y2);
- }
-}
-
-static void vt100_clear_xy(QemuVT100 *vt, int x, int y)
-{
- int y1 = (vt->y_base + y) % vt->total_height;
- if (x >= vt->width) {
- x = vt->width - 1;
- }
- TextCell *c = &vt->cells[y1 * vt->width + x];
- c->ch = ' ';
- c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
- vt100_update_xy(vt, x, y);
-}
-
-/*
- * UTF-8 DFA decoder by Bjoern Hoehrmann.
- * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
- * See https://github.com/polijan/utf8_decode for details.
- *
- * SPDX-License-Identifier: MIT
- */
-#define BH_UTF8_ACCEPT 0
-#define BH_UTF8_REJECT 12
-
-static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
-{
- static const uint8_t utf8d[] = {
- /* character class lookup */
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
- 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
-
- /* state transition lookup */
- 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
- 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
- 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
- 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
- 12,36,12,12,12,12,12,12,12,12,12,12,
- };
- uint32_t type = utf8d[byte];
-
- *codep = (*state != BH_UTF8_ACCEPT) ?
- (byte & 0x3fu) | (*codep << 6) :
- (0xffu >> type) & (byte);
-
- *state = utf8d[256 + *state + type];
- return *state;
-}
-
-static void vt100_put_one(QemuVT100 *vt, int ch)
-{
- TextCell *c;
- int y1;
- if (vt->x >= vt->width) {
- /* line wrap */
- vt->x = 0;
- vt100_put_lf(vt);
- }
- y1 = (vt->y_base + vt->y) % vt->total_height;
- c = &vt->cells[y1 * vt->width + vt->x];
- c->ch = ch;
- c->t_attrib = vt->t_attrib;
- vt100_update_xy(vt, vt->x, vt->y);
- vt->x++;
-}
-
-/* set cursor, checking bounds */
-static void vt100_set_cursor(QemuVT100 *vt, int x, int y)
-{
- if (x < 0) {
- x = 0;
- }
- if (y < 0) {
- y = 0;
- }
- if (y >= vt->height) {
- y = vt->height - 1;
- }
- if (x >= vt->width) {
- x = vt->width - 1;
- }
-
- vt->x = x;
- vt->y = y;
-}
-
-/**
- * vc_csi_P() - (DCH) deletes one or more characters from the cursor
- * position to the right. As characters are deleted, the remaining
- * characters between the cursor and right margin move to the
- * left. Character attributes move with the characters.
- */
-static void vt100_csi_P(QemuVT100 *vt, unsigned int nr)
-{
- TextCell *c1, *c2;
- unsigned int x1, x2, y;
- unsigned int end, len;
-
- if (!nr) {
- nr = 1;
- }
- if (nr > vt->width - vt->x) {
- nr = vt->width - vt->x;
- if (!nr) {
- return;
- }
- }
-
- x1 = vt->x;
- x2 = vt->x + nr;
- len = vt->width - x2;
- if (len) {
- y = (vt->y_base + vt->y) % vt->total_height;
- c1 = &vt->cells[y * vt->width + x1];
- c2 = &vt->cells[y * vt->width + x2];
- memmove(c1, c2, len * sizeof(*c1));
- for (end = x1 + len; x1 < end; x1++) {
- vt100_update_xy(vt, x1, vt->y);
- }
- }
- /* Clear the rest */
- for (; x1 < vt->width; x1++) {
- vt100_clear_xy(vt, x1, vt->y);
- }
-}
-
-/**
- * vc_csi_at() - (ICH) inserts `nr` blank characters with the default
- * character attribute. The cursor remains at the beginning of the
- * blank characters. Text between the cursor and right margin moves to
- * the right. Characters scrolled past the right margin are lost.
- */
-static void vt100_csi_at(QemuVT100 *vt, unsigned int nr)
-{
- TextCell *c1, *c2;
- unsigned int x1, x2, y;
- unsigned int end, len;
-
- if (!nr) {
- nr = 1;
- }
- if (nr > vt->width - vt->x) {
- nr = vt->width - vt->x;
- if (!nr) {
- return;
- }
- }
-
- x1 = vt->x + nr;
- x2 = vt->x;
- len = vt->width - x1;
- if (len) {
- y = (vt->y_base + vt->y) % vt->total_height;
- c1 = &vt->cells[y * vt->width + x1];
- c2 = &vt->cells[y * vt->width + x2];
- memmove(c1, c2, len * sizeof(*c1));
- for (end = x1 + len; x1 < end; x1++) {
- vt100_update_xy(vt, x1, vt->y);
- }
- }
- /* Insert blanks */
- for (x1 = vt->x; x1 < vt->x + nr; x1++) {
- vt100_clear_xy(vt, x1, vt->y);
- }
-}
-
-/**
- * vt100_save_cursor() - saves cursor position and character attributes.
- */
-static void vt100_save_cursor(QemuVT100 *vt)
-{
- vt->x_saved = vt->x;
- vt->y_saved = vt->y;
- vt->t_attrib_saved = vt->t_attrib;
-}
-
-/**
- * vt100_restore_cursor() - restores cursor position and character
- * attributes from saved state.
- */
-static void vt100_restore_cursor(QemuVT100 *vt)
-{
- vt->x = vt->x_saved;
- vt->y = vt->y_saved;
- vt->t_attrib = vt->t_attrib_saved;
-}
-
-static void vt100_putchar(QemuVT100 *vt, int ch)
-{
- int i;
- int x, y;
- g_autofree char *response = NULL;
-
- switch (vt->state) {
- case TTY_STATE_NORM:
- /* Feed byte through the UTF-8 DFA decoder */
- if (ch >= 0x80) {
- switch (bh_utf8_decode(&vt->utf8_state, &vt->utf8_codepoint, ch)) {
- case BH_UTF8_ACCEPT:
- vt100_put_one(vt, unicode_to_cp437(vt->utf8_codepoint));
- break;
- case BH_UTF8_REJECT:
- /* Reset state so the decoder can resync */
- vt->utf8_state = BH_UTF8_ACCEPT;
- break;
- default:
- /* Need more bytes */
- break;
- }
- break;
- }
- /* ASCII byte: abort any pending UTF-8 sequence */
- vt->utf8_state = BH_UTF8_ACCEPT;
- switch(ch) {
- case '\r': /* carriage return */
- vt->x = 0;
- break;
- case '\n': /* newline */
- vt100_put_lf(vt);
- break;
- case '\b': /* backspace */
- if (vt->x > 0)
- vt->x--;
- break;
- case '\t': /* tabspace */
- if (vt->x + (8 - (vt->x % 8)) > vt->width) {
- vt->x = 0;
- vt100_put_lf(vt);
- } else {
- vt->x = vt->x + (8 - (vt->x % 8));
- }
- break;
- case '\a': /* alert aka. bell */
- /* TODO: has to be implemented */
- break;
- case 14:
- /* SO (shift out), character set 1 (ignored) */
- break;
- case 15:
- /* SI (shift in), character set 0 (ignored) */
- break;
- case 27: /* esc (introducing an escape sequence) */
- vt->state = TTY_STATE_ESC;
- break;
- default:
- 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++)
- vt->esc_params[i] = 0;
- vt->nb_esc_params = 0;
- vt->state = TTY_STATE_CSI;
- } else if (ch == '(') {
- vt->state = TTY_STATE_G0;
- } else if (ch == ')') {
- vt->state = TTY_STATE_G1;
- } else if (ch == ']' || ch == 'P' || ch == 'X'
- || ch == '^' || ch == '_') {
- /* String sequences: OSC, DCS, SOS, PM, APC */
- vt->state = TTY_STATE_OSC;
- } else if (ch == '7') {
- vt100_save_cursor(vt);
- vt->state = TTY_STATE_NORM;
- } else if (ch == '8') {
- vt100_restore_cursor(vt);
- vt->state = TTY_STATE_NORM;
- } else {
- vt->state = TTY_STATE_NORM;
- }
- break;
- case TTY_STATE_CSI: /* handle escape sequence parameters */
- if (ch >= '0' && ch <= '9') {
- 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 (vt->nb_esc_params < MAX_ESC_PARAMS)
- vt->nb_esc_params++;
- if (ch == ';' || ch == '?') {
- break;
- }
- 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 (vt->esc_params[0] == 0) {
- vt->esc_params[0] = 1;
- }
- vt100_set_cursor(vt, vt->x, vt->y - vt->esc_params[0]);
- break;
- case 'B':
- /* move cursor down */
- if (vt->esc_params[0] == 0) {
- vt->esc_params[0] = 1;
- }
- vt100_set_cursor(vt, vt->x, vt->y + vt->esc_params[0]);
- break;
- case 'C':
- /* move cursor right */
- if (vt->esc_params[0] == 0) {
- vt->esc_params[0] = 1;
- }
- vt100_set_cursor(vt, vt->x + vt->esc_params[0], vt->y);
- break;
- case 'D':
- /* move cursor left */
- if (vt->esc_params[0] == 0) {
- vt->esc_params[0] = 1;
- }
- vt100_set_cursor(vt, vt->x - vt->esc_params[0], vt->y);
- break;
- case 'G':
- /* move cursor to column */
- vt100_set_cursor(vt, vt->esc_params[0] - 1, vt->y);
- break;
- case 'f':
- case 'H':
- /* move cursor to row, column */
- vt100_set_cursor(vt, vt->esc_params[1] - 1, vt->esc_params[0] - 1);
- break;
- case 'J':
- switch (vt->esc_params[0]) {
- case 0:
- /* clear to end of screen */
- for (y = vt->y; y < vt->height; y++) {
- for (x = 0; x < vt->width; x++) {
- if (y == vt->y && x < vt->x) {
- continue;
- }
- vt100_clear_xy(vt, x, y);
- }
- }
- break;
- case 1:
- /* clear from beginning of screen */
- for (y = 0; y <= vt->y; y++) {
- for (x = 0; x < vt->width; x++) {
- if (y == vt->y && x > vt->x) {
- break;
- }
- vt100_clear_xy(vt, x, y);
- }
- }
- break;
- case 2:
- /* clear entire screen */
- for (y = 0; y < vt->height; y++) {
- for (x = 0; x < vt->width; x++) {
- vt100_clear_xy(vt, x, y);
- }
- }
- break;
- }
- break;
- case 'K':
- switch (vt->esc_params[0]) {
- case 0:
- /* clear to eol */
- for(x = vt->x; x < vt->width; x++) {
- 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++) {
- vt100_clear_xy(vt, x, vt->y);
- }
- break;
- case 2:
- /* clear entire line */
- for(x = 0; x < vt->width; x++) {
- vt100_clear_xy(vt, x, vt->y);
- }
- break;
- }
- break;
- case 'P':
- vt100_csi_P(vt, vt->esc_params[0]);
- break;
- case 'm':
- vt100_handle_escape(vt);
- break;
- case 'n':
- switch (vt->esc_params[0]) {
- case 5:
- /* report console status (always succeed)*/
- 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);
- vt100_write(vt, response, strlen(response));
- break;
- }
- break;
- case 's':
- vt100_save_cursor(vt);
- break;
- case 'u':
- vt100_restore_cursor(vt);
- break;
- case '@':
- vt100_csi_at(vt, vt->esc_params[0]);
- break;
- default:
- trace_console_putchar_unhandled(ch);
- break;
- }
- break;
- }
- break;
- case TTY_STATE_OSC: /* Operating System Command: ESC ] ... BEL/ST */
- if (ch == '\a') {
- /* BEL terminates OSC */
- vt->state = TTY_STATE_NORM;
- } else if (ch == 27) {
- /* ESC might start ST (ESC \) */
- vt->state = TTY_STATE_ESC;
- }
- /* All other bytes are silently consumed */
- break;
- case TTY_STATE_G0: /* set character sets */
- case TTY_STATE_G1: /* set character sets */
- switch (ch) {
- case 'B':
- /* Latin-1 map */
- break;
- }
- vt->state = TTY_STATE_NORM;
- break;
- }
-}
-
#define TYPE_CHARDEV_VC "chardev-vc"
DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
TYPE_CHARDEV_VC)
-static size_t vt100_input(QemuVT100 *vt, const uint8_t *buf, size_t len)
-{
- 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);
- for(i = 0; i < len; i++) {
- vt100_putchar(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);
- }
- return len;
-}
-
static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
VCChardev *drv = VC_CHARDEV(chr);
@@ -1093,30 +111,6 @@ static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
return vt100_input(&s->vt, buf, len);
}
-void vt100_update_cursor(void)
-{
- QemuVT100 *vt;
-
- cursor_visible_phase = !cursor_visible_phase;
-
- if (QTAILQ_EMPTY(&vt100s)) {
- return;
- }
-
- QTAILQ_FOREACH(vt, &vt100s, list) {
- vt100_refresh(vt);
- }
-
- timer_mod(cursor_timer,
- qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
-}
-
-static void
-cursor_timer_cb(void *opaque)
-{
- vt100_update_cursor();
-}
-
static void text_console_invalidate(void *opaque)
{
QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
@@ -1127,13 +121,6 @@ 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)
{
@@ -1212,25 +199,6 @@ static void text_console_out_flush(QemuVT100 *vt)
qemu_text_console_out_flush(console);
}
-static void vt100_init(QemuVT100 *vt,
- pixman_image_t *image,
- 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);
- }
-
- 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;
diff --git a/ui/console.c b/ui/console.c
index c997e8df572..7ffea2776ef 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -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"
diff --git a/ui/vt100.c b/ui/vt100.c
new file mode 100644
index 00000000000..ef97eb7ba67
--- /dev/null
+++ b/ui/vt100.c
@@ -0,0 +1,986 @@
+/*
+ * SPDX-License-Identifier: MIT
+ * QEMU vt100
+ */
+#include "qemu/osdep.h"
+#include "qemu/timer.h"
+#include "cp437.h"
+#include "vgafont.h"
+#include "vt100.h"
+
+#include "trace.h"
+
+#define DEFAULT_BACKSCROLL 512
+#define CONSOLE_CURSOR_PERIOD 500
+
+static const pixman_color_t color_table_rgb[2][8] = {
+ { /* dark */
+ [QEMU_COLOR_BLACK] = QEMU_PIXMAN_COLOR_BLACK,
+ [QEMU_COLOR_BLUE] = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xaa), /* blue */
+ [QEMU_COLOR_GREEN] = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0x00), /* green */
+ [QEMU_COLOR_CYAN] = QEMU_PIXMAN_COLOR(0x00, 0xaa, 0xaa), /* cyan */
+ [QEMU_COLOR_RED] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0x00), /* red */
+ [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xaa, 0x00, 0xaa), /* magenta */
+ [QEMU_COLOR_YELLOW] = QEMU_PIXMAN_COLOR(0xaa, 0xaa, 0x00), /* yellow */
+ [QEMU_COLOR_WHITE] = QEMU_PIXMAN_COLOR_GRAY,
+ },
+ { /* bright */
+ [QEMU_COLOR_BLACK] = QEMU_PIXMAN_COLOR_BLACK,
+ [QEMU_COLOR_BLUE] = QEMU_PIXMAN_COLOR(0x00, 0x00, 0xff), /* blue */
+ [QEMU_COLOR_GREEN] = QEMU_PIXMAN_COLOR(0x00, 0xff, 0x00), /* green */
+ [QEMU_COLOR_CYAN] = QEMU_PIXMAN_COLOR(0x00, 0xff, 0xff), /* cyan */
+ [QEMU_COLOR_RED] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0x00), /* red */
+ [QEMU_COLOR_MAGENTA] = QEMU_PIXMAN_COLOR(0xff, 0x00, 0xff), /* magenta */
+ [QEMU_COLOR_YELLOW] = QEMU_PIXMAN_COLOR(0xff, 0xff, 0x00), /* yellow */
+ [QEMU_COLOR_WHITE] = QEMU_PIXMAN_COLOR(0xff, 0xff, 0xff), /* white */
+ }
+};
+
+static bool cursor_visible_phase;
+static QEMUTimer *cursor_timer;
+static QTAILQ_HEAD(QemuVT100Head, QemuVT100) vt100s =
+ QTAILQ_HEAD_INITIALIZER(vt100s);
+
+static void image_fill_rect(pixman_image_t *image, int posx, int posy,
+ int width, int height, pixman_color_t color)
+{
+ pixman_rectangle16_t rect = {
+ .x = posx, .y = posy, .width = width, .height = height
+ };
+
+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, image,
+ &color, 1, &rect);
+}
+
+/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
+static void image_bitblt(pixman_image_t *image,
+ int xs, int ys, int xd, int yd, int w, int h)
+{
+ pixman_image_composite(PIXMAN_OP_SRC,
+ image, NULL, image,
+ xs, ys, 0, 0, xd, yd, w, h);
+}
+
+static void vt100_putcharxy(QemuVT100 *vt, int x, int y, int ch,
+ TextAttributes *t_attrib)
+{
+ static pixman_image_t *glyphs[256];
+ pixman_color_t fgcol, bgcol;
+
+ assert(vt->image);
+ if (t_attrib->invers) {
+ bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+ fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
+ } else {
+ fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
+ bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
+ }
+
+ if (!glyphs[ch]) {
+ glyphs[ch] = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, ch);
+ }
+ qemu_pixman_glyph_render(glyphs[ch], vt->image,
+ &fgcol, &bgcol, x, y, FONT_WIDTH, FONT_HEIGHT);
+}
+
+static void vt100_invalidate_xy(QemuVT100 *vt, int x, int y)
+{
+ if (vt->update_x0 > x * FONT_WIDTH) {
+ vt->update_x0 = x * FONT_WIDTH;
+ }
+ if (vt->update_y0 > y * FONT_HEIGHT) {
+ vt->update_y0 = y * FONT_HEIGHT;
+ }
+ if (vt->update_x1 < (x + 1) * FONT_WIDTH) {
+ vt->update_x1 = (x + 1) * FONT_WIDTH;
+ }
+ if (vt->update_y1 < (y + 1) * FONT_HEIGHT) {
+ vt->update_y1 = (y + 1) * FONT_HEIGHT;
+ }
+}
+
+static void vt100_show_cursor(QemuVT100 *vt, int show)
+{
+ TextCell *c;
+ int y, y1;
+ int x = vt->x;
+
+ vt->cursor_invalidate = 1;
+
+ if (x >= vt->width) {
+ x = vt->width - 1;
+ }
+ y1 = (vt->y_base + vt->y) % vt->total_height;
+ y = y1 - vt->y_displayed;
+ if (y < 0) {
+ y += vt->total_height;
+ }
+ if (y < vt->height) {
+ c = &vt->cells[y1 * vt->width + x];
+ if (show && cursor_visible_phase) {
+ TextAttributes t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
+ vt100_putcharxy(vt, x, y, c->ch, &t_attrib);
+ } else {
+ vt100_putcharxy(vt, x, y, c->ch, &(c->t_attrib));
+ }
+ vt100_invalidate_xy(vt, x, y);
+ }
+}
+
+static void vt100_image_update(QemuVT100 *vt, int x, int y, int width, int height)
+{
+ vt->image_update(vt, x, y, width, height);
+}
+
+void vt100_refresh(QemuVT100 *vt)
+{
+ TextCell *c;
+ int x, y, y1;
+ int w = pixman_image_get_width(vt->image);
+ int h = pixman_image_get_height(vt->image);
+
+ vt->text_x[0] = 0;
+ vt->text_y[0] = 0;
+ vt->text_x[1] = vt->width - 1;
+ vt->text_y[1] = vt->height - 1;
+ vt->cursor_invalidate = 1;
+
+ image_fill_rect(vt->image, 0, 0, w, h,
+ color_table_rgb[0][QEMU_COLOR_BLACK]);
+ y1 = vt->y_displayed;
+ for (y = 0; y < vt->height; y++) {
+ c = vt->cells + y1 * vt->width;
+ for (x = 0; x < vt->width; x++) {
+ vt100_putcharxy(vt, x, y, c->ch,
+ &(c->t_attrib));
+ c++;
+ }
+ if (++y1 == vt->total_height) {
+ y1 = 0;
+ }
+ }
+ vt100_show_cursor(vt, 1);
+ vt100_image_update(vt, 0, 0, w, h);
+}
+
+static void vt100_scroll(QemuVT100 *vt, int ydelta)
+{
+ int i, y1;
+
+ if (ydelta > 0) {
+ for (i = 0; i < ydelta; i++) {
+ if (vt->y_displayed == vt->y_base) {
+ break;
+ }
+ if (++vt->y_displayed == vt->total_height) {
+ vt->y_displayed = 0;
+ }
+ }
+ } else {
+ ydelta = -ydelta;
+ i = vt->backscroll_height;
+ if (i > vt->total_height - vt->height) {
+ i = vt->total_height - vt->height;
+ }
+ y1 = vt->y_base - i;
+ if (y1 < 0) {
+ y1 += vt->total_height;
+ }
+ for (i = 0; i < ydelta; i++) {
+ if (vt->y_displayed == y1) {
+ break;
+ }
+ if (--vt->y_displayed < 0) {
+ vt->y_displayed = vt->total_height - 1;
+ }
+ }
+ }
+ vt100_refresh(vt);
+}
+
+static void vt100_write(QemuVT100 *vt, const void *buf, size_t len)
+{
+ uint32_t num_free;
+
+ num_free = fifo8_num_free(&vt->out_fifo);
+ fifo8_push_all(&vt->out_fifo, buf, MIN(num_free, len));
+ vt->out_flush(vt);
+}
+
+void vt100_set_image(QemuVT100 *vt, pixman_image_t *image)
+{
+ TextCell *cells, *c, *c1;
+ int w1, x, y, last_width, w, h;
+
+ vt->image = image;
+ w = pixman_image_get_width(vt->image) / FONT_WIDTH;
+ h = pixman_image_get_height(vt->image) / FONT_HEIGHT;
+ if (w == vt->width && h == vt->height) {
+ return;
+ }
+
+ last_width = vt->width;
+ vt->width = w;
+ vt->height = h;
+
+ w1 = MIN(vt->width, last_width);
+
+ cells = g_new(TextCell, vt->width * vt->total_height + 1);
+ for (y = 0; y < vt->total_height; y++) {
+ c = &cells[y * vt->width];
+ if (w1 > 0) {
+ c1 = &vt->cells[y * last_width];
+ for (x = 0; x < w1; x++) {
+ *c++ = *c1++;
+ }
+ }
+ for (x = w1; x < vt->width; x++) {
+ c->ch = ' ';
+ c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ c++;
+ }
+ }
+ g_free(vt->cells);
+ vt->cells = cells;
+}
+
+static void vt100_put_lf(QemuVT100 *vt)
+{
+ TextCell *c;
+ int x, y1;
+
+ vt->y++;
+ if (vt->y >= vt->height) {
+ vt->y = vt->height - 1;
+
+ if (vt->y_displayed == vt->y_base) {
+ if (++vt->y_displayed == vt->total_height) {
+ vt->y_displayed = 0;
+ }
+ }
+ if (++vt->y_base == vt->total_height) {
+ vt->y_base = 0;
+ }
+ if (vt->backscroll_height < vt->total_height) {
+ vt->backscroll_height++;
+ }
+ y1 = (vt->y_base + vt->height - 1) % vt->total_height;
+ c = &vt->cells[y1 * vt->width];
+ for (x = 0; x < vt->width; x++) {
+ c->ch = ' ';
+ c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ c++;
+ }
+ if (vt->y_displayed == vt->y_base) {
+ vt->text_x[0] = 0;
+ vt->text_y[0] = 0;
+ vt->text_x[1] = vt->width - 1;
+ vt->text_y[1] = vt->height - 1;
+
+ image_bitblt(vt->image, 0, FONT_HEIGHT, 0, 0,
+ vt->width * FONT_WIDTH,
+ (vt->height - 1) * FONT_HEIGHT);
+ image_fill_rect(vt->image, 0, (vt->height - 1) * FONT_HEIGHT,
+ vt->width * FONT_WIDTH, FONT_HEIGHT,
+ color_table_rgb[0][TEXT_ATTRIBUTES_DEFAULT.bgcol]);
+ vt->update_x0 = 0;
+ vt->update_y0 = 0;
+ vt->update_x1 = vt->width * FONT_WIDTH;
+ vt->update_y1 = vt->height * FONT_HEIGHT;
+ }
+ }
+}
+
+/*
+ * Set console attributes depending on the current escape codes.
+ * 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 vt100_handle_escape(QemuVT100 *vt)
+{
+ int i;
+
+ for (i = 0; i < vt->nb_esc_params; i++) {
+ switch (vt->esc_params[i]) {
+ case 0: /* reset all console attributes to default */
+ vt->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ break;
+ case 1:
+ vt->t_attrib.bold = 1;
+ break;
+ case 4:
+ vt->t_attrib.uline = 1;
+ break;
+ case 5:
+ vt->t_attrib.blink = 1;
+ break;
+ case 7:
+ vt->t_attrib.invers = 1;
+ break;
+ case 8:
+ vt->t_attrib.unvisible = 1;
+ break;
+ case 22:
+ vt->t_attrib.bold = 0;
+ break;
+ case 24:
+ vt->t_attrib.uline = 0;
+ break;
+ case 25:
+ vt->t_attrib.blink = 0;
+ break;
+ case 27:
+ vt->t_attrib.invers = 0;
+ break;
+ case 28:
+ vt->t_attrib.unvisible = 0;
+ break;
+ /* set foreground color */
+ case 30:
+ vt->t_attrib.fgcol = QEMU_COLOR_BLACK;
+ break;
+ case 31:
+ vt->t_attrib.fgcol = QEMU_COLOR_RED;
+ break;
+ case 32:
+ vt->t_attrib.fgcol = QEMU_COLOR_GREEN;
+ break;
+ case 33:
+ vt->t_attrib.fgcol = QEMU_COLOR_YELLOW;
+ break;
+ case 34:
+ vt->t_attrib.fgcol = QEMU_COLOR_BLUE;
+ break;
+ case 35:
+ vt->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
+ break;
+ case 36:
+ vt->t_attrib.fgcol = QEMU_COLOR_CYAN;
+ break;
+ case 37:
+ vt->t_attrib.fgcol = QEMU_COLOR_WHITE;
+ break;
+ /* set background color */
+ case 40:
+ vt->t_attrib.bgcol = QEMU_COLOR_BLACK;
+ break;
+ case 41:
+ vt->t_attrib.bgcol = QEMU_COLOR_RED;
+ break;
+ case 42:
+ vt->t_attrib.bgcol = QEMU_COLOR_GREEN;
+ break;
+ case 43:
+ vt->t_attrib.bgcol = QEMU_COLOR_YELLOW;
+ break;
+ case 44:
+ vt->t_attrib.bgcol = QEMU_COLOR_BLUE;
+ break;
+ case 45:
+ vt->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
+ break;
+ case 46:
+ vt->t_attrib.bgcol = QEMU_COLOR_CYAN;
+ break;
+ case 47:
+ vt->t_attrib.bgcol = QEMU_COLOR_WHITE;
+ break;
+ }
+ }
+}
+
+static void vt100_update_xy(QemuVT100 *vt, int x, int y)
+{
+ TextCell *c;
+ int y1, y2;
+
+ vt->text_x[0] = MIN(vt->text_x[0], x);
+ vt->text_x[1] = MAX(vt->text_x[1], x);
+ vt->text_y[0] = MIN(vt->text_y[0], y);
+ vt->text_y[1] = MAX(vt->text_y[1], y);
+
+ y1 = (vt->y_base + y) % vt->total_height;
+ y2 = y1 - vt->y_displayed;
+ if (y2 < 0) {
+ y2 += vt->total_height;
+ }
+ if (y2 < vt->height) {
+ if (x >= vt->width) {
+ x = vt->width - 1;
+ }
+ c = &vt->cells[y1 * vt->width + x];
+ vt100_putcharxy(vt, x, y2, c->ch,
+ &(c->t_attrib));
+ vt100_invalidate_xy(vt, x, y2);
+ }
+}
+
+static void vt100_clear_xy(QemuVT100 *vt, int x, int y)
+{
+ int y1 = (vt->y_base + y) % vt->total_height;
+ if (x >= vt->width) {
+ x = vt->width - 1;
+ }
+ TextCell *c = &vt->cells[y1 * vt->width + x];
+ c->ch = ' ';
+ c->t_attrib = TEXT_ATTRIBUTES_DEFAULT;
+ vt100_update_xy(vt, x, y);
+}
+
+/*
+ * UTF-8 DFA decoder by Bjoern Hoehrmann.
+ * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
+ * See https://github.com/polijan/utf8_decode for details.
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#define BH_UTF8_ACCEPT 0
+#define BH_UTF8_REJECT 12
+
+static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
+{
+ static const uint8_t utf8d[] = {
+ /* character class lookup */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
+ 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
+ 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+
+ /* state transition lookup */
+ 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
+ 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
+ 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
+ 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
+ 12,36,12,12,12,12,12,12,12,12,12,12,
+ };
+ uint32_t type = utf8d[byte];
+
+ *codep = (*state != BH_UTF8_ACCEPT) ?
+ (byte & 0x3fu) | (*codep << 6) :
+ (0xffu >> type) & (byte);
+
+ *state = utf8d[256 + *state + type];
+ return *state;
+}
+
+static void vt100_put_one(QemuVT100 *vt, int ch)
+{
+ TextCell *c;
+ int y1;
+ if (vt->x >= vt->width) {
+ /* line wrap */
+ vt->x = 0;
+ vt100_put_lf(vt);
+ }
+ y1 = (vt->y_base + vt->y) % vt->total_height;
+ c = &vt->cells[y1 * vt->width + vt->x];
+ c->ch = ch;
+ c->t_attrib = vt->t_attrib;
+ vt100_update_xy(vt, vt->x, vt->y);
+ vt->x++;
+}
+
+/* set cursor, checking bounds */
+static void vt100_set_cursor(QemuVT100 *vt, int x, int y)
+{
+ if (x < 0) {
+ x = 0;
+ }
+ if (y < 0) {
+ y = 0;
+ }
+ if (y >= vt->height) {
+ y = vt->height - 1;
+ }
+ if (x >= vt->width) {
+ x = vt->width - 1;
+ }
+
+ vt->x = x;
+ vt->y = y;
+}
+
+/**
+ * vt100_csi_P() - (DCH) deletes one or more characters from the cursor
+ * position to the right. As characters are deleted, the remaining
+ * characters between the cursor and right margin move to the
+ * left. Character attributes move with the characters.
+ */
+static void vt100_csi_P(QemuVT100 *vt, unsigned int nr)
+{
+ TextCell *c1, *c2;
+ unsigned int x1, x2, y;
+ unsigned int end, len;
+
+ if (!nr) {
+ nr = 1;
+ }
+ if (nr > vt->width - vt->x) {
+ nr = vt->width - vt->x;
+ if (!nr) {
+ return;
+ }
+ }
+
+ x1 = vt->x;
+ x2 = vt->x + nr;
+ len = vt->width - x2;
+ if (len) {
+ y = (vt->y_base + vt->y) % vt->total_height;
+ c1 = &vt->cells[y * vt->width + x1];
+ c2 = &vt->cells[y * vt->width + x2];
+ memmove(c1, c2, len * sizeof(*c1));
+ for (end = x1 + len; x1 < end; x1++) {
+ vt100_update_xy(vt, x1, vt->y);
+ }
+ }
+ /* Clear the rest */
+ for (; x1 < vt->width; x1++) {
+ vt100_clear_xy(vt, x1, vt->y);
+ }
+}
+
+/**
+ * vt100_csi_at() - (ICH) inserts `nr` blank characters with the default
+ * character attribute. The cursor remains at the beginning of the
+ * blank characters. Text between the cursor and right margin moves to
+ * the right. Characters scrolled past the right margin are lost.
+ */
+static void vt100_csi_at(QemuVT100 *vt, unsigned int nr)
+{
+ TextCell *c1, *c2;
+ unsigned int x1, x2, y;
+ unsigned int end, len;
+
+ if (!nr) {
+ nr = 1;
+ }
+ if (nr > vt->width - vt->x) {
+ nr = vt->width - vt->x;
+ if (!nr) {
+ return;
+ }
+ }
+
+ x1 = vt->x + nr;
+ x2 = vt->x;
+ len = vt->width - x1;
+ if (len) {
+ y = (vt->y_base + vt->y) % vt->total_height;
+ c1 = &vt->cells[y * vt->width + x1];
+ c2 = &vt->cells[y * vt->width + x2];
+ memmove(c1, c2, len * sizeof(*c1));
+ for (end = x1 + len; x1 < end; x1++) {
+ vt100_update_xy(vt, x1, vt->y);
+ }
+ }
+ /* Insert blanks */
+ for (x1 = vt->x; x1 < vt->x + nr; x1++) {
+ vt100_clear_xy(vt, x1, vt->y);
+ }
+}
+
+/**
+ * vt100_save_cursor() - saves cursor position and character attributes.
+ */
+static void vt100_save_cursor(QemuVT100 *vt)
+{
+ vt->x_saved = vt->x;
+ vt->y_saved = vt->y;
+ vt->t_attrib_saved = vt->t_attrib;
+}
+
+/**
+ * vt100_restore_cursor() - restores cursor position and character
+ * attributes from saved state.
+ */
+static void vt100_restore_cursor(QemuVT100 *vt)
+{
+ vt->x = vt->x_saved;
+ vt->y = vt->y_saved;
+ vt->t_attrib = vt->t_attrib_saved;
+}
+
+static void vt100_putchar(QemuVT100 *vt, int ch)
+{
+ int i;
+ int x, y;
+ g_autofree char *response = NULL;
+
+ switch (vt->state) {
+ case TTY_STATE_NORM:
+ /* Feed byte through the UTF-8 DFA decoder */
+ if (ch >= 0x80) {
+ switch (bh_utf8_decode(&vt->utf8_state, &vt->utf8_codepoint, ch)) {
+ case BH_UTF8_ACCEPT:
+ vt100_put_one(vt, unicode_to_cp437(vt->utf8_codepoint));
+ break;
+ case BH_UTF8_REJECT:
+ /* Reset state so the decoder can resync */
+ vt->utf8_state = BH_UTF8_ACCEPT;
+ break;
+ default:
+ /* Need more bytes */
+ break;
+ }
+ break;
+ }
+ /* ASCII byte: abort any pending UTF-8 sequence */
+ vt->utf8_state = BH_UTF8_ACCEPT;
+ switch (ch) {
+ case '\r': /* carriage return */
+ vt->x = 0;
+ break;
+ case '\n': /* newline */
+ vt100_put_lf(vt);
+ break;
+ case '\b': /* backspace */
+ if (vt->x > 0) {
+ vt->x--;
+ }
+ break;
+ case '\t': /* tabspace */
+ if (vt->x + (8 - (vt->x % 8)) > vt->width) {
+ vt->x = 0;
+ vt100_put_lf(vt);
+ } else {
+ vt->x = vt->x + (8 - (vt->x % 8));
+ }
+ break;
+ case '\a': /* alert aka. bell */
+ /* TODO: has to be implemented */
+ break;
+ case 14:
+ /* SO (shift out), character set 1 (ignored) */
+ break;
+ case 15:
+ /* SI (shift in), character set 0 (ignored) */
+ break;
+ case 27: /* esc (introducing an escape sequence) */
+ vt->state = TTY_STATE_ESC;
+ break;
+ default:
+ 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++) {
+ vt->esc_params[i] = 0;
+ }
+ vt->nb_esc_params = 0;
+ vt->state = TTY_STATE_CSI;
+ } else if (ch == '(') {
+ vt->state = TTY_STATE_G0;
+ } else if (ch == ')') {
+ vt->state = TTY_STATE_G1;
+ } else if (ch == ']' || ch == 'P' || ch == 'X'
+ || ch == '^' || ch == '_') {
+ /* String sequences: OSC, DCS, SOS, PM, APC */
+ vt->state = TTY_STATE_OSC;
+ } else if (ch == '7') {
+ vt100_save_cursor(vt);
+ vt->state = TTY_STATE_NORM;
+ } else if (ch == '8') {
+ vt100_restore_cursor(vt);
+ vt->state = TTY_STATE_NORM;
+ } else {
+ vt->state = TTY_STATE_NORM;
+ }
+ break;
+ case TTY_STATE_CSI: /* handle escape sequence parameters */
+ if (ch >= '0' && ch <= '9') {
+ 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 (vt->nb_esc_params < MAX_ESC_PARAMS) {
+ vt->nb_esc_params++;
+ }
+ if (ch == ';' || ch == '?') {
+ break;
+ }
+ 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 (vt->esc_params[0] == 0) {
+ vt->esc_params[0] = 1;
+ }
+ vt100_set_cursor(vt, vt->x, vt->y - vt->esc_params[0]);
+ break;
+ case 'B':
+ /* move cursor down */
+ if (vt->esc_params[0] == 0) {
+ vt->esc_params[0] = 1;
+ }
+ vt100_set_cursor(vt, vt->x, vt->y + vt->esc_params[0]);
+ break;
+ case 'C':
+ /* move cursor right */
+ if (vt->esc_params[0] == 0) {
+ vt->esc_params[0] = 1;
+ }
+ vt100_set_cursor(vt, vt->x + vt->esc_params[0], vt->y);
+ break;
+ case 'D':
+ /* move cursor left */
+ if (vt->esc_params[0] == 0) {
+ vt->esc_params[0] = 1;
+ }
+ vt100_set_cursor(vt, vt->x - vt->esc_params[0], vt->y);
+ break;
+ case 'G':
+ /* move cursor to column */
+ vt100_set_cursor(vt, vt->esc_params[0] - 1, vt->y);
+ break;
+ case 'f':
+ case 'H':
+ /* move cursor to row, column */
+ vt100_set_cursor(vt, vt->esc_params[1] - 1, vt->esc_params[0] - 1);
+ break;
+ case 'J':
+ switch (vt->esc_params[0]) {
+ case 0:
+ /* clear to end of screen */
+ for (y = vt->y; y < vt->height; y++) {
+ for (x = 0; x < vt->width; x++) {
+ if (y == vt->y && x < vt->x) {
+ continue;
+ }
+ vt100_clear_xy(vt, x, y);
+ }
+ }
+ break;
+ case 1:
+ /* clear from beginning of screen */
+ for (y = 0; y <= vt->y; y++) {
+ for (x = 0; x < vt->width; x++) {
+ if (y == vt->y && x > vt->x) {
+ break;
+ }
+ vt100_clear_xy(vt, x, y);
+ }
+ }
+ break;
+ case 2:
+ /* clear entire screen */
+ for (y = 0; y < vt->height; y++) {
+ for (x = 0; x < vt->width; x++) {
+ vt100_clear_xy(vt, x, y);
+ }
+ }
+ break;
+ }
+ break;
+ case 'K':
+ switch (vt->esc_params[0]) {
+ case 0:
+ /* clear to eol */
+ for (x = vt->x; x < vt->width; x++) {
+ 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++) {
+ vt100_clear_xy(vt, x, vt->y);
+ }
+ break;
+ case 2:
+ /* clear entire line */
+ for (x = 0; x < vt->width; x++) {
+ vt100_clear_xy(vt, x, vt->y);
+ }
+ break;
+ }
+ break;
+ case 'P':
+ vt100_csi_P(vt, vt->esc_params[0]);
+ break;
+ case 'm':
+ vt100_handle_escape(vt);
+ break;
+ case 'n':
+ switch (vt->esc_params[0]) {
+ case 5:
+ /* report console status (always succeed)*/
+ 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);
+ vt100_write(vt, response, strlen(response));
+ break;
+ }
+ break;
+ case 's':
+ vt100_save_cursor(vt);
+ break;
+ case 'u':
+ vt100_restore_cursor(vt);
+ break;
+ case '@':
+ vt100_csi_at(vt, vt->esc_params[0]);
+ break;
+ default:
+ trace_console_putchar_unhandled(ch);
+ break;
+ }
+ break;
+ }
+ break;
+ case TTY_STATE_OSC: /* Operating System Command: ESC ] ... BEL/ST */
+ if (ch == '\a') {
+ /* BEL terminates OSC */
+ vt->state = TTY_STATE_NORM;
+ } else if (ch == 27) {
+ /* ESC might start ST (ESC \) */
+ vt->state = TTY_STATE_ESC;
+ }
+ /* All other bytes are silently consumed */
+ break;
+ case TTY_STATE_G0: /* set character sets */
+ case TTY_STATE_G1: /* set character sets */
+ switch (ch) {
+ case 'B':
+ /* Latin-1 map */
+ break;
+ }
+ vt->state = TTY_STATE_NORM;
+ break;
+ }
+
+}
+
+size_t vt100_input(QemuVT100 *vt, const uint8_t *buf, size_t len)
+{
+ 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);
+ for (i = 0; i < len; i++) {
+ vt100_putchar(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);
+ }
+ return len;
+}
+
+void vt100_keysym(QemuVT100 *vt, int keysym)
+{
+ uint8_t buf[16], *q;
+ int c;
+
+ switch (keysym) {
+ case QEMU_KEY_CTRL_UP:
+ vt100_scroll(vt, -1);
+ break;
+ case QEMU_KEY_CTRL_DOWN:
+ vt100_scroll(vt, 1);
+ break;
+ case QEMU_KEY_CTRL_PAGEUP:
+ vt100_scroll(vt, -10);
+ break;
+ case QEMU_KEY_CTRL_PAGEDOWN:
+ vt100_scroll(vt, 10);
+ break;
+ default:
+ /* convert the QEMU keysym to VT100 key string */
+ q = buf;
+ if (keysym >= 0xe100 && keysym <= 0xe11f) {
+ *q++ = '\033';
+ *q++ = '[';
+ c = keysym - 0xe100;
+ if (c >= 10) {
+ *q++ = '0' + (c / 10);
+ }
+ *q++ = '0' + (c % 10);
+ *q++ = '~';
+ } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
+ *q++ = '\033';
+ *q++ = '[';
+ *q++ = keysym & 0xff;
+ } else if (vt->echo && (keysym == '\r' || keysym == '\n')) {
+ vt100_input(vt, (uint8_t *)"\r", 1);
+ *q++ = '\n';
+ } else {
+ *q++ = keysym;
+ }
+ if (vt->echo) {
+ vt100_input(vt, buf, q - buf);
+ }
+ vt100_write(vt, buf, q - buf);
+ break;
+ }
+}
+
+void vt100_update_cursor(void)
+{
+ QemuVT100 *vt;
+
+ cursor_visible_phase = !cursor_visible_phase;
+
+ if (QTAILQ_EMPTY(&vt100s)) {
+ return;
+ }
+
+ QTAILQ_FOREACH(vt, &vt100s, list) {
+ vt100_refresh(vt);
+ }
+
+ timer_mod(cursor_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + CONSOLE_CURSOR_PERIOD / 2);
+}
+
+static void
+cursor_timer_cb(void *opaque)
+{
+ vt100_update_cursor();
+}
+
+void vt100_init(QemuVT100 *vt,
+ pixman_image_t *image,
+ 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);
+ }
+
+ 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);
+}
+
+void vt100_fini(QemuVT100 *vt)
+{
+ QTAILQ_REMOVE(&vt100s, vt, list);
+ fifo8_destroy(&vt->out_fifo);
+ g_free(vt->cells);
+}
diff --git a/ui/meson.build b/ui/meson.build
index 25657af50e7..9ece6f262b6 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -3,6 +3,7 @@ system_ss.add(png)
system_ss.add(files(
'clipboard.c',
'console.c',
+ 'cp437.c',
'cursor.c',
'dmabuf.c',
'input-keymap.c',
@@ -16,8 +17,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
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 34/67] util: move datadir.c from system/
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (32 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 33/67] ui/console-vc: move VT100 emulation into separate unit Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 35/67] ui: move DisplaySurface functions to display-surface.c Marc-André Lureau
` (32 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
The datadir module provides general-purpose data file lookup
utilities that are not specific to system emulation. Move it
to util/ so it can be reused more broadly.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
{system => util}/datadir.c | 0
system/meson.build | 1 -
system/trace-events | 1 -
util/meson.build | 1 +
util/trace-events | 3 +++
5 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/system/datadir.c b/util/datadir.c
similarity index 100%
rename from system/datadir.c
rename to util/datadir.c
diff --git a/system/meson.build b/system/meson.build
index 579e8353d53..9cdfe1b3e75 100644
--- a/system/meson.build
+++ b/system/meson.build
@@ -8,7 +8,6 @@ system_ss.add(files(
'bootdevice.c',
'cpus.c',
'cpu-timers.c',
- 'datadir.c',
'dirtylimit.c',
'dma-helpers.c',
'exit-with-parent.c',
diff --git a/system/trace-events b/system/trace-events
index 6d29a823f04..e6e1b612798 100644
--- a/system/trace-events
+++ b/system/trace-events
@@ -46,7 +46,6 @@ vm_stop_flush_all(int ret) "ret %d"
# vl.c
vm_state_notify(int running, int reason, const char *reason_str) "running %d reason %d (%s)"
-load_file(const char *name, const char *path) "name %s location %s"
runstate_set(int current_state, const char *current_state_str, int new_state, const char *new_state_str) "current_run_state %d (%s) new_state %d (%s)"
system_wakeup_request(int reason) "reason=%d"
qemu_system_shutdown_request(int reason) "reason=%d"
diff --git a/util/meson.build b/util/meson.build
index 5d3fff0eea4..8bed0267c07 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -30,6 +30,7 @@ util_ss.add(when: linux_io_uring, if_true: files('fdmon-io_uring.c'))
if glib_has_gslice
util_ss.add(files('qtree.c'))
endif
+util_ss.add(files('datadir.c'))
util_ss.add(files('defer-call.c'))
util_ss.add(files('envlist.c', 'path.c', 'module.c'))
util_ss.add(files('event.c'))
diff --git a/util/trace-events b/util/trace-events
index 540d6625073..df549646d12 100644
--- a/util/trace-events
+++ b/util/trace-events
@@ -114,3 +114,6 @@ uffd_unregister_memory_failed(void *addr, uint64_t length, int err) "addr: %p le
# module.c
module_load_module(const char *name) "file %s"
module_lookup_object_type(const char *name) "name %s"
+
+# datadir.c
+load_file(const char *name, const char *path) "name %s location %s"
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 35/67] ui: move DisplaySurface functions to display-surface.c
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (33 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 34/67] util: move datadir.c from system/ Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 36/67] ui: make qemu_default_pixelformat() static inline Marc-André Lureau
` (31 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Extract DisplaySurface creation and destruction functions from console.c
into their own file to reduce the size of console.c and improve code
organization.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console.c | 96 ---------------------------------------------
ui/display-surface.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++
ui/meson.build | 1 +
3 files changed, 108 insertions(+), 96 deletions(-)
diff --git a/ui/console.c b/ui/console.c
index 7ffea2776ef..24794e5a9dc 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -507,102 +507,6 @@ qemu_graphic_console_init(Object *obj)
{
}
-void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
- qemu_pixman_shareable handle,
- uint32_t offset)
-{
- assert(surface->share_handle == SHAREABLE_NONE);
-
- surface->share_handle = handle;
- surface->share_handle_offset = offset;
-
-}
-
-DisplaySurface *qemu_create_displaysurface(int width, int height)
-{
- trace_displaysurface_create(width, height);
-
- return qemu_create_displaysurface_from(
- width, height,
- PIXMAN_x8r8g8b8,
- width * 4, NULL
- );
-}
-
-DisplaySurface *qemu_create_displaysurface_from(int width, int height,
- pixman_format_code_t format,
- int linesize, uint8_t *data)
-{
- DisplaySurface *surface = g_new0(DisplaySurface, 1);
-
- trace_displaysurface_create_from(surface, width, height, format);
- surface->share_handle = SHAREABLE_NONE;
-
- if (data) {
- surface->image = pixman_image_create_bits(format,
- width, height,
- (void *)data, linesize);
- } else {
- qemu_pixman_image_new_shareable(&surface->image,
- &surface->share_handle,
- "displaysurface",
- format,
- width,
- height,
- linesize,
- &error_abort);
- surface->flags = QEMU_ALLOCATED_FLAG;
- }
-
- assert(surface->image != NULL);
- return surface;
-}
-
-DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
-{
- DisplaySurface *surface = g_new0(DisplaySurface, 1);
-
- trace_displaysurface_create_pixman(surface);
- surface->share_handle = SHAREABLE_NONE;
- surface->image = pixman_image_ref(image);
-
- return surface;
-}
-
-DisplaySurface *qemu_create_placeholder_surface(int w, int h,
- const char *msg)
-{
- DisplaySurface *surface = qemu_create_displaysurface(w, h);
-#ifdef CONFIG_PIXMAN
- pixman_color_t bg = QEMU_PIXMAN_COLOR_BLACK;
- pixman_color_t fg = QEMU_PIXMAN_COLOR_GRAY;
- pixman_image_t *glyph;
- int len, x, y, i;
-
- len = strlen(msg);
- x = (w / FONT_WIDTH - len) / 2;
- y = (h / FONT_HEIGHT - 1) / 2;
- for (i = 0; i < len; i++) {
- glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
- qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
- x+i, y, FONT_WIDTH, FONT_HEIGHT);
- qemu_pixman_image_unref(glyph);
- }
-#endif
- surface->flags |= QEMU_PLACEHOLDER_FLAG;
- return surface;
-}
-
-void qemu_free_displaysurface(DisplaySurface *surface)
-{
- if (surface == NULL) {
- return;
- }
- trace_displaysurface_free(surface);
- qemu_pixman_image_unref(surface->image);
- g_free(surface);
-}
-
bool console_has_gl(QemuConsole *con)
{
return con->gl != NULL;
diff --git a/ui/display-surface.c b/ui/display-surface.c
new file mode 100644
index 00000000000..38e408513cc
--- /dev/null
+++ b/ui/display-surface.c
@@ -0,0 +1,107 @@
+/*
+ * QEMU graphical console surface helper
+ *
+ * Copyright (c) 2004 Fabrice Bellard
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#include "qemu/osdep.h"
+#include "ui/console.h"
+#include "ui/vgafont.h"
+#include "trace.h"
+
+void qemu_displaysurface_set_share_handle(DisplaySurface *surface,
+ qemu_pixman_shareable handle,
+ uint32_t offset)
+{
+ assert(surface->share_handle == SHAREABLE_NONE);
+
+ surface->share_handle = handle;
+ surface->share_handle_offset = offset;
+
+}
+
+DisplaySurface *qemu_create_displaysurface(int width, int height)
+{
+ trace_displaysurface_create(width, height);
+
+ return qemu_create_displaysurface_from(
+ width, height,
+ PIXMAN_x8r8g8b8,
+ width * 4, NULL
+ );
+}
+
+DisplaySurface *qemu_create_displaysurface_from(int width, int height,
+ pixman_format_code_t format,
+ int linesize, uint8_t *data)
+{
+ DisplaySurface *surface = g_new0(DisplaySurface, 1);
+
+ trace_displaysurface_create_from(surface, width, height, format);
+ surface->share_handle = SHAREABLE_NONE;
+
+ if (data) {
+ surface->image = pixman_image_create_bits(format,
+ width, height,
+ (void *)data, linesize);
+ } else {
+ qemu_pixman_image_new_shareable(&surface->image,
+ &surface->share_handle,
+ "displaysurface",
+ format,
+ width,
+ height,
+ linesize,
+ &error_abort);
+ surface->flags = QEMU_ALLOCATED_FLAG;
+ }
+
+ assert(surface->image != NULL);
+ return surface;
+}
+
+DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
+{
+ DisplaySurface *surface = g_new0(DisplaySurface, 1);
+
+ trace_displaysurface_create_pixman(surface);
+ surface->share_handle = SHAREABLE_NONE;
+ surface->image = pixman_image_ref(image);
+
+ return surface;
+}
+
+DisplaySurface *qemu_create_placeholder_surface(int w, int h,
+ const char *msg)
+{
+ DisplaySurface *surface = qemu_create_displaysurface(w, h);
+#ifdef CONFIG_PIXMAN
+ pixman_color_t bg = QEMU_PIXMAN_COLOR_BLACK;
+ pixman_color_t fg = QEMU_PIXMAN_COLOR_GRAY;
+ pixman_image_t *glyph;
+ int len, x, y, i;
+
+ len = strlen(msg);
+ x = (w / FONT_WIDTH - len) / 2;
+ y = (h / FONT_HEIGHT - 1) / 2;
+ for (i = 0; i < len; i++) {
+ glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
+ qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
+ x + i, y, FONT_WIDTH, FONT_HEIGHT);
+ qemu_pixman_image_unref(glyph);
+ }
+#endif
+ surface->flags |= QEMU_PLACEHOLDER_FLAG;
+ return surface;
+}
+
+void qemu_free_displaysurface(DisplaySurface *surface)
+{
+ if (surface == NULL) {
+ return;
+ }
+ trace_displaysurface_free(surface);
+ qemu_pixman_image_unref(surface->image);
+ g_free(surface);
+}
diff --git a/ui/meson.build b/ui/meson.build
index 9ece6f262b6..bae6ea0d2dc 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -5,6 +5,7 @@ system_ss.add(files(
'console.c',
'cp437.c',
'cursor.c',
+ 'display-surface.c',
'dmabuf.c',
'input-keymap.c',
'input-legacy.c',
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 36/67] ui: make qemu_default_pixelformat() static inline
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (34 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 35/67] ui: move DisplaySurface functions to display-surface.c Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 37/67] ui: make unregister_displaychangelistener() skip unregistered Marc-André Lureau
` (30 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
The function is a trivial wrapper around qemu_default_pixman_format()
and qemu_pixelformat_from_pixman(), so make it static inline in
qemu-pixman.h instead of a standalone function in console.c, allowing to
be easily reused.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/qemu-pixman.h | 8 ++++++++
include/ui/surface.h | 2 --
ui/console.c | 7 -------
3 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h
index 2ca0ed7029c..4bc7a59698e 100644
--- a/include/ui/qemu-pixman.h
+++ b/include/ui/qemu-pixman.h
@@ -73,6 +73,14 @@ typedef struct PixelFormat {
PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format);
pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian);
+
+static inline PixelFormat qemu_default_pixelformat(int bpp)
+{
+ pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
+ PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
+ return pf;
+}
+
pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format);
uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman);
int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian);
diff --git a/include/ui/surface.h b/include/ui/surface.h
index d2542d3ace5..8e5f3e35e8c 100644
--- a/include/ui/surface.h
+++ b/include/ui/surface.h
@@ -24,8 +24,6 @@ typedef struct DisplaySurface {
uint32_t share_handle_offset;
} DisplaySurface;
-PixelFormat qemu_default_pixelformat(int bpp);
-
DisplaySurface *qemu_create_displaysurface_from(int width, int height,
pixman_format_code_t format,
int linesize, uint8_t *data);
diff --git a/ui/console.c b/ui/console.c
index 24794e5a9dc..78b0ac27827 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -1392,13 +1392,6 @@ DisplaySurface *qemu_console_surface(QemuConsole *console)
}
}
-PixelFormat qemu_default_pixelformat(int bpp)
-{
- pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
- PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
- return pf;
-}
-
static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
void qemu_display_register(QemuDisplay *ui)
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 37/67] ui: make unregister_displaychangelistener() skip unregistered
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (35 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 36/67] ui: make qemu_default_pixelformat() static inline Marc-André Lureau
@ 2026-04-10 19:18 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 38/67] ui: minor code simplification Marc-André Lureau
` (29 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:18 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
If the listener doesn't have associate ds / display state, it is already
unregistered.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/ui/console.c b/ui/console.c
index 78b0ac27827..a9132e09eac 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -677,6 +677,9 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl)
{
DisplayState *ds = dcl->ds;
trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
+ if (!ds) {
+ return;
+ }
if (dcl->con) {
dcl->con->dcls--;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 38/67] ui: minor code simplification
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (36 preceding siblings ...)
2026-04-10 19:18 ` [PATCH v2 37/67] ui: make unregister_displaychangelistener() skip unregistered Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-15 11:25 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 39/67] system: make qemu_del_vm_change_state_handler accept NULL Marc-André Lureau
` (28 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
Drop memset() usage.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/sdl2.c | 8 ++++----
ui/vnc.c | 6 ++----
2 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/ui/sdl2.c b/ui/sdl2.c
index aaaede56e0e..30e0042fe29 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -600,10 +600,10 @@ static void handle_windowevent(SDL_Event *ev)
switch (ev->window.event) {
case SDL_WINDOWEVENT_RESIZED:
{
- QemuUIInfo info;
- memset(&info, 0, sizeof(info));
- info.width = ev->window.data1;
- info.height = ev->window.data2;
+ QemuUIInfo info = {
+ .width = ev->window.data1,
+ .height = ev->window.data2,
+ };
dpy_set_ui_info(scon->dcl.con, &info, true);
}
sdl2_redraw(scon);
diff --git a/ui/vnc.c b/ui/vnc.c
index 4aa446a48d7..9c8fe280bc9 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -43,6 +43,7 @@
#include "qapi/qapi-events-ui.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-ui.h"
+#include "ui/console.h"
#include "ui/input.h"
#include "crypto/hash.h"
#include "crypto/tlscreds.h"
@@ -2638,10 +2639,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
trace_vnc_msg_client_set_desktop_size(vs, vs->ioc, w, h, screens);
if (dpy_ui_info_supported(vs->vd->dcl.con)) {
- QemuUIInfo info;
- memset(&info, 0, sizeof(info));
- info.width = w;
- info.height = h;
+ QemuUIInfo info = { .width = w, .height = h };
dpy_set_ui_info(vs->vd->dcl.con, &info, false);
vnc_desktop_resize_ext(vs, 4 /* Request forwarded */);
} else {
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 39/67] system: make qemu_del_vm_change_state_handler accept NULL
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (37 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 38/67] ui: minor code simplification Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 40/67] ui/vnc: assert preconditions instead of silently returning Marc-André Lureau
` (27 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
For convenience.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
system/runstate.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/system/runstate.c b/system/runstate.c
index 2d4e95a2166..770253b467b 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -349,6 +349,9 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
{
+ if (!e) {
+ return;
+ }
QTAILQ_REMOVE(&vm_change_state_head, e, entries);
g_free(e);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 40/67] ui/vnc: assert preconditions instead of silently returning
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (38 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 39/67] system: make qemu_del_vm_change_state_handler accept NULL Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 41/67] ui/vnc: simplify vnc_init_func error handling Marc-André Lureau
` (26 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
Replace defensive NULL guards with assert() in vnc_display_close()
and vnc_display_open(). These are internal functions whose callers
guarantee non-NULL arguments, so a NULL value would indicate a
programming error rather than a runtime condition.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 9c8fe280bc9..3633fbeb6ce 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3465,9 +3465,7 @@ void vnc_display_init(const char *id, Error **errp)
static void vnc_display_close(VncDisplay *vd)
{
- if (!vd) {
- return;
- }
+ assert(vd);
if (vd->listener) {
qio_net_listener_disconnect(vd->listener);
@@ -4068,15 +4066,10 @@ void vnc_display_open(const char *id, Error **errp)
const char *audiodev;
const char *passwordSecret;
- if (!vd) {
- error_setg(errp, "VNC display not active");
- return;
- }
- vnc_display_close(vd);
+ assert(vd);
+ assert(opts);
- if (!opts) {
- return;
- }
+ vnc_display_close(vd);
reverse = qemu_opt_get_bool(opts, "reverse", false);
if (vnc_display_get_addresses(opts, reverse, &saddr_list, &wsaddr_list,
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 41/67] ui/vnc: simplify vnc_init_func error handling
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (39 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 40/67] ui/vnc: assert preconditions instead of silently returning Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 42/67] ui/vnc: VncDisplay.id is not const Marc-André Lureau
` (25 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 3633fbeb6ce..2df91642570 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -4319,7 +4319,7 @@ void vnc_parse(const char *str)
int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
{
- Error *local_err = NULL;
+ ERRP_GUARD();
char *id = (char *)qemu_opts_id(opts);
if (!id) {
@@ -4327,14 +4327,12 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
id = vnc_auto_assign_id(opts);
}
- vnc_display_init(id, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ vnc_display_init(id, errp);
+ if (*errp) {
return -1;
}
- vnc_display_open(id, &local_err);
- if (local_err != NULL) {
- error_propagate(errp, local_err);
+ vnc_display_open(id, errp);
+ if (*errp) {
return -1;
}
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 42/67] ui/vnc: VncDisplay.id is not const
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (40 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 41/67] ui/vnc: simplify vnc_init_func error handling Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free() Marc-André Lureau
` (24 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
s/strdup/g_strdup to highlight the issue and be consistent with other
allocations.
The next patch is going to introduce vnc_display_free() to take care of
deallocating it.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.h | 2 +-
ui/vnc.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index ec8d0c91b57..c5d678ac31e 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -166,7 +166,7 @@ struct VncDisplay
pixman_image_t *server; /* vnc server surface */
int true_width; /* server surface width before rounding up */
- const char *id;
+ char *id;
QTAILQ_ENTRY(VncDisplay) next;
char *password;
time_t expires;
diff --git a/ui/vnc.c b/ui/vnc.c
index 2df91642570..522d4d8fb88 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3431,7 +3431,7 @@ void vnc_display_init(const char *id, Error **errp)
}
vd = g_malloc0(sizeof(*vd));
- vd->id = strdup(id);
+ vd->id = g_strdup(id);
QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
QTAILQ_INIT(&vd->clients);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (41 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 42/67] ui/vnc: VncDisplay.id is not const Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-11 22:26 ` Philippe Mathieu-Daudé
2026-04-15 11:31 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 44/67] ui/vnc: fix vnc_display_init() leak on failure Marc-André Lureau
` (23 subsequent siblings)
66 siblings, 2 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Enable callers to properly tear down keyboard layouts.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/keymaps.h | 1 +
ui/keymaps.c | 13 ++++++++++---
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/ui/keymaps.h b/ui/keymaps.h
index 3d52c0882a1..e8917e56404 100644
--- a/ui/keymaps.h
+++ b/ui/keymaps.h
@@ -54,6 +54,7 @@ typedef struct kbd_layout_t kbd_layout_t;
kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
const char *language, Error **errp);
+void kbd_layout_free(kbd_layout_t *k);
int keysym2scancode(kbd_layout_t *k, int keysym,
QKbdState *kbd, bool down);
int keycode_is_keypad(kbd_layout_t *k, int keycode);
diff --git a/ui/keymaps.c b/ui/keymaps.c
index 2359dbfe7e6..d1b3f43dc8a 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -178,6 +178,14 @@ out:
return ret;
}
+void kbd_layout_free(kbd_layout_t *k)
+{
+ if (!k) {
+ return;
+ }
+ g_hash_table_unref(k->hash);
+ g_free(k);
+}
kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
const char *language, Error **errp)
@@ -185,10 +193,9 @@ kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
kbd_layout_t *k;
k = g_new0(kbd_layout_t, 1);
- k->hash = g_hash_table_new(NULL, NULL);
+ k->hash = g_hash_table_new_full(NULL, NULL, NULL, g_free);
if (parse_keyboard_layout(k, table, language, errp) < 0) {
- g_hash_table_unref(k->hash);
- g_free(k);
+ kbd_layout_free(k);
return NULL;
}
return k;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 44/67] ui/vnc: fix vnc_display_init() leak on failure
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (42 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free() Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-15 11:34 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private Marc-André Lureau
` (22 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Do not add the display state to the vnc list, if the initialization
failed. Add vnc_display_free(), to free the display state and associated
data in such case. The function is meant to be public and reused in the
following changes.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 522d4d8fb88..512e11d687e 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3422,6 +3422,8 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
}
+static void vnc_display_free(VncDisplay *vd);
+
void vnc_display_init(const char *id, Error **errp)
{
VncDisplay *vd;
@@ -3431,8 +3433,9 @@ void vnc_display_init(const char *id, Error **errp)
}
vd = g_malloc0(sizeof(*vd));
+ qemu_mutex_init(&vd->mutex);
vd->id = g_strdup(id);
- QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
+ vd->dcl.ops = &dcl_ops;
QTAILQ_INIT(&vd->clients);
vd->expires = TIME_MAX;
@@ -3446,22 +3449,22 @@ void vnc_display_init(const char *id, Error **errp)
}
if (!vd->kbd_layout) {
+ vnc_display_free(vd);
return;
}
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
vd->connections_limit = 32;
- qemu_mutex_init(&vd->mutex);
vnc_start_worker_thread();
- vd->dcl.ops = &dcl_ops;
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);
-}
+ QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
+}
static void vnc_display_close(VncDisplay *vd)
{
@@ -3505,6 +3508,28 @@ static void vnc_display_close(VncDisplay *vd)
#endif
}
+static void vnc_display_free(VncDisplay *vd)
+{
+ if (!vd) {
+ return;
+ }
+
+ assert(QTAILQ_EMPTY(&vd->clients));
+
+ vnc_display_close(vd);
+ unregister_displaychangelistener(&vd->dcl);
+ qkbd_state_free(vd->kbd);
+ qemu_del_vm_change_state_handler(vd->vmstate_handler_entry);
+ kbd_layout_free(vd->kbd_layout);
+ qemu_mutex_destroy(&vd->mutex);
+ if (QTAILQ_IN_USE(vd, next)) {
+ QTAILQ_REMOVE(&vnc_displays, vd, next);
+ }
+ g_free(vd->id);
+ g_free(vd);
+}
+
+
int vnc_display_password(const char *id, const char *password, Error **errp)
{
VncDisplay *vd = vnc_display_find(id);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (43 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 44/67] ui/vnc: fix vnc_display_init() leak on failure Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-11 22:27 ` Philippe Mathieu-Daudé
2026-04-15 11:34 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay Marc-André Lureau
` (21 subsequent siblings)
66 siblings, 2 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.h | 1 -
ui/vnc.c | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index c5d678ac31e..110c2bd4600 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -570,7 +570,6 @@ void vnc_write_u16(VncState *vs, uint16_t value);
void vnc_write_u8(VncState *vs, uint8_t value);
void vnc_flush(VncState *vs);
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
-void vnc_disconnect_finish(VncState *vs);
void vnc_start_protocol(VncState *vs);
diff --git a/ui/vnc.c b/ui/vnc.c
index 512e11d687e..ba7376360e6 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -71,6 +71,7 @@ static QTAILQ_HEAD(, VncDisplay) vnc_displays =
static int vnc_cursor_define(VncState *vs);
static void vnc_update_throttle_offset(VncState *vs);
+static void vnc_disconnect_finish(VncState *vs);
static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
{
@@ -1307,7 +1308,7 @@ static void vnc_disconnect_start(VncState *vs)
vs->disconnecting = TRUE;
}
-void vnc_disconnect_finish(VncState *vs)
+static void vnc_disconnect_finish(VncState *vs)
{
VncConnection *vc = container_of(vs, VncConnection, vs);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (44 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-15 16:03 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool Marc-André Lureau
` (20 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc-jobs.h | 3 ++-
ui/vnc.h | 2 ++
ui/vnc-jobs.c | 76 +++++++++++++++++++++++++++++++++--------------------------
ui/vnc.c | 3 ++-
4 files changed, 49 insertions(+), 35 deletions(-)
diff --git a/ui/vnc-jobs.h b/ui/vnc-jobs.h
index 59f66bcc353..e5ab55c1da6 100644
--- a/ui/vnc-jobs.h
+++ b/ui/vnc-jobs.h
@@ -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)
diff --git a/ui/vnc.h b/ui/vnc.h
index 110c2bd4600..9a09fcdad8b 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -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;
diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
index 5b17ef54091..c809287dd3a 100644
--- a/ui/vnc-jobs.c
+++ b/ui/vnc-jobs.c
@@ -29,8 +29,6 @@
#include "qemu/osdep.h"
#include "vnc.h"
#include "vnc-jobs.h"
-#include "qemu/sockets.h"
-#include "qemu/main-loop.h"
#include "trace.h"
/*
@@ -56,17 +54,10 @@ struct VncJobQueue {
QemuCond cond;
QemuMutex mutex;
QemuThread thread;
+ bool exit;
QTAILQ_HEAD(, VncJob) jobs;
};
-typedef struct VncJobQueue VncJobQueue;
-
-/*
- * We use a single global queue, but most of the functions are
- * already reentrant, so we can easily add more than one encoding thread
- */
-static VncJobQueue *queue;
-
static void vnc_lock_queue(VncJobQueue *queue)
{
qemu_mutex_lock(&queue->mutex);
@@ -125,19 +116,22 @@ static void vnc_job_free(VncJob *job)
*/
void vnc_job_push(VncJob *job)
{
+ VncJobQueue *queue = job->vs->vd->queue;
+
assert(!QTAILQ_IN_USE(job, next));
if (QLIST_EMPTY(&job->rectangles)) {
vnc_job_free(job);
} else {
vnc_lock_queue(queue);
+ assert(!queue->exit);
QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
qemu_cond_broadcast(&queue->cond);
vnc_unlock_queue(queue);
}
}
-static bool vnc_has_job_locked(VncState *vs)
+static bool vnc_has_job_locked(VncJobQueue *queue, VncState *vs)
{
VncJob *job;
@@ -151,8 +145,10 @@ static bool vnc_has_job_locked(VncState *vs)
void vnc_jobs_join(VncState *vs)
{
+ VncJobQueue *queue = vs->vd->queue;
+
vnc_lock_queue(queue);
- while (vnc_has_job_locked(vs)) {
+ while (vnc_has_job_locked(queue, vs)) {
qemu_cond_wait(&queue->cond, &queue->mutex);
}
vnc_unlock_queue(queue);
@@ -252,9 +248,13 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
int saved_offset;
vnc_lock_queue(queue);
- while (QTAILQ_EMPTY(&queue->jobs)) {
+ while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
qemu_cond_wait(&queue->cond, &queue->mutex);
}
+ if (queue->exit) {
+ vnc_unlock_queue(queue);
+ return 1;
+ }
job = QTAILQ_FIRST(&queue->jobs);
vnc_unlock_queue(queue);
@@ -340,39 +340,49 @@ disconnected:
return 0;
}
-static VncJobQueue *vnc_queue_init(void)
-{
- VncJobQueue *queue = g_new0(VncJobQueue, 1);
-
- qemu_cond_init(&queue->cond);
- qemu_mutex_init(&queue->mutex);
- QTAILQ_INIT(&queue->jobs);
- return queue;
-}
-
static void *vnc_worker_thread(void *arg)
{
VncJobQueue *queue = arg;
while (!vnc_worker_thread_loop(queue)) ;
- g_assert_not_reached();
+
return NULL;
}
-static bool vnc_worker_thread_running(void)
+void vnc_start_worker_thread(VncDisplay *vd)
{
- return queue; /* Check global queue */
+ VncJobQueue *queue;
+
+ assert(vd->queue == NULL);
+
+ queue = g_new0(VncJobQueue, 1);
+ qemu_cond_init(&queue->cond);
+ qemu_mutex_init(&queue->mutex);
+ QTAILQ_INIT(&queue->jobs);
+ vd->queue = queue;
+
+ qemu_thread_create(&queue->thread, "vnc_worker", vnc_worker_thread, queue,
+ QEMU_THREAD_JOINABLE);
}
-void vnc_start_worker_thread(void)
+void vnc_stop_worker_thread(VncDisplay *vd)
{
- VncJobQueue *q;
+ VncJobQueue *queue = vd->queue;
- if (vnc_worker_thread_running())
+ if (!queue) {
return;
+ }
+
+ /* all VNC clients must have finished before we can stop the worker thread */
+ vnc_lock_queue(queue);
+ assert(QTAILQ_EMPTY(&queue->jobs));
+ queue->exit = true;
+ qemu_cond_broadcast(&queue->cond);
+ vnc_unlock_queue(queue);
- q = vnc_queue_init();
- qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
- QEMU_THREAD_DETACHED);
- queue = q; /* Set global queue */
+ qemu_thread_join(&queue->thread);
+ qemu_cond_destroy(&queue->cond);
+ qemu_mutex_destroy(&queue->mutex);
+ g_free(queue);
+ vd->queue = NULL;
}
diff --git a/ui/vnc.c b/ui/vnc.c
index ba7376360e6..4e5a9ee0341 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -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);
@@ -3517,6 +3517,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);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (45 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-11 22:28 ` Philippe Mathieu-Daudé
2026-04-15 16:11 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open() Marc-André Lureau
` (19 subsequent siblings)
66 siblings, 2 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Use the QEMU-style error pattern returning "true" on success.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 4 ++--
ui/vnc.c | 20 ++++++++++----------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 75cd48ed7ad..f9b4665cb90 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -448,8 +448,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);
diff --git a/ui/vnc.c b/ui/vnc.c
index 4e5a9ee0341..0775417c418 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -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)
@@ -4074,7 +4075,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);
@@ -4277,7 +4278,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) {
@@ -4295,10 +4296,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)
@@ -4354,12 +4356,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;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (46 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-11 22:31 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 49/67] ui/vnc: add vnc_cleanup() Marc-André Lureau
` (18 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 2 --
ui/vnc.h | 3 +++
ui/vnc.c | 75 ++++++++++++++++++++++------------------------------
3 files changed, 35 insertions(+), 45 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index f9b4665cb90..1794f1a2cf0 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -448,8 +448,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);
diff --git a/ui/vnc.h b/ui/vnc.h
index 9a09fcdad8b..de41517be48 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -550,6 +550,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
diff --git a/ui/vnc.c b/ui/vnc.c
index 0775417c418..4d5b36a6fa8 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3423,14 +3423,14 @@ static void vmstate_change_handler(void *opaque, bool running, RunState state)
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
}
-static void vnc_display_free(VncDisplay *vd);
+static bool vnc_display_open(VncDisplay *vd, Error **errp);
-bool vnc_display_init(const char *id, Error **errp)
+VncDisplay *vnc_display_new(const char *id, Error **errp)
{
VncDisplay *vd;
if (vnc_display_find(id) != NULL) {
- return true;
+ return NULL;
}
vd = g_malloc0(sizeof(*vd));
@@ -3451,7 +3451,7 @@ bool vnc_display_init(const char *id, Error **errp)
if (!vd->kbd_layout) {
vnc_display_free(vd);
- return false;
+ return NULL;
}
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
@@ -3464,8 +3464,13 @@ bool vnc_display_init(const char *id, Error **errp)
vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
&vmstate_change_handler, vd);
+ if (!vnc_display_open(vd, errp)) {
+ vnc_display_free(vd);
+ return NULL;
+ }
+
QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
- return true;
+ return vd;
}
static void vnc_display_close(VncDisplay *vd)
@@ -3510,7 +3515,7 @@ static void vnc_display_close(VncDisplay *vd)
#endif
}
-static void vnc_display_free(VncDisplay *vd)
+void vnc_display_free(VncDisplay *vd)
{
if (!vd) {
return;
@@ -3532,7 +3537,6 @@ static void vnc_display_free(VncDisplay *vd)
g_free(vd);
}
-
int vnc_display_password(const char *id, const char *password, Error **errp)
{
VncDisplay *vd = vnc_display_find(id);
@@ -4075,10 +4079,9 @@ bool vnc_display_update(DisplayUpdateOptionsVNC *arg, Error **errp)
return true;
}
-bool vnc_display_open(const char *id, Error **errp)
+static bool vnc_display_open(VncDisplay *vd, Error **errp)
{
- VncDisplay *vd = vnc_display_find(id);
- QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
+ QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, vd->id);
g_autoptr(SocketAddressList) saddr_list = NULL;
g_autoptr(SocketAddressList) wsaddr_list = NULL;
const char *share, *device_id;
@@ -4097,26 +4100,23 @@ bool vnc_display_open(const char *id, Error **errp)
assert(vd);
assert(opts);
- vnc_display_close(vd);
-
reverse = qemu_opt_get_bool(opts, "reverse", false);
if (vnc_display_get_addresses(opts, reverse, &saddr_list, &wsaddr_list,
errp) < 0) {
- goto fail;
+ return false;
}
-
passwordSecret = qemu_opt_get(opts, "password-secret");
if (passwordSecret) {
if (qemu_opt_get(opts, "password")) {
error_setg(errp,
"'password' flag is redundant with 'password-secret'");
- goto fail;
+ return false;
}
vd->password = qcrypto_secret_lookup_as_utf8(passwordSecret,
errp);
if (!vd->password) {
- goto fail;
+ return false;
}
password = true;
} else {
@@ -4127,7 +4127,7 @@ bool vnc_display_open(const char *id, Error **errp)
QCRYPTO_CIPHER_ALGO_DES, QCRYPTO_CIPHER_MODE_ECB)) {
error_setg(errp,
"Cipher backend does not support DES algorithm");
- goto fail;
+ return false;
}
}
@@ -4137,7 +4137,7 @@ bool vnc_display_open(const char *id, Error **errp)
#ifndef CONFIG_VNC_SASL
if (sasl) {
error_setg(errp, "VNC SASL auth requires cyrus-sasl support");
- goto fail;
+ return false;
}
#endif /* CONFIG_VNC_SASL */
credid = qemu_opt_get(opts, "tls-creds");
@@ -4148,7 +4148,7 @@ bool vnc_display_open(const char *id, Error **errp)
if (!creds) {
error_setg(errp, "No TLS credentials with id '%s'",
credid);
- goto fail;
+ return false;
}
vd->tlscreds = (QCryptoTLSCreds *)
object_dynamic_cast(creds,
@@ -4156,26 +4156,26 @@ bool vnc_display_open(const char *id, Error **errp)
if (!vd->tlscreds) {
error_setg(errp, "Object with id '%s' is not TLS credentials",
credid);
- goto fail;
+ return false;
}
object_ref(OBJECT(vd->tlscreds));
if (!qcrypto_tls_creds_check_endpoint(vd->tlscreds,
QCRYPTO_TLS_CREDS_ENDPOINT_SERVER,
errp)) {
- goto fail;
+ return false;
}
}
tlsauthz = qemu_opt_get(opts, "tls-authz");
if (tlsauthz && !vd->tlscreds) {
error_setg(errp, "'tls-authz' provided but TLS is not enabled");
- goto fail;
+ return false;
}
saslauthz = qemu_opt_get(opts, "sasl-authz");
if (saslauthz && !sasl) {
error_setg(errp, "'sasl-authz' provided but SASL auth is not enabled");
- goto fail;
+ return false;
}
share = qemu_opt_get(opts, "share");
@@ -4188,7 +4188,7 @@ bool vnc_display_open(const char *id, Error **errp)
vd->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
} else {
error_setg(errp, "unknown vnc share= option");
- goto fail;
+ return false;
}
} else {
vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
@@ -4222,20 +4222,20 @@ bool vnc_display_open(const char *id, Error **errp)
if (vnc_display_setup_auth(&vd->auth, &vd->subauth,
vd->tlscreds, password,
sasl, false, errp) < 0) {
- goto fail;
+ return false;
}
trace_vnc_auth_init(vd, 0, vd->auth, vd->subauth);
if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth,
vd->tlscreds, password,
sasl, true, errp) < 0) {
- goto fail;
+ return false;
}
trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth);
#ifdef CONFIG_VNC_SASL
if (sasl && !vnc_sasl_server_init(errp)) {
- goto fail;
+ return false;
}
#endif
vd->lock_key_sync = lock_key_sync;
@@ -4248,7 +4248,7 @@ bool vnc_display_open(const char *id, Error **errp)
if (audiodev) {
vd->audio_be = audio_be_by_name(audiodev, errp);
if (!vd->audio_be) {
- goto fail;
+ return false;
}
} else {
vd->audio_be = audio_get_default_audio_be(NULL);
@@ -4262,7 +4262,7 @@ bool vnc_display_open(const char *id, Error **errp)
con = qemu_console_lookup_by_device_name(device_id, head, &err);
if (err) {
error_propagate(errp, err);
- goto fail;
+ return false;
}
} else {
con = qemu_console_lookup_default();
@@ -4283,11 +4283,11 @@ bool vnc_display_open(const char *id, Error **errp)
if (reverse) {
if (vnc_display_connect(vd, saddr_list, wsaddr_list, errp) < 0) {
- goto fail;
+ return false;
}
} else {
if (vnc_display_listen(vd, saddr_list, wsaddr_list, errp) < 0) {
- goto fail;
+ return false;
}
}
@@ -4295,12 +4295,7 @@ bool vnc_display_open(const char *id, Error **errp)
vnc_display_print_local_addr(vd);
}
- /* Success */
return true;
-
-fail:
- vnc_display_close(vd);
- return false;
}
void vnc_display_add_client(const char *id, int csock, bool skipauth)
@@ -4356,13 +4351,7 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
id = vnc_auto_assign_id(opts);
}
- if (!vnc_display_init(id, errp)) {
- return -1;
- }
- if (!vnc_display_open(id, errp)) {
- return -1;
- }
- return 0;
+ return vnc_display_new(id, errp) != NULL ? 0 : -1;
}
static void vnc_register_config(void)
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 49/67] ui/vnc: add vnc_cleanup()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (47 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open() Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-15 11:56 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 50/67] ui/vnc: report an error for duplicate display id Marc-André Lureau
` (17 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Add a function to tear down VNC displays, call it when leaving QEMU.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 1 +
system/runstate.c | 5 +++++
ui/vnc.c | 24 ++++++++++++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/include/ui/console.h b/include/ui/console.h
index 1794f1a2cf0..b3aaf3ff12b 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -455,6 +455,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);
diff --git a/system/runstate.c b/system/runstate.c
index 770253b467b..0e1cb3b4e67 100644
--- a/system/runstate.c
+++ b/system/runstate.c
@@ -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 */
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 4d5b36a6fa8..c26b581f3ef 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -4354,6 +4354,30 @@ 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;
+ VncState *vs;
+
+ QTAILQ_FOREACH(vd, &vnc_displays, next) {
+ if (vd->listener) {
+ qio_net_listener_disconnect(vd->listener);
+ }
+ if (vd->wslistener) {
+ qio_net_listener_disconnect(vd->wslistener);
+ }
+ QTAILQ_FOREACH(vs, &vd->clients, next) {
+ vnc_disconnect_start(vs);
+ }
+ }
+ QTAILQ_FOREACH_SAFE(vd, &vnc_displays, next, vd_next) {
+ while (!QTAILQ_EMPTY(&vd->clients)) {
+ main_loop_wait(false);
+ }
+ vnc_display_free(vd);
+ }
+}
+
static void vnc_register_config(void)
{
qemu_add_opts(&qemu_vnc_opts);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 50/67] ui/vnc: report an error for duplicate display id
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (48 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 49/67] ui/vnc: add vnc_cleanup() Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-11 22:33 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 51/67] ui/vnc: defer listener registration until the console is known Marc-André Lureau
` (16 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
Returning NULL without setting an error is odd.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/ui/vnc.c b/ui/vnc.c
index c26b581f3ef..6f9cc3f25a3 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3430,6 +3430,7 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
VncDisplay *vd;
if (vnc_display_find(id) != NULL) {
+ error_setg(errp, "Display '%s' already exists", id);
return NULL;
}
vd = g_malloc0(sizeof(*vd));
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 51/67] ui/vnc: defer listener registration until the console is known
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (49 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 50/67] ui/vnc: report an error for duplicate display id Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 52/67] ui/vnc: expose vnc_disconnect_start() Marc-André Lureau
` (15 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
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.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/ui/vnc.c b/ui/vnc.c
index 6f9cc3f25a3..747b1c44e36 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3460,8 +3460,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) {
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 52/67] ui/vnc: expose vnc_disconnect_start()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (50 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 51/67] ui/vnc: defer listener registration until the console is known Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-15 12:19 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 53/67] ui/vnc: remove left-over dead code Marc-André Lureau
` (14 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
This allows VncDisplay users to tear down all clients before freeing the
VncDisplay for example.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.h | 1 +
ui/vnc.c | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index de41517be48..794341265b3 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -560,6 +560,7 @@ void vnc_display_free(VncDisplay *vd);
*****************************************************************************/
/* Event loop functions */
+void vnc_disconnect_start(VncState *vs);
gboolean vnc_client_io(QIOChannel *ioc,
GIOCondition condition,
void *opaque);
diff --git a/ui/vnc.c b/ui/vnc.c
index 747b1c44e36..6fef80e98c4 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -617,7 +617,6 @@ bool vnc_display_reload_certs(const char *id, Error **errp)
*/
static int vnc_update_client(VncState *vs, int has_dirty);
-static void vnc_disconnect_start(VncState *vs);
static void vnc_colordepth(VncState *vs);
static void framebuffer_update_request(VncState *vs, int incremental,
@@ -1296,7 +1295,7 @@ static void audio_del(VncState *vs)
}
}
-static void vnc_disconnect_start(VncState *vs)
+void vnc_disconnect_start(VncState *vs)
{
if (vs->disconnecting) {
return;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 53/67] ui/vnc: remove left-over dead code
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (51 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 52/67] ui/vnc: expose vnc_disconnect_start() Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-15 11:58 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 54/67] ui/vnc: explicitly link with png Marc-André Lureau
` (13 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Since commit 5994dcb8d85 ("ui, monitor: remove deprecated VNC ACL option
and HMP commands"), this field is no longer used.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.h | 1 -
ui/vnc.c | 4 ----
2 files changed, 5 deletions(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index 794341265b3..993ec022e52 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -180,7 +180,6 @@ struct VncDisplay
bool non_adaptive;
bool power_control;
QCryptoTLSCreds *tlscreds;
- QAuthZ *tlsauthz;
char *tlsauthzid;
#ifdef CONFIG_VNC_SASL
VncDisplaySASL sasl;
diff --git a/ui/vnc.c b/ui/vnc.c
index 6fef80e98c4..e7ec1fb7f68 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3493,10 +3493,6 @@ static void vnc_display_close(VncDisplay *vd)
object_unref(OBJECT(vd->tlscreds));
vd->tlscreds = NULL;
}
- if (vd->tlsauthz) {
- object_unparent(OBJECT(vd->tlsauthz));
- vd->tlsauthz = NULL;
- }
g_free(vd->tlsauthzid);
vd->tlsauthzid = NULL;
if (vd->lock_key_sync) {
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 54/67] ui/vnc: explicitly link with png
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (52 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 53/67] ui/vnc: remove left-over dead code Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 55/67] ui/vnc: add vnc-system unit, to allow different implementations Marc-André Lureau
` (12 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
The VNC code uses PNG directly.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ui/meson.build b/ui/meson.build
index bae6ea0d2dc..b31ddf96282 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -45,7 +45,7 @@ vnc_ss.add(files(
'vnc-jobs.c',
'vnc-clipboard.c',
))
-vnc_ss.add(zlib, jpeg)
+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'))
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 55/67] ui/vnc: add vnc-system unit, to allow different implementations
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (53 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 54/67] ui/vnc: explicitly link with png Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 56/67] ui/console: remove qemu_console_is_visible() Marc-André Lureau
` (11 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
The qemu-vnc server will want to signal the XVP requests, let it
have its own implementation.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/vnc.h | 4 ++++
ui/vnc-system.c | 19 +++++++++++++++++++
ui/vnc.c | 4 ++--
ui/meson.build | 2 +-
4 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index 993ec022e52..7341fb0f25c 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -649,4 +649,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 */
diff --git a/ui/vnc-system.c b/ui/vnc-system.c
new file mode 100644
index 00000000000..0632885f655
--- /dev/null
+++ b/ui/vnc-system.c
@@ -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);
+}
diff --git a/ui/vnc.c b/ui/vnc.c
index e7ec1fb7f68..5dd1eb399cc 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2521,13 +2521,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);
diff --git a/ui/meson.build b/ui/meson.build
index b31ddf96282..f959f8972b5 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -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 = {}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 56/67] ui/console: remove qemu_console_is_visible()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (54 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 55/67] ui/vnc: add vnc-system unit, to allow different implementations Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 57/67] ui/console: simplify registering display/console change listener Marc-André Lureau
` (10 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Daniel P. Berrangé
Drop the bookkeeping, we can simply afford an empty "foreach".
Notice that dpy_gfx_update_texture() is now called even when there are
no listeners. This is more correct, as the texture is not fully
refreshed when a listener connects, so it may be outdated/garbaged.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 1 -
ui/console-priv.h | 1 -
ui/console.c | 29 -----------------------------
3 files changed, 31 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index b3aaf3ff12b..472c188a727 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -392,7 +392,6 @@ QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head);
QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
uint32_t head, Error **errp);
QEMUCursor *qemu_console_get_cursor(QemuConsole *con);
-bool qemu_console_is_visible(QemuConsole *con);
bool qemu_console_is_graphic(QemuConsole *con);
bool qemu_console_is_fixedsize(QemuConsole *con);
bool qemu_console_is_gl_blocked(QemuConsole *con);
diff --git a/ui/console-priv.h b/ui/console-priv.h
index f8855753e30..4f731b4f9ce 100644
--- a/ui/console-priv.h
+++ b/ui/console-priv.h
@@ -16,7 +16,6 @@ struct QemuConsole {
DisplayState *ds;
DisplaySurface *surface;
DisplayScanout scanout;
- int dcls;
DisplayGLCtx *gl;
int gl_block;
QEMUTimer *gl_unblock_timer;
diff --git a/ui/console.c b/ui/console.c
index a9132e09eac..baffdeb22b1 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -650,9 +650,6 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
dcl->ds = get_alloc_displaystate();
QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
gui_setup_refresh(dcl->ds);
- if (dcl->con) {
- dcl->con->dcls++;
- }
displaychangelistener_display_console(dcl, &error_fatal);
if (QEMU_IS_GRAPHIC_CONSOLE(dcl->con)) {
dcl_set_graphic_cursor(dcl, QEMU_GRAPHIC_CONSOLE(dcl->con));
@@ -680,9 +677,6 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl)
if (!ds) {
return;
}
- if (dcl->con) {
- dcl->con->dcls--;
- }
QLIST_REMOVE(dcl, next);
dcl->ds = NULL;
gui_setup_refresh(ds);
@@ -747,9 +741,6 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
w = MIN(w, width - x);
h = MIN(h, height - y);
- if (!qemu_console_is_visible(con)) {
- return;
- }
dpy_gfx_update_texture(con, con->surface, x, y, w, h);
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != dcl->con) {
@@ -848,9 +839,6 @@ void dpy_text_cursor(QemuConsole *con, int x, int y)
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
- if (!qemu_console_is_visible(con)) {
- return;
- }
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != dcl->con) {
continue;
@@ -866,9 +854,6 @@ void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
- if (!qemu_console_is_visible(con)) {
- return;
- }
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != dcl->con) {
continue;
@@ -884,9 +869,6 @@ void dpy_text_resize(QemuConsole *con, int w, int h)
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
- if (!qemu_console_is_visible(con)) {
- return;
- }
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != dcl->con) {
continue;
@@ -906,9 +888,6 @@ void dpy_mouse_set(QemuConsole *c, int x, int y, bool on)
con->cursor_x = x;
con->cursor_y = y;
con->cursor_on = on;
- if (!qemu_console_is_visible(c)) {
- return;
- }
QLIST_FOREACH(dcl, &s->listeners, next) {
if (c != dcl->con) {
continue;
@@ -927,9 +906,6 @@ void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
cursor_unref(con->cursor);
con->cursor = cursor_ref(cursor);
- if (!qemu_console_is_visible(c)) {
- return;
- }
QLIST_FOREACH(dcl, &s->listeners, next) {
if (c != dcl->con) {
continue;
@@ -1287,11 +1263,6 @@ QEMUCursor *qemu_console_get_cursor(QemuConsole *con)
return QEMU_IS_GRAPHIC_CONSOLE(con) ? QEMU_GRAPHIC_CONSOLE(con)->cursor : NULL;
}
-bool qemu_console_is_visible(QemuConsole *con)
-{
- return con->dcls > 0;
-}
-
bool qemu_console_is_graphic(QemuConsole *con)
{
return con && QEMU_IS_GRAPHIC_CONSOLE(con);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 57/67] ui/console: simplify registering display/console change listener
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (55 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 56/67] ui/console: remove qemu_console_is_visible() Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 58/67] ui/console: add doc comment for qemu_console_{un}register_listener() Marc-André Lureau
` (9 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
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.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
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(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 472c188a727..823d3b819b2 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -305,10 +305,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);
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 3d4b5635568..02e8c1435be 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -2252,9 +2252,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)
diff --git a/ui/console.c b/ui/console.c
index baffdeb22b1..3ab987add34 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -642,10 +642,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);
@@ -670,10 +675,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;
}
diff --git a/ui/curses.c b/ui/curses.c
index 78f21d940e3..4e2a0b25955 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -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;
}
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 85e215ef233..249760d82aa 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -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);
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 37945236e11..fe58e3ef24d 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -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
@@ -1256,6 +1240,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;
@@ -1288,8 +1273,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;
}
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 352b30b43fb..4f046c975a9 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -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);
}
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 9ebe7e8df0d..3aaa44ff3e2 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -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);
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 30e0042fe29..4f8b05fbd85 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -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)
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 87cc193cdee..56d8140fad8 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -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)
diff --git a/ui/vnc.c b/ui/vnc.c
index 5dd1eb399cc..21698835084 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -1859,10 +1859,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;
}
@@ -3436,7 +3435,6 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
qemu_mutex_init(&vd->mutex);
vd->id = g_strdup(id);
- vd->dcl.ops = &dcl_ops;
QTAILQ_INIT(&vd->clients);
vd->expires = TIME_MAX;
@@ -3519,7 +3517,7 @@ void vnc_display_free(VncDisplay *vd)
vnc_stop_worker_thread(vd);
vnc_display_close(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);
@@ -4262,8 +4260,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);
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 9093d1e408f..aaf82421589 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -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];
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 58/67] ui/console: add doc comment for qemu_console_{un}register_listener()
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (56 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 57/67] ui/console: simplify registering display/console change listener Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 59/67] ui/console: return completion status from gfx_update callback Marc-André Lureau
` (8 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/console.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/ui/console.c b/ui/console.c
index 3ab987add34..f96e3cf16fa 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -642,6 +642,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)
@@ -675,6 +686,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;
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 59/67] ui/console: return completion status from gfx_update callback
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (57 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 58/67] ui/console: add doc comment for qemu_console_{un}register_listener() Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-23 13:59 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 60/67] ui/console: rename public API to use consistent qemu_console_ prefix Marc-André Lureau
` (7 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Replace the two-field design (gfx_update void callback + gfx_update_async
flag) with a single bool return value from gfx_update. Returning true
means the update completed synchronously and graphic_hw_update_done()
should be called by the console layer. Returning false means the update
is deferred and the device will call graphic_hw_update_done() itself
later (as done by QXL/SPICE and Apple GFX).
This simplifies the interface and makes the async contract explicit at
each call site rather than relying on a separate struct field.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
hw/display/qxl.h | 2 +-
include/ui/console.h | 9 +++++++--
hw/arm/musicpal.c | 3 ++-
hw/display/artist.c | 4 +++-
hw/display/bcm2835_fb.c | 7 ++++---
hw/display/bochs-display.c | 6 ++++--
hw/display/cg3.c | 5 +++--
hw/display/dm163.c | 4 +++-
hw/display/exynos4210_fimd.c | 6 ++++--
hw/display/g364fb.c | 9 ++++++---
hw/display/jazz_led.c | 6 ++++--
hw/display/macfb.c | 6 ++++--
hw/display/next-fb.c | 4 +++-
hw/display/omap_lcdc.c | 14 ++++++++------
hw/display/pl110.c | 5 +++--
hw/display/qxl-render.c | 6 +++---
hw/display/qxl.c | 7 +++----
hw/display/ramfb-standalone.c | 4 +++-
hw/display/sm501.c | 8 +++++---
hw/display/ssd0303.c | 10 ++++++----
hw/display/ssd0323.c | 11 ++++++-----
hw/display/tcx.c | 6 ++++--
hw/display/vga.c | 4 +++-
hw/display/virtio-gpu-base.c | 3 ++-
hw/display/virtio-vga.c | 6 +++---
hw/display/vmware_vga.c | 7 ++++---
hw/display/xenfb.c | 6 ++++--
hw/display/xlnx_dp.c | 10 ++++++----
hw/vfio/display.c | 17 ++++++++++-------
ui/console.c | 7 +------
hw/display/apple-gfx.m | 10 +++++-----
31 files changed, 127 insertions(+), 85 deletions(-)
diff --git a/hw/display/qxl.h b/hw/display/qxl.h
index e0a85a5ca49..ad8a9128785 100644
--- a/hw/display/qxl.h
+++ b/hw/display/qxl.h
@@ -187,7 +187,7 @@ int qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
/* qxl-render.c */
void qxl_render_resize(PCIQXLDevice *qxl);
-void qxl_render_update(PCIQXLDevice *qxl);
+bool qxl_render_update(PCIQXLDevice *qxl);
int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
void qxl_render_update_area_bh(void *opaque);
diff --git a/include/ui/console.h b/include/ui/console.h
index 823d3b819b2..c93ab7d619e 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -363,8 +363,13 @@ enum {
typedef struct GraphicHwOps {
int (*get_flags)(void *opaque); /* optional, default 0 */
void (*invalidate)(void *opaque);
- void (*gfx_update)(void *opaque);
- bool gfx_update_async; /* if true, calls graphic_hw_update_done() */
+ /*
+ * Returns true if the update is handled synchronously, false if deferred
+ * and graphic_hw_update_done() will be called when ready (to resume waiting
+ * tasks/coroutines).
+ * Optional.
+ */
+ bool (*gfx_update)(void *opaque);
void (*text_update)(void *opaque, uint32_t *text);
void (*ui_info)(void *opaque, uint32_t head, QemuUIInfo *info);
void (*gl_block)(void *opaque, bool block);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 250fdb49b6f..913f98b5d8e 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -153,7 +153,7 @@ static inline void set_lcd_pixel32(musicpal_lcd_state *s,
}
}
-static void lcd_refresh(void *opaque)
+static bool lcd_refresh(void *opaque)
{
musicpal_lcd_state *s = opaque;
int x, y, col;
@@ -172,6 +172,7 @@ static void lcd_refresh(void *opaque)
}
dpy_gfx_update(s->con, 0, 0, 128*3, 64*3);
+ return true;
}
static void lcd_invalidate(void *opaque)
diff --git a/hw/display/artist.c b/hw/display/artist.c
index 206f77afba1..a07508378c7 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -1311,7 +1311,7 @@ static void artist_draw_line(void *opaque, uint8_t *d, const uint8_t *src,
}
}
-static void artist_update_display(void *opaque)
+static bool artist_update_display(void *opaque)
{
ARTISTState *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -1326,6 +1326,8 @@ static void artist_update_display(void *opaque)
if (first >= 0) {
dpy_gfx_update(s->con, 0, first, s->width, last - first + 1);
}
+
+ return true;
}
static void artist_invalidate(void *opaque)
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index 75d7c0f8499..83c4c03c7ca 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -150,7 +150,7 @@ static bool fb_use_offsets(BCM2835FBConfig *config)
config->yres_virtual > config->yres;
}
-static void fb_update_display(void *opaque)
+static bool fb_update_display(void *opaque)
{
BCM2835FBState *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -161,7 +161,7 @@ static void fb_update_display(void *opaque)
uint32_t xoff = 0, yoff = 0;
if (s->lock || !s->config.xres) {
- return;
+ return true;
}
src_width = bcm2835_fb_get_pitch(&s->config);
@@ -174,7 +174,7 @@ static void fb_update_display(void *opaque)
switch (surface_bits_per_pixel(surface)) {
case 0:
- return;
+ return true;
case 8:
break;
case 15:
@@ -212,6 +212,7 @@ static void fb_update_display(void *opaque)
}
s->invalidate = false;
+ return true;
}
void bcm2835_fb_validate_config(BCM2835FBConfig *config)
diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c
index 5fb6b733cb5..8ef9b76cf85 100644
--- a/hw/display/bochs-display.c
+++ b/hw/display/bochs-display.c
@@ -198,7 +198,7 @@ static int bochs_display_get_mode(BochsDisplayState *s,
return 0;
}
-static void bochs_display_update(void *opaque)
+static bool bochs_display_update(void *opaque)
{
BochsDisplayState *s = opaque;
DirtyBitmapSnapshot *snap = NULL;
@@ -212,7 +212,7 @@ static void bochs_display_update(void *opaque)
ret = bochs_display_get_mode(s, &mode);
if (ret < 0) {
/* no (valid) video mode */
- return;
+ return true;
}
if (memcmp(&s->mode, &mode, sizeof(mode)) != 0) {
@@ -255,6 +255,8 @@ static void bochs_display_update(void *opaque)
g_free(snap);
}
+
+ return true;
}
static const GraphicHwOps bochs_display_gfx_ops = {
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 0a413fbb7ec..963bb3427a6 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -85,7 +85,7 @@ struct CG3State {
uint8_t dac_index, dac_state;
};
-static void cg3_update_display(void *opaque)
+static bool cg3_update_display(void *opaque)
{
CG3State *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -98,7 +98,7 @@ static void cg3_update_display(void *opaque)
DirtyBitmapSnapshot *snap = NULL;
if (surface_bits_per_pixel(surface) != 32) {
- return;
+ return true;
}
width = s->width;
height = s->height;
@@ -154,6 +154,7 @@ static void cg3_update_display(void *opaque)
qemu_irq_raise(s->irq);
}
g_free(snap);
+ return true;
}
static void cg3_invalidate_display(void *opaque)
diff --git a/hw/display/dm163.c b/hw/display/dm163.c
index 4feae912945..9ea62cb4f76 100644
--- a/hw/display/dm163.c
+++ b/hw/display/dm163.c
@@ -285,7 +285,7 @@ static uint32_t *update_display_of_row(DM163State *s, uint32_t *dest,
return dest;
}
-static void dm163_update_display(void *opaque)
+static bool dm163_update_display(void *opaque)
{
DM163State *s = (DM163State *)opaque;
DisplaySurface *surface = qemu_console_surface(s->console);
@@ -300,6 +300,8 @@ static void dm163_update_display(void *opaque)
}
dest = update_display_of_row(s, dest, row);
}
+
+ return true;
}
static const GraphicHwOps dm163_ops = {
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index 2d8fa7ee944..a91f04aaf79 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -1270,7 +1270,7 @@ static void exynos4210_update_resolution(Exynos4210fimdState *s)
}
}
-static void exynos4210_fimd_update(void *opaque)
+static bool exynos4210_fimd_update(void *opaque)
{
Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
DisplaySurface *surface;
@@ -1287,7 +1287,7 @@ static void exynos4210_fimd_update(void *opaque)
if (!s || !s->console || !s->enabled ||
surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) {
- return;
+ return true;
}
global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
@@ -1348,6 +1348,8 @@ static void exynos4210_fimd_update(void *opaque)
exynos4210_fimd_enable(s, false);
}
exynos4210_fimd_update_irq(s);
+
+ return true;
}
static void exynos4210_fimd_reset(DeviceState *d)
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index 50952e9934b..bd15f6f0acc 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -238,15 +238,16 @@ static void g364fb_draw_blank(G364State *s)
s->blanked = 1;
}
-static void g364fb_update_display(void *opaque)
+static bool g364fb_update_display(void *opaque)
{
G364State *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
qemu_flush_coalesced_mmio_buffer();
- if (s->width == 0 || s->height == 0)
- return;
+ if (s->width == 0 || s->height == 0) {
+ return true;
+ }
if (s->width != surface_width(surface) ||
s->height != surface_height(surface)) {
@@ -262,6 +263,8 @@ static void g364fb_update_display(void *opaque)
}
qemu_irq_raise(s->irq);
+
+ return true;
}
static inline void g364fb_invalidate_display(void *opaque)
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index d5783982950..ee9758a94b5 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -144,7 +144,7 @@ static void draw_vertical_line(DisplaySurface *ds,
}
}
-static void jazz_led_update_display(void *opaque)
+static bool jazz_led_update_display(void *opaque)
{
LedState *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -186,7 +186,7 @@ static void jazz_led_update_display(void *opaque)
color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
break;
default:
- return;
+ return true;
}
/* display segments */
@@ -218,6 +218,8 @@ static void jazz_led_update_display(void *opaque)
s->state = REDRAW_NONE;
dpy_gfx_update_full(s->con);
+
+ return true;
}
static void jazz_led_invalidate_display(void *opaque)
diff --git a/hw/display/macfb.c b/hw/display/macfb.c
index b8115c2be13..848c3c282bd 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -454,7 +454,7 @@ static gchar *macfb_mode_list(void)
}
-static void macfb_update_display(void *opaque)
+static bool macfb_update_display(void *opaque)
{
MacfbState *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -462,7 +462,7 @@ static void macfb_update_display(void *opaque)
qemu_flush_coalesced_mmio_buffer();
if (s->width == 0 || s->height == 0) {
- return;
+ return true;
}
if (s->width != surface_width(surface) ||
@@ -471,6 +471,8 @@ static void macfb_update_display(void *opaque)
}
macfb_draw_graphic(s);
+
+ return true;
}
static void macfb_update_irq(MacfbState *s)
diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c
index 3d97702fce5..e758b223ef7 100644
--- a/hw/display/next-fb.c
+++ b/hw/display/next-fb.c
@@ -67,7 +67,7 @@ static void nextfb_draw_line(void *opaque, uint8_t *d, const uint8_t *s,
}
}
-static void nextfb_update(void *opaque)
+static bool nextfb_update(void *opaque)
{
NeXTFbState *s = NEXTFB(opaque);
int dest_width = 4;
@@ -90,6 +90,8 @@ static void nextfb_update(void *opaque)
s, &first, &last);
dpy_gfx_update(s->con, 0, 0, s->cols, s->rows);
+
+ return true;
}
static void nextfb_invalidate(void *opaque)
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index c41c65bb2e0..1e8385ebffb 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -197,7 +197,7 @@ static void draw_line16_32(void *opaque, uint8_t *d, const uint8_t *s,
} while (-- width != 0);
}
-static void omap_update_display(void *opaque)
+static bool omap_update_display(void *opaque)
{
struct omap_lcd_panel_s *omap_lcd = opaque;
DisplaySurface *surface;
@@ -207,12 +207,12 @@ static void omap_update_display(void *opaque)
hwaddr frame_base;
if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable) {
- return;
+ return true;
}
surface = qemu_console_surface(omap_lcd->con);
if (!surface_bits_per_pixel(surface)) {
- return;
+ return true;
}
frame_offset = 0;
@@ -256,7 +256,7 @@ static void omap_update_display(void *opaque)
default:
/* Unsupported at the moment. */
- return;
+ return true;
}
/* Resolution */
@@ -278,7 +278,7 @@ static void omap_update_display(void *opaque)
omap_lcd->sync_error = 1;
omap_lcd_interrupts(omap_lcd);
omap_lcd->enable = 0;
- return;
+ return true;
}
/* Content */
@@ -291,7 +291,7 @@ static void omap_update_display(void *opaque)
omap_lcd->dma->current_frame ^= 1;
if (!surface_bits_per_pixel(surface)) {
- return;
+ return true;
}
first = 0;
@@ -323,6 +323,8 @@ static void omap_update_display(void *opaque)
dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1);
}
omap_lcd->invalidate = 0;
+
+ return true;
}
static void omap_invalidate_display(void *opaque) {
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index 4cd62a98757..e134ac28eb6 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -210,7 +210,7 @@ static int pl110_enabled(PL110State *s)
return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
}
-static void pl110_update_display(void *opaque)
+static bool pl110_update_display(void *opaque)
{
PL110State *s = (PL110State *)opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -221,7 +221,7 @@ static void pl110_update_display(void *opaque)
int last;
if (!pl110_enabled(s)) {
- return;
+ return true;
}
if (s->cr & PL110_CR_BGR)
@@ -306,6 +306,7 @@ static void pl110_update_display(void *opaque)
dpy_gfx_update(s->con, 0, first, s->cols, last - first + 1);
}
s->invalidate = 0;
+ return true;
}
static void pl110_invalidate_display(void * opaque)
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index c6a9ac1da10..5b4f8842011 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -173,7 +173,7 @@ end:
* callbacks are called by spice_server thread, deferring to bh called from the
* io thread.
*/
-void qxl_render_update(PCIQXLDevice *qxl)
+bool qxl_render_update(PCIQXLDevice *qxl)
{
QXLCookie *cookie;
@@ -183,8 +183,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
qxl->mode == QXL_MODE_UNDEFINED) {
qxl_render_update_area_unlocked(qxl);
qemu_mutex_unlock(&qxl->ssd.lock);
- graphic_hw_update_done(qxl->ssd.dcl.con);
- return;
+ return true;
}
qxl->guest_primary.commands = 0;
@@ -195,6 +194,7 @@ void qxl_render_update(PCIQXLDevice *qxl)
qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
+ return false;
}
void qxl_render_update_area_bh(void *opaque)
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 02e8c1435be..6c3a9b1e879 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -122,7 +122,7 @@ static void qxl_reset_memslots(PCIQXLDevice *d);
static void qxl_reset_surfaces(PCIQXLDevice *d);
static void qxl_ring_set_dirty(PCIQXLDevice *qxl);
-static void qxl_hw_update(void *opaque);
+static bool qxl_hw_update(void *opaque);
void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...)
{
@@ -1144,7 +1144,6 @@ static const QXLInterface qxl_interface = {
static const GraphicHwOps qxl_ops = {
.gfx_update = qxl_hw_update,
- .gfx_update_async = true,
};
static void qxl_enter_vga_mode(PCIQXLDevice *d)
@@ -1928,11 +1927,11 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events)
/* graphics console */
-static void qxl_hw_update(void *opaque)
+static bool qxl_hw_update(void *opaque)
{
PCIQXLDevice *qxl = opaque;
- qxl_render_update(qxl);
+ return qxl_render_update(qxl);
}
static void qxl_dirty_one_surface(PCIQXLDevice *qxl, QXLPHYSICAL pqxl,
diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c
index f1958be32ad..27f0ba19f90 100644
--- a/hw/display/ramfb-standalone.c
+++ b/hw/display/ramfb-standalone.c
@@ -20,7 +20,7 @@ struct RAMFBStandaloneState {
bool use_legacy_x86_rom;
};
-static void display_update_wrapper(void *dev)
+static bool display_update_wrapper(void *dev)
{
RAMFBStandaloneState *ramfb = RAMFB(dev);
@@ -29,6 +29,8 @@ static void display_update_wrapper(void *dev)
} else {
ramfb_display_update(ramfb->con, ramfb->state);
}
+
+ return true;
}
static const GraphicHwOps wrapper_ops = {
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index a07aa9886f9..a3993ceba29 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -1716,7 +1716,7 @@ static void draw_hwc_line_32(uint8_t *d, const uint8_t *s, int width,
}
}
-static void sm501_update_display(void *opaque)
+static bool sm501_update_display(void *opaque)
{
SM501State *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -1740,7 +1740,7 @@ static void sm501_update_display(void *opaque)
if (!((crt ? s->dc_crt_control : s->dc_panel_control)
& SM501_DC_CRT_CONTROL_ENABLE)) {
- return;
+ return true;
}
palette = (uint32_t *)(crt ? &s->dc_palette[SM501_DC_CRT_PALETTE -
@@ -1761,7 +1761,7 @@ static void sm501_update_display(void *opaque)
default:
qemu_log_mask(LOG_GUEST_ERROR, "sm501: update display"
"invalid control register value.\n");
- return;
+ return true;
}
/* set up to draw hardware cursor */
@@ -1833,6 +1833,8 @@ static void sm501_update_display(void *opaque)
if (y_start >= 0) {
dpy_gfx_update(s->con, 0, y_start, width, y - y_start);
}
+
+ return true;
}
static const GraphicHwOps sm501_ops = {
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index 87781438cd5..229856cc427 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -203,7 +203,7 @@ static int ssd0303_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static void ssd0303_update_display(void *opaque)
+static bool ssd0303_update_display(void *opaque)
{
ssd0303_state *s = (ssd0303_state *)opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -218,11 +218,11 @@ static void ssd0303_update_display(void *opaque)
uint8_t mask;
if (!s->redraw)
- return;
+ return true;
switch (surface_bits_per_pixel(surface)) {
case 0:
- return;
+ return true;
case 15:
dest_width = 2;
break;
@@ -237,7 +237,7 @@ static void ssd0303_update_display(void *opaque)
break;
default:
BADF("Bad color depth\n");
- return;
+ return true;
}
dest_width *= MAGNIFY;
memset(colortab, 0xff, dest_width);
@@ -269,6 +269,8 @@ static void ssd0303_update_display(void *opaque)
}
s->redraw = 0;
dpy_gfx_update(s->con, 0, 0, 96 * MAGNIFY, 16 * MAGNIFY);
+
+ return true;
}
static void ssd0303_invalidate_display(void * opaque)
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index af5ff4fecdc..67db16086c8 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -181,7 +181,7 @@ static uint32_t ssd0323_transfer(SSIPeripheral *dev, uint32_t data)
return 0;
}
-static void ssd0323_update_display(void *opaque)
+static bool ssd0323_update_display(void *opaque)
{
ssd0323_state *s = (ssd0323_state *)opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -197,11 +197,11 @@ static void ssd0323_update_display(void *opaque)
int dest_width;
if (!s->redraw)
- return;
+ return true;
switch (surface_bits_per_pixel(surface)) {
case 0:
- return;
+ return true;
case 15:
dest_width = 2;
break;
@@ -216,7 +216,7 @@ static void ssd0323_update_display(void *opaque)
break;
default:
BADF("Bad color depth\n");
- return;
+ return true;
}
p = colortab;
for (i = 0; i < 16; i++) {
@@ -240,7 +240,7 @@ static void ssd0323_update_display(void *opaque)
break;
default:
BADF("Bad color depth\n");
- return;
+ return true;
}
p += dest_width;
}
@@ -271,6 +271,7 @@ static void ssd0323_update_display(void *opaque)
}
s->redraw = 0;
dpy_gfx_update(s->con, 0, 0, 128 * MAGNIFY, 64 * MAGNIFY);
+ return true;
}
static void ssd0323_invalidate_display(void * opaque)
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index ea92a48400c..cedbf5c7acd 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -209,7 +209,7 @@ static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
/* Fixed line length 1024 allows us to do nice tricks not possible on
VGA... */
-static void tcx_update_display(void *opaque)
+static bool tcx_update_display(void *opaque)
{
TCXState *ts = opaque;
DisplaySurface *surface = qemu_console_surface(ts->con);
@@ -257,9 +257,10 @@ static void tcx_update_display(void *opaque)
ts->width, y - y_start);
}
g_free(snap);
+ return true;
}
-static void tcx24_update_display(void *opaque)
+static bool tcx24_update_display(void *opaque)
{
TCXState *ts = opaque;
DisplaySurface *surface = qemu_console_surface(ts->con);
@@ -312,6 +313,7 @@ static void tcx24_update_display(void *opaque)
ts->width, y - y_start);
}
g_free(snap);
+ return true;
}
static void tcx_invalidate_display(void *opaque)
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 36cfc59a74e..409c02272a3 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -1783,7 +1783,7 @@ static void vga_draw_blank(VGACommonState *s, int full_update)
#define GMODE_GRAPH 1
#define GMODE_BLANK 2
-static void vga_update_display(void *opaque)
+static bool vga_update_display(void *opaque)
{
VGACommonState *s = opaque;
DisplaySurface *surface = qemu_console_surface(s->con);
@@ -1818,6 +1818,8 @@ static void vga_update_display(void *opaque)
break;
}
}
+
+ return true;
}
/* force a full display refresh */
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index 7b107509510..bdc24492850 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -83,8 +83,9 @@ static void virtio_gpu_invalidate_display(void *opaque)
{
}
-static void virtio_gpu_update_display(void *opaque)
+static bool virtio_gpu_update_display(void *opaque)
{
+ return true;
}
static void virtio_gpu_text_update(void *opaque, uint32_t *chardata)
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index 02fb36b31fc..efd4858f3d0 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -19,15 +19,15 @@ static void virtio_vga_base_invalidate_display(void *opaque)
}
}
-static void virtio_vga_base_update_display(void *opaque)
+static bool virtio_vga_base_update_display(void *opaque)
{
VirtIOVGABase *vvga = opaque;
VirtIOGPUBase *g = vvga->vgpu;
if (g->enable) {
- g->hw_ops->gfx_update(g);
+ return g->hw_ops->gfx_update(g);
} else {
- vvga->vga.hw_ops->gfx_update(&vvga->vga);
+ return vvga->vga.hw_ops->gfx_update(&vvga->vga);
}
}
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 1e154e7f99e..39606d80be1 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -1135,14 +1135,13 @@ static inline void vmsvga_check_size(struct vmsvga_state_s *s)
}
}
-static void vmsvga_update_display(void *opaque)
+static bool vmsvga_update_display(void *opaque)
{
struct vmsvga_state_s *s = opaque;
if (!s->enable || !s->config) {
/* in standard vga mode */
- s->vga.hw_ops->gfx_update(&s->vga);
- return;
+ return s->vga.hw_ops->gfx_update(&s->vga);
}
vmsvga_check_size(s);
@@ -1154,6 +1153,8 @@ static void vmsvga_update_display(void *opaque)
s->invalidated = 0;
dpy_gfx_update_full(s->vga.con);
}
+
+ return true;
}
static void vmsvga_reset(DeviceState *dev)
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index ba886a940ee..2e431e27be6 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -709,14 +709,14 @@ static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
* Our screen might be inactive. When asked for
* an update we know it is active.
*/
-static void xenfb_update(void *opaque)
+static bool xenfb_update(void *opaque)
{
struct XenFB *xenfb = opaque;
DisplaySurface *surface;
int i;
if (xenfb->c.xendev.be_state != XenbusStateConnected)
- return;
+ return true;
if (!xenfb->feature_update) {
/* we don't get update notifications, thus use the
@@ -770,6 +770,8 @@ static void xenfb_update(void *opaque)
}
xenfb->up_count = 0;
xenfb->up_fullscreen = 0;
+
+ return true;
}
static void xenfb_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info)
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index 7d037b46a35..50e6ef10984 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -1252,12 +1252,12 @@ static inline void xlnx_dp_blend_surface(XlnxDPState *s)
surface_height(s->g_plane.surface));
}
-static void xlnx_dp_update_display(void *opaque)
+static bool xlnx_dp_update_display(void *opaque)
{
XlnxDPState *s = XLNX_DP(opaque);
if ((s->core_registers[DP_TRANSMITTER_ENABLE] & 0x01) == 0) {
- return;
+ return true;
}
xlnx_dpdma_trigger_vsync_irq(s->dpdma);
@@ -1272,14 +1272,14 @@ static void xlnx_dp_update_display(void *opaque)
*/
s->core_registers[DP_INT_STATUS] |= (1 << 21);
xlnx_dp_update_irq(s);
- return;
+ return true;
}
if (xlnx_dp_global_alpha_enabled(s)) {
if (!xlnx_dpdma_start_operation(s->dpdma, 0, false)) {
s->core_registers[DP_INT_STATUS] |= (1 << 21);
xlnx_dp_update_irq(s);
- return;
+ return true;
}
xlnx_dp_blend_surface(s);
}
@@ -1288,6 +1288,8 @@ static void xlnx_dp_update_display(void *opaque)
* XXX: We might want to update only what changed.
*/
dpy_gfx_update_full(s->console);
+
+ return true;
}
static const GraphicHwOps xlnx_dp_gfx_ops = {
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
index 5a42a6f7a29..4a9a58036e3 100644
--- a/hw/vfio/display.c
+++ b/hw/vfio/display.c
@@ -285,7 +285,7 @@ static void vfio_display_free_dmabufs(VFIOPCIDevice *vdev)
}
}
-static void vfio_display_dmabuf_update(void *opaque)
+static bool vfio_display_dmabuf_update(void *opaque)
{
VFIOPCIDevice *vdev = opaque;
VFIODisplay *dpy = vdev->dpy;
@@ -298,7 +298,7 @@ static void vfio_display_dmabuf_update(void *opaque)
if (dpy->ramfb) {
ramfb_display_update(dpy->con, dpy->ramfb);
}
- return;
+ return true;
}
width = qemu_dmabuf_get_width(primary->buf);
@@ -340,6 +340,8 @@ static void vfio_display_dmabuf_update(void *opaque)
if (free_bufs) {
vfio_display_free_dmabufs(vdev);
}
+
+ return true;
}
static int vfio_display_get_flags(void *opaque)
@@ -399,7 +401,7 @@ void vfio_display_reset(VFIOPCIDevice *vdev)
dpy_gfx_update_full(vdev->dpy->con);
}
-static void vfio_display_region_update(void *opaque)
+static bool vfio_display_region_update(void *opaque)
{
VFIOPCIDevice *vdev = opaque;
VFIODisplay *dpy = vdev->dpy;
@@ -414,18 +416,18 @@ static void vfio_display_region_update(void *opaque)
if (ret < 0) {
error_report("ioctl VFIO_DEVICE_QUERY_GFX_PLANE: %s",
strerror(errno));
- return;
+ return true;
}
if (!plane.drm_format || !plane.size) {
if (dpy->ramfb) {
ramfb_display_update(dpy->con, dpy->ramfb);
dpy->region.surface = NULL;
}
- return;
+ return true;
}
format = qemu_drm_format_to_pixman(plane.drm_format);
if (!format) {
- return;
+ return true;
}
if (dpy->region.buffer.size &&
@@ -476,11 +478,12 @@ static void vfio_display_region_update(void *opaque)
dpy_gfx_update(dpy->con, 0, 0,
surface_width(dpy->region.surface),
surface_height(dpy->region.surface));
- return;
+ return true;
err:
vfio_region_exit(&dpy->region.buffer);
vfio_region_finalize(&dpy->region.buffer);
+ return true;
}
static const GraphicHwOps vfio_display_region_ops = {
diff --git a/ui/console.c b/ui/console.c
index f96e3cf16fa..6e073cacca0 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -138,15 +138,10 @@ void graphic_hw_update_done(QemuConsole *con)
void graphic_hw_update(QemuConsole *con)
{
- bool async = false;
if (!con) {
return;
}
- if (con->hw_ops->gfx_update) {
- con->hw_ops->gfx_update(con->hw);
- async = con->hw_ops->gfx_update_async;
- }
- if (!async) {
+ if (!con->hw_ops->gfx_update || con->hw_ops->gfx_update(con->hw)) {
graphic_hw_update_done(con);
}
}
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
index e0a765fcb1f..77d80fb7cef 100644
--- a/hw/display/apple-gfx.m
+++ b/hw/display/apple-gfx.m
@@ -330,25 +330,25 @@ static void apple_gfx_render_frame_completed_bh(void *opaque)
}
}
-static void apple_gfx_fb_update_display(void *opaque)
+static bool apple_gfx_fb_update_display(void *opaque)
{
AppleGFXState *s = opaque;
+ bool done = true;
assert(bql_locked());
if (s->new_frame_ready) {
dpy_gfx_update_full(s->con);
s->new_frame_ready = false;
- graphic_hw_update_done(s->con);
} else if (s->pending_frames > 0) {
s->gfx_update_requested = true;
- } else {
- graphic_hw_update_done(s->con);
+ done = false;
}
+
+ return done;
}
static const GraphicHwOps apple_gfx_fb_ops = {
.gfx_update = apple_gfx_fb_update_display,
- .gfx_update_async = true,
};
/* ------ Mouse cursor and display mode setting ------ */
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 60/67] ui/console: rename public API to use consistent qemu_console_ prefix
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (58 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 59/67] ui/console: return completion status from gfx_update callback Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-11 22:38 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 61/67] ui/console: move console_handle_touch_event() to input Marc-André Lureau
` (6 subsequent siblings)
66 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
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/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 +--
56 files changed, 372 insertions(+), 382 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index c93ab7d619e..5566d1f65f9 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -308,49 +308,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,
@@ -375,19 +375,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);
diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c
index 913f98b5d8e..2f43d774dbe 100644
--- a/hw/arm/musicpal.c
+++ b/hw/arm/musicpal.c
@@ -171,7 +171,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;
}
@@ -254,7 +254,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);
}
diff --git a/hw/display/artist.c b/hw/display/artist.c
index a07508378c7..288d466ec64 100644
--- a/hw/display/artist.c
+++ b/hw/display/artist.c
@@ -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);
}
diff --git a/hw/display/ati.c b/hw/display/ati.c
index 88a5bbbf07a..882ffc1bcf9 100644
--- a/hw/display/ati.c
+++ b/hw/display/ati.c
@@ -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 */
@@ -624,9 +624,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)) !=
@@ -778,8 +778,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;
}
@@ -1092,7 +1092,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;
@@ -1165,7 +1165,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[] = {
diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c
index 83c4c03c7ca..bd58f625fcd 100644
--- a/hw/display/bcm2835_fb.c
+++ b/hw/display/bcm2835_fb.c
@@ -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);
}
diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c
index 8ef9b76cf85..64e669429c4 100644
--- a/hw/display/bochs-display.c
+++ b/hw/display/bochs-display.c
@@ -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[] = {
diff --git a/hw/display/cg3.c b/hw/display/cg3.c
index 963bb3427a6..f9dda1549dd 100644
--- a/hw/display/cg3.c
+++ b/hw/display/cg3.c
@@ -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);
}
diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c
index 48be3c8a932..0a8c74e1374 100644
--- a/hw/display/cirrus_vga.c
+++ b/hw/display/cirrus_vga.c
@@ -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);
diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c
index 76034a88605..b8052d1d8ed 100644
--- a/hw/display/cirrus_vga_isa.c
+++ b/hw/display/cirrus_vga_isa.c
@@ -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 */
diff --git a/hw/display/dm163.c b/hw/display/dm163.c
index 9ea62cb4f76..afade0b98c3 100644
--- a/hw/display/dm163.c
+++ b/hw/display/dm163.c
@@ -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);
}
diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c
index a91f04aaf79..5133623ee2e 100644
--- a/hw/display/exynos4210_fimd.c
+++ b/hw/display/exynos4210_fimd.c
@@ -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)
diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c
index bd15f6f0acc..af54f1f9005 100644
--- a/hw/display/g364fb.c
+++ b/hw/display/g364fb.c
@@ -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);
diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c
index ee9758a94b5..84fe1058406 100644
--- a/hw/display/jazz_led.c
+++ b/hw/display/jazz_led.c
@@ -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)
diff --git a/hw/display/macfb.c b/hw/display/macfb.c
index 848c3c282bd..f40a7ed9f52 100644
--- a/hw/display/macfb.c
+++ b/hw/display/macfb.c
@@ -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) {
diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c
index e758b223ef7..fa2e0d0da80 100644
--- a/hw/display/next-fb.c
+++ b/hw/display/next-fb.c
@@ -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);
}
diff --git a/hw/display/omap_lcdc.c b/hw/display/omap_lcdc.c
index 1e8385ebffb..2a8d5ffdd57 100644
--- a/hw/display/omap_lcdc.c
+++ b/hw/display/omap_lcdc.c
@@ -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;
}
diff --git a/hw/display/pl110.c b/hw/display/pl110.c
index e134ac28eb6..4a93cf4cda9 100644
--- a/hw/display/pl110.c
+++ b/hw/display/pl110.c
@@ -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)
diff --git a/hw/display/qxl-render.c b/hw/display/qxl-render.c
index 5b4f8842011..7b692d5a854 100644
--- a/hw/display/qxl-render.c
+++ b/hw/display/qxl-render.c
@@ -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);
}
}
diff --git a/hw/display/qxl.c b/hw/display/qxl.c
index 6c3a9b1e879..c4da51e4f4c 100644
--- a/hw/display/qxl.c
+++ b/hw/display/qxl.c
@@ -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 */
diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c
index 27f0ba19f90..8e8ba37514a 100644
--- a/hw/display/ramfb-standalone.c
+++ b/hw/display/ramfb-standalone.c
@@ -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);
}
diff --git a/hw/display/ramfb.c b/hw/display/ramfb.c
index 50c25706a52..7a88f934e11 100644
--- a/hw/display/ramfb.c
+++ b/hw/display/ramfb.c
@@ -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)
diff --git a/hw/display/sm501.c b/hw/display/sm501.c
index a3993ceba29..af870048372 100644
--- a/hw/display/sm501.c
+++ b/hw/display/sm501.c
@@ -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 = {
diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c
index 229856cc427..4e3dede33f1 100644
--- a/hw/display/ssd0303.c
+++ b/hw/display/ssd0303.c
@@ -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);
}
diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c
index 67db16086c8..9309d4d10c4 100644
--- a/hw/display/ssd0323.c
+++ b/hw/display/ssd0323.c
@@ -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);
diff --git a/hw/display/tcx.c b/hw/display/tcx.c
index cedbf5c7acd..2c33a9c4a32 100644
--- a/hw/display/tcx.c
+++ b/hw/display/tcx.c
@@ -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;
diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c
index 5f55c884a1b..2cccb0ef12e 100644
--- a/hw/display/vga-isa.c
+++ b/hw/display/vga-isa.c
@@ -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,
diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c
index 1a9608d865f..3cd64951c09 100644
--- a/hw/display/vga-mmio.c
+++ b/hw/display/vga-mmio.c
@@ -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[] = {
diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c
index 4e68dd57a17..d089847bdae 100644
--- a/hw/display/vga-pci.c
+++ b/hw/display/vga-pci.c
@@ -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)) {
diff --git a/hw/display/vga.c b/hw/display/vga.c
index 409c02272a3..3f456b96608 100644
--- a/hw/display/vga.c
+++ b/hw/display/vga.c
@@ -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,
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 3f6fb7a8033..6e5e6540a46 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -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;
}
diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c
index bdc24492850..a68b1848295 100644
--- a/hw/display/virtio-gpu-base.c
+++ b/hw/display/virtio-gpu-base.c
@@ -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;
diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c
index ebb6c783fb0..6ff12639012 100644
--- a/hw/display/virtio-gpu-rutabaga.c
+++ b/hw/display/virtio-gpu-rutabaga.c
@@ -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;
}
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index 74b6a7766af..d5ac1cfca0e 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -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);
diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
index b7a2d160ddd..f8437616779 100644
--- a/hw/display/virtio-gpu-virgl.c
+++ b/hw/display/virtio-gpu-virgl.c
@@ -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);
}
}
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index b998ce8324d..aad45e6fc0f 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -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;
diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c
index efd4858f3d0..2ae649c91ae 100644
--- a/hw/display/virtio-vga.c
+++ b/hw/display/virtio-vga.c
@@ -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",
diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c
index 39606d80be1..f8906776b16 100644
--- a/hw/display/vmware_vga.c
+++ b/hw/display/vmware_vga.c
@@ -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,
diff --git a/hw/display/xenfb.c b/hw/display/xenfb.c
index 2e431e27be6..8e9953bda43 100644
--- a/hw/display/xenfb.c
+++ b/hw/display/xenfb.c
@@ -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;
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
index 50e6ef10984..2486d9e5825 100644
--- a/hw/display/xlnx_dp.c
+++ b/hw/display/xlnx_dp.c
@@ -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));
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
index 4a9a58036e3..8f91e83da88 100644
--- a/hw/vfio/display.c
+++ b/hw/vfio/display.c
@@ -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);
diff --git a/ui/console-vc.c b/ui/console-vc.c
index 6e8f2552e41..ec7106b169a 100644
--- a/ui/console-vc.c
+++ b/ui/console-vc.c
@@ -86,15 +86,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;
}
}
@@ -182,14 +182,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)
@@ -228,7 +228,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));
vt100_init(&s->vt, QEMU_CONSOLE(s)->surface->image,
text_console_image_update,
text_console_out_flush);
diff --git a/ui/console.c b/ui/console.c
index 6e073cacca0..344bf308b0c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -129,26 +129,26 @@ static void gui_setup_refresh(DisplayState *ds)
}
}
-void graphic_hw_update_done(QemuConsole *con)
+void qemu_console_hw_update_done(QemuConsole *con)
{
if (con) {
qemu_co_enter_all(&con->dump_queue, NULL);
}
}
-void graphic_hw_update(QemuConsole *con)
+void qemu_console_hw_update(QemuConsole *con)
{
if (!con) {
return;
}
if (!con->hw_ops->gfx_update || con->hw_ops->gfx_update(con->hw)) {
- graphic_hw_update_done(con);
+ qemu_console_hw_update_done(con);
}
}
-static void graphic_hw_update_bh(void *con)
+static void console_hw_update_bh(void *con)
{
- graphic_hw_update(con);
+ qemu_console_hw_update(con);
}
void qemu_console_co_wait_update(QemuConsole *con)
@@ -156,18 +156,18 @@ void qemu_console_co_wait_update(QemuConsole *con)
if (qemu_co_queue_empty(&con->dump_queue)) {
/* Defer the update, it will restart the pending coroutines */
aio_bh_schedule_oneshot(qemu_get_aio_context(),
- graphic_hw_update_bh, con);
+ console_hw_update_bh, con);
}
qemu_co_queue_wait(&con->dump_queue, NULL);
}
-static void graphic_hw_gl_unblock_timer(void *opaque)
+static void console_hw_gl_unblock_timer(void *opaque)
{
warn_report("console: no gl-unblock within one second");
}
-void graphic_hw_gl_block(QemuConsole *con, bool block)
+void qemu_console_hw_gl_block(QemuConsole *con, bool block)
{
uint64_t timeout;
assert(con != NULL);
@@ -205,14 +205,14 @@ void qemu_console_set_window_id(QemuConsole *con, int window_id)
con->window_id = window_id;
}
-void graphic_hw_invalidate(QemuConsole *con)
+void qemu_console_hw_invalidate(QemuConsole *con)
{
if (con && con->hw_ops->invalidate) {
con->hw_ops->invalidate(con->hw);
}
}
-void graphic_hw_text_update(QemuConsole *con, uint32_t *chardata)
+void qemu_console_hw_text_update(QemuConsole *con, uint32_t *chardata)
{
if (con && con->hw_ops->text_update) {
con->hw_ops->text_update(con->hw, chardata);
@@ -502,7 +502,7 @@ qemu_graphic_console_init(Object *obj)
{
}
-bool console_has_gl(QemuConsole *con)
+bool qemu_console_has_gl(QemuConsole *con)
{
return con->gl != NULL;
}
@@ -527,7 +527,7 @@ static bool console_compatible_with(QemuConsole *con,
flags = con->hw_ops->get_flags ? con->hw_ops->get_flags(con->hw) : 0;
- if (console_has_gl(con) &&
+ if (qemu_console_has_gl(con) &&
!con->gl->ops->dpy_gl_ctx_is_compatible_dcl(con->gl, dcl)) {
error_setg(errp, "Display %s is incompatible with the GL context",
dcl->ops->dpy_name);
@@ -535,7 +535,7 @@ static bool console_compatible_with(QemuConsole *con,
}
if (flags & GRAPHIC_FLAGS_GL &&
- !console_has_gl(con)) {
+ !qemu_console_has_gl(con)) {
error_setg(errp, "The console requires a GL context.");
return false;
@@ -670,8 +670,8 @@ void qemu_console_register_listener(QemuConsole *con,
vt100_update_cursor();
}
-void update_displaychangelistener(DisplayChangeListener *dcl,
- uint64_t interval)
+void qemu_console_listener_set_refresh(DisplayChangeListener *dcl,
+ uint64_t interval)
{
DisplayState *ds = dcl->ds;
@@ -710,7 +710,7 @@ static void dpy_set_ui_info_timer(void *opaque)
con->hw_ops->ui_info(con->hw, head, &con->ui_info);
}
-bool dpy_ui_info_supported(const QemuConsole *con)
+bool qemu_console_ui_info_supported(const QemuConsole *con)
{
if (con == NULL) {
return false;
@@ -719,16 +719,16 @@ bool dpy_ui_info_supported(const QemuConsole *con)
return con->hw_ops->ui_info != NULL;
}
-const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
+const QemuUIInfo *qemu_console_get_ui_info(const QemuConsole *con)
{
- assert(dpy_ui_info_supported(con));
+ assert(qemu_console_ui_info_supported(con));
return &con->ui_info;
}
-int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
+int qemu_console_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
{
- if (!dpy_ui_info_supported(con)) {
+ if (!qemu_console_ui_info_supported(con)) {
return -1;
}
if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
@@ -747,7 +747,7 @@ int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info, bool delay)
return 0;
}
-void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
+void qemu_console_update(QemuConsole *con, int x, int y, int w, int h)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -772,15 +772,15 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
}
}
-void dpy_gfx_update_full(QemuConsole *con)
+void qemu_console_update_full(QemuConsole *con)
{
int w = qemu_console_get_width(con, 0);
int h = qemu_console_get_height(con, 0);
- dpy_gfx_update(con, 0, 0, w, h);
+ qemu_console_update(con, 0, 0, w, h);
}
-void dpy_gfx_replace_surface(QemuConsole *con,
+void qemu_console_set_surface(QemuConsole *con,
DisplaySurface *surface)
{
static const char placeholder_msg[] = "Display output is not active.";
@@ -818,8 +818,8 @@ void dpy_gfx_replace_surface(QemuConsole *con,
qemu_free_displaysurface(old_surface);
}
-bool dpy_gfx_check_format(QemuConsole *con,
- pixman_format_code_t format)
+bool qemu_console_check_format(QemuConsole *con,
+ pixman_format_code_t format)
{
DisplayChangeListener *dcl;
DisplayState *s = con->ds;
@@ -854,7 +854,7 @@ static void dpy_refresh(DisplayState *s)
}
}
-void dpy_text_cursor(QemuConsole *con, int x, int y)
+void qemu_console_text_set_cursor(QemuConsole *con, int x, int y)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -869,7 +869,7 @@ 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 qemu_console_text_update(QemuConsole *con, int x, int y, int w, int h)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -884,7 +884,7 @@ 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 qemu_console_text_resize(QemuConsole *con, int w, int h)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -899,7 +899,7 @@ void dpy_text_resize(QemuConsole *con, int w, int h)
}
}
-void dpy_mouse_set(QemuConsole *c, int x, int y, bool on)
+void qemu_console_set_mouse(QemuConsole *c, int x, int y, bool on)
{
QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
DisplayState *s = c->ds;
@@ -918,7 +918,7 @@ void dpy_mouse_set(QemuConsole *c, int x, int y, bool on)
}
}
-void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
+void qemu_console_set_cursor(QemuConsole *c, QEMUCursor *cursor)
{
QemuGraphicConsole *con = QEMU_GRAPHIC_CONSOLE(c);
DisplayState *s = c->ds;
@@ -936,26 +936,26 @@ void dpy_cursor_define(QemuConsole *c, QEMUCursor *cursor)
}
}
-QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
- struct QEMUGLParams *qparams)
+QEMUGLContext qemu_console_gl_ctx_create(QemuConsole *con,
+ QEMUGLParams *qparams)
{
assert(con->gl);
return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
}
-void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
+void qemu_console_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
{
assert(con->gl);
con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
}
-int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
+int qemu_console_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
{
assert(con->gl);
return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
}
-void dpy_gl_scanout_disable(QemuConsole *con)
+void qemu_console_gl_scanout_disable(QemuConsole *con)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -973,14 +973,14 @@ 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 width, uint32_t height,
- void *d3d_tex2d)
+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 width, uint32_t height,
+ void *d3d_tex2d)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -1004,8 +1004,8 @@ void dpy_gl_scanout_texture(QemuConsole *con,
}
}
-void dpy_gl_scanout_dmabuf(QemuConsole *con,
- QemuDmaBuf *dmabuf)
+void qemu_console_gl_scanout_dmabuf(QemuConsole *con,
+ QemuDmaBuf *dmabuf)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -1022,8 +1022,8 @@ void dpy_gl_scanout_dmabuf(QemuConsole *con,
}
}
-void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
- bool have_hot, uint32_t hot_x, uint32_t hot_y)
+void qemu_console_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
+ bool have_hot, uint32_t hot_x, uint32_t hot_y)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -1039,8 +1039,8 @@ void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
}
}
-void dpy_gl_cursor_position(QemuConsole *con,
- uint32_t pos_x, uint32_t pos_y)
+void qemu_console_gl_cursor_position(QemuConsole *con,
+ uint32_t pos_x, uint32_t pos_y)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -1055,8 +1055,8 @@ void dpy_gl_cursor_position(QemuConsole *con,
}
}
-void dpy_gl_release_dmabuf(QemuConsole *con,
- QemuDmaBuf *dmabuf)
+void qemu_console_gl_release_dmabuf(QemuConsole *con,
+ QemuDmaBuf *dmabuf)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
@@ -1071,15 +1071,15 @@ void dpy_gl_release_dmabuf(QemuConsole *con,
}
}
-void dpy_gl_update(QemuConsole *con,
- uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+void qemu_console_gl_update(QemuConsole *con,
+ uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
assert(con->gl);
- graphic_hw_gl_block(con, true);
+ qemu_console_hw_gl_block(con, true);
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != dcl->con) {
continue;
@@ -1088,7 +1088,7 @@ void dpy_gl_update(QemuConsole *con,
dcl->ops->dpy_gl_update(dcl, x, y, w, h);
}
}
- graphic_hw_gl_block(con, false);
+ qemu_console_hw_gl_block(con, false);
}
/***********************************************************/
@@ -1125,17 +1125,17 @@ DisplayState *init_displaystate(void)
return display_state;
}
-void graphic_console_set_hwops(QemuConsole *con,
- const GraphicHwOps *hw_ops,
- void *opaque)
+void qemu_graphic_console_set_hwops(QemuConsole *con,
+ const GraphicHwOps *hw_ops,
+ void *opaque)
{
con->hw_ops = hw_ops;
con->hw = opaque;
}
-QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
- const GraphicHwOps *hw_ops,
- void *opaque)
+QemuConsole *qemu_graphic_console_create(DeviceState *dev, uint32_t head,
+ const GraphicHwOps *hw_ops,
+ void *opaque)
{
static const char noinit[] =
"Guest has not initialized the display (yet).";
@@ -1154,16 +1154,16 @@ QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
s = (QemuConsole *)object_new(TYPE_QEMU_GRAPHIC_CONSOLE);
}
QEMU_GRAPHIC_CONSOLE(s)->head = head;
- graphic_console_set_hwops(s, hw_ops, opaque);
+ qemu_graphic_console_set_hwops(s, hw_ops, opaque);
if (dev) {
object_property_set_link(OBJECT(s), "device", OBJECT(dev),
&error_abort);
}
surface = qemu_create_placeholder_surface(width, height, noinit);
- dpy_gfx_replace_surface(s, surface);
+ qemu_console_set_surface(s, surface);
s->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
- graphic_hw_gl_unblock_timer, s);
+ console_hw_gl_unblock_timer, s);
return s;
}
@@ -1171,7 +1171,7 @@ static const GraphicHwOps unused_ops = {
/* no callbacks */
};
-void graphic_console_close(QemuConsole *con)
+void qemu_graphic_console_close(QemuConsole *con)
{
static const char unplugged[] =
"Guest display has been unplugged";
@@ -1181,13 +1181,13 @@ void graphic_console_close(QemuConsole *con)
trace_console_gfx_close(con->index);
object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
- graphic_console_set_hwops(con, &unused_ops, NULL);
+ qemu_graphic_console_set_hwops(con, &unused_ops, NULL);
if (con->gl) {
- dpy_gl_scanout_disable(con);
+ qemu_console_gl_scanout_disable(con);
}
surface = qemu_create_placeholder_surface(width, height, unplugged);
- dpy_gfx_replace_surface(con, surface);
+ qemu_console_set_surface(con, surface);
}
QemuConsole *qemu_console_lookup_default(void)
@@ -1373,7 +1373,7 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
}
surface = qemu_create_displaysurface(width, height);
- dpy_gfx_replace_surface(s, surface);
+ qemu_console_set_surface(s, surface);
}
DisplaySurface *qemu_console_surface(QemuConsole *console)
diff --git a/ui/curses.c b/ui/curses.c
index 4e2a0b25955..f8d4542768b 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -1,8 +1,8 @@
/*
* QEMU curses/ncurses display driver
- *
+ *
* Copyright (c) 2005 Andrzej Zaborowski <balrog@zabor.org>
- *
+ *
* 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 */
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 249760d82aa..88f58e88efb 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -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;
}
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index fe58e3ef24d..40287d1c687 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -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
diff --git a/ui/egl-headless.c b/ui/egl-headless.c
index 4f046c975a9..878bfebb40c 100644
--- a/ui/egl-headless.c
+++ b/ui/egl-headless.c
@@ -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 = {
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index fa8fe8970c1..7c5c9b2428c 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -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);
diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c
index ce49000d3f1..23806b9d01b 100644
--- a/ui/gtk-gl-area.c
+++ b/ui/gtk-gl-area.c
@@ -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);
}
diff --git a/ui/gtk.c b/ui/gtk.c
index 3aaa44ff3e2..bcb67db7ee7 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -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) {
diff --git a/ui/sdl2-2d.c b/ui/sdl2-2d.c
index 73052383c2e..68a3aff7151 100644
--- a/ui/sdl2-2d.c
+++ b/ui/sdl2-2d.c
@@ -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);
}
diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c
index bb066cdd885..1547ad2f6f8 100644
--- a/ui/sdl2-gl.c
+++ b/ui/sdl2-gl.c
@@ -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);
diff --git a/ui/sdl2.c b/ui/sdl2.c
index 4f8b05fbd85..0f93a2fec84 100644
--- a/ui/sdl2.c
+++ b/ui/sdl2.c
@@ -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)) {
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 56d8140fad8..e3716127203 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -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();
diff --git a/ui/vnc.c b/ui/vnc.c
index 21698835084..e1fba53ee57 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -2324,8 +2324,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) {
@@ -2383,7 +2383,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]) {
@@ -2637,9 +2637,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 */);
@@ -3241,14 +3241,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;
}
@@ -3322,7 +3322,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) {
@@ -3362,7 +3362,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);
@@ -3418,7 +3418,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);
diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m
index 77d80fb7cef..be0061b9db2 100644
--- a/hw/display/apple-gfx.m
+++ b/hw/display/apple-gfx.m
@@ -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;
}
diff --git a/ui/cocoa.m b/ui/cocoa.m
index aaf82421589..98394cdc507 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -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);
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 61/67] ui/console: move console_handle_touch_event() to input
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (59 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 60/67] ui/console: rename public API to use consistent qemu_console_ prefix Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 62/67] ui/vnc: replace VNC_DEBUG with trace-events Marc-André Lureau
` (5 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
The function uses input.c functions to provide a simpler abstraction for
touch events. Let's move it from the already overloaded console.c, and
to avoid some unnecessary dependency from console.c on input.c.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
include/ui/console.h | 14 -----------
include/ui/input.h | 15 ++++++++++++
ui/console.c | 65 ----------------------------------------------------
ui/dbus-console.c | 6 ++---
ui/gtk.c | 8 +++----
ui/input.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 87 insertions(+), 86 deletions(-)
diff --git a/include/ui/console.h b/include/ui/console.h
index 5566d1f65f9..89a93230bb0 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -111,20 +111,6 @@ void qemu_text_console_put_keysym(QemuTextConsole *s, int keysym);
bool qemu_text_console_put_qcode(QemuTextConsole *s, int qcode, bool ctrl);
void qemu_text_console_put_string(QemuTextConsole *s, const char *str, int len);
-/* Touch devices */
-typedef struct touch_slot {
- int x;
- int y;
- int tracking_id;
-} touch_slot;
-
-void console_handle_touch_event(QemuConsole *con,
- struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
- uint64_t num_slot,
- int width, int height,
- double x, double y,
- InputMultiTouchType type,
- Error **errp);
/* consoles */
struct QemuConsoleClass {
diff --git a/include/ui/input.h b/include/ui/input.h
index 8f9aac562ed..52c164bde57 100644
--- a/include/ui/input.h
+++ b/include/ui/input.h
@@ -70,6 +70,21 @@ void qemu_input_queue_mtt_abs(QemuConsole *src, InputAxis axis, int value,
int min_in, int max_in,
int slot, int tracking_id);
+/* Touch devices */
+typedef struct touch_slot {
+ int x;
+ int y;
+ int tracking_id;
+} touch_slot;
+
+void qemu_input_touch_event(QemuConsole *con,
+ struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
+ uint64_t num_slot,
+ int width, int height,
+ double x, double y,
+ InputMultiTouchType type,
+ Error **errp);
+
void qemu_input_check_mode_change(void);
void qemu_add_mouse_mode_change_notifier(Notifier *notify);
void qemu_remove_mouse_mode_change_notifier(Notifier *notify);
diff --git a/ui/console.c b/ui/console.c
index 344bf308b0c..405dd1bb5b8 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -550,71 +550,6 @@ static bool console_compatible_with(QemuConsole *con,
return true;
}
-void console_handle_touch_event(QemuConsole *con,
- struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
- uint64_t num_slot,
- int width, int height,
- double x, double y,
- InputMultiTouchType type,
- Error **errp)
-{
- struct touch_slot *slot;
- bool needs_sync = false;
- int update;
- int i;
-
- if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
- error_setg(errp,
- "Unexpected touch slot number: % " PRId64" >= %d",
- num_slot, INPUT_EVENT_SLOTS_MAX);
- return;
- }
-
- slot = &touch_slots[num_slot];
- slot->x = x;
- slot->y = y;
-
- if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
- slot->tracking_id = num_slot;
- }
-
- for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
- if (i == num_slot) {
- update = type;
- } else {
- update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
- }
-
- slot = &touch_slots[i];
-
- if (slot->tracking_id == -1) {
- continue;
- }
-
- if (update == INPUT_MULTI_TOUCH_TYPE_END) {
- slot->tracking_id = -1;
- qemu_input_queue_mtt(con, update, i, slot->tracking_id);
- needs_sync = true;
- } else {
- qemu_input_queue_mtt(con, update, i, slot->tracking_id);
- qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
- qemu_input_queue_mtt_abs(con,
- INPUT_AXIS_X, (int) slot->x,
- 0, width,
- i, slot->tracking_id);
- qemu_input_queue_mtt_abs(con,
- INPUT_AXIS_Y, (int) slot->y,
- 0, height,
- i, slot->tracking_id);
- needs_sync = true;
- }
- }
-
- if (needs_sync) {
- qemu_input_event_sync();
- }
-}
-
void qemu_console_set_display_gl_ctx(QemuConsole *con, DisplayGLCtx *gl)
{
/* display has opengl support */
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index 88f58e88efb..b8e5c57b148 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -423,9 +423,9 @@ dbus_touch_send_event(DBusDisplayConsole *ddc,
width = qemu_console_get_width(ddc->dcl.con, 0);
height = qemu_console_get_height(ddc->dcl.con, 0);
- console_handle_touch_event(ddc->dcl.con, touch_slots,
- num_slot, width, height,
- x, y, kind, &error);
+ qemu_input_touch_event(ddc->dcl.con, touch_slots,
+ num_slot, width, height,
+ x, y, kind, &error);
if (error != NULL) {
g_dbus_method_invocation_return_error(
invocation, DBUS_DISPLAY_ERROR,
diff --git a/ui/gtk.c b/ui/gtk.c
index bcb67db7ee7..3b84224d8e8 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1201,10 +1201,10 @@ static gboolean gd_touch_event(GtkWidget *widget, GdkEventTouch *touch,
return FALSE;
}
- console_handle_touch_event(vc->gfx.dcl.con, touch_slots,
- num_slot, surface_width(vc->gfx.ds),
- surface_height(vc->gfx.ds), touch->x,
- touch->y, type, &err);
+ qemu_input_touch_event(vc->gfx.dcl.con, touch_slots,
+ num_slot, surface_width(vc->gfx.ds),
+ surface_height(vc->gfx.ds), touch->x,
+ touch->y, type, &err);
if (err) {
warn_report_err(err);
}
diff --git a/ui/input.c b/ui/input.c
index 147e69c1c3c..57e7817878a 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -609,3 +609,68 @@ bool qemu_mouse_set(int index, Error **errp)
notifier_list_notify(&mouse_mode_notifiers, NULL);
return true;
}
+
+void qemu_input_touch_event(QemuConsole *con,
+ struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX],
+ uint64_t num_slot,
+ int width, int height,
+ double x, double y,
+ InputMultiTouchType type,
+ Error **errp)
+{
+ struct touch_slot *slot;
+ bool needs_sync = false;
+ int update;
+ int i;
+
+ if (num_slot >= INPUT_EVENT_SLOTS_MAX) {
+ error_setg(errp,
+ "Unexpected touch slot number: % " PRId64" >= %d",
+ num_slot, INPUT_EVENT_SLOTS_MAX);
+ return;
+ }
+
+ slot = &touch_slots[num_slot];
+ slot->x = x;
+ slot->y = y;
+
+ if (type == INPUT_MULTI_TOUCH_TYPE_BEGIN) {
+ slot->tracking_id = num_slot;
+ }
+
+ for (i = 0; i < INPUT_EVENT_SLOTS_MAX; ++i) {
+ if (i == num_slot) {
+ update = type;
+ } else {
+ update = INPUT_MULTI_TOUCH_TYPE_UPDATE;
+ }
+
+ slot = &touch_slots[i];
+
+ if (slot->tracking_id == -1) {
+ continue;
+ }
+
+ if (update == INPUT_MULTI_TOUCH_TYPE_END) {
+ slot->tracking_id = -1;
+ qemu_input_queue_mtt(con, update, i, slot->tracking_id);
+ needs_sync = true;
+ } else {
+ qemu_input_queue_mtt(con, update, i, slot->tracking_id);
+ qemu_input_queue_btn(con, INPUT_BUTTON_TOUCH, true);
+ qemu_input_queue_mtt_abs(con,
+ INPUT_AXIS_X, (int) slot->x,
+ 0, width,
+ i, slot->tracking_id);
+ qemu_input_queue_mtt_abs(con,
+ INPUT_AXIS_Y, (int) slot->y,
+ 0, height,
+ i, slot->tracking_id);
+ needs_sync = true;
+ }
+ }
+
+ if (needs_sync) {
+ qemu_input_event_sync();
+ }
+}
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 62/67] ui/vnc: replace VNC_DEBUG with trace-events
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (60 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 61/67] ui/console: move console_handle_touch_event() to input Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 63/67] ui: extract common sources into a static library Marc-André Lureau
` (4 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
Replace #ifdef printf() with run-time trace events.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
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(-)
diff --git a/ui/vnc.h b/ui/vnc.h
index 7341fb0f25c..0324e5a98bc 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -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
diff --git a/ui/vnc-auth-sasl.c b/ui/vnc-auth-sasl.c
index 3f4cfc471d5..9964b969ac2 100644
--- a/ui/vnc-auth-sasl.c
+++ b/ui/vnc-auth-sasl.c
@@ -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);
}
-
-
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 9dfe6ae5a24..ca671427018 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -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;
diff --git a/ui/vnc-enc-zlib.c b/ui/vnc-enc-zlib.c
index a6d287118aa..657b47ceb2b 100644
--- a/ui/vnc-enc-zlib.c
+++ b/ui/vnc-enc-zlib.c
@@ -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;
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index 9e3503d93d8..b7d4de41431 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -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);
}
@@ -71,7 +71,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;
@@ -101,11 +101,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);
diff --git a/ui/vnc.c b/ui/vnc.c
index e1fba53ee57..12a2b10b418 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -75,17 +75,7 @@ static void vnc_disconnect_finish(VncState *vs);
static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
{
-#ifdef _VNC_DEBUG
- static const char *mn[] = {
- [0] = "undefined",
- [VNC_SHARE_MODE_CONNECTING] = "connecting",
- [VNC_SHARE_MODE_SHARED] = "shared",
- [VNC_SHARE_MODE_EXCLUSIVE] = "exclusive",
- [VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
- };
- fprintf(stderr, "%s/%p: %s -> %s\n", __func__,
- vs->ioc, mn[vs->share_mode], mn[mode]);
-#endif
+ trace_vnc_set_share_mode(vs, vs->ioc, vs->share_mode, mode);
switch (vs->share_mode) {
case VNC_SHARE_MODE_CONNECTING:
@@ -185,8 +175,9 @@ static void vnc_init_basic_info_from_remote_addr(QIOChannelSocket *ioc,
qapi_free_SocketAddress(addr);
}
-static const char *vnc_auth_name(VncDisplay *vd) {
- switch (vd->auth) {
+static const char *vnc_auth_name(int auth, int subauth)
+{
+ switch (auth) {
case VNC_AUTH_INVALID:
return "invalid";
case VNC_AUTH_NONE:
@@ -204,7 +195,7 @@ static const char *vnc_auth_name(VncDisplay *vd) {
case VNC_AUTH_TLS:
return "tls";
case VNC_AUTH_VENCRYPT:
- switch (vd->subauth) {
+ switch (subauth) {
case VNC_AUTH_VENCRYPT_PLAIN:
return "vencrypt+plain";
case VNC_AUTH_VENCRYPT_TLSNONE:
@@ -244,7 +235,7 @@ static VncServerInfo *vnc_server_info_get(VncDisplay *vd)
info = g_malloc0(sizeof(*info));
vnc_init_basic_info_from_server_addr(qio_net_listener_sioc(vd->listener, 0),
qapi_VncServerInfo_base(info), &err);
- info->auth = g_strdup(vnc_auth_name(vd));
+ info->auth = g_strdup(vnc_auth_name(vd->auth, vd->subauth));
if (err) {
qapi_free_VncServerInfo(info);
info = NULL;
@@ -421,7 +412,7 @@ VncInfo *qmp_query_vnc(Error **errp)
info->has_family = true;
- info->auth = g_strdup(vnc_auth_name(vd));
+ info->auth = g_strdup(vnc_auth_name(vd->auth, vd->subauth));
}
qapi_free_SocketAddress(addr);
@@ -1382,7 +1373,7 @@ size_t vnc_client_io_error(VncState *vs, ssize_t ret, Error *err)
void vnc_client_error(VncState *vs)
{
- VNC_DEBUG("Closing down client sock: protocol error\n");
+ trace_vnc_client_protocol_error(vs);
vnc_disconnect_start(vs);
}
@@ -1407,7 +1398,7 @@ size_t vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen)
Error *err = NULL;
ssize_t ret;
ret = qio_channel_write(vs->ioc, (const char *)data, datalen, &err);
- VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret);
+ trace_vnc_client_write_wire(vs, data, datalen, ret);
return vnc_client_io_error(vs, ret, err);
}
@@ -1428,9 +1419,9 @@ static size_t vnc_client_write_plain(VncState *vs)
size_t ret;
#ifdef CONFIG_VNC_SASL
- VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n",
- vs->output.buffer, vs->output.capacity, vs->output.offset,
- vs->sasl.waitWriteSSF);
+ trace_vnc_client_write_plain(vs, vs->output.buffer,
+ vs->output.capacity, vs->output.offset,
+ vs->sasl.waitWriteSSF);
if (vs->sasl.conn &&
vs->sasl.runSSF &&
@@ -1531,7 +1522,7 @@ size_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
ssize_t ret;
Error *err = NULL;
ret = qio_channel_read(vs->ioc, (char *)data, datalen, &err);
- VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret);
+ trace_vnc_client_read_wire(vs, data, datalen, ret);
return vnc_client_io_error(vs, ret, err);
}
@@ -1548,8 +1539,8 @@ size_t vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen)
static size_t vnc_client_read_plain(VncState *vs)
{
size_t ret;
- VNC_DEBUG("Read plain %p size %zd offset %zd\n",
- vs->input.buffer, vs->input.capacity, vs->input.offset);
+ trace_vnc_client_read_plain(vs, vs->input.buffer,
+ vs->input.capacity, vs->input.offset);
buffer_reserve(&vs->input, 4096);
ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096);
if (!ret)
@@ -2212,7 +2203,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
}
break;
default:
- VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc);
+ trace_vnc_client_unknown_encoding(vs, i, enc);
break;
}
}
@@ -2580,14 +2571,13 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
case 4: vs->as.fmt = AUDIO_FORMAT_U32; break;
case 5: vs->as.fmt = AUDIO_FORMAT_S32; break;
default:
- VNC_DEBUG("Invalid audio format %d\n", read_u8(data, 4));
+ trace_vnc_client_invalid_audio_format(vs, read_u8(data, 4));
vnc_client_error(vs);
break;
}
vs->as.nchannels = read_u8(data, 5);
if (vs->as.nchannels != 1 && vs->as.nchannels != 2) {
- VNC_DEBUG("Invalid audio channel count %d\n",
- read_u8(data, 5));
+ trace_vnc_client_invalid_audio_channels(vs, read_u8(data, 5));
vnc_client_error(vs);
break;
}
@@ -2597,7 +2587,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
* protects calculations involving 'vs->as.freq' later.
*/
if (freq > 48000) {
- VNC_DEBUG("Invalid audio frequency %u > 48000", freq);
+ trace_vnc_client_invalid_audio_freq(vs, freq);
vnc_client_error(vs);
break;
}
@@ -2606,14 +2596,14 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
vs, vs->ioc, vs->as.fmt, vs->as.nchannels, vs->as.freq);
break;
default:
- VNC_DEBUG("Invalid audio message %d\n", read_u8(data, 2));
+ trace_vnc_client_invalid_audio_msg(vs, read_u8(data, 2));
vnc_client_error(vs);
break;
}
break;
default:
- VNC_DEBUG("Msg: %d\n", read_u16(data, 0));
+ trace_vnc_client_unknown_qemu_msg(vs, read_u16(data, 0));
vnc_client_error(vs);
break;
}
@@ -2648,7 +2638,7 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
break;
}
default:
- VNC_DEBUG("Msg: %d\n", data[0]);
+ trace_vnc_client_unknown_msg(vs, data[0]);
vnc_client_error(vs);
break;
}
@@ -2928,18 +2918,18 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
local[12] = 0;
if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
- VNC_DEBUG("Malformed protocol version %s\n", local);
+ trace_vnc_client_protocol_version_malformed(vs, local);
vnc_client_error(vs);
return 0;
}
- VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
+ trace_vnc_client_protocol_version(vs, vs->major, vs->minor);
if (vs->major != 3 ||
(vs->minor != 3 &&
vs->minor != 4 &&
vs->minor != 5 &&
vs->minor != 7 &&
vs->minor != 8)) {
- VNC_DEBUG("Unsupported client version\n");
+ trace_vnc_client_protocol_version_unsupported(vs);
vnc_write_u32(vs, VNC_AUTH_INVALID);
vnc_flush(vs);
vnc_client_error(vs);
@@ -2959,7 +2949,7 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
trace_vnc_auth_pass(vs, vs->auth);
start_client_init(vs);
} else if (vs->auth == VNC_AUTH_VNC) {
- VNC_DEBUG("Tell client VNC auth\n");
+ trace_vnc_client_auth_method(vs, vs->auth);
vnc_write_u32(vs, vs->auth);
vnc_flush(vs);
start_auth_vnc(vs);
@@ -3318,10 +3308,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
vs->subauth = vd->subauth;
}
}
- VNC_DEBUG("Client sioc=%p ws=%d auth=%d subauth=%d\n",
- sioc, websocket, vs->auth, vs->subauth);
-
- VNC_DEBUG("New client on socket %p\n", vs->sioc);
+ trace_vnc_client_setup(vs, sioc, websocket, vs->auth, vs->subauth);
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);
@@ -3722,13 +3709,10 @@ vnc_display_setup_auth(int *auth,
*/
if (websocket || !tlscreds) {
if (password) {
- VNC_DEBUG("Initializing VNC server with password auth\n");
*auth = VNC_AUTH_VNC;
} else if (sasl) {
- VNC_DEBUG("Initializing VNC server with SASL auth\n");
*auth = VNC_AUTH_SASL;
} else {
- VNC_DEBUG("Initializing VNC server with no auth\n");
*auth = VNC_AUTH_NONE;
}
*subauth = VNC_AUTH_INVALID;
@@ -3747,27 +3731,20 @@ vnc_display_setup_auth(int *auth,
*auth = VNC_AUTH_VENCRYPT;
if (password) {
if (is_x509) {
- VNC_DEBUG("Initializing VNC server with x509 password auth\n");
*subauth = VNC_AUTH_VENCRYPT_X509VNC;
} else {
- VNC_DEBUG("Initializing VNC server with TLS password auth\n");
*subauth = VNC_AUTH_VENCRYPT_TLSVNC;
}
-
} else if (sasl) {
if (is_x509) {
- VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
*subauth = VNC_AUTH_VENCRYPT_X509SASL;
} else {
- VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
*subauth = VNC_AUTH_VENCRYPT_TLSSASL;
}
} else {
if (is_x509) {
- VNC_DEBUG("Initializing VNC server with x509 no auth\n");
*subauth = VNC_AUTH_VENCRYPT_X509NONE;
} else {
- VNC_DEBUG("Initializing VNC server with TLS no auth\n");
*subauth = VNC_AUTH_VENCRYPT_TLSNONE;
}
}
@@ -4216,14 +4193,16 @@ static bool vnc_display_open(VncDisplay *vd, Error **errp)
sasl, false, errp) < 0) {
return false;
}
- trace_vnc_auth_init(vd, 0, vd->auth, vd->subauth);
+ trace_vnc_auth_init(vd, 0, vd->auth, vd->subauth,
+ vnc_auth_name(vd->auth, vd->subauth));
if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth,
vd->tlscreds, password,
sasl, true, errp) < 0) {
return false;
}
- trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth);
+ trace_vnc_auth_init(vd, 1, vd->ws_auth, vd->ws_subauth,
+ vnc_auth_name(vd->ws_auth, vd->ws_subauth));
#ifdef CONFIG_VNC_SASL
if (sasl && !vnc_sasl_server_init(errp)) {
diff --git a/ui/trace-events b/ui/trace-events
index 3eba9ca3a82..c1ea56874ee 100644
--- a/ui/trace-events
+++ b/ui/trace-events
@@ -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
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 63/67] ui: extract common sources into a static library
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (61 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 62/67] ui/vnc: replace VNC_DEBUG with trace-events Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 64/67] tests: rename the dbus-daemon helper script Marc-André Lureau
` (3 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Philippe Mathieu-Daudé
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.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
ui/meson.build | 103 ++++++++++++++++++++++++++++++---------------------------
1 file changed, 55 insertions(+), 48 deletions(-)
diff --git a/ui/meson.build b/ui/meson.build
index f959f8972b5..c3f4d03eaf8 100644
--- a/ui/meson.build
+++ b/ui/meson.build
@@ -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-@1@.c.inc'.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'))
@@ -151,41 +193,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-@1@.c.inc'.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
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 64/67] tests: rename the dbus-daemon helper script
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (62 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 63/67] ui: extract common sources into a static library Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 65/67] tests/qtest: fix dbus-vmstate-test compilation Marc-André Lureau
` (2 subsequent siblings)
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel
Cc: Marc-André Lureau, Daniel P. Berrangé,
Philippe Mathieu-Daudé
The following patches are going to use it for qemu-vnc.
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
tests/{dbus-vmstate-daemon.sh => dbus-daemon.sh} | 0
tests/qtest/meson.build | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/dbus-vmstate-daemon.sh b/tests/dbus-daemon.sh
similarity index 100%
rename from tests/dbus-vmstate-daemon.sh
rename to tests/dbus-daemon.sh
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index be4fa627b5f..b735f55fc40 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -435,7 +435,7 @@ foreach dir : target_dirs
qtest_env.set('QTEST_QEMU_IMG', './qemu-img')
test_deps += [qemu_img]
endif
- qtest_env.set('G_TEST_DBUS_DAEMON', meson.project_source_root() / 'tests/dbus-vmstate-daemon.sh')
+ qtest_env.set('G_TEST_DBUS_DAEMON', meson.project_source_root() / 'tests/dbus-daemon.sh')
qtest_env.set('QTEST_QEMU_BINARY', './qemu-system-' + target_base)
if have_tools and have_vhost_user_blk_server
qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon')
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 65/67] tests/qtest: fix dbus-vmstate-test compilation
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (63 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 64/67] tests: rename the dbus-daemon helper script Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 66/67] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 67/67] tools/qemu-vnc: add standalone VNC server over D-Bus Marc-André Lureau
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
The test is still disabled, and trying to compile it will fail now.
Fix it, and remove the G_TEST_DBUS_DAEMON setting, since it is passed by
meson test. Fwiw, the test passes here.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
tests/qtest/dbus-vmstate-test.c | 11 ++---------
tests/qtest/meson.build | 3 ++-
2 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/tests/qtest/dbus-vmstate-test.c b/tests/qtest/dbus-vmstate-test.c
index 0a82cc9f935..5c80bb303b6 100644
--- a/tests/qtest/dbus-vmstate-test.c
+++ b/tests/qtest/dbus-vmstate-test.c
@@ -3,7 +3,7 @@
#include <gio/gio.h>
#include "libqtest.h"
#include "dbus-vmstate1.h"
-#include "migration-helpers.h"
+#include "migration/migration-qmp.h"
static char *workdir;
@@ -230,7 +230,7 @@ test_dbus_vmstate(Test *test)
thread = g_thread_new("dbus-vmstate-thread", dbus_vmstate_thread, loop);
migrate_incoming_qmp(dst_qemu, uri, NULL, "{}");
- migrate_qmp(src_qemu, uri, "{}");
+ migrate_qmp(src_qemu, dst_qemu, uri, NULL, "{}");
test->src_qemu = src_qemu;
if (test->migrate_fail) {
wait_for_migration_fail(src_qemu, true);
@@ -343,15 +343,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);
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index b735f55fc40..5f8cff172c8 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -130,7 +130,8 @@ if dbus_daemon.found() and gdbus_codegen.found()
input: meson.project_source_root() / 'backends/dbus-vmstate1.xml',
command: [gdbus_codegen, '@INPUT@',
'--interface-prefix', 'org.qemu',
- '--generate-c-code', '@BASENAME@']).to_list()
+ '--generate-c-code', '@BASENAME@',
+ '--output-directory', meson.current_build_dir()]).to_list()
else
dbus_vmstate1 = []
endif
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 66/67] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (64 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 65/67] tests/qtest: fix dbus-vmstate-test compilation Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 67/67] tools/qemu-vnc: add standalone VNC server over D-Bus Marc-André Lureau
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
It can rely on the location of the temporary configuration instead.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
tests/qtest/dbus-vmstate-test.c | 2 --
tests/dbus-daemon.sh | 2 +-
2 files changed, 1 insertion(+), 3 deletions(-)
diff --git a/tests/qtest/dbus-vmstate-test.c b/tests/qtest/dbus-vmstate-test.c
index 5c80bb303b6..1812d0fb70a 100644
--- a/tests/qtest/dbus-vmstate-test.c
+++ b/tests/qtest/dbus-vmstate-test.c
@@ -353,8 +353,6 @@ main(int argc, char **argv)
exit(1);
}
- 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",
diff --git a/tests/dbus-daemon.sh b/tests/dbus-daemon.sh
index 474e2501548..c4a50c73774 100755
--- a/tests/dbus-daemon.sh
+++ b/tests/dbus-daemon.sh
@@ -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
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* [PATCH v2 67/67] tools/qemu-vnc: add standalone VNC server over D-Bus
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
` (65 preceding siblings ...)
2026-04-10 19:19 ` [PATCH v2 66/67] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR Marc-André Lureau
@ 2026-04-10 19:19 ` Marc-André Lureau
66 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-10 19:19 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau
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.
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
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 | 222 +++++++
meson.build | 17 +
tools/qemu-vnc/qemu-vnc.h | 46 ++
tools/qemu-vnc/trace.h | 4 +
tests/qtest/dbus-vnc-test.c | 1342 +++++++++++++++++++++++++++++++++++++++++
tools/qemu-vnc/audio.c | 307 ++++++++++
tools/qemu-vnc/chardev.c | 127 ++++
tools/qemu-vnc/clipboard.c | 378 ++++++++++++
tools/qemu-vnc/console.c | 168 ++++++
tools/qemu-vnc/dbus.c | 439 ++++++++++++++
tools/qemu-vnc/display.c | 456 ++++++++++++++
tools/qemu-vnc/input.c | 239 ++++++++
tools/qemu-vnc/qemu-vnc.c | 491 +++++++++++++++
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 | 174 ++++++
tools/qemu-vnc/trace-events | 20 +
29 files changed, 4645 insertions(+), 3 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS
index ad215eced84..9cddf898c77 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2825,6 +2825,11 @@ F: docs/interop/vhost-user-gpu.rst
F: contrib/vhost-user-gpu
F: hw/display/vhost-user-*
+qemu-vnc:
+M: Marc-André Lureau <marcandre.lureau@redhat.com>
+S: Maintained
+F: tools/qemu-vnc
+
Cirrus VGA
M: Gerd Hoffmann <kraxel@redhat.com>
S: Odd Fixes
diff --git a/docs/conf.py b/docs/conf.py
index f835904ba1e..7e35d2158d3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -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
diff --git a/docs/interop/dbus-display.rst b/docs/interop/dbus-display.rst
index 8c6e8e0f5a8..87648e91dc0 100644
--- a/docs/interop/dbus-display.rst
+++ b/docs/interop/dbus-display.rst
@@ -1,3 +1,5 @@
+.. _dbus-display:
+
D-Bus display
=============
diff --git a/docs/interop/dbus-vnc.rst b/docs/interop/dbus-vnc.rst
new file mode 100644
index 00000000000..d2b77978f63
--- /dev/null
+++ b/docs/interop/dbus-vnc.rst
@@ -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
diff --git a/docs/interop/index.rst b/docs/interop/index.rst
index d830c5c4104..2cf3a8c9aa3 100644
--- a/docs/interop/index.rst
+++ b/docs/interop/index.rst
@@ -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
diff --git a/docs/meson.build b/docs/meson.build
index 7e54b01e6a0..c3e9fb05846 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -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'
diff --git a/docs/tools/index.rst b/docs/tools/index.rst
index 1e88ae48cdc..868c3c4d9d8 100644
--- a/docs/tools/index.rst
+++ b/docs/tools/index.rst
@@ -16,3 +16,4 @@ command line utilities and other standalone programs.
qemu-pr-helper
qemu-trace-stap
qemu-vmsr-helper
+ qemu-vnc
diff --git a/docs/tools/qemu-vnc.rst b/docs/tools/qemu-vnc.rst
new file mode 100644
index 00000000000..a4de4a7d4f8
--- /dev/null
+++ b/docs/tools/qemu-vnc.rst
@@ -0,0 +1,222 @@
+.. _qemu-vnc:
+
+==========================
+QEMU standalone VNC server
+==========================
+
+Synopsis
+--------
+
+**qemu-vnc** [*OPTION*]...
+
+Description
+-----------
+
+``qemu-vnc`` is a standalone VNC server that connects to a running QEMU instance
+via the D-Bus display interface (:ref:`dbus-display`). It serves the guest
+display, input, audio, clipboard, and serial console chardevs over the VNC
+protocol, allowing VNC clients to interact with the virtual machine without QEMU
+itself binding a VNC socket.
+
+Options
+-------
+
+.. program:: qemu-vnc
+
+.. option:: -h, --help
+
+ Display help and exit.
+
+.. option:: -V, --version
+
+ Print version information and exit.
+
+.. option:: -a ADDRESS, --dbus-address=ADDRESS
+
+ D-Bus address to connect to. When not specified, ``qemu-vnc`` connects to the
+ session bus.
+
+.. option:: -p FD, --dbus-p2p-fd=FD
+
+ File descriptor of an inherited Unix socket for a peer-to-peer D-Bus
+ connection to QEMU. This is mutually exclusive with ``--dbus-address`` and
+ ``--bus-name``.
+
+.. option:: -n NAME, --bus-name=NAME
+
+ D-Bus bus name of the QEMU instance to connect to. The default is
+ ``org.qemu``. When a custom ``--dbus-address`` is given without a bus name,
+ peer-to-peer D-Bus is used.
+
+.. option:: --password
+
+ Require VNC password authentication from connecting clients. The password is
+ set at runtime via the D-Bus ``SetPassword`` method (see
+ :doc:`/interop/dbus-vnc`). Clients will not be able to connect until a
+ password has been set.
+
+ This option is ignored when a systemd credential password is present, since
+ password authentication is already enabled via ``password-secret`` in that
+ case.
+
+.. option:: -l ADDR, --vnc-addr=ADDR
+
+ VNC listen address in the same format as the QEMU ``-vnc`` option (default
+ ``localhost:0``, i.e. TCP port 5900).
+
+.. option:: -w ADDR, --websocket=ADDR
+
+ Enable WebSocket transport on the given address. *ADDR* can be a port number
+ or an *address:port* pair.
+
+.. option:: -O OBJDEF, --object=OBJDEF
+
+ Create a QEMU user-creatable object. *OBJDEF* uses the same key=value syntax
+ as the QEMU ``-object`` option. This option may be given multiple times. It is
+ needed, for example, to create authorization objects referenced by
+ ``--tls-authz``.
+
+.. option:: -t DIR, --tls-creds=DIR
+
+ Directory containing TLS x509 credentials (``ca-cert.pem``,
+ ``server-cert.pem``, ``server-key.pem``). When specified, the VNC server
+ requires TLS from connecting clients.
+
+.. option:: --tls-authz=ID
+
+ ID of a ``QAuthZ`` object previously created with ``--object`` for TLS client
+ certificate authorization. When specified, the TLS credentials are created
+ with ``verify-peer=yes`` so connecting clients must present a valid
+ certificate. After the TLS handshake, the client certificate Distinguished
+ Name is checked against the authorization object. This option requires
+ ``--tls-creds``.
+
+.. option:: --sasl
+
+ Require that the client use SASL to authenticate with the VNC server. The
+ exact choice of authentication method used is controlled from the system /
+ user's SASL configuration file for the 'qemu' service. This is typically found
+ in ``/etc/sasl2/qemu.conf``. If running QEMU as an unprivileged user, an
+ environment variable ``SASL_CONF_PATH`` can be used to make it search
+ alternate locations for the service config. While some SASL auth methods can
+ also provide data encryption (eg GSSAPI), it is recommended that SASL always
+ be combined with the 'tls' and 'x509' settings to enable use of SSL and server
+ certificates. This ensures a data encryption preventing compromise of
+ authentication credentials. See the :ref:`VNC security` section in the System
+ Emulation Users Guide for details on using SASL authentication.
+
+.. option:: --sasl-authz=ID
+
+ ID of a ``QAuthZ`` object previously created with ``--object`` for SASL
+ username authorization. After successful SASL authentication, the
+ authenticated username is checked against the authorization object. If the
+ check fails, the client is disconnected. This option requires ``--sasl``.
+
+.. option:: -s POLICY, --share=POLICY
+
+ Set display sharing policy. *POLICY* is one of ``allow-exclusive``,
+ ``force-shared``, or ``ignore``.
+
+ ``allow-exclusive`` allows clients to ask for exclusive access. As suggested
+ by the RFB spec this is implemented by dropping other connections. Connecting
+ multiple clients in parallel requires all clients asking for a shared session
+ (vncviewer: -shared switch). This is the default.
+
+ ``force-shared`` disables exclusive client access. Useful for shared desktop
+ sessions, where you don't want someone forgetting to specify -shared
+ disconnect everybody else.
+
+ ``ignore`` completely ignores the shared flag and allows everybody to connect
+ unconditionally. Doesn't conform to the RFB spec but is traditional QEMU
+ behavior.
+
+.. option:: -C NAME, --vt-chardev=NAME
+
+ Chardev type name to expose as a VNC text console. This option may be given
+ multiple times to expose several chardevs. When not specified, the defaults
+ ``org.qemu.console.serial.0`` and ``org.qemu.monitor.hmp.0`` are used.
+
+.. option:: -N, --no-vt
+
+ Do not expose any chardevs as text consoles. This overrides the default
+ chardev list and any ``--vt-chardev`` options.
+
+.. option:: -k LAYOUT, --keyboard-layout=LAYOUT
+
+ Keyboard layout (e.g. ``en-us``). Passed through to the VNC server for
+ key-code translation.
+
+.. option:: --lossy
+
+ Enable lossy compression methods (gradient, JPEG, ...). If this option is set,
+ VNC client may receive lossy framebuffer updates depending on its encoding
+ settings. Enabling this option can save a lot of bandwidth at the expense of
+ quality.
+
+.. option:: --non-adaptive
+
+ Disable adaptive encodings. Adaptive encodings are enabled by default. An
+ adaptive encoding will try to detect frequently updated screen regions, and
+ send updates in these regions using a lossy encoding (like JPEG). This can be
+ really helpful to save bandwidth when playing videos. Disabling adaptive
+ encodings restores the original static behavior of encodings like Tight.
+
+.. option:: -T, --trace [[enable=]PATTERN][,events=FILE][,file=FILE]
+
+ .. include:: ../qemu-option-trace.rst.inc
+
+Examples
+--------
+
+Start QEMU with the D-Bus display backend::
+
+ qemu-system-x86_64 -display dbus ...
+
+Then attach ``qemu-vnc``::
+
+ qemu-vnc
+
+A VNC client can now connect to ``localhost:5900``.
+
+To listen on a different port with TLS::
+
+ qemu-vnc --vnc-addr localhost:1 --tls-creds /etc/pki/qemu-vnc
+
+To require TLS with client certificate authorization::
+
+ qemu-vnc --object authz-list-file,id=auth0,filename=/etc/qemu/vnc.acl,refresh=on \
+ --tls-creds /etc/pki/qemu-vnc --tls-authz auth0
+
+To enable SASL authentication with TLS::
+
+ qemu-vnc --tls-creds /etc/pki/qemu-vnc --sasl
+
+VNC password authentication
+----------------------------
+
+There are two ways to enable VNC password authentication:
+
+1. ``--password`` flag -- start ``qemu-vnc`` with ``--password`` and
+ then set the password at runtime using the D-Bus ``SetPassword``
+ method. Clients will be rejected until a password is set.
+
+2. systemd credentials -- if the ``CREDENTIALS_DIRECTORY``
+ environment variable is set (see :manpage:`systemd.exec(5)`) and
+ contains a file named ``vnc-password``, the VNC server will use
+ that file's contents as the password automatically. The
+ ``--password`` flag is not needed in this case.
+
+D-Bus interface
+---------------
+
+``qemu-vnc`` exposes a D-Bus interface for management and monitoring of
+VNC connections. See :doc:`/interop/dbus-vnc` for the full interface
+reference.
+
+See also
+--------
+
+:manpage:`qemu(1)`,
+:doc:`/interop/dbus-display`,
+:doc:`/interop/dbus-vnc`,
+`The RFB Protocol <https://github.com/rfbproto/rfbproto>`_
diff --git a/meson.build b/meson.build
index ab3e97eb9f4..78aa3d490ad 100644
--- a/meson.build
+++ b/meson.build
@@ -2341,6 +2341,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') \
@@ -3595,6 +3606,7 @@ trace_events_subdirs = [
'monitor',
'util',
'gdbstub',
+ 'tools/qemu-vnc',
]
if have_linux_user
trace_events_subdirs += [ 'linux-user' ]
@@ -4563,6 +4575,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()
@@ -4898,6 +4914,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}
diff --git a/tools/qemu-vnc/qemu-vnc.h b/tools/qemu-vnc/qemu-vnc.h
new file mode 100644
index 00000000000..420d5f66d42
--- /dev/null
+++ b/tools/qemu-vnc/qemu-vnc.h
@@ -0,0 +1,46 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef CONTRIB_QEMU_VNC_H
+#define CONTRIB_QEMU_VNC_H
+
+#include "qemu/osdep.h"
+
+#include <gio/gunixfdlist.h>
+#include "qemu/dbus.h"
+#include "ui/console.h"
+#include "ui/dbus-display1.h"
+
+#define TEXT_COLS 80
+#define TEXT_ROWS 24
+#define TEXT_FONT_WIDTH 8
+#define TEXT_FONT_HEIGHT 16
+
+
+QemuTextConsole *qemu_vnc_text_console_new(const char *name,
+ int fd, bool echo);
+
+void input_setup(QemuDBusDisplay1Keyboard *kbd,
+ QemuDBusDisplay1Mouse *mouse);
+bool console_setup(GDBusConnection *bus, const char *bus_name,
+ const char *console_path);
+QemuDBusDisplay1Keyboard *console_get_keyboard(QemuConsole *con);
+QemuDBusDisplay1Mouse *console_get_mouse(QemuConsole *con);
+
+void audio_setup(GDBusObjectManager *manager);
+void clipboard_setup(GDBusObjectManager *manager, GDBusConnection *bus);
+void chardev_setup(const char * const *chardev_names,
+ GDBusObjectManager *manager);
+
+GThread *p2p_dbus_thread_new(int fd);
+
+void vnc_dbus_setup(GDBusConnection *bus);
+void vnc_dbus_cleanup(void);
+void vnc_dbus_client_connected(const char *host, const char *service,
+ const char *family, bool websocket);
+void vnc_dbus_client_initialized(const char *host, const char *service,
+ const char *x509_dname,
+ const char *sasl_username);
+void vnc_dbus_client_disconnected(const char *host, const char *service);
+
+#endif /* CONTRIB_QEMU_VNC_H */
diff --git a/tools/qemu-vnc/trace.h b/tools/qemu-vnc/trace.h
new file mode 100644
index 00000000000..5fb7b432359
--- /dev/null
+++ b/tools/qemu-vnc/trace.h
@@ -0,0 +1,4 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#include "trace/trace-tools_qemu_vnc.h"
diff --git a/tests/qtest/dbus-vnc-test.c b/tests/qtest/dbus-vnc-test.c
new file mode 100644
index 00000000000..cbd6def9d51
--- /dev/null
+++ b/tests/qtest/dbus-vnc-test.c
@@ -0,0 +1,1342 @@
+/*
+ * D-Bus VNC server (qemu-vnc) end-to-end test
+ *
+ * Copyright (c) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include <gio/gio.h>
+#include <gvnc.h>
+#include <sys/un.h>
+#include "qemu/sockets.h"
+#include "libqtest.h"
+#include "qemu-vnc1.h"
+#ifdef CONFIG_TASN1
+#include "tests/unit/crypto-tls-x509-helpers.h"
+#endif
+
+#define VNC_TEST_TIMEOUT_MS 10000
+
+typedef struct DbusTest {
+ QTestState *qts;
+ GSubprocess *vnc_subprocess;
+ GTestDBus *bus;
+ GDBusConnection *bus_conn;
+ GMainLoop *loop;
+ char *vnc_sock_path;
+ char *tmp_dir;
+ char *bus_addr;
+} DbusTest;
+
+typedef struct LifecycleData {
+ DbusTest *dt;
+ QemuVnc1Server *server_proxy;
+ VncConnection *conn;
+ char *client_path;
+ gboolean got_connected;
+ gboolean got_initialized;
+ gboolean got_disconnected;
+} LifecycleData;
+
+static QemuVnc1Server *
+create_server_proxy(GDBusConnection *bus_conn, GError **errp)
+{
+ return qemu_vnc1_server_proxy_new_sync(
+ bus_conn,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.qemu.vnc",
+ "/org/qemu/Vnc1/Server",
+ NULL, errp);
+}
+
+static void
+on_vnc_error(VncConnection *self, const char *msg)
+{
+ g_error("vnc-error: %s", msg);
+}
+
+static void
+on_vnc_auth_failure(VncConnection *self, const char *msg)
+{
+ g_error("vnc-auth-failure: %s", msg);
+}
+
+static void
+on_vnc_initialized(VncConnection *self, GMainLoop *loop)
+{
+ const char *name = vnc_connection_get_name(self);
+
+ g_assert_cmpstr(name, ==, "QEMU (dbus-vnc-test)");
+ g_main_loop_quit(loop);
+}
+
+static gboolean
+timeout_cb(gpointer data)
+{
+ g_error("test timed out");
+ return G_SOURCE_REMOVE;
+}
+
+static int
+connect_unix_socket(const char *path)
+{
+ int fd;
+ struct sockaddr_un addr = { .sun_family = AF_UNIX };
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ g_assert(fd >= 0);
+
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
+
+ if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static int
+wait_for_vnc_socket(const char *path, int timeout_ms)
+{
+ int elapsed = 0;
+ const int interval = 50;
+
+ while (elapsed < timeout_ms) {
+ int fd = connect_unix_socket(path);
+
+ if (fd >= 0) {
+ return fd;
+ }
+
+ g_usleep(interval * 1000);
+ elapsed += interval;
+ }
+ return -1;
+}
+
+static GSubprocess *
+spawn_qemu_vnc(int dbus_fd, const char *sock_path)
+{
+ const char *binary;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GSubprocessLauncher) launcher = NULL;
+ GSubprocess *proc;
+ g_autofree char *fd_str = NULL;
+ g_autofree char *vnc_addr = NULL;
+
+ binary = g_getenv("QTEST_QEMU_VNC_BINARY");
+ g_assert(binary != NULL);
+
+ fd_str = g_strdup_printf("%d", dbus_fd);
+ vnc_addr = g_strdup_printf("unix:%s", sock_path);
+
+ launcher = g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE);
+ g_subprocess_launcher_take_fd(launcher, dbus_fd, dbus_fd);
+
+ proc = g_subprocess_launcher_spawn(launcher, &err,
+ binary,
+ "--dbus-p2p-fd", fd_str,
+ "--vnc-addr", vnc_addr,
+ NULL);
+ g_assert_no_error(err);
+ g_assert(proc != NULL);
+
+ return proc;
+}
+
+static GSubprocess *
+spawn_qemu_vnc_bus_full(const char *dbus_addr, const char *sock_path,
+ const char *const *extra_args)
+{
+ const char *binary;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GSubprocessLauncher) launcher = NULL;
+ g_autoptr(GPtrArray) argv = NULL;
+ GSubprocess *proc;
+ g_autofree char *vnc_addr = NULL;
+
+ binary = g_getenv("QTEST_QEMU_VNC_BINARY");
+ g_assert(binary != NULL);
+
+ vnc_addr = g_strdup_printf("unix:%s", sock_path);
+
+ argv = g_ptr_array_new();
+ g_ptr_array_add(argv, (gpointer)binary);
+ g_ptr_array_add(argv, (gpointer)"--dbus-address");
+ g_ptr_array_add(argv, (gpointer)dbus_addr);
+ g_ptr_array_add(argv, (gpointer)"--bus-name");
+ g_ptr_array_add(argv, (gpointer)"org.qemu");
+ g_ptr_array_add(argv, (gpointer)"--vnc-addr");
+ g_ptr_array_add(argv, (gpointer)vnc_addr);
+
+ if (extra_args) {
+ for (int i = 0; extra_args[i]; i++) {
+ g_ptr_array_add(argv, (gpointer)extra_args[i]);
+ }
+ }
+
+ g_ptr_array_add(argv, NULL);
+
+ launcher = g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE);
+ proc = g_subprocess_launcher_spawnv(launcher, (const char *const *)argv->pdata, &err);
+ g_assert_no_error(err);
+ g_assert(proc != NULL);
+
+ return proc;
+}
+
+
+static void
+name_appeared_cb(GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ gboolean *appeared = user_data;
+ *appeared = TRUE;
+}
+
+static bool
+setup_dbus_test_full(DbusTest *dt, const char *const *vnc_extra_args)
+{
+ g_autoptr(GError) err = NULL;
+ g_auto(GStrv) addr_parts = NULL;
+ g_autofree char *qemu_args = NULL;
+
+ if (!g_getenv("QTEST_QEMU_VNC_BINARY")) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return false;
+ }
+
+ dt->bus = g_test_dbus_new(G_TEST_DBUS_NONE);
+ g_test_dbus_up(dt->bus);
+
+ /* remove ,guid=foo part */
+ addr_parts = g_strsplit(g_test_dbus_get_bus_address(dt->bus), ",", 2);
+ dt->bus_addr = g_strdup(addr_parts[0]);
+
+ dt->bus_conn = g_dbus_connection_new_for_address_sync(
+ g_test_dbus_get_bus_address(dt->bus),
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
+ NULL, NULL, &err);
+ g_assert_no_error(err);
+
+ qemu_args = g_strdup_printf("-display dbus,addr=%s "
+ "-name dbus-vnc-test", dt->bus_addr);
+ dt->qts = qtest_init(qemu_args);
+
+ dt->tmp_dir = g_dir_make_tmp("dbus-vnc-test-XXXXXX", NULL);
+ g_assert(dt->tmp_dir != NULL);
+ dt->vnc_sock_path = g_build_filename(dt->tmp_dir, "vnc.sock", NULL);
+ dt->vnc_subprocess = spawn_qemu_vnc_bus_full(dt->bus_addr,
+ dt->vnc_sock_path,
+ vnc_extra_args);
+
+ /*
+ * Wait for the org.qemu.vnc bus name to appear, which indicates
+ * qemu-vnc has fully initialized (connected to QEMU, set up the
+ * display, exported its D-Bus interfaces, and opened the VNC
+ * socket).
+ */
+ {
+ guint watch_id, timeout_id;
+ gboolean appeared = FALSE;
+
+ watch_id = g_bus_watch_name_on_connection(
+ dt->bus_conn, "org.qemu.vnc",
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ name_appeared_cb, NULL, &appeared, NULL);
+ timeout_id = g_timeout_add_seconds(10, timeout_cb, NULL);
+
+ while (!appeared &&
+ g_main_context_iteration(NULL, TRUE)) {
+ }
+
+ g_bus_unwatch_name(watch_id);
+ g_source_remove(timeout_id);
+
+ if (!appeared) {
+ g_test_fail();
+ g_test_message("Timed out waiting for org.qemu.vnc bus name");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+setup_dbus_test(DbusTest *dt)
+{
+ return setup_dbus_test_full(dt, NULL);
+}
+
+static void
+cleanup_dbus_test(DbusTest *dt)
+{
+ if (dt->bus_conn) {
+ g_dbus_connection_close_sync(dt->bus_conn, NULL, NULL);
+ g_object_unref(dt->bus_conn);
+ }
+ if (dt->vnc_subprocess) {
+ g_subprocess_force_exit(dt->vnc_subprocess);
+ g_subprocess_wait(dt->vnc_subprocess, NULL, NULL);
+ g_object_unref(dt->vnc_subprocess);
+ }
+ if (dt->vnc_sock_path) {
+ unlink(dt->vnc_sock_path);
+ g_free(dt->vnc_sock_path);
+ }
+ if (dt->tmp_dir) {
+ rmdir(dt->tmp_dir);
+ g_free(dt->tmp_dir);
+ }
+ if (dt->qts) {
+ qtest_quit(dt->qts);
+ }
+ if (dt->bus) {
+ g_test_dbus_down(dt->bus);
+ g_object_unref(dt->bus);
+ }
+ g_free(dt->bus_addr);
+}
+
+static void
+test_dbus_vnc_basic(void)
+{
+ DbusTest dt = { 0 };
+ VncConnection *conn = NULL;
+ GMainLoop *loop = NULL;
+ int pair[2];
+ int vnc_fd;
+ guint timeout_id;
+
+ if (!g_getenv("QTEST_QEMU_VNC_BINARY")) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return;
+ }
+
+ dt.qts = qtest_init("-display dbus,p2p=yes -name dbus-vnc-test");
+
+ g_assert_cmpint(qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair), ==, 0);
+ qtest_qmp_add_client(dt.qts, "@dbus-display", pair[1]);
+ close(pair[1]);
+
+ dt.tmp_dir = g_dir_make_tmp("dbus-vnc-test-XXXXXX", NULL);
+ g_assert(dt.tmp_dir != NULL);
+ dt.vnc_sock_path = g_build_filename(dt.tmp_dir, "vnc.sock", NULL);
+
+ dt.vnc_subprocess = spawn_qemu_vnc(pair[0], dt.vnc_sock_path);
+
+ vnc_fd = wait_for_vnc_socket(dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(vnc_fd >= 0);
+
+ loop = g_main_loop_new(NULL, FALSE);
+
+ conn = vnc_connection_new();
+ g_signal_connect(conn, "vnc-error",
+ G_CALLBACK(on_vnc_error), NULL);
+ g_signal_connect(conn, "vnc-auth-failure",
+ G_CALLBACK(on_vnc_auth_failure), NULL);
+ g_signal_connect(conn, "vnc-initialized",
+ G_CALLBACK(on_vnc_initialized), loop);
+ vnc_connection_set_auth_type(conn, VNC_CONNECTION_AUTH_NONE);
+ vnc_connection_open_fd(conn, vnc_fd);
+
+ timeout_id = g_timeout_add_seconds(10, timeout_cb, NULL);
+ g_main_loop_run(loop);
+ g_source_remove(timeout_id);
+
+ if (conn) {
+ vnc_connection_shutdown(conn);
+ g_object_unref(conn);
+ }
+ g_clear_pointer(&loop, g_main_loop_unref);
+ cleanup_dbus_test(&dt);
+}
+
+static void
+test_dbus_vnc_server_props(void)
+{
+ DbusTest dt = { 0 };
+ QemuVnc1Server *proxy = NULL;
+ g_autoptr(GError) err = NULL;
+ const gchar *const *clients;
+ GVariant *listeners;
+
+ if (!setup_dbus_test(&dt)) {
+ goto cleanup;
+ }
+
+ proxy = create_server_proxy(dt.bus_conn, &err);
+ g_assert_no_error(err);
+ g_assert_nonnull(proxy);
+
+ g_assert_cmpstr(qemu_vnc1_server_get_name(proxy), ==,
+ "dbus-vnc-test");
+ g_assert_cmpstr(qemu_vnc1_server_get_auth(proxy), ==,
+ "none");
+ g_assert_cmpstr(qemu_vnc1_server_get_vencrypt_sub_auth(proxy), ==,
+ "");
+
+ clients = qemu_vnc1_server_get_clients(proxy);
+ g_assert_nonnull(clients);
+ g_assert_cmpint(g_strv_length((gchar **)clients), ==, 0);
+
+ listeners = qemu_vnc1_server_get_listeners(proxy);
+ g_assert_nonnull(listeners);
+ g_assert_cmpint(g_variant_n_children(listeners), >, 0);
+
+cleanup:
+ g_clear_object(&proxy);
+ cleanup_dbus_test(&dt);
+}
+
+static void
+on_client_connected(QemuVnc1Server *proxy,
+ const gchar *client_path,
+ LifecycleData *data)
+{
+ data->got_connected = TRUE;
+ data->client_path = g_strdup(client_path);
+}
+
+static void
+on_client_initialized(QemuVnc1Server *proxy,
+ const gchar *client_path,
+ LifecycleData *data)
+{
+ data->got_initialized = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+on_client_disconnected(QemuVnc1Server *proxy,
+ const gchar *client_path,
+ LifecycleData *data)
+{
+ data->got_disconnected = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+test_dbus_vnc_client_lifecycle(void)
+{
+ DbusTest dt = { 0 };
+ QemuVnc1Server *server_proxy = NULL;
+ QemuVnc1Client *client_proxy = NULL;
+ g_autoptr(GError) err = NULL;
+ LifecycleData ldata = { 0 };
+ int vnc_fd;
+ guint timeout_id;
+
+ if (!setup_dbus_test(&dt)) {
+ goto cleanup;
+ }
+
+ server_proxy = create_server_proxy(dt.bus_conn, &err);
+ g_assert_no_error(err);
+
+ ldata.dt = &dt;
+ ldata.server_proxy = server_proxy;
+
+ g_signal_connect(server_proxy, "client-connected",
+ G_CALLBACK(on_client_connected), &ldata);
+ g_signal_connect(server_proxy, "client-initialized",
+ G_CALLBACK(on_client_initialized), &ldata);
+ g_signal_connect(server_proxy, "client-disconnected",
+ G_CALLBACK(on_client_disconnected), &ldata);
+
+ vnc_fd = wait_for_vnc_socket(dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(vnc_fd >= 0);
+
+ ldata.conn = vnc_connection_new();
+ g_signal_connect(ldata.conn, "vnc-error",
+ G_CALLBACK(on_vnc_error), NULL);
+ g_signal_connect(ldata.conn, "vnc-auth-failure",
+ G_CALLBACK(on_vnc_auth_failure), NULL);
+ vnc_connection_set_auth_type(ldata.conn, VNC_CONNECTION_AUTH_NONE);
+ vnc_connection_open_fd(ldata.conn, vnc_fd);
+
+ /* wait for ClientInitialized */
+ dt.loop = g_main_loop_new(NULL, FALSE);
+ timeout_id = g_timeout_add_seconds(10, timeout_cb, NULL);
+ g_main_loop_run(dt.loop);
+ g_source_remove(timeout_id);
+
+ g_assert_true(ldata.got_connected);
+ g_assert_true(ldata.got_initialized);
+ g_assert_nonnull(ldata.client_path);
+
+ /* Check client properties while still connected */
+ client_proxy = qemu_vnc1_client_proxy_new_sync(
+ dt.bus_conn,
+ G_DBUS_PROXY_FLAGS_NONE,
+ "org.qemu.vnc",
+ ldata.client_path,
+ NULL, &err);
+ g_assert_no_error(err);
+
+ g_assert_cmpstr(qemu_vnc1_client_get_family(client_proxy), ==,
+ "unix");
+ g_assert_false(qemu_vnc1_client_get_web_socket(client_proxy));
+ g_assert_cmpstr(qemu_vnc1_client_get_x509_dname(client_proxy), ==,
+ "");
+ g_assert_cmpstr(qemu_vnc1_client_get_sasl_username(client_proxy),
+ ==, "");
+
+ /* disconnect and wait for ClientDisconnected */
+ vnc_connection_shutdown(ldata.conn);
+ timeout_id = g_timeout_add_seconds(10, timeout_cb, NULL);
+ g_main_loop_run(dt.loop);
+ g_source_remove(timeout_id);
+
+ g_assert_true(ldata.got_disconnected);
+
+ g_object_unref(ldata.conn);
+ g_main_loop_unref(dt.loop);
+ dt.loop = NULL;
+ g_free(ldata.client_path);
+
+cleanup:
+ g_clear_object(&server_proxy);
+ g_clear_object(&client_proxy);
+ cleanup_dbus_test(&dt);
+}
+
+static void
+test_dbus_vnc_no_password(void)
+{
+ DbusTest dt = { 0 };
+ QemuVnc1Server *proxy = NULL;
+ g_autoptr(GError) err = NULL;
+ gboolean ret;
+
+ if (!setup_dbus_test(&dt)) {
+ goto cleanup;
+ }
+
+ proxy = create_server_proxy(dt.bus_conn, &err);
+ g_assert_no_error(err);
+
+ /*
+ * With default auth=none, SetPassword should return an error
+ * because VNC password authentication is not enabled.
+ */
+ ret = qemu_vnc1_server_call_set_password_sync(
+ proxy, "secret",
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ g_assert_false(ret);
+ g_assert_error(err, G_DBUS_ERROR, G_DBUS_ERROR_FAILED);
+ g_clear_error(&err);
+
+ ret = qemu_vnc1_server_call_expire_password_sync(
+ proxy, "never",
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ g_assert_no_error(err);
+ g_assert_true(ret);
+
+ ret = qemu_vnc1_server_call_expire_password_sync(
+ proxy, "+3600",
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ g_assert_no_error(err);
+ g_assert_true(ret);
+
+cleanup:
+ g_clear_object(&proxy);
+ cleanup_dbus_test(&dt);
+}
+
+typedef struct PasswordData {
+ DbusTest *dt;
+ VncConnection *conn;
+ const char *password;
+ gboolean auth_succeeded;
+ gboolean auth_failed;
+} PasswordData;
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+static void
+on_pw_vnc_auth_credential(VncConnection *conn, GValueArray *creds,
+ PasswordData *data)
+{
+ for (guint i = 0; i < creds->n_values; i++) {
+ int type = g_value_get_enum(g_value_array_get_nth(creds, i));
+
+ if (type == VNC_CONNECTION_CREDENTIAL_PASSWORD) {
+ vnc_connection_set_credential(conn, type, data->password);
+ }
+ }
+}
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+static void
+on_pw_vnc_initialized(VncConnection *conn, PasswordData *data)
+{
+ data->auth_succeeded = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+on_pw_vnc_auth_failure(VncConnection *conn, const char *msg,
+ PasswordData *data)
+{
+ data->auth_failed = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+on_pw_vnc_error(VncConnection *conn, const char *msg,
+ PasswordData *data)
+{
+ data->auth_failed = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+test_dbus_vnc_password_auth(void)
+{
+ DbusTest dt = { 0 };
+ QemuVnc1Server *proxy = NULL;
+ g_autoptr(GError) err = NULL;
+ PasswordData pdata = { 0 };
+ const char *extra_args[] = { "--password", NULL };
+ int vnc_fd;
+ guint timeout_id;
+ gboolean ret;
+
+ if (!setup_dbus_test_full(&dt, extra_args)) {
+ goto cleanup;
+ }
+
+ proxy = create_server_proxy(dt.bus_conn, &err);
+ g_assert_no_error(err);
+
+ g_assert_cmpstr(qemu_vnc1_server_get_auth(proxy), ==, "vnc");
+
+ ret = qemu_vnc1_server_call_set_password_sync(
+ proxy, "testpass123",
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ g_assert_no_error(err);
+ g_assert_true(ret);
+
+ vnc_fd = wait_for_vnc_socket(dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(vnc_fd >= 0);
+
+ pdata.dt = &dt;
+ pdata.password = "testpass123";
+ pdata.conn = vnc_connection_new();
+
+ g_signal_connect(pdata.conn, "vnc-error",
+ G_CALLBACK(on_pw_vnc_error), &pdata);
+ g_signal_connect(pdata.conn, "vnc-auth-failure",
+ G_CALLBACK(on_pw_vnc_auth_failure), &pdata);
+ g_signal_connect(pdata.conn, "vnc-auth-credential",
+ G_CALLBACK(on_pw_vnc_auth_credential), &pdata);
+ g_signal_connect(pdata.conn, "vnc-initialized",
+ G_CALLBACK(on_pw_vnc_initialized), &pdata);
+ vnc_connection_set_auth_type(pdata.conn, VNC_CONNECTION_AUTH_VNC);
+ vnc_connection_open_fd(pdata.conn, vnc_fd);
+
+ dt.loop = g_main_loop_new(NULL, FALSE);
+ timeout_id = g_timeout_add_seconds(10, timeout_cb, NULL);
+ g_main_loop_run(dt.loop);
+ g_source_remove(timeout_id);
+
+ g_assert_true(pdata.auth_succeeded);
+ g_assert_false(pdata.auth_failed);
+
+ vnc_connection_shutdown(pdata.conn);
+ g_object_unref(pdata.conn);
+ g_main_loop_unref(dt.loop);
+ dt.loop = NULL;
+
+cleanup:
+ g_clear_object(&proxy);
+ cleanup_dbus_test(&dt);
+}
+
+static void
+test_dbus_vnc_sasl_authz_no_sasl(void)
+{
+ const char *binary;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GSubprocess) proc = NULL;
+ gboolean ok;
+
+ binary = g_getenv("QTEST_QEMU_VNC_BINARY");
+ if (!binary) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return;
+ }
+
+ proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDERR_SILENCE,
+ &err,
+ binary,
+ "--sasl-authz", "authz0",
+ NULL);
+ g_assert_no_error(err);
+ g_assert_nonnull(proc);
+
+ ok = g_subprocess_wait(proc, NULL, &err);
+ g_assert_no_error(err);
+ g_assert_true(ok);
+ g_assert_false(g_subprocess_get_successful(proc));
+}
+
+#ifdef CONFIG_VNC_SASL
+static void
+test_dbus_vnc_sasl_server_props(void)
+{
+ DbusTest dt = { 0 };
+ QemuVnc1Server *proxy = NULL;
+ g_autoptr(GError) err = NULL;
+ const char *extra_args[] = { "--sasl", NULL };
+
+ if (!setup_dbus_test_full(&dt, extra_args)) {
+ goto cleanup;
+ }
+
+ proxy = create_server_proxy(dt.bus_conn, &err);
+ g_assert_no_error(err);
+ g_assert_nonnull(proxy);
+
+ g_assert_cmpstr(qemu_vnc1_server_get_auth(proxy), ==, "sasl");
+
+cleanup:
+ g_clear_object(&proxy);
+ cleanup_dbus_test(&dt);
+}
+
+#define SASL_TEST_USER "testuser"
+#define SASL_TEST_PASS "testpass123"
+
+typedef struct SaslAuthData {
+ DbusTest *dt;
+ const char *username;
+ const char *password;
+ gboolean auth_succeeded;
+ gboolean auth_failed;
+} SaslAuthData;
+
+typedef struct SaslTestData {
+ DbusTest dt;
+ SaslAuthData sdata;
+ char *sasl_dir;
+ char *db_path;
+} SaslTestData;
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+static void
+on_sasl_vnc_auth_credential(VncConnection *conn, GValueArray *creds,
+ SaslAuthData *data)
+{
+ for (guint i = 0; i < creds->n_values; i++) {
+ int type = g_value_get_enum(g_value_array_get_nth(creds, i));
+
+ switch (type) {
+ case VNC_CONNECTION_CREDENTIAL_USERNAME:
+ vnc_connection_set_credential(conn, type, data->username);
+ break;
+ case VNC_CONNECTION_CREDENTIAL_PASSWORD:
+ vnc_connection_set_credential(conn, type, data->password);
+ break;
+ }
+ }
+}
+G_GNUC_END_IGNORE_DEPRECATIONS
+
+static void
+on_sasl_vnc_initialized(VncConnection *conn, SaslAuthData *data)
+{
+ data->auth_succeeded = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+on_sasl_vnc_auth_failure(VncConnection *conn, const char *msg,
+ SaslAuthData *data)
+{
+ data->auth_failed = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+static void
+on_sasl_vnc_error(VncConnection *conn, const char *msg,
+ SaslAuthData *data)
+{
+ data->auth_failed = TRUE;
+ g_main_loop_quit(data->dt->loop);
+}
+
+/*
+ * Create a SASL configuration directory with a qemu.conf and a
+ * sasldb2 user database. Returns the path to the sasldb file,
+ * or NULL if saslpasswd2 is not available.
+ */
+static char *
+create_sasl_config(const char *dir, const char *username,
+ const char *password)
+{
+ g_autofree char *conf_path = g_strdup_printf("%s/qemu.conf", dir);
+ g_autofree char *db_path = g_strdup_printf("%s/sasldb2", dir);
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GSubprocess) proc = NULL;
+ g_autofree char *conf = NULL;
+ GOutputStream *stdin_stream;
+ gboolean ok;
+
+ /* use PLAIN, and local auxprop sasldb plugin */
+ conf = g_strdup_printf(
+ "mech_list: plain\n"
+ "pwcheck_method: auxprop\n"
+ "auxprop_plugin: sasldb\n"
+ "sasldb_path: %s\n", db_path);
+ g_assert_true(g_file_set_contents(conf_path, conf, -1, NULL));
+
+ proc = g_subprocess_new(
+ G_SUBPROCESS_FLAGS_STDIN_PIPE |
+ G_SUBPROCESS_FLAGS_STDOUT_SILENCE |
+ G_SUBPROCESS_FLAGS_STDERR_SILENCE,
+ &err,
+ "saslpasswd2", "-f", db_path, "-a", "qemu", "-p", "-c",
+ username, NULL);
+ if (!proc) {
+ return NULL;
+ }
+
+ stdin_stream = g_subprocess_get_stdin_pipe(proc);
+ g_output_stream_write_all(stdin_stream, password,
+ strlen(password), NULL, NULL, NULL);
+ g_output_stream_close(stdin_stream, NULL, NULL);
+
+ ok = g_subprocess_wait_check(proc, NULL, &err);
+ if (!ok) {
+ return NULL;
+ }
+
+ return g_strdup(db_path);
+}
+
+static void
+cleanup_sasl_config(const char *dir, const char *db_path)
+{
+ g_autofree char *conf = g_strdup_printf("%s/qemu.conf", dir);
+
+ unlink(conf);
+ if (db_path) {
+ unlink(db_path);
+ }
+ rmdir(dir);
+}
+
+/*
+ * Set up SASL environment: create temp config dir, sasldb, and
+ * start qemu-vnc with the given extra_args. Returns FALSE if the
+ * test should be skipped.
+ */
+static gboolean
+setup_sasl_test(SaslTestData *st, const char **extra_args)
+{
+ if (!g_getenv("QTEST_QEMU_VNC_BINARY")) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return FALSE;
+ }
+
+ st->sasl_dir = g_dir_make_tmp("dbus-vnc-sasl-XXXXXX", NULL);
+ g_assert_nonnull(st->sasl_dir);
+
+ st->db_path = create_sasl_config(st->sasl_dir, SASL_TEST_USER,
+ SASL_TEST_PASS);
+ if (!st->db_path) {
+ g_test_skip("saslpasswd2 not available or failed");
+ cleanup_sasl_config(st->sasl_dir, NULL);
+ return FALSE;
+ }
+
+ g_setenv("SASL_CONF_PATH", st->sasl_dir, TRUE);
+
+ if (!setup_dbus_test_full(&st->dt, extra_args)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Connect to the VNC server using SASL and run the main loop
+ * until authentication completes or times out.
+ */
+static void
+run_sasl_auth(SaslTestData *st, const char *username,
+ const char *password)
+{
+ VncConnection *conn;
+ guint timeout_id;
+ int vnc_fd;
+
+ st->sdata.dt = &st->dt;
+ st->sdata.username = username;
+ st->sdata.password = password;
+
+ vnc_fd = wait_for_vnc_socket(st->dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(vnc_fd >= 0);
+
+ conn = vnc_connection_new();
+ g_signal_connect(conn, "vnc-error",
+ G_CALLBACK(on_sasl_vnc_error), &st->sdata);
+ g_signal_connect(conn, "vnc-auth-failure",
+ G_CALLBACK(on_sasl_vnc_auth_failure), &st->sdata);
+ g_signal_connect(conn, "vnc-auth-credential",
+ G_CALLBACK(on_sasl_vnc_auth_credential),
+ &st->sdata);
+ g_signal_connect(conn, "vnc-initialized",
+ G_CALLBACK(on_sasl_vnc_initialized), &st->sdata);
+ vnc_connection_set_auth_type(conn, VNC_CONNECTION_AUTH_SASL);
+ vnc_connection_open_fd(conn, vnc_fd);
+
+ st->dt.loop = g_main_loop_new(NULL, FALSE);
+ timeout_id = g_timeout_add_seconds(10, timeout_cb, NULL);
+ g_main_loop_run(st->dt.loop);
+ g_source_remove(timeout_id);
+
+ g_signal_handlers_disconnect_by_data(conn, &st->sdata);
+ vnc_connection_shutdown(conn);
+ g_object_unref(conn);
+ g_main_loop_unref(st->dt.loop);
+ st->dt.loop = NULL;
+}
+
+static void
+cleanup_sasl_test(SaslTestData *st)
+{
+ cleanup_dbus_test(&st->dt);
+ g_unsetenv("SASL_CONF_PATH");
+ cleanup_sasl_config(st->sasl_dir, st->db_path);
+ g_free(st->sasl_dir);
+ g_free(st->db_path);
+}
+
+static void
+test_dbus_vnc_sasl_auth(void)
+{
+ SaslTestData st = { 0 };
+ const char *extra_args[] = { "--sasl", NULL };
+
+ if (!setup_sasl_test(&st, extra_args)) {
+ return;
+ }
+
+ run_sasl_auth(&st, SASL_TEST_USER, SASL_TEST_PASS);
+
+ g_assert_true(st.sdata.auth_succeeded);
+ g_assert_false(st.sdata.auth_failed);
+
+ cleanup_sasl_test(&st);
+}
+
+static void
+test_dbus_vnc_sasl_auth_bad_password(void)
+{
+ SaslTestData st = { 0 };
+ const char *extra_args[] = { "--sasl", NULL };
+
+ if (!setup_sasl_test(&st, extra_args)) {
+ return;
+ }
+
+ run_sasl_auth(&st, SASL_TEST_USER, "wrongpassword");
+
+ g_assert_false(st.sdata.auth_succeeded);
+ g_assert_true(st.sdata.auth_failed);
+
+ cleanup_sasl_test(&st);
+}
+
+static void
+test_dbus_vnc_sasl_authz_denied(void)
+{
+ SaslTestData st = { 0 };
+ const char *extra_args[] = {
+ "--sasl",
+ "--object",
+ "authz-simple,id=authz0,identity=otheruser",
+ "--sasl-authz", "authz0",
+ NULL
+ };
+
+ if (!setup_sasl_test(&st, extra_args)) {
+ return;
+ }
+
+ run_sasl_auth(&st, SASL_TEST_USER, SASL_TEST_PASS);
+
+ g_assert_false(st.sdata.auth_succeeded);
+ g_assert_true(st.sdata.auth_failed);
+
+ cleanup_sasl_test(&st);
+}
+#endif /* CONFIG_VNC_SASL */
+
+static void
+test_dbus_vnc_tls_authz_no_creds(void)
+{
+ const char *binary;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GSubprocess) proc = NULL;
+ gboolean ok;
+
+ binary = g_getenv("QTEST_QEMU_VNC_BINARY");
+ if (!binary) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return;
+ }
+
+ proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDERR_SILENCE,
+ &err,
+ binary,
+ "--tls-authz", "authz0",
+ NULL);
+ g_assert_no_error(err);
+ g_assert_nonnull(proc);
+
+ ok = g_subprocess_wait(proc, NULL, &err);
+ g_assert_no_error(err);
+ g_assert_true(ok);
+ g_assert_false(g_subprocess_get_successful(proc));
+}
+
+#ifdef CONFIG_TASN1
+#define CLIENT_CERT_CN "qemu-vnc-test"
+
+static char *
+create_tls_certs(const char *dir)
+{
+ char *keyfile = g_strdup_printf("%s/key.pem", dir);
+ char *cacert = g_strdup_printf("%s/ca-cert.pem", dir);
+ char *servercert = g_strdup_printf("%s/server-cert.pem", dir);
+ char *serverkey = g_strdup_printf("%s/server-key.pem", dir);
+ char *clientcert = g_strdup_printf("%s/client-cert.pem", dir);
+
+ test_tls_init(keyfile);
+ g_assert(link(keyfile, serverkey) == 0);
+
+ TLS_ROOT_REQ_SIMPLE(cacertreq, cacert);
+ TLS_CERT_REQ_SIMPLE_SERVER(servercertreq, cacertreq,
+ servercert, "localhost", NULL);
+ TLS_CERT_REQ_SIMPLE_CLIENT(clientcertreq, cacertreq,
+ CLIENT_CERT_CN, clientcert);
+
+ test_tls_deinit_cert(&clientcertreq);
+ test_tls_deinit_cert(&servercertreq);
+ test_tls_deinit_cert(&cacertreq);
+
+ g_free(cacert);
+ g_free(servercert);
+ g_free(serverkey);
+ g_free(clientcert);
+ return keyfile;
+}
+
+static void
+cleanup_tls_certs(const char *dir, const char *keyfile)
+{
+ g_autofree char *cacert = g_strdup_printf("%s/ca-cert.pem", dir);
+ g_autofree char *servercert = g_strdup_printf("%s/server-cert.pem", dir);
+ g_autofree char *serverkey = g_strdup_printf("%s/server-key.pem", dir);
+ g_autofree char *clientcert = g_strdup_printf("%s/client-cert.pem", dir);
+
+ unlink(cacert);
+ unlink(servercert);
+ unlink(serverkey);
+ unlink(clientcert);
+ unlink(keyfile);
+ test_tls_cleanup(keyfile);
+ rmdir(dir);
+}
+
+/*
+ * Do a minimal VNC/VeNCrypt negotiation on @fd up to the point where
+ * the TLS handshake should begin, then perform a GnuTLS handshake
+ * using the given credentials.
+ */
+static bool
+try_raw_tls_connect(int fd, gnutls_certificate_credentials_t cred)
+{
+ char buf[13];
+ uint8_t num_types, type;
+ uint8_t vencrypt_ver[2], ack;
+ uint8_t num_sub;
+ uint32_t subtype;
+ gnutls_session_t session;
+ int ret;
+ bool success;
+
+ /* RFB version exchange */
+ g_assert_cmpint(read(fd, buf, 12), ==, 12);
+ g_assert_cmpint(write(fd, "RFB 003.008\n", 12), ==, 12);
+
+ /* Select VeNCrypt (type 19) from the auth list */
+ g_assert_cmpint(read(fd, &num_types, 1), ==, 1);
+ for (int i = 0; i < num_types; i++) {
+ g_assert_cmpint(read(fd, &type, 1), ==, 1);
+ }
+ type = 19;
+ g_assert_cmpint(write(fd, &type, 1), ==, 1);
+
+ /* VeNCrypt version exchange */
+ g_assert_cmpint(read(fd, vencrypt_ver, 2), ==, 2);
+ g_assert_cmpint(write(fd, vencrypt_ver, 2), ==, 2);
+ g_assert_cmpint(read(fd, &ack, 1), ==, 1);
+ g_assert_cmpint(ack, ==, 0);
+
+ /* Select x509-none (260) sub-auth */
+ g_assert_cmpint(read(fd, &num_sub, 1), ==, 1);
+ for (int i = 0; i < num_sub; i++) {
+ g_assert_cmpint(read(fd, &subtype, 4), ==, 4);
+ }
+ subtype = htonl(260);
+ g_assert_cmpint(write(fd, &subtype, 4), ==, 4);
+
+ /* Server sends 1-byte ack (1 = accepted) before TLS starts */
+ g_assert_cmpint(read(fd, &ack, 1), ==, 1);
+ g_assert_cmpint(ack, ==, 1);
+
+ /* TLS handshake */
+ g_assert_cmpint(gnutls_init(&session, GNUTLS_CLIENT), >=, 0);
+ g_assert_cmpint(
+ gnutls_set_default_priority(session), >=, 0);
+ g_assert_cmpint(
+ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred),
+ >=, 0);
+ gnutls_transport_set_int(session, fd);
+
+ do {
+ ret = gnutls_handshake(session);
+ } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+
+ if (ret < 0) {
+ success = false;
+ } else {
+ /*
+ * Try reading the VNC security-result (4 bytes) — if the
+ * server rejected us it will have closed the connection.
+ */
+ char tmp[4];
+ do {
+ ret = gnutls_record_recv(session, tmp, sizeof(tmp));
+ } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED);
+ success = (ret > 0);
+ }
+
+ gnutls_deinit(session);
+ return success;
+}
+
+static void
+test_dbus_vnc_tls_server_props(void)
+{
+ DbusTest dt = { 0 };
+ QemuVnc1Server *proxy = NULL;
+ g_autoptr(GError) err = NULL;
+ g_autofree char *tls_dir = NULL;
+ g_autofree char *keyfile = NULL;
+
+ if (!g_getenv("QTEST_QEMU_VNC_BINARY")) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return;
+ }
+
+ tls_dir = g_dir_make_tmp("dbus-vnc-tls-XXXXXX", NULL);
+ g_assert_nonnull(tls_dir);
+ keyfile = create_tls_certs(tls_dir);
+
+ {
+ const char *extra_args[] = {
+ "--tls-creds", tls_dir, NULL
+ };
+ if (!setup_dbus_test_full(&dt, extra_args)) {
+ goto cleanup;
+ }
+ }
+
+ proxy = create_server_proxy(dt.bus_conn, &err);
+ g_assert_no_error(err);
+ g_assert_nonnull(proxy);
+
+ g_assert_cmpstr(qemu_vnc1_server_get_auth(proxy), ==, "vencrypt");
+ g_assert_cmpstr(qemu_vnc1_server_get_vencrypt_sub_auth(proxy), ==,
+ "x509-none");
+
+ /*
+ * With verify-peer=no, a client without a certificate should
+ * be able to connect successfully through TLS.
+ */
+ {
+ g_autofree char *ca_path =
+ g_strdup_printf("%s/ca-cert.pem", tls_dir);
+ gnutls_certificate_credentials_t cred;
+ int fd;
+
+ g_assert_cmpint(
+ gnutls_certificate_allocate_credentials(&cred), >=, 0);
+ g_assert_cmpint(
+ gnutls_certificate_set_x509_trust_file(
+ cred, ca_path, GNUTLS_X509_FMT_PEM), >=, 0);
+
+ fd = wait_for_vnc_socket(dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(fd >= 0);
+ g_assert_true(try_raw_tls_connect(fd, cred));
+ close(fd);
+
+ gnutls_certificate_free_credentials(cred);
+ }
+
+cleanup:
+ g_clear_object(&proxy);
+ cleanup_dbus_test(&dt);
+ cleanup_tls_certs(tls_dir, keyfile);
+}
+
+static void
+test_dbus_vnc_tls_authz(void)
+{
+ DbusTest dt = { 0 };
+ g_autofree char *tls_dir = NULL;
+ g_autofree char *keyfile = NULL;
+ g_autofree char *ca_path = NULL;
+
+ if (!g_getenv("QTEST_QEMU_VNC_BINARY")) {
+ g_test_skip("QTEST_QEMU_VNC_BINARY not set");
+ return;
+ }
+
+ tls_dir = g_dir_make_tmp("dbus-vnc-tls-XXXXXX", NULL);
+ g_assert_nonnull(tls_dir);
+ keyfile = create_tls_certs(tls_dir);
+
+ /*
+ * The client cert has CN=qemu-vnc-test, so the DN string
+ * reported by GnuTLS is "CN=qemu-vnc-test". Configure
+ * authz-simple to accept exactly that identity.
+ */
+ {
+ g_autofree char *identity =
+ g_strdup_printf("CN=%s", CLIENT_CERT_CN);
+ const char *extra_args[] = {
+ "--tls-creds", tls_dir,
+ "--object",
+ NULL, /* filled below */
+ "--tls-authz", "authz0",
+ NULL
+ };
+ g_autofree char *object_arg =
+ g_strdup_printf("authz-simple,id=authz0,identity=%s", identity);
+ extra_args[3] = object_arg;
+
+ if (!setup_dbus_test_full(&dt, extra_args)) {
+ goto cleanup;
+ }
+ }
+
+ ca_path = g_strdup_printf("%s/ca-cert.pem", tls_dir);
+
+ /*
+ * Connect without a client certificate.
+ * With verify-peer=yes the TLS handshake must fail.
+ */
+ {
+ gnutls_certificate_credentials_t cred;
+ int fd;
+
+ g_assert_cmpint(
+ gnutls_certificate_allocate_credentials(&cred), >=, 0);
+ g_assert_cmpint(
+ gnutls_certificate_set_x509_trust_file(
+ cred, ca_path, GNUTLS_X509_FMT_PEM), >=, 0);
+
+ fd = wait_for_vnc_socket(dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(fd >= 0);
+ g_assert_false(try_raw_tls_connect(fd, cred));
+ close(fd);
+
+ gnutls_certificate_free_credentials(cred);
+ }
+
+ /*
+ * Connect with a valid client certificate whose DN
+ * matches the authz-simple identity. This must succeed.
+ */
+ {
+ g_autofree char *cert_path =
+ g_strdup_printf("%s/client-cert.pem", tls_dir);
+ g_autofree char *key_path =
+ g_strdup_printf("%s/key.pem", tls_dir);
+ gnutls_certificate_credentials_t cred;
+ int fd;
+
+ g_assert_cmpint(
+ gnutls_certificate_allocate_credentials(&cred), >=, 0);
+ g_assert_cmpint(
+ gnutls_certificate_set_x509_trust_file(
+ cred, ca_path, GNUTLS_X509_FMT_PEM), >=, 0);
+ g_assert_cmpint(
+ gnutls_certificate_set_x509_key_file(
+ cred, cert_path, key_path, GNUTLS_X509_FMT_PEM), >=, 0);
+
+ fd = wait_for_vnc_socket(dt.vnc_sock_path, VNC_TEST_TIMEOUT_MS);
+ g_assert(fd >= 0);
+ g_assert_true(try_raw_tls_connect(fd, cred));
+ close(fd);
+
+ gnutls_certificate_free_credentials(cred);
+ }
+
+cleanup:
+ cleanup_dbus_test(&dt);
+ cleanup_tls_certs(tls_dir, keyfile);
+}
+#endif /* CONFIG_TASN1 */
+
+int
+main(int argc, char **argv)
+{
+ g_log_set_always_fatal(G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL);
+
+ if (getenv("GTK_VNC_DEBUG")) {
+ vnc_util_set_debug(true);
+ }
+
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/dbus-vnc/basic", test_dbus_vnc_basic);
+ qtest_add_func("/dbus-vnc/server-props", test_dbus_vnc_server_props);
+ qtest_add_func("/dbus-vnc/client-lifecycle", test_dbus_vnc_client_lifecycle);
+ qtest_add_func("/dbus-vnc/no-password", test_dbus_vnc_no_password);
+ qtest_add_func("/dbus-vnc/password-auth", test_dbus_vnc_password_auth);
+ qtest_add_func("/dbus-vnc/sasl-authz-no-sasl",
+ test_dbus_vnc_sasl_authz_no_sasl);
+#ifdef CONFIG_VNC_SASL
+ qtest_add_func("/dbus-vnc/sasl-server-props",
+ test_dbus_vnc_sasl_server_props);
+ qtest_add_func("/dbus-vnc/sasl-auth",
+ test_dbus_vnc_sasl_auth);
+ qtest_add_func("/dbus-vnc/sasl-auth-bad-password",
+ test_dbus_vnc_sasl_auth_bad_password);
+ qtest_add_func("/dbus-vnc/sasl-authz-denied",
+ test_dbus_vnc_sasl_authz_denied);
+#endif
+ qtest_add_func("/dbus-vnc/tls-authz-no-creds",
+ test_dbus_vnc_tls_authz_no_creds);
+#ifdef CONFIG_TASN1
+ qtest_add_func("/dbus-vnc/tls-server-props",
+ test_dbus_vnc_tls_server_props);
+ qtest_add_func("/dbus-vnc/tls-authz",
+ test_dbus_vnc_tls_authz);
+#endif
+
+ return g_test_run();
+}
diff --git a/tools/qemu-vnc/audio.c b/tools/qemu-vnc/audio.c
new file mode 100644
index 00000000000..b55b04bc92a
--- /dev/null
+++ b/tools/qemu-vnc/audio.c
@@ -0,0 +1,307 @@
+/*
+ * Standalone VNC server connecting to QEMU via D-Bus display interface.
+ * Audio support. Only one audio stream is tracked. Mixing/resampling could be added.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/audio.h"
+#include "qemu/audio-capture.h"
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "ui/dbus-display1.h"
+#include "trace.h"
+#include "qemu-vnc.h"
+
+struct CaptureVoiceOut {
+ struct audsettings as;
+ struct audio_capture_ops ops;
+ void *opaque;
+ QLIST_ENTRY(CaptureVoiceOut) entries;
+};
+
+typedef struct AudioOut {
+ guint64 id;
+ struct audsettings as;
+} AudioOut;
+
+static QLIST_HEAD(, CaptureVoiceOut) capture_list =
+ QLIST_HEAD_INITIALIZER(capture_list);
+static GDBusConnection *audio_listener_conn;
+static AudioOut audio_out;
+
+static bool audsettings_eq(const struct audsettings *a,
+ const struct audsettings *b)
+{
+ return a->freq == b->freq &&
+ a->nchannels == b->nchannels &&
+ a->fmt == b->fmt &&
+ a->big_endian == b->big_endian;
+}
+
+static gboolean
+on_audio_out_init(QemuDBusDisplay1AudioOutListener *listener,
+ GDBusMethodInvocation *invocation,
+ guint64 id, guchar bits, gboolean is_signed,
+ gboolean is_float, guint freq, guchar nchannels,
+ guint bytes_per_frame, guint bytes_per_second,
+ gboolean be, gpointer user_data)
+{
+ AudioFormat fmt;
+
+ switch (bits) {
+ case 8:
+ fmt = is_signed ? AUDIO_FORMAT_S8 : AUDIO_FORMAT_U8;
+ break;
+ case 16:
+ fmt = is_signed ? AUDIO_FORMAT_S16 : AUDIO_FORMAT_U16;
+ break;
+ case 32:
+ fmt = is_float ? AUDIO_FORMAT_F32 :
+ is_signed ? AUDIO_FORMAT_S32 : AUDIO_FORMAT_U32;
+ break;
+ default:
+ g_return_val_if_reached(DBUS_METHOD_INVOCATION_HANDLED);
+ }
+
+ struct audsettings as = {
+ .freq = freq,
+ .nchannels = nchannels,
+ .fmt = fmt,
+ .big_endian = be,
+ };
+ audio_out = (AudioOut) {
+ .id = id,
+ .as = as,
+ };
+
+ trace_qemu_vnc_audio_out_init(id, freq, nchannels, bits);
+
+ qemu_dbus_display1_audio_out_listener_complete_init(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_audio_out_fini(QemuDBusDisplay1AudioOutListener *listener,
+ GDBusMethodInvocation *invocation,
+ guint64 id, gpointer user_data)
+{
+ trace_qemu_vnc_audio_out_fini(id);
+
+ qemu_dbus_display1_audio_out_listener_complete_fini(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_audio_out_set_enabled(QemuDBusDisplay1AudioOutListener *listener,
+ GDBusMethodInvocation *invocation,
+ guint64 id, gboolean enabled,
+ gpointer user_data)
+{
+ CaptureVoiceOut *cap;
+
+ trace_qemu_vnc_audio_out_set_enabled(id, enabled);
+
+ if (id == audio_out.id) {
+ QLIST_FOREACH(cap, &capture_list, entries) {
+ cap->ops.notify(cap->opaque,
+ enabled ? AUD_CNOTIFY_ENABLE
+ : AUD_CNOTIFY_DISABLE);
+ }
+ }
+
+ qemu_dbus_display1_audio_out_listener_complete_set_enabled(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_audio_out_set_volume(QemuDBusDisplay1AudioOutListener *listener,
+ GDBusMethodInvocation *invocation,
+ guint64 id, gboolean mute,
+ GVariant *volume, gpointer user_data)
+{
+ qemu_dbus_display1_audio_out_listener_complete_set_volume(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_audio_out_write(QemuDBusDisplay1AudioOutListener *listener,
+ GDBusMethodInvocation *invocation,
+ guint64 id, GVariant *data,
+ gpointer user_data)
+{
+ CaptureVoiceOut *cap;
+ gsize size;
+ const void *buf;
+
+ if (id == audio_out.id) {
+ buf = g_variant_get_fixed_array(data, &size, 1);
+
+ trace_qemu_vnc_audio_out_write(id, size);
+
+ QLIST_FOREACH(cap, &capture_list, entries) {
+ /* we don't handle audio resampling/format conversion */
+ if (audsettings_eq(&cap->as, &audio_out.as)) {
+ cap->ops.capture(cap->opaque, buf, size);
+ }
+ }
+ }
+
+ qemu_dbus_display1_audio_out_listener_complete_write(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+CaptureVoiceOut *audio_be_add_capture(
+ AudioBackend *be,
+ const struct audsettings *as,
+ const struct audio_capture_ops *ops,
+ void *opaque)
+{
+ CaptureVoiceOut *cap;
+
+ if (!audio_listener_conn) {
+ return NULL;
+ }
+
+ cap = g_new0(CaptureVoiceOut, 1);
+ cap->ops = *ops;
+ cap->opaque = opaque;
+ cap->as = *as;
+ QLIST_INSERT_HEAD(&capture_list, cap, entries);
+
+ return cap;
+}
+
+void audio_be_del_capture(
+ AudioBackend *be,
+ CaptureVoiceOut *cap,
+ void *cb_opaque)
+{
+ if (!cap) {
+ return;
+ }
+
+ cap->ops.destroy(cap->opaque);
+ QLIST_REMOVE(cap, entries);
+ g_free(cap);
+}
+
+/*
+ * Dummy audio backend — the VNC server only needs a non-NULL pointer
+ * so that audio capture registration doesn't bail out. The pointer
+ * is never dereferenced by our code (audio_be_add_capture ignores it).
+ */
+static AudioBackend dummy_audio_be;
+
+AudioBackend *audio_get_default_audio_be(Error **errp)
+{
+ return &dummy_audio_be;
+}
+
+AudioBackend *audio_be_by_name(const char *name, Error **errp)
+{
+ return NULL;
+}
+
+static void
+on_register_audio_listener_finished(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GThread *thread = user_data;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GDBusObjectSkeleton) obj = NULL;
+ GDBusObjectManagerServer *server;
+ QemuDBusDisplay1AudioOutListener *audio_skel;
+
+ qemu_dbus_display1_audio_call_register_out_listener_finish(
+ QEMU_DBUS_DISPLAY1_AUDIO(source_object),
+ NULL, res, &err);
+
+ if (err) {
+ error_report("RegisterOutListener failed: %s", err->message);
+ g_thread_join(thread);
+ return;
+ }
+
+ audio_listener_conn = g_thread_join(thread);
+ if (!audio_listener_conn) {
+ return;
+ }
+
+ server = g_dbus_object_manager_server_new(DBUS_DISPLAY1_ROOT);
+ obj = g_dbus_object_skeleton_new(
+ DBUS_DISPLAY1_ROOT "/AudioOutListener");
+
+ audio_skel = qemu_dbus_display1_audio_out_listener_skeleton_new();
+ g_object_connect(audio_skel,
+ "signal::handle-init",
+ on_audio_out_init, NULL,
+ "signal::handle-fini",
+ on_audio_out_fini, NULL,
+ "signal::handle-set-enabled",
+ on_audio_out_set_enabled, NULL,
+ "signal::handle-set-volume",
+ on_audio_out_set_volume, NULL,
+ "signal::handle-write",
+ on_audio_out_write, NULL,
+ NULL);
+ g_dbus_object_skeleton_add_interface(
+ obj, G_DBUS_INTERFACE_SKELETON(audio_skel));
+
+ g_dbus_object_manager_server_export(server, obj);
+ g_dbus_object_manager_server_set_connection(
+ server, audio_listener_conn);
+
+ g_dbus_connection_start_message_processing(audio_listener_conn);
+}
+
+void audio_setup(GDBusObjectManager *manager)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ g_autoptr(GDBusInterface) iface = NULL;
+ GThread *thread;
+ int pair[2];
+ int idx;
+
+ iface = g_dbus_object_manager_get_interface(
+ manager, DBUS_DISPLAY1_ROOT "/Audio",
+ "org.qemu.Display1.Audio");
+ if (!iface) {
+ return;
+ }
+
+ if (qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
+ error_report("audio socketpair failed: %s", strerror(errno));
+ return;
+ }
+
+ fd_list = g_unix_fd_list_new();
+ idx = g_unix_fd_list_append(fd_list, pair[1], &err);
+ close(pair[1]);
+ if (idx < 0) {
+ close(pair[0]);
+ error_report("Failed to append fd: %s", err->message);
+ return;
+ }
+
+ thread = p2p_dbus_thread_new(pair[0]);
+
+ qemu_dbus_display1_audio_call_register_out_listener(
+ QEMU_DBUS_DISPLAY1_AUDIO(iface),
+ g_variant_new_handle(idx),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ fd_list, NULL,
+ on_register_audio_listener_finished,
+ thread);
+}
diff --git a/tools/qemu-vnc/chardev.c b/tools/qemu-vnc/chardev.c
new file mode 100644
index 00000000000..d9d51973724
--- /dev/null
+++ b/tools/qemu-vnc/chardev.c
@@ -0,0 +1,127 @@
+/*
+ * Standalone VNC server connecting to QEMU via D-Bus display interface.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "ui/dbus-display1.h"
+#include "trace.h"
+#include "qemu-vnc.h"
+
+typedef struct ChardevRegisterData {
+ QemuDBusDisplay1Chardev *proxy;
+ int local_fd;
+ char *name;
+ bool echo;
+} ChardevRegisterData;
+
+static void
+on_chardev_register_finished(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ChardevRegisterData *data = user_data;
+ g_autoptr(GError) err = NULL;
+ QemuTextConsole *tc;
+
+ if (!qemu_dbus_display1_chardev_call_register_finish(
+ data->proxy, NULL, res, &err)) {
+ error_report("Chardev Register failed for %s: %s",
+ data->name, err->message);
+ close(data->local_fd);
+ goto out;
+ }
+
+ tc = qemu_vnc_text_console_new(data->name, data->local_fd, data->echo);
+ if (!tc) {
+ close(data->local_fd);
+ goto out;
+ }
+
+ trace_qemu_vnc_chardev_connected(data->name);
+
+out:
+ g_object_unref(data->proxy);
+ g_free(data->name);
+ g_free(data);
+}
+
+/* Default chardevs to expose as VNC text consoles */
+static const char * const default_names[] = {
+ "org.qemu.console.serial.0",
+ "org.qemu.monitor.hmp.0",
+ NULL,
+};
+
+/* Active chardev names list (points to CLI args or default_names) */
+static const char * const *names;
+
+static void
+chardev_register(QemuDBusDisplay1Chardev *proxy)
+{
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ ChardevRegisterData *data;
+ const char *name;
+ int pair[2];
+ int idx;
+
+ name = qemu_dbus_display1_chardev_get_name(proxy);
+ if (!name || !g_strv_contains(names, name)) {
+ return;
+ }
+
+ if (qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
+ error_report("chardev socketpair failed: %s", strerror(errno));
+ return;
+ }
+
+ fd_list = g_unix_fd_list_new();
+ idx = g_unix_fd_list_append(fd_list, pair[1], NULL);
+ close(pair[1]);
+
+ data = g_new0(ChardevRegisterData, 1);
+ data->proxy = g_object_ref(proxy);
+ data->local_fd = pair[0];
+ data->name = g_strdup(name);
+ data->echo = qemu_dbus_display1_chardev_get_echo(proxy);
+
+ qemu_dbus_display1_chardev_call_register(
+ proxy, g_variant_new_handle(idx),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ fd_list, NULL,
+ on_chardev_register_finished, data);
+}
+
+void chardev_setup(const char * const *chardev_names,
+ GDBusObjectManager *manager)
+{
+ GList *objects, *l;
+
+ names = chardev_names ? chardev_names : default_names;
+
+ objects = g_dbus_object_manager_get_objects(manager);
+ for (l = objects; l; l = l->next) {
+ GDBusObject *obj = l->data;
+ const char *path = g_dbus_object_get_object_path(obj);
+ g_autoptr(GDBusInterface) iface = NULL;
+
+ if (!g_str_has_prefix(path, DBUS_DISPLAY1_ROOT "/Chardev_")) {
+ continue;
+ }
+
+ iface = g_dbus_object_get_interface(
+ obj, "org.qemu.Display1.Chardev");
+ if (!iface) {
+ continue;
+ }
+
+ chardev_register(QEMU_DBUS_DISPLAY1_CHARDEV(iface));
+ }
+ g_list_free_full(objects, g_object_unref);
+}
diff --git a/tools/qemu-vnc/clipboard.c b/tools/qemu-vnc/clipboard.c
new file mode 100644
index 00000000000..d1673b97899
--- /dev/null
+++ b/tools/qemu-vnc/clipboard.c
@@ -0,0 +1,378 @@
+/*
+ * Standalone VNC server connecting to QEMU via D-Bus display interface.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/error-report.h"
+#include "ui/clipboard.h"
+#include "ui/dbus-display1.h"
+#include "trace.h"
+#include "qemu-vnc.h"
+
+#define MIME_TEXT_PLAIN_UTF8 "text/plain;charset=utf-8"
+
+typedef struct {
+ GDBusMethodInvocation *invocation;
+ QemuClipboardType type;
+ guint timeout_id;
+} VncDBusClipboardRequest;
+
+static QemuDBusDisplay1Clipboard *clipboard_proxy;
+static QemuDBusDisplay1Clipboard *clipboard_skel;
+static QemuClipboardPeer clipboard_peer;
+static uint32_t clipboard_serial;
+static VncDBusClipboardRequest
+ clipboard_request[QEMU_CLIPBOARD_SELECTION__COUNT];
+
+static void
+vnc_dbus_clipboard_complete_request(
+ GDBusMethodInvocation *invocation,
+ QemuClipboardInfo *info,
+ QemuClipboardType type)
+{
+ GVariant *v_data = g_variant_new_from_data(
+ G_VARIANT_TYPE("ay"),
+ info->types[type].data,
+ info->types[type].size,
+ TRUE,
+ (GDestroyNotify)qemu_clipboard_info_unref,
+ qemu_clipboard_info_ref(info));
+
+ qemu_dbus_display1_clipboard_complete_request(
+ clipboard_skel, invocation,
+ MIME_TEXT_PLAIN_UTF8, v_data);
+}
+
+static void
+vnc_dbus_clipboard_request_cancelled(VncDBusClipboardRequest *req)
+{
+ if (!req->invocation) {
+ return;
+ }
+
+ g_dbus_method_invocation_return_error(
+ req->invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Cancelled clipboard request");
+
+ g_clear_object(&req->invocation);
+ g_source_remove(req->timeout_id);
+ req->timeout_id = 0;
+}
+
+static gboolean
+vnc_dbus_clipboard_request_timeout(gpointer user_data)
+{
+ vnc_dbus_clipboard_request_cancelled(user_data);
+ return G_SOURCE_REMOVE;
+}
+
+static void
+vnc_dbus_clipboard_request(QemuClipboardInfo *info,
+ QemuClipboardType type)
+{
+ g_autofree char *mime = NULL;
+ g_autoptr(GVariant) v_data = NULL;
+ g_autoptr(GError) err = NULL;
+ const char *data = NULL;
+ const char *mimes[] = { MIME_TEXT_PLAIN_UTF8, NULL };
+ size_t n;
+
+ if (type != QEMU_CLIPBOARD_TYPE_TEXT) {
+ return;
+ }
+
+ if (!clipboard_proxy) {
+ return;
+ }
+
+ if (!qemu_dbus_display1_clipboard_call_request_sync(
+ clipboard_proxy,
+ info->selection,
+ mimes,
+ G_DBUS_CALL_FLAGS_NONE, -1, &mime, &v_data, NULL, &err)) {
+ error_report("Failed to request clipboard: %s", err->message);
+ return;
+ }
+
+ if (!g_str_equal(mime, MIME_TEXT_PLAIN_UTF8)) {
+ error_report("Unsupported returned MIME: %s", mime);
+ return;
+ }
+
+ data = g_variant_get_fixed_array(v_data, &n, 1);
+ qemu_clipboard_set_data(&clipboard_peer, info, type,
+ n, data, true);
+}
+
+static void
+vnc_dbus_clipboard_update_info(QemuClipboardInfo *info)
+{
+ bool self_update = info->owner == &clipboard_peer;
+ const char *mime[QEMU_CLIPBOARD_TYPE__COUNT + 1] = { 0, };
+ VncDBusClipboardRequest *req;
+ int i = 0;
+
+ if (info->owner == NULL) {
+ if (clipboard_proxy) {
+ qemu_dbus_display1_clipboard_call_release(
+ clipboard_proxy,
+ info->selection,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ }
+ return;
+ }
+
+ if (self_update) {
+ return;
+ }
+
+ req = &clipboard_request[info->selection];
+ if (req->invocation && info->types[req->type].data) {
+ vnc_dbus_clipboard_complete_request(
+ req->invocation, info, req->type);
+ g_clear_object(&req->invocation);
+ g_source_remove(req->timeout_id);
+ req->timeout_id = 0;
+ return;
+ }
+
+ if (info->types[QEMU_CLIPBOARD_TYPE_TEXT].available) {
+ mime[i++] = MIME_TEXT_PLAIN_UTF8;
+ }
+
+ if (i > 0 && clipboard_proxy) {
+ uint32_t serial = info->has_serial ?
+ info->serial : ++clipboard_serial;
+ qemu_dbus_display1_clipboard_call_grab(
+ clipboard_proxy,
+ info->selection,
+ serial,
+ mime,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ }
+}
+
+static void
+vnc_dbus_clipboard_notify(Notifier *notifier, void *data)
+{
+ QemuClipboardNotify *notify = data;
+
+ switch (notify->type) {
+ case QEMU_CLIPBOARD_UPDATE_INFO:
+ vnc_dbus_clipboard_update_info(notify->info);
+ return;
+ case QEMU_CLIPBOARD_RESET_SERIAL:
+ if (clipboard_proxy) {
+ qemu_dbus_display1_clipboard_call_register(
+ clipboard_proxy,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, NULL, NULL);
+ }
+ return;
+ }
+}
+
+static gboolean
+on_clipboard_register(QemuDBusDisplay1Clipboard *clipboard,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ clipboard_serial = 0;
+ qemu_clipboard_reset_serial();
+
+ qemu_dbus_display1_clipboard_complete_register(
+ clipboard, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_clipboard_unregister(QemuDBusDisplay1Clipboard *clipboard,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ int i;
+
+ for (i = 0; i < G_N_ELEMENTS(clipboard_request); ++i) {
+ vnc_dbus_clipboard_request_cancelled(&clipboard_request[i]);
+ }
+
+ qemu_dbus_display1_clipboard_complete_unregister(
+ clipboard, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_clipboard_grab(QemuDBusDisplay1Clipboard *clipboard,
+ GDBusMethodInvocation *invocation,
+ gint arg_selection,
+ guint arg_serial,
+ const gchar *const *arg_mimes,
+ gpointer user_data)
+{
+ QemuClipboardSelection s = arg_selection;
+ g_autoptr(QemuClipboardInfo) info = NULL;
+
+ if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Invalid clipboard selection: %d", arg_selection);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ trace_qemu_vnc_clipboard_grab(arg_selection, arg_serial);
+
+ info = qemu_clipboard_info_new(&clipboard_peer, s);
+ if (g_strv_contains(arg_mimes, MIME_TEXT_PLAIN_UTF8)) {
+ info->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
+ }
+ info->serial = arg_serial;
+ info->has_serial = true;
+ if (qemu_clipboard_check_serial(info, true)) {
+ qemu_clipboard_update(info);
+ }
+
+ qemu_dbus_display1_clipboard_complete_grab(
+ clipboard, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_clipboard_release(QemuDBusDisplay1Clipboard *clipboard,
+ GDBusMethodInvocation *invocation,
+ gint arg_selection,
+ gpointer user_data)
+{
+ trace_qemu_vnc_clipboard_release(arg_selection);
+
+ qemu_clipboard_peer_release(&clipboard_peer, arg_selection);
+
+ qemu_dbus_display1_clipboard_complete_release(
+ clipboard, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_clipboard_request(QemuDBusDisplay1Clipboard *clipboard,
+ GDBusMethodInvocation *invocation,
+ gint arg_selection,
+ const gchar *const *arg_mimes,
+ gpointer user_data)
+{
+ QemuClipboardSelection s = arg_selection;
+ QemuClipboardType type = QEMU_CLIPBOARD_TYPE_TEXT;
+ QemuClipboardInfo *info = NULL;
+
+ trace_qemu_vnc_clipboard_request(arg_selection);
+
+ if (s >= QEMU_CLIPBOARD_SELECTION__COUNT) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Invalid clipboard selection: %d", arg_selection);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ if (clipboard_request[s].invocation) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Pending request");
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ info = qemu_clipboard_info(s);
+ if (!info || !info->owner || info->owner == &clipboard_peer) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Empty clipboard");
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ if (!g_strv_contains(arg_mimes, MIME_TEXT_PLAIN_UTF8) ||
+ !info->types[type].available) {
+ g_dbus_method_invocation_return_error(
+ invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Unhandled MIME types requested");
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ if (info->types[type].data) {
+ vnc_dbus_clipboard_complete_request(invocation, info, type);
+ } else {
+ qemu_clipboard_request(info, type);
+
+ clipboard_request[s].invocation = g_object_ref(invocation);
+ clipboard_request[s].type = type;
+ clipboard_request[s].timeout_id =
+ g_timeout_add_seconds(5,
+ vnc_dbus_clipboard_request_timeout,
+ &clipboard_request[s]);
+ }
+
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+void clipboard_setup(GDBusObjectManager *manager, GDBusConnection *bus)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GDBusInterface) iface = NULL;
+
+ iface = g_dbus_object_manager_get_interface(
+ manager, DBUS_DISPLAY1_ROOT "/Clipboard",
+ "org.qemu.Display1.Clipboard");
+ if (!iface) {
+ return;
+ }
+
+ clipboard_proxy = g_object_ref(QEMU_DBUS_DISPLAY1_CLIPBOARD(iface));
+
+ clipboard_skel = qemu_dbus_display1_clipboard_skeleton_new();
+ g_object_connect(clipboard_skel,
+ "signal::handle-register",
+ on_clipboard_register, NULL,
+ "signal::handle-unregister",
+ on_clipboard_unregister, NULL,
+ "signal::handle-grab",
+ on_clipboard_grab, NULL,
+ "signal::handle-release",
+ on_clipboard_release, NULL,
+ "signal::handle-request",
+ on_clipboard_request, NULL,
+ NULL);
+
+ if (!g_dbus_interface_skeleton_export(
+ G_DBUS_INTERFACE_SKELETON(clipboard_skel),
+ bus,
+ DBUS_DISPLAY1_ROOT "/Clipboard",
+ &err)) {
+ error_report("Failed to export clipboard: %s", err->message);
+ g_clear_object(&clipboard_skel);
+ g_clear_object(&clipboard_proxy);
+ return;
+ }
+
+ clipboard_peer.name = "dbus";
+ clipboard_peer.notifier.notify = vnc_dbus_clipboard_notify;
+ clipboard_peer.request = vnc_dbus_clipboard_request;
+ qemu_clipboard_peer_register(&clipboard_peer);
+
+ qemu_dbus_display1_clipboard_call_register(
+ clipboard_proxy,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, NULL, NULL);
+}
diff --git a/tools/qemu-vnc/console.c b/tools/qemu-vnc/console.c
new file mode 100644
index 00000000000..076365adf77
--- /dev/null
+++ b/tools/qemu-vnc/console.c
@@ -0,0 +1,168 @@
+/*
+ * Minimal QemuConsole helpers for the standalone qemu-vnc binary.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "ui/console.h"
+#include "ui/console-priv.h"
+#include "ui/vt100.h"
+#include "qemu-vnc.h"
+#include "trace.h"
+
+/*
+ * Our own QemuTextConsole definition — the one in console-vc.c uses
+ * a Chardev* backend which is not available in the standalone binary.
+ * Here we drive the VT100 emulator directly over a raw file descriptor.
+ */
+typedef struct QemuTextConsole {
+ QemuConsole parent;
+ QemuVT100 vt;
+ int chardev_fd;
+ guint io_watch_id;
+ char *name;
+} QemuTextConsole;
+
+typedef QemuConsoleClass QemuTextConsoleClass;
+
+OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console,
+ QEMU_TEXT_CONSOLE, QEMU_CONSOLE)
+
+static void qemu_text_console_class_init(ObjectClass *oc, const void *data)
+{
+}
+
+static void text_console_invalidate(void *opaque)
+{
+ QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
+
+ vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
+ vt100_refresh(&s->vt);
+}
+
+static const GraphicHwOps text_console_ops = {
+ .invalidate = text_console_invalidate,
+};
+
+static void qemu_text_console_init(Object *obj)
+{
+ QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
+
+ QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
+ QEMU_CONSOLE(c)->hw = c;
+}
+
+static void qemu_text_console_finalize(Object *obj)
+{
+ QemuTextConsole *tc = QEMU_TEXT_CONSOLE(obj);
+
+ vt100_fini(&tc->vt);
+ if (tc->io_watch_id) {
+ g_source_remove(tc->io_watch_id);
+ }
+ if (tc->chardev_fd >= 0) {
+ close(tc->chardev_fd);
+ }
+ g_free(tc->name);
+}
+
+
+static void text_console_out_flush(QemuVT100 *vt)
+{
+ QemuTextConsole *tc = container_of(vt, QemuTextConsole, vt);
+ const uint8_t *data;
+ uint32_t len;
+
+ while (!fifo8_is_empty(&vt->out_fifo)) {
+ ssize_t ret;
+
+ data = fifo8_pop_bufptr(&vt->out_fifo,
+ fifo8_num_used(&vt->out_fifo), &len);
+ ret = write(tc->chardev_fd, data, len);
+ if (ret < 0) {
+ trace_qemu_vnc_console_io_error(tc->name);
+ break;
+ }
+ }
+}
+
+static void text_console_image_update(QemuVT100 *vt, int x, int y, int w, int h)
+{
+ QemuTextConsole *tc = container_of(vt, QemuTextConsole, vt);
+ QemuConsole *con = QEMU_CONSOLE(tc);
+
+ qemu_console_update(con, x, y, w, h);
+}
+
+static gboolean text_console_io_cb(GIOChannel *source,
+ GIOCondition cond, gpointer data)
+{
+ QemuTextConsole *tc = data;
+ uint8_t buf[4096];
+ ssize_t n;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ tc->io_watch_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ n = read(tc->chardev_fd, buf, sizeof(buf));
+ if (n <= 0) {
+ trace_qemu_vnc_console_io_error(tc->name);
+ tc->io_watch_id = 0;
+ return G_SOURCE_REMOVE;
+ }
+
+ vt100_input(&tc->vt, buf, n);
+ return G_SOURCE_CONTINUE;
+}
+
+QemuTextConsole *qemu_vnc_text_console_new(const char *name,
+ int fd, bool echo)
+{
+ int w = TEXT_COLS * TEXT_FONT_WIDTH;
+ int h = TEXT_ROWS * TEXT_FONT_HEIGHT;
+ QemuTextConsole *tc;
+ QemuConsole *con;
+ pixman_image_t *image;
+ GIOChannel *chan;
+
+ tc = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_TEXT_CONSOLE));
+ con = QEMU_CONSOLE(tc);
+
+ tc->name = g_strdup(name);
+ tc->chardev_fd = fd;
+
+ image = pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h, NULL, 0);
+ con->surface = qemu_create_displaysurface_pixman(image);
+ con->scanout.kind = SCANOUT_SURFACE;
+ qemu_pixman_image_unref(image);
+
+ vt100_init(&tc->vt, con->surface->image,
+ text_console_image_update, text_console_out_flush);
+ tc->vt.echo = echo;
+ vt100_refresh(&tc->vt);
+
+ chan = g_io_channel_unix_new(fd);
+ g_io_channel_set_encoding(chan, NULL, NULL);
+ tc->io_watch_id = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR,
+ text_console_io_cb, tc);
+ g_io_channel_unref(chan);
+
+ return tc;
+}
+
+void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
+{
+ vt100_keysym(&s->vt, keysym);
+}
+
+void qemu_text_console_update_size(QemuTextConsole *c)
+{
+ qemu_console_text_resize(QEMU_CONSOLE(c), c->vt.width, c->vt.height);
+}
diff --git a/tools/qemu-vnc/dbus.c b/tools/qemu-vnc/dbus.c
new file mode 100644
index 00000000000..0e5f52623ea
--- /dev/null
+++ b/tools/qemu-vnc/dbus.c
@@ -0,0 +1,439 @@
+/*
+ * D-Bus interface for qemu-vnc standalone VNC server.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/cutils.h"
+#include "qapi-types-trace.h"
+#include "system/system.h"
+#include "qapi/qapi-types-ui.h"
+#include "qapi/qapi-commands-ui.h"
+#include "qemu-vnc.h"
+#include "qemu-vnc1.h"
+#include "qapi/qapi-emit-events.h"
+#include "qobject/qdict.h"
+#include "ui/vnc.h"
+#include "trace.h"
+
+typedef struct VncDbusClient {
+ QemuVnc1ClientSkeleton *skeleton;
+ char *path;
+ char *host;
+ char *service;
+ unsigned int id;
+ QTAILQ_ENTRY(VncDbusClient) next;
+} VncDbusClient;
+
+static QemuVnc1ServerSkeleton *server_skeleton;
+static GDBusObjectManagerServer *obj_manager;
+static unsigned int next_client_id;
+
+static QTAILQ_HEAD(, VncDbusClient)
+ dbus_clients = QTAILQ_HEAD_INITIALIZER(dbus_clients);
+
+static VncDbusClient *vnc_dbus_find_client(const char *host,
+ const char *service)
+{
+ VncDbusClient *c;
+
+ QTAILQ_FOREACH(c, &dbus_clients, next) {
+ if (g_str_equal(c->host, host) &&
+ g_str_equal(c->service, service)) {
+ return c;
+ }
+ }
+ return NULL;
+}
+
+static void vnc_dbus_update_clients_property(void)
+{
+ VncDbusClient *c;
+ GPtrArray *paths;
+ const char **strv;
+
+ paths = g_ptr_array_new();
+ QTAILQ_FOREACH(c, &dbus_clients, next) {
+ g_ptr_array_add(paths, c->path);
+ }
+ g_ptr_array_add(paths, NULL);
+
+ strv = (const char **)paths->pdata;
+ qemu_vnc1_server_set_clients(QEMU_VNC1_SERVER(server_skeleton), strv);
+ g_ptr_array_free(paths, TRUE);
+}
+
+void vnc_dbus_client_connected(const char *host, const char *service,
+ const char *family, bool websocket)
+{
+ VncDbusClient *c;
+ g_autoptr(GDBusObjectSkeleton) obj = NULL;
+
+ if (!server_skeleton) {
+ return;
+ }
+
+ c = g_new0(VncDbusClient, 1);
+ c->id = next_client_id++;
+ c->host = g_strdup(host);
+ c->service = g_strdup(service);
+ c->path = g_strdup_printf("/org/qemu/Vnc1/Client_%u", c->id);
+
+ c->skeleton = QEMU_VNC1_CLIENT_SKELETON(qemu_vnc1_client_skeleton_new());
+ qemu_vnc1_client_set_host(QEMU_VNC1_CLIENT(c->skeleton), host);
+ qemu_vnc1_client_set_service(QEMU_VNC1_CLIENT(c->skeleton), service);
+ qemu_vnc1_client_set_family(QEMU_VNC1_CLIENT(c->skeleton), family);
+ qemu_vnc1_client_set_web_socket(QEMU_VNC1_CLIENT(c->skeleton), websocket);
+ qemu_vnc1_client_set_x509_dname(QEMU_VNC1_CLIENT(c->skeleton), "");
+ qemu_vnc1_client_set_sasl_username(QEMU_VNC1_CLIENT(c->skeleton), "");
+
+ obj = g_dbus_object_skeleton_new(c->path);
+ g_dbus_object_skeleton_add_interface(
+ obj, G_DBUS_INTERFACE_SKELETON(c->skeleton));
+ g_dbus_object_manager_server_export(obj_manager, obj);
+
+ QTAILQ_INSERT_TAIL(&dbus_clients, c, next);
+ vnc_dbus_update_clients_property();
+
+ qemu_vnc1_server_emit_client_connected(
+ QEMU_VNC1_SERVER(server_skeleton), c->path);
+}
+
+void vnc_dbus_client_initialized(const char *host, const char *service,
+ const char *x509_dname,
+ const char *sasl_username)
+{
+ VncDbusClient *c;
+
+ if (!server_skeleton) {
+ return;
+ }
+
+ c = vnc_dbus_find_client(host, service);
+ if (!c) {
+ trace_qemu_vnc_client_not_found(host, service);
+ return;
+ }
+
+ if (x509_dname) {
+ qemu_vnc1_client_set_x509_dname(
+ QEMU_VNC1_CLIENT(c->skeleton), x509_dname);
+ }
+ if (sasl_username) {
+ qemu_vnc1_client_set_sasl_username(
+ QEMU_VNC1_CLIENT(c->skeleton), sasl_username);
+ }
+
+ qemu_vnc1_server_emit_client_initialized(
+ QEMU_VNC1_SERVER(server_skeleton), c->path);
+}
+
+void vnc_dbus_client_disconnected(const char *host, const char *service)
+{
+ VncDbusClient *c;
+
+ if (!server_skeleton) {
+ return;
+ }
+
+ c = vnc_dbus_find_client(host, service);
+ if (!c) {
+ trace_qemu_vnc_client_not_found(host, service);
+ return;
+ }
+
+ qemu_vnc1_server_emit_client_disconnected(
+ QEMU_VNC1_SERVER(server_skeleton), c->path);
+
+ g_dbus_object_manager_server_unexport(obj_manager, c->path);
+ QTAILQ_REMOVE(&dbus_clients, c, next);
+ vnc_dbus_update_clients_property();
+
+ g_object_unref(c->skeleton);
+ g_free(c->path);
+ g_free(c->host);
+ g_free(c->service);
+ g_free(c);
+}
+
+static gboolean
+on_set_password(QemuVnc1Server *iface,
+ GDBusMethodInvocation *invocation,
+ const gchar *password,
+ gpointer user_data)
+{
+ Error *err = NULL;
+
+ if (vnc_display_password("default", password, &err) < 0) {
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "%s", error_get_pretty(err));
+ error_free(err);
+ return TRUE;
+ }
+
+ qemu_vnc1_server_complete_set_password(iface, invocation);
+ return TRUE;
+}
+
+static gboolean
+on_expire_password(QemuVnc1Server *iface,
+ GDBusMethodInvocation *invocation,
+ const gchar *time_str,
+ gpointer user_data)
+{
+ time_t when;
+
+ if (g_str_equal(time_str, "now")) {
+ when = 0;
+ } else if (g_str_equal(time_str, "never")) {
+ when = TIME_MAX;
+ } else if (time_str[0] == '+') {
+ int seconds;
+ if (qemu_strtoi(time_str + 1, NULL, 10, &seconds) < 0) {
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid time format: %s", time_str);
+ return TRUE;
+ }
+ when = time(NULL) + seconds;
+ } else {
+ int64_t epoch;
+ if (qemu_strtoi64(time_str, NULL, 10, &epoch) < 0) {
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Invalid time format: %s", time_str);
+ return TRUE;
+ }
+ when = epoch;
+ }
+
+ if (vnc_display_pw_expire("default", when) < 0) {
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Failed to set password expiry");
+ return TRUE;
+ }
+
+ qemu_vnc1_server_complete_expire_password(iface, invocation);
+ return TRUE;
+}
+
+static gboolean
+on_reload_certificates(QemuVnc1Server *iface,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ Error *err = NULL;
+
+ if (!vnc_display_reload_certs("default", &err)) {
+ g_dbus_method_invocation_return_error(
+ invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "%s", error_get_pretty(err));
+ error_free(err);
+ return TRUE;
+ }
+
+ qemu_vnc1_server_complete_reload_certificates(iface, invocation);
+ return TRUE;
+}
+
+static void vnc_dbus_add_listeners(VncInfo2 *info)
+{
+ GVariantBuilder builder;
+ VncServerInfo2List *entry;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}"));
+
+ for (entry = info->server; entry; entry = entry->next) {
+ VncServerInfo2 *s = entry->value;
+ const char *vencrypt_str = "";
+
+ if (s->has_vencrypt) {
+ vencrypt_str = VncVencryptSubAuth_str(s->vencrypt);
+ }
+
+ g_variant_builder_open(&builder, G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(&builder, "{sv}", "Host",
+ g_variant_new_string(s->host));
+ g_variant_builder_add(&builder, "{sv}", "Service",
+ g_variant_new_string(s->service));
+ g_variant_builder_add(&builder, "{sv}", "Family",
+ g_variant_new_string(
+ NetworkAddressFamily_str(s->family)));
+ g_variant_builder_add(&builder, "{sv}", "WebSocket",
+ g_variant_new_boolean(s->websocket));
+ g_variant_builder_add(&builder, "{sv}", "Auth",
+ g_variant_new_string(
+ VncPrimaryAuth_str(s->auth)));
+ g_variant_builder_add(&builder, "{sv}", "VencryptSubAuth",
+ g_variant_new_string(vencrypt_str));
+ g_variant_builder_close(&builder);
+ }
+
+ qemu_vnc1_server_set_listeners(
+ QEMU_VNC1_SERVER(server_skeleton),
+ g_variant_builder_end(&builder));
+}
+
+void vnc_dbus_setup(GDBusConnection *bus)
+{
+ g_autoptr(GDBusObjectSkeleton) server_obj = NULL;
+ VncInfo2List *info_list;
+ Error *err = NULL;
+ const char *auth_str = "none";
+ const char *vencrypt_str = "";
+
+ obj_manager = g_dbus_object_manager_server_new("/org/qemu/Vnc1");
+
+ server_skeleton = QEMU_VNC1_SERVER_SKELETON(
+ qemu_vnc1_server_skeleton_new());
+
+ qemu_vnc1_server_set_name(QEMU_VNC1_SERVER(server_skeleton),
+ qemu_name ? qemu_name : "");
+ qemu_vnc1_server_set_clients(QEMU_VNC1_SERVER(server_skeleton), NULL);
+
+ /* Query auth info from the VNC display */
+ info_list = qmp_query_vnc_servers(&err);
+ if (info_list) {
+ VncInfo2 *info = info_list->value;
+ auth_str = VncPrimaryAuth_str(info->auth);
+ if (info->has_vencrypt) {
+ vencrypt_str = VncVencryptSubAuth_str(info->vencrypt);
+ }
+ vnc_dbus_add_listeners(info);
+ }
+
+ qemu_vnc1_server_set_auth(QEMU_VNC1_SERVER(server_skeleton), auth_str);
+ qemu_vnc1_server_set_vencrypt_sub_auth(
+ QEMU_VNC1_SERVER(server_skeleton), vencrypt_str);
+
+ qapi_free_VncInfo2List(info_list);
+
+ g_signal_connect(server_skeleton, "handle-set-password",
+ G_CALLBACK(on_set_password), NULL);
+ g_signal_connect(server_skeleton, "handle-expire-password",
+ G_CALLBACK(on_expire_password), NULL);
+ g_signal_connect(server_skeleton, "handle-reload-certificates",
+ G_CALLBACK(on_reload_certificates), NULL);
+
+ server_obj = g_dbus_object_skeleton_new("/org/qemu/Vnc1/Server");
+ g_dbus_object_skeleton_add_interface(
+ server_obj, G_DBUS_INTERFACE_SKELETON(server_skeleton));
+ g_dbus_object_manager_server_export(obj_manager, server_obj);
+
+ g_dbus_object_manager_server_set_connection(obj_manager, bus);
+
+ if (g_dbus_connection_get_flags(bus)
+ & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) {
+ g_bus_own_name_on_connection(
+ bus, "org.qemu.vnc",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL, NULL, NULL, NULL);
+ }
+}
+
+void vnc_action_shutdown(VncState *vs)
+{
+ VncDbusClient *c;
+
+ c = vnc_dbus_find_client(vs->info->host, vs->info->service);
+ if (!c) {
+ trace_qemu_vnc_client_not_found(vs->info->host, vs->info->service);
+ return;
+ }
+
+ qemu_vnc1_client_emit_shutdown_request(QEMU_VNC1_CLIENT(c->skeleton));
+}
+
+void vnc_action_reset(VncState *vs)
+{
+ VncDbusClient *c;
+
+ c = vnc_dbus_find_client(vs->info->host, vs->info->service);
+ if (!c) {
+ trace_qemu_vnc_client_not_found(vs->info->host, vs->info->service);
+ return;
+ }
+
+ qemu_vnc1_client_emit_reset_request(QEMU_VNC1_CLIENT(c->skeleton));
+}
+
+/*
+ * Override the stub qapi_event_emit() to capture VNC events
+ * and forward them to the D-Bus interface.
+ */
+void qapi_event_emit(QAPIEvent event, QDict *qdict)
+{
+ QDict *data, *client;
+ const char *host, *service, *family;
+ bool websocket;
+
+ if (event != QAPI_EVENT_VNC_CONNECTED &&
+ event != QAPI_EVENT_VNC_INITIALIZED &&
+ event != QAPI_EVENT_VNC_DISCONNECTED) {
+ return;
+ }
+
+ data = qdict_get_qdict(qdict, "data");
+ if (!data) {
+ return;
+ }
+
+ client = qdict_get_qdict(data, "client");
+ if (!client) {
+ return;
+ }
+
+ host = qdict_get_str(client, "host");
+ service = qdict_get_str(client, "service");
+ family = qdict_get_str(client, "family");
+ websocket = qdict_get_bool(client, "websocket");
+
+ switch (event) {
+ case QAPI_EVENT_VNC_CONNECTED:
+ vnc_dbus_client_connected(host, service, family, websocket);
+ break;
+ case QAPI_EVENT_VNC_INITIALIZED: {
+ const char *x509_dname = NULL;
+ const char *sasl_username = NULL;
+
+ if (qdict_haskey(client, "x509_dname")) {
+ x509_dname = qdict_get_str(client, "x509_dname");
+ }
+ if (qdict_haskey(client, "sasl_username")) {
+ sasl_username = qdict_get_str(client, "sasl_username");
+ }
+ vnc_dbus_client_initialized(host, service,
+ x509_dname, sasl_username);
+ break;
+ }
+ case QAPI_EVENT_VNC_DISCONNECTED:
+ vnc_dbus_client_disconnected(host, service);
+ break;
+ default:
+ break;
+ }
+}
+
+void vnc_dbus_cleanup(void)
+{
+ VncDbusClient *c, *next;
+
+ QTAILQ_FOREACH_SAFE(c, &dbus_clients, next, next) {
+ g_dbus_object_manager_server_unexport(obj_manager, c->path);
+ QTAILQ_REMOVE(&dbus_clients, c, next);
+ g_object_unref(c->skeleton);
+ g_free(c->path);
+ g_free(c->host);
+ g_free(c->service);
+ g_free(c);
+ }
+
+ g_clear_object(&server_skeleton);
+ g_clear_object(&obj_manager);
+}
diff --git a/tools/qemu-vnc/display.c b/tools/qemu-vnc/display.c
new file mode 100644
index 00000000000..8fe9b6fc898
--- /dev/null
+++ b/tools/qemu-vnc/display.c
@@ -0,0 +1,456 @@
+/*
+ * D-Bus display listener — scanout, update and cursor handling.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/sockets.h"
+#include "qemu/error-report.h"
+#include "ui/console-priv.h"
+#include "ui/dbus-display1.h"
+#include "ui/surface.h"
+#include "trace.h"
+#include "qemu-vnc.h"
+
+typedef struct ConsoleData {
+ QemuDBusDisplay1Console *console_proxy;
+ QemuDBusDisplay1Keyboard *keyboard_proxy;
+ QemuDBusDisplay1Mouse *mouse_proxy;
+ QemuGraphicConsole *gfx_con;
+ GDBusConnection *listener_conn;
+ /*
+ * When true the surface is backed by a read-only mmap (ScanoutMap path)
+ * and Update messages must be rejected because compositing into the
+ * surface is not possible. The plain Scanout path provides a writable
+ * copy and clears this flag.
+ */
+ bool read_only;
+} ConsoleData;
+
+static void display_ui_info(void *opaque, uint32_t head, QemuUIInfo *info)
+{
+ ConsoleData *cd = opaque;
+ g_autoptr(GError) err = NULL;
+
+ if (!cd || !cd->console_proxy) {
+ return;
+ }
+
+ qemu_dbus_display1_console_call_set_uiinfo_sync(
+ cd->console_proxy,
+ info->width_mm, info->height_mm,
+ info->xoff, info->yoff,
+ info->width, info->height,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+ if (err) {
+ error_report("SetUIInfo failed: %s", err->message);
+ }
+}
+
+static void
+scanout_image_destroy(pixman_image_t *image, void *data)
+{
+ g_variant_unref(data);
+}
+
+typedef struct {
+ void *addr;
+ size_t len;
+} ScanoutMapData;
+
+static void
+scanout_map_destroy(pixman_image_t *image, void *data)
+{
+ ScanoutMapData *map = data;
+ munmap(map->addr, map->len);
+ g_free(map);
+}
+
+static gboolean
+on_scanout(QemuDBusDisplay1Listener *listener,
+ GDBusMethodInvocation *invocation,
+ guint width, guint height, guint stride,
+ guint pixman_format, GVariant *data,
+ gpointer user_data)
+{
+ ConsoleData *cd = user_data;
+ QemuConsole *con = QEMU_CONSOLE(cd->gfx_con);
+ gsize size;
+ const uint8_t *pixels;
+ pixman_image_t *image;
+ DisplaySurface *surface;
+
+ trace_qemu_vnc_scanout(width, height, stride, pixman_format);
+
+ pixels = g_variant_get_fixed_array(data, &size, 1);
+
+ image = pixman_image_create_bits((pixman_format_code_t)pixman_format,
+ width, height, (uint32_t *)pixels, stride);
+ assert(image);
+
+ g_variant_ref(data);
+ pixman_image_set_destroy_function(image, scanout_image_destroy, data);
+
+ cd->read_only = false;
+ surface = qemu_create_displaysurface_pixman(image);
+ qemu_console_set_surface(con, surface);
+
+ qemu_dbus_display1_listener_complete_scanout(listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_update(QemuDBusDisplay1Listener *listener,
+ GDBusMethodInvocation *invocation,
+ gint x, gint y, gint w, gint h,
+ guint stride, guint pixman_format, GVariant *data,
+ gpointer user_data)
+{
+ ConsoleData *cd = user_data;
+ QemuConsole *con = QEMU_CONSOLE(cd->gfx_con);
+ DisplaySurface *surface = qemu_console_surface(con);
+ gsize size;
+ const uint8_t *pixels;
+ pixman_image_t *src;
+
+ trace_qemu_vnc_update(x, y, w, h, stride, pixman_format);
+ if (!surface || cd->read_only) {
+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED, "No active or writable console");
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ pixels = g_variant_get_fixed_array(data, &size, 1);
+ src = pixman_image_create_bits((pixman_format_code_t)pixman_format,
+ w, h, (uint32_t *)pixels, stride);
+ assert(src);
+ pixman_image_composite(PIXMAN_OP_SRC, src, NULL,
+ surface->image,
+ 0, 0, 0, 0, x, y, w, h);
+ pixman_image_unref(src);
+
+ qemu_console_update(con, x, y, w, h);
+
+ qemu_dbus_display1_listener_complete_update(listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_scanout_map(QemuDBusDisplay1ListenerUnixMap *listener,
+ GDBusMethodInvocation *invocation,
+ GUnixFDList *fd_list,
+ GVariant *arg_handle,
+ guint offset, guint width, guint height,
+ guint stride, guint pixman_format,
+ gpointer user_data)
+{
+ ConsoleData *cd = user_data;
+ gint32 handle = g_variant_get_handle(arg_handle);
+ g_autoptr(GError) err = NULL;
+ DisplaySurface *surface;
+ int fd;
+ void *addr;
+ size_t len = (size_t)height * stride;
+ pixman_image_t *image;
+
+ trace_qemu_vnc_scanout_map(width, height, stride, pixman_format, offset);
+
+ fd = g_unix_fd_list_get(fd_list, handle, &err);
+ if (fd < 0) {
+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED, "Failed to get fd: %s", err->message);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ /* MAP_PRIVATE: we only read; avoid propagating writes back to QEMU */
+ addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, offset);
+ close(fd);
+ if (addr == MAP_FAILED) {
+ g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED, "mmap failed: %s", g_strerror(errno));
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ image = pixman_image_create_bits((pixman_format_code_t)pixman_format,
+ width, height, addr, stride);
+ assert(image);
+ {
+ ScanoutMapData *map = g_new0(ScanoutMapData, 1);
+ map->addr = addr;
+ map->len = len;
+ pixman_image_set_destroy_function(image, scanout_map_destroy, map);
+ }
+
+ cd->read_only = true;
+ surface = qemu_create_displaysurface_pixman(image);
+ qemu_console_set_surface(QEMU_CONSOLE(cd->gfx_con), surface);
+
+ qemu_dbus_display1_listener_unix_map_complete_scanout_map(
+ listener, invocation, NULL);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_update_map(QemuDBusDisplay1ListenerUnixMap *listener,
+ GDBusMethodInvocation *invocation,
+ guint x, guint y, guint w, guint h,
+ gpointer user_data)
+{
+ ConsoleData *cd = user_data;
+
+ trace_qemu_vnc_update_map(x, y, w, h);
+
+ qemu_console_update(QEMU_CONSOLE(cd->gfx_con), x, y, w, h);
+
+ qemu_dbus_display1_listener_unix_map_complete_update_map(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static gboolean
+on_cursor_define(QemuDBusDisplay1Listener *listener,
+ GDBusMethodInvocation *invocation,
+ gint width, gint height,
+ gint hot_x, gint hot_y,
+ GVariant *data,
+ gpointer user_data)
+{
+ ConsoleData *cd = user_data;
+ gsize size;
+ const uint8_t *pixels;
+ QEMUCursor *c;
+
+ trace_qemu_vnc_cursor_define(width, height, hot_x, hot_y);
+
+ c = cursor_alloc(width, height);
+ if (!c) {
+ qemu_dbus_display1_listener_complete_cursor_define(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ c->hot_x = hot_x;
+ c->hot_y = hot_y;
+
+ pixels = g_variant_get_fixed_array(data, &size, 1);
+ memcpy(c->data, pixels, MIN(size, (gsize)width * height * 4));
+
+ qemu_console_set_cursor(QEMU_CONSOLE(cd->gfx_con), c);
+ cursor_unref(c);
+
+ qemu_dbus_display1_listener_complete_cursor_define(
+ listener, invocation);
+ return DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+typedef struct {
+ GMainLoop *loop;
+ GThread *thread;
+ GDBusConnection *listener_conn;
+} ListenerSetupData;
+
+static void
+on_register_listener_finished(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ListenerSetupData *data = user_data;
+ g_autoptr(GError) err = NULL;
+
+ qemu_dbus_display1_console_call_register_listener_finish(
+ QEMU_DBUS_DISPLAY1_CONSOLE(source_object),
+ NULL,
+ res, &err);
+
+ if (err) {
+ error_report("RegisterListener failed: %s", err->message);
+ g_main_loop_quit(data->loop);
+ return;
+ }
+
+ data->listener_conn = g_thread_join(data->thread);
+ g_main_loop_quit(data->loop);
+}
+
+static GDBusConnection *
+console_register_display_listener(QemuDBusDisplay1Console *console)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GMainLoop) loop = NULL;
+ g_autoptr(GUnixFDList) fd_list = NULL;
+ ListenerSetupData data = { 0 };
+ int pair[2];
+ int idx;
+
+ if (qemu_socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) {
+ error_report("socketpair failed: %s", strerror(errno));
+ return NULL;
+ }
+
+ fd_list = g_unix_fd_list_new();
+ idx = g_unix_fd_list_append(fd_list, pair[1], &err);
+ close(pair[1]);
+ if (idx < 0) {
+ close(pair[0]);
+ error_report("Failed to append fd: %s", err->message);
+ return NULL;
+ }
+
+ loop = g_main_loop_new(NULL, FALSE);
+ data.loop = loop;
+ data.thread = p2p_dbus_thread_new(pair[0]);
+
+ qemu_dbus_display1_console_call_register_listener(
+ console,
+ g_variant_new_handle(idx),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ fd_list,
+ NULL,
+ on_register_listener_finished,
+ &data);
+
+ g_main_loop_run(loop);
+
+ return data.listener_conn;
+}
+
+static void
+setup_display_listener(ConsoleData *cd)
+{
+ g_autoptr(GDBusObjectSkeleton) obj = NULL;
+ GDBusObjectManagerServer *server;
+ QemuDBusDisplay1Listener *iface;
+ QemuDBusDisplay1ListenerUnixMap *iface_map;
+
+ server = g_dbus_object_manager_server_new(DBUS_DISPLAY1_ROOT);
+ obj = g_dbus_object_skeleton_new(DBUS_DISPLAY1_ROOT "/Listener");
+
+ /* Main listener interface */
+ iface = qemu_dbus_display1_listener_skeleton_new();
+ g_object_connect(iface,
+ "signal::handle-scanout", on_scanout, cd,
+ "signal::handle-update", on_update, cd,
+ "signal::handle-cursor-define", on_cursor_define, cd,
+ NULL);
+ g_dbus_object_skeleton_add_interface(obj,
+ G_DBUS_INTERFACE_SKELETON(iface));
+
+ /* Unix shared memory map interface */
+ iface_map = qemu_dbus_display1_listener_unix_map_skeleton_new();
+ g_object_connect(iface_map,
+ "signal::handle-scanout-map", on_scanout_map, cd,
+ "signal::handle-update-map", on_update_map, cd,
+ NULL);
+ g_dbus_object_skeleton_add_interface(obj,
+ G_DBUS_INTERFACE_SKELETON(iface_map));
+
+ {
+ const gchar *ifaces[] = {
+ "org.qemu.Display1.Listener.Unix.Map", NULL
+ };
+ g_object_set(iface, "interfaces", ifaces, NULL);
+ }
+
+ g_dbus_object_manager_server_export(server, obj);
+ g_dbus_object_manager_server_set_connection(server,
+ cd->listener_conn);
+
+ g_dbus_connection_start_message_processing(cd->listener_conn);
+}
+
+static const GraphicHwOps vnc_hw_ops = {
+ .ui_info = display_ui_info,
+};
+
+bool console_setup(GDBusConnection *bus, const char *bus_name,
+ const char *console_path)
+{
+ g_autoptr(GError) err = NULL;
+ ConsoleData *cd;
+ QemuConsole *con;
+
+ cd = g_new0(ConsoleData, 1);
+
+ cd->console_proxy = qemu_dbus_display1_console_proxy_new_sync(
+ bus, G_DBUS_PROXY_FLAGS_NONE, bus_name,
+ console_path, NULL, &err);
+ if (!cd->console_proxy) {
+ error_report("Failed to create console proxy for %s: %s",
+ console_path, err->message);
+ g_free(cd);
+ return false;
+ }
+
+ cd->keyboard_proxy = QEMU_DBUS_DISPLAY1_KEYBOARD(
+ qemu_dbus_display1_keyboard_proxy_new_sync(
+ bus, G_DBUS_PROXY_FLAGS_NONE, bus_name,
+ console_path, NULL, &err));
+ if (!cd->keyboard_proxy) {
+ error_report("Failed to create keyboard proxy for %s: %s",
+ console_path, err->message);
+ g_object_unref(cd->console_proxy);
+ g_free(cd);
+ return false;
+ }
+
+ g_clear_error(&err);
+ cd->mouse_proxy = QEMU_DBUS_DISPLAY1_MOUSE(
+ qemu_dbus_display1_mouse_proxy_new_sync(
+ bus, G_DBUS_PROXY_FLAGS_NONE, bus_name,
+ console_path, NULL, &err));
+ if (!cd->mouse_proxy) {
+ error_report("Failed to create mouse proxy for %s: %s",
+ console_path, err->message);
+ g_object_unref(cd->keyboard_proxy);
+ g_object_unref(cd->console_proxy);
+ g_free(cd);
+ return false;
+ }
+
+ con = qemu_graphic_console_create(NULL, 0, &vnc_hw_ops, cd);
+ cd->gfx_con = QEMU_GRAPHIC_CONSOLE(con);
+
+ cd->listener_conn = console_register_display_listener(
+ cd->console_proxy);
+ if (!cd->listener_conn) {
+ error_report("Failed to setup D-Bus listener for %s",
+ console_path);
+ g_object_unref(cd->mouse_proxy);
+ g_object_unref(cd->keyboard_proxy);
+ g_object_unref(cd->console_proxy);
+ g_free(cd);
+ return false;
+ }
+
+ setup_display_listener(cd);
+ input_setup(cd->keyboard_proxy, cd->mouse_proxy);
+
+ return true;
+}
+
+QemuDBusDisplay1Keyboard *console_get_keyboard(QemuConsole *con)
+{
+ ConsoleData *cd;
+
+ if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
+ return NULL;
+ }
+ cd = con->hw;
+ return cd ? cd->keyboard_proxy : NULL;
+}
+
+QemuDBusDisplay1Mouse *console_get_mouse(QemuConsole *con)
+{
+ ConsoleData *cd;
+
+ if (!QEMU_IS_GRAPHIC_CONSOLE(con)) {
+ return NULL;
+ }
+ cd = con->hw;
+ return cd ? cd->mouse_proxy : NULL;
+}
diff --git a/tools/qemu-vnc/input.c b/tools/qemu-vnc/input.c
new file mode 100644
index 00000000000..2313b0a7c77
--- /dev/null
+++ b/tools/qemu-vnc/input.c
@@ -0,0 +1,239 @@
+/*
+ * Keyboard and mouse input dispatch via D-Bus.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "ui/dbus-display1.h"
+#include "ui/input.h"
+#include "trace.h"
+#include "qemu-vnc.h"
+
+struct QEMUPutLEDEntry {
+ QEMUPutLEDEvent *put_led;
+ void *opaque;
+ QTAILQ_ENTRY(QEMUPutLEDEntry) next;
+};
+
+static NotifierList mouse_mode_notifiers =
+ NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
+static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers =
+ QTAILQ_HEAD_INITIALIZER(led_handlers);
+
+/* Track the target console for pending mouse events (used by sync) */
+static QemuConsole *mouse_target;
+
+QEMUPutLEDEntry *qemu_add_led_event_handler(QEMUPutLEDEvent *func,
+ void *opaque)
+{
+ QEMUPutLEDEntry *s;
+
+ s = g_new0(QEMUPutLEDEntry, 1);
+ s->put_led = func;
+ s->opaque = opaque;
+ QTAILQ_INSERT_TAIL(&led_handlers, s, next);
+ return s;
+}
+
+void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry)
+{
+ if (!entry) {
+ return;
+ }
+ QTAILQ_REMOVE(&led_handlers, entry, next);
+ g_free(entry);
+}
+
+static void
+on_keyboard_modifiers_changed(GObject *gobject, GParamSpec *pspec,
+ gpointer user_data)
+{
+ guint modifiers;
+ QEMUPutLEDEntry *cursor;
+
+ modifiers = qemu_dbus_display1_keyboard_get_modifiers(
+ QEMU_DBUS_DISPLAY1_KEYBOARD(gobject));
+
+ /*
+ * The D-Bus Keyboard.Modifiers property uses the same
+ * bit layout as QEMU's LED constants.
+ */
+ QTAILQ_FOREACH(cursor, &led_handlers, next) {
+ cursor->put_led(cursor->opaque, modifiers);
+ }
+}
+
+void qemu_add_mouse_mode_change_notifier(Notifier *notify)
+{
+ notifier_list_add(&mouse_mode_notifiers, notify);
+}
+
+void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
+{
+ notifier_remove(notify);
+}
+
+void qemu_input_event_send_key_delay(uint32_t delay_ms)
+{
+}
+
+void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
+{
+ QemuDBusDisplay1Keyboard *kbd;
+ guint qnum;
+
+ trace_qemu_vnc_key_event(q, down);
+
+ if (!src) {
+ return;
+ }
+ kbd = console_get_keyboard(src);
+ if (!kbd) {
+ return;
+ }
+
+ if (q >= qemu_input_map_qcode_to_qnum_len) {
+ return;
+ }
+ qnum = qemu_input_map_qcode_to_qnum[q];
+
+ if (down) {
+ qemu_dbus_display1_keyboard_call_press(
+ kbd, qnum,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ } else {
+ qemu_dbus_display1_keyboard_call_release(
+ kbd, qnum,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ }
+}
+
+static guint abs_x, abs_y;
+static bool abs_pending;
+static gint rel_dx, rel_dy;
+static bool rel_pending;
+
+void qemu_input_queue_abs(QemuConsole *src, InputAxis axis,
+ int value, int min_in, int max_in)
+{
+ if (axis == INPUT_AXIS_X) {
+ abs_x = value;
+ } else if (axis == INPUT_AXIS_Y) {
+ abs_y = value;
+ }
+ abs_pending = true;
+ mouse_target = src;
+}
+
+void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
+{
+ if (axis == INPUT_AXIS_X) {
+ rel_dx += value;
+ } else if (axis == INPUT_AXIS_Y) {
+ rel_dy += value;
+ }
+ rel_pending = true;
+ mouse_target = src;
+}
+
+void qemu_input_event_sync(void)
+{
+ QemuDBusDisplay1Mouse *mouse;
+
+ if (!mouse_target) {
+ return;
+ }
+
+ mouse = console_get_mouse(mouse_target);
+ if (!mouse) {
+ abs_pending = false;
+ rel_pending = false;
+ return;
+ }
+
+ if (abs_pending) {
+ trace_qemu_vnc_input_abs(abs_x, abs_y);
+ abs_pending = false;
+ qemu_dbus_display1_mouse_call_set_abs_position(
+ mouse, abs_x, abs_y,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ }
+
+ if (rel_pending) {
+ trace_qemu_vnc_input_rel(rel_dx, rel_dy);
+ rel_pending = false;
+ qemu_dbus_display1_mouse_call_rel_motion(
+ mouse, rel_dx, rel_dy,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ rel_dx = 0;
+ rel_dy = 0;
+ }
+}
+
+bool qemu_input_is_absolute(QemuConsole *con)
+{
+ QemuDBusDisplay1Mouse *mouse;
+
+ if (!con) {
+ return false;
+ }
+ mouse = console_get_mouse(con);
+
+ if (!mouse) {
+ return false;
+ }
+ return qemu_dbus_display1_mouse_get_is_absolute(mouse);
+}
+
+static void
+on_mouse_is_absolute_changed(GObject *gobject, GParamSpec *pspec,
+ gpointer user_data)
+{
+ notifier_list_notify(&mouse_mode_notifiers, NULL);
+}
+
+void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
+ uint32_t button_old, uint32_t button_new)
+{
+ QemuDBusDisplay1Mouse *mouse;
+ uint32_t changed;
+ int i;
+
+ if (!src) {
+ return;
+ }
+ mouse = console_get_mouse(src);
+ if (!mouse) {
+ return;
+ }
+
+ changed = button_old ^ button_new;
+ for (i = 0; i < 32; i++) {
+ if (!(changed & (1u << i))) {
+ continue;
+ }
+ trace_qemu_vnc_input_btn(i, !!(button_new & (1u << i)));
+ if (button_new & (1u << i)) {
+ qemu_dbus_display1_mouse_call_press(
+ mouse, i,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ } else {
+ qemu_dbus_display1_mouse_call_release(
+ mouse, i,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ }
+ }
+}
+
+void input_setup(QemuDBusDisplay1Keyboard *kbd,
+ QemuDBusDisplay1Mouse *mouse)
+{
+ g_signal_connect(kbd, "notify::modifiers",
+ G_CALLBACK(on_keyboard_modifiers_changed), NULL);
+ g_signal_connect(mouse, "notify::is-absolute",
+ G_CALLBACK(on_mouse_is_absolute_changed), NULL);
+}
diff --git a/tools/qemu-vnc/qemu-vnc.c b/tools/qemu-vnc/qemu-vnc.c
new file mode 100644
index 00000000000..d063aff7a62
--- /dev/null
+++ b/tools/qemu-vnc/qemu-vnc.c
@@ -0,0 +1,491 @@
+/*
+ * Standalone VNC server connecting to QEMU via D-Bus display interface.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/cutils.h"
+#include "qemu/datadir.h"
+#include "qemu/error-report.h"
+#include "qemu/config-file.h"
+#include "qemu/option.h"
+#include "qemu/log.h"
+#include "qemu/main-loop.h"
+#include "qemu-version.h"
+#include "ui/vnc.h"
+#include "crypto/secret.h"
+#include "crypto/tlscredsx509.h"
+#include "qom/object_interfaces.h"
+#include "trace.h"
+#include "qemu-vnc.h"
+
+const char *qemu_name;
+const char *keyboard_layout;
+
+static bool terminate;
+static VncDisplay *vd;
+
+static GType
+dbus_display_get_proxy_type(GDBusObjectManagerClient *manager,
+ const gchar *object_path,
+ const gchar *interface_name,
+ gpointer user_data)
+{
+ static const struct {
+ const char *iface;
+ GType (*get_type)(void);
+ } types[] = {
+ { "org.qemu.Display1.Clipboard",
+ qemu_dbus_display1_clipboard_proxy_get_type },
+ { "org.qemu.Display1.Audio",
+ qemu_dbus_display1_audio_proxy_get_type },
+ { "org.qemu.Display1.Chardev",
+ qemu_dbus_display1_chardev_proxy_get_type },
+ };
+
+ if (!interface_name) {
+ return G_TYPE_DBUS_OBJECT_PROXY;
+ }
+
+ for (int i = 0; i < G_N_ELEMENTS(types); i++) {
+ if (g_str_equal(interface_name, types[i].iface)) {
+ return types[i].get_type();
+ }
+ }
+
+ return G_TYPE_DBUS_PROXY;
+}
+
+static void
+on_bus_closed(GDBusConnection *connection,
+ gboolean remote_peer_vanished,
+ GError *error,
+ gpointer user_data)
+{
+ terminate = true;
+ qemu_notify_event();
+}
+
+static void
+on_owner_vanished(GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ trace_qemu_vnc_owner_vanished(name);
+ error_report("D-Bus peer %s vanished, terminating", name);
+ terminate = true;
+ qemu_notify_event();
+}
+
+typedef struct {
+ GDBusConnection *bus;
+ const char *bus_name;
+ const char * const *chardev_names;
+ bool no_vt;
+} ManagerSetupData;
+
+static int
+compare_console_paths(const void *a, const void *b)
+{
+ const char *pa = *(const char **)a;
+ const char *pb = *(const char **)b;
+ return strcmp(pa, pb);
+}
+
+static void
+on_manager_ready(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ ManagerSetupData *data = user_data;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GDBusObjectManager) manager = NULL;
+ GList *objects, *l;
+ g_autoptr(GPtrArray) console_paths = NULL;
+ bool found = false;
+
+ manager = G_DBUS_OBJECT_MANAGER(
+ g_dbus_object_manager_client_new_finish(res, &err));
+ if (!manager) {
+ error_report("Failed to create object manager: %s",
+ err->message);
+ terminate = true;
+ qemu_notify_event();
+ g_free(data);
+ return;
+ }
+
+ /*
+ * Discover all Console objects and sort them so that console
+ * indices are assigned in a predictable order matching QEMU's.
+ */
+ console_paths = g_ptr_array_new_with_free_func(g_free);
+ objects = g_dbus_object_manager_get_objects(manager);
+ for (l = objects; l; l = l->next) {
+ GDBusObject *obj = l->data;
+ const char *path = g_dbus_object_get_object_path(obj);
+
+ if (g_str_has_prefix(path, DBUS_DISPLAY1_ROOT "/Console_")) {
+ g_ptr_array_add(console_paths, g_strdup(path));
+ }
+ }
+ g_list_free_full(objects, g_object_unref);
+
+ g_ptr_array_sort(console_paths, compare_console_paths);
+
+ for (guint i = 0; i < console_paths->len; i++) {
+ const char *path = g_ptr_array_index(console_paths, i);
+
+ if (!console_setup(data->bus, data->bus_name, path)) {
+ error_report("Failed to setup console %s", path);
+ continue;
+ }
+ found = true;
+ }
+
+ if (!found) {
+ error_report("No consoles found");
+ terminate = true;
+ qemu_notify_event();
+ g_free(data);
+ return;
+ }
+
+ /*
+ * Create the VNC display now that consoles exist, so that the
+ * display change listener is registered against a valid console.
+ */
+ {
+ Error *local_err = NULL;
+
+ vd = vnc_display_new("default", &local_err);
+ if (!vd) {
+ error_report_err(local_err);
+ terminate = true;
+ qemu_notify_event();
+ g_free(data);
+ return;
+ }
+ }
+
+ vnc_dbus_setup(data->bus);
+
+ clipboard_setup(manager, data->bus);
+ audio_setup(manager);
+ if (!data->no_vt) {
+ chardev_setup(data->chardev_names, manager);
+ }
+ g_free(data);
+}
+
+int main(int argc, char *argv[])
+{
+ Error *local_err = NULL;
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GDBusConnection) bus = NULL;
+ g_autofree char *dbus_address = NULL;
+ g_autofree char *bus_name = NULL;
+ int dbus_p2p_fd = -1;
+ g_autofree char *vnc_addr = NULL;
+ g_autofree char *ws_addr = NULL;
+ g_autofree char *share = NULL;
+ g_autofree char *tls_creds_dir = NULL;
+ g_autofree char *tls_authz = NULL;
+ g_autofree char *sasl_authz = NULL;
+ g_autofree char *trace_opt = NULL;
+ g_auto(GStrv) chardev_names = NULL;
+ g_auto(GStrv) object_strs = NULL;
+ const char *creds_dir;
+ bool has_vnc_password = false;
+ bool show_version = false;
+ bool no_vt = false;
+ bool password = false;
+ bool sasl = false;
+ bool lossy = false;
+ bool non_adaptive = false;
+ g_autoptr(GOptionContext) context = NULL;
+ GOptionEntry entries[] = {
+ { "dbus-address", 'a', 0, G_OPTION_ARG_STRING, &dbus_address,
+ "D-Bus address to connect to (default: session bus)", "ADDRESS" },
+ { "dbus-p2p-fd", 'p', 0, G_OPTION_ARG_INT, &dbus_p2p_fd,
+ "D-Bus peer-to-peer socket file descriptor", "FD" },
+ { "bus-name", 'n', 0, G_OPTION_ARG_STRING, &bus_name,
+ "D-Bus bus name (default: org.qemu)", "NAME" },
+ { "vnc-addr", 'l', 0, G_OPTION_ARG_STRING, &vnc_addr,
+ "VNC display address (default localhost:0)", "ADDR" },
+ { "websocket", 'w', 0, G_OPTION_ARG_STRING, &ws_addr,
+ "WebSocket address (e.g. port number or addr:port)", "ADDR" },
+ { "share", 's', 0, G_OPTION_ARG_STRING, &share,
+ "Display sharing policy "
+ "(allow-exclusive|force-shared|ignore)", "POLICY" },
+ { "tls-creds", 't', 0, G_OPTION_ARG_STRING, &tls_creds_dir,
+ "TLS x509 credentials directory", "DIR" },
+ { "tls-authz", 0, 0, G_OPTION_ARG_STRING, &tls_authz,
+ "ID of a QAuthZ object for TLS client certificate "
+ "authorization", "ID" },
+ { "object", 'O', 0, G_OPTION_ARG_STRING_ARRAY, &object_strs,
+ "QEMU user-creatable object "
+ "(e.g. authz-list-file,id=auth0,filename=acl.json)", "OBJDEF" },
+ { "vt-chardev", 'C', 0, G_OPTION_ARG_STRING_ARRAY, &chardev_names,
+ "Chardev type names to expose as text console (repeatable, "
+ "default: serial & hmp)", "NAME" },
+ { "no-vt", 'N', 0, G_OPTION_ARG_NONE, &no_vt,
+ "Do not expose any chardevs as text consoles", NULL },
+ { "keyboard-layout", 'k', 0, G_OPTION_ARG_STRING, &keyboard_layout,
+ "Keyboard layout", "LAYOUT" },
+ { "trace", 'T', 0, G_OPTION_ARG_STRING, &trace_opt,
+ "Trace options (same as QEMU -trace)", "PATTERN" },
+ { "version", 'V', 0, G_OPTION_ARG_NONE, &show_version,
+ "Print version information and exit", NULL },
+ { "password", 0, 0, G_OPTION_ARG_NONE, &password,
+ "Require password authentication (use D-Bus SetPassword to set)",
+ NULL },
+ { "lossy", 0, 0, G_OPTION_ARG_NONE, &lossy,
+ "Enable lossy compression", NULL },
+ { "non-adaptive", 0, 0, G_OPTION_ARG_NONE, &non_adaptive,
+ "Disable adaptive encodings", NULL },
+ { "sasl", 0, 0, G_OPTION_ARG_NONE, &sasl,
+ "Enable SASL authentication", NULL },
+ { "sasl-authz", 0, 0, G_OPTION_ARG_STRING, &sasl_authz,
+ "ID of a QAuthZ object for SASL username "
+ "authorization", "ID" },
+ { NULL }
+ };
+
+ qemu_init_exec_dir(argv[0]);
+ qemu_add_data_dir(get_relocated_path(CONFIG_QEMU_DATADIR));
+
+ module_call_init(MODULE_INIT_TRACE);
+ module_call_init(MODULE_INIT_QOM);
+ module_call_init(MODULE_INIT_OPTS);
+ qemu_add_opts(&qemu_trace_opts);
+
+ context = g_option_context_new("- standalone VNC server for QEMU");
+ g_option_context_add_main_entries(context, entries, NULL);
+ if (!g_option_context_parse(context, &argc, &argv, &err)) {
+ error_report("Option parsing failed: %s", err->message);
+ return 1;
+ }
+
+ if (show_version) {
+ printf("qemu-vnc " QEMU_FULL_VERSION "\n");
+ return 0;
+ }
+
+ if (trace_opt) {
+ trace_opt_parse(trace_opt);
+ qemu_set_log(LOG_TRACE, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return 1;
+ }
+ }
+ trace_init_file();
+
+ if (qemu_init_main_loop(&local_err)) {
+ error_report_err(local_err);
+ return 1;
+ }
+
+ if (!vnc_addr) {
+ vnc_addr = g_strdup("localhost:0");
+ }
+
+ if (object_strs) {
+ for (int i = 0; object_strs[i]; i++) {
+ user_creatable_process_cmdline(object_strs[i]);
+ }
+ }
+
+ if (tls_authz && !tls_creds_dir) {
+ error_report("--tls-authz requires --tls-creds");
+ return 1;
+ }
+
+ if (sasl_authz && !sasl) {
+ error_report("--sasl-authz requires --sasl");
+ return 1;
+ }
+
+ if (dbus_p2p_fd >= 0 && dbus_address) {
+ error_report("--dbus-p2p-fd and --dbus-address are"
+ " mutually exclusive");
+ return 1;
+ }
+
+ if (dbus_p2p_fd >= 0) {
+ g_autoptr(GSocket) socket = NULL;
+ g_autoptr(GSocketConnection) socketc = NULL;
+
+ if (bus_name) {
+ error_report("--bus-name is not supported with --dbus-p2p-fd");
+ return 1;
+ }
+
+ socket = g_socket_new_from_fd(dbus_p2p_fd, &err);
+ if (!socket) {
+ error_report("Failed to create socket from fd %d: %s",
+ dbus_p2p_fd, err->message);
+ return 1;
+ }
+
+ socketc = g_socket_connection_factory_create_connection(socket);
+ if (!socketc) {
+ error_report("Failed to create socket connection");
+ return 1;
+ }
+
+ bus = g_dbus_connection_new_sync(
+ G_IO_STREAM(socketc), NULL,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, NULL, &err);
+ } else if (dbus_address) {
+ GDBusConnectionFlags flags =
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT;
+ if (bus_name) {
+ flags |= G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION;
+ }
+ bus = g_dbus_connection_new_for_address_sync(
+ dbus_address, flags, NULL, NULL, &err);
+ } else {
+ bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
+ if (!bus_name) {
+ bus_name = g_strdup("org.qemu");
+ }
+ }
+ if (!bus) {
+ error_report("Failed to connect to D-Bus: %s", err->message);
+ return 1;
+ }
+
+ {
+ g_autoptr(QemuDBusDisplay1VMProxy) vm_proxy = QEMU_DBUS_DISPLAY1_VM_PROXY(
+ qemu_dbus_display1_vm_proxy_new_sync(
+ bus, G_DBUS_PROXY_FLAGS_NONE, bus_name,
+ DBUS_DISPLAY1_ROOT "/VM", NULL, NULL));
+ if (vm_proxy) {
+ qemu_name = g_strdup(qemu_dbus_display1_vm_get_name(
+ QEMU_DBUS_DISPLAY1_VM(vm_proxy)));
+ }
+ }
+
+ /*
+ * Set up TLS credentials if requested. The object must exist
+ * before vnc_display_open() which looks it up by ID.
+ */
+ if (tls_creds_dir) {
+ if (!object_new_with_props(TYPE_QCRYPTO_TLS_CREDS_X509,
+ object_get_objects_root(),
+ "tlscreds0",
+ &local_err,
+ "endpoint", "server",
+ "dir", tls_creds_dir,
+ "verify-peer", tls_authz ? "yes" : "no",
+ NULL)) {
+ error_report_err(local_err);
+ return 1;
+ }
+ }
+
+ /*
+ * Check for systemd credentials: if a vnc-password credential
+ * file exists, create a QCryptoSecret and enable VNC password auth.
+ */
+ creds_dir = g_getenv("CREDENTIALS_DIRECTORY");
+ if (creds_dir) {
+ g_autofree char *password_path =
+ g_build_filename(creds_dir, "vnc-password", NULL);
+ if (g_file_test(password_path, G_FILE_TEST_EXISTS)) {
+ if (!object_new_with_props(TYPE_QCRYPTO_SECRET,
+ object_get_objects_root(),
+ "vncsecret0",
+ &local_err,
+ "file", password_path,
+ NULL)) {
+ error_report_err(local_err);
+ return 1;
+ }
+ has_vnc_password = true;
+ }
+ }
+
+ {
+ g_autoptr(GString) vnc_opts = g_string_new(vnc_addr);
+ QemuOptsList *olist = qemu_find_opts("vnc");
+ QemuOpts *opts;
+
+ if (tls_creds_dir) {
+ g_string_append(vnc_opts, ",tls-creds=tlscreds0");
+ }
+ if (tls_authz) {
+ g_string_append_printf(vnc_opts, ",tls-authz=%s", tls_authz);
+ }
+ if (sasl) {
+ g_string_append(vnc_opts, ",sasl=on");
+ }
+ if (sasl_authz) {
+ g_string_append_printf(vnc_opts, ",sasl-authz=%s", sasl_authz);
+ }
+ if (has_vnc_password) {
+ g_string_append(vnc_opts, ",password-secret=vncsecret0");
+ }
+ if (ws_addr) {
+ g_string_append_printf(vnc_opts, ",websocket=%s", ws_addr);
+ }
+ if (share) {
+ g_string_append_printf(vnc_opts, ",share=%s", share);
+ }
+ if (password && !has_vnc_password) {
+ g_string_append(vnc_opts, ",password=on");
+ }
+ if (lossy) {
+ g_string_append(vnc_opts, ",lossy=on");
+ }
+ if (non_adaptive) {
+ g_string_append(vnc_opts, ",non-adaptive=on");
+ }
+
+ opts = qemu_opts_parse_noisily(olist, vnc_opts->str, true);
+ if (!opts) {
+ return 1;
+ }
+ qemu_opts_set_id(opts, g_strdup("default"));
+ }
+
+ {
+ ManagerSetupData *mgr_data = g_new0(ManagerSetupData, 1);
+ mgr_data->bus = bus;
+ mgr_data->bus_name = bus_name;
+ mgr_data->chardev_names = (const char * const *)chardev_names;
+ mgr_data->no_vt = no_vt;
+
+ g_dbus_object_manager_client_new(
+ bus, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+ bus_name, DBUS_DISPLAY1_ROOT,
+ dbus_display_get_proxy_type,
+ NULL, NULL, NULL,
+ on_manager_ready, mgr_data);
+ }
+
+ g_signal_connect(bus, "closed", G_CALLBACK(on_bus_closed), NULL);
+
+ if (bus_name) {
+ g_bus_watch_name_on_connection(bus, bus_name,
+ G_BUS_NAME_WATCHER_FLAGS_NONE,
+ NULL, on_owner_vanished,
+ NULL, NULL);
+ }
+
+ while (!terminate) {
+ main_loop_wait(false);
+ }
+
+ vnc_dbus_cleanup();
+ vnc_cleanup();
+
+ return 0;
+}
diff --git a/tools/qemu-vnc/stubs.c b/tools/qemu-vnc/stubs.c
new file mode 100644
index 00000000000..a865ce85f04
--- /dev/null
+++ b/tools/qemu-vnc/stubs.c
@@ -0,0 +1,62 @@
+/*
+ * Stubs for qemu-vnc standalone binary.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "system/runstate.h"
+#include "hw/core/qdev.h"
+#include "monitor/monitor.h"
+#include "migration/vmstate.h"
+
+bool runstate_is_running(void)
+{
+ return true;
+}
+
+bool phase_check(MachineInitPhase phase)
+{
+ return true;
+}
+
+DeviceState *qdev_find_recursive(BusState *bus, const char *id)
+{
+ return NULL;
+}
+
+/*
+ * Provide the monitor stubs locally so that the linker does not
+ * pull stubs/monitor-core.c.o from libqemuutil.a (which would
+ * bring a conflicting qapi_event_emit definition).
+ */
+Monitor *monitor_cur(void)
+{
+ return NULL;
+}
+
+bool monitor_cur_is_qmp(void)
+{
+ return false;
+}
+
+Monitor *monitor_set_cur(Coroutine *co, Monitor *mon)
+{
+ return NULL;
+}
+
+int monitor_vprintf(Monitor *mon, const char *fmt, va_list ap)
+{
+ return -1;
+}
+
+/*
+ * Link-time stubs for VMState symbols referenced by VNC code.
+ * The standalone binary never performs migration, so these are
+ * never actually used at runtime.
+ */
+const VMStateInfo vmstate_info_bool = {};
+const VMStateInfo vmstate_info_int32 = {};
+const VMStateInfo vmstate_info_uint32 = {};
+const VMStateInfo vmstate_info_buffer = {};
diff --git a/tools/qemu-vnc/utils.c b/tools/qemu-vnc/utils.c
new file mode 100644
index 00000000000..d261aa9eaf0
--- /dev/null
+++ b/tools/qemu-vnc/utils.c
@@ -0,0 +1,59 @@
+/*
+ * Standalone VNC server connecting to QEMU via D-Bus display interface.
+ *
+ * Copyright (C) 2026 Red Hat, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/error-report.h"
+#include "qemu-vnc.h"
+
+static GDBusConnection *
+dbus_p2p_from_fd(int fd)
+{
+ g_autoptr(GError) err = NULL;
+ g_autoptr(GSocket) socket = NULL;
+ g_autoptr(GSocketConnection) socketc = NULL;
+ GDBusConnection *conn;
+
+ socket = g_socket_new_from_fd(fd, &err);
+ if (!socket) {
+ error_report("Failed to create socket: %s", err->message);
+ return NULL;
+ }
+
+ socketc = g_socket_connection_factory_create_connection(socket);
+ if (!socketc) {
+ error_report("Failed to create socket connection");
+ return NULL;
+ }
+
+ conn = g_dbus_connection_new_sync(
+ G_IO_STREAM(socketc), NULL,
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
+ G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
+ NULL, NULL, &err);
+ if (!conn) {
+ error_report("Failed to create D-Bus connection: %s", err->message);
+ return NULL;
+ }
+
+ return conn;
+}
+
+static gpointer
+p2p_server_setup_thread(gpointer data)
+{
+ return dbus_p2p_from_fd(GPOINTER_TO_INT(data));
+}
+
+GThread *
+p2p_dbus_thread_new(int fd)
+{
+ return g_thread_new("p2p-server-setup",
+ p2p_server_setup_thread,
+ GINT_TO_POINTER(fd));
+}
diff --git a/meson_options.txt b/meson_options.txt
index 31d5916cfce..ef938e74793 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -119,6 +119,8 @@ option('vfio_user_server', type: 'feature', value: 'disabled',
description: 'vfio-user server support')
option('dbus_display', type: 'feature', value: 'auto',
description: '-display dbus support')
+option('qemu_vnc', type: 'feature', value: 'auto',
+ description: 'standalone VNC server over D-Bus')
option('tpm', type : 'feature', value : 'auto',
description: 'TPM support')
option('valgrind', type : 'feature', value: 'auto',
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index ca5b113119a..5f7a351ca4a 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -174,6 +174,7 @@ meson_options_help() {
printf "%s\n" ' qatzip QATzip compression support'
printf "%s\n" ' qcow1 qcow1 image format support'
printf "%s\n" ' qed qed image format support'
+ printf "%s\n" ' qemu-vnc standalone VNC server over D-Bus'
printf "%s\n" ' qga-vss build QGA VSS support (broken with MinGW)'
printf "%s\n" ' qpl Query Processing Library support'
printf "%s\n" ' rbd Ceph block device driver'
@@ -458,6 +459,8 @@ _meson_option_parse() {
--qemu-ga-manufacturer=*) quote_sh "-Dqemu_ga_manufacturer=$2" ;;
--qemu-ga-version=*) quote_sh "-Dqemu_ga_version=$2" ;;
--with-suffix=*) quote_sh "-Dqemu_suffix=$2" ;;
+ --enable-qemu-vnc) printf "%s" -Dqemu_vnc=enabled ;;
+ --disable-qemu-vnc) printf "%s" -Dqemu_vnc=disabled ;;
--enable-qga-vss) printf "%s" -Dqga_vss=enabled ;;
--disable-qga-vss) printf "%s" -Dqga_vss=disabled ;;
--enable-qom-cast-debug) printf "%s" -Dqom_cast_debug=true ;;
diff --git a/tests/dbus-daemon.sh b/tests/dbus-daemon.sh
index c4a50c73774..85f9597db43 100755
--- a/tests/dbus-daemon.sh
+++ b/tests/dbus-daemon.sh
@@ -62,9 +62,17 @@ write_config()
<deny send_destination="org.freedesktop.DBus"
send_interface="org.freedesktop.systemd1.Activator"/>
- <allow own="org.qemu.VMState1"/>
- <allow send_destination="org.qemu.VMState1"/>
- <allow receive_sender="org.qemu.VMState1"/>
+ <allow own="org.qemu"/>
+ <allow send_destination="org.qemu"/>
+ <allow receive_sender="org.qemu"/>
+
+ <allow own="org.qemu.VMState1"/>
+ <allow send_destination="org.qemu.VMState1"/>
+ <allow receive_sender="org.qemu.VMState1"/>
+
+ <allow own="org.qemu.vnc"/>
+ <allow send_destination="org.qemu.vnc"/>
+ <allow receive_sender="org.qemu.vnc"/>
</policy>
diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build
index 5f8cff172c8..e9d23003f8c 100644
--- a/tests/qtest/meson.build
+++ b/tests/qtest/meson.build
@@ -411,6 +411,15 @@ if vnc.found()
if gvnc.found()
qtests += {'vnc-display-test': [gvnc, keymap_targets]}
qtests_generic += [ 'vnc-display-test' ]
+ if have_qemu_vnc and dbus_display and config_all_devices.has_key('CONFIG_VGA')
+ dbus_vnc_test_deps = [dbus_display1, qemu_vnc1, gio, gvnc, keymap_targets]
+ if gnutls.found() and tasn1.found()
+ dbus_vnc_test_deps += [files('../unit/crypto-tls-x509-helpers.c'),
+ gnutls, tasn1]
+ endif
+ qtests += {'dbus-vnc-test': dbus_vnc_test_deps}
+ qtests_x86_64 += ['dbus-vnc-test']
+ endif
endif
endif
@@ -442,6 +451,10 @@ foreach dir : target_dirs
qtest_env.set('QTEST_QEMU_STORAGE_DAEMON_BINARY', './storage-daemon/qemu-storage-daemon')
test_deps += [qsd]
endif
+ if have_qemu_vnc
+ qtest_env.set('QTEST_QEMU_VNC_BINARY', './tools/qemu-vnc/qemu-vnc')
+ test_deps += [qemu_vnc]
+ endif
qtest_env.set('PYTHON', python.full_path())
diff --git a/tools/qemu-vnc/meson.build b/tools/qemu-vnc/meson.build
new file mode 100644
index 00000000000..08168da0630
--- /dev/null
+++ b/tools/qemu-vnc/meson.build
@@ -0,0 +1,26 @@
+vnca = vnc_ss.apply({}, strict: false)
+
+qemu_vnc1 = custom_target('qemu-vnc1 gdbus-codegen',
+ output: ['qemu-vnc1.h', 'qemu-vnc1.c'],
+ input: files('qemu-vnc1.xml'),
+ command: [gdbus_codegen, '@INPUT@',
+ '--glib-min-required', '2.64',
+ '--output-directory', meson.current_build_dir(),
+ '--interface-prefix', 'org.qemu.',
+ '--c-namespace', 'Qemu',
+ '--generate-c-code', '@BASENAME@'])
+
+qemu_vnc = executable('qemu-vnc',
+ sources: ['qemu-vnc.c', 'display.c', 'input.c',
+ 'audio.c', 'chardev.c', 'clipboard.c', 'console.c',
+ 'dbus.c', 'stubs.c', 'utils.c',
+ vnca.sources(), dbus_display1, qemu_vnc1],
+ dependencies: [vnca.dependencies(), io, crypto, qemuutil, gio, ui])
+
+# The executable lives in a subdirectory of the build tree, but
+# get_relocated_path() looks for qemu-bundle relative to the binary.
+# Create a symlink so that firmware/keymap lookup works during development.
+run_command('ln', '-sfn',
+ '../../qemu-bundle',
+ meson.current_build_dir() / 'qemu-bundle',
+ check: false)
diff --git a/tools/qemu-vnc/qemu-vnc1.xml b/tools/qemu-vnc/qemu-vnc1.xml
new file mode 100644
index 00000000000..2037e72ae2a
--- /dev/null
+++ b/tools/qemu-vnc/qemu-vnc1.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="utf-8"?>
+<node>
+ <!--
+ org.qemu.Vnc1.Server:
+
+ This interface is implemented on ``/org/qemu/Vnc1/Server``.
+ It provides management and monitoring of the VNC server.
+ -->
+ <interface name="org.qemu.Vnc1.Server">
+ <!--
+ Name:
+
+ The VM name.
+ -->
+ <property name="Name" type="s" access="read"/>
+
+ <!--
+ Auth:
+
+ Primary authentication method (none, vnc, vencrypt, sasl, etc.).
+ -->
+ <property name="Auth" type="s" access="read"/>
+
+ <!--
+ VencryptSubAuth:
+
+ VEncrypt sub-authentication method, if applicable.
+ Empty string otherwise.
+ -->
+ <property name="VencryptSubAuth" type="s" access="read"/>
+
+ <!--
+ Clients:
+
+ Object paths of connected VNC clients.
+ -->
+ <property name="Clients" type="ao" access="read"/>
+
+ <!--
+ Listeners:
+
+ List of listening sockets. Each entry is a dictionary with keys:
+ ``Host`` (s), ``Service`` (s), ``Family`` (s),
+ ``WebSocket`` (b), ``Auth`` (s), ``VencryptSubAuth`` (s).
+ -->
+ <property name="Listeners" type="aa{sv}" access="read"/>
+
+ <!--
+ SetPassword:
+ @password: The new VNC password.
+
+ Change the VNC password. Existing clients are unaffected.
+ -->
+ <method name="SetPassword">
+ <arg type="s" name="password" direction="in"/>
+ </method>
+
+ <!--
+ ExpirePassword:
+ @time: Expiry specification.
+
+ Set password expiry. Values: ``"now"``, ``"never"``,
+ ``"+N"`` (seconds from now), ``"N"`` (absolute epoch seconds).
+ -->
+ <method name="ExpirePassword">
+ <arg type="s" name="time" direction="in"/>
+ </method>
+
+ <!--
+ ReloadCertificates:
+
+ Reload TLS certificates from disk.
+ -->
+ <method name="ReloadCertificates"/>
+
+ <!--
+ ClientConnected:
+ @client: Object path of the new client.
+
+ Emitted when a VNC client TCP connection is established
+ (before authentication).
+ -->
+ <signal name="ClientConnected">
+ <arg type="o" name="client"/>
+ </signal>
+
+ <!--
+ ClientInitialized:
+ @client: Object path of the client.
+
+ Emitted when a VNC client has completed authentication
+ and is active.
+ -->
+ <signal name="ClientInitialized">
+ <arg type="o" name="client"/>
+ </signal>
+
+ <!--
+ ClientDisconnected:
+ @client: Object path of the client.
+
+ Emitted when a VNC client disconnects.
+ -->
+ <signal name="ClientDisconnected">
+ <arg type="o" name="client"/>
+ </signal>
+ </interface>
+
+ <!--
+ org.qemu.Vnc1.Client:
+
+ This interface is implemented on ``/org/qemu/Vnc1/Client_$id``.
+ It exposes information about a connected VNC client.
+ -->
+ <interface name="org.qemu.Vnc1.Client">
+ <!--
+ Host:
+
+ Client IP address.
+ -->
+ <property name="Host" type="s" access="read"/>
+
+ <!--
+ Service:
+
+ Client port or service name. This may depend on the host system’s
+ service database so symbolic names should not be relied on.
+ -->
+ <property name="Service" type="s" access="read"/>
+
+ <!--
+ Family:
+
+ Address family (ipv4, ipv6, unix).
+ -->
+ <property name="Family" type="s" access="read"/>
+
+ <!--
+ WebSocket:
+
+ Whether this is a WebSocket connection.
+ -->
+ <property name="WebSocket" type="b" access="read"/>
+
+ <!--
+ X509Dname:
+
+ X.509 distinguished name (empty if not applicable).
+ -->
+ <property name="X509Dname" type="s" access="read"/>
+
+ <!--
+ SaslUsername:
+
+ SASL username (empty if not applicable).
+ -->
+ <property name="SaslUsername" type="s" access="read"/>
+
+ <!--
+ ShutdownRequest:
+
+ Emitted when the VNC client requests a guest shutdown.
+ -->
+ <signal name="ShutdownRequest"/>
+
+ <!--
+ ResetRequest:
+
+ Emitted when the VNC client requests a guest reset.
+ -->
+ <signal name="ResetRequest"/>
+ </interface>
+
+</node>
diff --git a/tools/qemu-vnc/trace-events b/tools/qemu-vnc/trace-events
new file mode 100644
index 00000000000..f2d66a80986
--- /dev/null
+++ b/tools/qemu-vnc/trace-events
@@ -0,0 +1,20 @@
+qemu_vnc_audio_out_fini(uint64_t id) "id=%" PRIu64
+qemu_vnc_audio_out_init(uint64_t id, uint32_t freq, uint8_t channels, uint8_t bits) "id=%" PRIu64 " freq=%u ch=%u bits=%u"
+qemu_vnc_audio_out_set_enabled(uint64_t id, bool enabled) "id=%" PRIu64 " enabled=%d"
+qemu_vnc_audio_out_write(uint64_t id, size_t size) "id=%" PRIu64 " size=%zu"
+qemu_vnc_chardev_connected(const char *name) "name=%s"
+qemu_vnc_clipboard_grab(int selection, uint32_t serial) "selection=%d serial=%u"
+qemu_vnc_clipboard_release(int selection) "selection=%d"
+qemu_vnc_clipboard_request(int selection) "selection=%d"
+qemu_vnc_client_not_found(const char *host, const char *service) "host=%s service=%s"
+qemu_vnc_console_io_error(const char *name) "name=%s"
+qemu_vnc_cursor_define(int width, int height, int hot_x, int hot_y) "w=%d h=%d hot=%d,%d"
+qemu_vnc_input_abs(uint32_t x, uint32_t y) "x=%u y=%u"
+qemu_vnc_input_btn(int button, bool press) "button=%d press=%d"
+qemu_vnc_input_rel(int dx, int dy) "dx=%d dy=%d"
+qemu_vnc_key_event(int qcode, bool down) "qcode=%d down=%d"
+qemu_vnc_owner_vanished(const char *name) "peer=%s"
+qemu_vnc_scanout(uint32_t width, uint32_t height, uint32_t stride, uint32_t format) "w=%u h=%u stride=%u fmt=0x%x"
+qemu_vnc_scanout_map(uint32_t width, uint32_t height, uint32_t stride, uint32_t format, uint32_t offset) "w=%u h=%u stride=%u fmt=0x%x offset=%u"
+qemu_vnc_update(int x, int y, int w, int h, uint32_t stride, uint32_t format) "x=%d y=%d w=%d h=%d stride=%u fmt=0x%x"
+qemu_vnc_update_map(uint32_t x, uint32_t y, uint32_t w, uint32_t h) "x=%u y=%u w=%u h=%u"
--
2.53.0
^ permalink raw reply related [flat|nested] 100+ messages in thread
* Re: [PATCH v2 29/67] ui/console: remove console_ch_t typedef and console_write_ch()
2026-04-10 19:18 ` [PATCH v2 29/67] ui/console: remove console_ch_t typedef and console_write_ch() Marc-André Lureau
@ 2026-04-11 22:24 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:24 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:18, Marc-André Lureau wrote:
> 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.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/ui/console.h | 11 ++---------
> 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, 27 insertions(+), 35 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free()
2026-04-10 19:19 ` [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free() Marc-André Lureau
@ 2026-04-11 22:26 ` Philippe Mathieu-Daudé
2026-04-12 14:10 ` Marc-André Lureau
2026-04-15 11:31 ` Daniel P. Berrangé
1 sibling, 1 reply; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:26 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:19, Marc-André Lureau wrote:
> Enable callers to properly tear down keyboard layouts.
>
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/keymaps.h | 1 +
> ui/keymaps.c | 13 ++++++++++---
> 2 files changed, 11 insertions(+), 3 deletions(-)
> diff --git a/ui/keymaps.c b/ui/keymaps.c
> index 2359dbfe7e6..d1b3f43dc8a 100644
> --- a/ui/keymaps.c
> +++ b/ui/keymaps.c
> @@ -178,6 +178,14 @@ out:
> return ret;
> }
>
> +void kbd_layout_free(kbd_layout_t *k)
> +{
> + if (!k) {
> + return;
> + }
> + g_hash_table_unref(k->hash);
> + g_free(k);
> +}
>
> kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
> const char *language, Error **errp)
Worth renaming kbd_layout_new/init?
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private
2026-04-10 19:19 ` [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private Marc-André Lureau
@ 2026-04-11 22:27 ` Philippe Mathieu-Daudé
2026-04-15 11:34 ` Daniel P. Berrangé
1 sibling, 0 replies; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:27 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:19, Marc-André Lureau wrote:
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.h | 1 -
> ui/vnc.c | 3 ++-
> 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool
2026-04-10 19:19 ` [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool Marc-André Lureau
@ 2026-04-11 22:28 ` Philippe Mathieu-Daudé
2026-04-12 14:12 ` Marc-André Lureau
2026-04-15 16:11 ` Daniel P. Berrangé
1 sibling, 1 reply; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:28 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:19, Marc-André Lureau wrote:
> Use the QEMU-style error pattern returning "true" on success.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/ui/console.h | 4 ++--
> ui/vnc.c | 20 ++++++++++----------
> 2 files changed, 12 insertions(+), 12 deletions(-)
> @@ -4354,12 +4356,10 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
vnc_init_func() could also return a boolean.
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> 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;
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open()
2026-04-10 19:19 ` [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open() Marc-André Lureau
@ 2026-04-11 22:31 ` Philippe Mathieu-Daudé
2026-04-12 14:17 ` Marc-André Lureau
0 siblings, 1 reply; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:31 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:19, Marc-André Lureau wrote:
> 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.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/ui/console.h | 2 --
> ui/vnc.h | 3 +++
> ui/vnc.c | 75 ++++++++++++++++++++++------------------------------
> 3 files changed, 35 insertions(+), 45 deletions(-)
> -bool vnc_display_init(const char *id, Error **errp)
> +VncDisplay *vnc_display_new(const char *id, Error **errp)
> {
> VncDisplay *vd;
>
> if (vnc_display_find(id) != NULL) {
> - return true;
> + return NULL;
Can you explain why we don't return the VncDisplay found here?
> }
> vd = g_malloc0(sizeof(*vd));
>
> @@ -3451,7 +3451,7 @@ bool vnc_display_init(const char *id, Error **errp)
>
> if (!vd->kbd_layout) {
> vnc_display_free(vd);
> - return false;
> + return NULL;
> }
>
> vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
> @@ -3464,8 +3464,13 @@ bool vnc_display_init(const char *id, Error **errp)
> vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
> &vmstate_change_handler, vd);
>
> + if (!vnc_display_open(vd, errp)) {
> + vnc_display_free(vd);
> + return NULL;
> + }
> +
> QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
> - return true;
> + return vd;
> }
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 50/67] ui/vnc: report an error for duplicate display id
2026-04-10 19:19 ` [PATCH v2 50/67] ui/vnc: report an error for duplicate display id Marc-André Lureau
@ 2026-04-11 22:33 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:33 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel; +Cc: Daniel P. Berrangé
On 10/4/26 21:19, Marc-André Lureau wrote:
> Returning NULL without setting an error is odd.
>
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/ui/vnc.c b/ui/vnc.c
> index c26b581f3ef..6f9cc3f25a3 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -3430,6 +3430,7 @@ VncDisplay *vnc_display_new(const char *id, Error **errp)
> VncDisplay *vd;
>
> if (vnc_display_find(id) != NULL) {
> + error_setg(errp, "Display '%s' already exists", id);
Ah. That should get squashed in patch #48 "merge vnc_display_init() and
vnc_display_open()" and answer my previous question there.
> return NULL;
> }
> vd = g_malloc0(sizeof(*vd));
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 60/67] ui/console: rename public API to use consistent qemu_console_ prefix
2026-04-10 19:19 ` [PATCH v2 60/67] ui/console: rename public API to use consistent qemu_console_ prefix Marc-André Lureau
@ 2026-04-11 22:38 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:38 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:19, Marc-André Lureau wrote:
> 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.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> 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/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 +--
> 56 files changed, 372 insertions(+), 382 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method
2026-04-10 19:18 ` [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method Marc-André Lureau
@ 2026-04-11 22:41 ` Philippe Mathieu-Daudé
2026-04-12 14:45 ` Marc-André Lureau
0 siblings, 1 reply; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:41 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel; +Cc: Daniel P. Berrangé
On 10/4/26 21:18, Marc-André Lureau wrote:
> Replace the type-checking chain in qemu_console_get_label() (using
> QEMU_IS_GRAPHIC_CONSOLE/QEMU_IS_TEXT_CONSOLE) with a QemuConsoleClass
> virtual method, allowing each console subclass to provide its own
> get_label implementation.
>
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/ui/console.h | 2 +
> ui/console-priv.h | 1 -
> ui/console-vc-stubs.c | 6 ---
> ui/console-vc.c | 12 ++++--
> ui/console.c | 101 +++++++++++++++++++++++++++-----------------------
> 5 files changed, 65 insertions(+), 57 deletions(-)
>
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 08082389f71..395a723e318 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -129,6 +129,8 @@ void console_handle_touch_event(QemuConsole *con,
>
> struct QemuConsoleClass {
> ObjectClass parent_class;
> +
> + char * (*get_label)(QemuConsole *con);
Preferably 'const QemuConsole *con', otherwise:
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> };
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 08/67] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen)
2026-04-10 19:18 ` [PATCH v2 08/67] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen) Marc-André Lureau
@ 2026-04-11 22:42 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-11 22:42 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel; +Cc: Daniel P. Berrangé
On 10/4/26 21:18, Marc-André Lureau wrote:
> The loop condition used `y <= s->height` instead of `y < s->height`,
> causing vc_clear_xy() to be called with y == s->height. This clears
> a row in the scrollback buffer beyond the visible screen.
>
> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/console-vc.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free()
2026-04-11 22:26 ` Philippe Mathieu-Daudé
@ 2026-04-12 14:10 ` Marc-André Lureau
0 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-12 14:10 UTC (permalink / raw)
To: Philippe Mathieu-Daudé; +Cc: qemu-devel
hi
On Sun, Apr 12, 2026 at 2:27 AM Philippe Mathieu-Daudé
<philmd@linaro.org> wrote:
>
> On 10/4/26 21:19, Marc-André Lureau wrote:
> > Enable callers to properly tear down keyboard layouts.
> >
> > Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > ui/keymaps.h | 1 +
> > ui/keymaps.c | 13 ++++++++++---
> > 2 files changed, 11 insertions(+), 3 deletions(-)
>
>
> > diff --git a/ui/keymaps.c b/ui/keymaps.c
> > index 2359dbfe7e6..d1b3f43dc8a 100644
> > --- a/ui/keymaps.c
> > +++ b/ui/keymaps.c
> > @@ -178,6 +178,14 @@ out:
> > return ret;
> > }
> >
> > +void kbd_layout_free(kbd_layout_t *k)
> > +{
> > + if (!k) {
> > + return;
> > + }
> > + g_hash_table_unref(k->hash);
> > + g_free(k);
> > +}
> >
> > kbd_layout_t *init_keyboard_layout(const name2keysym_t *table,
> > const char *language, Error **errp)
>
> Worth renaming kbd_layout_new/init?
sure
>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>
thanks
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool
2026-04-11 22:28 ` Philippe Mathieu-Daudé
@ 2026-04-12 14:12 ` Marc-André Lureau
0 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-12 14:12 UTC (permalink / raw)
To: Philippe Mathieu-Daudé; +Cc: qemu-devel
Hi
On Sun, Apr 12, 2026 at 2:28 AM Philippe Mathieu-Daudé
<philmd@linaro.org> wrote:
>
> On 10/4/26 21:19, Marc-André Lureau wrote:
> > Use the QEMU-style error pattern returning "true" on success.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > include/ui/console.h | 4 ++--
> > ui/vnc.c | 20 ++++++++++----------
> > 2 files changed, 12 insertions(+), 12 deletions(-)
>
>
> > @@ -4354,12 +4356,10 @@ int vnc_init_func(void *opaque, QemuOpts *opts, Error **errp)
>
> vnc_init_func() could also return a boolean.
it must be of type:
typedef int (*qemu_opt_loopfunc)(void *opaque, const char *name, const
char *value, Error **errp);
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
thanks
>
> > 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;
> >
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open()
2026-04-11 22:31 ` Philippe Mathieu-Daudé
@ 2026-04-12 14:17 ` Marc-André Lureau
2026-04-12 20:57 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-12 14:17 UTC (permalink / raw)
To: Philippe Mathieu-Daudé; +Cc: qemu-devel
Hi
On Sun, Apr 12, 2026 at 2:31 AM Philippe Mathieu-Daudé
<philmd@linaro.org> wrote:
>
> On 10/4/26 21:19, Marc-André Lureau wrote:
> > 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.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > include/ui/console.h | 2 --
> > ui/vnc.h | 3 +++
> > ui/vnc.c | 75 ++++++++++++++++++++++------------------------------
> > 3 files changed, 35 insertions(+), 45 deletions(-)
>
>
> > -bool vnc_display_init(const char *id, Error **errp)
> > +VncDisplay *vnc_display_new(const char *id, Error **errp)
> > {
> > VncDisplay *vd;
> >
> > if (vnc_display_find(id) != NULL) {
> > - return true;
> > + return NULL;
>
> Can you explain why we don't return the VncDisplay found here?
`vnc_display_new()` is called from `vnc_init_func()`. If we have
duplicate IDs, the function returns NULL, which is treated as an
error.
Duplicate IDs are handled earlier by qemu_opts_create() though. So we
could assert() instead ?
>
> > }
> > vd = g_malloc0(sizeof(*vd));
> >
> > @@ -3451,7 +3451,7 @@ bool vnc_display_init(const char *id, Error **errp)
> >
> > if (!vd->kbd_layout) {
> > vnc_display_free(vd);
> > - return false;
> > + return NULL;
> > }
> >
> > vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
> > @@ -3464,8 +3464,13 @@ bool vnc_display_init(const char *id, Error **errp)
> > vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
> > &vmstate_change_handler, vd);
> >
> > + if (!vnc_display_open(vd, errp)) {
> > + vnc_display_free(vd);
> > + return NULL;
> > + }
> > +
> > QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
> > - return true;
> > + return vd;
> > }
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method
2026-04-11 22:41 ` Philippe Mathieu-Daudé
@ 2026-04-12 14:45 ` Marc-André Lureau
0 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-12 14:45 UTC (permalink / raw)
To: Philippe Mathieu-Daudé; +Cc: qemu-devel, Daniel P. Berrangé
Hi
On Sun, Apr 12, 2026 at 2:41 AM Philippe Mathieu-Daudé
<philmd@linaro.org> wrote:
>
> On 10/4/26 21:18, Marc-André Lureau wrote:
> > Replace the type-checking chain in qemu_console_get_label() (using
> > QEMU_IS_GRAPHIC_CONSOLE/QEMU_IS_TEXT_CONSOLE) with a QemuConsoleClass
> > virtual method, allowing each console subclass to provide its own
> > get_label implementation.
> >
> > Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > include/ui/console.h | 2 +
> > ui/console-priv.h | 1 -
> > ui/console-vc-stubs.c | 6 ---
> > ui/console-vc.c | 12 ++++--
> > ui/console.c | 101 +++++++++++++++++++++++++++-----------------------
> > 5 files changed, 65 insertions(+), 57 deletions(-)
> >
> > diff --git a/include/ui/console.h b/include/ui/console.h
> > index 08082389f71..395a723e318 100644
> > --- a/include/ui/console.h
> > +++ b/include/ui/console.h
> > @@ -129,6 +129,8 @@ void console_handle_touch_event(QemuConsole *con,
> >
> > struct QemuConsoleClass {
> > ObjectClass parent_class;
> > +
> > + char * (*get_label)(QemuConsole *con);
>
> Preferably 'const QemuConsole *con', otherwise:
>
good point
thanks
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
>
> > };
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open()
2026-04-12 14:17 ` Marc-André Lureau
@ 2026-04-12 20:57 ` Philippe Mathieu-Daudé
2026-04-15 16:14 ` Daniel P. Berrangé
0 siblings, 1 reply; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-12 20:57 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On 12/4/26 16:17, Marc-André Lureau wrote:
> Hi
>
> On Sun, Apr 12, 2026 at 2:31 AM Philippe Mathieu-Daudé
> <philmd@linaro.org> wrote:
>>
>> On 10/4/26 21:19, Marc-André Lureau wrote:
>>> 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.
>>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>> include/ui/console.h | 2 --
>>> ui/vnc.h | 3 +++
>>> ui/vnc.c | 75 ++++++++++++++++++++++------------------------------
>>> 3 files changed, 35 insertions(+), 45 deletions(-)
>>
>>
>>> -bool vnc_display_init(const char *id, Error **errp)
>>> +VncDisplay *vnc_display_new(const char *id, Error **errp)
>>> {
>>> VncDisplay *vd;
>>>
>>> if (vnc_display_find(id) != NULL) {
>>> - return true;
>>> + return NULL;
>>
>> Can you explain why we don't return the VncDisplay found here?
>
> `vnc_display_new()` is called from `vnc_init_func()`. If we have
> duplicate IDs, the function returns NULL, which is treated as an
> error.
>
> Duplicate IDs are handled earlier by qemu_opts_create() though. So we
> could assert() instead ?
That would make this code path clearer for sure.
>
>>
>>> }
>>> vd = g_malloc0(sizeof(*vd));
>>>
>>> @@ -3451,7 +3451,7 @@ bool vnc_display_init(const char *id, Error **errp)
>>>
>>> if (!vd->kbd_layout) {
>>> vnc_display_free(vd);
>>> - return false;
>>> + return NULL;
>>> }
>>>
>>> vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
>>> @@ -3464,8 +3464,13 @@ bool vnc_display_init(const char *id, Error **errp)
>>> vd->vmstate_handler_entry = qemu_add_vm_change_state_handler(
>>> &vmstate_change_handler, vd);
>>>
>>> + if (!vnc_display_open(vd, errp)) {
>>> + vnc_display_free(vd);
>>> + return NULL;
>>> + }
>>> +
>>> QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
>>> - return true;
>>> + return vd;
>>> }
>>
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 06/67] ui/vnc-jobs: narrow taking the queue lock
2026-04-10 19:18 ` [PATCH v2 06/67] ui/vnc-jobs: narrow taking the queue lock Marc-André Lureau
@ 2026-04-15 9:17 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 9:17 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:18:28PM +0400, Marc-André Lureau wrote:
> It's not needed unless manipulating the queue.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc-jobs.c | 17 +++++++++++------
> 1 file changed, 11 insertions(+), 6 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 10/67] ui/console-vc: ignore string-type escape sequences
2026-04-10 19:18 ` [PATCH v2 10/67] ui/console-vc: ignore string-type escape sequences Marc-André Lureau
@ 2026-04-15 9:19 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 9:19 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:18:32PM +0400, Marc-André Lureau wrote:
> Modern terminals and applications emit OSC (Operating System Command),
> DCS, SOS, PM, and APC escape sequences (e.g. for setting window
> titles). The text console currently does not recognise these
> string-type introducers, so each byte of the payload is interpreted as
> a normal character or a new escape, producing garbage on screen.
>
> Add a TTY_STATE_OSC state that silently consumes all bytes until the
> sequence is terminated by BEL or ST (ESC \).
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/console-vc.c | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering
2026-04-10 19:18 ` [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering Marc-André Lureau
@ 2026-04-15 11:24 ` Daniel P. Berrangé
2026-04-20 7:54 ` Marc-André Lureau
0 siblings, 1 reply; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:24 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:18:31PM +0400, Marc-André Lureau wrote:
> 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.
Presumably the key words here are "may be" .... as in, it
also "may NOT be" UTF-8.
IIUC, the current code is assuming that all data from the guest
is in the CP437 encoding (8-bit Extended ASCII), and that encoding
has valid characters for all 256 code points.
By adding UTF-8 decoding for val > 0x80 this is breaking compat
with any guest that is outputting data with the full range of
CP437.
IOW, this patch is moving the brokeness from guests which
use UTF8, onto guests which use CP437.
Only guests which strictly limit themselves to 7-bit ASCII
are unaffected.
I accept the UTF8 should probably be considered the common
case for modern guests, but this hardcoding a different type
of breakage feels undesirable to me.
Surely we need an explicit config property here to select
the between character sets we expect from the guest ?
>
> 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.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/cp437.h | 13 ++++
> ui/console-vc.c | 61 +++++++++++++++++
> ui/cp437.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ui/meson.build | 2 +-
> 4 files changed, 280 insertions(+), 1 deletion(-)
>
> diff --git a/ui/cp437.h b/ui/cp437.h
> new file mode 100644
> index 00000000000..81ace8317c7
> --- /dev/null
> +++ b/ui/cp437.h
> @@ -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 */
> diff --git a/ui/console-vc.c b/ui/console-vc.c
> index 8dee1f9bd01..d9d6966410a 100644
> --- a/ui/console-vc.c
> +++ b/ui/console-vc.c
> @@ -9,6 +9,7 @@
> #include "qemu/fifo8.h"
> #include "qemu/option.h"
> #include "ui/console.h"
> +#include "ui/cp437.h"
>
> #include "trace.h"
> #include "console-priv.h"
> @@ -89,6 +90,8 @@ struct VCChardev {
> 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;
> @@ -598,6 +601,46 @@ static void vc_clear_xy(VCChardev *vc, int x, int y)
> vc_update_xy(vc, x, y);
> }
>
> +/*
> + * UTF-8 DFA decoder by Bjoern Hoehrmann.
> + * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
> + * See https://github.com/polijan/utf8_decode for details.
> + *
> + * SPDX-License-Identifier: MIT
> + */
> +#define BH_UTF8_ACCEPT 0
> +#define BH_UTF8_REJECT 12
> +
> +static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
> +{
> + static const uint8_t utf8d[] = {
> + /* character class lookup */
> + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
> + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
> + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
> +
> + /* state transition lookup */
> + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
> + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
> + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
> + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
> + 12,36,12,12,12,12,12,12,12,12,12,12,
> + };
> + uint32_t type = utf8d[byte];
> +
> + *codep = (*state != BH_UTF8_ACCEPT) ?
> + (byte & 0x3fu) | (*codep << 6) :
> + (0xffu >> type) & (byte);
> +
> + *state = utf8d[256 + *state + type];
> + return *state;
> +}
> +
> static void vc_put_one(VCChardev *vc, int ch)
> {
> QemuTextConsole *s = vc->console;
> @@ -761,6 +804,24 @@ static void vc_putchar(VCChardev *vc, int ch)
>
> switch(vc->state) {
> case TTY_STATE_NORM:
> + /* Feed byte through the UTF-8 DFA decoder */
> + if (ch >= 0x80) {
> + switch (bh_utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
> + case BH_UTF8_ACCEPT:
> + vc_put_one(vc, unicode_to_cp437(vc->utf8_codepoint));
> + break;
> + case BH_UTF8_REJECT:
> + /* Reset state so the decoder can resync */
> + vc->utf8_state = BH_UTF8_ACCEPT;
> + break;
> + default:
> + /* Need more bytes */
> + break;
> + }
> + break;
> + }
> + /* ASCII byte: abort any pending UTF-8 sequence */
> + vc->utf8_state = BH_UTF8_ACCEPT;
> switch(ch) {
> case '\r': /* carriage return */
> s->x = 0;
> diff --git a/ui/cp437.c b/ui/cp437.c
> new file mode 100644
> index 00000000000..8ec38b73419
> --- /dev/null
> +++ b/ui/cp437.c
> @@ -0,0 +1,205 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * Copyright (c) QEMU contributors
> + */
> +#include "qemu/osdep.h"
> +#include "cp437.h"
> +
> +/*
> + * Unicode to CP437 page tables.
> + *
> + * Borrowed from the Linux kernel (fs/nls/nls_cp437.c, "Dual BSD/GPL"),
> + * generated from the Unicode Organization tables (www.unicode.org).
> + */
> +static const unsigned char uni2cp437_page00[256] = {
> + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
> + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
> + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
> + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
> + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
> + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
> + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
> + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
> + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
> + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
> + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
> + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
> + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
> + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
> + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
> + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
> +
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> + 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
> + 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
> + 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
> + 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
> + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
> + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
> + 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
> + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
> + 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
> + 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
> + 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
> + 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
> +};
> +
> +static const unsigned char uni2cp437_page01[256] = {
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> +
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> + 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> +};
> +
> +static const unsigned char uni2cp437_page03[256] = {
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> +
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> + 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> + 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> + 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
> + 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
> + 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
> + 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
> +};
> +
> +static const unsigned char uni2cp437_page20[256] = {
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
> +
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
> +};
> +
> +static const unsigned char uni2cp437_page22[256] = {
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> + 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> + 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> + 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> + 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
> +};
> +
> +static const unsigned char uni2cp437_page23[256] = {
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> + 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> + 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> +};
> +
> +static const unsigned char uni2cp437_page25[256] = {
> + 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> + 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> + 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> + 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> + 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> + 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> + 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> + 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
> + 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
> + 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
> + 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> +
> + 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> + 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> + 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
> +};
> +
> +static const unsigned char *const uni2cp437_page[256] = {
> + [0x00] = uni2cp437_page00, [0x01] = uni2cp437_page01,
> + [0x03] = uni2cp437_page03, [0x20] = uni2cp437_page20,
> + [0x22] = uni2cp437_page22, [0x23] = uni2cp437_page23,
> + [0x25] = uni2cp437_page25,
> +};
> +
> +/*
> + * Convert a Unicode code point to its CP437 equivalent for
> + * rendering with the VGA font.
> + * Returns '?' for characters that cannot be mapped.
> + */
> +int unicode_to_cp437(uint32_t codepoint)
> +{
> + const unsigned char *page;
> + unsigned char hi = (codepoint >> 8) & 0xff;
> + unsigned char lo = codepoint & 0xff;
> +
> + if (codepoint > 0xffff) {
> + return '?';
> + }
> +
> + page = uni2cp437_page[hi];
> + if (page && page[lo]) {
> + return page[lo];
> + }
> +
> + return '?';
> +}
> diff --git a/ui/meson.build b/ui/meson.build
> index 69404bca71a..d4d9312b98c 100644
> --- a/ui/meson.build
> +++ b/ui/meson.build
> @@ -16,7 +16,7 @@ system_ss.add(files(
> 'ui-qmp-cmds.c',
> 'util.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
>
> --
> 2.53.0
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 38/67] ui: minor code simplification
2026-04-10 19:19 ` [PATCH v2 38/67] ui: minor code simplification Marc-André Lureau
@ 2026-04-15 11:25 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:25 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel, Philippe Mathieu-Daudé
On Fri, Apr 10, 2026 at 11:19:00PM +0400, Marc-André Lureau wrote:
> Drop memset() usage.
>
> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/sdl2.c | 8 ++++----
> ui/vnc.c | 6 ++----
> 2 files changed, 6 insertions(+), 8 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free()
2026-04-10 19:19 ` [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free() Marc-André Lureau
2026-04-11 22:26 ` Philippe Mathieu-Daudé
@ 2026-04-15 11:31 ` Daniel P. Berrangé
1 sibling, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:31 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:05PM +0400, Marc-André Lureau wrote:
> Enable callers to properly tear down keyboard layouts.
>
> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/keymaps.h | 1 +
> ui/keymaps.c | 13 ++++++++++---
> 2 files changed, 11 insertions(+), 3 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 44/67] ui/vnc: fix vnc_display_init() leak on failure
2026-04-10 19:19 ` [PATCH v2 44/67] ui/vnc: fix vnc_display_init() leak on failure Marc-André Lureau
@ 2026-04-15 11:34 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:34 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:06PM +0400, Marc-André Lureau wrote:
> Do not add the display state to the vnc list, if the initialization
> failed. Add vnc_display_free(), to free the display state and associated
> data in such case. The function is meant to be public and reused in the
> following changes.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.c | 33 +++++++++++++++++++++++++++++----
> 1 file changed, 29 insertions(+), 4 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private
2026-04-10 19:19 ` [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private Marc-André Lureau
2026-04-11 22:27 ` Philippe Mathieu-Daudé
@ 2026-04-15 11:34 ` Daniel P. Berrangé
1 sibling, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:34 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:07PM +0400, Marc-André Lureau wrote:
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.h | 1 -
> ui/vnc.c | 3 ++-
> 2 files changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 49/67] ui/vnc: add vnc_cleanup()
2026-04-10 19:19 ` [PATCH v2 49/67] ui/vnc: add vnc_cleanup() Marc-André Lureau
@ 2026-04-15 11:56 ` Daniel P. Berrangé
2026-04-20 20:08 ` Marc-André Lureau
0 siblings, 1 reply; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:56 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:11PM +0400, Marc-André Lureau wrote:
> Add a function to tear down VNC displays, call it when leaving QEMU.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/ui/console.h | 1 +
> system/runstate.c | 5 +++++
> ui/vnc.c | 24 ++++++++++++++++++++++++
> 3 files changed, 30 insertions(+)
>
> diff --git a/include/ui/console.h b/include/ui/console.h
> index 1794f1a2cf0..b3aaf3ff12b 100644
> --- a/include/ui/console.h
> +++ b/include/ui/console.h
> @@ -455,6 +455,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);
> diff --git a/system/runstate.c b/system/runstate.c
> index 770253b467b..0e1cb3b4e67 100644
> --- a/system/runstate.c
> +++ b/system/runstate.c
> @@ -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 */
> }
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 4d5b36a6fa8..c26b581f3ef 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -4354,6 +4354,30 @@ 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;
> + VncState *vs;
> +
> + QTAILQ_FOREACH(vd, &vnc_displays, next) {
> + if (vd->listener) {
> + qio_net_listener_disconnect(vd->listener);
> + }
> + if (vd->wslistener) {
> + qio_net_listener_disconnect(vd->wslistener);
> + }
> + QTAILQ_FOREACH(vs, &vd->clients, next) {
> + vnc_disconnect_start(vs);
> + }
> + }
Upto this point, I feel like there is conceptual overlap with
what I'd expect vnc_display_close to be doing, except that its
current impl does not kill off the clients - it doesn't need
to as it is currently only called in a startup path where
(IIUC) we can assume no clients are present.
IOW, could we have this look more like
QTAILQ_FOREACH(vd, &vnc_displays, next) {
vnc_display_close(vd);
}
pushing the vnc_disconnect_start into vnc_display_close.
> + QTAILQ_FOREACH_SAFE(vd, &vnc_displays, next, vd_next) {
> + while (!QTAILQ_EMPTY(&vd->clients)) {
> + main_loop_wait(false);
> + }
Could we push this loop into vnc_display_free, on the assumption
that a call to vnc_display_close be made a documented pre-condition ?
> + vnc_display_free(vd);
> + }
> +}
> +
> static void vnc_register_config(void)
> {
> qemu_add_opts(&qemu_vnc_opts);
>
> --
> 2.53.0
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 53/67] ui/vnc: remove left-over dead code
2026-04-10 19:19 ` [PATCH v2 53/67] ui/vnc: remove left-over dead code Marc-André Lureau
@ 2026-04-15 11:58 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 11:58 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:15PM +0400, Marc-André Lureau wrote:
> Since commit 5994dcb8d85 ("ui, monitor: remove deprecated VNC ACL option
> and HMP commands"), this field is no longer used.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.h | 1 -
> ui/vnc.c | 4 ----
> 2 files changed, 5 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 52/67] ui/vnc: expose vnc_disconnect_start()
2026-04-10 19:19 ` [PATCH v2 52/67] ui/vnc: expose vnc_disconnect_start() Marc-André Lureau
@ 2026-04-15 12:19 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 12:19 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:14PM +0400, Marc-André Lureau wrote:
> This allows VncDisplay users to tear down all clients before freeing the
> VncDisplay for example.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc.h | 1 +
> ui/vnc.c | 3 +--
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/ui/vnc.h b/ui/vnc.h
> index de41517be48..794341265b3 100644
> --- a/ui/vnc.h
> +++ b/ui/vnc.h
> @@ -560,6 +560,7 @@ void vnc_display_free(VncDisplay *vd);
> *****************************************************************************/
>
> /* Event loop functions */
> +void vnc_disconnect_start(VncState *vs);
AFAICT, nothing later in this series calls this, so this patch
looks redundant
> gboolean vnc_client_io(QIOChannel *ioc,
> GIOCondition condition,
> void *opaque);
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 747b1c44e36..6fef80e98c4 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -617,7 +617,6 @@ bool vnc_display_reload_certs(const char *id, Error **errp)
> */
>
> static int vnc_update_client(VncState *vs, int has_dirty);
> -static void vnc_disconnect_start(VncState *vs);
>
> static void vnc_colordepth(VncState *vs);
> static void framebuffer_update_request(VncState *vs, int incremental,
> @@ -1296,7 +1295,7 @@ static void audio_del(VncState *vs)
> }
> }
>
> -static void vnc_disconnect_start(VncState *vs)
> +void vnc_disconnect_start(VncState *vs)
> {
> if (vs->disconnecting) {
> return;
>
> --
> 2.53.0
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay
2026-04-10 19:19 ` [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay Marc-André Lureau
@ 2026-04-15 16:03 ` Daniel P. Berrangé
2026-04-20 15:03 ` Marc-André Lureau
0 siblings, 1 reply; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 16:03 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:08PM +0400, Marc-André Lureau wrote:
> 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.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> ui/vnc-jobs.h | 3 ++-
> ui/vnc.h | 2 ++
> ui/vnc-jobs.c | 76 +++++++++++++++++++++++++++++++++--------------------------
> ui/vnc.c | 3 ++-
> 4 files changed, 49 insertions(+), 35 deletions(-)
>
> diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
> index 5b17ef54091..c809287dd3a 100644
> --- a/ui/vnc-jobs.c
> +++ b/ui/vnc-jobs.c
> @@ -29,8 +29,6 @@
> #include "qemu/osdep.h"
> #include "vnc.h"
> #include "vnc-jobs.h"
> -#include "qemu/sockets.h"
> -#include "qemu/main-loop.h"
> #include "trace.h"
>
> /*
> @@ -56,17 +54,10 @@ struct VncJobQueue {
> QemuCond cond;
> QemuMutex mutex;
> QemuThread thread;
> + bool exit;
> QTAILQ_HEAD(, VncJob) jobs;
> };
>
> -typedef struct VncJobQueue VncJobQueue;
> -
> -/*
> - * We use a single global queue, but most of the functions are
> - * already reentrant, so we can easily add more than one encoding thread
> - */
> -static VncJobQueue *queue;
> -
> static void vnc_lock_queue(VncJobQueue *queue)
> {
> qemu_mutex_lock(&queue->mutex);
> @@ -125,19 +116,22 @@ static void vnc_job_free(VncJob *job)
> */
> void vnc_job_push(VncJob *job)
> {
> + VncJobQueue *queue = job->vs->vd->queue;
> +
> assert(!QTAILQ_IN_USE(job, next));
>
> if (QLIST_EMPTY(&job->rectangles)) {
> vnc_job_free(job);
> } else {
> vnc_lock_queue(queue);
> + assert(!queue->exit);
> QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
> qemu_cond_broadcast(&queue->cond);
> vnc_unlock_queue(queue);
> }
> }
>
> -static bool vnc_has_job_locked(VncState *vs)
> +static bool vnc_has_job_locked(VncJobQueue *queue, VncState *vs)
> {
Instead of passing this I think you could add
VncJobQueue *queue = vs->vd->queue;
which guarantees the queue object matches the state object
instead of leaving that precondition to the caller.
> VncJob *job;
>
> @@ -151,8 +145,10 @@ static bool vnc_has_job_locked(VncState *vs)
>
> void vnc_jobs_join(VncState *vs)
> {
> + VncJobQueue *queue = vs->vd->queue;
> +
> vnc_lock_queue(queue);
> - while (vnc_has_job_locked(vs)) {
> + while (vnc_has_job_locked(queue, vs)) {
> qemu_cond_wait(&queue->cond, &queue->mutex);
> }
> vnc_unlock_queue(queue);
> @@ -252,9 +248,13 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
> int saved_offset;
>
> vnc_lock_queue(queue);
> - while (QTAILQ_EMPTY(&queue->jobs)) {
> + while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
> qemu_cond_wait(&queue->cond, &queue->mutex);
> }
> + if (queue->exit) {
> + vnc_unlock_queue(queue);
> + return 1;
> + }
> job = QTAILQ_FIRST(&queue->jobs);
> vnc_unlock_queue(queue);
>
> @@ -340,39 +340,49 @@ disconnected:
> return 0;
> }
>
> -static VncJobQueue *vnc_queue_init(void)
> -{
> - VncJobQueue *queue = g_new0(VncJobQueue, 1);
> -
> - qemu_cond_init(&queue->cond);
> - qemu_mutex_init(&queue->mutex);
> - QTAILQ_INIT(&queue->jobs);
> - return queue;
> -}
IMHO it makes sense to keep this object allocator
method and call it from...
> -
> static void *vnc_worker_thread(void *arg)
> {
> VncJobQueue *queue = arg;
>
> while (!vnc_worker_thread_loop(queue)) ;
> - g_assert_not_reached();
> +
> return NULL;
> }
>
> -static bool vnc_worker_thread_running(void)
> +void vnc_start_worker_thread(VncDisplay *vd)
> {
> - return queue; /* Check global queue */
> + VncJobQueue *queue;
> +
> + assert(vd->queue == NULL);
> +
> + queue = g_new0(VncJobQueue, 1);
> + qemu_cond_init(&queue->cond);
> + qemu_mutex_init(&queue->mutex);
> + QTAILQ_INIT(&queue->jobs);
> + vd->queue = queue;
....here
vd->queue = vnc_queue_init();
though renaming it to vnc_queue_new() would be more
in keeping with the naming patterns.
> +
> + qemu_thread_create(&queue->thread, "vnc_worker", vnc_worker_thread, queue,
> + QEMU_THREAD_JOINABLE);
> }
>
> -void vnc_start_worker_thread(void)
> +void vnc_stop_worker_thread(VncDisplay *vd)
> {
> - VncJobQueue *q;
> + VncJobQueue *queue = vd->queue;
>
> - if (vnc_worker_thread_running())
> + if (!queue) {
> return;
> + }
> +
> + /* all VNC clients must have finished before we can stop the worker thread */
> + vnc_lock_queue(queue);
> + assert(QTAILQ_EMPTY(&queue->jobs));
> + queue->exit = true;
> + qemu_cond_broadcast(&queue->cond);
> + vnc_unlock_queue(queue);
>
> - q = vnc_queue_init();
> - qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
> - QEMU_THREAD_DETACHED);
> - queue = q; /* Set global queue */
> + qemu_thread_join(&queue->thread);
> + qemu_cond_destroy(&queue->cond);
> + qemu_mutex_destroy(&queue->mutex);
> + g_free(queue);
I'd suggest a vnc_queue_free(queue) method here too
> + vd->queue = NULL;
> }
> diff --git a/ui/vnc.c b/ui/vnc.c
> index ba7376360e6..4e5a9ee0341 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -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);
> @@ -3517,6 +3517,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);
>
> --
> 2.53.0
>
>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool
2026-04-10 19:19 ` [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool Marc-André Lureau
2026-04-11 22:28 ` Philippe Mathieu-Daudé
@ 2026-04-15 16:11 ` Daniel P. Berrangé
1 sibling, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 16:11 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Fri, Apr 10, 2026 at 11:19:09PM +0400, Marc-André Lureau wrote:
> Use the QEMU-style error pattern returning "true" on success.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> include/ui/console.h | 4 ++--
> ui/vnc.c | 20 ++++++++++----------
> 2 files changed, 12 insertions(+), 12 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open()
2026-04-12 20:57 ` Philippe Mathieu-Daudé
@ 2026-04-15 16:14 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-15 16:14 UTC (permalink / raw)
To: Philippe Mathieu-Daudé; +Cc: Marc-André Lureau, qemu-devel
On Sun, Apr 12, 2026 at 10:57:51PM +0200, Philippe Mathieu-Daudé wrote:
> On 12/4/26 16:17, Marc-André Lureau wrote:
> > Hi
> >
> > On Sun, Apr 12, 2026 at 2:31 AM Philippe Mathieu-Daudé
> > <philmd@linaro.org> wrote:
> > >
> > > On 10/4/26 21:19, Marc-André Lureau wrote:
> > > > 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.
> > > >
> > > > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > > > ---
> > > > include/ui/console.h | 2 --
> > > > ui/vnc.h | 3 +++
> > > > ui/vnc.c | 75 ++++++++++++++++++++++------------------------------
> > > > 3 files changed, 35 insertions(+), 45 deletions(-)
> > >
> > >
> > > > -bool vnc_display_init(const char *id, Error **errp)
> > > > +VncDisplay *vnc_display_new(const char *id, Error **errp)
> > > > {
> > > > VncDisplay *vd;
> > > >
> > > > if (vnc_display_find(id) != NULL) {
> > > > - return true;
> > > > + return NULL;
> > >
> > > Can you explain why we don't return the VncDisplay found here?
> >
> > `vnc_display_new()` is called from `vnc_init_func()`. If we have
> > duplicate IDs, the function returns NULL, which is treated as an
> > error.
> >
> > Duplicate IDs are handled earlier by qemu_opts_create() though. So we
> > could assert() instead ?
>
> That would make this code path clearer for sure.
Yeah, an assert(!vnc_display_find(id)) would make sense.
With regards,
Daniel
--
|: https://berrange.com ~~ https://hachyderm.io/@berrange :|
|: https://libvirt.org ~~ https://entangle-photo.org :|
|: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering
2026-04-15 11:24 ` Daniel P. Berrangé
@ 2026-04-20 7:54 ` Marc-André Lureau
2026-04-29 8:30 ` Daniel P. Berrangé
0 siblings, 1 reply; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-20 7:54 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel
Hi
On Wed, Apr 15, 2026 at 3:24 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Fri, Apr 10, 2026 at 11:18:31PM +0400, Marc-André Lureau wrote:
> > 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.
>
> Presumably the key words here are "may be" .... as in, it
> also "may NOT be" UTF-8.
>
> IIUC, the current code is assuming that all data from the guest
> is in the CP437 encoding (8-bit Extended ASCII), and that encoding
> has valid characters for all 256 code points.
>
> By adding UTF-8 decoding for val > 0x80 this is breaking compat
> with any guest that is outputting data with the full range of
> CP437.
>
> IOW, this patch is moving the brokeness from guests which
> use UTF8, onto guests which use CP437.
>
> Only guests which strictly limit themselves to 7-bit ASCII
> are unaffected.
>
> I accept the UTF8 should probably be considered the common
> case for modern guests, but this hardcoding a different type
> of breakage feels undesirable to me.
>
> Surely we need an explicit config property here to select
> the between character sets we expect from the guest ?
Probably, I don't know if many guest/apps rely on the serial encoding,
but we should probably be conservative.
Adjusting the decoding at runtime may be possible, but it could be tricky.
Instead, we could add a vc chardev option like charset=cp437/utf8.
What should be the default? For compatibility reasons, use CP437 for
pc machine <=11.0 and default to utf8 for others? wdyt?
>
> >
> > 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.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > ui/cp437.h | 13 ++++
> > ui/console-vc.c | 61 +++++++++++++++++
> > ui/cp437.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > ui/meson.build | 2 +-
> > 4 files changed, 280 insertions(+), 1 deletion(-)
> >
> > diff --git a/ui/cp437.h b/ui/cp437.h
> > new file mode 100644
> > index 00000000000..81ace8317c7
> > --- /dev/null
> > +++ b/ui/cp437.h
> > @@ -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 */
> > diff --git a/ui/console-vc.c b/ui/console-vc.c
> > index 8dee1f9bd01..d9d6966410a 100644
> > --- a/ui/console-vc.c
> > +++ b/ui/console-vc.c
> > @@ -9,6 +9,7 @@
> > #include "qemu/fifo8.h"
> > #include "qemu/option.h"
> > #include "ui/console.h"
> > +#include "ui/cp437.h"
> >
> > #include "trace.h"
> > #include "console-priv.h"
> > @@ -89,6 +90,8 @@ struct VCChardev {
> > 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;
> > @@ -598,6 +601,46 @@ static void vc_clear_xy(VCChardev *vc, int x, int y)
> > vc_update_xy(vc, x, y);
> > }
> >
> > +/*
> > + * UTF-8 DFA decoder by Bjoern Hoehrmann.
> > + * Copyright (c) 2008-2010 Bjoern Hoehrmann <bjoern@hoehrmann.de>
> > + * See https://github.com/polijan/utf8_decode for details.
> > + *
> > + * SPDX-License-Identifier: MIT
> > + */
> > +#define BH_UTF8_ACCEPT 0
> > +#define BH_UTF8_REJECT 12
> > +
> > +static uint32_t bh_utf8_decode(uint32_t *state, uint32_t *codep, uint32_t byte)
> > +{
> > + static const uint8_t utf8d[] = {
> > + /* character class lookup */
> > + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> > + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> > + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> > + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
> > + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
> > + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
> > + 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
> > + 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
> > +
> > + /* state transition lookup */
> > + 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
> > + 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
> > + 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
> > + 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
> > + 12,36,12,12,12,12,12,12,12,12,12,12,
> > + };
> > + uint32_t type = utf8d[byte];
> > +
> > + *codep = (*state != BH_UTF8_ACCEPT) ?
> > + (byte & 0x3fu) | (*codep << 6) :
> > + (0xffu >> type) & (byte);
> > +
> > + *state = utf8d[256 + *state + type];
> > + return *state;
> > +}
> > +
> > static void vc_put_one(VCChardev *vc, int ch)
> > {
> > QemuTextConsole *s = vc->console;
> > @@ -761,6 +804,24 @@ static void vc_putchar(VCChardev *vc, int ch)
> >
> > switch(vc->state) {
> > case TTY_STATE_NORM:
> > + /* Feed byte through the UTF-8 DFA decoder */
> > + if (ch >= 0x80) {
> > + switch (bh_utf8_decode(&vc->utf8_state, &vc->utf8_codepoint, ch)) {
> > + case BH_UTF8_ACCEPT:
> > + vc_put_one(vc, unicode_to_cp437(vc->utf8_codepoint));
> > + break;
> > + case BH_UTF8_REJECT:
> > + /* Reset state so the decoder can resync */
> > + vc->utf8_state = BH_UTF8_ACCEPT;
> > + break;
> > + default:
> > + /* Need more bytes */
> > + break;
> > + }
> > + break;
> > + }
> > + /* ASCII byte: abort any pending UTF-8 sequence */
> > + vc->utf8_state = BH_UTF8_ACCEPT;
> > switch(ch) {
> > case '\r': /* carriage return */
> > s->x = 0;
> > diff --git a/ui/cp437.c b/ui/cp437.c
> > new file mode 100644
> > index 00000000000..8ec38b73419
> > --- /dev/null
> > +++ b/ui/cp437.c
> > @@ -0,0 +1,205 @@
> > +/*
> > + * SPDX-License-Identifier: GPL-2.0-or-later
> > + *
> > + * Copyright (c) QEMU contributors
> > + */
> > +#include "qemu/osdep.h"
> > +#include "cp437.h"
> > +
> > +/*
> > + * Unicode to CP437 page tables.
> > + *
> > + * Borrowed from the Linux kernel (fs/nls/nls_cp437.c, "Dual BSD/GPL"),
> > + * generated from the Unicode Organization tables (www.unicode.org).
> > + */
> > +static const unsigned char uni2cp437_page00[256] = {
> > + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */
> > + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */
> > + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */
> > + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */
> > + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */
> > + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */
> > + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */
> > + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */
> > + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */
> > + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */
> > + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */
> > + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */
> > + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */
> > + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */
> > + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */
> > + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */
> > +
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> > + 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */
> > + 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
> > + 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */
> > + 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */
> > + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */
> > + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */
> > + 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */
> > + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */
> > + 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */
> > + 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */
> > + 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */
> > + 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */
> > +};
> > +
> > +static const unsigned char uni2cp437_page01[256] = {
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> > +
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> > + 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> > +};
> > +
> > +static const unsigned char uni2cp437_page03[256] = {
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> > +
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> > + 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> > + 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> > + 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */
> > + 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */
> > + 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */
> > + 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */
> > +};
> > +
> > +static const unsigned char uni2cp437_page20[256] = {
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */
> > +
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */
> > +};
> > +
> > +static const unsigned char uni2cp437_page22[256] = {
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> > + 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> > + 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> > + 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */
> > + 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */
> > +};
> > +
> > +static const unsigned char uni2cp437_page23[256] = {
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> > + 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> > + 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> > +};
> > +
> > +static const unsigned char uni2cp437_page25[256] = {
> > + 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */
> > + 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */
> > + 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */
> > + 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */
> > + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */
> > + 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */
> > + 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */
> > + 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */
> > + 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */
> > + 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */
> > + 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */
> > + 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */
> > +
> > + 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */
> > + 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */
> > + 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */
> > + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */
> > + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */
> > +};
> > +
> > +static const unsigned char *const uni2cp437_page[256] = {
> > + [0x00] = uni2cp437_page00, [0x01] = uni2cp437_page01,
> > + [0x03] = uni2cp437_page03, [0x20] = uni2cp437_page20,
> > + [0x22] = uni2cp437_page22, [0x23] = uni2cp437_page23,
> > + [0x25] = uni2cp437_page25,
> > +};
> > +
> > +/*
> > + * Convert a Unicode code point to its CP437 equivalent for
> > + * rendering with the VGA font.
> > + * Returns '?' for characters that cannot be mapped.
> > + */
> > +int unicode_to_cp437(uint32_t codepoint)
> > +{
> > + const unsigned char *page;
> > + unsigned char hi = (codepoint >> 8) & 0xff;
> > + unsigned char lo = codepoint & 0xff;
> > +
> > + if (codepoint > 0xffff) {
> > + return '?';
> > + }
> > +
> > + page = uni2cp437_page[hi];
> > + if (page && page[lo]) {
> > + return page[lo];
> > + }
> > +
> > + return '?';
> > +}
> > diff --git a/ui/meson.build b/ui/meson.build
> > index 69404bca71a..d4d9312b98c 100644
> > --- a/ui/meson.build
> > +++ b/ui/meson.build
> > @@ -16,7 +16,7 @@ system_ss.add(files(
> > 'ui-qmp-cmds.c',
> > 'util.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
> >
> > --
> > 2.53.0
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
> |: https://libvirt.org ~~ https://entangle-photo.org :|
> |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay
2026-04-15 16:03 ` Daniel P. Berrangé
@ 2026-04-20 15:03 ` Marc-André Lureau
0 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-20 15:03 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel
Hi
On Wed, Apr 15, 2026 at 8:03 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Fri, Apr 10, 2026 at 11:19:08PM +0400, Marc-André Lureau wrote:
> > 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.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > ui/vnc-jobs.h | 3 ++-
> > ui/vnc.h | 2 ++
> > ui/vnc-jobs.c | 76 +++++++++++++++++++++++++++++++++--------------------------
> > ui/vnc.c | 3 ++-
> > 4 files changed, 49 insertions(+), 35 deletions(-)
> >
>
> > diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c
> > index 5b17ef54091..c809287dd3a 100644
> > --- a/ui/vnc-jobs.c
> > +++ b/ui/vnc-jobs.c
> > @@ -29,8 +29,6 @@
> > #include "qemu/osdep.h"
> > #include "vnc.h"
> > #include "vnc-jobs.h"
> > -#include "qemu/sockets.h"
> > -#include "qemu/main-loop.h"
> > #include "trace.h"
> >
> > /*
> > @@ -56,17 +54,10 @@ struct VncJobQueue {
> > QemuCond cond;
> > QemuMutex mutex;
> > QemuThread thread;
> > + bool exit;
> > QTAILQ_HEAD(, VncJob) jobs;
> > };
> >
> > -typedef struct VncJobQueue VncJobQueue;
> > -
> > -/*
> > - * We use a single global queue, but most of the functions are
> > - * already reentrant, so we can easily add more than one encoding thread
> > - */
> > -static VncJobQueue *queue;
> > -
> > static void vnc_lock_queue(VncJobQueue *queue)
> > {
> > qemu_mutex_lock(&queue->mutex);
> > @@ -125,19 +116,22 @@ static void vnc_job_free(VncJob *job)
> > */
> > void vnc_job_push(VncJob *job)
> > {
> > + VncJobQueue *queue = job->vs->vd->queue;
> > +
> > assert(!QTAILQ_IN_USE(job, next));
> >
> > if (QLIST_EMPTY(&job->rectangles)) {
> > vnc_job_free(job);
> > } else {
> > vnc_lock_queue(queue);
> > + assert(!queue->exit);
> > QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
> > qemu_cond_broadcast(&queue->cond);
> > vnc_unlock_queue(queue);
> > }
> > }
> >
> > -static bool vnc_has_job_locked(VncState *vs)
> > +static bool vnc_has_job_locked(VncJobQueue *queue, VncState *vs)
> > {
>
> Instead of passing this I think you could add
>
> VncJobQueue *queue = vs->vd->queue;
>
> which guarantees the queue object matches the state object
> instead of leaving that precondition to the caller.
ok
>
> > VncJob *job;
> >
> > @@ -151,8 +145,10 @@ static bool vnc_has_job_locked(VncState *vs)
> >
> > void vnc_jobs_join(VncState *vs)
> > {
> > + VncJobQueue *queue = vs->vd->queue;
> > +
> > vnc_lock_queue(queue);
> > - while (vnc_has_job_locked(vs)) {
> > + while (vnc_has_job_locked(queue, vs)) {
> > qemu_cond_wait(&queue->cond, &queue->mutex);
> > }
> > vnc_unlock_queue(queue);
> > @@ -252,9 +248,13 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
> > int saved_offset;
> >
> > vnc_lock_queue(queue);
> > - while (QTAILQ_EMPTY(&queue->jobs)) {
> > + while (QTAILQ_EMPTY(&queue->jobs) && !queue->exit) {
> > qemu_cond_wait(&queue->cond, &queue->mutex);
> > }
> > + if (queue->exit) {
> > + vnc_unlock_queue(queue);
> > + return 1;
> > + }
> > job = QTAILQ_FIRST(&queue->jobs);
> > vnc_unlock_queue(queue);
> >
> > @@ -340,39 +340,49 @@ disconnected:
> > return 0;
> > }
> >
> > -static VncJobQueue *vnc_queue_init(void)
> > -{
> > - VncJobQueue *queue = g_new0(VncJobQueue, 1);
> > -
> > - qemu_cond_init(&queue->cond);
> > - qemu_mutex_init(&queue->mutex);
> > - QTAILQ_INIT(&queue->jobs);
> > - return queue;
> > -}
>
> IMHO it makes sense to keep this object allocator
> method and call it from...
>
> > -
> > static void *vnc_worker_thread(void *arg)
> > {
> > VncJobQueue *queue = arg;
> >
> > while (!vnc_worker_thread_loop(queue)) ;
> > - g_assert_not_reached();
> > +
> > return NULL;
> > }
> >
> > -static bool vnc_worker_thread_running(void)
> > +void vnc_start_worker_thread(VncDisplay *vd)
> > {
> > - return queue; /* Check global queue */
> > + VncJobQueue *queue;
> > +
> > + assert(vd->queue == NULL);
> > +
> > + queue = g_new0(VncJobQueue, 1);
> > + qemu_cond_init(&queue->cond);
> > + qemu_mutex_init(&queue->mutex);
> > + QTAILQ_INIT(&queue->jobs);
> > + vd->queue = queue;
>
> ....here
>
> vd->queue = vnc_queue_init();
>
> though renaming it to vnc_queue_new() would be more
> in keeping with the naming patterns.
ok
>
> > +
> > + qemu_thread_create(&queue->thread, "vnc_worker", vnc_worker_thread, queue,
> > + QEMU_THREAD_JOINABLE);
> > }
> >
> > -void vnc_start_worker_thread(void)
> > +void vnc_stop_worker_thread(VncDisplay *vd)
> > {
> > - VncJobQueue *q;
> > + VncJobQueue *queue = vd->queue;
> >
> > - if (vnc_worker_thread_running())
> > + if (!queue) {
> > return;
> > + }
> > +
> > + /* all VNC clients must have finished before we can stop the worker thread */
> > + vnc_lock_queue(queue);
> > + assert(QTAILQ_EMPTY(&queue->jobs));
> > + queue->exit = true;
> > + qemu_cond_broadcast(&queue->cond);
> > + vnc_unlock_queue(queue);
> >
> > - q = vnc_queue_init();
> > - qemu_thread_create(&q->thread, "vnc_worker", vnc_worker_thread, q,
> > - QEMU_THREAD_DETACHED);
> > - queue = q; /* Set global queue */
> > + qemu_thread_join(&queue->thread);
> > + qemu_cond_destroy(&queue->cond);
> > + qemu_mutex_destroy(&queue->mutex);
> > + g_free(queue);
>
>
> I'd suggest a vnc_queue_free(queue) method here too
>
> > + vd->queue = NULL;
> > }
> > diff --git a/ui/vnc.c b/ui/vnc.c
> > index ba7376360e6..4e5a9ee0341 100644
> > --- a/ui/vnc.c
> > +++ b/ui/vnc.c
> > @@ -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);
> > @@ -3517,6 +3517,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);
> >
> > --
> > 2.53.0
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
> |: https://libvirt.org ~~ https://entangle-photo.org :|
> |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 49/67] ui/vnc: add vnc_cleanup()
2026-04-15 11:56 ` Daniel P. Berrangé
@ 2026-04-20 20:08 ` Marc-André Lureau
0 siblings, 0 replies; 100+ messages in thread
From: Marc-André Lureau @ 2026-04-20 20:08 UTC (permalink / raw)
To: Daniel P. Berrangé; +Cc: qemu-devel
Hi
On Wed, Apr 15, 2026 at 3:58 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> On Fri, Apr 10, 2026 at 11:19:11PM +0400, Marc-André Lureau wrote:
> > Add a function to tear down VNC displays, call it when leaving QEMU.
> >
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> > include/ui/console.h | 1 +
> > system/runstate.c | 5 +++++
> > ui/vnc.c | 24 ++++++++++++++++++++++++
> > 3 files changed, 30 insertions(+)
> >
> > diff --git a/include/ui/console.h b/include/ui/console.h
> > index 1794f1a2cf0..b3aaf3ff12b 100644
> > --- a/include/ui/console.h
> > +++ b/include/ui/console.h
> > @@ -455,6 +455,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);
> > diff --git a/system/runstate.c b/system/runstate.c
> > index 770253b467b..0e1cb3b4e67 100644
> > --- a/system/runstate.c
> > +++ b/system/runstate.c
> > @@ -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 */
> > }
> > diff --git a/ui/vnc.c b/ui/vnc.c
> > index 4d5b36a6fa8..c26b581f3ef 100644
> > --- a/ui/vnc.c
> > +++ b/ui/vnc.c
> > @@ -4354,6 +4354,30 @@ 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;
> > + VncState *vs;
> > +
> > + QTAILQ_FOREACH(vd, &vnc_displays, next) {
> > + if (vd->listener) {
> > + qio_net_listener_disconnect(vd->listener);
> > + }
> > + if (vd->wslistener) {
> > + qio_net_listener_disconnect(vd->wslistener);
> > + }
> > + QTAILQ_FOREACH(vs, &vd->clients, next) {
> > + vnc_disconnect_start(vs);
> > + }
> > + }
>
> Upto this point, I feel like there is conceptual overlap with
> what I'd expect vnc_display_close to be doing, except that its
> current impl does not kill off the clients - it doesn't need
> to as it is currently only called in a startup path where
> (IIUC) we can assume no clients are present.
>
> IOW, could we have this look more like
>
> QTAILQ_FOREACH(vd, &vnc_displays, next) {
> vnc_display_close(vd);
> }
>
> pushing the vnc_disconnect_start into vnc_display_close.
Calling vnc_display_close() before all the clients are gone seems
riskier, as some of the VncDisplay states are reset. But since
vnc_client_io() is removed (ioc_tag), this looks quite safe to me.
(hopefully vnc servers will run out of QEMU process after this series
;)
>
> > + QTAILQ_FOREACH_SAFE(vd, &vnc_displays, next, vd_next) {
> > + while (!QTAILQ_EMPTY(&vd->clients)) {
> > + main_loop_wait(false);
> > + }
>
> Could we push this loop into vnc_display_free, on the assumption
> that a call to vnc_display_close be made a documented pre-condition ?
Or we call close() there? seems appropriate too then. double-close
should be idempotent.
>
> > + vnc_display_free(vd);
> > + }
> > +}
> > +
> > static void vnc_register_config(void)
> > {
> > qemu_add_opts(&qemu_vnc_opts);
> >
> > --
> > 2.53.0
> >
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com ~~ https://hachyderm.io/@berrange :|
> |: https://libvirt.org ~~ https://entangle-photo.org :|
> |: https://pixelfed.art/berrange ~~ https://fstop138.berrange.com :|
>
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 59/67] ui/console: return completion status from gfx_update callback
2026-04-10 19:19 ` [PATCH v2 59/67] ui/console: return completion status from gfx_update callback Marc-André Lureau
@ 2026-04-23 13:59 ` Philippe Mathieu-Daudé
0 siblings, 0 replies; 100+ messages in thread
From: Philippe Mathieu-Daudé @ 2026-04-23 13:59 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 10/4/26 21:19, Marc-André Lureau wrote:
> Replace the two-field design (gfx_update void callback + gfx_update_async
> flag) with a single bool return value from gfx_update. Returning true
> means the update completed synchronously and graphic_hw_update_done()
> should be called by the console layer. Returning false means the update
> is deferred and the device will call graphic_hw_update_done() itself
> later (as done by QXL/SPICE and Apple GFX).
>
> This simplifies the interface and makes the async contract explicit at
> each call site rather than relying on a separate struct field.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
> hw/display/qxl.h | 2 +-
> include/ui/console.h | 9 +++++++--
> hw/arm/musicpal.c | 3 ++-
> hw/display/artist.c | 4 +++-
> hw/display/bcm2835_fb.c | 7 ++++---
> hw/display/bochs-display.c | 6 ++++--
> hw/display/cg3.c | 5 +++--
> hw/display/dm163.c | 4 +++-
> hw/display/exynos4210_fimd.c | 6 ++++--
> hw/display/g364fb.c | 9 ++++++---
> hw/display/jazz_led.c | 6 ++++--
> hw/display/macfb.c | 6 ++++--
> hw/display/next-fb.c | 4 +++-
> hw/display/omap_lcdc.c | 14 ++++++++------
> hw/display/pl110.c | 5 +++--
> hw/display/qxl-render.c | 6 +++---
> hw/display/qxl.c | 7 +++----
> hw/display/ramfb-standalone.c | 4 +++-
> hw/display/sm501.c | 8 +++++---
> hw/display/ssd0303.c | 10 ++++++----
> hw/display/ssd0323.c | 11 ++++++-----
> hw/display/tcx.c | 6 ++++--
> hw/display/vga.c | 4 +++-
> hw/display/virtio-gpu-base.c | 3 ++-
> hw/display/virtio-vga.c | 6 +++---
> hw/display/vmware_vga.c | 7 ++++---
> hw/display/xenfb.c | 6 ++++--
> hw/display/xlnx_dp.c | 10 ++++++----
> hw/vfio/display.c | 17 ++++++++++-------
> ui/console.c | 7 +------
> hw/display/apple-gfx.m | 10 +++++-----
> 31 files changed, 127 insertions(+), 85 deletions(-)
Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering
2026-04-20 7:54 ` Marc-André Lureau
@ 2026-04-29 8:30 ` Daniel P. Berrangé
0 siblings, 0 replies; 100+ messages in thread
From: Daniel P. Berrangé @ 2026-04-29 8:30 UTC (permalink / raw)
To: Marc-André Lureau; +Cc: qemu-devel
On Mon, Apr 20, 2026 at 11:54:40AM +0400, Marc-André Lureau wrote:
> Hi
>
> On Wed, Apr 15, 2026 at 3:24 PM Daniel P. Berrangé <berrange@redhat.com> wrote:
> >
> > On Fri, Apr 10, 2026 at 11:18:31PM +0400, Marc-André Lureau wrote:
> > > 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.
> >
> > Presumably the key words here are "may be" .... as in, it
> > also "may NOT be" UTF-8.
> >
> > IIUC, the current code is assuming that all data from the guest
> > is in the CP437 encoding (8-bit Extended ASCII), and that encoding
> > has valid characters for all 256 code points.
> >
> > By adding UTF-8 decoding for val > 0x80 this is breaking compat
> > with any guest that is outputting data with the full range of
> > CP437.
> >
> > IOW, this patch is moving the brokeness from guests which
> > use UTF8, onto guests which use CP437.
> >
> > Only guests which strictly limit themselves to 7-bit ASCII
> > are unaffected.
> >
> > I accept the UTF8 should probably be considered the common
> > case for modern guests, but this hardcoding a different type
> > of breakage feels undesirable to me.
> >
> > Surely we need an explicit config property here to select
> > the between character sets we expect from the guest ?
>
> Probably, I don't know if many guest/apps rely on the serial encoding,
> but we should probably be conservative.
>
> Adjusting the decoding at runtime may be possible, but it could be tricky.
>
> Instead, we could add a vc chardev option like charset=cp437/utf8.
>
> What should be the default? For compatibility reasons, use CP437 for
> pc machine <=11.0 and default to utf8 for others? wdyt?
Strictly speaking this is not guest ABI, just a change in defaults
for the backend. So as long as we provide the config option, we could
potentially just change the default to UTF8 unconditionally, on the
basis that UTF8 has been the default charset in mainstream Linux for
20 years. Not sure what Windows uses by default, but use of the serial
console with Linux guests is much more likely than Windows guests IMHO.
^ permalink raw reply [flat|nested] 100+ messages in thread
end of thread, other threads:[~2026-04-29 8:31 UTC | newest]
Thread overview: 100+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-10 19:18 [PATCH v2 00/67] ui: add standalone VNC server over D-Bus Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 01/67] ui/vnc-jobs: remove needless buffer_reset() before end Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 02/67] ui/vnc: clarify intent using buffer_empty() function Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 03/67] ui/vnc-jobs: vnc_has_job_locked() argument cannot be NULL Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 04/67] ui/vnc-jobs: remove dead VncJobQueue.exit Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 05/67] ui/vnc-jobs: remove vnc_queue_clear() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 06/67] ui/vnc-jobs: narrow taking the queue lock Marc-André Lureau
2026-04-15 9:17 ` Daniel P. Berrangé
2026-04-10 19:18 ` [PATCH v2 07/67] ui/vnc-jobs: drop redundant (and needless) qemu_thread_get_self() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 08/67] ui/console-vc: fix off-by-one in CSI J 2 (clear entire screen) Marc-André Lureau
2026-04-11 22:42 ` Philippe Mathieu-Daudé
2026-04-10 19:18 ` [PATCH v2 09/67] ui/console-vc: add UTF-8 input decoding with CP437 rendering Marc-André Lureau
2026-04-15 11:24 ` Daniel P. Berrangé
2026-04-20 7:54 ` Marc-André Lureau
2026-04-29 8:30 ` Daniel P. Berrangé
2026-04-10 19:18 ` [PATCH v2 10/67] ui/console-vc: ignore string-type escape sequences Marc-André Lureau
2026-04-15 9:19 ` Daniel P. Berrangé
2026-04-10 19:18 ` [PATCH v2 11/67] ui/console-vc: fix comment shift-out/in comments Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 12/67] ui/console: dispatch get_label() through QOM virtual method Marc-André Lureau
2026-04-11 22:41 ` Philippe Mathieu-Daudé
2026-04-12 14:45 ` Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 13/67] ui/console-vc: introduce QemuVT100 Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 14/67] ui/console-vc: set vt100 associated pixman image Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 15/67] ui/console-vc: vga_putcharxy()->vt100_putcharxy() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 16/67] ui/console-vc: make invalidate_xy() take vt100 Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 17/67] ui/console-vc: make show_cursor() " Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 18/67] ui/console-vc: decouple VT100 display updates via function pointer Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 19/67] ui/console-vc: console_refresh() -> vt100_refresh() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 20/67] ui/console-vc: move cursor blinking logic into VT100 layer Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 21/67] ui/console-vc: console_scroll() -> vt100_scroll() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 22/67] ui/console-vc: refactor text_console_resize() into vt100_set_image() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 23/67] ui/console-vc: move vc_put_lf() to VT100 layer as vt100_put_lf() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 24/67] ui/console-vc: unify the write path Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 25/67] ui/console-vc: move VT100 state machine and output FIFO into QemuVT100 Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 26/67] ui/console-vc: extract vt100_input() from vc_chr_write() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 27/67] ui/console-vc: extract vt100_keysym() from qemu_text_console_handle_keysym() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 28/67] ui/console-vc: extract vt100_init() and vt100_fini() Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 29/67] ui/console: remove console_ch_t typedef and console_write_ch() Marc-André Lureau
2026-04-11 22:24 ` Philippe Mathieu-Daudé
2026-04-10 19:18 ` [PATCH v2 30/67] ui: avoid duplicating vgafont16 in each translation unit Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 31/67] ui/vgafont: add SPDX license header Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 32/67] ui: move FONT_WIDTH/HEIGHT to vgafont.h Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 33/67] ui/console-vc: move VT100 emulation into separate unit Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 34/67] util: move datadir.c from system/ Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 35/67] ui: move DisplaySurface functions to display-surface.c Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 36/67] ui: make qemu_default_pixelformat() static inline Marc-André Lureau
2026-04-10 19:18 ` [PATCH v2 37/67] ui: make unregister_displaychangelistener() skip unregistered Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 38/67] ui: minor code simplification Marc-André Lureau
2026-04-15 11:25 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 39/67] system: make qemu_del_vm_change_state_handler accept NULL Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 40/67] ui/vnc: assert preconditions instead of silently returning Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 41/67] ui/vnc: simplify vnc_init_func error handling Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 42/67] ui/vnc: VncDisplay.id is not const Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 43/67] ui/keymaps: introduce kbd_layout_free() Marc-André Lureau
2026-04-11 22:26 ` Philippe Mathieu-Daudé
2026-04-12 14:10 ` Marc-André Lureau
2026-04-15 11:31 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 44/67] ui/vnc: fix vnc_display_init() leak on failure Marc-André Lureau
2026-04-15 11:34 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 45/67] ui/vnc: make vnc_disconnect_finish() private Marc-André Lureau
2026-04-11 22:27 ` Philippe Mathieu-Daudé
2026-04-15 11:34 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 46/67] ui/vnc: make the worker thread per-VncDisplay Marc-André Lureau
2026-04-15 16:03 ` Daniel P. Berrangé
2026-04-20 15:03 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 47/67] ui/vnc: vnc_display_init() and vnc_display_open() return bool Marc-André Lureau
2026-04-11 22:28 ` Philippe Mathieu-Daudé
2026-04-12 14:12 ` Marc-André Lureau
2026-04-15 16:11 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 48/67] ui/vnc: merge vnc_display_init() and vnc_display_open() Marc-André Lureau
2026-04-11 22:31 ` Philippe Mathieu-Daudé
2026-04-12 14:17 ` Marc-André Lureau
2026-04-12 20:57 ` Philippe Mathieu-Daudé
2026-04-15 16:14 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 49/67] ui/vnc: add vnc_cleanup() Marc-André Lureau
2026-04-15 11:56 ` Daniel P. Berrangé
2026-04-20 20:08 ` Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 50/67] ui/vnc: report an error for duplicate display id Marc-André Lureau
2026-04-11 22:33 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 51/67] ui/vnc: defer listener registration until the console is known Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 52/67] ui/vnc: expose vnc_disconnect_start() Marc-André Lureau
2026-04-15 12:19 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 53/67] ui/vnc: remove left-over dead code Marc-André Lureau
2026-04-15 11:58 ` Daniel P. Berrangé
2026-04-10 19:19 ` [PATCH v2 54/67] ui/vnc: explicitly link with png Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 55/67] ui/vnc: add vnc-system unit, to allow different implementations Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 56/67] ui/console: remove qemu_console_is_visible() Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 57/67] ui/console: simplify registering display/console change listener Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 58/67] ui/console: add doc comment for qemu_console_{un}register_listener() Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 59/67] ui/console: return completion status from gfx_update callback Marc-André Lureau
2026-04-23 13:59 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 60/67] ui/console: rename public API to use consistent qemu_console_ prefix Marc-André Lureau
2026-04-11 22:38 ` Philippe Mathieu-Daudé
2026-04-10 19:19 ` [PATCH v2 61/67] ui/console: move console_handle_touch_event() to input Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 62/67] ui/vnc: replace VNC_DEBUG with trace-events Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 63/67] ui: extract common sources into a static library Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 64/67] tests: rename the dbus-daemon helper script Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 65/67] tests/qtest: fix dbus-vmstate-test compilation Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 66/67] tests/qtest: drop DBUS_VMSTATE_TEST_TMPDIR Marc-André Lureau
2026-04-10 19:19 ` [PATCH v2 67/67] tools/qemu-vnc: add standalone VNC server over D-Bus Marc-André Lureau
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.