#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
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)
{
g_free (display_x11->name);
if (!display_x11->foreign_display && display_x11->display) {
+ XSync (display_x11->display, FALSE);
XCloseDisplay (display_x11->display);
}
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;
}
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;
{
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;
+}
#include <gst/gst.h>
#include <locale.h>
-#include "x11_event_source.h"
#include "gstglwindow_x11.h"
#include "gstgldisplay_x11.h"
/* for XkbKeycodeToKeysym */
#define gst_gl_window_x11_parent_class parent_class
G_DEFINE_TYPE (GstGLWindowX11, gst_gl_window_x11, GST_TYPE_GL_WINDOW);
+gboolean gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11,
+ xcb_generic_event_t * event);
+
/* X error trap */
static int TrappedErrorCode = 0;
static int (*old_error_handler) (Display *, XErrorEvent *);
-gboolean gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11);
-
enum
{
ARG_0,
GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
GstGLDisplayX11 *display_x11 = (GstGLDisplayX11 *) window->display;
- window_x11->device = XOpenDisplay (display_x11->name);
-// window_x11->device = display_x11->display;
+ window_x11->device = display_x11->display;
+// window_x11->device = XOpenDisplay (display_x11->name);
if (window_x11->device == NULL) {
g_set_error (error, GST_GL_WINDOW_ERROR,
GST_GL_WINDOW_ERROR_RESOURCE_UNAVAILABLE,
goto failure;
}
- XSynchronize (window_x11->device, FALSE);
-
GST_LOG ("gl device id: %ld", (gulong) window_x11->device);
window_x11->screen = DefaultScreenOfDisplay (window_x11->device);
window_x11->device_height =
DisplayHeight (window_x11->device, window_x11->screen_num);
- if (!GST_GL_WINDOW_CLASS (parent_class)->open (window, error))
- return FALSE;
-
- if (!display_x11->foreign_display) {
- window_x11->x11_source = x11_event_source_new (window_x11);
- g_source_attach (window_x11->x11_source,
- g_main_context_get_thread_default ());
- }
-
window_x11->allow_extra_expose_events = TRUE;
- return TRUE;
+ return GST_GL_WINDOW_CLASS (parent_class)->open (window, error);
failure:
return FALSE;
gst_gl_window_x11_close (GstGLWindow * window)
{
GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
- GstGLDisplay *display = window->display;
- XEvent event;
if (window_x11->device) {
- /* Avoid BadDrawable Errors... */
- if (gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_X11)
- XSync (GST_GL_DISPLAY_X11 (display)->display, FALSE);
-
- if (window_x11->internal_win_id)
+ if (window_x11->internal_win_id) {
XUnmapWindow (window_x11->device, window_x11->internal_win_id);
- XFree (window_x11->visual_info);
-
- if (window_x11->internal_win_id) {
- XReparentWindow (window_x11->device, window_x11->internal_win_id,
- window_x11->root, 0, 0);
XDestroyWindow (window_x11->device, window_x11->internal_win_id);
}
- XSync (window_x11->device, FALSE);
-
- while (XPending (window_x11->device))
- XNextEvent (window_x11->device, &event);
+ XFree (window_x11->visual_info);
- XCloseDisplay (window_x11->device);
GST_DEBUG ("display receiver closed");
}
- if (window_x11->x11_source) {
- g_source_destroy (window_x11->x11_source);
- g_source_unref (window_x11->x11_source);
- window_x11->x11_source = NULL;
- }
-
window_x11->running = FALSE;
GST_GL_WINDOW_CLASS (parent_class)->close (window);
gst_gl_window_x11_set_window_handle (GstGLWindow * window, guintptr id)
{
GstGLWindowX11 *window_x11;
- XWindowAttributes attr;
+ gint width, height;
window_x11 = GST_GL_WINDOW_X11 (window);
window_x11->parent_win = (Window) id;
- /* XXX: seems to be needed for the difference between gtk videooverlay and
- * the embedding gl into gtk directly */
- if (id && !window_x11->x11_source) {
- window_x11->x11_source = x11_event_source_new (window_x11);
- g_source_attach (window_x11->x11_source,
- g_main_context_get_thread_default ());
- }
+ if (window_x11->parent_win) {
+ XWindowAttributes attr;
- XGetWindowAttributes (window_x11->device, window_x11->parent_win, &attr);
+ XGetWindowAttributes (window_x11->device, window_x11->parent_win, &attr);
+ width = attr.width;
+ height = attr.height;
+ } else {
+ width = window_x11->priv->preferred_width;
+ height = window_x11->priv->preferred_height;
+ }
XResizeWindow (window_x11->device, window_x11->internal_win_id,
- attr.width, attr.height);
+ width, height);
XReparentWindow (window_x11->device, window_x11->internal_win_id,
window_x11->parent_win, 0, 0);
GstGLWindowX11 *window_x11 = GST_GL_WINDOW_X11 (window);
guint width = window_x11->priv->preferred_width;
guint height = window_x11->priv->preferred_height;
- XWindowAttributes attr;
-
- XGetWindowAttributes (window_x11->device, window_x11->internal_win_id, &attr);
if (!window_x11->visible) {
-
if (!window_x11->parent_win) {
- attr.width = width;
- attr.height = height;
XResizeWindow (window_x11->device, window_x11->internal_win_id,
- attr.width, attr.height);
- XSync (window_x11->device, FALSE);
+ width, height);
}
XMapWindow (window_x11->device, window_x11->internal_win_id);
+ XSync (window_x11->device, FALSE);
window_x11->visible = TRUE;
}
}
gst_gl_window_send_message (window, (GstGLWindowCB) _show_window, window);
}
+static void
+_context_draw (GstGLContext * context, GstGLWindow * window)
+{
+ GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
+
+ window->draw (window->draw_data);
+ context_class->swap_buffers (context);
+
+ gst_object_unref (context);
+}
+
static void
draw_cb (gpointer data)
{
XGetWindowAttributes (window_x11->device, window_x11->internal_win_id,
&attr);
+ GST_TRACE_OBJECT (window, "window size %ux%u", attr.width, attr.height);
if (window_x11->parent_win) {
XWindowAttributes attr_parent;
XGetWindowAttributes (window_x11->device, window_x11->parent_win,
&attr_parent);
+ GST_TRACE_OBJECT (window, "parent window size %ux%u", attr_parent.width,
+ attr_parent.height);
if (attr.width != attr_parent.width || attr.height != attr_parent.height) {
XMoveResizeWindow (window_x11->device, window_x11->internal_win_id,
if (window->draw) {
GstGLContext *context = gst_gl_window_get_context (window);
- GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
- window->draw (window->draw_data);
- context_class->swap_buffers (context);
-
- gst_object_unref (context);
+ _context_draw (context, window);
}
}
}
}
gboolean
-gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11)
+gst_gl_window_x11_handle_event (GstGLWindowX11 * window_x11,
+ xcb_generic_event_t * event)
{
- GstGLContext *context;
- GstGLContextClass *context_class;
- GstGLWindow *window;
- gboolean ret = TRUE;
-
- window = GST_GL_WINDOW (window_x11);
-
- if (gst_gl_window_is_running (window)
- && XPending (window_x11->device)) {
- XEvent event;
-
- /* XSendEvent (which are called in other threads) are done from another display structure */
- XNextEvent (window_x11->device, &event);
-
- window_x11->allow_extra_expose_events = XPending (window_x11->device) <= 2;
-
- GST_LOG ("got event %s", event_type_to_string (event.type));
+ GstGLWindow *window = GST_GL_WINDOW (window_x11);
+ GstGLDisplayX11 *display_x11 = GST_GL_DISPLAY_X11 (window->display);
+ xcb_connection_t *connection = display_x11->xcb_connection;
+ uint8_t event_code = event->response_type & 0x7f;
- switch (event.type) {
- case ClientMessage:
- {
- Atom wm_delete =
- XInternAtom (window_x11->device, "WM_DELETE_WINDOW", True);
+ switch (event_code) {
+ case XCB_CLIENT_MESSAGE:{
+ xcb_client_message_event_t *client_event;
+ xcb_intern_atom_cookie_t cookie;
+ xcb_intern_atom_reply_t *reply;
- if (wm_delete == None)
- GST_DEBUG ("Cannot create WM_DELETE_WINDOW");
+ client_event = (xcb_client_message_event_t *) event;
+ cookie = xcb_intern_atom (connection, 0, 16, "WM_DELETE_WINDOW");
+ reply = xcb_intern_atom_reply (connection, cookie, 0);
- /* User clicked on the cross */
- if (wm_delete != None && (Atom) event.xclient.data.l[0] == wm_delete) {
- GST_DEBUG ("Close %lud", (gulong) window_x11->internal_win_id);
+ if (client_event->data.data32[0] == reply->atom) {
+ GST_INFO_OBJECT (window_x11, "Close requested");
- if (window->close)
- window->close (window->close_data);
+ if (window->close)
+ window->close (window->close_data);
- ret = FALSE;
- }
- break;
+ gst_gl_display_remove_window (GST_GL_DISPLAY (display_x11),
+ GST_GL_WINDOW (window_x11));
}
- case CreateNotify:
- case ConfigureNotify:
- {
- gst_gl_window_resize (window, event.xconfigure.width,
- event.xconfigure.height);
- break;
- }
+ g_free (reply);
+ break;
+ }
+ case XCB_CONFIGURE_NOTIFY:{
+ xcb_configure_notify_event_t *configure_event;
- case DestroyNotify:
- break;
+ configure_event = (xcb_configure_notify_event_t *) event;
- case Expose:
- /* non-zero means that other Expose follows
- * so just wait for the last one
- * in theory we should not receive non-zero because
- * we have no sub areas here but just in case */
- if (event.xexpose.count != 0) {
- break;
- }
-
- /* We need to redraw on expose */
- if (window->draw) {
- context = gst_gl_window_get_context (window);
- context_class = GST_GL_CONTEXT_GET_CLASS (context);
-
- window->draw (window->draw_data);
- context_class->swap_buffers (context);
-
- gst_object_unref (context);
- }
- break;
+ gst_gl_window_resize (window, configure_event->width,
+ configure_event->height);
- case VisibilityNotify:
- /* actually nothing to do here */
- break;
- case KeyPress:
- case KeyRelease:
- {
- const char *key_str = NULL, *key_type = NULL;
- KeySym keysym;
-
- keysym = XkbKeycodeToKeysym (window_x11->device,
- event.xkey.keycode, 0, 0);
- key_str = XKeysymToString (keysym);
- key_type = event.type == KeyPress ? "key-press" : "key-release";
- GST_DEBUG ("input event key %d %s over window at %d,%d (%s)",
- event.xkey.keycode, key_type, event.xkey.x, event.xkey.y, key_str);
- gst_gl_window_send_key_event_async (window, key_type, key_str);
+ gst_gl_window_draw (window);
+ break;
+ }
+ case XCB_EXPOSE:{
+ xcb_expose_event_t *expose_event = (xcb_expose_event_t *) event;
+ /* non-zero means that other Expose follows
+ * so just wait for the last one
+ * in theory we should not receive non-zero because
+ * we have no sub areas here but just in case */
+ if (expose_event->count != 0)
break;
- }
- case ButtonPress:
- case ButtonRelease:{
- const char *mouse_type = NULL;
-
- mouse_type = event.type ==
- ButtonPress ? "mouse-button-press" : "mouse-button-release";
- GST_DEBUG ("input event mouse button %d %s over window at %d,%d",
- event.xbutton.button, mouse_type, event.xbutton.x, event.xbutton.y);
-
- gst_gl_window_send_mouse_event_async (window, mouse_type,
- event.xbutton.button, event.xbutton.x, event.xbutton.y);
- break;
- }
- case MotionNotify:
- GST_DEBUG ("input event pointer moved over window at %d,%d",
- event.xmotion.x, event.xmotion.y);
+ gst_gl_window_draw (window);
+ break;
+ }
+ case XCB_KEY_PRESS:
+ case XCB_KEY_RELEASE:{
+ xcb_key_press_event_t *kp = (xcb_key_press_event_t *) event;
+ const gchar *event_type_str;
+ gchar *key_str;
+ KeySym keysym;
+
+ keysym = XkbKeycodeToKeysym (window_x11->device, kp->detail, 0, 0);
+ key_str = XKeysymToString (keysym);
+
+ if (event_code == XCB_KEY_PRESS)
+ event_type_str = "key-press";
+ else
+ event_type_str = "key-release";
+
+ gst_gl_window_send_key_event (window, event_type_str, key_str);
+ break;
+ }
+ case XCB_BUTTON_PRESS:
+ case XCB_BUTTON_RELEASE:{
+ xcb_button_press_event_t *bp = (xcb_button_press_event_t *) event;
+ const gchar *event_type_str;
+
+ if (event_code == XCB_BUTTON_PRESS)
+ event_type_str = "mouse-button-press";
+ else
+ event_type_str = "mouse-button-release";
+
+ gst_gl_window_send_mouse_event (window, event_type_str, bp->detail,
+ (double) bp->event_x, (double) bp->event_y);
+ break;
+ }
+ case XCB_MOTION_NOTIFY:{
+ xcb_motion_notify_event_t *motion = (xcb_motion_notify_event_t *) event;
- gst_gl_window_send_mouse_event_async (window, "mouse-move", 0,
- event.xbutton.x, event.xbutton.y);
- break;
- default:
- GST_DEBUG ("unknown XEvent type: %u", event.type);
- break;
- } // switch
- } // while running
+ gst_gl_window_send_mouse_event (window, "mouse-move", 0,
+ (double) motion->event_x, (double) motion->event_y);
+ break;
+ }
+ default:
+ GST_TRACE ("unhandled XCB event: %u", event_code);
+ break;
+ }
- return ret;
+ return TRUE;
}
static int
--- /dev/null
+/*
+ * 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 "xcb_event_source.h"
+#include "gstgldisplay_x11.h"
+#include "gstglwindow_x11.h"
+
+extern gboolean gst_gl_display_x11_handle_event (GstGLDisplayX11 * display_x11);
+
+typedef struct _XCBEventSource
+{
+ GSource source;
+ GPollFD pfd;
+ uint32_t mask;
+ GstGLDisplayX11 *display_x11;
+} XCBEventSource;
+
+static gboolean
+xcb_event_source_prepare (GSource * base, gint * timeout)
+{
+ XCBEventSource *source = (XCBEventSource *) base;
+
+ xcb_flush (source->display_x11->xcb_connection);
+
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+xcb_event_source_check (GSource * base)
+{
+ XCBEventSource *source = (XCBEventSource *) base;
+ gboolean retval;
+
+ retval = source->pfd.revents;
+
+ return retval;
+}
+
+static gboolean
+xcb_event_source_dispatch (GSource * base, GSourceFunc callback, gpointer data)
+{
+ XCBEventSource *source = (XCBEventSource *) base;
+
+ gboolean ret = gst_gl_display_x11_handle_event (source->display_x11);
+
+ source->pfd.revents = 0;
+
+ if (callback)
+ callback (data);
+
+ return ret;
+}
+
+static GSourceFuncs xcb_event_source_funcs = {
+ xcb_event_source_prepare,
+ xcb_event_source_check,
+ xcb_event_source_dispatch,
+ NULL
+};
+
+GSource *
+xcb_event_source_new (GstGLDisplayX11 * display_x11)
+{
+ xcb_connection_t *connection;
+ XCBEventSource *source;
+
+ connection = display_x11->xcb_connection;
+ g_return_val_if_fail (connection != NULL, NULL);
+
+ source = (XCBEventSource *)
+ g_source_new (&xcb_event_source_funcs, sizeof (XCBEventSource));
+ source->display_x11 = display_x11;
+ source->pfd.fd = xcb_get_file_descriptor (connection);
+ source->pfd.events = G_IO_IN | G_IO_ERR;
+ g_source_add_poll (&source->source, &source->pfd);
+
+ return &source->source;
+}