master
c 170 lines 4.35 KB
Raw
1 /*
2 * Minimal QemuConsole helpers for the standalone qemu-vnc binary.
3 *
4 * Copyright (C) 2026 Red Hat, Inc.
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10
11 #include "ui/console.h"
12 #include "ui/console-priv.h"
13 #include "ui/vt100.h"
14 #include "qapi-types-char.h"
15 #include "qemu-vnc.h"
16 #include "trace.h"
17
18 /*
19 * Our own QemuTextConsole definition — the one in console-vc.c uses
20 * a Chardev* backend which is not available in the standalone binary.
21 * Here we drive the VT100 emulator directly over a raw file descriptor.
22 */
23 typedef struct QemuTextConsole {
24 QemuConsole parent;
25 QemuVT100 vt;
26 int chardev_fd;
27 guint io_watch_id;
28 char *name;
29 } QemuTextConsole;
30
31 typedef QemuConsoleClass QemuTextConsoleClass;
32
33 OBJECT_DEFINE_TYPE(QemuTextConsole, qemu_text_console,
34 QEMU_TEXT_CONSOLE, QEMU_CONSOLE)
35
36 static void qemu_text_console_class_init(ObjectClass *oc, const void *data)
37 {
38 }
39
40 static void text_console_invalidate(void *opaque)
41 {
42 QemuTextConsole *s = QEMU_TEXT_CONSOLE(opaque);
43
44 vt100_set_image(&s->vt, QEMU_CONSOLE(s)->surface->image);
45 vt100_refresh(&s->vt);
46 }
47
48 static const GraphicHwOps text_console_ops = {
49 .invalidate = text_console_invalidate,
50 };
51
52 static void qemu_text_console_init(Object *obj)
53 {
54 QemuTextConsole *c = QEMU_TEXT_CONSOLE(obj);
55
56 QEMU_CONSOLE(c)->hw_ops = &text_console_ops;
57 QEMU_CONSOLE(c)->hw = c;
58 }
59
60 static void qemu_text_console_finalize(Object *obj)
61 {
62 QemuTextConsole *tc = QEMU_TEXT_CONSOLE(obj);
63
64 vt100_fini(&tc->vt);
65 if (tc->io_watch_id) {
66 g_source_remove(tc->io_watch_id);
67 }
68 if (tc->chardev_fd >= 0) {
69 close(tc->chardev_fd);
70 }
71 g_free(tc->name);
72 }
73
74
75 static void text_console_out_flush(QemuVT100 *vt)
76 {
77 QemuTextConsole *tc = container_of(vt, QemuTextConsole, vt);
78 const uint8_t *data;
79 uint32_t len;
80
81 while (!fifo8_is_empty(&vt->out_fifo)) {
82 ssize_t ret;
83
84 data = fifo8_pop_bufptr(&vt->out_fifo,
85 fifo8_num_used(&vt->out_fifo), &len);
86 ret = write(tc->chardev_fd, data, len);
87 if (ret < 0) {
88 trace_qemu_vnc_console_io_error(tc->name);
89 break;
90 }
91 }
92 }
93
94 static void text_console_image_update(QemuVT100 *vt, int x, int y, int w, int h)
95 {
96 QemuTextConsole *tc = container_of(vt, QemuTextConsole, vt);
97 QemuConsole *con = QEMU_CONSOLE(tc);
98
99 qemu_console_update(con, x, y, w, h);
100 }
101
102 static gboolean text_console_io_cb(GIOChannel *source,
103 GIOCondition cond, gpointer data)
104 {
105 QemuTextConsole *tc = data;
106 uint8_t buf[4096];
107 ssize_t n;
108
109 if (cond & (G_IO_HUP | G_IO_ERR)) {
110 tc->io_watch_id = 0;
111 return G_SOURCE_REMOVE;
112 }
113
114 n = read(tc->chardev_fd, buf, sizeof(buf));
115 if (n <= 0) {
116 trace_qemu_vnc_console_io_error(tc->name);
117 tc->io_watch_id = 0;
118 return G_SOURCE_REMOVE;
119 }
120
121 vt100_input(&tc->vt, buf, n);
122 return G_SOURCE_CONTINUE;
123 }
124
125 QemuTextConsole *qemu_vnc_text_console_new(const char *name,
126 int fd, bool echo,
127 ChardevVCEncoding encoding)
128 {
129 int w = TEXT_COLS * TEXT_FONT_WIDTH;
130 int h = TEXT_ROWS * TEXT_FONT_HEIGHT;
131 QemuTextConsole *tc;
132 QemuConsole *con;
133 pixman_image_t *image;
134 GIOChannel *chan;
135
136 tc = QEMU_TEXT_CONSOLE(object_new(TYPE_QEMU_TEXT_CONSOLE));
137 con = QEMU_CONSOLE(tc);
138
139 tc->name = g_strdup(name);
140 tc->chardev_fd = fd;
141
142 image = pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h, NULL, 0);
143 con->surface = qemu_create_displaysurface_pixman(image);
144 con->scanout.kind = SCANOUT_SURFACE;
145 qemu_pixman_image_unref(image);
146
147 vt100_init(&tc->vt, con->surface->image, encoding,
148 text_console_image_update, text_console_out_flush);
149 tc->vt.echo = echo;
150 vt100_refresh(&tc->vt);
151
152 chan = g_io_channel_unix_new(fd);
153 g_io_channel_set_encoding(chan, NULL, NULL);
154 tc->io_watch_id = g_io_add_watch(chan,
155 G_IO_IN | G_IO_HUP | G_IO_ERR,
156 text_console_io_cb, tc);
157 g_io_channel_unref(chan);
158
159 return tc;
160 }
161
162 void qemu_text_console_handle_keysym(QemuTextConsole *s, int keysym)
163 {
164 vt100_keysym(&s->vt, keysym);
165 }
166
167 void qemu_text_console_update_size(QemuTextConsole *c)
168 {
169 qemu_console_text_resize(QEMU_CONSOLE(c), c->vt.width, c->vt.height);
170 }