diff options
author | Benjamin Otte <otte@redhat.com> | 2010-04-22 12:59:43 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2010-04-22 12:59:43 +0200 |
commit | c88e437582a970baa01afeef69a41cd472d62a61 (patch) | |
tree | 2dbff2066a6932d8ea816df538d5bd944d254193 | |
parent | f415b5aa42b3b02b62a14815a62dd3ef79d287e4 (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.c | 128 | ||||
-rw-r--r-- | ext/xlib/gstcairoxsink.h | 1 | ||||
-rw-r--r-- | ext/xlib/gstcairoxtarget.c | 106 | ||||
-rw-r--r-- | ext/xlib/gstcairoxtarget.h | 1 |
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); |