summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiels De Graef <niels.degraef@barco.com>2019-03-01 09:56:24 +0100
committerNiels De Graef <nielsdegraef@gmail.com>2019-03-04 10:58:54 +0000
commit67bb17e4fae76f8f662fdd69bba6cdaaf37a90fa (patch)
tree4db52e5703fdf86981c9a7ba4b84aaaebc1f2a83
parentc461f22befeae020b4411907164925a4250b583f (diff)
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]: https://github.com/wayland-project/wayland/commit/698dde195837f3d0844b2725ba4ea8ce9ee7518c [XML spec]: https://github.com/wayland-project/wayland-protocols/blob/master/stable/xdg-shell/xdg-shell.xml
-rw-r--r--configure.ac2
-rw-r--r--ext/wayland/Makefile.am7
-rw-r--r--ext/wayland/gstwaylandsink.c12
-rw-r--r--ext/wayland/meson.build3
-rw-r--r--ext/wayland/wldisplay.c26
-rw-r--r--ext/wayland/wldisplay.h1
-rw-r--r--ext/wayland/wlwindow.c135
-rw-r--r--ext/wayland/wlwindow.h2
-rw-r--r--gst-libs/gst/wayland/meson.build2
9 files changed, 164 insertions, 26 deletions
diff --git a/configure.ac b/configure.ac
index 90a5bc25c..68a144d8a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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`)
diff --git a/ext/wayland/Makefile.am b/ext/wayland/Makefile.am
index a7fcc3278..95bb97e7f 100644
--- a/ext/wayland/Makefile.am
+++ b/ext/wayland/Makefile.am
@@ -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) \
diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c
index 158c9af88..78dd294a0 100644
--- a/ext/wayland/gstwaylandsink.c
+++ b/ext/wayland/gstwaylandsink.c
@@ -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);
}
}
diff --git a/ext/wayland/meson.build b/ext/wayland/meson.build
index 3246cae9b..fa6fbf42f 100644
--- a/ext/wayland/meson.build
+++ b/ext/wayland/meson.build
@@ -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 = []
diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c
index 079901979..940009556 100644
--- a/ext/wayland/wldisplay.c
+++ b/ext/wayland/wldisplay.c
@@ -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);
@@ -187,6 +190,17 @@ gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display,
}
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,
diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h
index 020ed6ea3..4ecc0d659 100644
--- a/ext/wayland/wldisplay.h
+++ b/ext/wayland/wldisplay.h
@@ -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;
diff --git a/ext/wayland/wlwindow.c b/ext/wayland/wlwindow.c
index 547917baa..afb598878 100644
--- a/ext/wayland/wlwindow.c
+++ b/ext/wayland/wlwindow.c
@@ -31,11 +31,70 @@
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,11 +224,18 @@ gst_wl_window_ensure_fullscreen (GstWlWindow * window, gboolean fullscreen)
if (!window)
return;
- 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);
+ 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 *
@@ -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) {
- wl_shell_surface_add_listener (window->wl_shell_surface,
- &wl_shell_surface_listener, window);
- gst_wl_window_ensure_fullscreen (window, fullscreen);
- } else {
+ if (!window->wl_shell_surface) {
GST_ERROR ("Unable to get wl_shell_surface");
- g_object_unref (window);
- return NULL;
+ goto error;
}
+
+ wl_shell_surface_add_listener (window->wl_shell_surface,
+ &wl_shell_surface_listener, window);
+ gst_wl_window_ensure_fullscreen (window, fullscreen);
} 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 *
diff --git a/ext/wayland/wlwindow.h b/ext/wayland/wlwindow.h
index ce2fa939a..861e324ad 100644
--- a/ext/wayland/wlwindow.h
+++ b/ext/wayland/wlwindow.h
@@ -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;
diff --git a/gst-libs/gst/wayland/meson.build b/gst-libs/gst/wayland/meson.build
index 8bfefcb3b..b1ede41f1 100644
--- a/gst-libs/gst/wayland/meson.build
+++ b/gst-libs/gst/wayland/meson.build
@@ -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'))