summaryrefslogtreecommitdiff
path: root/gst-libs/gst/gl/x11/gstgldisplay_x11.c
diff options
context:
space:
mode:
authorMatthew Waters <matthew@centricular.com>2016-07-01 00:07:23 +1000
committerMatthew Waters <matthew@centricular.com>2016-11-08 15:14:26 +1100
commit4f6c226bd24ae3ef66bd8f4c17b001444c9b0bf1 (patch)
treef4e7cf1170b9a3036a13354d8caea46d9fac993b /gst-libs/gst/gl/x11/gstgldisplay_x11.c
parente4916fb1ef8e5ecc075978b98f50bd799faf83e0 (diff)
gl/x11: use xcb instead of libX11
- xcb is supposedly thread-safe! videotestsrc ! glimagesink now doesn't spuriously result in a 'call XInitThreads()' error however if anybody else is using X11, then XInitThreads() still needs to be called and multiple glimagesink's still need XInitThreads(). Everything still takes libX11 handles as they are compatible with the xcb variants. Unfortunately we cannot move fully over to xcb due to GLX being entirely based on Xlib. It's also impossible to transform a xcb_connection to a Display which means we require X11 handles.
Diffstat (limited to 'gst-libs/gst/gl/x11/gstgldisplay_x11.c')
-rw-r--r--gst-libs/gst/gl/x11/gstgldisplay_x11.c112
1 files changed, 112 insertions, 0 deletions
diff --git a/gst-libs/gst/gl/x11/gstgldisplay_x11.c b/gst-libs/gst/gl/x11/gstgldisplay_x11.c
index 696929eb8..92101d45e 100644
--- a/gst-libs/gst/gl/x11/gstgldisplay_x11.c
+++ b/gst-libs/gst/gl/x11/gstgldisplay_x11.c
@@ -23,6 +23,8 @@
#endif
#include <gst/gl/x11/gstgldisplay_x11.h>
+#include <gst/gl/x11/gstglwindow_x11.h>
+#include "xcb_event_source.h"
GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug);
#define GST_CAT_DEFAULT gst_gl_display_debug
@@ -32,6 +34,10 @@ G_DEFINE_TYPE (GstGLDisplayX11, gst_gl_display_x11, GST_TYPE_GL_DISPLAY);
static void gst_gl_display_x11_finalize (GObject * object);
static guintptr gst_gl_display_x11_get_handle (GstGLDisplay * display);
+gboolean gst_gl_display_x11_handle_event (GstGLDisplayX11 * display_x11);
+extern gboolean gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11,
+ xcb_generic_event_t * event);
+
static void
gst_gl_display_x11_class_init (GstGLDisplayX11Class * klass)
{
@@ -58,6 +64,7 @@ gst_gl_display_x11_finalize (GObject * object)
g_free (display_x11->name);
if (!display_x11->foreign_display && display_x11->display) {
+ XSync (display_x11->display, FALSE);
XCloseDisplay (display_x11->display);
}
@@ -86,8 +93,23 @@ gst_gl_display_x11_new (const gchar * name)
if (!ret->display) {
GST_ERROR ("Failed to open X11 display connection with name, \'%s\'", name);
+ gst_object_unref (ret);
+ return NULL;
+ }
+
+ ret->xcb_connection = XGetXCBConnection (ret->display);
+ if (!ret->xcb_connection) {
+ GST_ERROR ("Failed to open retieve XCB connection from X11 Display");
+ gst_object_unref (ret);
+ return NULL;
}
+ XSetEventQueueOwner (ret->display, XCBOwnsEventQueue);
+
+ GST_GL_DISPLAY (ret)->event_source = xcb_event_source_new (ret);
+ g_source_attach (GST_GL_DISPLAY (ret)->event_source,
+ GST_GL_DISPLAY (ret)->main_context);
+
return ret;
}
@@ -112,6 +134,14 @@ gst_gl_display_x11_new_with_display (Display * display)
ret->name = g_strdup (DisplayString (display));
ret->display = display;
+
+ ret->xcb_connection = XGetXCBConnection (ret->display);
+ if (!ret->xcb_connection) {
+ GST_ERROR ("Failed to open retieve XCB connection from X11 Display");
+ gst_object_unref (ret);
+ return NULL;
+ }
+
ret->foreign_display = TRUE;
return ret;
@@ -122,3 +152,85 @@ gst_gl_display_x11_get_handle (GstGLDisplay * display)
{
return (guintptr) GST_GL_DISPLAY_X11 (display)->display;
}
+
+static int
+_compare_xcb_window (GstGLWindowX11 * window_x11, xcb_window_t * window_id)
+{
+ return window_x11->internal_win_id - *window_id;
+}
+
+static GstGLWindowX11 *
+_find_window_from_xcb_window (GstGLDisplayX11 * display_x11,
+ xcb_window_t window_id)
+{
+ GstGLDisplay *display = GST_GL_DISPLAY (display_x11);
+ GstGLWindowX11 *ret = NULL;
+ GList *l;
+
+ if (!window_id)
+ return NULL;
+
+ GST_OBJECT_LOCK (display);
+ l = g_list_find_custom (display->windows, &window_id,
+ (GCompareFunc) _compare_xcb_window);
+ if (l)
+ ret = gst_object_ref (l->data);
+ GST_OBJECT_UNLOCK (display);
+
+ return ret;
+}
+
+static GstGLWindowX11 *
+_window_from_event (GstGLDisplayX11 * display_x11, xcb_generic_event_t * event)
+{
+ uint8_t event_code = event->response_type & 0x7f;
+
+ switch (event_code) {
+/* *INDENT-OFF* */
+#define WIN_FROM_EVENT(case_val,event_type,window_field) \
+ case case_val:{ \
+ event_type * real_event = (event_type *) event; \
+ return _find_window_from_xcb_window (display_x11, real_event->window_field); \
+ }
+ WIN_FROM_EVENT (XCB_CLIENT_MESSAGE, xcb_client_message_event_t, window)
+ WIN_FROM_EVENT (XCB_CONFIGURE_NOTIFY, xcb_configure_notify_event_t, window)
+ WIN_FROM_EVENT (XCB_EXPOSE, xcb_expose_event_t, window)
+ WIN_FROM_EVENT (XCB_KEY_PRESS, xcb_key_press_event_t, event)
+ WIN_FROM_EVENT (XCB_KEY_RELEASE, xcb_key_release_event_t, event)
+ WIN_FROM_EVENT (XCB_BUTTON_PRESS, xcb_button_press_event_t, event)
+ WIN_FROM_EVENT (XCB_BUTTON_RELEASE, xcb_button_release_event_t, event)
+ WIN_FROM_EVENT (XCB_MOTION_NOTIFY, xcb_motion_notify_event_t, event)
+#undef WIN_FROM_EVENT
+/* *INDENT-ON* */
+ default:
+ return NULL;
+ }
+}
+
+gboolean
+gst_gl_display_x11_handle_event (GstGLDisplayX11 * display_x11)
+{
+ xcb_connection_t *connection = display_x11->xcb_connection;
+ xcb_generic_event_t *event;
+ gboolean ret = TRUE;
+
+ while ((event = xcb_poll_for_event (connection))) {
+ GstGLWindowX11 *window_x11 = _window_from_event (display_x11, event);
+
+ GST_TRACE_OBJECT (display_x11, "got event %p to window %" GST_PTR_FORMAT,
+ event, window_x11);
+
+ if (window_x11) {
+ ret = gst_gl_window_x11_handle_event (window_x11, event);
+ } else {
+ /* unknown window, ignore */
+ ret = TRUE;
+ }
+
+ if (window_x11)
+ gst_object_unref (window_x11);
+ g_free (event);
+ }
+
+ return ret;
+}