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
);