libs: wayland: add support for XDG-shell protocol

[wl_shell] is officially [deprecated], so provide support for the
XDG-shell protocol should be provided by all desktop-like compositors.
(In case they don't, we can of course fall back to wl_shell).

Note that the XML file is directly provided by the `wayland-protocols`
dependency and generates the protocol marshalling code.

[wl_shell]: https://people.freedesktop.org/~whot/wayland-doxygen/wayland/Client/group__iface__wl__shell.html
[deprecated]: 698dde1958
This commit is contained in:
Niels De Graef 2019-01-14 11:30:48 +01:00 committed by Víctor Manuel Jáquez Leal
parent 8e695c8fdb
commit f84394fa49
8 changed files with 222 additions and 19 deletions

View file

@ -466,13 +466,18 @@ fi
dnl Check for Wayland
USE_WAYLAND=0
if test "x$enable_wayland" = "xyes"; then
PKG_CHECK_MODULES([WAYLAND], [wayland-client >= $WAYLAND_REQ],
PKG_CHECK_MODULES([WAYLAND], [wayland-client >= $WAYLAND_REQ, wayland-protocols >= 1.15],
[
USE_WAYLAND=1
saved_CPPFLAGS="$CPPFLAGS"
CPPFLAGS="$CPPFLAGS $WAYLAND_CFLAGS"
AC_CHECK_HEADERS([wayland-client.h], [], [USE_WAYLAND=0])
CPPFLAGS="$saved_CPPFLAGS"
AC_CHECK_PROGS(WAYLAND_SCANNER, wayland-scanner, [USE_WAYLAND=0])
WAYLAND_PROTOCOLS_DATADIR="`$PKG_CONFIG --variable=pkgdatadir wayland-protocols`"
AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, $WAYLAND_PROTOCOLS_DATADIR)
], [:])
fi

View file

@ -314,9 +314,28 @@ libgstvaapi_egl_source_priv_h = \
ogl_compat.h \
$(NULL)
BUILT_SOURCES=
CLEANFILES=
# Generate the necessary files for XDG-shell
if USE_WAYLAND
xdg_shell_protocol_spec = $(WAYLAND_PROTOCOLS_DATADIR)/stable/xdg-shell/xdg-shell.xml
xdg_shell_header = xdg-shell-client-protocol.h
xdg_shell_source = xdg-shell-client-protocol.c
$(xdg_shell_header): $(xdg_shell_protocol_spec)
$(AM_V_GEN) $(WAYLAND_SCANNER) client-header < $< > $@
$(xdg_shell_source): $(xdg_shell_protocol_spec)
$(AM_V_GEN) $(WAYLAND_SCANNER) private-code < $< > $@
BUILT_SOURCES += $(xdg_shell_header) $(xdg_shell_source)
CLEANFILES += $(BUILT_SOURCES)
endif
libgstvaapi_wayland_source_c = \
gstvaapidisplay_wayland.c \
gstvaapiwindow_wayland.c \
$(xdg_shell_source) \
$(NULL)
libgstvaapi_wayland_source_h = \
@ -327,6 +346,7 @@ libgstvaapi_wayland_source_h = \
libgstvaapi_wayland_source_priv_h = \
gstvaapicompat.h \
gstvaapidisplay_wayland_priv.h \
$(xdg_shell_header) \
$(NULL)
libgstvaapi_la_SOURCES = \

View file

@ -94,6 +94,17 @@ static const struct wl_output_listener output_listener = {
output_handle_mode,
};
static void
handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base,
uint32_t serial)
{
xdg_wm_base_pong (xdg_wm_base, serial);
}
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
handle_xdg_wm_base_ping
};
static void
registry_handle_global (void *data,
struct wl_registry *registry,
@ -106,7 +117,11 @@ registry_handle_global (void *data,
wl_registry_bind (registry, id, &wl_compositor_interface, 1);
else if (strcmp (interface, "wl_shell") == 0)
priv->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
else if (strcmp (interface, "wl_output") == 0) {
else if (strcmp (interface, "xdg_wm_base") == 0) {
priv->xdg_wm_base =
wl_registry_bind (registry, id, &xdg_wm_base_interface, 1);
xdg_wm_base_add_listener (priv->xdg_wm_base, &xdg_wm_base_listener, priv);
} else if (strcmp (interface, "wl_output") == 0) {
priv->output = wl_registry_bind (registry, id, &wl_output_interface, 1);
wl_output_add_listener (priv->output, &output_listener, priv);
}
@ -142,10 +157,14 @@ gst_vaapi_display_wayland_setup (GstVaapiDisplay * display)
return FALSE;
}
if (priv->xdg_wm_base)
return TRUE;
if (!priv->wl_shell) {
GST_ERROR ("failed to bind wl_shell interface");
return FALSE;
}
return TRUE;
}
@ -192,6 +211,7 @@ gst_vaapi_display_wayland_close_display (GstVaapiDisplay * display)
g_clear_pointer (&priv->output, wl_output_destroy);
g_clear_pointer (&priv->wl_shell, wl_shell_destroy);
g_clear_pointer (&priv->xdg_wm_base, xdg_wm_base_destroy);
g_clear_pointer (&priv->compositor, wl_compositor_destroy);
g_clear_pointer (&priv->registry, wl_registry_destroy);

View file

@ -24,6 +24,8 @@
#ifndef GST_VAAPI_DISPLAY_WAYLAND_PRIV_H
#define GST_VAAPI_DISPLAY_WAYLAND_PRIV_H
#include "xdg-shell-client-protocol.h"
#include <gst/vaapi/gstvaapidisplay_wayland.h>
#include "gstvaapidisplay_priv.h"
@ -61,6 +63,7 @@ struct _GstVaapiDisplayWaylandPrivate
struct wl_display *wl_display;
struct wl_compositor *compositor;
struct wl_shell *wl_shell;
struct xdg_wm_base *xdg_wm_base;
struct wl_output *output;
struct wl_registry *registry;
guint width;

View file

@ -98,6 +98,8 @@ frame_state_free (FrameState * frame)
struct _GstVaapiWindowWaylandPrivate
{
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_shell_surface *wl_shell_surface;
struct wl_surface *surface;
struct wl_region *opaque_region;
@ -137,10 +139,79 @@ struct _GstVaapiWindowWaylandClass
G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowWayland, gst_vaapi_window_wayland,
GST_TYPE_VAAPI_WINDOW);
/* Object signals */
enum
{
SIZE_CHANGED,
N_SIGNALS
};
static guint signals[N_SIGNALS];
static void
handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel,
int32_t width, int32_t height, struct wl_array *states)
{
GstVaapiWindow *window = GST_VAAPI_WINDOW (data);
const uint32_t *state;
GST_DEBUG ("Got XDG-toplevel::reconfigure, [width x height] = [%d x %d]",
width, height);
wl_array_for_each (state, states) {
switch (*state) {
case XDG_TOPLEVEL_STATE_FULLSCREEN:
case XDG_TOPLEVEL_STATE_MAXIMIZED:
case XDG_TOPLEVEL_STATE_RESIZING:
case XDG_TOPLEVEL_STATE_ACTIVATED:
break;
}
}
if (width > 0 && height > 0) {
gst_vaapi_window_set_size (window, width, height);
g_signal_emit (window, signals[SIZE_CHANGED], 0, width, height);
}
}
static void
handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel)
{
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_xdg_toplevel_configure,
handle_xdg_toplevel_close,
};
static gboolean
gst_vaapi_window_wayland_show (GstVaapiWindow * window)
{
GST_WARNING ("unimplemented GstVaapiWindowWayland::show()");
GstVaapiWindowWaylandPrivate *priv =
GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
if (priv->xdg_surface == NULL) {
GST_FIXME ("GstVaapiWindowWayland::show() unimplemented for wl_shell");
return TRUE;
}
if (priv->xdg_toplevel != NULL) {
GST_DEBUG ("XDG toplevel already mapped");
return TRUE;
}
/* Create a toplevel window out of it */
priv->xdg_toplevel = xdg_surface_get_toplevel (priv->xdg_surface);
g_return_val_if_fail (priv->xdg_toplevel, FALSE);
xdg_toplevel_set_title (priv->xdg_toplevel, "VA-API Wayland window");
wl_proxy_set_queue ((struct wl_proxy *) priv->xdg_toplevel,
priv->event_queue);
xdg_toplevel_add_listener (priv->xdg_toplevel, &xdg_toplevel_listener,
window);
/* Commit the xdg_surface state as top-level window */
wl_surface_commit (priv->surface);
return TRUE;
}
@ -148,7 +219,18 @@ gst_vaapi_window_wayland_show (GstVaapiWindow * window)
static gboolean
gst_vaapi_window_wayland_hide (GstVaapiWindow * window)
{
GST_WARNING ("unimplemented GstVaapiWindowWayland::hide()");
GstVaapiWindowWaylandPrivate *priv =
GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
if (priv->xdg_surface == NULL) {
GST_FIXME ("GstVaapiWindowWayland::hide() unimplemented for wl_shell");
return TRUE;
}
if (priv->xdg_toplevel != NULL) {
g_clear_pointer (&priv->xdg_toplevel, xdg_toplevel_destroy);
wl_surface_commit (priv->surface);
}
return TRUE;
}
@ -236,6 +318,17 @@ static const struct wl_shell_surface_listener shell_surface_listener = {
handle_popup_done
};
static void
handle_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface,
uint32_t serial)
{
xdg_surface_ack_configure (xdg_surface, serial);
}
static const struct xdg_surface_listener xdg_surface_listener = {
handle_xdg_surface_configure,
};
static gboolean
gst_vaapi_window_wayland_set_fullscreen (GstVaapiWindow * window,
gboolean fullscreen)
@ -248,6 +341,16 @@ gst_vaapi_window_wayland_set_fullscreen (GstVaapiWindow * window,
return TRUE;
}
/* XDG-shell */
if (priv->xdg_toplevel != NULL) {
if (fullscreen)
xdg_toplevel_set_fullscreen (priv->xdg_toplevel, NULL);
else
xdg_toplevel_unset_fullscreen (priv->xdg_toplevel);
return TRUE;
}
/* wl_shell fallback */
if (!fullscreen)
wl_shell_surface_set_toplevel (priv->wl_shell_surface);
else {
@ -270,7 +373,8 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window,
GST_DEBUG ("create window, size %ux%u", *width, *height);
g_return_val_if_fail (priv_display->compositor != NULL, FALSE);
g_return_val_if_fail (priv_display->wl_shell != NULL, FALSE);
g_return_val_if_fail (priv_display->xdg_wm_base || priv_display->wl_shell,
FALSE);
GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
priv->event_queue = wl_display_create_queue (priv_display->wl_display);
@ -285,18 +389,33 @@ gst_vaapi_window_wayland_create (GstVaapiWindow * window,
return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->surface, priv->event_queue);
GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
priv->wl_shell_surface = wl_shell_get_shell_surface (priv_display->wl_shell,
priv->surface);
GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
if (!priv->wl_shell_surface)
return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->wl_shell_surface,
priv->event_queue);
/* Prefer XDG-shell over deprecated wl_shell (if available) */
if (priv_display->xdg_wm_base) {
/* Create the XDG surface. We make the toplevel on VaapiWindow::show() */
GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
priv->xdg_surface = xdg_wm_base_get_xdg_surface (priv_display->xdg_wm_base,
priv->surface);
GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
if (!priv->xdg_surface)
return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->xdg_surface,
priv->event_queue);
xdg_surface_add_listener (priv->xdg_surface, &xdg_surface_listener, window);
} else {
/* Fall back to wl_shell */
GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
priv->wl_shell_surface = wl_shell_get_shell_surface (priv_display->wl_shell,
priv->surface);
GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
if (!priv->wl_shell_surface)
return FALSE;
wl_proxy_set_queue ((struct wl_proxy *) priv->wl_shell_surface,
priv->event_queue);
wl_shell_surface_add_listener (priv->wl_shell_surface,
&shell_surface_listener, priv);
wl_shell_surface_set_toplevel (priv->wl_shell_surface);
wl_shell_surface_add_listener (priv->wl_shell_surface,
&shell_surface_listener, priv);
wl_shell_surface_set_toplevel (priv->wl_shell_surface);
}
priv->poll = gst_poll_new (TRUE);
gst_poll_fd_init (&priv->pollfd);
@ -332,6 +451,7 @@ gst_vaapi_window_wayland_finalize (GObject * object)
if (priv->event_queue)
wl_display_roundtrip_queue (wl_display, priv->event_queue);
g_clear_pointer (&priv->xdg_surface, xdg_surface_destroy);
g_clear_pointer (&priv->wl_shell_surface, wl_shell_surface_destroy);
g_clear_pointer (&priv->surface, wl_surface_destroy);
g_clear_pointer (&priv->event_queue, wl_event_queue_destroy);
@ -550,6 +670,10 @@ gst_vaapi_window_wayland_class_init (GstVaapiWindowWaylandClass * klass)
window_class->set_fullscreen = gst_vaapi_window_wayland_set_fullscreen;
window_class->unblock = gst_vaapi_window_wayland_unblock;
window_class->unblock_cancel = gst_vaapi_window_wayland_unblock_cancel;
signals[SIZE_CHANGED] = g_signal_new ("size-changed",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
}
static void

View file

@ -183,10 +183,24 @@ if USE_EGL
endif
if USE_WAYLAND
# The XDG shell interface needs to be generated first
wayland_protocols_basedir = wayland_protocols_dep.get_pkgconfig_variable('pkgdatadir')
xdg_shell_xml_spec = join_paths(wayland_protocols_basedir, 'stable', 'xdg-shell', 'xdg-shell.xml')
xdg_shell_header = custom_target('vaapi-xdg-shell-client-header',
command: [ wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@' ],
input: xdg_shell_xml_spec,
output: 'xdg-shell-client-protocol.h')
xdg_shell_code = custom_target('vaapi-xdg-shell-client-code',
command: [ wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@' ],
input: xdg_shell_xml_spec,
output: 'xdg-shell-client-protocol.c')
gstlibvaapi_sources += [
'gstvaapidisplay_wayland.c',
'gstvaapiwindow_wayland.c',
]
xdg_shell_header,
xdg_shell_code,
]
gstlibvaapi_headers += [
'gstvaapidisplay_wayland.h',
'gstvaapiwindow_wayland.h',
@ -209,7 +223,7 @@ if USE_GLX
gstlibvaapi_deps += [libva_x11_dep, x11_dep, gl_dep, libdl_dep]
endif
if USE_WAYLAND
gstlibvaapi_deps += [libva_wayland_dep, wayland_client_dep]
gstlibvaapi_deps += [libva_wayland_dep, wayland_client_dep, wayland_protocols_dep]
endif
if USE_X11
gstlibvaapi_deps += [libva_x11_dep, x11_dep, xrandr_dep, xrender_dep]

View file

@ -533,6 +533,17 @@ gst_vaapisink_backend_x11 (void)
#include <gst/vaapi/gstvaapidisplay_wayland.h>
#include <gst/vaapi/gstvaapiwindow_wayland.h>
static void
on_window_wayland_size_changed (GstVaapiWindowWayland * window, gint width,
gint height, gpointer user_data)
{
GstVaapiSink *sink = GST_VAAPISINK (user_data);
GST_DEBUG ("Wayland window size changed to: %dx%d", width, height);
gst_vaapisink_reconfigure_window (sink);
gst_vaapisink_show_frame (GST_VIDEO_SINK_CAST (sink), NULL);
}
static gboolean
gst_vaapisink_wayland_create_window (GstVaapiSink * sink, guint width,
guint height)
@ -544,6 +555,10 @@ gst_vaapisink_wayland_create_window (GstVaapiSink * sink, guint width,
sink->window = gst_vaapi_window_wayland_new (display, width, height);
if (!sink->window)
return FALSE;
g_signal_connect_object (sink->window, "size-changed",
G_CALLBACK (on_window_wayland_size_changed), sink, 0);
return TRUE;
}

View file

@ -65,6 +65,8 @@ gl_dep = dependency('gl', required: false)
glesv2_dep = dependency('glesv2', required: false)
libdl_dep = cc.find_library('dl', required: false)
wayland_client_dep = dependency('wayland-client', version: libwayland_req, required: false)
wayland_protocols_dep = dependency('wayland-protocols', version: '>= 1.15', required: false)
wayland_scanner_bin = find_program('wayland-scanner', required: false)
x11_dep = dependency('x11', required: false)
xrandr_dep = dependency('xrandr', required: false)
xrender_dep = dependency('xrender', required: false)
@ -92,7 +94,7 @@ USE_H264_FEI_ENCODER = USE_ENCODERS and cc.has_header('va/va_fei_h264.h', depend
USE_DRM = libva_drm_dep.found() and libdrm_dep.found() and libudev_dep.found() and get_option('with_drm') != 'no'
USE_EGL = gmodule_dep.found() and egl_dep.found() and GLES_VERSION_MASK != 0 and get_option('with_egl') != 'no'
USE_GLX = libva_x11_dep.found() and x11_dep.found() and gl_dep.found() and libdl_dep.found() and get_option('with_glx') != 'no'
USE_WAYLAND = libva_wayland_dep.found() and wayland_client_dep.found() and get_option('with_wayland') != 'no'
USE_WAYLAND = libva_wayland_dep.found() and wayland_client_dep.found() and wayland_protocols_dep.found() and wayland_scanner_bin.found() and get_option('with_wayland') != 'no'
USE_X11 = libva_x11_dep.found() and x11_dep.found() and get_option('with_x11') != 'no'
driverdir = libva_dep.get_pkgconfig_variable('driverdir')