Merge tag 'for-11.0-rc-pull-request' of https://gitlab.com/marcandre.lureau/qemu into staging

Various UI & audio fixes for 11.0-rc

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCgAdFiEEh6m9kz+HxgbSdvYt2ujhCXWWnOUFAmnLmTsACgkQ2ujhCXWW
# nOUKig//Z6OlzPu5bmwwXulJpVsnwMHG5l+gftbYgs7p2XuMNFuejTQzHO6Ozns2
# chLJ3Of0xm9Z8NsQ2DZJThXjBUCanXCAOsuMYCAGy5PP2vTNBklwc6Sfm0a357cY
# um9E7GN21Kgc8CPizR/b5sv0enTZUT0JXPGapLZpuX2lOPrGpRXHA5thRtwcfaQP
# CHXJ6inWEgz3hXTTgxslvKIlwlTaH5EvjMWbjWgda//V/ZV2x8643o8n2qwO5spL
# ZY8j3TbPr10f4YnfwVcoRLfxnAswXeuk6LkJne0zv8WAQUOOkmi78H6oOmOCoJrt
# Lj08WXU+BJXZS6RKNN20eS1AmcHa2Z+59jXzwRDSRkskugeGACFlx/hbBMZwhbR9
# 0siL/dLJUdQhO/XiCYerN/HNwTy9j0lw4PWFNBBNPn66ykQQZWii4bzMWsVwt5IY
# yKhBQuAvHiN/wre0/NV914TuGWVHqwRYA37SPuLl7VfiR6hVJwTSUK7FscbswTLg
# WGjXB/uxn2XQJnYDXV9WaUHKAOIJ228HXBWLEB5vW55ZkJIl3xT5GL93kX8oFjSh
# 1vy3rVwrMO7UdS0UVhvXZC6E0tmI/fu67jcI8cQsENK6eqnXMdQEKY7otblW9LzM
# pesEUc7LKYFbYbxX8627MnbNU52HXan/XeV2otUJiX9ssUoIdag=
# =qtVg
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue Mar 31 10:51:55 2026 BST
# gpg:                using RSA key 87A9BD933F87C606D276F62DDAE8E10975969CE5
# gpg: Good signature from "Marc-André Lureau <marcandre.lureau@redhat.com>" [full]
# gpg:                 aka "Marc-André Lureau <marcandre.lureau@gmail.com>" [full]
# Primary key fingerprint: 87A9 BD93 3F87 C606 D276  F62D DAE8 E109 7596 9CE5

* tag 'for-11.0-rc-pull-request' of https://gitlab.com/marcandre.lureau/qemu:
  tests: don't build audio tests when no audio drivers are enabled
  ui/vnc-jobs: clear source tag
  ui/vnc-jobs: fix VncRectEntry leak on job cleanup
  ui/dbus: tear down clipboard callbacks on display finalize
  ui/dbus: associate add_client completion with its request
  audio/mixeng: fix sw/hw mixup in audio_pcm_sw_init_

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell
2026-03-31 13:41:29 +01:00
8 changed files with 99 additions and 44 deletions

View File

@@ -172,7 +172,7 @@ static int glue (audio_pcm_sw_init_, TYPE) (
sw->empty = true; sw->empty = true;
#endif #endif
if (audio_format_is_float(hw->info.af)) { if (audio_format_is_float(sw->info.af)) {
#ifdef DAC #ifdef DAC
sw->conv = mixeng_conv_float[sw->info.nchannels == 2] sw->conv = mixeng_conv_float[sw->info.nchannels == 2]
[sw->info.swap_endianness]; [sw->info.swap_endianness];
@@ -187,9 +187,9 @@ static int glue (audio_pcm_sw_init_, TYPE) (
sw->clip = mixeng_clip sw->clip = mixeng_clip
#endif #endif
[sw->info.nchannels == 2] [sw->info.nchannels == 2]
[audio_format_is_signed(hw->info.af)] [audio_format_is_signed(sw->info.af)]
[sw->info.swap_endianness] [sw->info.swap_endianness]
[audio_format_to_index(hw->info.af)]; [audio_format_to_index(sw->info.af)];
} }
sw->name = g_strdup (name); sw->name = g_strdup (name);

View File

@@ -6,12 +6,14 @@ endif
modinfo_dep = not_found modinfo_dep = not_found
if enable_modules if enable_modules
modinfo_src = custom_target('modinfo.c', modinfo_src = 'modinfo-stub.c'
output: 'modinfo.c', if audio_modinfo_files.length() != 0
input: audio_modinfo_files, modinfo_src = custom_target('modinfo.c',
command: [modinfo_generate, '--skip-missing-deps', '@INPUT@'], output: 'modinfo.c',
capture: true) input: audio_modinfo_files,
command: [modinfo_generate, '--skip-missing-deps', '@INPUT@'],
capture: true)
endif
modinfo_lib = static_library('modinfo.c', modinfo_src) modinfo_lib = static_library('modinfo.c', modinfo_src)
modinfo_dep = declare_dependency(link_with: modinfo_lib) modinfo_dep = declare_dependency(link_with: modinfo_lib)
endif endif

View File

@@ -0,0 +1,5 @@
#include "qemu/osdep.h"
#include "qemu/module.h"
const QemuModinfo qemu_modinfo[] = {
{ /* end of list */ }
};

View File

@@ -191,6 +191,7 @@ static void
dbus_clipboard_unregister_proxy(DBusDisplay *dpy) dbus_clipboard_unregister_proxy(DBusDisplay *dpy)
{ {
const char *name = NULL; const char *name = NULL;
GDBusConnection *connection = NULL;
int i; int i;
for (i = 0; i < G_N_ELEMENTS(dpy->clipboard_request); ++i) { for (i = 0; i < G_N_ELEMENTS(dpy->clipboard_request); ++i) {
@@ -201,6 +202,13 @@ dbus_clipboard_unregister_proxy(DBusDisplay *dpy)
return; return;
} }
connection = g_dbus_proxy_get_connection(
G_DBUS_PROXY(dpy->clipboard_proxy));
if (connection) {
g_signal_handlers_disconnect_by_data(connection, dpy);
}
g_signal_handlers_disconnect_by_data(dpy->clipboard_proxy, dpy);
name = g_dbus_proxy_get_name(G_DBUS_PROXY(dpy->clipboard_proxy)); name = g_dbus_proxy_get_name(G_DBUS_PROXY(dpy->clipboard_proxy));
trace_dbus_clipboard_unregister(name); trace_dbus_clipboard_unregister(name);
g_clear_object(&dpy->clipboard_proxy); g_clear_object(&dpy->clipboard_proxy);
@@ -425,6 +433,14 @@ dbus_clipboard_request(
return DBUS_METHOD_INVOCATION_HANDLED; return DBUS_METHOD_INVOCATION_HANDLED;
} }
void
dbus_clipboard_fini(DBusDisplay *dpy)
{
dbus_clipboard_unregister_proxy(dpy);
qemu_clipboard_peer_unregister(&dpy->clipboard_peer);
g_clear_object(&dpy->clipboard);
}
void void
dbus_clipboard_init(DBusDisplay *dpy) dbus_clipboard_init(DBusDisplay *dpy)
{ {

View File

@@ -145,8 +145,7 @@ dbus_display_finalize(Object *o)
dbus_display_notifier_remove(&dd->notifier); dbus_display_notifier_remove(&dd->notifier);
} }
qemu_clipboard_peer_unregister(&dd->clipboard_peer); dbus_clipboard_fini(dd);
g_clear_object(&dd->clipboard);
g_clear_object(&dd->server); g_clear_object(&dd->server);
g_clear_pointer(&dd->consoles, g_ptr_array_unref); g_clear_pointer(&dd->consoles, g_ptr_array_unref);
@@ -263,22 +262,52 @@ dbus_display_complete(UserCreatable *uc, Error **errp)
} }
} }
typedef struct DBusDisplayAddClientData {
DBusDisplay *display;
GCancellable *cancellable;
} DBusDisplayAddClientData;
static void dbus_display_add_client_data_free(DBusDisplayAddClientData *data)
{
if (data->display) {
object_unref(OBJECT(data->display));
data->display = NULL;
}
g_clear_object(&data->cancellable);
g_free(data);
}
G_DEFINE_AUTOPTR_CLEANUP_FUNC(DBusDisplayAddClientData,
dbus_display_add_client_data_free)
static void static void
dbus_display_add_client_ready(GObject *source_object, dbus_display_add_client_ready(GObject *source_object,
GAsyncResult *res, GAsyncResult *res,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(DBusDisplayAddClientData) data = user_data;
DBusDisplay *display = data->display;
bool current = display->add_client_cancellable == data->cancellable;
g_autoptr(GError) err = NULL; g_autoptr(GError) err = NULL;
g_autoptr(GDBusConnection) conn = NULL; g_autoptr(GDBusConnection) conn = NULL;
g_clear_object(&dbus_display->add_client_cancellable); if (current) {
g_clear_object(&display->add_client_cancellable);
}
conn = g_dbus_connection_new_finish(res, &err); conn = g_dbus_connection_new_finish(res, &err);
if (!conn) { if (!conn) {
error_printf("Failed to accept D-Bus client: %s", err->message); if (!g_error_matches(err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
error_printf("Failed to accept D-Bus client: %s", err->message);
}
return;
} }
g_dbus_object_manager_server_set_connection(dbus_display->server, conn); if (!current) {
return;
}
g_dbus_object_manager_server_set_connection(display->server, conn);
g_dbus_connection_start_message_processing(conn); g_dbus_connection_start_message_processing(conn);
} }
@@ -290,6 +319,7 @@ dbus_display_add_client(int csock, Error **errp)
g_autoptr(GSocket) socket = NULL; g_autoptr(GSocket) socket = NULL;
g_autoptr(GSocketConnection) conn = NULL; g_autoptr(GSocketConnection) conn = NULL;
g_autofree char *guid = g_dbus_generate_guid(); g_autofree char *guid = g_dbus_generate_guid();
DBusDisplayAddClientData *data;
if (!dbus_display) { if (!dbus_display) {
error_setg(errp, "p2p connections not accepted in bus mode"); error_setg(errp, "p2p connections not accepted in bus mode");
@@ -298,6 +328,7 @@ dbus_display_add_client(int csock, Error **errp)
if (dbus_display->add_client_cancellable) { if (dbus_display->add_client_cancellable) {
g_cancellable_cancel(dbus_display->add_client_cancellable); g_cancellable_cancel(dbus_display->add_client_cancellable);
g_clear_object(&dbus_display->add_client_cancellable);
} }
#ifdef WIN32 #ifdef WIN32
@@ -318,6 +349,10 @@ dbus_display_add_client(int csock, Error **errp)
conn = g_socket_connection_factory_create_connection(socket); conn = g_socket_connection_factory_create_connection(socket);
dbus_display->add_client_cancellable = g_cancellable_new(); dbus_display->add_client_cancellable = g_cancellable_new();
data = g_new0(DBusDisplayAddClientData, 1);
data->display = DBUS_DISPLAY(object_ref(OBJECT(dbus_display)));
data->cancellable = g_object_ref(dbus_display->add_client_cancellable);
GDBusConnectionFlags flags = GDBusConnectionFlags flags =
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER | G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER |
G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING; G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING;
@@ -332,7 +367,7 @@ dbus_display_add_client(int csock, Error **errp)
NULL, NULL,
dbus_display->add_client_cancellable, dbus_display->add_client_cancellable,
dbus_display_add_client_ready, dbus_display_add_client_ready,
NULL); data);
return true; return true;
} }

View File

@@ -150,5 +150,6 @@ void dbus_display_notify(DBusDisplayEvent *event);
void dbus_chardev_init(DBusDisplay *dpy); void dbus_chardev_init(DBusDisplay *dpy);
void dbus_clipboard_init(DBusDisplay *dpy); void dbus_clipboard_init(DBusDisplay *dpy);
void dbus_clipboard_fini(DBusDisplay *dpy);
#endif /* UI_DBUS_H */ #endif /* UI_DBUS_H */

View File

@@ -107,11 +107,25 @@ int vnc_job_add_rect(VncJob *job, int x, int y, int w, int h)
return 1; return 1;
} }
static void vnc_job_free(VncJob *job)
{
VncRectEntry *entry, *tmp;
if (!job) {
return;
}
QLIST_FOREACH_SAFE(entry, &job->rectangles, next, tmp) {
/* no need for QLIST_REMOVE(entry, next) */
g_free(entry);
}
g_free(job);
}
void vnc_job_push(VncJob *job) void vnc_job_push(VncJob *job)
{ {
vnc_lock_queue(queue); vnc_lock_queue(queue);
if (queue->exit || QLIST_EMPTY(&job->rectangles)) { if (queue->exit || QLIST_EMPTY(&job->rectangles)) {
g_free(job); vnc_job_free(job);
} else { } else {
QTAILQ_INSERT_TAIL(&queue->jobs, job, next); QTAILQ_INSERT_TAIL(&queue->jobs, job, next);
qemu_cond_broadcast(&queue->cond); qemu_cond_broadcast(&queue->cond);
@@ -148,9 +162,7 @@ void vnc_jobs_consume_buffer(VncState *vs)
vnc_lock_output(vs); vnc_lock_output(vs);
if (vs->jobs_buffer.offset) { if (vs->jobs_buffer.offset) {
if (vs->ioc != NULL && buffer_empty(&vs->output)) { if (vs->ioc != NULL && buffer_empty(&vs->output)) {
if (vs->ioc_tag) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
if (vs->disconnecting == FALSE) { if (vs->disconnecting == FALSE) {
vs->ioc_tag = qio_channel_add_watch( vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_OUT, vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_OUT,
@@ -296,6 +308,7 @@ static int vnc_worker_thread_loop(VncJobQueue *queue)
n_rectangles += n; n_rectangles += n;
} }
} }
QLIST_REMOVE(entry, next);
g_free(entry); g_free(entry);
} }
trace_vnc_job_nrects(&vs, job, n_rectangles); trace_vnc_job_nrects(&vs, job, n_rectangles);
@@ -324,7 +337,7 @@ disconnected:
QTAILQ_REMOVE(&queue->jobs, job, next); QTAILQ_REMOVE(&queue->jobs, job, next);
vnc_unlock_queue(queue); vnc_unlock_queue(queue);
qemu_cond_broadcast(&queue->cond); qemu_cond_broadcast(&queue->cond);
g_free(job); vnc_job_free(job);
vs.magic = 0; vs.magic = 0;
return 0; return 0;
} }

View File

@@ -1301,10 +1301,7 @@ static void vnc_disconnect_start(VncState *vs)
} }
trace_vnc_client_disconnect_start(vs, vs->ioc); trace_vnc_client_disconnect_start(vs, vs->ioc);
vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED); vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
if (vs->ioc_tag) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
vs->ioc_tag = 0;
}
qio_channel_close(vs->ioc, NULL); qio_channel_close(vs->ioc, NULL);
vs->disconnecting = TRUE; vs->disconnecting = TRUE;
} }
@@ -1462,9 +1459,7 @@ static size_t vnc_client_write_plain(VncState *vs)
} }
if (vs->output.offset == 0) { if (vs->output.offset == 0) {
if (vs->ioc_tag) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
vs->ioc_tag = qio_channel_add_watch( vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR, vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR,
vnc_client_io, vs, NULL); vnc_client_io, vs, NULL);
@@ -1500,9 +1495,7 @@ static void vnc_client_write(VncState *vs)
if (vs->output.offset) { if (vs->output.offset) {
vnc_client_write_locked(vs); vnc_client_write_locked(vs);
} else if (vs->ioc != NULL) { } else if (vs->ioc != NULL) {
if (vs->ioc_tag) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
vs->ioc_tag = qio_channel_add_watch( vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR, vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR,
vnc_client_io, vs, NULL); vnc_client_io, vs, NULL);
@@ -1638,10 +1631,7 @@ gboolean vnc_client_io(QIOChannel *ioc G_GNUC_UNUSED,
} }
if (vs->disconnecting) { if (vs->disconnecting) {
if (vs->ioc_tag != 0) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
vs->ioc_tag = 0;
} }
return TRUE; return TRUE;
} }
@@ -1684,9 +1674,7 @@ void vnc_write(VncState *vs, const void *data, size_t len)
buffer_reserve(&vs->output, len); buffer_reserve(&vs->output, len);
if (vs->ioc != NULL && buffer_empty(&vs->output)) { if (vs->ioc != NULL && buffer_empty(&vs->output)) {
if (vs->ioc_tag) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
vs->ioc_tag = qio_channel_add_watch( vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_OUT, vs->ioc, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_OUT,
vnc_client_io, vs, NULL); vnc_client_io, vs, NULL);
@@ -1734,10 +1722,7 @@ void vnc_flush(VncState *vs)
vnc_client_write_locked(vs); vnc_client_write_locked(vs);
} }
if (vs->disconnecting) { if (vs->disconnecting) {
if (vs->ioc_tag != 0) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
vs->ioc_tag = 0;
} }
vnc_unlock_output(vs); vnc_unlock_output(vs);
} }
@@ -3342,9 +3327,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
VNC_DEBUG("New client on socket %p\n", vs->sioc); VNC_DEBUG("New client on socket %p\n", vs->sioc);
update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE); update_displaychangelistener(&vd->dcl, VNC_REFRESH_INTERVAL_BASE);
qio_channel_set_blocking(vs->ioc, false, &error_abort); qio_channel_set_blocking(vs->ioc, false, &error_abort);
if (vs->ioc_tag) { g_clear_handle_id(&vs->ioc_tag, g_source_remove);
g_source_remove(vs->ioc_tag);
}
if (websocket) { if (websocket) {
vs->websocket = 1; vs->websocket = 1;
if (vd->tlscreds) { if (vd->tlscreds) {