[725/906] x11: use GMainContext/GMainLoop
authorMatthew Waters <ystreet00@gmail.com>
Tue, 2 Jul 2013 12:06:03 +0000 (22:06 +1000)
committerMatthew Waters <ystreet00@gmail.com>
Sat, 15 Mar 2014 17:36:57 +0000 (18:36 +0100)
allows us to be reentrant

https://bugzilla.gnome.org/show_bug.cgi?id=703445

gst-libs/gst/gl/x11/Makefile.am
gst-libs/gst/gl/x11/gstglwindow_x11.c
gst-libs/gst/gl/x11/gstglwindow_x11.h
gst-libs/gst/gl/x11/x11_event_source.c [new file with mode: 0644]
gst-libs/gst/gl/x11/x11_event_source.h [new file with mode: 0644]

index 329be2d..fa990ce 100644 (file)
@@ -6,10 +6,12 @@ libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@
 libgstglx11includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl/x11
 
 libgstgl_x11_la_SOURCES = \
-       gstglwindow_x11.c
+       gstglwindow_x11.c \
+       x11_event_source.c
 
 libgstglx11include_HEADERS = \
-       gstglwindow_x11.h
+       gstglwindow_x11.h \
+       x11_event_source.h
 
 if USE_GLX
 libgstgl_x11_la_SOURCES += gstglwindow_x11_glx.c
index 2dde3dd..185acd8 100644 (file)
@@ -28,6 +28,7 @@
 #include <gst/gst.h>
 #include <locale.h>
 
+#include "x11_event_source.h"
 #include "gstglwindow_x11.h"
 
 #if GST_GL_HAVE_PLATFORM_GLX
@@ -157,8 +158,6 @@ static void
 gst_gl_window_x11_init (GstGLWindowX11 * window)
 {
   window->priv = GST_GL_WINDOW_X11_GET_PRIVATE (window);
-
-  g_cond_init (&window->cond_send_message);
 }
 
 /* Must be called in the gl thread */
@@ -228,7 +227,7 @@ gst_gl_window_x11_create_context (GstGLWindow * window,
 
   setlocale (LC_NUMERIC, "C");
 
-  gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), TRUE);
+  gst_gl_window_set_need_lock (GST_GL_WINDOW (window_x11), FALSE);
 
   window_x11->running = TRUE;
   window_x11->visible = FALSE;
@@ -253,7 +252,11 @@ gst_gl_window_x11_create_context (GstGLWindow * window,
   window_x11->device_height =
       DisplayHeight (window_x11->device, window_x11->screen_num);
 
-  window_x11->connection = ConnectionNumber (window_x11->device);
+  window_x11->x11_source = x11_event_source_new (window_x11);
+  window_x11->main_context = g_main_context_new ();
+  window_x11->loop = g_main_loop_new (window_x11->main_context, FALSE);
+
+  g_source_attach (window_x11->x11_source, window_x11->main_context);
 
   if (!window_class->choose_format (window_x11, error)) {
     goto failure;
@@ -286,7 +289,7 @@ gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11)
   XWMHints wm_hints;
   unsigned long mask;
   const gchar *title = "OpenGL renderer";
-  Atom wm_atoms[3];
+  Atom wm_atoms[1];
 
   static gint x = 0;
   static gint y = 0;
@@ -337,16 +340,8 @@ gst_gl_window_x11_create_window (GstGLWindowX11 * window_x11)
   if (wm_atoms[0] == None)
     GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
 
-  wm_atoms[1] = XInternAtom (window_x11->device, "WM_GL_WINDOW", False);
-  if (wm_atoms[1] == None)
-    GST_DEBUG ("Cannot create WM_GL_WINDOW");
-
-  wm_atoms[2] = XInternAtom (window_x11->device, "WM_QUIT_LOOP", False);
-  if (wm_atoms[2] == None)
-    GST_DEBUG ("Cannot create WM_QUIT_LOOP");
-
   XSetWMProtocols (window_x11->device, window_x11->internal_win_id, wm_atoms,
-      2);
+      1);
 
   wm_hints.flags = StateHint;
   wm_hints.initial_state = NormalState;
@@ -413,8 +408,6 @@ gst_gl_window_x11_close (GstGLWindow * window)
     GST_DEBUG ("display sender closed");
   }
 
-  g_cond_clear (&window_x11->cond_send_message);
-
   GST_GL_WINDOW_UNLOCK (window_x11);
 }
 
@@ -577,143 +570,76 @@ gst_gl_window_x11_draw (GstGLWindow * window, guint width, guint height)
   }
 }
 
-/* Called in the gl thread */
+typedef struct _GstGLMessage
+{
+  GstGLWindow *window;
+  GMutex lock;
+  GCond cond;
+  gboolean fired;
+
+  GstGLWindowCB callback;
+  gpointer data;
+} GstGLMessage;
+
+static gboolean
+_run_message (GstGLMessage * message)
+{
+  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);
+
+  return FALSE;
+}
+
 void
 gst_gl_window_x11_run (GstGLWindow * window)
 {
   GstGLWindowX11 *window_x11;
-  GstGLWindowX11Class *window_class;
 
   window_x11 = GST_GL_WINDOW_X11 (window);
-  window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11);
 
-  GST_DEBUG ("begin loop");
+  g_main_loop_run (window_x11->loop);
+}
 
-  while (window_x11->running) {
-    XEvent event;
-    XEvent pending_event;
+void
+gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11)
+{
+  GstGLWindow *window;
+  GstGLWindowX11Class *window_class;
 
-    GST_GL_WINDOW_UNLOCK (window);
+  window = GST_GL_WINDOW (window_x11);
+  window_class = GST_GL_WINDOW_X11_GET_CLASS (window_x11);
+
+  if (window_x11->running && XPending (window_x11->device)) {
+    XEvent event;
 
     /* XSendEvent (which are called in other threads) are done from another display structure */
     XNextEvent (window_x11->device, &event);
 
-    GST_GL_WINDOW_LOCK (window);
-
     // use in generic/cube and other related uses
     window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2;
 
     switch (event.type) {
       case ClientMessage:
       {
-
         Atom wm_delete =
             XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True);
-        Atom wm_gl = XInternAtom (window_x11->device, "WM_GL_WINDOW", True);
-        Atom wm_quit_loop =
-            XInternAtom (window_x11->device, "WM_QUIT_LOOP", True);
 
         if (wm_delete == None)
           GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
-        if (wm_gl == None)
-          GST_DEBUG ("Cannot create WM_GL_WINDOW");
-        if (wm_quit_loop == None)
-          GST_DEBUG ("Cannot create WM_QUIT_LOOP");
-
-        /* Message sent with gst_gl_window_send_message */
-        if (wm_gl != None && event.xclient.message_type == wm_gl) {
-          if (window_x11->running) {
-#if SIZEOF_VOID_P == 8
-            GstGLWindowCB custom_cb =
-                (GstGLWindowCB) (((event.xclient.data.
-                        l[0] & 0xffffffff) << 32) | (event.xclient.data.
-                    l[1] & 0xffffffff));
-            gpointer custom_data =
-                (gpointer) (((event.xclient.data.
-                        l[2] & 0xffffffff) << 32) | (event.xclient.data.
-                    l[3] & 0xffffffff));
-#else
-            GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0];
-            gpointer custom_data = (gpointer) event.xclient.data.l[1];
-#endif
-
-            if (!custom_cb || !custom_data)
-              GST_DEBUG ("custom cb not initialized");
-
-            custom_cb (custom_data);
-          }
-
-          g_cond_signal (&window_x11->cond_send_message);
-        }
 
         /* User clicked on the cross */
-        else if (wm_delete != None
-            && (Atom) event.xclient.data.l[0] == wm_delete) {
+        if (wm_delete != None && (Atom) event.xclient.data.l[0] == wm_delete) {
           GST_DEBUG ("Close %lud", (gulong) window_x11->internal_win_id);
 
           if (window->close)
             window->close (window->close_data);
         }
-
-        /* message sent with gst_gl_window_quit_loop */
-        else if (wm_quit_loop != None
-            && event.xclient.message_type == wm_quit_loop) {
-#if SIZEOF_VOID_P == 8
-          GstGLWindowCB destroy_cb =
-              (GstGLWindowCB) (((event.xclient.data.
-                      l[0] & 0xffffffff) << 32) | (event.xclient.data.
-                  l[1] & 0xffffffff));
-          gpointer destroy_data =
-              (gpointer) (((event.xclient.data.
-                      l[2] & 0xffffffff) << 32) | (event.xclient.data.
-                  l[3] & 0xffffffff));
-#else
-          GstGLWindowCB destroy_cb = (GstGLWindowCB) event.xclient.data.l[0];
-          gpointer destroy_data = (gpointer) event.xclient.data.l[1];
-#endif
-
-          GST_DEBUG ("Quit loop message %lud",
-              (gulong) window_x11->internal_win_id);
-
-          /* exit loop */
-          window_x11->running = FALSE;
-
-          /* make sure last pendings send message calls are executed */
-          XFlush (window_x11->device);
-          while (XCheckTypedEvent (window_x11->device, ClientMessage,
-                  &pending_event)) {
-#if SIZEOF_VOID_P == 8
-            GstGLWindowCB custom_cb =
-                (GstGLWindowCB) (((event.xclient.data.
-                        l[0] & 0xffffffff) << 32) | (event.xclient.data.
-                    l[1] & 0xffffffff));
-            gpointer custom_data =
-                (gpointer) (((event.xclient.data.
-                        l[2] & 0xffffffff) << 32) | (event.xclient.data.
-                    l[3] & 0xffffffff));
-#else
-            GstGLWindowCB custom_cb = (GstGLWindowCB) event.xclient.data.l[0];
-            gpointer custom_data = (gpointer) event.xclient.data.l[1];
-#endif
-            GST_DEBUG ("execute last pending custom x events");
-
-            if (!custom_cb || !custom_data)
-              GST_DEBUG ("custom cb not initialized");
-
-            custom_cb (custom_data);
-
-            g_cond_signal (&window_x11->cond_send_message);
-          }
-
-          /* Finally we can destroy opengl ressources (texture/shaders/fbo) */
-          if (!destroy_cb || !destroy_data)
-            GST_FIXME ("destroy cb not correctly set");
-
-          if (destroy_cb)
-            destroy_cb (destroy_data);
-
-        } else
-          GST_DEBUG ("client message not recognized");
         break;
       }
 
@@ -767,7 +693,6 @@ gst_gl_window_x11_run (GstGLWindow * window)
     }                           // switch
   }                             // while running
 
-  GST_DEBUG ("end loop");
 }
 
 /* Not called by the gl thread */
@@ -779,32 +704,14 @@ gst_gl_window_x11_quit (GstGLWindow * window, GstGLWindowCB callback,
 
   window_x11 = GST_GL_WINDOW_X11 (window);
 
-  GST_DEBUG ("sending quit, running:%i", window_x11->running);
+  if (callback)
+    gst_gl_window_x11_send_message (window, callback, data);
 
-  if (window_x11->running) {
-    XEvent event;
+  GST_LOG ("sending quit");
 
-    event.xclient.type = ClientMessage;
-    event.xclient.send_event = TRUE;
-    event.xclient.display = window_x11->disp_send;
-    event.xclient.window = window_x11->internal_win_id;
-    event.xclient.message_type =
-        XInternAtom (window_x11->disp_send, "WM_QUIT_LOOP", True);
-    event.xclient.format = 32;
-#if SIZEOF_VOID_P == 8
-    event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff;
-    event.xclient.data.l[1] = (((long) callback)) & 0xffffffff;
-    event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff;
-    event.xclient.data.l[3] = (((long) data)) & 0xffffffff;
-#else
-    event.xclient.data.l[0] = (long) callback;
-    event.xclient.data.l[1] = (long) data;
-#endif
+  g_main_loop_quit (window_x11->loop);
 
-    XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE,
-        NoEventMask, &event);
-    XSync (window_x11->disp_send, FALSE);
-  }
+  GST_LOG ("quit sent");
 }
 
 /* Not called by the gl thread */
@@ -817,32 +724,24 @@ gst_gl_window_x11_send_message (GstGLWindow * window, GstGLWindowCB callback,
   window_x11 = GST_GL_WINDOW_X11 (window);
 
   if (window_x11->running) {
-    XEvent event;
+    GstGLMessage message;
 
-    event.xclient.type = ClientMessage;
-    event.xclient.send_event = TRUE;
-    event.xclient.display = window_x11->disp_send;
-    event.xclient.window = window_x11->internal_win_id;
-    event.xclient.message_type =
-        XInternAtom (window_x11->disp_send, "WM_GL_WINDOW", True);
-    event.xclient.format = 32;
-#if SIZEOF_VOID_P == 8
-    event.xclient.data.l[0] = (((long) callback) >> 32) & 0xffffffff;
-    event.xclient.data.l[1] = (((long) callback)) & 0xffffffff;
-    event.xclient.data.l[2] = (((long) data) >> 32) & 0xffffffff;
-    event.xclient.data.l[3] = (((long) data)) & 0xffffffff;
-#else
-    event.xclient.data.l[0] = (long) callback;
-    event.xclient.data.l[1] = (long) data;
-#endif
+    message.window = window;
+    message.callback = callback;
+    message.data = data;
+    message.fired = FALSE;
+    g_mutex_init (&message.lock);
+    g_cond_init (&message.cond);
 
-    XSendEvent (window_x11->disp_send, window_x11->internal_win_id, FALSE,
-        NoEventMask, &event);
-    XSync (window_x11->disp_send, FALSE);
+    g_main_context_invoke (window_x11->main_context, (GSourceFunc) _run_message,
+        &message);
+
+    g_mutex_lock (&message.lock);
 
     /* block until opengl calls have been executed in the gl thread */
-    g_cond_wait (&window_x11->cond_send_message,
-        GST_GL_WINDOW_GET_LOCK (window));
+    while (!message.fired)
+      g_cond_wait (&message.cond, &message.lock);
+    g_mutex_unlock (&message.lock);
   }
 }
 
index 8271640..ea27cf1 100644 (file)
@@ -43,8 +43,7 @@ typedef struct _GstGLWindowX11Class   GstGLWindowX11Class;
 struct _GstGLWindowX11 {
   /*< private >*/
   GstGLWindow parent;
-  
-  GCond cond_send_message;
+
   gboolean      running;
   gboolean      visible;
   gboolean      allow_extra_expose_events;
@@ -71,6 +70,10 @@ struct _GstGLWindowX11 {
   /* X window */
   Window        internal_win_id;
 
+  GSource *x11_source;
+  GMainContext *main_context;
+  GMainLoop *loop;
+
   /*< private >*/
   GstGLWindowX11Private *priv;
   
diff --git a/gst-libs/gst/gl/x11/x11_event_source.c b/gst-libs/gst/gl/x11/x11_event_source.c
new file mode 100644 (file)
index 0000000..382b10a
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <wayland-client.h>
+
+#include "x11_event_source.h"
+
+extern void gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11);
+
+typedef struct _X11EventSource
+{
+  GSource source;
+  GPollFD pfd;
+  uint32_t mask;
+  GstGLWindowX11 *window;
+} X11EventSource;
+
+static gboolean
+x11_event_source_prepare (GSource * base, gint * timeout)
+{
+  X11EventSource *source = (X11EventSource *) base;
+  gboolean retval;
+
+  *timeout = -1;
+
+  retval = XPending (source->window->device);   //clutter_events_pending ();
+
+  return retval;
+}
+
+static gboolean
+x11_event_source_check (GSource * base)
+{
+  X11EventSource *source = (X11EventSource *) base;
+  gboolean retval;
+
+  retval = source->pfd.revents; // || clutter_events_pending();
+
+  return retval;
+}
+
+static gboolean
+x11_event_source_dispatch (GSource * base, GSourceFunc callback, gpointer data)
+{
+  X11EventSource *source = (X11EventSource *) base;
+
+  gst_gl_window_x11_handle_event (source->window);
+
+  if (callback)
+    callback (data);
+
+  return TRUE;
+}
+
+static GSourceFuncs x11_event_source_funcs = {
+  x11_event_source_prepare,
+  x11_event_source_check,
+  x11_event_source_dispatch,
+  NULL
+};
+
+GSource *
+x11_event_source_new (GstGLWindowX11 * window_x11)
+{
+  X11EventSource *source;
+
+  source = (X11EventSource *)
+      g_source_new (&x11_event_source_funcs, sizeof (X11EventSource));
+  source->window = window_x11;
+  source->pfd.fd = ConnectionNumber (window_x11->device);
+  source->pfd.events = G_IO_IN | G_IO_ERR;
+  g_source_add_poll (&source->source, &source->pfd);
+
+  return &source->source;
+}
diff --git a/gst-libs/gst/gl/x11/x11_event_source.h b/gst-libs/gst/gl/x11/x11_event_source.h
new file mode 100644 (file)
index 0000000..39f79f0
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * GStreamer
+ * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
+ *
+ * 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 St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __X11_EVENT_SOURCE_H__
+#define __X11_EVENT_SOURCE_H__
+
+#include <glib-object.h>
+#include "gstglwindow_x11.h"
+
+GSource *
+x11_event_source_new (GstGLWindowX11 *window_x11);
+
+#endif /* __WAYLAND_EVENT_SOURCE_H__ */