mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
waylandsink: Implement XDG-shell stable support
[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 spec] is provided by the `wayland-protocols`
git repository, which is provided by the Wayland project.
Fixes https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/issues/897
[wl_shell]: https://people.freedesktop.org/~whot/wayland-doxygen/wayland/Client/group__iface__wl__shell.html
[deprecated]: 698dde1958
[XML spec]: https://github.com/wayland-project/wayland-protocols/blob/master/stable/xdg-shell/xdg-shell.xml
This commit is contained in:
parent
c461f22bef
commit
67bb17e4fa
9 changed files with 164 additions and 26 deletions
|
@ -1319,7 +1319,7 @@ dnl **** Wayland ****
|
|||
translit(dnm, m, l) AM_CONDITIONAL(USE_WAYLAND, true)
|
||||
AC_PATH_PROG([wayland_scanner], [wayland-scanner])
|
||||
AG_GST_CHECK_FEATURE(WAYLAND, [wayland sink], wayland , [
|
||||
PKG_CHECK_MODULES(WAYLAND, wayland-client >= 1.11.0 libdrm >= 2.4.55 wayland-protocols >= 1.4, [
|
||||
PKG_CHECK_MODULES(WAYLAND, wayland-client >= 1.11.0 libdrm >= 2.4.55 wayland-protocols >= 1.15, [
|
||||
if test "x$wayland_scanner" != "x"; then
|
||||
HAVE_WAYLAND="yes"
|
||||
AC_SUBST(WAYLAND_PROTOCOLS_DATADIR, `$PKG_CONFIG --variable=pkgdatadir wayland-protocols`)
|
||||
|
|
|
@ -6,7 +6,9 @@ BUILT_SOURCES = \
|
|||
linux-dmabuf-unstable-v1-protocol.c \
|
||||
linux-dmabuf-unstable-v1-client-protocol.h \
|
||||
fullscreen-shell-unstable-v1-protocol.c \
|
||||
fullscreen-shell-unstable-v1-client-protocol.h
|
||||
fullscreen-shell-unstable-v1-client-protocol.h \
|
||||
xdg-shell-protocol.c \
|
||||
xdg-shell-client-protocol.h
|
||||
|
||||
libgstwaylandsink_la_SOURCES = \
|
||||
gstwaylandsink.c \
|
||||
|
@ -20,7 +22,8 @@ libgstwaylandsink_la_SOURCES = \
|
|||
nodist_libgstwaylandsink_la_SOURCES = \
|
||||
viewporter-protocol.c \
|
||||
linux-dmabuf-unstable-v1-protocol.c \
|
||||
fullscreen-shell-unstable-v1-protocol.c
|
||||
fullscreen-shell-unstable-v1-protocol.c \
|
||||
xdg-shell-protocol.c
|
||||
|
||||
libgstwaylandsink_la_CFLAGS = \
|
||||
$(GST_PLUGINS_BAD_CFLAGS) \
|
||||
|
|
|
@ -659,6 +659,16 @@ render_last_buffer (GstWaylandSink * sink, gboolean redraw)
|
|||
gst_wl_window_render (sink->window, wlbuffer, info);
|
||||
}
|
||||
|
||||
static void
|
||||
on_window_closed (GstWlWindow * window, gpointer user_data)
|
||||
{
|
||||
GstWaylandSink *sink = GST_WAYLAND_SINK (user_data);
|
||||
|
||||
/* Handle window closure by posting an error on the bus */
|
||||
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
|
||||
("Output window was closed"), (NULL));
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
||||
{
|
||||
|
@ -688,6 +698,8 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer)
|
|||
/* if we were not provided a window, create one ourselves */
|
||||
sink->window = gst_wl_window_new_toplevel (sink->display,
|
||||
&sink->video_info, sink->fullscreen, &sink->render_lock);
|
||||
g_signal_connect_object (sink->window, "closed",
|
||||
G_CALLBACK (on_window_closed), sink, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@ if use_wayland
|
|||
['/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
||||
'linux-dmabuf-unstable-v1-protocol.c', 'linux-dmabuf-unstable-v1-client-protocol.h'],
|
||||
['/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml',
|
||||
'fullscreen-shell-unstable-v1-protocol.c', 'fullscreen-shell-unstable-v1-client-protocol.h']
|
||||
'fullscreen-shell-unstable-v1-protocol.c', 'fullscreen-shell-unstable-v1-client-protocol.h'],
|
||||
['/stable/xdg-shell/xdg-shell.xml', 'xdg-shell-protocol.c', 'xdg-shell-client-protocol.h'],
|
||||
]
|
||||
protocols_files = []
|
||||
|
||||
|
|
|
@ -90,6 +90,9 @@ gst_wl_display_finalize (GObject * gobject)
|
|||
if (self->wl_shell)
|
||||
wl_shell_destroy (self->wl_shell);
|
||||
|
||||
if (self->xdg_wm_base)
|
||||
xdg_wm_base_destroy (self->xdg_wm_base);
|
||||
|
||||
if (self->fullscreen_shell)
|
||||
zwp_fullscreen_shell_v1_release (self->fullscreen_shell);
|
||||
|
||||
|
@ -186,6 +189,17 @@ gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
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,
|
||||
uint32_t id, const char *interface, uint32_t version)
|
||||
|
@ -200,6 +214,10 @@ registry_handle_global (void *data, struct wl_registry *registry,
|
|||
wl_registry_bind (registry, id, &wl_subcompositor_interface, 1);
|
||||
} else if (g_strcmp0 (interface, "wl_shell") == 0) {
|
||||
self->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
|
||||
} else if (g_strcmp0 (interface, "xdg_wm_base") == 0) {
|
||||
self->xdg_wm_base =
|
||||
wl_registry_bind (registry, id, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener (self->xdg_wm_base, &xdg_wm_base_listener, self);
|
||||
} else if (g_strcmp0 (interface, "zwp_fullscreen_shell_v1") == 0) {
|
||||
self->fullscreen_shell = wl_registry_bind (registry, id,
|
||||
&zwp_fullscreen_shell_v1_interface, 1);
|
||||
|
@ -331,13 +349,13 @@ gst_wl_display_new_existing (struct wl_display * display,
|
|||
g_warning ("Could not bind to zwp_linux_dmabuf_v1");
|
||||
}
|
||||
|
||||
if (!self->wl_shell && !self->fullscreen_shell) {
|
||||
if (!self->wl_shell && !self->xdg_wm_base && !self->fullscreen_shell) {
|
||||
/* If wl_surface and wl_display are passed via GstContext
|
||||
* wl_shell, zwp_fullscreen_shell are not used.
|
||||
* wl_shell, xdg_shell and zwp_fullscreen_shell are not used.
|
||||
* In this case is correct to continue.
|
||||
*/
|
||||
g_warning ("Could not bind to wl_shell or zwp_fullscreen_shell, video "
|
||||
"display may not work properly.");
|
||||
g_warning ("Could not bind to either wl_shell, xdg_wm_base or "
|
||||
"zwp_fullscreen_shell, video display may not work properly.");
|
||||
}
|
||||
|
||||
self->thread = g_thread_try_new ("GstWlDisplay", gst_wl_display_thread_run,
|
||||
|
|
|
@ -55,6 +55,7 @@ struct _GstWlDisplay
|
|||
struct wl_compositor *compositor;
|
||||
struct wl_subcompositor *subcompositor;
|
||||
struct wl_shell *wl_shell;
|
||||
struct xdg_wm_base *xdg_wm_base;
|
||||
struct zwp_fullscreen_shell_v1 *fullscreen_shell;
|
||||
struct wl_shm *shm;
|
||||
struct wp_viewporter *viewporter;
|
||||
|
|
|
@ -31,10 +31,69 @@
|
|||
GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
|
||||
#define GST_CAT_DEFAULT gstwayland_debug
|
||||
|
||||
enum
|
||||
{
|
||||
CLOSED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT);
|
||||
|
||||
static void gst_wl_window_finalize (GObject * gobject);
|
||||
|
||||
static void
|
||||
handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel)
|
||||
{
|
||||
GstWlWindow *window = data;
|
||||
|
||||
GST_DEBUG ("XDG toplevel got a \"close\" event.");
|
||||
g_signal_emit (window, signals[CLOSED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel,
|
||||
int32_t width, int32_t height, struct wl_array *states)
|
||||
{
|
||||
GstWlWindow *window = data;
|
||||
const uint32_t *state;
|
||||
|
||||
GST_DEBUG ("XDG toplevel got a \"configure\" event, [ %d, %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)
|
||||
return;
|
||||
|
||||
gst_wl_window_set_render_rectangle (window, 0, 0, width, height);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
handle_xdg_toplevel_configure,
|
||||
handle_xdg_toplevel_close,
|
||||
};
|
||||
|
||||
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 void
|
||||
handle_ping (void *data, struct wl_shell_surface *wl_shell_surface,
|
||||
uint32_t serial)
|
||||
|
@ -74,6 +133,9 @@ gst_wl_window_class_init (GstWlWindowClass * klass)
|
|||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
gobject_class->finalize = gst_wl_window_finalize;
|
||||
|
||||
signals[CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -89,6 +151,11 @@ gst_wl_window_finalize (GObject * gobject)
|
|||
if (self->wl_shell_surface)
|
||||
wl_shell_surface_destroy (self->wl_shell_surface);
|
||||
|
||||
if (self->xdg_toplevel)
|
||||
xdg_toplevel_destroy (self->xdg_toplevel);
|
||||
if (self->xdg_surface)
|
||||
xdg_surface_destroy (self->xdg_surface);
|
||||
|
||||
if (self->video_viewport)
|
||||
wp_viewport_destroy (self->video_viewport);
|
||||
|
||||
|
@ -157,12 +224,19 @@ gst_wl_window_ensure_fullscreen (GstWlWindow * window, gboolean fullscreen)
|
|||
if (!window)
|
||||
return;
|
||||
|
||||
if (window->display->xdg_wm_base) {
|
||||
if (fullscreen)
|
||||
xdg_toplevel_set_fullscreen (window->xdg_toplevel, NULL);
|
||||
else
|
||||
xdg_toplevel_unset_fullscreen (window->xdg_toplevel);
|
||||
} else {
|
||||
if (fullscreen)
|
||||
wl_shell_surface_set_fullscreen (window->wl_shell_surface,
|
||||
WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, 0, NULL);
|
||||
else
|
||||
wl_shell_surface_set_toplevel (window->wl_shell_surface);
|
||||
}
|
||||
}
|
||||
|
||||
GstWlWindow *
|
||||
gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info,
|
||||
|
@ -173,28 +247,51 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info,
|
|||
|
||||
window = gst_wl_window_new_internal (display, render_lock);
|
||||
|
||||
if (display->wl_shell) {
|
||||
/* Check which protocol we will use (in order of preference) */
|
||||
if (display->xdg_wm_base) {
|
||||
/* First create the XDG surface */
|
||||
window->xdg_surface = xdg_wm_base_get_xdg_surface (display->xdg_wm_base,
|
||||
window->area_surface);
|
||||
if (!window->xdg_surface) {
|
||||
GST_ERROR ("Unable to get xdg_surface");
|
||||
goto error;
|
||||
}
|
||||
xdg_surface_add_listener (window->xdg_surface, &xdg_surface_listener,
|
||||
window);
|
||||
|
||||
/* Then the toplevel */
|
||||
window->xdg_toplevel = xdg_surface_get_toplevel (window->xdg_surface);
|
||||
if (!window->xdg_toplevel) {
|
||||
GST_ERROR ("Unable to get xdg_toplevel");
|
||||
goto error;
|
||||
}
|
||||
xdg_toplevel_add_listener (window->xdg_toplevel,
|
||||
&xdg_toplevel_listener, window);
|
||||
|
||||
/* Finally, commit the xdg_surface state as toplevel */
|
||||
wl_surface_commit (window->area_surface);
|
||||
|
||||
gst_wl_window_ensure_fullscreen (window, fullscreen);
|
||||
} else if (display->wl_shell) {
|
||||
/* go toplevel */
|
||||
window->wl_shell_surface = wl_shell_get_shell_surface (display->wl_shell,
|
||||
window->area_surface);
|
||||
if (!window->wl_shell_surface) {
|
||||
GST_ERROR ("Unable to get wl_shell_surface");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (window->wl_shell_surface) {
|
||||
wl_shell_surface_add_listener (window->wl_shell_surface,
|
||||
&wl_shell_surface_listener, window);
|
||||
gst_wl_window_ensure_fullscreen (window, fullscreen);
|
||||
} else {
|
||||
GST_ERROR ("Unable to get wl_shell_surface");
|
||||
g_object_unref (window);
|
||||
return NULL;
|
||||
}
|
||||
} else if (display->fullscreen_shell) {
|
||||
zwp_fullscreen_shell_v1_present_surface (display->fullscreen_shell,
|
||||
window->area_surface, ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM,
|
||||
NULL);
|
||||
} else {
|
||||
GST_ERROR ("Unable to use wl_shell or zwp_fullscreen_shell.");
|
||||
g_object_unref (window);
|
||||
return NULL;
|
||||
GST_ERROR ("Unable to use either wl_shell, xdg_wm_base or "
|
||||
"zwp_fullscreen_shell.");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* set the initial size to be the same as the reported video size */
|
||||
|
@ -203,6 +300,10 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info,
|
|||
gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
|
||||
|
||||
return window;
|
||||
|
||||
error:
|
||||
g_object_unref (window);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GstWlWindow *
|
||||
|
|
|
@ -53,6 +53,8 @@ struct _GstWlWindow
|
|||
struct wl_subsurface *video_subsurface;
|
||||
struct wp_viewport *video_viewport;
|
||||
struct wl_shell_surface *wl_shell_surface;
|
||||
struct xdg_surface *xdg_surface;
|
||||
struct xdg_toplevel *xdg_toplevel;
|
||||
|
||||
/* the size and position of the area_(sub)surface */
|
||||
GstVideoRectangle render_rectangle;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
wl_req = '>= 1.4'
|
||||
wl_req = '>= 1.15'
|
||||
wl_client_dep = dependency('wayland-client', version: wl_req, required: get_option('wayland'))
|
||||
libdrm_dep = dependency('libdrm', version: '>= 2.4.55', required: get_option('wayland'))
|
||||
wl_protocol_dep = dependency('wayland-protocols', version: wl_req, required: get_option('wayland'))
|
||||
|
|
Loading…
Reference in a new issue