summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2010-04-19 21:56:46 +0200
committerBenjamin Otte <otte@redhat.com>2010-04-19 22:04:59 +0200
commit023df851e732d65f4d89a0a2499c2a8ebe204f2a (patch)
treebc1fda77f42e24885dce27d36888569fb0385b25
parenta8d00fb971fe988a4e4c4e9d10c11414852e1628 (diff)
cairoxsink: Implement the XOverlay interface
-rw-r--r--ext/xlib/gstcairoxsink.c241
-rw-r--r--ext/xlib/gstcairoxsink.h1
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 */