/**
 * gst_gl_window_get_context:
 * @window: a #GstGLWindow
 *
 * Returns: (transfer full): the #GstGLContext associated with this @window
 */
GstGLContext *
gst_gl_window_get_context (GstGLWindow * window)
{
  g_return_val_if_fail (GST_GL_IS_WINDOW (window), NULL);

  return (GstGLContext *) g_weak_ref_get (&window->context_ref);
}
/**
 * gst_gl_window_get_window_handle:
 * @window: a #GstGLWindow
 *
 * Returns: the window handle we are currently rendering into
 */
guintptr
gst_gl_window_get_window_handle (GstGLWindow * window)
{
  GstGLWindowClass *window_class;

  g_return_val_if_fail (GST_GL_IS_WINDOW (window), 0);
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_val_if_fail (window_class->get_window_handle != NULL, 0);

  return window_class->get_window_handle (window);
}
/**
 * gst_gl_window_draw_unlocked:
 * @window: a #GstGLWindow
 * @width: requested width of the window
 * @height: requested height of the window
 *
 * Redraw the window contents.  Implementations should invoke the draw callback.
 */
void
gst_gl_window_draw_unlocked (GstGLWindow * window, guint width, guint height)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->draw_unlocked != NULL);

  window_class->draw_unlocked (window, width, height);
}
/**
 * gst_gl_window_run:
 * @window: a #GstGLWindow
 *
 * Start the execution of the runloop.
 */
void
gst_gl_window_run (GstGLWindow * window)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->run != NULL);

  window->priv->alive = TRUE;
  window_class->run (window);
}
/**
 * gst_gl_window_set_window_handle:
 * @window: a #GstGLWindow
 * @handle: handle to the window
 *
 * Sets the window that this @window should render into.  Some implementations
 * require this to be called with a valid handle before drawing can commence.
 */
void
gst_gl_window_set_window_handle (GstGLWindow * window, guintptr handle)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  g_return_if_fail (handle != 0);
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->set_window_handle != NULL);

  window_class->set_window_handle (window, handle);
}
/**
 * gst_gl_window_send_message_async:
 * @window: a #GstGLWindow
 * @callback: (scope async): function to invoke
 * @data: (closure): data to invoke @callback with
 * @destroy: (destroy): called when @data is not needed anymore
 *
 * Invoke @callback with @data on the window thread.  The callback may not
 * have been executed when this function returns.
 */
void
gst_gl_window_send_message_async (GstGLWindow * window, GstGLWindowCB callback,
    gpointer data, GDestroyNotify destroy)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  g_return_if_fail (callback != NULL);
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->send_message_async != NULL);

  window_class->send_message_async (window, callback, data, destroy);
}
/**
 * gst_gl_window_send_message:
 * @window: a #GstGLWindow
 * @callback: (scope async): function to invoke
 * @data: (closure): data to invoke @callback with
 *
 * Invoke @callback with data on the window thread.  @callback is guarenteed to
 * have executed when this function returns.
 */
void
gst_gl_window_send_message (GstGLWindow * window, GstGLWindowCB callback,
    gpointer data)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  g_return_if_fail (callback != NULL);
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->send_message != NULL);

  window_class->send_message (window, callback, data);
}
/**
 * gst_gl_window_draw:
 * @window: a #GstGLWindow
 * @width: requested width of the window
 * @height: requested height of the window
 *
 * Redraw the window contents.  Implementations should invoke the draw callback.
 */
void
gst_gl_window_draw (GstGLWindow * window, guint width, guint height)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->draw != NULL);

  /* avoid to overload the drawer */
  if (window->is_drawing) {
    return;
  }

  window_class->draw (window, width, height);
}
/**
 * gst_gl_window_set_close_callback:
 * @window: a #GstGLWindow
 * @callback: (scope notified): function to invoke
 * @data: (closure): data to invoke @callback with
 * @destroy_notify: (destroy): called when @data is not needed any more
 *
 * Sets the callback called when the window is about to close.
 */
void
gst_gl_window_set_close_callback (GstGLWindow * window, GstGLWindowCB callback,
    gpointer data, GDestroyNotify destroy_notify)
{
  g_return_if_fail (GST_GL_IS_WINDOW (window));

  GST_GL_WINDOW_LOCK (window);

  if (window->close_notify)
    window->close_notify (window->close_data);

  window->close = callback;
  window->close_data = data;
  window->close_notify = destroy_notify;

  GST_GL_WINDOW_UNLOCK (window);
}
/**
 * gst_gl_window_quit:
 * @window: a #GstGLWindow
 *
 * Quit the runloop's execution.
 */
void
gst_gl_window_quit (GstGLWindow * window)
{
  GstGLWindowClass *window_class;

  g_return_if_fail (GST_GL_IS_WINDOW (window));
  window_class = GST_GL_WINDOW_GET_CLASS (window);
  g_return_if_fail (window_class->quit != NULL);

  GST_GL_WINDOW_LOCK (window);

  window->priv->alive = FALSE;

  window_class->quit (window);

  GST_INFO ("quit sent to gl window loop");

  GST_GL_WINDOW_UNLOCK (window);
}
static void
gst_glimage_sink_navigation_send_event (GstNavigation * navigation, GstStructure
    * structure)
{
  GstGLImageSink *sink = GST_GLIMAGE_SINK (navigation);
  GstEvent *event = NULL;
  GstPad *pad = NULL;
  GstGLWindow *window = gst_gl_context_get_window (sink->context);
  guint width, height;
  gdouble x, y, xscale, yscale;

  g_return_if_fail (GST_GL_IS_WINDOW (window));

  width = GST_VIDEO_SINK_WIDTH (sink);
  height = GST_VIDEO_SINK_HEIGHT (sink);
  gst_gl_window_get_surface_dimensions (window, &width, &height);

  event = gst_event_new_navigation (structure);

  pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (sink));
  /* Converting pointer coordinates to the non scaled geometry */
  if (width != GST_VIDEO_SINK_WIDTH (sink) &&
      width != 0 && gst_structure_get_double (structure, "pointer_x", &x)) {
    xscale = (gdouble) GST_VIDEO_SINK_WIDTH (sink) / width;
    gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE,
        (gdouble) x * xscale, NULL);
  }
  if (height != GST_VIDEO_SINK_HEIGHT (sink) &&
      height != 0 && gst_structure_get_double (structure, "pointer_y", &y)) {
    yscale = (gdouble) GST_VIDEO_SINK_HEIGHT (sink) / height;
    gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE,
        (gdouble) y * yscale, NULL);
  }


  if (GST_IS_PAD (pad) && GST_IS_EVENT (event))
    gst_pad_send_event (pad, event);

  gst_object_unref (pad);
  gst_object_unref (window);
}
static void
gst_gl_window_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
  GstGLWindow *window;
  GstGLWindowPrivate *priv;

  g_return_if_fail (GST_GL_IS_WINDOW (object));

  window = GST_GL_WINDOW (object);

  priv = window->priv;

  switch (prop_id) {
    case ARG_DISPLAY:
      g_value_set_string (value, priv->display_name);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}