This fixes surface texture double free with multiple connections and out-of-sync display size with multiple displays.
This also reduces resource usage a little and allows to remove code to support multiple listeners for OpenGL displays. Signed-off-by: Akihiko Odaki <akihiko.od...@gmail.com> --- ui/dbus-console.c | 109 +++--------- ui/dbus-listener.c | 401 +++++++++++++++++++++++++++++++++------------ ui/dbus.h | 32 +++- 3 files changed, 344 insertions(+), 198 deletions(-) diff --git a/ui/dbus-console.c b/ui/dbus-console.c index e062f721d76..ec035c427db 100644 --- a/ui/dbus-console.c +++ b/ui/dbus-console.c @@ -33,11 +33,10 @@ struct _DBusDisplayConsole { GDBusObjectSkeleton parent_instance; - DisplayChangeListener dcl; DBusDisplay *display; QemuConsole *con; - GHashTable *listeners; + DBusDisplayListener *listener; QemuDBusDisplay1Console *iface; QemuDBusDisplay1Keyboard *iface_kbd; @@ -54,7 +53,7 @@ G_DEFINE_TYPE(DBusDisplayConsole, dbus_display_console, G_TYPE_DBUS_OBJECT_SKELETON) -static void +void dbus_display_console_set_size(DBusDisplayConsole *ddc, uint32_t width, uint32_t height) { @@ -64,78 +63,9 @@ dbus_display_console_set_size(DBusDisplayConsole *ddc, NULL); } -static void -dbus_gfx_switch(DisplayChangeListener *dcl, - struct DisplaySurface *new_surface) -{ - DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl); - - dbus_display_console_set_size(ddc, - surface_width(new_surface), - surface_height(new_surface)); -} - -static void -dbus_gfx_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) -{ -} - -static void -dbus_gl_scanout_disable(DisplayChangeListener *dcl) -{ -} - -static void -dbus_gl_scanout_texture(DisplayChangeListener *dcl, - uint32_t tex_id, - bool backing_y_0_top, - uint32_t backing_width, - uint32_t backing_height, - uint32_t x, uint32_t y, - uint32_t w, uint32_t h) -{ - DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl); - - dbus_display_console_set_size(ddc, w, h); -} - -static void -dbus_gl_scanout_dmabuf(DisplayChangeListener *dcl, - QemuDmaBuf *dmabuf) -{ - DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl); - - dbus_display_console_set_size(ddc, - dmabuf->width, - dmabuf->height); -} - -static void -dbus_gl_scanout_update(DisplayChangeListener *dcl, - uint32_t x, uint32_t y, - uint32_t w, uint32_t h) -{ -} - -static const DisplayChangeListenerOps dbus_console_dcl_ops = { - .dpy_name = "dbus-console", - .dpy_gfx_switch = dbus_gfx_switch, - .dpy_gfx_update = dbus_gfx_update, - .dpy_gl_scanout_disable = dbus_gl_scanout_disable, - .dpy_gl_scanout_texture = dbus_gl_scanout_texture, - .dpy_gl_scanout_dmabuf = dbus_gl_scanout_dmabuf, - .dpy_gl_update = dbus_gl_scanout_update, -}; - static void dbus_display_console_init(DBusDisplayConsole *object) { - DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object); - - ddc->listeners = g_hash_table_new_full(g_str_hash, g_str_equal, - NULL, g_object_unref); - ddc->dcl.ops = &dbus_console_dcl_ops; } static void @@ -143,10 +73,10 @@ dbus_display_console_dispose(GObject *object) { DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object); - unregister_displaychangelistener(&ddc->dcl); g_clear_object(&ddc->iface_kbd); g_clear_object(&ddc->iface); - g_clear_pointer(&ddc->listeners, g_hash_table_unref); + dbus_display_listener_unref_all_connections(ddc->listener); + g_clear_object(&ddc->listener); g_clear_pointer(&ddc->kbd, qkbd_state_free); G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object); @@ -161,14 +91,14 @@ dbus_display_console_class_init(DBusDisplayConsoleClass *klass) } static void -listener_vanished_cb(DBusDisplayListener *listener) +listener_vanished_cb(DBusDisplayListenerConnection *ddlc) { - DBusDisplayConsole *ddc = dbus_display_listener_get_console(listener); - const char *name = dbus_display_listener_get_bus_name(listener); + DBusDisplayConsole *ddc = dbus_display_listener_connection_get_console(ddlc); + const char *name = dbus_display_listener_connection_get_bus_name(ddlc); trace_dbus_listener_vanished(name); - g_hash_table_remove(ddc->listeners, name); + g_object_unref(ddlc); qkbd_state_lift_all_keys(ddc->kbd); } @@ -211,15 +141,15 @@ dbus_console_register_listener(DBusDisplayConsole *ddc, GVariant *arg_listener) { const char *sender = g_dbus_method_invocation_get_sender(invocation); - GDBusConnection *listener_conn; + GDBusConnection *conn; g_autoptr(GError) err = NULL; g_autoptr(GSocket) socket = NULL; g_autoptr(GSocketConnection) socket_conn = NULL; g_autofree char *guid = g_dbus_generate_guid(); - DBusDisplayListener *listener; + DBusDisplayListenerConnection *listener_conn; int fd; - if (sender && g_hash_table_contains(ddc->listeners, sender)) { + if (sender && dbus_display_listener_has_connection(ddc->listener, sender)) { g_dbus_method_invocation_return_error( invocation, DBUS_DISPLAY_ERROR, @@ -254,7 +184,7 @@ dbus_console_register_listener(DBusDisplayConsole *ddc, qemu_dbus_display1_console_complete_register_listener( ddc->iface, invocation, NULL); - listener_conn = g_dbus_connection_new_sync( + conn = g_dbus_connection_new_sync( G_IO_STREAM(socket_conn), guid, G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER, @@ -264,16 +194,15 @@ dbus_console_register_listener(DBusDisplayConsole *ddc, return DBUS_METHOD_INVOCATION_HANDLED; } - listener = dbus_display_listener_new(sender, listener_conn, ddc); - if (!listener) { + listener_conn = dbus_display_listener_add_connection(ddc->listener, + sender, conn); + if (!listener_conn) { return DBUS_METHOD_INVOCATION_HANDLED; } - g_hash_table_insert(ddc->listeners, - (gpointer)dbus_display_listener_get_bus_name(listener), - listener); - g_object_connect(listener_conn, - "swapped-signal::closed", listener_vanished_cb, listener, + g_object_connect(conn, + "swapped-signal::closed", listener_vanished_cb, + listener_conn, NULL); trace_dbus_registered_listener(sender); @@ -489,7 +418,7 @@ dbus_display_console_new(DBusDisplay *display, QemuConsole *con) g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse)); - register_displaychangelistener(&ddc->dcl); + ddc->listener = dbus_display_listener_new(ddc); ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change; qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier); diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 81c119b13a2..e4242d69de2 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -31,18 +31,36 @@ #include "ui/egl-context.h" #include "trace.h" -struct _DBusDisplayListener { +struct _DBusDisplayListenerConnection { GObject parent; char *bus_name; - DBusDisplayConsole *console; + DBusDisplayListener *listener; GDBusConnection *conn; QemuDBusDisplay1Listener *proxy; +}; + +G_DEFINE_TYPE(DBusDisplayListenerConnection, + dbus_display_listener_connection, + G_TYPE_OBJECT) + +struct _DBusDisplayListener { + GObject parent; + + GHashTable *conns; + DBusDisplayConsole *console; DisplayChangeListener dcl; DisplaySurface *ds; QemuGLShader *gls; + GUnixFDList *dmabuf_fd_list; + uint32_t dmabuf_width; + uint32_t dmabuf_height; + uint32_t dmabuf_stride; + uint32_t dmabuf_fourcc; + uint64_t dmabuf_modifier; + bool dmabuf_y0_top; int gl_updates; }; @@ -53,65 +71,98 @@ static void dbus_update_gl_cb(GObject *source_object, gpointer user_data) { g_autoptr(GError) err = NULL; - DBusDisplayListener *ddl = user_data; + DBusDisplayListenerConnection *ddlc = user_data; - if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddl->proxy, + if (!qemu_dbus_display1_listener_call_update_dmabuf_finish(ddlc->proxy, res, &err)) { error_report("Failed to call update: %s", err->message); } - graphic_hw_gl_block(ddl->dcl.con, false); - g_object_unref(ddl); + graphic_hw_gl_block(ddlc->listener->dcl.con, false); + g_object_unref(ddlc); } static void dbus_call_update_gl(DBusDisplayListener *ddl, int x, int y, int w, int h) { - graphic_hw_gl_block(ddl->dcl.con, true); - glFlush(); - qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy, - x, y, w, h, - G_DBUS_CALL_FLAGS_NONE, - DBUS_DEFAULT_TIMEOUT, NULL, - dbus_update_gl_cb, - g_object_ref(ddl)); + GHashTableIter iter; + gpointer ddlc; + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + graphic_hw_gl_block(ddl->dcl.con, true); + glFlush(); + qemu_dbus_display1_listener_call_update_dmabuf( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + x, y, w, h, + G_DBUS_CALL_FLAGS_NONE, + DBUS_DEFAULT_TIMEOUT, NULL, + dbus_update_gl_cb, + g_object_ref(ddlc)); + } } static void dbus_scanout_disable(DisplayChangeListener *dcl) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); + GHashTableIter iter; + gpointer ddlc; ddl->ds = NULL; - qemu_dbus_display1_listener_call_disable( - ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_disable( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + } } static void dbus_scanout_dmabuf(DisplayChangeListener *dcl, QemuDmaBuf *dmabuf) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); + GHashTableIter iter; + gpointer ddlc; g_autoptr(GError) err = NULL; g_autoptr(GUnixFDList) fd_list = NULL; - fd_list = g_unix_fd_list_new(); - if (g_unix_fd_list_append(fd_list, dmabuf->fd, &err) != 0) { + if (ddl->dmabuf_fd_list) { + g_clear_object(&ddl->dmabuf_fd_list); + } + + ddl->dmabuf_fd_list = g_unix_fd_list_new(); + if (g_unix_fd_list_append(ddl->dmabuf_fd_list, dmabuf->fd, &err) != 0) { + g_clear_object(&ddl->dmabuf_fd_list); error_report("Failed to setup dmabuf fdlist: %s", err->message); return; } - qemu_dbus_display1_listener_call_scanout_dmabuf( - ddl->proxy, - g_variant_new_handle(0), - dmabuf->width, - dmabuf->height, - dmabuf->stride, - dmabuf->fourcc, - dmabuf->modifier, - dmabuf->y0_top, - G_DBUS_CALL_FLAGS_NONE, - -1, - fd_list, - NULL, NULL, NULL); + ddl->dmabuf_width = dmabuf->width; + ddl->dmabuf_height = dmabuf->height; + ddl->dmabuf_stride = dmabuf->stride; + ddl->dmabuf_fourcc = dmabuf->fourcc; + ddl->dmabuf_modifier = dmabuf->modifier; + ddl->dmabuf_y0_top = dmabuf->y0_top; + + dbus_display_console_set_size(ddl->console, dmabuf->width, dmabuf->height); + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_scanout_dmabuf( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + g_variant_new_handle(0), + ddl->dmabuf_width, + ddl->dmabuf_height, + ddl->dmabuf_stride, + ddl->dmabuf_fourcc, + ddl->dmabuf_modifier, + ddl->dmabuf_y0_top, + G_DBUS_CALL_FLAGS_NONE, + -1, + ddl->dmabuf_fd_list, + NULL, NULL, NULL); + } } static void dbus_scanout_texture(DisplayChangeListener *dcl, @@ -150,11 +201,16 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl, DisplaySurface *ds; GVariant *v_data = NULL; egl_fb cursor_fb; + GHashTableIter iter; + gpointer ddlc; if (!dmabuf) { - qemu_dbus_display1_listener_call_mouse_set( - ddl->proxy, 0, 0, false, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_mouse_set( + ((DBusDisplayListenerConnection *)ddlc)->proxy, 0, 0, false, + G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + } return; } @@ -174,28 +230,37 @@ static void dbus_cursor_dmabuf(DisplayChangeListener *dcl, TRUE, (GDestroyNotify)qemu_free_displaysurface, ds); - qemu_dbus_display1_listener_call_cursor_define( - ddl->proxy, - surface_width(ds), - surface_height(ds), - hot_x, - hot_y, - v_data, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_cursor_define( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + surface_width(ds), + surface_height(ds), + hot_x, + hot_y, + v_data, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + } } static void dbus_cursor_position(DisplayChangeListener *dcl, uint32_t pos_x, uint32_t pos_y) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); + GHashTableIter iter; + gpointer ddlc; - qemu_dbus_display1_listener_call_mouse_set( - ddl->proxy, pos_x, pos_y, true, - G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_mouse_set( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + pos_x, pos_y, true, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + } } static void dbus_release_dmabuf(DisplayChangeListener *dcl, @@ -254,6 +319,8 @@ static void dbus_gfx_update(DisplayChangeListener *dcl, pixman_image_t *img; GVariant *v_data; size_t stride; + GHashTableIter iter; + gpointer ddlc; assert(ddl->ds); stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8); @@ -273,11 +340,16 @@ static void dbus_gfx_update(DisplayChangeListener *dcl, TRUE, (GDestroyNotify)pixman_image_unref, img); - qemu_dbus_display1_listener_call_update(ddl->proxy, - x, y, w, h, pixman_image_get_stride(img), pixman_image_get_format(img), - v_data, - G_DBUS_CALL_FLAGS_NONE, - DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_update( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + x, y, w, h, pixman_image_get_stride(img), pixman_image_get_format(img), + v_data, + G_DBUS_CALL_FLAGS_NONE, + DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + } } static void dbus_gl_gfx_switch(DisplayChangeListener *dcl, @@ -293,6 +365,8 @@ static void dbus_gl_gfx_switch(DisplayChangeListener *dcl, int width = surface_width(ddl->ds); int height = surface_height(ddl->ds); + dbus_display_console_set_size(ddl->console, width, height); + surface_gl_create_texture(ddl->gls, ddl->ds); /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */ dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false, @@ -305,6 +379,8 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); GVariant *v_data = NULL; + GHashTableIter iter; + gpointer ddlc; ddl->ds = new_surface; if (!ddl->ds) { @@ -312,6 +388,10 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, return; } + dbus_display_console_set_size(ddl->console, + surface_width(ddl->ds), + surface_height(ddl->ds)); + v_data = g_variant_new_from_data( G_VARIANT_TYPE("ay"), surface_data(ddl->ds), @@ -319,23 +399,34 @@ static void dbus_gfx_switch(DisplayChangeListener *dcl, TRUE, (GDestroyNotify)pixman_image_unref, pixman_image_ref(ddl->ds->image)); - qemu_dbus_display1_listener_call_scanout(ddl->proxy, - surface_width(ddl->ds), - surface_height(ddl->ds), - surface_stride(ddl->ds), - surface_format(ddl->ds), - v_data, - G_DBUS_CALL_FLAGS_NONE, - DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_scanout( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + surface_width(ddl->ds), + surface_height(ddl->ds), + surface_stride(ddl->ds), + surface_format(ddl->ds), + v_data, + G_DBUS_CALL_FLAGS_NONE, + DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + } } static void dbus_mouse_set(DisplayChangeListener *dcl, int x, int y, int on) { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); + GHashTableIter iter; + gpointer ddlc; - qemu_dbus_display1_listener_call_mouse_set( - ddl->proxy, x, y, on, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_mouse_set( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + x, y, on, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + } } static void dbus_cursor_define(DisplayChangeListener *dcl, @@ -343,6 +434,8 @@ static void dbus_cursor_define(DisplayChangeListener *dcl, { DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl); GVariant *v_data = NULL; + GHashTableIter iter; + gpointer ddlc; cursor_get(c); v_data = g_variant_new_from_data( @@ -353,18 +446,21 @@ static void dbus_cursor_define(DisplayChangeListener *dcl, (GDestroyNotify)cursor_put, c); - qemu_dbus_display1_listener_call_cursor_define( - ddl->proxy, - c->width, - c->height, - c->hot_x, - c->hot_y, - v_data, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - NULL, - NULL); + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + qemu_dbus_display1_listener_call_cursor_define( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + c->width, + c->height, + c->hot_x, + c->hot_y, + v_data, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); + } } const DisplayChangeListenerOps dbus_gl_dcl_ops = { @@ -400,9 +496,8 @@ dbus_display_listener_dispose(GObject *object) DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object); unregister_displaychangelistener(&ddl->dcl); - g_clear_object(&ddl->conn); - g_clear_pointer(&ddl->bus_name, g_free); - g_clear_object(&ddl->proxy); + g_clear_object(&ddl->dmabuf_fd_list); + g_clear_pointer(&ddl->conns, g_hash_table_unref); g_clear_pointer(&ddl->gls, qemu_gl_fini_shader); G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object); @@ -435,46 +530,146 @@ dbus_display_listener_class_init(DBusDisplayListenerClass *klass) static void dbus_display_listener_init(DBusDisplayListener *ddl) { + ddl->conns = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL); } -const char * -dbus_display_listener_get_bus_name(DBusDisplayListener *ddl) -{ - return ddl->bus_name ?: "p2p"; -} - -DBusDisplayConsole * -dbus_display_listener_get_console(DBusDisplayListener *ddl) +DBusDisplayListenerConnection * +dbus_display_listener_add_connection(DBusDisplayListener *ddl, + const char *bus_name, + GDBusConnection *conn) { - return ddl->console; -} - -DBusDisplayListener * -dbus_display_listener_new(const char *bus_name, - GDBusConnection *conn, - DBusDisplayConsole *console) -{ - DBusDisplayListener *ddl; - QemuConsole *con; + DBusDisplayListenerConnection *ddlc; + QemuDBusDisplay1Listener *proxy; g_autoptr(GError) err = NULL; - ddl = g_object_new(DBUS_DISPLAY_TYPE_LISTENER, NULL); - ddl->proxy = + proxy = qemu_dbus_display1_listener_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, "/org/qemu/Display1/Listener", NULL, &err); - if (!ddl->proxy) { + if (!proxy) { error_report("Failed to setup proxy: %s", err->message); g_object_unref(conn); - g_object_unref(ddl); return NULL; } - ddl->bus_name = g_strdup(bus_name); - ddl->conn = conn; + ddlc = g_object_new(DBUS_DISPLAY_TYPE_LISTENER_CONNECTION, NULL); + ddlc->listener = g_object_ref(ddl); + ddlc->proxy = proxy; + ddlc->bus_name = g_strdup(bus_name); + ddlc->conn = conn; + + g_hash_table_insert(ddl->conns, ddlc->bus_name, ddlc); + + if (display_opengl) { + if (ddl->dmabuf_fd_list) { + qemu_dbus_display1_listener_call_scanout_dmabuf( + ddlc->proxy, + g_variant_new_handle(0), + ddl->dmabuf_width, + ddl->dmabuf_height, + ddl->dmabuf_stride, + ddl->dmabuf_fourcc, + ddl->dmabuf_modifier, + ddl->dmabuf_y0_top, + G_DBUS_CALL_FLAGS_NONE, + -1, + ddl->dmabuf_fd_list, + NULL, NULL, NULL); + } + } else { + if (ddl->ds) { + GVariant *v_data = NULL; + + v_data = g_variant_new_from_data( + G_VARIANT_TYPE("ay"), + surface_data(ddl->ds), + surface_stride(ddl->ds) * surface_height(ddl->ds), + TRUE, + (GDestroyNotify)pixman_image_unref, + pixman_image_ref(ddl->ds->image)); + + qemu_dbus_display1_listener_call_scanout( + ((DBusDisplayListenerConnection *)ddlc)->proxy, + surface_width(ddl->ds), + surface_height(ddl->ds), + surface_stride(ddl->ds), + surface_format(ddl->ds), + v_data, + G_DBUS_CALL_FLAGS_NONE, + DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL); + } + } + + return ddlc; +} + +bool +dbus_display_listener_has_connection(DBusDisplayListener *ddl, + const char *bus_name) +{ + return g_hash_table_contains(ddl->conns, bus_name); +} + +void +dbus_display_listener_unref_all_connections(DBusDisplayListener *ddl) +{ + GHashTableIter iter; + gpointer ddlc; + + g_hash_table_iter_init(&iter, ddl->conns); + while (g_hash_table_iter_next(&iter, NULL, &ddlc)) { + g_object_unref(ddlc); + } +} + +static void +dbus_display_listener_connection_dispose(GObject *object) +{ + DBusDisplayListenerConnection *ddlc = + DBUS_DISPLAY_LISTENER_CONNECTION(object); + + g_hash_table_remove(ddlc->listener->conns, ddlc->bus_name); + g_clear_object(&ddlc->listener); + g_clear_object(&ddlc->conn); + g_clear_pointer(&ddlc->bus_name, g_free); + g_clear_object(&ddlc->proxy); + + G_OBJECT_CLASS(dbus_display_listener_connection_parent_class)->dispose(object); +} + +static void +dbus_display_listener_connection_class_init(DBusDisplayListenerConnectionClass *klass) +{ + G_OBJECT_CLASS(klass)->dispose = dbus_display_listener_connection_dispose; +} + +static void +dbus_display_listener_connection_init(DBusDisplayListenerConnection *ddl) +{ +} + +const char * +dbus_display_listener_connection_get_bus_name(DBusDisplayListenerConnection *ddlc) +{ + return ddlc->bus_name ?: "p2p"; +} + +DBusDisplayConsole * +dbus_display_listener_connection_get_console(DBusDisplayListenerConnection *ddlc) +{ + return ddlc->listener->console; +} + +DBusDisplayListener * +dbus_display_listener_new(DBusDisplayConsole *console) +{ + DBusDisplayListener *ddl; + QemuConsole *con; + + ddl = g_object_new(DBUS_DISPLAY_TYPE_LISTENER, NULL); ddl->console = console; con = qemu_console_lookup_by_index(dbus_display_console_get_index(console)); diff --git a/ui/dbus.h b/ui/dbus.h index 64c77cab444..fd24b299bbf 100644 --- a/ui/dbus.h +++ b/ui/dbus.h @@ -76,9 +76,19 @@ G_DECLARE_FINAL_TYPE(DBusDisplayConsole, DBusDisplayConsole * dbus_display_console_new(DBusDisplay *display, QemuConsole *con); +void +dbus_display_console_set_size(DBusDisplayConsole *ddc, + uint32_t width, uint32_t height); + int dbus_display_console_get_index(DBusDisplayConsole *ddc); +G_DECLARE_FINAL_TYPE(DBusDisplayListenerConnection, + dbus_display_listener_connection, + DBUS_DISPLAY, + LISTENER_CONNECTION, + GObject) + #define DBUS_DISPLAY_TYPE_LISTENER dbus_display_listener_get_type() G_DECLARE_FINAL_TYPE(DBusDisplayListener, dbus_display_listener, @@ -86,16 +96,28 @@ G_DECLARE_FINAL_TYPE(DBusDisplayListener, LISTENER, GObject) +#define DBUS_DISPLAY_TYPE_LISTENER_CONNECTION \ + dbus_display_listener_connection_get_type() DBusDisplayListener * -dbus_display_listener_new(const char *bus_name, - GDBusConnection *conn, - DBusDisplayConsole *console); +dbus_display_listener_new(DBusDisplayConsole *console); + +DBusDisplayListenerConnection * +dbus_display_listener_add_connection(DBusDisplayListener *ddl, + const char *bus_name, + GDBusConnection *conn); + +bool +dbus_display_listener_has_connection(DBusDisplayListener *ddl, + const char *bus_name); + +void +dbus_display_listener_unref_all_connections(DBusDisplayListener *ddl); DBusDisplayConsole * -dbus_display_listener_get_console(DBusDisplayListener *ddl); +dbus_display_listener_connection_get_console(DBusDisplayListenerConnection *ddlc); const char * -dbus_display_listener_get_bus_name(DBusDisplayListener *ddl); +dbus_display_listener_connection_get_bus_name(DBusDisplayListenerConnection *ddlc); extern const DisplayChangeListenerOps dbus_gl_dcl_ops; extern const DisplayChangeListenerOps dbus_dcl_ops; -- 2.32.0 (Apple Git-132)