/* GStreamer Wayland video sink * * Copyright (C) 2011 Intel Corporation * Copyright (C) 2011 Sreerenj Balachandran * Copyright (C) 2014 Collabora Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include #endif #include "wlwindow.h" GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); #define GST_CAT_DEFAULT gstwayland_debug G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT); static void gst_wl_window_finalize (GObject * gobject); static void handle_ping (void *data, struct wl_shell_surface *shell_surface, uint32_t serial) { wl_shell_surface_pong (shell_surface, serial); } static void handle_configure (void *data, struct wl_shell_surface *shell_surface, uint32_t edges, int32_t width, int32_t height) { } static void handle_popup_done (void *data, struct wl_shell_surface *shell_surface) { } static const struct wl_shell_surface_listener shell_surface_listener = { handle_ping, handle_configure, handle_popup_done }; static void gst_wl_window_class_init (GstWlWindowClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = gst_wl_window_finalize; } static void gst_wl_window_init (GstWlWindow * self) { } static void gst_wl_window_finalize (GObject * gobject) { GstWlWindow *self = GST_WL_WINDOW (gobject); if (self->shell_surface) { wl_shell_surface_destroy (self->shell_surface); } if (self->subsurface) { wl_subsurface_destroy (self->subsurface); } wl_viewport_destroy (self->viewport); wl_surface_destroy (self->surface); g_clear_object (&self->display); G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject); } static GstWlWindow * gst_wl_window_new_internal (GstWlDisplay * display, struct wl_surface *surface) { GstWlWindow *window; struct wl_region *region; g_return_val_if_fail (surface != NULL, NULL); window = g_object_new (GST_TYPE_WL_WINDOW, NULL); window->display = g_object_ref (display); window->surface = surface; /* make sure the surface runs on our local queue */ wl_proxy_set_queue ((struct wl_proxy *) surface, display->queue); window->viewport = wl_scaler_get_viewport (display->scaler, window->surface); /* do not accept input */ region = wl_compositor_create_region (display->compositor); wl_surface_set_input_region (surface, region); wl_region_destroy (region); return window; } GstWlWindow * gst_wl_window_new_toplevel (GstWlDisplay * display, GstVideoInfo * video_info) { GstWlWindow *window; window = gst_wl_window_new_internal (display, wl_compositor_create_surface (display->compositor)); gst_wl_window_set_video_info (window, video_info); gst_wl_window_set_render_rectangle (window, 0, 0, window->video_width, window->video_height); window->shell_surface = wl_shell_get_shell_surface (display->shell, window->surface); if (window->shell_surface) { wl_shell_surface_add_listener (window->shell_surface, &shell_surface_listener, window); wl_shell_surface_set_toplevel (window->shell_surface); } else { GST_ERROR ("Unable to get wl_shell_surface"); g_object_unref (window); return NULL; } return window; } GstWlWindow * gst_wl_window_new_in_surface (GstWlDisplay * display, struct wl_surface * parent) { GstWlWindow *window; window = gst_wl_window_new_internal (display, wl_compositor_create_surface (display->compositor)); window->subsurface = wl_subcompositor_get_subsurface (display->subcompositor, window->surface, parent); wl_subsurface_set_desync (window->subsurface); return window; } GstWlDisplay * gst_wl_window_get_display (GstWlWindow * window) { g_return_val_if_fail (window != NULL, NULL); return g_object_ref (window->display); } struct wl_surface * gst_wl_window_get_wl_surface (GstWlWindow * window) { g_return_val_if_fail (window != NULL, NULL); return window->surface; } gboolean gst_wl_window_is_toplevel (GstWlWindow * window) { g_return_val_if_fail (window != NULL, FALSE); return (window->shell_surface != NULL); } static void gst_wl_window_resize_internal (GstWlWindow * window) { GstVideoRectangle src, res; src.w = window->video_width; src.h = window->video_height; gst_video_sink_center_rect (src, window->render_rectangle, &res, TRUE); if (window->subsurface) wl_subsurface_set_position (window->subsurface, window->render_rectangle.x + res.x, window->render_rectangle.y + res.y); wl_viewport_set_destination (window->viewport, res.w, res.h); wl_surface_damage (window->surface, 0, 0, res.w, res.h); wl_surface_commit (window->surface); /* this is saved for use in wl_surface_damage */ window->surface_width = res.w; window->surface_height = res.h; } void gst_wl_window_set_video_info (GstWlWindow * window, GstVideoInfo * info) { g_return_if_fail (window != NULL); window->video_width = gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); window->video_height = info->height; if (window->render_rectangle.w != 0) gst_wl_window_resize_internal (window); } void gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y, gint w, gint h) { g_return_if_fail (window != NULL); window->render_rectangle.x = x; window->render_rectangle.y = y; window->render_rectangle.w = w; window->render_rectangle.h = h; if (window->video_width != 0) gst_wl_window_resize_internal (window); }