2 * QEMU DBus display console
4 * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 #include "qemu/osdep.h"
25 #include "qemu/error-report.h"
26 #include "qapi/error.h"
27 #include "sysemu/sysemu.h"
30 #include <gio/gunixfdlist.h>
38 #include "ui/shader.h"
39 #include "ui/egl-helpers.h"
40 #include "ui/egl-context.h"
41 #include "ui/qemu-pixman.h"
45 static void dbus_gfx_switch(DisplayChangeListener *dcl,
46 struct DisplaySurface *new_surface);
54 struct _DBusDisplayListener {
58 DBusDisplayConsole *console;
59 GDBusConnection *conn;
61 QemuDBusDisplay1Listener *proxy;
64 /* Keep track of the damage region */
65 pixman_region32_t gl_damage;
70 DisplayChangeListener dcl;
72 enum share_kind ds_share;
78 QemuDBusDisplay1ListenerWin32Map *map_proxy;
79 QemuDBusDisplay1ListenerWin32D3d11 *d3d11_proxy;
81 ID3D11Texture2D *d3d_texture;
88 G_DEFINE_TYPE(DBusDisplayListener, dbus_display_listener, G_TYPE_OBJECT)
90 static void dbus_gfx_update(DisplayChangeListener *dcl,
91 int x, int y, int w, int h);
94 static void dbus_scanout_disable(DisplayChangeListener *dcl)
96 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
98 qemu_dbus_display1_listener_call_disable(
99 ddl->proxy, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
103 static bool d3d_texture2d_share(ID3D11Texture2D *d3d_texture,
104 HANDLE *handle, Error **errp)
106 IDXGIResource1 *dxgiResource = NULL;
109 hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
111 (void **)&dxgiResource);
116 hr = dxgiResource->lpVtbl->CreateSharedHandle(
119 DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
124 dxgiResource->lpVtbl->Release(dxgiResource);
131 error_setg_win32(errp, GetLastError(), "failed to create shared handle");
135 static bool d3d_texture2d_acquire0(ID3D11Texture2D *d3d_texture, Error **errp)
137 IDXGIKeyedMutex *dxgiMutex = NULL;
140 hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
141 &IID_IDXGIKeyedMutex,
142 (void **)&dxgiMutex);
147 hr = dxgiMutex->lpVtbl->AcquireSync(dxgiMutex, 0, INFINITE);
149 dxgiMutex->lpVtbl->Release(dxgiMutex);
156 error_setg_win32(errp, GetLastError(), "failed to acquire texture mutex");
160 static bool d3d_texture2d_release0(ID3D11Texture2D *d3d_texture, Error **errp)
162 IDXGIKeyedMutex *dxgiMutex = NULL;
165 hr = d3d_texture->lpVtbl->QueryInterface(d3d_texture,
166 &IID_IDXGIKeyedMutex,
167 (void **)&dxgiMutex);
172 hr = dxgiMutex->lpVtbl->ReleaseSync(dxgiMutex, 0);
174 dxgiMutex->lpVtbl->Release(dxgiMutex);
181 error_setg_win32(errp, GetLastError(), "failed to release texture mutex");
186 #if defined(CONFIG_GBM) || defined(WIN32)
187 static void dbus_update_gl_cb(GObject *source_object,
191 g_autoptr(GError) err = NULL;
192 DBusDisplayListener *ddl = user_data;
196 success = qemu_dbus_display1_listener_call_update_dmabuf_finish(
197 ddl->proxy, res, &err);
201 success = qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
202 ddl->d3d11_proxy, res, &err);
203 d3d_texture2d_acquire0(ddl->d3d_texture, &error_warn);
207 error_report("Failed to call update: %s", err->message);
210 graphic_hw_gl_block(ddl->dcl.con, false);
215 static void dbus_call_update_gl(DisplayChangeListener *dcl,
216 int x, int y, int w, int h)
218 #if defined(CONFIG_GBM) || defined(WIN32)
219 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
222 trace_dbus_update_gl(x, y, w, h);
226 graphic_hw_gl_block(ddl->dcl.con, true);
227 qemu_dbus_display1_listener_call_update_dmabuf(ddl->proxy,
229 G_DBUS_CALL_FLAGS_NONE,
230 DBUS_DEFAULT_TIMEOUT, NULL,
236 switch (ddl->ds_share) {
237 case SHARE_KIND_MAPPED:
238 egl_fb_read_rect(ddl->ds, &ddl->fb, x, y, w, h);
239 dbus_gfx_update(dcl, x, y, w, h);
241 case SHARE_KIND_D3DTEX: {
243 assert(ddl->d3d_texture);
245 graphic_hw_gl_block(ddl->dcl.con, true);
246 if (!d3d_texture2d_release0(ddl->d3d_texture, &err)) {
247 error_report_err(err);
250 qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
253 G_DBUS_CALL_FLAGS_NONE,
254 DBUS_DEFAULT_TIMEOUT, NULL,
266 static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
269 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
270 g_autoptr(GError) err = NULL;
271 g_autoptr(GUnixFDList) fd_list = NULL;
273 fd_list = g_unix_fd_list_new();
274 if (g_unix_fd_list_append(fd_list, dmabuf->fd, &err) != 0) {
275 error_report("Failed to setup dmabuf fdlist: %s", err->message);
279 /* FIXME: add missing x/y/w/h support */
280 qemu_dbus_display1_listener_call_scanout_dmabuf(
282 g_variant_new_handle(0),
289 G_DBUS_CALL_FLAGS_NONE,
298 static bool dbus_scanout_map(DBusDisplayListener *ddl)
300 g_autoptr(GError) err = NULL;
302 HANDLE target_handle;
304 if (ddl->ds_share == SHARE_KIND_MAPPED) {
308 if (!ddl->can_share_map || !ddl->ds->handle) {
312 success = DuplicateHandle(
317 FILE_MAP_READ | SECTION_QUERY,
320 g_autofree char *msg = g_win32_error_message(GetLastError());
321 g_debug("Failed to DuplicateHandle: %s", msg);
322 ddl->can_share_map = false;
326 if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
328 GPOINTER_TO_UINT(target_handle),
329 ddl->ds->handle_offset,
330 surface_width(ddl->ds),
331 surface_height(ddl->ds),
332 surface_stride(ddl->ds),
333 surface_format(ddl->ds),
334 G_DBUS_CALL_FLAGS_NONE,
335 DBUS_DEFAULT_TIMEOUT,
338 g_debug("Failed to call ScanoutMap: %s", err->message);
339 ddl->can_share_map = false;
343 ddl->ds_share = SHARE_KIND_MAPPED;
350 dbus_scanout_share_d3d_texture(
351 DBusDisplayListener *ddl,
352 ID3D11Texture2D *tex,
353 bool backing_y_0_top,
354 uint32_t backing_width,
355 uint32_t backing_height,
356 uint32_t x, uint32_t y,
357 uint32_t w, uint32_t h)
361 HANDLE share_handle, target_handle;
363 if (!d3d_texture2d_release0(tex, &err)) {
364 error_report_err(err);
368 if (!d3d_texture2d_share(tex, &share_handle, &err)) {
369 error_report_err(err);
373 success = DuplicateHandle(
379 FALSE, DUPLICATE_SAME_ACCESS);
381 g_autofree char *msg = g_win32_error_message(GetLastError());
382 g_debug("Failed to DuplicateHandle: %s", msg);
383 CloseHandle(share_handle);
387 qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
389 GPOINTER_TO_INT(target_handle),
394 G_DBUS_CALL_FLAGS_NONE,
398 CloseHandle(share_handle);
400 if (!d3d_texture2d_acquire0(tex, &err)) {
401 error_report_err(err);
405 ddl->d3d_texture = tex;
406 ddl->ds_share = SHARE_KIND_D3DTEX;
410 #endif /* CONFIG_OPENGL */
414 static void dbus_scanout_texture(DisplayChangeListener *dcl,
416 bool backing_y_0_top,
417 uint32_t backing_width,
418 uint32_t backing_height,
419 uint32_t x, uint32_t y,
420 uint32_t w, uint32_t h,
423 trace_dbus_scanout_texture(tex_id, backing_y_0_top,
424 backing_width, backing_height, x, y, w, h);
426 QemuDmaBuf dmabuf = {
429 .y0_top = backing_y_0_top,
432 .backing_width = backing_width,
433 .backing_height = backing_height,
437 dmabuf.fd = egl_get_fd_for_texture(
438 tex_id, (EGLint *)&dmabuf.stride,
439 (EGLint *)&dmabuf.fourcc,
442 error_report("%s: failed to get fd for texture", __func__);
446 dbus_scanout_dmabuf(dcl, &dmabuf);
451 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
453 /* there must be a matching gfx_switch before */
454 assert(surface_width(ddl->ds) == w);
455 assert(surface_height(ddl->ds) == h);
458 dbus_scanout_share_d3d_texture(ddl, d3d_tex2d, backing_y_0_top,
459 backing_width, backing_height, x, y, w, h);
461 dbus_scanout_map(ddl);
462 egl_fb_setup_for_tex(&ddl->fb, backing_width, backing_height, tex_id, false);
468 static void dbus_cursor_dmabuf(DisplayChangeListener *dcl,
469 QemuDmaBuf *dmabuf, bool have_hot,
470 uint32_t hot_x, uint32_t hot_y)
472 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
474 GVariant *v_data = NULL;
475 egl_fb cursor_fb = EGL_FB_INIT;
478 qemu_dbus_display1_listener_call_mouse_set(
479 ddl->proxy, 0, 0, false,
480 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
484 egl_dmabuf_import_texture(dmabuf);
485 if (!dmabuf->texture) {
488 egl_fb_setup_for_tex(&cursor_fb, dmabuf->width, dmabuf->height,
489 dmabuf->texture, false);
490 ds = qemu_create_displaysurface(dmabuf->width, dmabuf->height);
491 egl_fb_read(ds, &cursor_fb);
493 v_data = g_variant_new_from_data(
494 G_VARIANT_TYPE("ay"),
496 surface_width(ds) * surface_height(ds) * 4,
498 (GDestroyNotify)qemu_free_displaysurface,
500 qemu_dbus_display1_listener_call_cursor_define(
507 G_DBUS_CALL_FLAGS_NONE,
514 static void dbus_release_dmabuf(DisplayChangeListener *dcl,
517 dbus_scanout_disable(dcl);
521 static void dbus_gl_cursor_position(DisplayChangeListener *dcl,
522 uint32_t pos_x, uint32_t pos_y)
524 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
526 qemu_dbus_display1_listener_call_mouse_set(
527 ddl->proxy, pos_x, pos_y, true,
528 G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
531 static void dbus_scanout_update(DisplayChangeListener *dcl,
532 uint32_t x, uint32_t y,
533 uint32_t w, uint32_t h)
535 dbus_call_update_gl(dcl, x, y, w, h);
538 static void dbus_gl_refresh(DisplayChangeListener *dcl)
540 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
542 graphic_hw_update(dcl->con);
544 if (!ddl->ds || qemu_console_is_gl_blocked(ddl->dcl.con)) {
549 int n_rects = pixman_region32_n_rects(&ddl->gl_damage);
551 for (int i = 0; i < n_rects; i++) {
553 box = pixman_region32_rectangles(&ddl->gl_damage, NULL) + i;
554 /* TODO: Add a UpdateList call to send multiple updates at once */
555 dbus_call_update_gl(dcl, box->x1, box->y1,
556 box->x2 - box->x1, box->y2 - box->y1);
558 pixman_region32_clear(&ddl->gl_damage);
560 if (ddl->gl_damage) {
561 dbus_call_update_gl(dcl, 0, 0,
562 surface_width(ddl->ds), surface_height(ddl->ds));
569 static void dbus_refresh(DisplayChangeListener *dcl)
571 graphic_hw_update(dcl->con);
575 static void dbus_gl_gfx_update(DisplayChangeListener *dcl,
576 int x, int y, int w, int h)
578 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
581 pixman_region32_t rect_region;
582 pixman_region32_init_rect(&rect_region, x, y, w, h);
583 pixman_region32_union(&ddl->gl_damage, &ddl->gl_damage, &rect_region);
584 pixman_region32_fini(&rect_region);
591 static void dbus_gfx_update_sub(DBusDisplayListener *ddl,
592 int x, int y, int w, int h)
598 /* make a copy, since gvariant only handles linear data */
599 stride = w * DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl->ds)), 8);
600 img = pixman_image_create_bits(surface_format(ddl->ds),
603 pixman_image_composite(PIXMAN_OP_SRC, ddl->ds->image, NULL, img,
604 x, y, 0, 0, 0, 0, w, h);
607 uint8_t *src = (uint8_t *)pixman_image_get_data(ddl->ds->image);
608 uint8_t *dst = (uint8_t *)pixman_image_get_data(img);
609 int bp = PIXMAN_FORMAT_BPP(surface_format(ddl->ds)) / 8;
612 for (hh = 0; hh < h; hh++) {
613 memcpy(&dst[stride * hh],
614 &src[surface_stride(ddl->ds) * (hh + y) + x * bp],
619 v_data = g_variant_new_from_data(
620 G_VARIANT_TYPE("ay"),
621 pixman_image_get_data(img),
622 pixman_image_get_stride(img) * h,
624 (GDestroyNotify)pixman_image_unref,
626 qemu_dbus_display1_listener_call_update(ddl->proxy,
627 x, y, w, h, pixman_image_get_stride(img), pixman_image_get_format(img),
629 G_DBUS_CALL_FLAGS_NONE,
630 DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
633 static void dbus_gfx_update(DisplayChangeListener *dcl,
634 int x, int y, int w, int h)
636 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
641 trace_dbus_update(x, y, w, h);
644 if (dbus_scanout_map(ddl)) {
645 qemu_dbus_display1_listener_win32_map_call_update_map(
648 G_DBUS_CALL_FLAGS_NONE,
649 DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
654 if (x == 0 && y == 0 && w == surface_width(ddl->ds) && h == surface_height(ddl->ds)) {
655 v_data = g_variant_new_from_data(
656 G_VARIANT_TYPE("ay"),
657 surface_data(ddl->ds),
658 surface_stride(ddl->ds) * surface_height(ddl->ds),
660 (GDestroyNotify)pixman_image_unref,
661 pixman_image_ref(ddl->ds->image));
662 qemu_dbus_display1_listener_call_scanout(
664 surface_width(ddl->ds),
665 surface_height(ddl->ds),
666 surface_stride(ddl->ds),
667 surface_format(ddl->ds),
669 G_DBUS_CALL_FLAGS_NONE,
670 DBUS_DEFAULT_TIMEOUT, NULL, NULL, NULL);
674 dbus_gfx_update_sub(ddl, x, y, w, h);
678 static void dbus_gl_gfx_switch(DisplayChangeListener *dcl,
679 struct DisplaySurface *new_surface)
681 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
683 trace_dbus_gl_gfx_switch(new_surface);
685 ddl->ds = new_surface;
686 ddl->ds_share = SHARE_KIND_NONE;
688 int width = surface_width(ddl->ds);
689 int height = surface_height(ddl->ds);
691 /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
692 dbus_scanout_texture(&ddl->dcl, ddl->ds->texture, false,
693 width, height, 0, 0, width, height, NULL);
698 static void dbus_gfx_switch(DisplayChangeListener *dcl,
699 struct DisplaySurface *new_surface)
701 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
703 ddl->ds = new_surface;
704 ddl->ds_share = SHARE_KIND_NONE;
707 static void dbus_mouse_set(DisplayChangeListener *dcl,
708 int x, int y, int on)
710 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
712 qemu_dbus_display1_listener_call_mouse_set(
713 ddl->proxy, x, y, on, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
716 static void dbus_cursor_define(DisplayChangeListener *dcl,
719 DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
720 GVariant *v_data = NULL;
722 v_data = g_variant_new_from_data(
723 G_VARIANT_TYPE("ay"),
725 c->width * c->height * 4,
727 (GDestroyNotify)cursor_unref,
730 qemu_dbus_display1_listener_call_cursor_define(
737 G_DBUS_CALL_FLAGS_NONE,
745 const DisplayChangeListenerOps dbus_gl_dcl_ops = {
746 .dpy_name = "dbus-gl",
747 .dpy_gfx_update = dbus_gl_gfx_update,
748 .dpy_gfx_switch = dbus_gl_gfx_switch,
749 .dpy_gfx_check_format = console_gl_check_format,
750 .dpy_refresh = dbus_gl_refresh,
751 .dpy_mouse_set = dbus_mouse_set,
752 .dpy_cursor_define = dbus_cursor_define,
754 .dpy_gl_scanout_disable = dbus_scanout_disable,
755 .dpy_gl_scanout_texture = dbus_scanout_texture,
757 .dpy_gl_scanout_dmabuf = dbus_scanout_dmabuf,
758 .dpy_gl_cursor_dmabuf = dbus_cursor_dmabuf,
759 .dpy_gl_release_dmabuf = dbus_release_dmabuf,
761 .dpy_gl_cursor_position = dbus_gl_cursor_position,
762 .dpy_gl_update = dbus_scanout_update,
766 const DisplayChangeListenerOps dbus_dcl_ops = {
768 .dpy_gfx_update = dbus_gfx_update,
769 .dpy_gfx_switch = dbus_gfx_switch,
770 .dpy_refresh = dbus_refresh,
771 .dpy_mouse_set = dbus_mouse_set,
772 .dpy_cursor_define = dbus_cursor_define,
776 dbus_display_listener_dispose(GObject *object)
778 DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
780 unregister_displaychangelistener(&ddl->dcl);
781 g_clear_object(&ddl->conn);
782 g_clear_pointer(&ddl->bus_name, g_free);
783 g_clear_object(&ddl->proxy);
785 g_clear_object(&ddl->map_proxy);
786 g_clear_object(&ddl->d3d11_proxy);
787 g_clear_pointer(&ddl->peer_process, CloseHandle);
789 pixman_region32_fini(&ddl->gl_damage);
792 egl_fb_destroy(&ddl->fb);
796 G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
800 dbus_display_listener_constructed(GObject *object)
802 DBusDisplayListener *ddl = DBUS_DISPLAY_LISTENER(object);
804 ddl->dcl.ops = &dbus_dcl_ops;
806 if (display_opengl) {
807 ddl->dcl.ops = &dbus_gl_dcl_ops;
811 G_OBJECT_CLASS(dbus_display_listener_parent_class)->constructed(object);
815 dbus_display_listener_class_init(DBusDisplayListenerClass *klass)
817 GObjectClass *object_class = G_OBJECT_CLASS(klass);
819 object_class->dispose = dbus_display_listener_dispose;
820 object_class->constructed = dbus_display_listener_constructed;
824 dbus_display_listener_init(DBusDisplayListener *ddl)
827 pixman_region32_init(&ddl->gl_damage);
832 dbus_display_listener_get_bus_name(DBusDisplayListener *ddl)
834 return ddl->bus_name ?: "p2p";
838 dbus_display_listener_get_console(DBusDisplayListener *ddl)
845 dbus_display_listener_implements(DBusDisplayListener *ddl, const char *iface)
847 QemuDBusDisplay1Listener *l = QEMU_DBUS_DISPLAY1_LISTENER(ddl->proxy);
850 implements = g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l), iface);
852 g_debug("Display listener does not implement: `%s`", iface);
859 dbus_display_listener_setup_peer_process(DBusDisplayListener *ddl)
861 g_autoptr(GError) err = NULL;
862 GDBusConnection *conn;
865 g_autoptr(GCredentials) creds = NULL;
868 if (ddl->peer_process) {
872 conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl->proxy));
873 stream = g_dbus_connection_get_stream(conn);
875 if (!G_IS_UNIX_CONNECTION(stream)) {
879 sock = g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream));
880 creds = g_socket_get_credentials(sock, &err);
883 g_debug("Failed to get peer credentials: %s", err->message);
887 pid = g_credentials_get_native(creds, G_CREDENTIALS_TYPE_WIN32_PID);
890 g_debug("Failed to get peer PID");
894 ddl->peer_process = OpenProcess(
895 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
898 if (!ddl->peer_process) {
899 g_autofree char *msg = g_win32_error_message(GetLastError());
900 g_debug("Failed to OpenProcess: %s", msg);
909 dbus_display_listener_setup_d3d11(DBusDisplayListener *ddl)
912 g_autoptr(GError) err = NULL;
914 if (!dbus_display_listener_implements(ddl,
915 "org.qemu.Display1.Listener.Win32.D3d11")) {
919 if (!dbus_display_listener_setup_peer_process(ddl)) {
924 qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl->conn,
925 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
927 "/org/qemu/Display1/Listener",
930 if (!ddl->d3d11_proxy) {
931 g_debug("Failed to setup win32 d3d11 proxy: %s", err->message);
938 dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
941 g_autoptr(GError) err = NULL;
943 if (!dbus_display_listener_implements(ddl, "org.qemu.Display1.Listener.Win32.Map")) {
947 if (!dbus_display_listener_setup_peer_process(ddl)) {
952 qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl->conn,
953 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
955 "/org/qemu/Display1/Listener",
958 if (!ddl->map_proxy) {
959 g_debug("Failed to setup win32 map proxy: %s", err->message);
963 ddl->can_share_map = true;
967 DBusDisplayListener *
968 dbus_display_listener_new(const char *bus_name,
969 GDBusConnection *conn,
970 DBusDisplayConsole *console)
972 DBusDisplayListener *ddl;
974 g_autoptr(GError) err = NULL;
976 ddl = g_object_new(DBUS_DISPLAY_TYPE_LISTENER, NULL);
978 qemu_dbus_display1_listener_proxy_new_sync(conn,
979 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
981 "/org/qemu/Display1/Listener",
985 error_report("Failed to setup proxy: %s", err->message);
986 g_object_unref(conn);
991 ddl->bus_name = g_strdup(bus_name);
993 ddl->console = console;
995 dbus_display_listener_setup_shared_map(ddl);
996 dbus_display_listener_setup_d3d11(ddl);
998 con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
1001 register_displaychangelistener(&ddl->dcl);