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