Commit bd13682e7a for qemu.org
commit bd13682e7a1012109874e9f855381efe0e5dfe44
Author: Marc-André Lureau <marcandre.lureau@redhat.com>
Date: Tue Jun 23 11:44:48 2026 +0400
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>
diff --git a/ui/dbus-console.c b/ui/dbus-console.c
index bdbc208cf0..e1ac06814b 100644
--- a/ui/dbus-console.c
+++ b/ui/dbus-console.c
@@ -533,6 +533,11 @@ int dbus_display_console_get_index(DBusDisplayConsole *ddc)
return qemu_console_get_index(ddc->dcl.con);
}
+QemuConsole *dbus_display_console_get_qemu_console(DBusDisplayConsole *ddc)
+{
+ return ddc->dcl.con;
+}
+
DBusDisplayConsole *
dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
{
diff --git a/ui/dbus.c b/ui/dbus.c
index b23cb44c53..7be0f8e261 100644
--- a/ui/dbus.c
+++ b/ui/dbus.c
@@ -142,6 +142,9 @@ dbus_display_finalize(Object *o)
{
DBusDisplay *dd = DBUS_DISPLAY(o);
+ if (dd->console_notifier.notify) {
+ qemu_console_remove_notifier(&dd->console_notifier);
+ }
if (dd->notifier.notify) {
dbus_display_notifier_remove(&dd->notifier);
}
@@ -164,14 +167,35 @@ dbus_display_finalize(Object *o)
dbus_display = NULL;
}
+static void
+dbus_update_console_ids(DBusDisplay *dd)
+{
+ g_autoptr(GArray) arr = g_array_new(FALSE, FALSE, sizeof(guint32));
+
+ for (guint i = 0; i < dd->consoles->len; i++) {
+ DBusDisplayConsole *ddc = g_ptr_array_index(dd->consoles, i);
+ guint32 idx = dbus_display_console_get_index(ddc);
+ g_array_append_val(arr, idx);
+ }
+
+ g_object_set(dd->iface, "console-ids",
+ g_variant_new_fixed_array(G_VARIANT_TYPE("u"),
+ arr->data, arr->len,
+ sizeof(guint32)),
+ NULL);
+}
+
static bool
-dbus_display_add_console(DBusDisplay *dd, int idx, Error **errp)
+dbus_display_add_console(DBusDisplay *dd, QemuConsole *con, Error **errp)
{
- QemuConsole *con;
DBusDisplayConsole *dbus_console;
- con = qemu_console_lookup_by_index(idx);
- assert(con);
+ for (guint i = 0; i < dd->consoles->len; i++) {
+ DBusDisplayConsole *ddc = g_ptr_array_index(dd->consoles, i);
+ if (dbus_display_console_get_qemu_console(ddc) == con) {
+ return true;
+ }
+ }
if (qemu_console_is_graphic(con) &&
dd->gl_mode != DISPLAY_GL_MODE_OFF) {
@@ -179,20 +203,58 @@ dbus_display_add_console(DBusDisplay *dd, int idx, Error **errp)
}
dbus_console = dbus_display_console_new(dd, con);
- g_ptr_array_insert(dd->consoles, idx, dbus_console);
+ g_ptr_array_add(dd->consoles, dbus_console);
g_dbus_object_manager_server_export(dd->server,
G_DBUS_OBJECT_SKELETON(dbus_console));
+ dbus_update_console_ids(dd);
return true;
}
+static void
+dbus_display_remove_console(DBusDisplay *dd, QemuConsole *con)
+{
+ for (guint i = 0; i < dd->consoles->len; i++) {
+ DBusDisplayConsole *ddc = g_ptr_array_index(dd->consoles, i);
+ if (dbus_display_console_get_qemu_console(ddc) == con) {
+ if (display_opengl) {
+ qemu_console_set_display_gl_ctx(con, NULL);
+ }
+ g_dbus_object_manager_server_unexport(
+ dd->server,
+ g_dbus_object_get_object_path(G_DBUS_OBJECT(ddc)));
+ g_ptr_array_remove_index(dd->consoles, i);
+ dbus_update_console_ids(dd);
+ break;
+ }
+ }
+}
+
+static void
+dbus_console_notify(Notifier *n, void *data)
+{
+ DBusDisplay *dd = container_of(n, DBusDisplay, console_notifier);
+ QemuConsoleEvent *event = data;
+
+ switch (event->type) {
+ case QEMU_CONSOLE_ADDED: {
+ Error *err = NULL;
+ if (!dbus_display_add_console(dd, event->con, &err)) {
+ error_report_err(err);
+ }
+ break;
+ }
+ case QEMU_CONSOLE_REMOVED:
+ dbus_display_remove_console(dd, event->con);
+ break;
+ }
+}
+
static void
dbus_display_complete(UserCreatable *uc, Error **errp)
{
DBusDisplay *dd = DBUS_DISPLAY(uc);
g_autoptr(GError) err = NULL;
g_autofree char *uuid = qemu_uuid_unparse_strdup(&qemu_uuid);
- g_autoptr(GArray) consoles = NULL;
- GVariant *console_ids;
int idx;
if (!object_resolve_path_type("", TYPE_DBUS_DISPLAY, NULL)) {
@@ -233,27 +295,24 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
}
}
- consoles = g_array_new(FALSE, FALSE, sizeof(guint32));
for (idx = 0;; idx++) {
- if (!qemu_console_lookup_by_index(idx)) {
+ QemuConsole *con = qemu_console_lookup_by_index(idx);
+ if (!con) {
break;
}
- if (!dbus_display_add_console(dd, idx, errp)) {
+ if (!dbus_display_add_console(dd, con, errp)) {
return;
}
- g_array_append_val(consoles, idx);
}
- console_ids = g_variant_new_from_data(
- G_VARIANT_TYPE("au"),
- consoles->data, consoles->len * sizeof(guint32), TRUE,
- (GDestroyNotify)g_array_unref, consoles);
- g_steal_pointer(&consoles);
g_object_set(dd->iface,
"name", qemu_name ?: "QEMU " QEMU_VERSION,
"uuid", uuid,
- "console-ids", console_ids,
NULL);
+ dbus_update_console_ids(dd);
+
+ dd->console_notifier.notify = dbus_console_notify;
+ qemu_console_add_notifier(&dd->console_notifier);
if (dd->bus) {
g_dbus_object_manager_server_set_connection(dd->server, dd->bus);
diff --git a/ui/dbus.h b/ui/dbus.h
index e4e78590b4..d2cc176648 100644
--- a/ui/dbus.h
+++ b/ui/dbus.h
@@ -60,6 +60,7 @@ struct DBusDisplay {
DBusClipboardRequest clipboard_request[QEMU_CLIPBOARD_SELECTION__COUNT];
Notifier notifier;
+ Notifier console_notifier;
};
#ifdef WIN32
@@ -86,6 +87,8 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con);
int
dbus_display_console_get_index(DBusDisplayConsole *ddc);
+QemuConsole *
+dbus_display_console_get_qemu_console(DBusDisplayConsole *ddc);
extern const DisplayChangeListenerOps dbus_console_dcl_ops;