diff options
author | Benjamin Otte <otte@redhat.com> | 2010-04-19 21:56:46 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2010-04-19 22:04:59 +0200 |
commit | 023df851e732d65f4d89a0a2499c2a8ebe204f2a (patch) | |
tree | bc1fda77f42e24885dce27d36888569fb0385b25 | |
parent | a8d00fb971fe988a4e4c4e9d10c11414852e1628 (diff) |
cairoxsink: Implement the XOverlay interface
-rw-r--r-- | ext/xlib/gstcairoxsink.c | 241 | ||||
-rw-r--r-- | ext/xlib/gstcairoxsink.h | 1 |
2 files changed, 182 insertions, 60 deletions
diff --git a/ext/xlib/gstcairoxsink.c b/ext/xlib/gstcairoxsink.c index 656d13e..5820e21 100644 --- a/ext/xlib/gstcairoxsink.c +++ b/ext/xlib/gstcairoxsink.c @@ -37,6 +37,7 @@ #include "gstcairoxsink.h" #include <gst/interfaces/navigation.h> +#include <gst/interfaces/xoverlay.h> #include <cairo-xlib.h> #include "gstcairoxsource.h" @@ -50,6 +51,11 @@ gst_cairo_x_sink_navigation_send_event (GstNavigation * navigation, GstPad *pad; double d; + if (xsink->format == NULL) { + gst_structure_free (structure); + return; + } + pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (xsink)); if (!pad) { gst_structure_free (structure); @@ -71,22 +77,105 @@ 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_navigation_init (GstNavigationInterface * iface) +gst_cairo_x_sink_destroy_window (void *device) { - iface->send_event = gst_cairo_x_sink_navigation_send_event; + 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 -_do_init (GType g_define_type_id) +gst_cairo_x_sink_update_events (GstCairoXSink * xsink, Display * display) { - G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, gst_cairo_x_sink_navigation_init); + long mask; + + g_assert (xsink->window_surface); + + mask = ExposureMask | StructureNotifyMask; + + if (xsink->handle_events) { + mask |= PointerMotionMask | KeyPressMask | KeyReleaseMask; + + if (xsink->window_id == 0) + mask |= ButtonPressMask | ButtonReleaseMask; + } + + XSelectInput (display, + cairo_xlib_surface_get_drawable (xsink->window_surface), mask); } -GST_BOILERPLATE_FULL (GstCairoXSink, gst_cairo_x_sink, GstElement, - GST_TYPE_VIDEO_SINK, _do_init); +static void +gst_cairo_x_sink_create_window (GstCairoXSink * xsink, cairo_device_t * device) +{ + Display *display; -/* THREAD */ + g_assert (xsink->window_surface == NULL); + + if (cairo_device_acquire (device) != CAIRO_STATUS_SUCCESS) + return; + display = cairo_xlib_device_get_display (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); + } else { + XWindowAttributes attr; + 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); +} + +static void +gst_cairo_x_sink_xoverlay_set_xwindow_id (GstXOverlay * overlay, + gulong xwindow_id) +{ + GstCairoXSink *xsink = GST_CAIRO_X_SINK (overlay); + + if (xsink->window_id == xwindow_id) + return; + + 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); + xsink->surface = NULL; + 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); + } +} static void gst_cairo_x_sink_paint (GstCairoXSink * xsink, int x, int y, @@ -127,6 +216,88 @@ gst_cairo_x_sink_paint (GstCairoXSink * xsink, int x, int y, xsink->target->done_drawing (xsink->surface); } +static void +gst_cairo_x_sink_xoverlay_expose (GstXOverlay * overlay) +{ + GstCairoXSink *xsink = GST_CAIRO_X_SINK (overlay); + + if (xsink->window_surface == NULL) + return; + + gst_cairo_x_sink_paint (xsink, 0, 0, + cairo_xlib_surface_get_width (xsink->window_surface), + cairo_xlib_surface_get_height (xsink->window_surface)); +} + +static void +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) + return; + + gst_cairo_x_sink_update_events (xsink, + cairo_xlib_device_get_display (device)); + cairo_device_release (device); +} + +static void +gst_cairo_x_sink_xoverlay_set_render_rectangle (GstXOverlay * overlay, + gint x, gint y, gint width, gint height) +{ + /* FIXME */ +} + +static gboolean +gst_cairo_x_sink_implements_supported (GstImplementsInterface * iface, + GType iface_type) +{ + return TRUE; +} + +static void +gst_cairo_x_sink_navigation_init (GstNavigationInterface * iface) +{ + iface->send_event = gst_cairo_x_sink_navigation_send_event; +} + +static void +gst_cairo_x_sink_xoverlay_init (GstXOverlayClass * iface) +{ + iface->set_xwindow_id = gst_cairo_x_sink_xoverlay_set_xwindow_id; + iface->expose = gst_cairo_x_sink_xoverlay_expose; + iface->handle_events = gst_cairo_x_sink_xoverlay_handle_events; + iface->set_render_rectangle = gst_cairo_x_sink_xoverlay_set_render_rectangle; +} + +static void +gst_cairo_x_sink_implements_init (GstImplementsInterfaceClass * iface) +{ + iface->supported = gst_cairo_x_sink_implements_supported; +} + +static void +_do_init (GType g_define_type_id) +{ + G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, gst_cairo_x_sink_navigation_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_IMPLEMENTS_INTERFACE, + gst_cairo_x_sink_implements_init); + G_IMPLEMENT_INTERFACE (GST_TYPE_X_OVERLAY, gst_cairo_x_sink_xoverlay_init); +} + +GST_BOILERPLATE_FULL (GstCairoXSink, gst_cairo_x_sink, GstElement, + GST_TYPE_VIDEO_SINK, _do_init); + +/* THREAD */ + static gboolean gst_cairo_x_sink_handle_event (XEvent * event, gpointer sink) { @@ -279,58 +450,6 @@ gst_cairo_x_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) return TRUE; } -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 cairo_surface_t * -gst_cairo_x_sink_create_window (GstCairoXSink * xsink, cairo_device_t * device) -{ - Display *display; - cairo_surface_t *surface; - - if (cairo_device_acquire (device) != CAIRO_STATUS_SUCCESS) - return NULL; - display = cairo_xlib_device_get_display (device); - - if (xsink->window_id == 0) { - Window window = XCreateSimpleWindow (display, - DefaultRootWindow (display), - 0, 0, 400, 300, 0, 0, - XBlackPixel (display, DefaultScreen (display))); - surface = cairo_xlib_surface_create (display, window, - DefaultVisual (display, DefaultScreen (display)), 400, 300); - cairo_device_reference (device); - cairo_surface_set_user_data (surface, &window_key, device, - gst_cairo_x_sink_destroy_window); - cairo_device_set_user_data (device, &window_key, (gpointer) window, NULL); - } else { - XWindowAttributes attr; - XGetWindowAttributes (display, xsink->window_id, &attr); - surface = cairo_xlib_surface_create (display, xsink->window_id, - attr.visual, attr.width, attr.height); - } - - XSelectInput (display, cairo_xlib_surface_get_drawable (surface), - ExposureMask | StructureNotifyMask | PointerMotionMask | ButtonPressMask - | ButtonReleaseMask | KeyPressMask | KeyReleaseMask); - - cairo_device_release (device); - - return surface; -} - static gboolean gst_cairo_x_sink_start (GstBaseSink * bsink) { @@ -343,8 +462,9 @@ gst_cairo_x_sink_start (GstBaseSink * bsink) GST_WARNING_OBJECT (xsink, "Failed to open connection to X server"); return FALSE; } + XSynchronize (display, TRUE); device = cairo_xlib_device_create (display); - xsink->window_surface = gst_cairo_x_sink_create_window (xsink, device); + gst_cairo_x_sink_create_window (xsink, device); cairo_device_destroy (device); if (xsink->window_surface == NULL @@ -485,4 +605,5 @@ gst_cairo_x_sink_class_init (GstCairoXSinkClass * klass) static void gst_cairo_x_sink_init (GstCairoXSink * xsink, GstCairoXSinkClass * klass) { + xsink->handle_events = TRUE; } diff --git a/ext/xlib/gstcairoxsink.h b/ext/xlib/gstcairoxsink.h index 0e6e5b0..6c60b11 100644 --- a/ext/xlib/gstcairoxsink.h +++ b/ext/xlib/gstcairoxsink.h @@ -50,6 +50,7 @@ struct _GstCairoXSink { GstCairoFormat * format; /* negotiated format on the sink side */ /* 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_surface_t * window_surface; /* xlib window we draw onto */ /* loop we run for event handling */ |