summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2010-04-22 12:59:43 +0200
committerBenjamin Otte <otte@redhat.com>2010-04-22 12:59:43 +0200
commitc88e437582a970baa01afeef69a41cd472d62a61 (patch)
tree2dbff2066a6932d8ea816df538d5bd944d254193
parentf415b5aa42b3b02b62a14815a62dd3ef79d287e4 (diff)
cairoxsink: Completely rework window handling
We now always create a subwindow. This is useful because otherwise GL will throw various errors at us. It makes the code slightly more complicated, but we gotta live with that.
-rw-r--r--ext/xlib/gstcairoxsink.c128
-rw-r--r--ext/xlib/gstcairoxsink.h1
-rw-r--r--ext/xlib/gstcairoxtarget.c106
-rw-r--r--ext/xlib/gstcairoxtarget.h1
4 files changed, 153 insertions, 83 deletions
diff --git a/ext/xlib/gstcairoxsink.c b/ext/xlib/gstcairoxsink.c
index ac9560c..c93a7aa 100644
--- a/ext/xlib/gstcairoxsink.c
+++ b/ext/xlib/gstcairoxsink.c
@@ -77,76 +77,57 @@ gst_cairo_x_sink_navigation_send_event (GstNavigation * navigation,
gst_object_unref (pad);
}
-static const cairo_user_data_key_t window_key;
-
static void
-gst_cairo_x_sink_destroy_window (void *device)
-{
- Display *display = cairo_xlib_device_get_display (device);
- Window window = (Window) cairo_device_get_user_data (device, &window_key);
-
- if (display != NULL) {
- XDestroyWindow (display, window);
- }
-
- cairo_device_destroy (device);
-}
-
-static void
-gst_cairo_x_sink_update_events (GstCairoXSink * xsink, Display * display)
+gst_cairo_x_sink_update_events (GstCairoXSink * xsink)
{
long mask;
+ cairo_device_t *device;
- g_assert (xsink->window_surface);
+ g_assert (xsink->surface);
mask = ExposureMask | StructureNotifyMask;
if (xsink->handle_events) {
- mask |= PointerMotionMask | KeyPressMask | KeyReleaseMask;
-
- if (xsink->window_id == 0)
- mask |= ButtonPressMask | ButtonReleaseMask;
+ mask |= PointerMotionMask | KeyPressMask | KeyReleaseMask
+ | ButtonPressMask | ButtonReleaseMask;
}
- XSelectInput (display,
- cairo_xlib_surface_get_drawable (xsink->window_surface), mask);
+ device = cairo_surface_get_device (xsink->window_surface);
+ if (cairo_device_acquire (device) != CAIRO_STATUS_SUCCESS)
+ return;
+
+ XSelectInput (cairo_xlib_device_get_display (device),
+ xsink->target->get_window_id (xsink->surface), mask);
+
+ cairo_device_release (device);
}
static void
-gst_cairo_x_sink_create_window (GstCairoXSink * xsink, cairo_device_t * device)
+gst_cairo_x_sink_create_window (GstCairoXSink * xsink)
{
Display *display;
g_assert (xsink->window_surface == NULL);
- if (cairo_device_acquire (device) != CAIRO_STATUS_SUCCESS)
+ if (cairo_device_acquire (xsink->device) != CAIRO_STATUS_SUCCESS)
return;
- display = cairo_xlib_device_get_display (device);
+
+ display = cairo_xlib_device_get_display (xsink->device);
if (xsink->window_id == 0) {
- Window window = XCreateSimpleWindow (display,
- DefaultRootWindow (display),
- 0, 0, 400, 300, 0, 0,
- XBlackPixel (display, DefaultScreen (display)));
- xsink->window_surface = cairo_xlib_surface_create (display, window,
- DefaultVisual (display, DefaultScreen (display)), 400, 300);
- cairo_device_reference (device);
- cairo_surface_set_user_data (xsink->window_surface, &window_key, device,
- gst_cairo_x_sink_destroy_window);
- cairo_device_set_user_data (device, &window_key, (gpointer) window, NULL);
- gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (xsink), window);
+ xsink->window_surface =
+ xsink->window_surface = cairo_xlib_surface_create (display,
+ DefaultRootWindow (display), DefaultVisual (display,
+ DefaultScreen (display)), 400, 300);
} else {
XWindowAttributes attr;
- XSelectInput (display, xsink->window_id,
- ExposureMask | StructureNotifyMask);
+ XSelectInput (display, xsink->window_id, StructureNotifyMask);
XGetWindowAttributes (display, xsink->window_id, &attr);
xsink->window_surface = cairo_xlib_surface_create (display,
xsink->window_id, attr.visual, attr.width, attr.height);
}
- gst_cairo_x_sink_update_events (xsink, display);
-
- cairo_device_release (device);
+ cairo_device_release (xsink->device);
}
static void
@@ -158,11 +139,16 @@ gst_cairo_x_sink_xoverlay_set_xwindow_id (GstXOverlay * overlay,
if (xsink->window_id == xwindow_id)
return;
+ if (xsink->window_surface &&
+ cairo_device_acquire (xsink->device) == CAIRO_STATUS_SUCCESS) {
+ XSelectInput (cairo_xlib_device_get_display (xsink->device),
+ xsink->window_id, 0);
+ cairo_device_release (xsink->device);
+ }
+
xsink->window_id = xwindow_id;
if (xsink->window_surface) {
- cairo_device_t *device;
-
if (xsink->surface) {
/* FIXME: reuse the old device */
cairo_surface_destroy (xsink->surface);
@@ -170,13 +156,9 @@ gst_cairo_x_sink_xoverlay_set_xwindow_id (GstXOverlay * overlay,
xsink->target = NULL;
}
- device =
- cairo_device_reference (cairo_surface_get_device
- (xsink->window_surface));
cairo_surface_destroy (xsink->window_surface);
xsink->window_surface = NULL;
- gst_cairo_x_sink_create_window (xsink, device);
- cairo_device_destroy (device);
+ gst_cairo_x_sink_create_window (xsink);
}
}
@@ -193,20 +175,22 @@ gst_cairo_x_sink_paint (GstCairoXSink * xsink, int x, int y,
if (xsink->surface == NULL)
return;
- buffer = gst_base_sink_get_last_buffer (bsink);
-
- format = gst_cairo_format_new (GST_BUFFER_CAPS (buffer));
cr = cairo_create (xsink->surface);
+ buffer = gst_base_sink_get_last_buffer (bsink);
- cairo_scale (cr,
- (double) cairo_xlib_surface_get_width (xsink->window_surface) /
- gst_cairo_format_get_width (format),
- (double) cairo_xlib_surface_get_height (xsink->window_surface) /
- gst_cairo_format_get_height (format));
if (buffer) {
+ format = gst_cairo_format_new (GST_BUFFER_CAPS (buffer));
+
+ cairo_scale (cr,
+ (double) cairo_xlib_surface_get_width (xsink->window_surface) /
+ gst_cairo_format_get_width (format),
+ (double) cairo_xlib_surface_get_height (xsink->window_surface) /
+ gst_cairo_format_get_height (format));
source = gst_cairo_create_surface (buffer, format);
cairo_set_source_surface (cr, source, 0, 0);
cairo_surface_destroy (source);
+
+ gst_cairo_format_free (format);
gst_buffer_unref (buffer);
} else {
cairo_set_source_rgb (cr, 0, 0, 0);
@@ -216,8 +200,6 @@ gst_cairo_x_sink_paint (GstCairoXSink * xsink, int x, int y,
cairo_destroy (cr);
- gst_cairo_format_free (format);
-
xsink->target->done_drawing (xsink->surface);
}
@@ -239,19 +221,12 @@ gst_cairo_x_sink_xoverlay_handle_events (GstXOverlay * overlay,
gboolean handle_events)
{
GstCairoXSink *xsink = GST_CAIRO_X_SINK (overlay);
- cairo_device_t *device;
xsink->handle_events = handle_events;
- if (xsink->window_surface == NULL)
- return;
-
- device = cairo_surface_get_device (xsink->window_surface);
- if (cairo_device_acquire (device) != CAIRO_STATUS_SUCCESS)
+ if (xsink->surface == NULL)
return;
- gst_cairo_x_sink_update_events (xsink,
- cairo_xlib_device_get_display (device));
- cairo_device_release (device);
+ gst_cairo_x_sink_update_events (xsink);
}
static void
@@ -438,6 +413,7 @@ gst_cairo_x_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
cairo_surface_destroy (xsink->surface);
xsink->target = target;
xsink->surface = new_surface;
+ gst_cairo_x_sink_update_events (xsink);
}
if (xsink->window_id == 0) {
@@ -458,7 +434,6 @@ gst_cairo_x_sink_start (GstBaseSink * bsink)
{
GstCairoXSink *xsink = GST_CAIRO_X_SINK (bsink);
Display *display;
- cairo_device_t *device;
display = XOpenDisplay (NULL);
if (display == NULL) {
@@ -468,9 +443,8 @@ gst_cairo_x_sink_start (GstBaseSink * bsink)
XSynchronize (display, TRUE);
if (xsink->window_id == 0)
gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (xsink));
- device = cairo_xlib_device_create (display);
- gst_cairo_x_sink_create_window (xsink, device);
- cairo_device_destroy (device);
+ xsink->device = cairo_xlib_device_create (display);
+ gst_cairo_x_sink_create_window (xsink);
if (xsink->window_surface == NULL
|| cairo_surface_status (xsink->window_surface)) {
@@ -500,6 +474,8 @@ cleanup:
cairo_surface_destroy (xsink->window_surface);
xsink->window_surface = NULL;
}
+ cairo_device_destroy (xsink->device);
+ xsink->device = NULL;
XCloseDisplay (display);
return FALSE;
}
@@ -532,6 +508,10 @@ gst_cairo_x_sink_stop (GstBaseSink * bsink)
gst_cairo_format_free (xsink->format);
xsink->format = NULL;
+ XCloseDisplay (cairo_xlib_device_get_display (xsink->device));
+ cairo_device_destroy (xsink->device);
+ xsink->device = NULL;
+
return TRUE;
}
@@ -560,8 +540,10 @@ gst_cairo_x_sink_buffer_alloc (GstBaseSink * bsink, guint64 offset,
/* happens on first buffer alloc */
xsink->target =
gst_cairo_x_target_get (gst_cairo_format_get_surface_type (format));
- if (xsink->target)
+ if (xsink->target) {
xsink->surface = xsink->target->create_window (xsink->window_surface);
+ gst_cairo_x_sink_update_events (xsink);
+ }
}
if (xsink->surface &&
(gst_cairo_format_get_surface_type (format) == CAIRO_SURFACE_TYPE_IMAGE
diff --git a/ext/xlib/gstcairoxsink.h b/ext/xlib/gstcairoxsink.h
index 6c60b11..66be6fb 100644
--- a/ext/xlib/gstcairoxsink.h
+++ b/ext/xlib/gstcairoxsink.h
@@ -52,6 +52,7 @@ struct _GstCairoXSink {
/* stuff we do to X */
gboolean handle_events; /* TRUE if we should handle events */
unsigned long window_id; /* id set by X or 0 */
+ cairo_device_t * device; /* the xlib device */
cairo_surface_t * window_surface; /* xlib window we draw onto */
/* loop we run for event handling */
GMainContext * context; /* context of event thread */
diff --git a/ext/xlib/gstcairoxtarget.c b/ext/xlib/gstcairoxtarget.c
index 206e7d4..bc5286f 100644
--- a/ext/xlib/gstcairoxtarget.c
+++ b/ext/xlib/gstcairoxtarget.c
@@ -25,19 +25,63 @@
#include <cairo-xlib.h>
+typedef struct _GstCairoWindowData GstCairoWindowData;
+struct _GstCairoWindowData
+{
+ cairo_device_t *xdevice;
+ Window window;
+};
+
+static const cairo_user_data_key_t gst_cairo_window_data_key;
+
+static void
+gst_cairo_window_data_free (void *closure)
+{
+ GstCairoWindowData *data = closure;
+
+ if (cairo_device_acquire (data->xdevice) == CAIRO_STATUS_SUCCESS) {
+ XDestroyWindow (cairo_xlib_device_get_display (data->xdevice),
+ data->window);
+ cairo_device_release (data->xdevice);
+ }
+ g_slice_free (GstCairoWindowData, data);
+}
+
/*** X ***/
static cairo_surface_t *
gst_cairo_x_target_xlib_create_window (cairo_surface_t * window)
{
- return cairo_surface_reference (window);
-}
+ GstCairoWindowData *data = g_slice_new (GstCairoWindowData);
+ cairo_surface_t *surface;
+ cairo_device_t *device;
+ Display *display;
-static void
-gst_cairo_x_target_xlib_resize_window (cairo_surface_t * window,
- int width, int height)
-{
- /* NOOP as we use the parent window and don't create our own */
+ device = cairo_surface_get_device (window);
+ if (cairo_device_acquire (device) != CAIRO_STATUS_SUCCESS)
+ return NULL;
+
+ display = cairo_xlib_device_get_display (device);
+
+ data->xdevice = cairo_device_reference (device);
+ data->window = XCreateSimpleWindow (display,
+ cairo_xlib_surface_get_drawable (window),
+ 0, 0,
+ cairo_xlib_surface_get_width (window),
+ cairo_xlib_surface_get_height (window), 0, 0, XBlackPixel (display,
+ DefaultScreen (display)));
+ XMapWindow (display, data->window);
+
+ surface = cairo_xlib_surface_create (display, data->window,
+ cairo_xlib_surface_get_visual (window),
+ cairo_xlib_surface_get_width (window),
+ cairo_xlib_surface_get_height (window));
+ cairo_surface_set_user_data (surface, &gst_cairo_window_data_key, data,
+ gst_cairo_window_data_free);
+
+ cairo_device_release (device);
+
+ return surface;
}
static void
@@ -61,6 +105,18 @@ gst_cairo_x_target_xlib_done_drawing (cairo_surface_t * surface)
#endif
#include <cairo-gl.h>
+static unsigned long
+gst_cairo_x_target_gl_get_window_id (cairo_surface_t * surface)
+{
+ GstCairoWindowData *data =
+ cairo_surface_get_user_data (surface, &gst_cairo_window_data_key);
+
+ if (data == NULL)
+ return 0;
+
+ return data->window;
+}
+
static cairo_surface_t *
gst_cairo_x_target_gl_create_window (cairo_surface_t * window)
{
@@ -77,6 +133,8 @@ gst_cairo_x_target_gl_create_window (cairo_surface_t * window)
Display *display;
cairo_device_t *xdevice, *glxdevice;
cairo_surface_t *surface;
+ GstCairoWindowData *data;
+ XSetWindowAttributes win_attr;
xdevice = cairo_surface_get_device (window);
if (cairo_device_acquire (xdevice) != CAIRO_STATUS_SUCCESS)
@@ -97,14 +155,40 @@ gst_cairo_x_target_gl_create_window (cairo_surface_t * window)
}
ctx = glXCreateContext (display, visual, NULL, True);
- XFree (visual);
glxdevice = cairo_glx_device_create (display, ctx);
- surface = cairo_gl_surface_create_for_window (glxdevice,
+
+ win_attr.event_mask =
+ StructureNotifyMask | ExposureMask | VisibilityChangeMask;
+ win_attr.do_not_propagate_mask = NoEventMask;
+
+ win_attr.background_pixmap = None;
+ win_attr.background_pixel = 0;
+ win_attr.border_pixel = 0;
+
+ win_attr.colormap =
+ XCreateColormap (display, cairo_xlib_surface_get_drawable (window),
+ visual->visual, AllocNone);
+
+ data = g_slice_new (GstCairoWindowData);
+ data->xdevice = cairo_device_reference (xdevice);
+ data->window = XCreateWindow (display,
cairo_xlib_surface_get_drawable (window),
+ 0, 0,
+ cairo_xlib_surface_get_width (window),
+ cairo_xlib_surface_get_height (window), 0, visual->depth, InputOutput,
+ visual->visual, CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask,
+ &win_attr);
+ XMapWindow (display, data->window);
+
+ surface = cairo_gl_surface_create_for_window (glxdevice,
+ data->window,
cairo_xlib_surface_get_width (window),
cairo_xlib_surface_get_height (window));
+ cairo_surface_set_user_data (surface, &gst_cairo_window_data_key, data,
+ gst_cairo_window_data_free);
+ XFree (visual);
cairo_device_destroy (glxdevice);
cairo_device_release (xdevice);
@@ -117,10 +201,12 @@ gst_cairo_x_target_gl_create_window (cairo_surface_t * window)
static const GstCairoXTarget targets[] = {
[CAIRO_SURFACE_TYPE_XLIB] = {gst_cairo_x_target_xlib_create_window,
- gst_cairo_x_target_xlib_resize_window,
+ cairo_xlib_surface_get_drawable,
+ cairo_xlib_surface_set_size,
gst_cairo_x_target_xlib_done_drawing},
#ifdef HAVE_GLX
[CAIRO_SURFACE_TYPE_GL] = {gst_cairo_x_target_gl_create_window,
+ gst_cairo_x_target_gl_get_window_id,
cairo_gl_surface_set_size,
cairo_gl_surface_swapbuffers}
#endif /* HAVE_GLX */
diff --git a/ext/xlib/gstcairoxtarget.h b/ext/xlib/gstcairoxtarget.h
index 260838a..aa8804e 100644
--- a/ext/xlib/gstcairoxtarget.h
+++ b/ext/xlib/gstcairoxtarget.h
@@ -30,6 +30,7 @@ typedef struct _GstCairoXTarget GstCairoXTarget;
struct _GstCairoXTarget {
cairo_surface_t * (* create_window) (cairo_surface_t * window);
+ unsigned long (* get_window_id) (cairo_surface_t * window);
void (* resize_window) (cairo_surface_t * window,
int width,
int height);