glwindow: pass display to implementation's _new()
[platform/upstream/gstreamer.git] / gst-libs / gst / gl / wayland / gstglwindow_wayland_egl.c
index 0627198..07beb3d 100644 (file)
 #include "config.h"
 #endif
 
+#include <linux/input.h>
+
 #include "wayland_event_source.h"
 
+#include "../gstgl_fwd.h"
+#include <gst/gl/gstglcontext.h>
+
+#include "gstgldisplay_wayland.h"
 #include "gstglwindow_wayland_egl.h"
 
 const gchar *WlEGLErrorString ();
 
-#define GST_CAT_DEFAULT gst_gl_window_wayland_egl_debug
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+#define GST_CAT_DEFAULT gst_gl_window_debug
 
-#define DEBUG_INIT \
-  GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "glwindow");
 #define gst_gl_window_wayland_egl_parent_class parent_class
-G_DEFINE_TYPE_WITH_CODE (GstGLWindowWaylandEGL, gst_gl_window_wayland_egl,
-    GST_GL_TYPE_WINDOW, DEBUG_INIT);
+G_DEFINE_TYPE (GstGLWindowWaylandEGL, gst_gl_window_wayland_egl,
+    GST_GL_TYPE_WINDOW);
 
-static guintptr gst_gl_window_wayland_egl_get_gl_context (GstGLWindow * window);
-static gboolean gst_gl_window_wayland_egl_activate (GstGLWindow * window,
-    gboolean activate);
+static guintptr gst_gl_window_wayland_egl_get_window_handle (GstGLWindow *
+    window);
 static void gst_gl_window_wayland_egl_set_window_handle (GstGLWindow * window,
     guintptr handle);
-static void gst_gl_window_wayland_egl_draw (GstGLWindow * window, guint width,
-    guint height);
-static void gst_gl_window_wayland_egl_run (GstGLWindow * window);
-static void gst_gl_window_wayland_egl_quit (GstGLWindow * window,
-    GstGLWindowCB callback, gpointer data);
-static void gst_gl_window_wayland_egl_send_message (GstGLWindow * window,
-    GstGLWindowCB callback, gpointer data);
-static void gst_gl_window_wayland_egl_destroy_context (GstGLWindowWaylandEGL *
-    window_egl);
-static gboolean gst_gl_window_wayland_egl_create_context (GstGLWindowWaylandEGL
-    * window_egl, GstGLRendererAPI render_api, guintptr external_gl_context);
-
-static void gst_gl_window_wayland_egl_finalize (GObject * object);
+static void gst_gl_window_wayland_egl_show (GstGLWindow * window);
+static void gst_gl_window_wayland_egl_draw (GstGLWindow * window);
+static void gst_gl_window_wayland_egl_close (GstGLWindow * window);
+static gboolean gst_gl_window_wayland_egl_open (GstGLWindow * window,
+    GError ** error);
+static guintptr gst_gl_window_wayland_egl_get_display (GstGLWindow * window);
+static gboolean gst_gl_window_wayland_egl_set_render_rectangle (GstGLWindow *
+    window, gint x, gint y, gint width, gint height);
+
+#if 0
+static void
+pointer_handle_enter (void *data, struct wl_pointer *pointer, uint32_t serial,
+    struct wl_surface *surface, wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+  GstGLWindowWaylandEGL *window_egl = data;
+  struct wl_buffer *buffer;
+  struct wl_cursor_image *image = NULL;
+
+  window_egl->display.serial = serial;
+
+  if (window_egl->display.default_cursor) {
+    image = window_egl->display.default_cursor->images[0];
+    buffer = wl_cursor_image_get_buffer (image);
+    wl_pointer_set_cursor (pointer, serial,
+        window_egl->display.cursor_surface, image->hotspot_x, image->hotspot_y);
+    wl_surface_attach (window_egl->display.cursor_surface, buffer, 0, 0);
+    wl_surface_damage (window_egl->display.cursor_surface, 0, 0,
+        image->width, image->height);
+    wl_surface_commit (window_egl->display.cursor_surface);
+  }
+}
 
 static void
-handle_ping (void *data, struct wl_shell_surface *shell_surface,
-    uint32_t serial)
+pointer_handle_leave (void *data, struct wl_pointer *pointer, uint32_t serial,
+    struct wl_surface *surface)
 {
-  wl_shell_surface_pong (shell_surface, serial);
+  GstGLWindowWaylandEGL *window_egl = data;
+  window_egl->display.serial = serial;
 }
 
 static void
-handle_configure (void *data, struct wl_shell_surface *shell_surface,
-    uint32_t edges, int32_t width, int32_t height)
+pointer_handle_motion (void *data, struct wl_pointer *pointer, uint32_t time,
+    wl_fixed_t sx_w, wl_fixed_t sy_w)
+{
+  GstGLWindowWaylandEGL *window_egl = data;
+
+  window_egl->display.pointer_x = wl_fixed_to_double (sx_w);
+  window_egl->display.pointer_y = wl_fixed_to_double (sy_w);
+}
+
+enum wl_edges
+{
+  WL_EDGE_NONE = 0,
+  WL_EDGE_TOP = 1,
+  WL_EDGE_BOTTOM = 2,
+  WL_EDGE_LEFT = 4,
+  WL_EDGE_RIGHT = 8,
+};
+
+static guint
+_get_closest_pointer_corner (GstGLWindowWaylandEGL * window_egl)
+{
+  guint edges = 0;
+  gdouble win_width, win_height;
+  gdouble p_x, p_y;
+
+  win_width = (gdouble) window_egl->window.window_width;
+  win_height = (gdouble) window_egl->window.window_height;
+  p_x = window_egl->display.pointer_x;
+  p_y = window_egl->display.pointer_y;
+
+  if (win_width == 0.0 || win_height == 0.0)
+    return WL_EDGE_NONE;
+
+  edges |= win_width / 2.0 - p_x < 0.0 ? WL_EDGE_RIGHT : WL_EDGE_LEFT;
+  edges |= win_height / 2.0 - p_y < 0.0 ? WL_EDGE_BOTTOM : WL_EDGE_TOP;
+
+  return edges;
+}
+
+static void
+pointer_handle_button (void *data, struct wl_pointer *pointer, uint32_t serial,
+    uint32_t time, uint32_t button, uint32_t state_w)
 {
   GstGLWindowWaylandEGL *window_egl = data;
-  struct window window = window_egl->window;
+  guint edges = _get_closest_pointer_corner (window_egl);
+  window_egl->display.serial = serial;
 
-  if (window.native)
-    wl_egl_window_resize (window.native, width, height, 0, 0);
+  if (button == BTN_LEFT && state_w == WL_POINTER_BUTTON_STATE_PRESSED)
+    wl_shell_surface_move (window_egl->window.shell_surface,
+        window_egl->display.seat, serial);
 
-  window.window_width = width;
-  window.window_height = height;
+  if (button == BTN_RIGHT && state_w == WL_POINTER_BUTTON_STATE_PRESSED)
+    wl_shell_surface_resize (window_egl->window.shell_surface,
+        window_egl->display.seat, serial, edges);
 }
 
 static void
-handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
+pointer_handle_axis (void *data, struct wl_pointer *pointer, uint32_t time,
+    uint32_t axis, wl_fixed_t value)
 {
 }
 
-static const struct wl_shell_surface_listener shell_surface_listener = {
-  handle_ping,
-  handle_configure,
-  handle_popup_done
+static const struct wl_pointer_listener pointer_listener = {
+  pointer_handle_enter,
+  pointer_handle_leave,
+  pointer_handle_motion,
+  pointer_handle_button,
+  pointer_handle_axis,
 };
 
-static gboolean
-create_surface (GstGLWindowWaylandEGL * window_egl)
+static void
+seat_handle_capabilities (void *data, struct wl_seat *seat,
+    enum wl_seat_capability caps)
 {
-  struct display display = window_egl->display;
-  struct window window = window_egl->window;
-  EGLBoolean ret;
-
-  window.surface = wl_compositor_create_surface (display.compositor);
-  window.shell_surface = wl_shell_get_shell_surface (display.shell,
-      window.surface);
+  GstGLWindowWaylandEGL *window_egl = data;
+  struct display *display = &window_egl->display;
+
+  if ((caps & WL_SEAT_CAPABILITY_POINTER) && !display->pointer) {
+    display->pointer = wl_seat_get_pointer (seat);
+    wl_pointer_set_user_data (display->pointer, window_egl);
+    wl_pointer_add_listener (display->pointer, &pointer_listener, window_egl);
+  } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && display->pointer) {
+    wl_pointer_destroy (display->pointer);
+    display->pointer = NULL;
+  }
+#if 0
+  if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->keyboard) {
+    input->keyboard = wl_seat_get_keyboard (seat);
+    wl_keyboard_set_user_data (input->keyboard, input);
+    wl_keyboard_add_listener (input->keyboard, &keyboard_listener, input);
+  } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->keyboard) {
+    wl_keyboard_destroy (input->keyboard);
+    input->keyboard = NULL;
+  }
+#endif
+}
 
-  wl_shell_surface_add_listener (window.shell_surface,
-      &shell_surface_listener, window_egl);
+static const struct wl_seat_listener seat_listener = {
+  seat_handle_capabilities,
+};
+#endif
+static void
+handle_ping (void *data, struct wl_shell_surface *shell_surface,
+    uint32_t serial)
+{
+  GstGLWindowWaylandEGL *window_egl = data;
 
-  if (!window.window_width)
-    window.window_width = 320;
-  if (!window.window_height)
-    window.window_height = 240;
+  GST_TRACE_OBJECT (window_egl, "ping received serial %u", serial);
 
-  window.native =
-      wl_egl_window_create (window.surface, window.window_width,
-      window.window_height);
-  window_egl->egl_surface =
-      eglCreateWindowSurface (window_egl->egl_display, window_egl->egl_config,
-      window.native, NULL);
+  wl_shell_surface_pong (shell_surface, serial);
+}
 
-  wl_shell_surface_set_title (window.shell_surface, "OpenGL Renderer");
+static void window_resize (GstGLWindowWaylandEGL * window_egl, guint width,
+    guint height);
 
-  ret =
-      eglMakeCurrent (window_egl->egl_display, window_egl->egl_surface,
-      window_egl->egl_surface, window_egl->egl_context);
+static void
+handle_configure (void *data, struct wl_shell_surface *shell_surface,
+    uint32_t edges, int32_t width, int32_t height)
+{
+  GstGLWindowWaylandEGL *window_egl = data;
 
-  wl_shell_surface_set_toplevel (window.shell_surface);
-  handle_configure (window_egl, window.shell_surface, 0,
-      window_egl->window.window_width, window_egl->window.window_height);
+  GST_DEBUG ("configure event on surface %p, %ix%i", shell_surface, width,
+      height);
 
-  return ret == EGL_TRUE;
+  window_resize (window_egl, width, height);
 }
 
 static void
-destroy_surface (GstGLWindowWaylandEGL * window_egl)
+handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
 {
-  if (window_egl->window.native)
-    wl_egl_window_destroy (window_egl->window.native);
+}
 
-  if (window_egl->window.shell_surface)
-    wl_shell_surface_destroy (window_egl->window.shell_surface);
+static const struct wl_shell_surface_listener shell_surface_listener = {
+  handle_ping,
+  handle_configure,
+  handle_popup_done
+};
 
-  if (window_egl->window.surface)
+static void
+destroy_surfaces (GstGLWindowWaylandEGL * window_egl)
+{
+  if (window_egl->window.subsurface) {
+    wl_subsurface_destroy (window_egl->window.subsurface);
+    window_egl->window.subsurface = NULL;
+  }
+  if (window_egl->window.shell_surface) {
+    wl_shell_surface_destroy (window_egl->window.shell_surface);
+    window_egl->window.shell_surface = NULL;
+  }
+  if (window_egl->window.surface) {
     wl_surface_destroy (window_egl->window.surface);
-
-  if (window_egl->window.callback)
-    wl_callback_destroy (window_egl->window.callback);
+    window_egl->window.surface = NULL;
+  }
+  if (window_egl->window.native) {
+    wl_egl_window_destroy (window_egl->window.native);
+    window_egl->window.native = NULL;
+  }
 }
 
 static void
-registry_handle_global (void *data, struct wl_registry *registry,
-    uint32_t name, const char *interface, uint32_t version)
+create_surfaces (GstGLWindowWaylandEGL * window_egl)
 {
-  struct display *d = data;
-
-  if (g_strcmp0 (interface, "wl_compositor") == 0) {
-    d->compositor =
-        wl_registry_bind (registry, name, &wl_compositor_interface, 1);
-  } else if (g_strcmp0 (interface, "wl_shell") == 0) {
-    d->shell = wl_registry_bind (registry, name, &wl_shell_interface, 1);
-/*  } else if (strcmp(interface, "wl_seat") == 0) {
-    d->seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
-    wl_seat_add_listener(d->seat, &seat_listener, d);
-*/ } else if (g_strcmp0 (interface, "wl_shm") == 0) {
-    d->shm = wl_registry_bind (registry, name, &wl_shm_interface, 1);
-    d->cursor_theme = wl_cursor_theme_load (NULL, 32, d->shm);
-    d->default_cursor =
-        wl_cursor_theme_get_cursor (d->cursor_theme, "left_ptr");
+  GstGLDisplayWayland *display =
+      GST_GL_DISPLAY_WAYLAND (GST_GL_WINDOW (window_egl)->display);
+  gint width, height;
+
+  if (!window_egl->window.surface) {
+    window_egl->window.surface =
+        wl_compositor_create_surface (display->compositor);
+    if (window_egl->window.queue)
+      wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.surface,
+          window_egl->window.queue);
   }
-}
 
-static const struct wl_registry_listener registry_listener = {
-  registry_handle_global
-};
+  if (window_egl->window.foreign_surface) {
+    /* (re)parent */
+    if (!display->subcompositor) {
+      GST_ERROR_OBJECT (window_egl,
+          "Wayland server does not support subsurfaces");
+      window_egl->window.foreign_surface = NULL;
+      goto shell_window;
+    }
+
+    if (!window_egl->window.subsurface) {
+      window_egl->window.subsurface =
+          wl_subcompositor_get_subsurface (display->subcompositor,
+          window_egl->window.surface, window_egl->window.foreign_surface);
+      if (window_egl->window.queue)
+        wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.subsurface,
+            window_egl->window.queue);
+
+      wl_subsurface_set_position (window_egl->window.subsurface,
+          window_egl->window.window_x, window_egl->window.window_y);
+      wl_subsurface_set_desync (window_egl->window.subsurface);
+    }
+  } else {
+  shell_window:
+    if (!window_egl->window.shell_surface) {
+      window_egl->window.shell_surface =
+          wl_shell_get_shell_surface (display->shell,
+          window_egl->window.surface);
+      if (window_egl->window.queue)
+        wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.
+            shell_surface, window_egl->window.queue);
+
+      wl_shell_surface_add_listener (window_egl->window.shell_surface,
+          &shell_surface_listener, window_egl);
+
+      wl_shell_surface_set_title (window_egl->window.shell_surface,
+          "OpenGL Renderer");
+      wl_shell_surface_set_toplevel (window_egl->window.shell_surface);
+    }
+  }
+
+  if (window_egl->window.window_width > 0)
+    width = window_egl->window.window_width;
+  else
+    width = 320;
+  window_egl->window.window_width = width;
+
+  if (window_egl->window.window_height > 0)
+    height = window_egl->window.window_height;
+  else
+    height = 240;
+  window_egl->window.window_height = height;
+
+  if (!window_egl->window.native) {
+    window_egl->window.native =
+        wl_egl_window_create (window_egl->window.surface, width, height);
+    if (window_egl->window.queue)
+      wl_proxy_set_queue ((struct wl_proxy *) window_egl->window.native,
+          window_egl->window.queue);
+  }
+}
 
 static void
 gst_gl_window_wayland_egl_class_init (GstGLWindowWaylandEGLClass * klass)
 {
-  GObjectClass *object_class = (GObjectClass *) klass;
   GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
 
-  window_class->get_gl_context =
-      GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_get_gl_context);
-  window_class->activate =
-      GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_activate);
+  window_class->get_window_handle =
+      GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_get_window_handle);
   window_class->set_window_handle =
       GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_set_window_handle);
   window_class->draw_unlocked =
       GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_draw);
+  window_class->show = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_show);
   window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_draw);
-  window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_run);
-  window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_quit);
-  window_class->send_message =
-      GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_send_message);
-
-  object_class->finalize = gst_gl_window_wayland_egl_finalize;
+  window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_close);
+  window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_open);
+  window_class->get_display =
+      GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_get_display);
+  window_class->set_render_rectangle =
+      GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_set_render_rectangle);
 }
 
 static void
@@ -202,349 +351,213 @@ gst_gl_window_wayland_egl_init (GstGLWindowWaylandEGL * window)
 
 /* Must be called in the gl thread */
 GstGLWindowWaylandEGL *
-gst_gl_window_wayland_egl_new (GstGLRendererAPI render_api,
-    guintptr external_gl_context)
+gst_gl_window_wayland_egl_new (GstGLDisplay * display)
 {
-  GstGLWindowWaylandEGL *window =
-      g_object_new (GST_GL_TYPE_WINDOW_WAYLAND_EGL, NULL);
-
-  gst_gl_window_set_need_lock (GST_GL_WINDOW (window), FALSE);
-
-  window->display.display = wl_display_connect (NULL);
-  g_assert (window->display.display);
-
-  window->display.registry = wl_display_get_registry (window->display.display);
-  wl_registry_add_listener (window->display.registry, &registry_listener,
-      &window->display);
-
-  wl_display_dispatch (window->display.display);
+  if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_WAYLAND)
+      == 0)
+    /* we require a wayland display to create wayland surfaces */
+    return NULL;
 
-//  init_egl(&display, window.opaque);
-  create_surface (window);
-//  init_gl(&window);
+  GST_DEBUG ("creating Wayland EGL window");
 
-  window->display.cursor_surface =
-      wl_compositor_create_surface (window->display.compositor);
-
-  window->wl_source = wayland_event_source_new (window->display.display);
-  window->main_context = g_main_context_new ();
-  window->loop = g_main_loop_new (window->main_context, FALSE);
-
-  g_source_attach (window->wl_source, window->main_context);
-
-  gst_gl_window_wayland_egl_create_context (window, render_api,
-      external_gl_context);
-
-  return window;
+  return g_object_new (GST_GL_TYPE_WINDOW_WAYLAND_EGL, NULL);
 }
 
 static void
-gst_gl_window_wayland_egl_finalize (GObject * object)
+gst_gl_window_wayland_egl_close (GstGLWindow * window)
 {
   GstGLWindowWaylandEGL *window_egl;
 
-  window_egl = GST_GL_WINDOW_WAYLAND_EGL (object);
-
-  gst_gl_window_wayland_egl_destroy_context (window_egl);
-//  fini_egl(&display);
-
-  wl_surface_destroy (window_egl->display.cursor_surface);
-  if (window_egl->display.cursor_theme)
-    wl_cursor_theme_destroy (window_egl->display.cursor_theme);
-
-  if (window_egl->display.shell)
-    wl_shell_destroy (window_egl->display.shell);
+  window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
 
-  if (window_egl->display.compositor)
-    wl_compositor_destroy (window_egl->display.compositor);
+  destroy_surfaces (window_egl);
 
-  wl_display_flush (window_egl->display.display);
-  wl_display_disconnect (window_egl->display.display);
+  g_source_destroy (window_egl->wl_source);
+  g_source_unref (window_egl->wl_source);
+  window_egl->wl_source = NULL;
 
-  G_OBJECT_CLASS (parent_class)->finalize (object);
+  GST_GL_WINDOW_CLASS (parent_class)->close (window);
 }
 
 static gboolean
-gst_gl_window_wayland_egl_create_context (GstGLWindowWaylandEGL * window_egl,
-    GstGLRendererAPI render_api, guintptr external_gl_context)
+gst_gl_window_wayland_egl_open (GstGLWindow * window, GError ** error)
 {
-  EGLint config_attrib[] = {
-    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-    EGL_RED_SIZE, 1,
-    EGL_GREEN_SIZE, 1,
-    EGL_BLUE_SIZE, 1,
-    EGL_ALPHA_SIZE, 1,
-    EGL_DEPTH_SIZE, 1,
-    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-    EGL_NONE
-  };
-
-  EGLint context_attrib[] = {
-    EGL_CONTEXT_CLIENT_VERSION, 2,
-    EGL_NONE
-  };
-
-  EGLint majorVersion;
-  EGLint minorVersion;
-  EGLint numConfigs;
-
-  window_egl->egl_display =
-      eglGetDisplay ((EGLNativeDisplayType) window_egl->display.display);
-
-  if (eglInitialize (window_egl->egl_display, &majorVersion, &minorVersion))
-    GST_DEBUG ("egl initialized: %d.%d", majorVersion, minorVersion);
-  else {
-    GST_DEBUG ("failed to initialize egl %ld, %s",
-        (gulong) window_egl->egl_display, WlEGLErrorString ());
-    goto failure;
-  }
-
-  if (!eglBindAPI (EGL_OPENGL_ES_API)) {
-    GST_WARNING ("failed to bind OpenGL|ES API");
-    goto failure;
-  }
+  GstGLDisplayWayland *display = GST_GL_DISPLAY_WAYLAND (window->display);
+  GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
 
-  if (eglChooseConfig (window_egl->egl_display, config_attrib,
-          &window_egl->egl_config, 1, &numConfigs))
-    GST_DEBUG ("config set: %ld, %ld", (gulong) window_egl->egl_config,
-        (gulong) numConfigs);
-  else {
-    GST_DEBUG ("failed to set config %ld, %s", (gulong) window_egl->egl_display,
-        WlEGLErrorString ());
-    goto failure;
+  if (!display->display) {
+    g_set_error (error, GST_GL_WINDOW_ERROR,
+        GST_GL_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
+        "Failed to retrieve Wayland display");
+    return FALSE;
   }
 
-  GST_DEBUG ("about to create gl context");
+  window_egl->window.queue = wl_display_create_queue (display->display);
 
-  window_egl->egl_context =
-      eglCreateContext (window_egl->egl_display, window_egl->egl_config,
-      (EGLContext) external_gl_context, context_attrib);
+  window_egl->wl_source = wayland_event_source_new (display->display,
+      window_egl->window.queue);
 
-  if (window_egl->egl_context != EGL_NO_CONTEXT)
-    GST_DEBUG ("gl context created: %ld", (gulong) window_egl->egl_context);
-  else {
-    GST_DEBUG ("failed to create glcontext %ld, %ld, %s",
-        (gulong) window_egl->egl_context, (gulong) window_egl->egl_display,
-        WlEGLErrorString ());
-    goto failure;
-  }
+  if (!GST_GL_WINDOW_CLASS (parent_class)->open (window, error))
+    return FALSE;
 
-  create_surface (window_egl);
-/*  window_egl->egl_surface =
-      eglCreateWindowSurface (window_egl->egl_display, window_egl->config,
-      (EGLNativeWindowType) window_wayland_egl->internal_win_id, NULL);
-  if (window_egl->egl_surface != EGL_NO_SURFACE)
-    GST_DEBUG ("surface created: %ld", (gulong) window_egl->egl_surface);
-  else {
-    GST_DEBUG ("failed to create surface %ld, %ld, %ld, %s",
-        (gulong) window_egl->egl_display, (gulong) window_egl->egl_surface,
-        (gulong) window_egl->egl_display, WlEGLErrorString ());
-    goto failure;
-  }
-*/
+  g_source_attach (window_egl->wl_source, g_main_context_get_thread_default ());
 
   return TRUE;
-
-failure:
-  return FALSE;
 }
 
-static void
-gst_gl_window_wayland_egl_destroy_context (GstGLWindowWaylandEGL * window_egl)
+void
+gst_gl_window_wayland_egl_create_window (GstGLWindowWaylandEGL * window_egl)
 {
-  destroy_surface (window_egl);
-
-  if (window_egl->egl_context)
-    eglDestroyContext (window_egl->egl_display, window_egl->egl_context);
-
-  if (window_egl->egl_display) {
-    eglTerminate (window_egl->egl_display);
-    eglReleaseThread ();
-  }
-}
-
-static gboolean
-gst_gl_window_wayland_egl_activate (GstGLWindow * window, gboolean activate)
-{
-  gboolean result;
-  GstGLWindowWaylandEGL *window_egl;
-
-  window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
-
-  GST_DEBUG ("activate:%s", activate ? "TRUE" : "FALSE");
-
-  if (activate)
-    result = eglMakeCurrent (window_egl->egl_display, window_egl->egl_surface,
-        window_egl->egl_surface, window_egl->egl_context);
-  else
-    result = eglMakeCurrent (window_egl->egl_display, EGL_NO_SURFACE,
-        EGL_NO_SURFACE, EGL_NO_CONTEXT);
-
-  return result;
+  create_surfaces (window_egl);
 }
 
 static guintptr
-gst_gl_window_wayland_egl_get_gl_context (GstGLWindow * window)
+gst_gl_window_wayland_egl_get_window_handle (GstGLWindow * window)
 {
-  return (guintptr) GST_GL_WINDOW_WAYLAND_EGL (window)->egl_context;
+  return (guintptr) GST_GL_WINDOW_WAYLAND_EGL (window)->window.native;
 }
 
 static void
-gst_gl_window_wayland_egl_swap_buffers (GstGLWindow * window)
+gst_gl_window_wayland_egl_set_window_handle (GstGLWindow * window,
+    guintptr handle)
 {
   GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
+  struct wl_surface *surface = (struct wl_surface *) handle;
+
+  /* already set the NULL handle */
+  if (surface == NULL && window_egl->window.foreign_surface == NULL)
+    return;
 
-  eglSwapBuffers (window_egl->egl_display, window_egl->egl_surface);
+  /* unparent */
+  destroy_surfaces (window_egl);
+  window_egl->window.foreign_surface = surface;
+  create_surfaces (window_egl);
 }
 
 static void
-gst_gl_window_wayland_egl_run (GstGLWindow * window)
+gst_gl_window_wayland_egl_show (GstGLWindow * window)
 {
-  GstGLWindowWaylandEGL *window_egl;
+  GstGLDisplayWayland *display_wayland =
+      GST_GL_DISPLAY_WAYLAND (window->display);
+  GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
 
-  window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
+  create_surfaces (window_egl);
 
-  GST_LOG ("starting main loop");
-  g_main_loop_run (window_egl->loop);
-  GST_LOG ("exiting main loop");
+  if (gst_gl_wl_display_roundtrip_queue (display_wayland->display,
+          window_egl->window.queue) < 0)
+    GST_WARNING_OBJECT (window, "failed a roundtrip");
 }
 
 static void
-gst_gl_window_wayland_egl_quit (GstGLWindow * window, GstGLWindowCB callback,
-    gpointer data)
+window_resize (GstGLWindowWaylandEGL * window_egl, guint width, guint height)
 {
-  GstGLWindowWaylandEGL *window_egl;
-
-  window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
+  GstGLWindow *window = GST_GL_WINDOW (window_egl);
 
-  gst_gl_window_wayland_egl_send_message (window, callback, data);
+  GST_DEBUG ("resizing window from %ux%u to %ux%u",
+      window_egl->window.window_width, window_egl->window.window_height, width,
+      height);
 
-  GST_LOG ("sending quit");
+  if (window_egl->window.native) {
+    wl_egl_window_resize (window_egl->window.native, width, height, 0, 0);
+  }
 
-  g_main_loop_quit (window_egl->loop);
+  if (window->resize)
+    window->resize (window->resize_data, width, height);
 
-  GST_LOG ("quit sent");
+  window_egl->window.window_width = width;
+  window_egl->window.window_height = height;
 }
 
-typedef struct _GstGLMessage
-{
-  GMutex lock;
-  GCond cond;
-  gboolean fired;
-
-  GstGLWindowCB callback;
-  gpointer data;
-} GstGLMessage;
-
-static gboolean
-_run_message (GstGLMessage * message)
+static void
+draw_cb (gpointer data)
 {
-  g_mutex_lock (&message->lock);
-
-  if (message->callback)
-    message->callback (message->data);
-
-  message->fired = TRUE;
-  g_cond_signal (&message->cond);
-  g_mutex_unlock (&message->lock);
+  GstGLWindowWaylandEGL *window_egl = data;
+  GstGLWindow *window = GST_GL_WINDOW (window_egl);
+  GstGLContext *context = gst_gl_window_get_context (window);
+  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
 
-  return FALSE;
-}
+  create_surfaces (window_egl);
 
-static void
-gst_gl_window_wayland_egl_send_message (GstGLWindow * window,
-    GstGLWindowCB callback, gpointer data)
-{
-  GstGLWindowWaylandEGL *window_egl;
-  GstGLMessage message;
+  if (window_egl->window.subsurface)
+    wl_subsurface_set_desync (window_egl->window.subsurface);
 
-  window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
-  message.callback = callback;
-  message.data = data;
-  message.fired = FALSE;
-  g_mutex_init (&message.lock);
-  g_cond_init (&message.cond);
+  if (window->draw)
+    window->draw (window->draw_data);
 
-  g_mutex_lock (&message.lock);
+  context_class->swap_buffers (context);
 
-  g_main_context_invoke (window_egl->main_context, (GSourceFunc) _run_message,
-      &message);
+  if (window_egl->window.subsurface)
+    wl_subsurface_set_desync (window_egl->window.subsurface);
 
-  while (!message.fired)
-    g_cond_wait (&message.cond, &message.lock);
-  g_mutex_unlock (&message.lock);
+  gst_object_unref (context);
 }
 
 static void
-gst_gl_window_wayland_egl_set_window_handle (GstGLWindow * window,
-    guintptr handle)
+gst_gl_window_wayland_egl_draw (GstGLWindow * window)
 {
+  gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, window);
 }
 
-struct draw
+struct SetRenderRectangle
 {
-  GstGLWindowWaylandEGL *window;
-  guint width, height;
+  GstGLWindowWaylandEGL *window_egl;
+  GstVideoRectangle rect;
 };
 
 static void
-draw_cb (gpointer data)
+_free_set_render_rectangle (struct SetRenderRectangle *render)
+{
+  if (render) {
+    if (render->window_egl)
+      gst_object_unref (render->window_egl);
+    g_free (render);
+  }
+}
+
+static void
+_set_render_rectangle (gpointer data)
 {
-  struct draw *draw_data = data;
-  GstGLWindow *window = GST_GL_WINDOW (draw_data->window);
+  struct SetRenderRectangle *render = data;
 
-  if (window->draw)
-    window->draw (window->draw_data);
+  GST_LOG_OBJECT (render->window_egl, "setting render rectangle %i,%i+%ix%i",
+      render->rect.x, render->rect.y, render->rect.w, render->rect.h);
 
-  gst_gl_window_wayland_egl_swap_buffers (window);
+  if (render->window_egl->window.subsurface) {
+    wl_subsurface_set_sync (render->window_egl->window.subsurface);
+    wl_subsurface_set_position (render->window_egl->window.subsurface,
+        render->rect.x, render->rect.y);
+    render->window_egl->window.window_x = render->rect.x;
+    render->window_egl->window.window_y = render->rect.y;
+  }
+
+  window_resize (render->window_egl, render->rect.w, render->rect.h);
 }
 
-static void
-gst_gl_window_wayland_egl_draw (GstGLWindow * window, guint width, guint height)
+static gboolean
+gst_gl_window_wayland_egl_set_render_rectangle (GstGLWindow * window,
+    gint x, gint y, gint width, gint height)
 {
-  struct draw draw_data;
+  GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window);
+  struct SetRenderRectangle *render;
 
-  draw_data.window = GST_GL_WINDOW_WAYLAND_EGL (window);
-  draw_data.width = width;
-  draw_data.height = height;
+  render = g_new0 (struct SetRenderRectangle, 1);
+  render->window_egl = gst_object_ref (window_egl);
+  render->rect.x = x;
+  render->rect.y = y;
+  render->rect.w = width;
+  render->rect.h = height;
 
-  gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, &draw_data);
+  gst_gl_window_send_message_async (window,
+      (GstGLWindowCB) _set_render_rectangle, render,
+      (GDestroyNotify) _free_set_render_rectangle);
+
+  return TRUE;
 }
 
-const gchar *
-WlEGLErrorString ()
+static guintptr
+gst_gl_window_wayland_egl_get_display (GstGLWindow * window)
 {
-  EGLint nErr = eglGetError ();
-  switch (nErr) {
-    case EGL_SUCCESS:
-      return "EGL_SUCCESS";
-    case EGL_BAD_DISPLAY:
-      return "EGL_BAD_DISPLAY";
-    case EGL_NOT_INITIALIZED:
-      return "EGL_NOT_INITIALIZED";
-    case EGL_BAD_ACCESS:
-      return "EGL_BAD_ACCESS";
-    case EGL_BAD_ALLOC:
-      return "EGL_BAD_ALLOC";
-    case EGL_BAD_ATTRIBUTE:
-      return "EGL_BAD_ATTRIBUTE";
-    case EGL_BAD_CONFIG:
-      return "EGL_BAD_CONFIG";
-    case EGL_BAD_CONTEXT:
-      return "EGL_BAD_CONTEXT";
-    case EGL_BAD_CURRENT_SURFACE:
-      return "EGL_BAD_CURRENT_SURFACE";
-    case EGL_BAD_MATCH:
-      return "EGL_BAD_MATCH";
-    case EGL_BAD_NATIVE_PIXMAP:
-      return "EGL_BAD_NATIVE_PIXMAP";
-    case EGL_BAD_NATIVE_WINDOW:
-      return "EGL_BAD_NATIVE_WINDOW";
-    case EGL_BAD_PARAMETER:
-      return "EGL_BAD_PARAMETER";
-    case EGL_BAD_SURFACE:
-      return "EGL_BAD_SURFACE";
-    default:
-      return "unknown";
-  }
+  GstGLDisplayWayland *display = GST_GL_DISPLAY_WAYLAND (window->display);
+
+  return (guintptr) display->display;
 }