diff --git a/ChangeLog b/ChangeLog index fb75e481a0..656c01a1a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2007-01-04 Julien MOUTTE + + * gst-libs/gst/interfaces/xoverlay.c: + (gst_x_overlay_handle_events): + * gst-libs/gst/interfaces/xoverlay.h: + * sys/ximage/ximagesink.c: (gst_ximagesink_xwindow_new), + (gst_ximagesink_set_xwindow_id), + (gst_ximagesink_set_event_handling), + (gst_ximagesink_xoverlay_init), (gst_ximagesink_set_property), + (gst_ximagesink_get_property), (gst_ximagesink_init), + (gst_ximagesink_class_init): + * sys/ximage/ximagesink.h: + * sys/xvimage/xvimagesink.c: (gst_xvimagesink_xwindow_new), + (gst_xvimagesink_set_xwindow_id), + (gst_xvimagesink_set_event_handling), + (gst_xvimagesink_xoverlay_init), (gst_xvimagesink_set_property), + (gst_xvimagesink_get_property), (gst_xvimagesink_init), + (gst_xvimagesink_class_init): + * sys/xvimage/xvimagesink.h: + * tests/icles/stress-xoverlay.c: (toggle_events), (create_window): + Add a method to the XOverlay interface to allow disabling of + event handling in x[v]imagesink elements. This will let X events + propagate to parent windows which can be usefull in some cases. + Be carefull that the application is then responsible of pushing + navigation events and expose events to the video sink. + Fixes: #387138. + 2007-01-03 Tim-Philipp Müller * gst-libs/gst/tag/gstvorbistag.c: diff --git a/gst-libs/gst/interfaces/xoverlay.c b/gst-libs/gst/interfaces/xoverlay.c index 0352fe7076..525529a264 100644 --- a/gst-libs/gst/interfaces/xoverlay.c +++ b/gst-libs/gst/interfaces/xoverlay.c @@ -239,3 +239,28 @@ gst_x_overlay_expose (GstXOverlay * overlay) klass->expose (overlay); } } + +/** + * gst_x_overlay_handle_events: + * @overlay: a #GstXOverlay to expose. + * @handle_events: a #gboolean indicating if events should be handled or not. + * + * Tell an overlay that it should handle events from the window system. These + * events are forwared upstream as navigation events. In some window system, + * events are not propagated in the window hierarchy if a client is listening + * for them. This method allows you to disable events handling completely + * from the XOverlay. + */ +void +gst_x_overlay_handle_events (GstXOverlay * overlay, gboolean handle_events) +{ + GstXOverlayClass *klass; + + g_return_if_fail (overlay != NULL); + + klass = GST_X_OVERLAY_GET_CLASS (overlay); + + if (klass->handle_events) { + klass->handle_events (overlay, handle_events); + } +} diff --git a/gst-libs/gst/interfaces/xoverlay.h b/gst-libs/gst/interfaces/xoverlay.h index f859a8f41b..9301d3a7e0 100644 --- a/gst-libs/gst/interfaces/xoverlay.h +++ b/gst-libs/gst/interfaces/xoverlay.h @@ -51,9 +51,12 @@ typedef struct _GstXOverlayClass { gulong xwindow_id); void (* expose) (GstXOverlay *overlay); + + void (* handle_events) (GstXOverlay *overlay, + gboolean handle_events); /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING - 1]; } GstXOverlayClass; GType gst_x_overlay_get_type (void); @@ -63,6 +66,9 @@ void gst_x_overlay_set_xwindow_id (GstXOverlay *overlay, gulong xwindow_id); void gst_x_overlay_expose (GstXOverlay *overlay); +void gst_x_overlay_handle_events (GstXOverlay *overlay, + gboolean handle_events); + /* public methods to dispatch bus messages */ void gst_x_overlay_got_xwindow_id (GstXOverlay *overlay, gulong xwindow_id); diff --git a/sys/ximage/ximagesink.c b/sys/ximage/ximagesink.c index 9644b7c6d1..7ca9d6c8aa 100644 --- a/sys/ximage/ximagesink.c +++ b/sys/ximage/ximagesink.c @@ -164,7 +164,8 @@ enum PROP_DISPLAY, PROP_SYNCHRONOUS, PROP_PIXEL_ASPECT_RATIO, - PROP_FORCE_ASPECT_RATIO + PROP_FORCE_ASPECT_RATIO, + PROP_HANDLE_EVENTS /* FILL ME */ }; @@ -771,9 +772,11 @@ gst_ximagesink_xwindow_new (GstXImageSink * ximagesink, gint width, gint height) ConfigureNotify. This takes away flickering of video when resizing. */ XSetWindowBackgroundPixmap (ximagesink->xcontext->disp, xwindow->win, None); - XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + if (ximagesink->handle_events) { + XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | + StructureNotifyMask | PointerMotionMask | KeyPressMask | + KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + } xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, 0, &values); @@ -1817,9 +1820,11 @@ gst_ximagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) xwindow->width = attr.width; xwindow->height = attr.height; xwindow->internal = FALSE; - XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); + if (ximagesink->handle_events) { + XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | + StructureNotifyMask | PointerMotionMask | KeyPressMask | + KeyReleaseMask); + } xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, 0, NULL); g_mutex_unlock (ximagesink->x_lock); @@ -1842,11 +1847,42 @@ gst_ximagesink_expose (GstXOverlay * overlay) gst_ximagesink_ximage_put (ximagesink, NULL); } +static void +gst_ximagesink_set_event_handling (GstXOverlay * overlay, + gboolean handle_events) +{ + GstXImageSink *ximagesink = GST_XIMAGESINK (overlay); + + ximagesink->handle_events = handle_events; + + if (!ximagesink->xwindow) + return; + + g_mutex_lock (ximagesink->x_lock); + + if (handle_events) { + if (ximagesink->xwindow->internal) { + XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, + ExposureMask | StructureNotifyMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + } else { + XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, + ExposureMask | StructureNotifyMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask); + } + } else { + XSelectInput (ximagesink->xcontext->disp, ximagesink->xwindow->win, 0); + } + + g_mutex_unlock (ximagesink->x_lock); +} + static void gst_ximagesink_xoverlay_init (GstXOverlayClass * iface) { iface->set_xwindow_id = gst_ximagesink_set_xwindow_id; iface->expose = gst_ximagesink_expose; + iface->handle_events = gst_ximagesink_set_event_handling; } /* =========================================== */ @@ -1902,6 +1938,10 @@ gst_ximagesink_set_property (GObject * object, guint prop_id, } } break; + case PROP_HANDLE_EVENTS: + gst_ximagesink_set_event_handling (GST_X_OVERLAY (ximagesink), + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1932,6 +1972,9 @@ gst_ximagesink_get_property (GObject * object, guint prop_id, if (ximagesink->par) g_value_transform (ximagesink->par, value); break; + case PROP_HANDLE_EVENTS: + g_value_set_boolean (value, ximagesink->handle_events); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1994,6 +2037,7 @@ gst_ximagesink_init (GstXImageSink * ximagesink) ximagesink->synchronous = FALSE; ximagesink->keep_aspect = FALSE; + ximagesink->handle_events = TRUE; } static void @@ -2038,6 +2082,10 @@ gst_ximagesink_class_init (GstXImageSinkClass * klass) g_object_class_install_property (gobject_class, PROP_PIXEL_ASPECT_RATIO, g_param_spec_string ("pixel-aspect-ratio", "Pixel Aspect Ratio", "The pixel aspect ratio of the device", "1/1", G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_HANDLE_EVENTS, + g_param_spec_boolean ("handle-events", "Handle XEvents", + "When enabled, XEvents will be selected and handled", TRUE, + G_PARAM_READWRITE)); gstelement_class->change_state = gst_ximagesink_change_state; diff --git a/sys/ximage/ximagesink.h b/sys/ximage/ximagesink.h index 5f10d8962a..99c4f6fa09 100644 --- a/sys/ximage/ximagesink.h +++ b/sys/ximage/ximagesink.h @@ -179,6 +179,7 @@ struct _GstXImageBuffer { * debugging purpose only) * @keep_aspect: used to remember if reverse negotiation scaling should respect * aspect ratio + * @handle_events: used to know if we should handle select XEvents or not * * The #GstXImageSink data structure. */ @@ -211,6 +212,7 @@ struct _GstXImageSink { gboolean synchronous; gboolean keep_aspect; + gboolean handle_events; }; struct _GstXImageSinkClass { diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c index 34eb74fbbb..01efd4b02f 100644 --- a/sys/xvimage/xvimagesink.c +++ b/sys/xvimage/xvimagesink.c @@ -188,7 +188,8 @@ enum ARG_DISPLAY, ARG_SYNCHRONOUS, ARG_PIXEL_ASPECT_RATIO, - ARG_FORCE_ASPECT_RATIO + ARG_FORCE_ASPECT_RATIO, + ARG_HANDLE_EVENTS /* FILL ME */ }; @@ -829,9 +830,11 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, * ConfigureNotify. This takes away flickering of video when resizing. */ XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None); - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + if (xvimagesink->handle_events) { + XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | + StructureNotifyMask | PointerMotionMask | KeyPressMask | + KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + } xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, xwindow->win, 0, &values); @@ -2374,9 +2377,11 @@ gst_xvimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) xwindow->width = attr.width; xwindow->height = attr.height; xwindow->internal = FALSE; - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); + if (xvimagesink->handle_events) { + XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | + StructureNotifyMask | PointerMotionMask | KeyPressMask | + KeyReleaseMask); + } xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, xwindow->win, 0, NULL); @@ -2400,11 +2405,42 @@ gst_xvimagesink_expose (GstXOverlay * overlay) gst_xvimagesink_xvimage_put (xvimagesink, NULL); } +static void +gst_xvimagesink_set_event_handling (GstXOverlay * overlay, + gboolean handle_events) +{ + GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); + + xvimagesink->handle_events = handle_events; + + if (!xvimagesink->xwindow) + return; + + g_mutex_lock (xvimagesink->x_lock); + + if (handle_events) { + if (xvimagesink->xwindow->internal) { + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, + ExposureMask | StructureNotifyMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + } else { + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, + ExposureMask | StructureNotifyMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask); + } + } else { + XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0); + } + + g_mutex_unlock (xvimagesink->x_lock); +} + static void gst_xvimagesink_xoverlay_init (GstXOverlayClass * iface) { iface->set_xwindow_id = gst_xvimagesink_set_xwindow_id; iface->expose = gst_xvimagesink_expose; + iface->handle_events = gst_xvimagesink_set_event_handling; } static const GList * @@ -2552,6 +2588,10 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, case ARG_FORCE_ASPECT_RATIO: xvimagesink->keep_aspect = g_value_get_boolean (value); break; + case ARG_HANDLE_EVENTS: + gst_xvimagesink_set_event_handling (GST_X_OVERLAY (xvimagesink), + g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2594,6 +2634,9 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, case ARG_FORCE_ASPECT_RATIO: g_value_set_boolean (value, xvimagesink->keep_aspect); break; + case ARG_HANDLE_EVENTS: + g_value_set_boolean (value, xvimagesink->handle_events); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -2662,6 +2705,7 @@ gst_xvimagesink_init (GstXvImageSink * xvimagesink) xvimagesink->synchronous = FALSE; xvimagesink->running = FALSE; xvimagesink->keep_aspect = FALSE; + xvimagesink->handle_events = TRUE; xvimagesink->par = NULL; } @@ -2719,6 +2763,10 @@ gst_xvimagesink_class_init (GstXvImageSinkClass * klass) g_param_spec_boolean ("force-aspect-ratio", "Force aspect ratio", "When enabled, scaling will respect original aspect ratio", FALSE, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, ARG_HANDLE_EVENTS, + g_param_spec_boolean ("handle-events", "Handle XEvents", + "When enabled, XEvents will be selected and handled", TRUE, + G_PARAM_READWRITE)); gobject_class->finalize = gst_xvimagesink_finalize; diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h index e59e96108a..6872dc5ba6 100644 --- a/sys/xvimage/xvimagesink.h +++ b/sys/xvimage/xvimagesink.h @@ -209,6 +209,7 @@ struct _GstXvImageBuffer { * debugging purpose only) * @keep_aspect: used to remember if reverse negotiation scaling should respect * aspect ratio + * @handle_events: used to know if we should handle select XEvents or not * @brightness: used to store the user settings for color balance brightness * @contrast: used to store the user settings for color balance contrast * @hue: used to store the user settings for color balance hue @@ -247,6 +248,7 @@ struct _GstXvImageSink { gboolean synchronous; gboolean keep_aspect; + gboolean handle_events; gint brightness; gint contrast; diff --git a/tests/icles/stress-xoverlay.c b/tests/icles/stress-xoverlay.c index b26bb993ff..63d8bb06c5 100644 --- a/tests/icles/stress-xoverlay.c +++ b/tests/icles/stress-xoverlay.c @@ -93,17 +93,38 @@ move_window (GstPipeline * pipeline) return TRUE; } +static gboolean +toggle_events (GstXOverlay * ov) +{ + static gboolean events_toggled; + + gst_x_overlay_handle_events (ov, events_toggled); + + if (events_toggled) { + g_print ("Events are handled\n"); + events_toggled = FALSE; + } else { + g_print ("Events are NOT handled\n"); + events_toggled = TRUE; + } + + return TRUE; +} + static GstBusSyncReply create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline) { XGCValues values; const GstStructure *s; + GstXOverlay *ov = NULL; s = gst_message_get_structure (message); if (!gst_structure_has_name (s, "prepare-xwindow-id")) { return GST_BUS_PASS; } + ov = GST_X_OVERLAY (GST_MESSAGE_SRC (message)); + g_print ("Creating our own window\n"); win = XCreateSimpleWindow (disp, root, 0, 0, width, height, 0, 0, 0); @@ -116,10 +137,11 @@ create_window (GstBus * bus, GstMessage * message, GstPipeline * pipeline) XSync (disp, FALSE); - gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (GST_MESSAGE_SRC (message)), win); + gst_x_overlay_set_xwindow_id (ov, win); g_timeout_add (50, (GSourceFunc) resize_window, pipeline); g_timeout_add (50, (GSourceFunc) move_window, pipeline); + g_timeout_add (2000, (GSourceFunc) toggle_events, ov); return GST_BUS_DROP; }