@samitouri / QOSamiQemu / commits / bd13682e7a

ui/dbus: handle console hotplug/unplug events

Subscribe to QemuConsoleEvent notifications to dynamically add and remove D-Bus display consoles. This mirrors the GTK backend's handling added in the previous commits. Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20260623-b4-ui-v4-33-4656aec3398d@redhat.com>

Marc-André Lureau committed Jun 23, 2026 at 11:44 UTC bd13682e7a1012109874e9f855381efe0e5dfe44
3 files changed +84 -17
ui/dbus-console.c
+5
@@ -533,6 +533,11 @@ int dbus_display_console_get_index(DBusDisplayConsole *ddc)
533 return qemu_console_get_index(ddc->dcl.con);
534 }
535
536 +QemuConsole *dbus_display_console_get_qemu_console(DBusDisplayConsole *ddc)
537 +{
538 + return ddc->dcl.con;
539 +}
540 +
541 DBusDisplayConsole *
542 dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
543 {
ui/dbus.c
+76 -17
@@ -142,6 +142,9 @@ dbus_display_finalize(Object *o)
142 {
143 DBusDisplay *dd = DBUS_DISPLAY(o);
144
145 + if (dd->console_notifier.notify) {
146 + qemu_console_remove_notifier(&dd->console_notifier);
147 + }
148 if (dd->notifier.notify) {
149 dbus_display_notifier_remove(&dd->notifier);
150 }
@@ -164,14 +167,35 @@ dbus_display_finalize(Object *o)
167 dbus_display = NULL;
168 }
169
170 +static void
171 +dbus_update_console_ids(DBusDisplay *dd)
172 +{
173 + g_autoptr(GArray) arr = g_array_new(FALSE, FALSE, sizeof(guint32));
174 +
175 + for (guint i = 0; i < dd->consoles->len; i++) {
176 + DBusDisplayConsole *ddc = g_ptr_array_index(dd->consoles, i);
177 + guint32 idx = dbus_display_console_get_index(ddc);
178 + g_array_append_val(arr, idx);
179 + }
180 +
181 + g_object_set(dd->iface, "console-ids",
182 + g_variant_new_fixed_array(G_VARIANT_TYPE("u"),
183 + arr->data, arr->len,
184 + sizeof(guint32)),
185 + NULL);
186 +}
187 +
188 static bool
168 -dbus_display_add_console(DBusDisplay *dd, int idx, Error **errp)
189 +dbus_display_add_console(DBusDisplay *dd, QemuConsole *con, Error **errp)
190 {
170 - QemuConsole *con;
191 DBusDisplayConsole *dbus_console;
192
173 - con = qemu_console_lookup_by_index(idx);
174 - assert(con);
193 + for (guint i = 0; i < dd->consoles->len; i++) {
194 + DBusDisplayConsole *ddc = g_ptr_array_index(dd->consoles, i);
195 + if (dbus_display_console_get_qemu_console(ddc) == con) {
196 + return true;
197 + }
198 + }
199
200 if (qemu_console_is_graphic(con) &&
201 dd->gl_mode != DISPLAY_GL_MODE_OFF) {
@@ -179,20 +203,58 @@ dbus_display_add_console(DBusDisplay *dd, int idx, Error **errp)
203 }
204
205 dbus_console = dbus_display_console_new(dd, con);
182 - g_ptr_array_insert(dd->consoles, idx, dbus_console);
206 + g_ptr_array_add(dd->consoles, dbus_console);
207 g_dbus_object_manager_server_export(dd->server,
208 G_DBUS_OBJECT_SKELETON(dbus_console));
209 + dbus_update_console_ids(dd);
210 return true;
211 }
212
213 +static void
214 +dbus_display_remove_console(DBusDisplay *dd, QemuConsole *con)
215 +{
216 + for (guint i = 0; i < dd->consoles->len; i++) {
217 + DBusDisplayConsole *ddc = g_ptr_array_index(dd->consoles, i);
218 + if (dbus_display_console_get_qemu_console(ddc) == con) {
219 + if (display_opengl) {
220 + qemu_console_set_display_gl_ctx(con, NULL);
221 + }
222 + g_dbus_object_manager_server_unexport(
223 + dd->server,
224 + g_dbus_object_get_object_path(G_DBUS_OBJECT(ddc)));
225 + g_ptr_array_remove_index(dd->consoles, i);
226 + dbus_update_console_ids(dd);
227 + break;
228 + }
229 + }
230 +}
231 +
232 +static void
233 +dbus_console_notify(Notifier *n, void *data)
234 +{
235 + DBusDisplay *dd = container_of(n, DBusDisplay, console_notifier);
236 + QemuConsoleEvent *event = data;
237 +
238 + switch (event->type) {
239 + case QEMU_CONSOLE_ADDED: {
240 + Error *err = NULL;
241 + if (!dbus_display_add_console(dd, event->con, &err)) {
242 + error_report_err(err);
243 + }
244 + break;
245 + }
246 + case QEMU_CONSOLE_REMOVED:
247 + dbus_display_remove_console(dd, event->con);
248 + break;
249 + }
250 +}
251 +
252 static void
253 dbus_display_complete(UserCreatable *uc, Error **errp)
254 {
255 DBusDisplay *dd = DBUS_DISPLAY(uc);
256 g_autoptr(GError) err = NULL;
257 g_autofree char *uuid = qemu_uuid_unparse_strdup(&qemu_uuid);
194 - g_autoptr(GArray) consoles = NULL;
195 - GVariant *console_ids;
258 int idx;
259
260 if (!object_resolve_path_type("", TYPE_DBUS_DISPLAY, NULL)) {
@@ -233,27 +295,24 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
295 }
296 }
297
236 - consoles = g_array_new(FALSE, FALSE, sizeof(guint32));
298 for (idx = 0;; idx++) {
238 - if (!qemu_console_lookup_by_index(idx)) {
299 + QemuConsole *con = qemu_console_lookup_by_index(idx);
300 + if (!con) {
301 break;
302 }
241 - if (!dbus_display_add_console(dd, idx, errp)) {
303 + if (!dbus_display_add_console(dd, con, errp)) {
304 return;
305 }
244 - g_array_append_val(consoles, idx);
306 }
307
247 - console_ids = g_variant_new_from_data(
248 - G_VARIANT_TYPE("au"),
249 - consoles->data, consoles->len * sizeof(guint32), TRUE,
250 - (GDestroyNotify)g_array_unref, consoles);
251 - g_steal_pointer(&consoles);
308 g_object_set(dd->iface,
309 "name", qemu_name ?: "QEMU " QEMU_VERSION,
310 "uuid", uuid,
255 - "console-ids", console_ids,
311 NULL);
312 + dbus_update_console_ids(dd);
313 +
314 + dd->console_notifier.notify = dbus_console_notify;
315 + qemu_console_add_notifier(&dd->console_notifier);
316
317 if (dd->bus) {
318 g_dbus_object_manager_server_set_connection(dd->server, dd->bus);
ui/dbus.h
+3
@@ -60,6 +60,7 @@ struct DBusDisplay {
60 DBusClipboardRequest clipboard_request[QEMU_CLIPBOARD_SELECTION__COUNT];
61
62 Notifier notifier;
63 + Notifier console_notifier;
64 };
65
66 #ifdef WIN32
@@ -86,6 +87,8 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con);
87 int
88 dbus_display_console_get_index(DBusDisplayConsole *ddc);
89
90 +QemuConsole *
91 +dbus_display_console_get_qemu_console(DBusDisplayConsole *ddc);
92
93 extern const DisplayChangeListenerOps dbus_console_dcl_ops;
94