From 78fdb1abc730d97e5937ee3414779b9bbdff0413 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Fri, 5 Mar 2021 10:15:51 +0800 Subject: [PATCH 19/43] waylandsink: Support window layer property Support setting top|normal|bottom window layer. Tested with: gst-launch-1.0 videotestsrc ! waylandsink layer=top Signed-off-by: Jeffy Chen --- ext/wayland/gstwaylandsink.c | 52 ++++++++++++++++++++++++++++-- ext/wayland/gstwaylandsink.h | 1 + gst-libs/gst/wayland/gstwlwindow.c | 40 ++++++++++++++++++++++- gst-libs/gst/wayland/gstwlwindow.h | 15 +++++++-- 4 files changed, 103 insertions(+), 5 deletions(-) diff --git a/ext/wayland/gstwaylandsink.c b/ext/wayland/gstwaylandsink.c index 071bc5a..f492d72 100644 --- a/ext/wayland/gstwaylandsink.c +++ b/ext/wayland/gstwaylandsink.c @@ -61,6 +61,7 @@ enum PROP_DISPLAY, PROP_FULLSCREEN, PROP_ROTATE_METHOD, + PROP_LAYER, PROP_LAST }; @@ -116,6 +117,24 @@ G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK, GST_ELEMENT_REGISTER_DEFINE (waylandsink, "waylandsink", GST_RANK_MARGINAL, GST_TYPE_WAYLAND_SINK); +#define GST_TYPE_WL_WINDOW_LAYER (gst_wl_window_layer_get_type ()) +static GType +gst_wl_window_layer_get_type (void) +{ + static GType layer = 0; + + if (!layer) { + static const GEnumValue layers[] = { + {GST_WL_WINDOW_LAYER_TOP, "Top", "top"}, + {GST_WL_WINDOW_LAYER_NORMAL, "Normal", "normal"}, + {GST_WL_WINDOW_LAYER_BOTTOM, "Bottom", "bottom"}, + {0, NULL, NULL} + }; + layer = g_enum_register_static ("GstWlWindowLayer", layers); + } + return layer; +} + static void gst_wayland_sink_class_init (GstWaylandSinkClass * klass) { @@ -177,6 +196,12 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) GST_TYPE_VIDEO_ORIENTATION_METHOD, GST_VIDEO_ORIENTATION_IDENTITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_LAYER, + g_param_spec_enum ("layer", "Window layer", + "Wayland window layer", + GST_TYPE_WL_WINDOW_LAYER, GST_WL_WINDOW_LAYER_NORMAL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** * waylandsink:render-rectangle: * @@ -195,6 +220,7 @@ gst_wayland_sink_init (GstWaylandSink * self) g_mutex_init (&self->render_lock); self->window_handle = 1; + self->layer = GST_WL_WINDOW_LAYER_NORMAL; } static void @@ -246,6 +272,18 @@ gst_wayland_sink_set_rotate_method (GstWaylandSink * self, GST_OBJECT_UNLOCK (self); } +static void +gst_wayland_sink_set_layer (GstWaylandSink * self, GstWlWindowLayer layer) +{ + if (layer == self->layer) + return; + + g_mutex_lock (&self->render_lock); + self->layer = layer; + gst_wl_window_ensure_layer (self->window, layer); + g_mutex_unlock (&self->render_lock); +} + static void gst_wayland_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -268,6 +306,11 @@ gst_wayland_sink_get_property (GObject * object, g_value_set_enum (value, self->current_rotate_method); GST_OBJECT_UNLOCK (self); break; + case PROP_LAYER: + GST_OBJECT_LOCK (self); + g_value_set_enum (value, self->layer); + GST_OBJECT_UNLOCK (self); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -295,6 +338,11 @@ gst_wayland_sink_set_property (GObject * object, gst_wayland_sink_set_rotate_method (self, g_value_get_enum (value), FALSE); break; + case PROP_LAYER: + GST_OBJECT_LOCK (self); + gst_wayland_sink_set_layer (self, g_value_get_enum (value)); + GST_OBJECT_UNLOCK (self); + break; default: if (!gst_video_overlay_set_property (object, PROP_LAST, prop_id, value)) G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -773,8 +821,8 @@ gst_wayland_sink_show_frame (GstVideoSink * vsink, GstBuffer * buffer) if (!self->window) { /* if we were not provided a window, create one ourselves */ self->window = gst_wl_window_new_toplevel (self->display, - &self->video_info, self->fullscreen, &self->render_lock, - &self->render_rectangle); + &self->video_info, self->fullscreen, self->layer, + &self->render_lock, &self->render_rectangle); g_signal_connect_object (self->window, "closed", G_CALLBACK (on_window_closed), self, 0); gst_wl_window_set_rotate_method (self->window, diff --git a/ext/wayland/gstwaylandsink.h b/ext/wayland/gstwaylandsink.h index d4c3764..a417788 100644 --- a/ext/wayland/gstwaylandsink.h +++ b/ext/wayland/gstwaylandsink.h @@ -57,6 +57,7 @@ struct _GstWaylandSink gboolean video_info_changed; GstVideoInfo video_info; gboolean fullscreen; + GstWlWindowLayer layer; gchar *display_name; diff --git a/gst-libs/gst/wayland/gstwlwindow.c b/gst-libs/gst/wayland/gstwlwindow.c index dd6e1c2..7a3016c 100644 --- a/gst-libs/gst/wayland/gstwlwindow.c +++ b/gst-libs/gst/wayland/gstwlwindow.c @@ -252,6 +252,43 @@ gst_wl_window_new_internal (GstWlDisplay * display, GMutex * render_lock) return self; } +static void +gst_wl_window_set_config (GstWlWindow * self, const char *config) +{ + GstWlWindowPrivate *priv; + + /* TODO: support non-toplevel */ + if (!self || !gst_wl_window_is_toplevel (self)) + return; + + priv = gst_wl_window_get_instance_private (self); + + /* HACK: set window config through title */ + xdg_toplevel_set_title (priv->xdg_toplevel, config); +} + +void +gst_wl_window_ensure_layer (GstWlWindow * self, GstWlWindowLayer layer) +{ + char s[128] = "flags="; + + switch (layer) { + case GST_WL_WINDOW_LAYER_TOP: + strcat (s, "stay-on-top|-stay-on-bottom"); + break; + case GST_WL_WINDOW_LAYER_NORMAL: + strcat (s, "-stay-on-top|-stay-on-bottom"); + break; + case GST_WL_WINDOW_LAYER_BOTTOM: + strcat (s, "-stay-on-top|stay-on-bottom"); + break; + default: + return; + } + + gst_wl_window_set_config (self, s); +} + void gst_wl_window_ensure_fullscreen (GstWlWindow * self, gboolean fullscreen) { @@ -269,7 +306,7 @@ gst_wl_window_ensure_fullscreen (GstWlWindow * self, gboolean fullscreen) GstWlWindow * gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, - gboolean fullscreen, GMutex * render_lock, + gboolean fullscreen, GstWlWindowLayer layer, GMutex * render_lock, GstVideoRectangle * render_rectangle) { GstWlWindow *self; @@ -306,6 +343,7 @@ gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info, &xdg_toplevel_listener, self); gst_wl_window_ensure_fullscreen (self, fullscreen); + gst_wl_window_ensure_layer (self, layer); /* Finally, commit the xdg_surface state as toplevel */ priv->configured = FALSE; diff --git a/gst-libs/gst/wayland/gstwlwindow.h b/gst-libs/gst/wayland/gstwlwindow.h index 2bbd643..a0b05c3 100644 --- a/gst-libs/gst/wayland/gstwlwindow.h +++ b/gst-libs/gst/wayland/gstwlwindow.h @@ -28,19 +28,30 @@ G_BEGIN_DECLS #define GST_TYPE_WL_WINDOW (gst_wl_window_get_type ()) G_DECLARE_FINAL_TYPE (GstWlWindow, gst_wl_window, GST, WL_WINDOW, GObject); +typedef enum +{ + GST_WL_WINDOW_LAYER_TOP = 0, + GST_WL_WINDOW_LAYER_NORMAL = 1, + GST_WL_WINDOW_LAYER_BOTTOM = 2, +} GstWlWindowLayer; + struct _GstWlWindow { GObject parent_instance; }; +GST_WL_API +void gst_wl_window_ensure_layer (GstWlWindow * self, + GstWlWindowLayer layer); + GST_WL_API void gst_wl_window_ensure_fullscreen (GstWlWindow * self, gboolean fullscreen); GST_WL_API GstWlWindow *gst_wl_window_new_toplevel (GstWlDisplay * display, - const GstVideoInfo * info, gboolean fullscreen, GMutex * render_lock, - GstVideoRectangle * render_rectangle); + const GstVideoInfo * info, gboolean fullscreen, GstWlWindowLayer layer, + GMutex * render_lock, GstVideoRectangle * render_rectangle); GST_WL_API GstWlWindow *gst_wl_window_new_in_surface (GstWlDisplay * display, -- 2.20.1