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"
44 static void dbus_gfx_switch(DisplayChangeListener
*dcl
,
45 struct DisplaySurface
*new_surface
);
53 struct _DBusDisplayListener
{
57 DBusDisplayConsole
*console
;
58 GDBusConnection
*conn
;
60 QemuDBusDisplay1Listener
*proxy
;
62 DisplayChangeListener dcl
;
64 enum share_kind ds_share
;
72 QemuDBusDisplay1ListenerWin32Map
*map_proxy
;
73 QemuDBusDisplay1ListenerWin32D3d11
*d3d11_proxy
;
75 ID3D11Texture2D
*d3d_texture
;
82 G_DEFINE_TYPE(DBusDisplayListener
, dbus_display_listener
, G_TYPE_OBJECT
)
84 static void dbus_gfx_update(DisplayChangeListener
*dcl
,
85 int x
, int y
, int w
, int h
);
88 static void dbus_scanout_disable(DisplayChangeListener
*dcl
)
90 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
92 qemu_dbus_display1_listener_call_disable(
93 ddl
->proxy
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
97 static bool d3d_texture2d_share(ID3D11Texture2D
*d3d_texture
,
98 HANDLE
*handle
, Error
**errp
)
100 IDXGIResource1
*dxgiResource
= NULL
;
103 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
105 (void **)&dxgiResource
);
110 hr
= dxgiResource
->lpVtbl
->CreateSharedHandle(
113 DXGI_SHARED_RESOURCE_READ
| DXGI_SHARED_RESOURCE_WRITE
,
118 dxgiResource
->lpVtbl
->Release(dxgiResource
);
125 error_setg_win32(errp
, GetLastError(), "failed to create shared handle");
129 static bool d3d_texture2d_acquire0(ID3D11Texture2D
*d3d_texture
, Error
**errp
)
131 IDXGIKeyedMutex
*dxgiMutex
= NULL
;
134 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
135 &IID_IDXGIKeyedMutex
,
136 (void **)&dxgiMutex
);
141 hr
= dxgiMutex
->lpVtbl
->AcquireSync(dxgiMutex
, 0, INFINITE
);
143 dxgiMutex
->lpVtbl
->Release(dxgiMutex
);
150 error_setg_win32(errp
, GetLastError(), "failed to acquire texture mutex");
154 static bool d3d_texture2d_release0(ID3D11Texture2D
*d3d_texture
, Error
**errp
)
156 IDXGIKeyedMutex
*dxgiMutex
= NULL
;
159 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
160 &IID_IDXGIKeyedMutex
,
161 (void **)&dxgiMutex
);
166 hr
= dxgiMutex
->lpVtbl
->ReleaseSync(dxgiMutex
, 0);
168 dxgiMutex
->lpVtbl
->Release(dxgiMutex
);
175 error_setg_win32(errp
, GetLastError(), "failed to release texture mutex");
180 #if defined(CONFIG_GBM) || defined(WIN32)
181 static void dbus_update_gl_cb(GObject
*source_object
,
185 g_autoptr(GError
) err
= NULL
;
186 DBusDisplayListener
*ddl
= user_data
;
190 success
= qemu_dbus_display1_listener_call_update_dmabuf_finish(
191 ddl
->proxy
, res
, &err
);
195 success
= qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
196 ddl
->d3d11_proxy
, res
, &err
);
197 d3d_texture2d_acquire0(ddl
->d3d_texture
, &error_warn
);
201 error_report("Failed to call update: %s", err
->message
);
204 graphic_hw_gl_block(ddl
->dcl
.con
, false);
209 static void dbus_call_update_gl(DisplayChangeListener
*dcl
,
210 int x
, int y
, int w
, int h
)
212 #if defined(CONFIG_GBM) || defined(WIN32)
213 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
216 trace_dbus_update_gl(x
, y
, w
, h
);
220 graphic_hw_gl_block(ddl
->dcl
.con
, true);
221 qemu_dbus_display1_listener_call_update_dmabuf(ddl
->proxy
,
223 G_DBUS_CALL_FLAGS_NONE
,
224 DBUS_DEFAULT_TIMEOUT
, NULL
,
230 switch (ddl
->ds_share
) {
231 case SHARE_KIND_MAPPED
:
232 egl_fb_read_rect(ddl
->ds
, &ddl
->fb
, x
, y
, w
, h
);
233 dbus_gfx_update(dcl
, x
, y
, w
, h
);
235 case SHARE_KIND_D3DTEX
:
237 assert(ddl
->d3d_texture
);
239 graphic_hw_gl_block(ddl
->dcl
.con
, true);
240 if (!d3d_texture2d_release0(ddl
->d3d_texture
, &err
)) {
241 error_report_err(err
);
244 qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
247 G_DBUS_CALL_FLAGS_NONE
,
248 DBUS_DEFAULT_TIMEOUT
, NULL
,
259 static void dbus_scanout_dmabuf(DisplayChangeListener
*dcl
,
262 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
263 g_autoptr(GError
) err
= NULL
;
264 g_autoptr(GUnixFDList
) fd_list
= NULL
;
266 fd_list
= g_unix_fd_list_new();
267 if (g_unix_fd_list_append(fd_list
, dmabuf
->fd
, &err
) != 0) {
268 error_report("Failed to setup dmabuf fdlist: %s", err
->message
);
272 /* FIXME: add missing x/y/w/h support */
273 qemu_dbus_display1_listener_call_scanout_dmabuf(
275 g_variant_new_handle(0),
282 G_DBUS_CALL_FLAGS_NONE
,
291 static bool dbus_scanout_map(DBusDisplayListener
*ddl
)
293 g_autoptr(GError
) err
= NULL
;
295 HANDLE target_handle
;
297 if (ddl
->ds_share
== SHARE_KIND_MAPPED
) {
301 if (!ddl
->can_share_map
|| !ddl
->ds
->handle
) {
305 success
= DuplicateHandle(
310 FILE_MAP_READ
| SECTION_QUERY
,
313 g_autofree
char *msg
= g_win32_error_message(GetLastError());
314 g_debug("Failed to DuplicateHandle: %s", msg
);
315 ddl
->can_share_map
= false;
319 if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
321 GPOINTER_TO_UINT(target_handle
),
322 ddl
->ds
->handle_offset
,
323 surface_width(ddl
->ds
),
324 surface_height(ddl
->ds
),
325 surface_stride(ddl
->ds
),
326 surface_format(ddl
->ds
),
327 G_DBUS_CALL_FLAGS_NONE
,
328 DBUS_DEFAULT_TIMEOUT
,
331 g_debug("Failed to call ScanoutMap: %s", err
->message
);
332 ddl
->can_share_map
= false;
336 ddl
->ds_share
= SHARE_KIND_MAPPED
;
342 dbus_scanout_share_d3d_texture(
343 DBusDisplayListener
*ddl
,
344 ID3D11Texture2D
*tex
,
345 bool backing_y_0_top
,
346 uint32_t backing_width
,
347 uint32_t backing_height
,
348 uint32_t x
, uint32_t y
,
349 uint32_t w
, uint32_t h
)
353 HANDLE share_handle
, target_handle
;
355 if (!d3d_texture2d_release0(tex
, &err
)) {
356 error_report_err(err
);
360 if (!d3d_texture2d_share(tex
, &share_handle
, &err
)) {
361 error_report_err(err
);
365 success
= DuplicateHandle(
371 FALSE
, DUPLICATE_SAME_ACCESS
);
373 g_autofree
char *msg
= g_win32_error_message(GetLastError());
374 g_debug("Failed to DuplicateHandle: %s", msg
);
375 CloseHandle(share_handle
);
379 qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
381 GPOINTER_TO_INT(target_handle
),
386 G_DBUS_CALL_FLAGS_NONE
,
390 CloseHandle(share_handle
);
392 if (!d3d_texture2d_acquire0(tex
, &err
)) {
393 error_report_err(err
);
397 ddl
->d3d_texture
= tex
;
398 ddl
->ds_share
= SHARE_KIND_D3DTEX
;
405 static void dbus_scanout_texture(DisplayChangeListener
*dcl
,
407 bool backing_y_0_top
,
408 uint32_t backing_width
,
409 uint32_t backing_height
,
410 uint32_t x
, uint32_t y
,
411 uint32_t w
, uint32_t h
,
414 trace_dbus_scanout_texture(tex_id
, backing_y_0_top
,
415 backing_width
, backing_height
, x
, y
, w
, h
);
417 QemuDmaBuf dmabuf
= {
418 .width
= backing_width
,
419 .height
= backing_height
,
420 .y0_top
= backing_y_0_top
,
428 dmabuf
.fd
= egl_get_fd_for_texture(
429 tex_id
, (EGLint
*)&dmabuf
.stride
,
430 (EGLint
*)&dmabuf
.fourcc
,
433 error_report("%s: failed to get fd for texture", __func__
);
437 dbus_scanout_dmabuf(dcl
, &dmabuf
);
442 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
444 /* there must be a matching gfx_switch before */
445 assert(surface_width(ddl
->ds
) == w
);
446 assert(surface_height(ddl
->ds
) == h
);
449 dbus_scanout_share_d3d_texture(ddl
, d3d_tex2d
, backing_y_0_top
,
450 backing_width
, backing_height
, x
, y
, w
, h
);
452 dbus_scanout_map(ddl
);
453 egl_fb_setup_for_tex(&ddl
->fb
, backing_width
, backing_height
, tex_id
, false);
459 static void dbus_cursor_dmabuf(DisplayChangeListener
*dcl
,
460 QemuDmaBuf
*dmabuf
, bool have_hot
,
461 uint32_t hot_x
, uint32_t hot_y
)
463 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
465 GVariant
*v_data
= NULL
;
466 egl_fb cursor_fb
= EGL_FB_INIT
;
469 qemu_dbus_display1_listener_call_mouse_set(
470 ddl
->proxy
, 0, 0, false,
471 G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
475 egl_dmabuf_import_texture(dmabuf
);
476 if (!dmabuf
->texture
) {
479 egl_fb_setup_for_tex(&cursor_fb
, dmabuf
->width
, dmabuf
->height
,
480 dmabuf
->texture
, false);
481 ds
= qemu_create_displaysurface(dmabuf
->width
, dmabuf
->height
);
482 egl_fb_read(ds
, &cursor_fb
);
484 v_data
= g_variant_new_from_data(
485 G_VARIANT_TYPE("ay"),
487 surface_width(ds
) * surface_height(ds
) * 4,
489 (GDestroyNotify
)qemu_free_displaysurface
,
491 qemu_dbus_display1_listener_call_cursor_define(
498 G_DBUS_CALL_FLAGS_NONE
,
505 static void dbus_release_dmabuf(DisplayChangeListener
*dcl
,
508 dbus_scanout_disable(dcl
);
512 static void dbus_gl_cursor_position(DisplayChangeListener
*dcl
,
513 uint32_t pos_x
, uint32_t pos_y
)
515 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
517 qemu_dbus_display1_listener_call_mouse_set(
518 ddl
->proxy
, pos_x
, pos_y
, true,
519 G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
522 static void dbus_scanout_update(DisplayChangeListener
*dcl
,
523 uint32_t x
, uint32_t y
,
524 uint32_t w
, uint32_t h
)
526 dbus_call_update_gl(dcl
, x
, y
, w
, h
);
529 static void dbus_gl_refresh(DisplayChangeListener
*dcl
)
531 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
533 graphic_hw_update(dcl
->con
);
535 if (!ddl
->ds
|| qemu_console_is_gl_blocked(ddl
->dcl
.con
)) {
539 if (ddl
->gl_updates
) {
540 dbus_call_update_gl(dcl
, 0, 0,
541 surface_width(ddl
->ds
), surface_height(ddl
->ds
));
547 static void dbus_refresh(DisplayChangeListener
*dcl
)
549 graphic_hw_update(dcl
->con
);
553 static void dbus_gl_gfx_update(DisplayChangeListener
*dcl
,
554 int x
, int y
, int w
, int h
)
556 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
562 static void dbus_gfx_update(DisplayChangeListener
*dcl
,
563 int x
, int y
, int w
, int h
)
565 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
572 trace_dbus_update(x
, y
, w
, h
);
575 if (dbus_scanout_map(ddl
)) {
576 qemu_dbus_display1_listener_win32_map_call_update_map(
579 G_DBUS_CALL_FLAGS_NONE
,
580 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
585 if (x
== 0 && y
== 0 && w
== surface_width(ddl
->ds
) && h
== surface_height(ddl
->ds
)) {
586 v_data
= g_variant_new_from_data(
587 G_VARIANT_TYPE("ay"),
588 surface_data(ddl
->ds
),
589 surface_stride(ddl
->ds
) * surface_height(ddl
->ds
),
591 (GDestroyNotify
)pixman_image_unref
,
592 pixman_image_ref(ddl
->ds
->image
));
593 qemu_dbus_display1_listener_call_scanout(
595 surface_width(ddl
->ds
),
596 surface_height(ddl
->ds
),
597 surface_stride(ddl
->ds
),
598 surface_format(ddl
->ds
),
600 G_DBUS_CALL_FLAGS_NONE
,
601 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
605 /* make a copy, since gvariant only handles linear data */
606 stride
= w
* DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl
->ds
)), 8);
607 img
= pixman_image_create_bits(surface_format(ddl
->ds
),
609 pixman_image_composite(PIXMAN_OP_SRC
, ddl
->ds
->image
, NULL
, img
,
610 x
, y
, 0, 0, 0, 0, w
, h
);
612 v_data
= g_variant_new_from_data(
613 G_VARIANT_TYPE("ay"),
614 pixman_image_get_data(img
),
615 pixman_image_get_stride(img
) * h
,
617 (GDestroyNotify
)pixman_image_unref
,
619 qemu_dbus_display1_listener_call_update(ddl
->proxy
,
620 x
, y
, w
, h
, pixman_image_get_stride(img
), pixman_image_get_format(img
),
622 G_DBUS_CALL_FLAGS_NONE
,
623 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
627 static void dbus_gl_gfx_switch(DisplayChangeListener
*dcl
,
628 struct DisplaySurface
*new_surface
)
630 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
632 trace_dbus_gl_gfx_switch(new_surface
);
634 ddl
->ds
= new_surface
;
635 ddl
->ds_share
= SHARE_KIND_NONE
;
637 int width
= surface_width(ddl
->ds
);
638 int height
= surface_height(ddl
->ds
);
640 /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
641 dbus_scanout_texture(&ddl
->dcl
, ddl
->ds
->texture
, false,
642 width
, height
, 0, 0, width
, height
, NULL
);
647 static void dbus_gfx_switch(DisplayChangeListener
*dcl
,
648 struct DisplaySurface
*new_surface
)
650 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
652 ddl
->ds
= new_surface
;
653 ddl
->ds_share
= SHARE_KIND_NONE
;
656 static void dbus_mouse_set(DisplayChangeListener
*dcl
,
657 int x
, int y
, int on
)
659 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
661 qemu_dbus_display1_listener_call_mouse_set(
662 ddl
->proxy
, x
, y
, on
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
665 static void dbus_cursor_define(DisplayChangeListener
*dcl
,
668 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
669 GVariant
*v_data
= NULL
;
671 v_data
= g_variant_new_from_data(
672 G_VARIANT_TYPE("ay"),
674 c
->width
* c
->height
* 4,
676 (GDestroyNotify
)cursor_unref
,
679 qemu_dbus_display1_listener_call_cursor_define(
686 G_DBUS_CALL_FLAGS_NONE
,
694 const DisplayChangeListenerOps dbus_gl_dcl_ops
= {
695 .dpy_name
= "dbus-gl",
696 .dpy_gfx_update
= dbus_gl_gfx_update
,
697 .dpy_gfx_switch
= dbus_gl_gfx_switch
,
698 .dpy_gfx_check_format
= console_gl_check_format
,
699 .dpy_refresh
= dbus_gl_refresh
,
700 .dpy_mouse_set
= dbus_mouse_set
,
701 .dpy_cursor_define
= dbus_cursor_define
,
703 .dpy_gl_scanout_disable
= dbus_scanout_disable
,
704 .dpy_gl_scanout_texture
= dbus_scanout_texture
,
706 .dpy_gl_scanout_dmabuf
= dbus_scanout_dmabuf
,
707 .dpy_gl_cursor_dmabuf
= dbus_cursor_dmabuf
,
708 .dpy_gl_release_dmabuf
= dbus_release_dmabuf
,
710 .dpy_gl_cursor_position
= dbus_gl_cursor_position
,
711 .dpy_gl_update
= dbus_scanout_update
,
715 const DisplayChangeListenerOps dbus_dcl_ops
= {
717 .dpy_gfx_update
= dbus_gfx_update
,
718 .dpy_gfx_switch
= dbus_gfx_switch
,
719 .dpy_refresh
= dbus_refresh
,
720 .dpy_mouse_set
= dbus_mouse_set
,
721 .dpy_cursor_define
= dbus_cursor_define
,
725 dbus_display_listener_dispose(GObject
*object
)
727 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(object
);
729 unregister_displaychangelistener(&ddl
->dcl
);
730 g_clear_object(&ddl
->conn
);
731 g_clear_pointer(&ddl
->bus_name
, g_free
);
732 g_clear_object(&ddl
->proxy
);
734 g_clear_object(&ddl
->map_proxy
);
735 g_clear_object(&ddl
->d3d11_proxy
);
736 g_clear_pointer(&ddl
->peer_process
, CloseHandle
);
738 egl_fb_destroy(&ddl
->fb
);
742 G_OBJECT_CLASS(dbus_display_listener_parent_class
)->dispose(object
);
746 dbus_display_listener_constructed(GObject
*object
)
748 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(object
);
750 ddl
->dcl
.ops
= &dbus_dcl_ops
;
752 if (display_opengl
) {
753 ddl
->dcl
.ops
= &dbus_gl_dcl_ops
;
757 G_OBJECT_CLASS(dbus_display_listener_parent_class
)->constructed(object
);
761 dbus_display_listener_class_init(DBusDisplayListenerClass
*klass
)
763 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
765 object_class
->dispose
= dbus_display_listener_dispose
;
766 object_class
->constructed
= dbus_display_listener_constructed
;
770 dbus_display_listener_init(DBusDisplayListener
*ddl
)
775 dbus_display_listener_get_bus_name(DBusDisplayListener
*ddl
)
777 return ddl
->bus_name
?: "p2p";
781 dbus_display_listener_get_console(DBusDisplayListener
*ddl
)
788 dbus_display_listener_implements(DBusDisplayListener
*ddl
, const char *iface
)
790 QemuDBusDisplay1Listener
*l
= QEMU_DBUS_DISPLAY1_LISTENER(ddl
->proxy
);
793 implements
= g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l
), iface
);
795 g_debug("Display listener does not implement: `%s`", iface
);
802 dbus_display_listener_setup_peer_process(DBusDisplayListener
*ddl
)
804 g_autoptr(GError
) err
= NULL
;
805 GDBusConnection
*conn
;
808 g_autoptr(GCredentials
) creds
= NULL
;
811 if (ddl
->peer_process
) {
815 conn
= g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl
->proxy
));
816 stream
= g_dbus_connection_get_stream(conn
);
818 if (!G_IS_UNIX_CONNECTION(stream
)) {
822 sock
= g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream
));
823 creds
= g_socket_get_credentials(sock
, &err
);
826 g_debug("Failed to get peer credentials: %s", err
->message
);
830 pid
= g_credentials_get_native(creds
, G_CREDENTIALS_TYPE_WIN32_PID
);
833 g_debug("Failed to get peer PID");
837 ddl
->peer_process
= OpenProcess(
838 PROCESS_DUP_HANDLE
| PROCESS_QUERY_INFORMATION
,
841 if (!ddl
->peer_process
) {
842 g_autofree
char *msg
= g_win32_error_message(GetLastError());
843 g_debug("Failed to OpenProcess: %s", msg
);
852 dbus_display_listener_setup_d3d11(DBusDisplayListener
*ddl
)
855 g_autoptr(GError
) err
= NULL
;
857 if (!dbus_display_listener_implements(ddl
,
858 "org.qemu.Display1.Listener.Win32.D3d11")) {
862 if (!dbus_display_listener_setup_peer_process(ddl
)) {
867 qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl
->conn
,
868 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
870 "/org/qemu/Display1/Listener",
873 if (!ddl
->d3d11_proxy
) {
874 g_debug("Failed to setup win32 d3d11 proxy: %s", err
->message
);
881 dbus_display_listener_setup_shared_map(DBusDisplayListener
*ddl
)
884 g_autoptr(GError
) err
= NULL
;
886 if (!dbus_display_listener_implements(ddl
, "org.qemu.Display1.Listener.Win32.Map")) {
890 if (!dbus_display_listener_setup_peer_process(ddl
)) {
895 qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl
->conn
,
896 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
898 "/org/qemu/Display1/Listener",
901 if (!ddl
->map_proxy
) {
902 g_debug("Failed to setup win32 map proxy: %s", err
->message
);
906 ddl
->can_share_map
= true;
910 DBusDisplayListener
*
911 dbus_display_listener_new(const char *bus_name
,
912 GDBusConnection
*conn
,
913 DBusDisplayConsole
*console
)
915 DBusDisplayListener
*ddl
;
917 g_autoptr(GError
) err
= NULL
;
919 ddl
= g_object_new(DBUS_DISPLAY_TYPE_LISTENER
, NULL
);
921 qemu_dbus_display1_listener_proxy_new_sync(conn
,
922 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
924 "/org/qemu/Display1/Listener",
928 error_report("Failed to setup proxy: %s", err
->message
);
929 g_object_unref(conn
);
934 ddl
->bus_name
= g_strdup(bus_name
);
936 ddl
->console
= console
;
938 dbus_display_listener_setup_shared_map(ddl
);
939 dbus_display_listener_setup_d3d11(ddl
);
941 con
= qemu_console_lookup_by_index(dbus_display_console_get_index(console
));
944 register_displaychangelistener(&ddl
->dcl
);