From nobody Tue May 21 05:09:33 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=intel.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1624508739817270.2183804663879; Wed, 23 Jun 2021 21:25:39 -0700 (PDT) Received: from localhost ([::1]:45038 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1lwGvq-0002S8-Ks for importer@patchew.org; Thu, 24 Jun 2021 00:25:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:54684) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lwGtu-0000JM-82 for qemu-devel@nongnu.org; Thu, 24 Jun 2021 00:23:38 -0400 Received: from mga06.intel.com ([134.134.136.31]:55797) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1lwGtr-0003kg-9I for qemu-devel@nongnu.org; Thu, 24 Jun 2021 00:23:38 -0400 Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jun 2021 21:23:24 -0700 Received: from vkasired-desk2.fm.intel.com ([10.105.128.127]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 23 Jun 2021 21:23:24 -0700 IronPort-SDR: qN1RAU2uwDvt1ZFN5JQneMtSURUgHT75P7iRnARpbOYbiHjkDVpCp5osmHeP6ccUY4LCBGLIJO tcMoJvKO6EEQ== X-IronPort-AV: E=McAfee;i="6200,9189,10024"; a="268526360" X-IronPort-AV: E=Sophos;i="5.83,295,1616482800"; d="scan'208";a="268526360" IronPort-SDR: O5Xbwh97KCnAooB6ZlDTLuPhNx76TmSb84i7VsJlXYcm7rKHaWDphrDR5k42WaLjU2xXVvXJim gP+0f/R5fZ9w== X-IronPort-AV: E=Sophos;i="5.83,295,1616482800"; d="scan'208";a="624049666" From: Vivek Kasireddy To: qemu-devel@nongnu.org Subject: [RFC v1 1/1] ui: Add a plain Wayland backend for Qemu UI Date: Wed, 23 Jun 2021 21:10:40 -0700 Message-Id: <20210624041040.1250631-2-vivek.kasireddy@intel.com> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210624041040.1250631-1-vivek.kasireddy@intel.com> References: <20210624041040.1250631-1-vivek.kasireddy@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=134.134.136.31; envelope-from=vivek.kasireddy@intel.com; helo=mga06.intel.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Vivek Kasireddy , Gerd Hoffmann Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" Content-Type: text/plain; charset="utf-8" Cc: Gerd Hoffmann Signed-off-by: Vivek Kasireddy --- configure | 17 ++ meson.build | 25 +++ meson_options.txt | 2 + qapi/ui.json | 19 ++- ui/meson.build | 52 ++++++ ui/wayland.c | 402 ++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 516 insertions(+), 1 deletion(-) create mode 100644 ui/wayland.c diff --git a/configure b/configure index 8dcb9965b2..f6caaa6329 100755 --- a/configure +++ b/configure @@ -403,6 +403,7 @@ cfi_debug=3D"false" seccomp=3D"auto" glusterfs=3D"auto" gtk=3D"auto" +wayland=3D"auto" tls_priority=3D"NORMAL" gnutls=3D"$default_feature" nettle=3D"$default_feature" @@ -1372,6 +1373,10 @@ for opt do ;; --enable-gtk) gtk=3D"enabled" ;; + --disable-wayland) wayland=3D"disabled" + ;; + --enable-wayland) wayland=3D"enabled" + ;; --tls-priority=3D*) tls_priority=3D"$optarg" ;; --disable-gnutls) gnutls=3D"no" @@ -1845,6 +1850,7 @@ disabled with --disable-FEATURE, default is enabled i= f available sdl SDL UI sdl-image SDL Image support for icons gtk gtk UI + wayland Wayland UI vte vte support for the gtk UI curses curses UI iconv font glyph conversion support @@ -3616,6 +3622,11 @@ if $pkg_config gbm; then gbm=3D"yes" fi =20 +if $pkg_config wayland-client; then + wayland_cflags=3D"$($pkg_config --cflags wayland-client)" + wayland_libs=3D"$($pkg_config --libs wayland-client)" +fi + if test "$opengl" !=3D "no" ; then epoxy=3Dno if $pkg_config epoxy; then @@ -5870,6 +5881,11 @@ if test "$gbm" =3D "yes" ; then echo "GBM_CFLAGS=3D$gbm_cflags" >> $config_host_mak fi =20 +if test "$wayland" =3D "enabled" ; then + echo "CONFIG_WAYLAND=3Dy" >> $config_host_mak + echo "WAYLAND_LIBS=3D$wayland_libs" >> $config_host_mak + echo "WAYLAND_CFLAGS=3D$wayland_cflags" >> $config_host_mak +fi =20 if test "$avx2_opt" =3D "yes" ; then echo "CONFIG_AVX2_OPT=3Dy" >> $config_host_mak @@ -6436,6 +6452,7 @@ if test "$skip_meson" =3D no; then -Dkvm=3D$kvm -Dhax=3D$hax -Dwhpx=3D$whpx -Dhvf=3D$hvf -Dnvmm=3D$nv= mm \ -Dxen=3D$xen -Dxen_pci_passthrough=3D$xen_pci_passthrough -Dtcg=3D= $tcg \ -Dcocoa=3D$cocoa -Dgtk=3D$gtk -Dmpath=3D$mpath -Dsdl=3D$sdl -Dsdl_= image=3D$sdl_image \ + -Dwayland=3D$wayland \ -Dvnc=3D$vnc -Dvnc_sasl=3D$vnc_sasl -Dvnc_jpeg=3D$vnc_jpeg -Dvnc_p= ng=3D$vnc_png \ -Dgettext=3D$gettext -Dxkbcommon=3D$xkbcommon -Du2f=3D$u2f -Dvirti= ofsd=3D$virtiofsd \ -Dcapstone=3D$capstone -Dslirp=3D$slirp -Dfdt=3D$fdt -Dbrlapi=3D$b= rlapi \ diff --git a/meson.build b/meson.build index 626cf932c1..dbafe4a5d4 100644 --- a/meson.build +++ b/meson.build @@ -855,6 +855,29 @@ if gtkx11.found() x11 =3D dependency('x11', method: 'pkg-config', required: gtkx11.found(), kwargs: static_kwargs) endif + +wayland =3D not_found +if not get_option('wayland').auto() + wlclientdep =3D dependency('wayland-client', version: '>=3D 1.18.90', + method: 'pkg-config', + required: get_option('wayland'), + kwargs: static_kwargs) + wlprotocolsdep =3D dependency('wayland-protocols', version: '>=3D 1.14.9= 1', + method: 'pkg-config', + required: get_option('wayland'), + kwargs: static_kwargs) + + if not wlprotocolsdep.found() + wlproto_dir =3D subproject('wayland-protocols').get_variable('wayland_= protocols_srcdir') + else + wlproto_dir =3D wlprotocolsdep.get_pkgconfig_variable('pkgdatadir') + endif + + wayland =3D declare_dependency(dependencies: [wlclientdep, wlprotocolsde= p], + compile_args: config_host['WAYLAND_CFLAGS']= .split(), + link_args: config_host['WAYLAND_LIBS'].spli= t()) +endif + vnc =3D not_found png =3D not_found jpeg =3D not_found @@ -1146,6 +1169,7 @@ if glusterfs.found() config_host_data.set('CONFIG_GLUSTERFS_IOCB_HAS_STAT', glusterfs_iocb_ha= s_stat) endif config_host_data.set('CONFIG_GTK', gtk.found()) +config_host_data.set('CONFIG_WAYLAND', wayland.found()) config_host_data.set('CONFIG_LIBATTR', have_old_libattr) config_host_data.set('CONFIG_LIBCAP_NG', libcap_ng.found()) config_host_data.set('CONFIG_EBPF', libbpf.found()) @@ -2695,6 +2719,7 @@ summary_info +=3D {'SDL support': sdl.found()} summary_info +=3D {'SDL image support': sdl_image.found()} # TODO: add back version summary_info +=3D {'GTK support': gtk.found()} +summary_info +=3D {'Wayland support': wayland.found()} summary_info +=3D {'pixman': pixman.found()} # TODO: add back version summary_info +=3D {'VTE support': config_host.has_key('CONFIG_VTE')} diff --git a/meson_options.txt b/meson_options.txt index 3d304cac96..86066c63c9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -86,6 +86,8 @@ option('rbd', type : 'feature', value : 'auto', description: 'Ceph block device driver') option('gtk', type : 'feature', value : 'auto', description: 'GTK+ user interface') +option('wayland', type : 'feature', value : 'auto', + description: 'Wayland user interface') option('sdl', type : 'feature', value : 'auto', description: 'SDL user interface') option('sdl_image', type : 'feature', value : 'auto', diff --git a/qapi/ui.json b/qapi/ui.json index 1052ca9c38..55e5967889 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1057,6 +1057,20 @@ { 'struct' : 'DisplayEGLHeadless', 'data' : { '*rendernode' : 'str' } } =20 +## +# @DisplayWayland: +# +# Wayland display options. +# +# @rendernode: Which DRM render node should be used. Default is the first +# available node on the host. +# +# Since: 3.1 +# +## +{ 'struct' : 'DisplayWayland', + 'data' : { '*rendernode' : 'str' } } + ## # @DisplayGLMode: # @@ -1108,6 +1122,8 @@ # DRI device. Graphical display need to be paired with # VNC or Spice. (Since 3.1) # +# @wayland: The Wayland user interface. +# # @curses: Display video output via curses. For graphics device # models which support a text mode, QEMU can display this # output using a curses/ncurses interface. Nothing is @@ -1128,7 +1144,7 @@ { 'enum' : 'DisplayType', 'data' : [ 'default', 'none', 'gtk', 'sdl', 'egl-headless', 'curses', 'cocoa', - 'spice-app'] } + 'wayland', 'spice-app'] } =20 ## # @DisplayOptions: @@ -1154,6 +1170,7 @@ 'discriminator' : 'type', 'data' : { 'gtk' : 'DisplayGTK', 'curses' : 'DisplayCurses', + 'wayland' : 'DisplayWayland', 'egl-headless' : 'DisplayEGLHeadless'} } =20 ## diff --git a/ui/meson.build b/ui/meson.build index a3a187d633..fe255aec04 100644 --- a/ui/meson.build +++ b/ui/meson.build @@ -62,6 +62,58 @@ if config_host.has_key('CONFIG_OPENGL') and gbm.found() ui_modules +=3D {'egl-headless' : egl_headless_ss} endif =20 +wayland_scanner =3D find_program('wayland-scanner') +proto_sources =3D [ + ['xdg-shell', 'stable', ], + ['fullscreen-shell', 'unstable', 'v1', ], + ['linux-dmabuf', 'unstable', 'v1', ], +] +wayland_headers =3D [] +wayland_proto_sources =3D [] + +if wayland.found() + foreach p: proto_sources + proto_name =3D p.get(0) + proto_stability =3D p.get(1) + + if proto_stability =3D=3D 'stable' + output_base =3D proto_name + input =3D files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(pro= to_stability, proto_name, output_base))) + else + proto_version =3D p.get(2) + output_base =3D '@0@-@1@-@2@'.format(proto_name, proto_stability, pr= oto_version) + input =3D files(join_paths(wlproto_dir, '@0@/@1@/@2@.xml'.format(pro= to_stability, proto_name, output_base))) + endif + + wayland_headers +=3D custom_target('@0@ client header'.format(output_b= ase), + input: input, + output: '@0@-client-protocol.h'.format(output_base), + command: [ + wayland_scanner, + 'client-header', + '@INPUT@', '@OUTPUT@', + ], build_by_default: true + ) + + wayland_proto_sources +=3D custom_target('@0@ source'.format(output_ba= se), + input: input, + output: '@0@-protocol.c'.format(output_base), + command: [ + wayland_scanner, + 'private-code', + '@INPUT@', '@OUTPUT@', + ], build_by_default: true + ) + endforeach +endif + +if wayland.found() + wayland_ss =3D ss.source_set() + wayland_ss.add(when: wayland, if_true: files('wayland.c', 'xdg-shell-pro= tocol.c', 'fullscreen-shell-unstable-v1-protocol.c','linux-dmabuf-unstable-= v1-protocol.c')) + #wayland_ss.add(when: wayland, if_true: files('wayland.c'), [wayland_pro= to_sources]) + ui_modules +=3D {'wayland' : wayland_ss} +endif + if gtk.found() softmmu_ss.add(when: 'CONFIG_WIN32', if_true: files('win32-kbd-hook.c')) =20 diff --git a/ui/wayland.c b/ui/wayland.c new file mode 100644 index 0000000000..351d7e1146 --- /dev/null +++ b/ui/wayland.c @@ -0,0 +1,402 @@ +/* + * Wayland UI -- A simple Qemu UI backend to share buffers with Wayland co= mpositors + * + * This work is licensed under the terms of the GNU GPL, version 2 or late= r. + * See the COPYING file in the top-level directory. + * + * Mostly (boilerplate) based on cgit.freedesktop.org/wayland/weston/tree/= clients/simple-dmabuf-egl.c + */ + +#include "qemu/osdep.h" +#include "qemu/module.h" +#include "qemu/main-loop.h" +#include "sysemu/sysemu.h" +#include "ui/console.h" +#include +#include "xdg-shell-client-protocol.h" +#include "fullscreen-shell-unstable-v1-client-protocol.h" +#include "linux-dmabuf-unstable-v1-client-protocol.h" + +#define MAX_BUFFERS 3 + +typedef struct wayland_display { + struct wl_display *display; + struct wl_registry *registry; + struct wl_compositor *compositor; + struct xdg_wm_base *wm_base; + struct zwp_fullscreen_shell_v1 *fshell; + struct zwp_linux_dmabuf_v1 *dmabuf; +} wayland_display; + +typedef struct wayland_buffer { + QemuConsole *con; + QemuDmaBuf *dmabuf; + struct wl_buffer *buffer; + bool busy; +} wayland_buffer; + +typedef struct wayland_window { + wayland_display *display; + DisplayChangeListener dcl; + struct wl_surface *surface; + struct xdg_surface *xdg_surface; + struct xdg_toplevel *xdg_toplevel; + struct wl_callback *callback; + wayland_buffer buffers[MAX_BUFFERS]; + wayland_buffer *new_buffer; + bool redraw; +} wayland_window; + +static const struct wl_callback_listener frame_listener; + +static void +xdg_surface_handle_configure(void *data, struct xdg_surface *surface, + uint32_t serial) +{ + xdg_surface_ack_configure(surface, serial); +} + +static const struct xdg_surface_listener xdg_surface_listener =3D { + xdg_surface_handle_configure, +}; + +static void +xdg_toplevel_handle_configure(void *data, struct xdg_toplevel *toplevel, + int32_t width, int32_t height, + struct wl_array *states) +{ +} + +static void +xdg_toplevel_handle_close(void *data, struct xdg_toplevel *xdg_toplevel) +{ +} + +static const struct xdg_toplevel_listener xdg_toplevel_listener =3D { + xdg_toplevel_handle_configure, + xdg_toplevel_handle_close, +}; + +static void wayland_refresh(DisplayChangeListener *dcl) +{ + graphic_hw_update(dcl->con); +} + +static QEMUGLContext wayland_create_context(DisplayChangeListener *dcl, + QEMUGLParams *params) +{ + return NULL; +} + +static void wayland_destroy_context(DisplayChangeListener *dcl, + QEMUGLContext ctx) +{ +} + +static int wayland_make_context_current(DisplayChangeListener *dcl, + QEMUGLContext ctx) +{ + return 0; +} + +static void wayland_scanout_disable(DisplayChangeListener *dcl) +{ +} + +static void wayland_scanout_texture(DisplayChangeListener *dcl, + uint32_t backing_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) +{ +} + +static void wayland_release_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ +} + +static void wayland_dispatch_handler(void *opaque) +{ + wayland_display *wldpy =3D opaque; + + wl_display_prepare_read(wldpy->display); + wl_display_read_events(wldpy->display); + wl_display_dispatch_pending(wldpy->display); + wl_display_flush(wldpy->display); +} + +static void wayland_window_redraw(void *data, struct wl_callback *callback, + uint32_t time) +{ + wayland_window *window =3D data; + QemuDmaBuf *dmabuf =3D window->new_buffer->dmabuf; + + if (callback) { + wl_callback_destroy(callback); + window->callback =3D NULL; + } + if (!window->redraw) { + return; + } + window->callback =3D wl_surface_frame(window->surface); + wl_callback_add_listener(window->callback, &frame_listener, window); + + wl_surface_attach(window->surface, window->new_buffer->buffer, 0, 0); + wl_surface_damage(window->surface, 0, 0, dmabuf->width, dmabuf->height= ); + wl_surface_commit(window->surface); + wl_display_flush(window->display->display); + window->redraw =3D false; +} + +static const struct wl_callback_listener frame_listener =3D { + wayland_window_redraw +}; + +static void buffer_release(void *data, struct wl_buffer *buf) +{ + wayland_buffer *buffer =3D data; + QemuDmaBuf *dmabuf =3D buffer->dmabuf; + + dmabuf->fence_fd =3D -1; + graphic_hw_gl_block(buffer->con, false); + graphic_hw_gl_flushed(buffer->con); + buffer->busy =3D false; + wl_buffer_destroy(buf); +} + +static const struct wl_buffer_listener buffer_listener =3D { + buffer_release +}; + +static wayland_buffer *window_next_buffer(wayland_window *window) +{ + int i; + + for (i =3D 0; i < MAX_BUFFERS; i++) { + if (!window->buffers[i].busy) { + return &window->buffers[i]; + } + } + return NULL; +} + +static void wayland_scanout_dmabuf(DisplayChangeListener *dcl, + QemuDmaBuf *dmabuf) +{ + wayland_window *window =3D container_of(dcl, wayland_window, dcl); + wayland_display *display =3D window->display; + wayland_buffer *buffer =3D window_next_buffer(window); + struct zwp_linux_buffer_params_v1 *params; + + if (!buffer) { + error_report("Can't find free buffer\n"); + exit(1); + } + params =3D zwp_linux_dmabuf_v1_create_params(display->dmabuf); + zwp_linux_buffer_params_v1_add(params, dmabuf->fd, 0, 0, dmabuf->strid= e, + 0, 0); + buffer->buffer =3D zwp_linux_buffer_params_v1_create_immed(params, + dmabuf->width, + dmabuf->heigh= t, + dmabuf->fourc= c, + 0); + zwp_linux_buffer_params_v1_destroy(params); + buffer->dmabuf =3D dmabuf; + buffer->con =3D window->dcl.con; + window->new_buffer =3D buffer; + dmabuf->fence_fd =3D 1; + wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer); +} + +static void wayland_scanout_flush(DisplayChangeListener *dcl, + uint32_t x, uint32_t y, + uint32_t w, uint32_t h) +{ + wayland_window *window =3D container_of(dcl, wayland_window, dcl); + static bool first =3D true; + + if (!window->new_buffer->busy && !first) { + graphic_hw_gl_block(window->new_buffer->con, true); + } + + window->redraw =3D true; + if (first || !window->callback) { + wayland_window_redraw(window, NULL, 0); + } + window->new_buffer->busy =3D true; + first =3D false; +} + +static const DisplayChangeListenerOps wayland_ops =3D { + .dpy_name =3D "wayland", + .dpy_refresh =3D wayland_refresh, + + .dpy_gl_ctx_create =3D wayland_create_context, + .dpy_gl_ctx_destroy =3D wayland_destroy_context, + .dpy_gl_ctx_make_current =3D wayland_make_context_current, + + .dpy_gl_scanout_disable =3D wayland_scanout_disable, + .dpy_gl_scanout_texture =3D wayland_scanout_texture, + .dpy_gl_scanout_dmabuf =3D wayland_scanout_dmabuf, + .dpy_gl_release_dmabuf =3D wayland_release_dmabuf, + .dpy_gl_update =3D wayland_scanout_flush, +}; + +static void early_wayland_init(DisplayOptions *opts) +{ + display_opengl =3D 1; +} + +static void +dmabuf_modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, + uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo) +{ +} + +static void +dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, + uint32_t format) +{ +} + +static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener =3D { + dmabuf_format, + dmabuf_modifier +}; + +static void +xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial) +{ + xdg_wm_base_pong(shell, serial); +} + +static const struct xdg_wm_base_listener wm_base_listener =3D { + xdg_wm_base_ping, +}; + +static void +registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t versio= n) +{ + wayland_display *d =3D data; + + if (strcmp(interface, "wl_compositor") =3D=3D 0) { + d->compositor =3D wl_registry_bind(registry, + id, &wl_compositor_interface, 1); + } else if (strcmp(interface, "xdg_wm_base") =3D=3D 0) { + d->wm_base =3D wl_registry_bind(registry, + id, &xdg_wm_base_interface, 1); + xdg_wm_base_add_listener(d->wm_base, &wm_base_listener, d); + } else if (strcmp(interface, "zwp_fullscreen_shell_v1") =3D=3D 0) { + d->fshell =3D wl_registry_bind(registry, + id, &zwp_fullscreen_shell_v1_interface, + 1); + } else if (strcmp(interface, "zwp_linux_dmabuf_v1") =3D=3D 0) { + d->dmabuf =3D wl_registry_bind(registry, + id, &zwp_linux_dmabuf_v1_interface, 3); + zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, + d); + } +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ +} + +static const struct wl_registry_listener registry_listener =3D { + registry_handle_global, + registry_handle_global_remove +}; + +static wayland_display *create_display(void) +{ + wayland_display *display; + + display =3D g_new0(wayland_display, 1); + display->display =3D wl_display_connect(NULL); + assert(display->display); + + display->registry =3D wl_display_get_registry(display->display); + wl_registry_add_listener(display->registry, + ®istry_listener, display); + wl_display_roundtrip(display->display); + if (display->dmabuf =3D=3D NULL) { + error_report("No zwp_linux_dmabuf global\n"); + exit(1); + } + return display; +} + +static wayland_window *create_window(wayland_display *display) +{ + wayland_window *window; + + window =3D g_new0(wayland_window, 1); + window->display =3D display; + window->surface =3D wl_compositor_create_surface(display->compositor); + + if (display->wm_base) { + window->xdg_surface =3D xdg_wm_base_get_xdg_surface(display->wm_ba= se, + window->surface); + assert(window->xdg_surface); + xdg_surface_add_listener(window->xdg_surface, + &xdg_surface_listener, window); + window->xdg_toplevel =3D xdg_surface_get_toplevel(window->xdg_surf= ace); + assert(window->xdg_toplevel); + xdg_toplevel_add_listener(window->xdg_toplevel, + &xdg_toplevel_listener, window); + xdg_toplevel_set_title(window->xdg_toplevel, "qemu-wayland"); + wl_surface_commit(window->surface); + } else if (display->fshell) { + zwp_fullscreen_shell_v1_present_surface(display->fshell, + window->surface, + ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_D= EFAULT, + NULL); + } else { + assert(0); + } + + return window; +} + +static void wayland_init(DisplayState *ds, DisplayOptions *opts) +{ + QemuConsole *con; + wayland_display *wldpy; + wayland_window *wlwdw; + int idx; + + wldpy =3D create_display(); + for (idx =3D 0;; idx++) { + con =3D qemu_console_lookup_by_index(idx); + if (!con || !qemu_console_is_graphic(con)) { + break; + } + + wlwdw =3D create_window(wldpy); + wlwdw->dcl.con =3D con; + wlwdw->dcl.ops =3D &wayland_ops; + register_displaychangelistener(&wlwdw->dcl); + } + wl_display_roundtrip(wldpy->display); + qemu_set_fd_handler(wl_display_get_fd(wldpy->display), + wayland_dispatch_handler, NULL, wldpy); +} + +static QemuDisplay qemu_display_wayland =3D { + .type =3D DISPLAY_TYPE_WAYLAND, + .early_init =3D early_wayland_init, + .init =3D wayland_init, +}; + +static void register_wayland(void) +{ + qemu_display_register(&qemu_display_wayland); +} + +type_init(register_wayland); --=20 2.30.2