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 guint32 out_serial_to_discard
;
91 G_DEFINE_TYPE(DBusDisplayListener
, dbus_display_listener
, G_TYPE_OBJECT
)
93 static void dbus_gfx_update(DisplayChangeListener
*dcl
,
94 int x
, int y
, int w
, int h
);
96 static void ddl_discard_pending_messages(DBusDisplayListener
*ddl
)
98 ddl
->out_serial_to_discard
= g_dbus_connection_get_last_serial(
99 g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl
->proxy
)));
103 static void dbus_scanout_disable(DisplayChangeListener
*dcl
)
105 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
107 qemu_dbus_display1_listener_call_disable(
108 ddl
->proxy
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
112 static bool d3d_texture2d_share(ID3D11Texture2D
*d3d_texture
,
113 HANDLE
*handle
, Error
**errp
)
115 IDXGIResource1
*dxgiResource
= NULL
;
118 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
120 (void **)&dxgiResource
);
125 hr
= dxgiResource
->lpVtbl
->CreateSharedHandle(
128 DXGI_SHARED_RESOURCE_READ
| DXGI_SHARED_RESOURCE_WRITE
,
133 dxgiResource
->lpVtbl
->Release(dxgiResource
);
140 error_setg_win32(errp
, GetLastError(), "failed to create shared handle");
144 static bool d3d_texture2d_acquire0(ID3D11Texture2D
*d3d_texture
, Error
**errp
)
146 IDXGIKeyedMutex
*dxgiMutex
= NULL
;
149 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
150 &IID_IDXGIKeyedMutex
,
151 (void **)&dxgiMutex
);
156 hr
= dxgiMutex
->lpVtbl
->AcquireSync(dxgiMutex
, 0, INFINITE
);
158 dxgiMutex
->lpVtbl
->Release(dxgiMutex
);
165 error_setg_win32(errp
, GetLastError(), "failed to acquire texture mutex");
169 static bool d3d_texture2d_release0(ID3D11Texture2D
*d3d_texture
, Error
**errp
)
171 IDXGIKeyedMutex
*dxgiMutex
= NULL
;
174 hr
= d3d_texture
->lpVtbl
->QueryInterface(d3d_texture
,
175 &IID_IDXGIKeyedMutex
,
176 (void **)&dxgiMutex
);
181 hr
= dxgiMutex
->lpVtbl
->ReleaseSync(dxgiMutex
, 0);
183 dxgiMutex
->lpVtbl
->Release(dxgiMutex
);
190 error_setg_win32(errp
, GetLastError(), "failed to release texture mutex");
195 #if defined(CONFIG_GBM) || defined(WIN32)
196 static void dbus_update_gl_cb(GObject
*source_object
,
200 g_autoptr(GError
) err
= NULL
;
201 DBusDisplayListener
*ddl
= user_data
;
205 success
= qemu_dbus_display1_listener_call_update_dmabuf_finish(
206 ddl
->proxy
, res
, &err
);
210 success
= qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d_finish(
211 ddl
->d3d11_proxy
, res
, &err
);
212 d3d_texture2d_acquire0(ddl
->d3d_texture
, &error_warn
);
216 error_report("Failed to call update: %s", err
->message
);
219 graphic_hw_gl_block(ddl
->dcl
.con
, false);
224 static void dbus_call_update_gl(DisplayChangeListener
*dcl
,
225 int x
, int y
, int w
, int h
)
227 #if defined(CONFIG_GBM) || defined(WIN32)
228 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
231 trace_dbus_update_gl(x
, y
, w
, h
);
235 graphic_hw_gl_block(ddl
->dcl
.con
, true);
236 qemu_dbus_display1_listener_call_update_dmabuf(ddl
->proxy
,
238 G_DBUS_CALL_FLAGS_NONE
,
239 DBUS_DEFAULT_TIMEOUT
, NULL
,
245 switch (ddl
->ds_share
) {
246 case SHARE_KIND_MAPPED
:
247 egl_fb_read_rect(ddl
->ds
, &ddl
->fb
, x
, y
, w
, h
);
248 dbus_gfx_update(dcl
, x
, y
, w
, h
);
250 case SHARE_KIND_D3DTEX
: {
252 assert(ddl
->d3d_texture
);
254 graphic_hw_gl_block(ddl
->dcl
.con
, true);
255 if (!d3d_texture2d_release0(ddl
->d3d_texture
, &err
)) {
256 error_report_err(err
);
259 qemu_dbus_display1_listener_win32_d3d11_call_update_texture2d(
262 G_DBUS_CALL_FLAGS_NONE
,
263 DBUS_DEFAULT_TIMEOUT
, NULL
,
275 static void dbus_scanout_dmabuf(DisplayChangeListener
*dcl
,
278 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
279 g_autoptr(GError
) err
= NULL
;
280 g_autoptr(GUnixFDList
) fd_list
= NULL
;
282 fd_list
= g_unix_fd_list_new();
283 if (g_unix_fd_list_append(fd_list
, dmabuf
->fd
, &err
) != 0) {
284 error_report("Failed to setup dmabuf fdlist: %s", err
->message
);
288 ddl_discard_pending_messages(ddl
);
290 /* FIXME: add missing x/y/w/h support */
291 qemu_dbus_display1_listener_call_scanout_dmabuf(
293 g_variant_new_handle(0),
300 G_DBUS_CALL_FLAGS_NONE
,
309 static bool dbus_scanout_map(DBusDisplayListener
*ddl
)
311 g_autoptr(GError
) err
= NULL
;
313 HANDLE target_handle
;
315 if (ddl
->ds_share
== SHARE_KIND_MAPPED
) {
319 if (!ddl
->can_share_map
|| !ddl
->ds
->handle
) {
323 success
= DuplicateHandle(
328 FILE_MAP_READ
| SECTION_QUERY
,
331 g_autofree
char *msg
= g_win32_error_message(GetLastError());
332 g_debug("Failed to DuplicateHandle: %s", msg
);
333 ddl
->can_share_map
= false;
337 ddl_discard_pending_messages(ddl
);
339 if (!qemu_dbus_display1_listener_win32_map_call_scanout_map_sync(
341 GPOINTER_TO_UINT(target_handle
),
342 ddl
->ds
->handle_offset
,
343 surface_width(ddl
->ds
),
344 surface_height(ddl
->ds
),
345 surface_stride(ddl
->ds
),
346 surface_format(ddl
->ds
),
347 G_DBUS_CALL_FLAGS_NONE
,
348 DBUS_DEFAULT_TIMEOUT
,
351 g_debug("Failed to call ScanoutMap: %s", err
->message
);
352 ddl
->can_share_map
= false;
356 ddl
->ds_share
= SHARE_KIND_MAPPED
;
363 dbus_scanout_share_d3d_texture(
364 DBusDisplayListener
*ddl
,
365 ID3D11Texture2D
*tex
,
366 bool backing_y_0_top
,
367 uint32_t backing_width
,
368 uint32_t backing_height
,
369 uint32_t x
, uint32_t y
,
370 uint32_t w
, uint32_t h
)
374 HANDLE share_handle
, target_handle
;
376 if (!d3d_texture2d_release0(tex
, &err
)) {
377 error_report_err(err
);
381 if (!d3d_texture2d_share(tex
, &share_handle
, &err
)) {
382 error_report_err(err
);
386 success
= DuplicateHandle(
392 FALSE
, DUPLICATE_SAME_ACCESS
);
394 g_autofree
char *msg
= g_win32_error_message(GetLastError());
395 g_debug("Failed to DuplicateHandle: %s", msg
);
396 CloseHandle(share_handle
);
400 ddl_discard_pending_messages(ddl
);
402 qemu_dbus_display1_listener_win32_d3d11_call_scanout_texture2d(
404 GPOINTER_TO_INT(target_handle
),
409 G_DBUS_CALL_FLAGS_NONE
,
413 CloseHandle(share_handle
);
415 if (!d3d_texture2d_acquire0(tex
, &err
)) {
416 error_report_err(err
);
420 ddl
->d3d_texture
= tex
;
421 ddl
->ds_share
= SHARE_KIND_D3DTEX
;
425 #endif /* CONFIG_OPENGL */
429 static void dbus_scanout_texture(DisplayChangeListener
*dcl
,
431 bool backing_y_0_top
,
432 uint32_t backing_width
,
433 uint32_t backing_height
,
434 uint32_t x
, uint32_t y
,
435 uint32_t w
, uint32_t h
,
438 trace_dbus_scanout_texture(tex_id
, backing_y_0_top
,
439 backing_width
, backing_height
, x
, y
, w
, h
);
441 QemuDmaBuf dmabuf
= {
444 .y0_top
= backing_y_0_top
,
447 .backing_width
= backing_width
,
448 .backing_height
= backing_height
,
452 dmabuf
.fd
= egl_get_fd_for_texture(
453 tex_id
, (EGLint
*)&dmabuf
.stride
,
454 (EGLint
*)&dmabuf
.fourcc
,
457 error_report("%s: failed to get fd for texture", __func__
);
461 dbus_scanout_dmabuf(dcl
, &dmabuf
);
466 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
468 /* there must be a matching gfx_switch before */
469 assert(surface_width(ddl
->ds
) == w
);
470 assert(surface_height(ddl
->ds
) == h
);
473 dbus_scanout_share_d3d_texture(ddl
, d3d_tex2d
, backing_y_0_top
,
474 backing_width
, backing_height
, x
, y
, w
, h
);
476 dbus_scanout_map(ddl
);
477 egl_fb_setup_for_tex(&ddl
->fb
, backing_width
, backing_height
, tex_id
, false);
483 static void dbus_cursor_dmabuf(DisplayChangeListener
*dcl
,
484 QemuDmaBuf
*dmabuf
, bool have_hot
,
485 uint32_t hot_x
, uint32_t hot_y
)
487 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
489 GVariant
*v_data
= NULL
;
490 egl_fb cursor_fb
= EGL_FB_INIT
;
493 qemu_dbus_display1_listener_call_mouse_set(
494 ddl
->proxy
, 0, 0, false,
495 G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
499 egl_dmabuf_import_texture(dmabuf
);
500 if (!dmabuf
->texture
) {
503 egl_fb_setup_for_tex(&cursor_fb
, dmabuf
->width
, dmabuf
->height
,
504 dmabuf
->texture
, false);
505 ds
= qemu_create_displaysurface(dmabuf
->width
, dmabuf
->height
);
506 egl_fb_read(ds
, &cursor_fb
);
508 v_data
= g_variant_new_from_data(
509 G_VARIANT_TYPE("ay"),
511 surface_width(ds
) * surface_height(ds
) * 4,
513 (GDestroyNotify
)qemu_free_displaysurface
,
515 qemu_dbus_display1_listener_call_cursor_define(
522 G_DBUS_CALL_FLAGS_NONE
,
529 static void dbus_release_dmabuf(DisplayChangeListener
*dcl
,
532 dbus_scanout_disable(dcl
);
536 static void dbus_gl_cursor_position(DisplayChangeListener
*dcl
,
537 uint32_t pos_x
, uint32_t pos_y
)
539 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
541 qemu_dbus_display1_listener_call_mouse_set(
542 ddl
->proxy
, pos_x
, pos_y
, true,
543 G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
546 static void dbus_scanout_update(DisplayChangeListener
*dcl
,
547 uint32_t x
, uint32_t y
,
548 uint32_t w
, uint32_t h
)
550 dbus_call_update_gl(dcl
, x
, y
, w
, h
);
553 static void dbus_gl_refresh(DisplayChangeListener
*dcl
)
555 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
557 graphic_hw_update(dcl
->con
);
559 if (!ddl
->ds
|| qemu_console_is_gl_blocked(ddl
->dcl
.con
)) {
564 int n_rects
= pixman_region32_n_rects(&ddl
->gl_damage
);
566 for (int i
= 0; i
< n_rects
; i
++) {
568 box
= pixman_region32_rectangles(&ddl
->gl_damage
, NULL
) + i
;
569 /* TODO: Add a UpdateList call to send multiple updates at once */
570 dbus_call_update_gl(dcl
, box
->x1
, box
->y1
,
571 box
->x2
- box
->x1
, box
->y2
- box
->y1
);
573 pixman_region32_clear(&ddl
->gl_damage
);
575 if (ddl
->gl_damage
) {
576 dbus_call_update_gl(dcl
, 0, 0,
577 surface_width(ddl
->ds
), surface_height(ddl
->ds
));
584 static void dbus_refresh(DisplayChangeListener
*dcl
)
586 graphic_hw_update(dcl
->con
);
590 static void dbus_gl_gfx_update(DisplayChangeListener
*dcl
,
591 int x
, int y
, int w
, int h
)
593 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
596 pixman_region32_t rect_region
;
597 pixman_region32_init_rect(&rect_region
, x
, y
, w
, h
);
598 pixman_region32_union(&ddl
->gl_damage
, &ddl
->gl_damage
, &rect_region
);
599 pixman_region32_fini(&rect_region
);
606 static void dbus_gfx_update_sub(DBusDisplayListener
*ddl
,
607 int x
, int y
, int w
, int h
)
613 /* make a copy, since gvariant only handles linear data */
614 stride
= w
* DIV_ROUND_UP(PIXMAN_FORMAT_BPP(surface_format(ddl
->ds
)), 8);
615 img
= pixman_image_create_bits(surface_format(ddl
->ds
),
618 pixman_image_composite(PIXMAN_OP_SRC
, ddl
->ds
->image
, NULL
, img
,
619 x
, y
, 0, 0, 0, 0, w
, h
);
622 uint8_t *src
= (uint8_t *)pixman_image_get_data(ddl
->ds
->image
);
623 uint8_t *dst
= (uint8_t *)pixman_image_get_data(img
);
624 int bp
= PIXMAN_FORMAT_BPP(surface_format(ddl
->ds
)) / 8;
627 for (hh
= 0; hh
< h
; hh
++) {
628 memcpy(&dst
[stride
* hh
],
629 &src
[surface_stride(ddl
->ds
) * (hh
+ y
) + x
* bp
],
634 v_data
= g_variant_new_from_data(
635 G_VARIANT_TYPE("ay"),
636 pixman_image_get_data(img
),
637 pixman_image_get_stride(img
) * h
,
639 (GDestroyNotify
)pixman_image_unref
,
641 qemu_dbus_display1_listener_call_update(ddl
->proxy
,
642 x
, y
, w
, h
, pixman_image_get_stride(img
), pixman_image_get_format(img
),
644 G_DBUS_CALL_FLAGS_NONE
,
645 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
648 static void ddl_scanout(DBusDisplayListener
*ddl
)
652 v_data
= g_variant_new_from_data(
653 G_VARIANT_TYPE("ay"), surface_data(ddl
->ds
),
654 surface_stride(ddl
->ds
) * surface_height(ddl
->ds
), TRUE
,
655 (GDestroyNotify
)pixman_image_unref
, pixman_image_ref(ddl
->ds
->image
));
657 ddl_discard_pending_messages(ddl
);
659 qemu_dbus_display1_listener_call_scanout(
660 ddl
->proxy
, surface_width(ddl
->ds
), surface_height(ddl
->ds
),
661 surface_stride(ddl
->ds
), surface_format(ddl
->ds
), v_data
,
662 G_DBUS_CALL_FLAGS_NONE
, DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
,
666 static void dbus_gfx_update(DisplayChangeListener
*dcl
,
667 int x
, int y
, int w
, int h
)
669 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
673 trace_dbus_update(x
, y
, w
, h
);
676 if (dbus_scanout_map(ddl
)) {
677 qemu_dbus_display1_listener_win32_map_call_update_map(
680 G_DBUS_CALL_FLAGS_NONE
,
681 DBUS_DEFAULT_TIMEOUT
, NULL
, NULL
, NULL
);
686 if (x
== 0 && y
== 0 && w
== surface_width(ddl
->ds
) && h
== surface_height(ddl
->ds
)) {
687 return ddl_scanout(ddl
);
690 dbus_gfx_update_sub(ddl
, x
, y
, w
, h
);
694 static void dbus_gl_gfx_switch(DisplayChangeListener
*dcl
,
695 struct DisplaySurface
*new_surface
)
697 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
699 trace_dbus_gl_gfx_switch(new_surface
);
701 ddl
->ds
= new_surface
;
702 ddl
->ds_share
= SHARE_KIND_NONE
;
704 int width
= surface_width(ddl
->ds
);
705 int height
= surface_height(ddl
->ds
);
707 /* TODO: lazy send dmabuf (there are unnecessary sent otherwise) */
708 dbus_scanout_texture(&ddl
->dcl
, ddl
->ds
->texture
, false,
709 width
, height
, 0, 0, width
, height
, NULL
);
714 static void dbus_gfx_switch(DisplayChangeListener
*dcl
,
715 struct DisplaySurface
*new_surface
)
717 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
719 ddl
->ds
= new_surface
;
720 ddl
->ds_share
= SHARE_KIND_NONE
;
723 static void dbus_mouse_set(DisplayChangeListener
*dcl
,
724 int x
, int y
, int on
)
726 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
728 qemu_dbus_display1_listener_call_mouse_set(
729 ddl
->proxy
, x
, y
, on
, G_DBUS_CALL_FLAGS_NONE
, -1, NULL
, NULL
, NULL
);
732 static void dbus_cursor_define(DisplayChangeListener
*dcl
,
735 DBusDisplayListener
*ddl
= container_of(dcl
, DBusDisplayListener
, dcl
);
736 GVariant
*v_data
= NULL
;
738 v_data
= g_variant_new_from_data(
739 G_VARIANT_TYPE("ay"),
741 c
->width
* c
->height
* 4,
743 (GDestroyNotify
)cursor_unref
,
746 qemu_dbus_display1_listener_call_cursor_define(
753 G_DBUS_CALL_FLAGS_NONE
,
761 const DisplayChangeListenerOps dbus_gl_dcl_ops
= {
762 .dpy_name
= "dbus-gl",
763 .dpy_gfx_update
= dbus_gl_gfx_update
,
764 .dpy_gfx_switch
= dbus_gl_gfx_switch
,
765 .dpy_gfx_check_format
= console_gl_check_format
,
766 .dpy_refresh
= dbus_gl_refresh
,
767 .dpy_mouse_set
= dbus_mouse_set
,
768 .dpy_cursor_define
= dbus_cursor_define
,
770 .dpy_gl_scanout_disable
= dbus_scanout_disable
,
771 .dpy_gl_scanout_texture
= dbus_scanout_texture
,
773 .dpy_gl_scanout_dmabuf
= dbus_scanout_dmabuf
,
774 .dpy_gl_cursor_dmabuf
= dbus_cursor_dmabuf
,
775 .dpy_gl_release_dmabuf
= dbus_release_dmabuf
,
777 .dpy_gl_cursor_position
= dbus_gl_cursor_position
,
778 .dpy_gl_update
= dbus_scanout_update
,
782 const DisplayChangeListenerOps dbus_dcl_ops
= {
784 .dpy_gfx_update
= dbus_gfx_update
,
785 .dpy_gfx_switch
= dbus_gfx_switch
,
786 .dpy_refresh
= dbus_refresh
,
787 .dpy_mouse_set
= dbus_mouse_set
,
788 .dpy_cursor_define
= dbus_cursor_define
,
792 dbus_display_listener_dispose(GObject
*object
)
794 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(object
);
796 unregister_displaychangelistener(&ddl
->dcl
);
797 g_clear_object(&ddl
->conn
);
798 g_clear_pointer(&ddl
->bus_name
, g_free
);
799 g_clear_object(&ddl
->proxy
);
801 g_clear_object(&ddl
->map_proxy
);
802 g_clear_object(&ddl
->d3d11_proxy
);
803 g_clear_pointer(&ddl
->peer_process
, CloseHandle
);
805 pixman_region32_fini(&ddl
->gl_damage
);
808 egl_fb_destroy(&ddl
->fb
);
812 G_OBJECT_CLASS(dbus_display_listener_parent_class
)->dispose(object
);
816 dbus_display_listener_constructed(GObject
*object
)
818 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(object
);
820 ddl
->dcl
.ops
= &dbus_dcl_ops
;
822 if (display_opengl
) {
823 ddl
->dcl
.ops
= &dbus_gl_dcl_ops
;
827 G_OBJECT_CLASS(dbus_display_listener_parent_class
)->constructed(object
);
831 dbus_display_listener_class_init(DBusDisplayListenerClass
*klass
)
833 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
835 object_class
->dispose
= dbus_display_listener_dispose
;
836 object_class
->constructed
= dbus_display_listener_constructed
;
840 dbus_display_listener_init(DBusDisplayListener
*ddl
)
843 pixman_region32_init(&ddl
->gl_damage
);
848 dbus_display_listener_get_bus_name(DBusDisplayListener
*ddl
)
850 return ddl
->bus_name
?: "p2p";
854 dbus_display_listener_get_console(DBusDisplayListener
*ddl
)
861 dbus_display_listener_implements(DBusDisplayListener
*ddl
, const char *iface
)
863 QemuDBusDisplay1Listener
*l
= QEMU_DBUS_DISPLAY1_LISTENER(ddl
->proxy
);
866 implements
= g_strv_contains(qemu_dbus_display1_listener_get_interfaces(l
), iface
);
868 g_debug("Display listener does not implement: `%s`", iface
);
875 dbus_display_listener_setup_peer_process(DBusDisplayListener
*ddl
)
877 g_autoptr(GError
) err
= NULL
;
878 GDBusConnection
*conn
;
881 g_autoptr(GCredentials
) creds
= NULL
;
884 if (ddl
->peer_process
) {
888 conn
= g_dbus_proxy_get_connection(G_DBUS_PROXY(ddl
->proxy
));
889 stream
= g_dbus_connection_get_stream(conn
);
891 if (!G_IS_UNIX_CONNECTION(stream
)) {
895 sock
= g_socket_connection_get_socket(G_SOCKET_CONNECTION(stream
));
896 creds
= g_socket_get_credentials(sock
, &err
);
899 g_debug("Failed to get peer credentials: %s", err
->message
);
903 pid
= g_credentials_get_native(creds
, G_CREDENTIALS_TYPE_WIN32_PID
);
906 g_debug("Failed to get peer PID");
910 ddl
->peer_process
= OpenProcess(
911 PROCESS_DUP_HANDLE
| PROCESS_QUERY_INFORMATION
,
914 if (!ddl
->peer_process
) {
915 g_autofree
char *msg
= g_win32_error_message(GetLastError());
916 g_debug("Failed to OpenProcess: %s", msg
);
925 dbus_display_listener_setup_d3d11(DBusDisplayListener
*ddl
)
928 g_autoptr(GError
) err
= NULL
;
930 if (!dbus_display_listener_implements(ddl
,
931 "org.qemu.Display1.Listener.Win32.D3d11")) {
935 if (!dbus_display_listener_setup_peer_process(ddl
)) {
940 qemu_dbus_display1_listener_win32_d3d11_proxy_new_sync(ddl
->conn
,
941 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
943 "/org/qemu/Display1/Listener",
946 if (!ddl
->d3d11_proxy
) {
947 g_debug("Failed to setup win32 d3d11 proxy: %s", err
->message
);
954 dbus_display_listener_setup_shared_map(DBusDisplayListener
*ddl
)
957 g_autoptr(GError
) err
= NULL
;
959 if (!dbus_display_listener_implements(ddl
, "org.qemu.Display1.Listener.Win32.Map")) {
963 if (!dbus_display_listener_setup_peer_process(ddl
)) {
968 qemu_dbus_display1_listener_win32_map_proxy_new_sync(ddl
->conn
,
969 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
971 "/org/qemu/Display1/Listener",
974 if (!ddl
->map_proxy
) {
975 g_debug("Failed to setup win32 map proxy: %s", err
->message
);
979 ddl
->can_share_map
= true;
983 static GDBusMessage
*
984 dbus_filter(GDBusConnection
*connection
,
985 GDBusMessage
*message
,
989 DBusDisplayListener
*ddl
= DBUS_DISPLAY_LISTENER(user_data
);
996 serial
= g_dbus_message_get_serial(message
);
997 if (serial
<= ddl
->out_serial_to_discard
) {
998 trace_dbus_filter(serial
, ddl
->out_serial_to_discard
);
1005 DBusDisplayListener
*
1006 dbus_display_listener_new(const char *bus_name
,
1007 GDBusConnection
*conn
,
1008 DBusDisplayConsole
*console
)
1010 DBusDisplayListener
*ddl
;
1012 g_autoptr(GError
) err
= NULL
;
1014 ddl
= g_object_new(DBUS_DISPLAY_TYPE_LISTENER
, NULL
);
1016 qemu_dbus_display1_listener_proxy_new_sync(conn
,
1017 G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START
,
1019 "/org/qemu/Display1/Listener",
1023 error_report("Failed to setup proxy: %s", err
->message
);
1024 g_object_unref(conn
);
1025 g_object_unref(ddl
);
1029 ddl
->dbus_filter
= g_dbus_connection_add_filter(conn
, dbus_filter
, g_object_ref(ddl
), g_object_unref
);
1030 ddl
->bus_name
= g_strdup(bus_name
);
1032 ddl
->console
= console
;
1034 dbus_display_listener_setup_shared_map(ddl
);
1035 dbus_display_listener_setup_d3d11(ddl
);
1037 con
= qemu_console_lookup_by_index(dbus_display_console_get_index(console
));
1040 register_displaychangelistener(&ddl
->dcl
);