From cbc95dfb3d65ffbc9457038125d31c582943615e Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 17 May 2007 17:35:46 +0000 Subject: [PATCH] sys/: When we create our own window, indicate that we handle the Original commit message from CVS: * sys/ximage/ximagesink.c: (gst_ximagesink_ximage_put), (gst_ximagesink_xwindow_new), (gst_ximagesink_handle_xevents), (gst_ximagesink_show_frame): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_put), (gst_xvimagesink_xwindow_new), (gst_xvimagesink_handle_xevents), (gst_xvimagesink_show_frame): When we create our own window, indicate that we handle the WM_DELETE client message from the window manager, so that it won't kill our window (and our app) along with it. Handle ClientMessage, post an error on the bus, and close the window. Further buffers arriving will result in a FlowError because the window has been destroyed. Fixes: #393975 Clean up the X event handling loop and make them the same for both xvimagesink and ximagesink while I'm at it. --- ChangeLog | 20 ++++++ sys/ximage/ximagesink.c | 159 +++++++++++++++++++++++++++++----------------- sys/xvimage/xvimagesink.c | 119 +++++++++++++++++++++++----------- 3 files changed, 202 insertions(+), 96 deletions(-) diff --git a/ChangeLog b/ChangeLog index 39880ee..6d01cc9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +2007-05-17 Jan Schmidt + + * sys/ximage/ximagesink.c: (gst_ximagesink_ximage_put), + (gst_ximagesink_xwindow_new), (gst_ximagesink_handle_xevents), + (gst_ximagesink_show_frame): + * sys/xvimage/xvimagesink.c: (gst_xvimagesink_xvimage_put), + (gst_xvimagesink_xwindow_new), (gst_xvimagesink_handle_xevents), + (gst_xvimagesink_show_frame): + When we create our own window, indicate that we handle the + WM_DELETE client message from the window manager, so that it won't + kill our window (and our app) along with it. Handle ClientMessage, + post an error on the bus, and close the window. Further buffers + arriving will result in a FlowError because the window has been + destroyed. + + Fixes: #393975 + + Clean up the X event handling loop and make them the same for + both xvimagesink and ximagesink while I'm at it. + 2007-05-17 Wim Taymans * gst/playback/gstdecodebin2.c: (gst_decode_bin_factory_filter): diff --git a/sys/ximage/ximagesink.c b/sys/ximage/ximagesink.c index 321a1fc..7f2a1d3 100644 --- a/sys/ximage/ximagesink.c +++ b/sys/ximage/ximagesink.c @@ -668,13 +668,13 @@ gst_ximagesink_xwindow_draw_borders (GstXImageSink * ximagesink, } /* This function puts a GstXImageBuffer on a GstXImageSink's window */ -static void +static gboolean gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage) { GstVideoRectangle src, dst, result; gboolean draw_border = FALSE; - g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); + g_return_val_if_fail (GST_IS_XIMAGESINK (ximagesink), FALSE); /* We take the flow_lock. If expose is in there we don't want to run concurrently from the data flow thread */ @@ -682,7 +682,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage) if (G_UNLIKELY (ximagesink->xwindow == NULL)) { g_mutex_unlock (ximagesink->flow_lock); - return; + return FALSE; } /* Draw borders when displaying the first frame. After this @@ -709,7 +709,7 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage) ximage = ximagesink->cur_image; } else { g_mutex_unlock (ximagesink->flow_lock); - return; + return TRUE; } } @@ -754,6 +754,8 @@ gst_ximagesink_ximage_put (GstXImageSink * ximagesink, GstXImageBuffer * ximage) g_mutex_unlock (ximagesink->x_lock); g_mutex_unlock (ximagesink->flow_lock); + + return TRUE; } static gboolean @@ -818,9 +820,18 @@ gst_ximagesink_xwindow_new (GstXImageSink * ximagesink, gint width, gint height) XSetWindowBackgroundPixmap (ximagesink->xcontext->disp, xwindow->win, None); if (ximagesink->handle_events) { + Atom wm_delete; + XSelectInput (ximagesink->xcontext->disp, xwindow->win, ExposureMask | StructureNotifyMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + + /* Tell the window manager we'd like delete client messages instead of + * being killed */ + wm_delete = XInternAtom (ximagesink->xcontext->disp, + "WM_DELETE_WINDOW", False); + (void) XSetWMProtocols (ximagesink->xcontext->disp, xwindow->win, + &wm_delete, 1); } xwindow->gc = XCreateGC (ximagesink->xcontext->disp, xwindow->win, @@ -911,48 +922,48 @@ static void gst_ximagesink_handle_xevents (GstXImageSink * ximagesink) { XEvent e; + guint pointer_x = 0, pointer_y = 0; + gboolean pointer_moved = FALSE; + gboolean exposed = FALSE, configured = FALSE; g_return_if_fail (GST_IS_XIMAGESINK (ximagesink)); - { - guint pointer_x = 0, pointer_y = 0; - gboolean pointer_moved = FALSE; + /* Then we get all pointer motion events, only the last position is + interesting. */ + g_mutex_lock (ximagesink->flow_lock); + g_mutex_lock (ximagesink->x_lock); + while (XCheckWindowEvent (ximagesink->xcontext->disp, + ximagesink->xwindow->win, PointerMotionMask, &e)) { + g_mutex_unlock (ximagesink->x_lock); + g_mutex_unlock (ximagesink->flow_lock); - /* Then we get all pointer motion events, only the last position is - interesting. */ + switch (e.type) { + case MotionNotify: + pointer_x = e.xmotion.x; + pointer_y = e.xmotion.y; + pointer_moved = TRUE; + break; + default: + break; + } g_mutex_lock (ximagesink->flow_lock); g_mutex_lock (ximagesink->x_lock); - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, PointerMotionMask, &e)) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); + } - switch (e.type) { - case MotionNotify: - pointer_x = e.xmotion.x; - pointer_y = e.xmotion.y; - pointer_moved = TRUE; - break; - default: - break; - } - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - } + if (pointer_moved) { g_mutex_unlock (ximagesink->x_lock); g_mutex_unlock (ximagesink->flow_lock); - if (pointer_moved) { - GST_DEBUG ("ximagesink pointer moved over window at %d,%d", - pointer_x, pointer_y); - gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), - "mouse-move", 0, pointer_x, pointer_y); - } + GST_DEBUG ("ximagesink pointer moved over window at %d,%d", + pointer_x, pointer_y); + gst_navigation_send_mouse_event (GST_NAVIGATION (ximagesink), + "mouse-move", 0, pointer_x, pointer_y); + + g_mutex_lock (ximagesink->flow_lock); + g_mutex_lock (ximagesink->x_lock); } /* We get all remaining events on our window to throw them upstream */ - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); while (XCheckWindowEvent (ximagesink->xcontext->disp, ximagesink->xwindow->win, KeyPressMask | KeyReleaseMask | @@ -1009,36 +1020,60 @@ gst_ximagesink_handle_xevents (GstXImageSink * ximagesink) g_mutex_lock (ximagesink->flow_lock); g_mutex_lock (ximagesink->x_lock); } - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - { - gboolean exposed = FALSE; - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); - while (XCheckWindowEvent (ximagesink->xcontext->disp, - ximagesink->xwindow->win, ExposureMask, &e)) { - g_mutex_unlock (ximagesink->x_lock); - g_mutex_unlock (ximagesink->flow_lock); - - switch (e.type) { - case Expose: - exposed = TRUE; - break; - default: - break; - } - g_mutex_lock (ximagesink->flow_lock); - g_mutex_lock (ximagesink->x_lock); + while (XCheckWindowEvent (ximagesink->xcontext->disp, + ximagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { + switch (e.type) { + case Expose: + exposed = TRUE; + break; + case ConfigureNotify: + configured = TRUE; + break; + default: + break; } + } + + if (exposed || configured) { g_mutex_unlock (ximagesink->x_lock); g_mutex_unlock (ximagesink->flow_lock); - if (exposed) { - gst_ximagesink_expose (GST_X_OVERLAY (ximagesink)); + gst_ximagesink_expose (GST_X_OVERLAY (ximagesink)); + + g_mutex_lock (ximagesink->x_lock); + g_mutex_lock (ximagesink->flow_lock); + } + + /* Handle Display events */ + while (XPending (ximagesink->xcontext->disp)) { + XNextEvent (ximagesink->xcontext->disp, &e); + + switch (e.type) { + case ClientMessage:{ + Atom wm_delete; + + wm_delete = XInternAtom (ximagesink->xcontext->disp, + "WM_DELETE_WINDOW", False); + if (wm_delete == (Atom) e.xclient.data.l[0]) { + /* Handle window deletion by posting an error on the bus */ + GST_ELEMENT_ERROR (ximagesink, RESOURCE, NOT_FOUND, + ("Output window was closed"), (NULL)); + + g_mutex_unlock (ximagesink->x_lock); + gst_ximagesink_xwindow_destroy (ximagesink, ximagesink->xwindow); + ximagesink->xwindow = NULL; + g_mutex_lock (ximagesink->x_lock); + } + break; + } + default: + break; } } + + g_mutex_unlock (ximagesink->x_lock); + g_mutex_unlock (ximagesink->flow_lock); } static gpointer @@ -1543,7 +1578,8 @@ gst_ximagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf) put the ximage which is in the PRIVATE pointer */ if (GST_IS_XIMAGE_BUFFER (buf)) { GST_LOG_OBJECT (ximagesink, "buffer from our pool, writing directly"); - gst_ximagesink_ximage_put (ximagesink, GST_XIMAGE_BUFFER (buf)); + if (!gst_ximagesink_ximage_put (ximagesink, GST_XIMAGE_BUFFER (buf))) + goto no_window; } else { /* Else we have to copy the data into our private image, */ /* if we have one... */ @@ -1569,7 +1605,8 @@ gst_ximagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf) } memcpy (GST_BUFFER_DATA (ximagesink->ximage), GST_BUFFER_DATA (buf), MIN (GST_BUFFER_SIZE (buf), ximagesink->ximage->size)); - gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage); + if (!gst_ximagesink_ximage_put (ximagesink, ximagesink->ximage)) + goto no_window; } return GST_FLOW_OK; @@ -1581,6 +1618,12 @@ no_ximage: GST_DEBUG ("could not create image"); return GST_FLOW_ERROR; } +no_window: + { + /* No Window available to put our image into */ + GST_WARNING_OBJECT (ximagesink, "could not output image - no window"); + return GST_FLOW_ERROR; + } } /* Buffer management diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c index b225ce3..2f19443 100644 --- a/sys/xvimage/xvimagesink.c +++ b/sys/xvimage/xvimagesink.c @@ -719,15 +719,16 @@ gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink, } } -/* This function puts a GstXvImage on a GstXvImageSink's window */ -static void +/* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE + * if no window was available */ +static gboolean gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstXvImageBuffer * xvimage) { GstVideoRectangle src, dst, result; gboolean draw_border = FALSE; - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); + g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE); /* We take the flow_lock. If expose is in there we don't want to run concurrently from the data flow thread */ @@ -735,7 +736,7 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { g_mutex_unlock (xvimagesink->flow_lock); - return; + return FALSE; } /* Draw borders when displaying the first frame. After this @@ -762,7 +763,7 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, xvimage = xvimagesink->cur_image; } else { g_mutex_unlock (xvimagesink->flow_lock); - return; + return TRUE; } } @@ -821,6 +822,8 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->flow_lock); + + return TRUE; } static gboolean @@ -888,9 +891,18 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None); if (xvimagesink->handle_events) { + Atom wm_delete; + XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | StructureNotifyMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + + /* Tell the window manager we'd like delete client messages instead of + * being killed */ + wm_delete = XInternAtom (xvimagesink->xcontext->disp, + "WM_DELETE_WINDOW", False); + (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win, + &wm_delete, 1); } xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, @@ -1048,6 +1060,7 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) XEvent e; guint pointer_x = 0, pointer_y = 0; gboolean pointer_moved = FALSE; + gboolean exposed = FALSE, configured = FALSE; g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); @@ -1072,19 +1085,20 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) g_mutex_lock (xvimagesink->flow_lock); g_mutex_lock (xvimagesink->x_lock); } - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - if (pointer_moved) { + g_mutex_unlock (xvimagesink->x_lock); + g_mutex_unlock (xvimagesink->flow_lock); + GST_DEBUG ("xvimagesink pointer moved over window at %d,%d", pointer_x, pointer_y); gst_navigation_send_mouse_event (GST_NAVIGATION (xvimagesink), "mouse-move", 0, e.xbutton.x, e.xbutton.y); + + g_mutex_lock (xvimagesink->flow_lock); + g_mutex_lock (xvimagesink->x_lock); } /* We get all events on our window to throw them upstream */ - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); while (XCheckWindowEvent (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, @@ -1141,40 +1155,61 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) g_mutex_lock (xvimagesink->flow_lock); g_mutex_lock (xvimagesink->x_lock); } - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); /* Handle Expose */ - { - gboolean exposed = FALSE, configured = FALSE; - - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); - while (XCheckWindowEvent (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, - &e)) { - g_mutex_unlock (xvimagesink->x_lock); - g_mutex_unlock (xvimagesink->flow_lock); - - switch (e.type) { - case Expose: - exposed = TRUE; - break; - case ConfigureNotify: - configured = TRUE; - default: - break; - } - g_mutex_lock (xvimagesink->flow_lock); - g_mutex_lock (xvimagesink->x_lock); + while (XCheckWindowEvent (xvimagesink->xcontext->disp, + xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { + switch (e.type) { + case Expose: + exposed = TRUE; + break; + case ConfigureNotify: + configured = TRUE; + break; + default: + break; } + } + + if (exposed || configured) { g_mutex_unlock (xvimagesink->x_lock); g_mutex_unlock (xvimagesink->flow_lock); - if (exposed || configured) { - gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); + gst_xvimagesink_expose (GST_X_OVERLAY (xvimagesink)); + + g_mutex_lock (xvimagesink->x_lock); + g_mutex_lock (xvimagesink->flow_lock); + } + + /* Handle Display events */ + while (XPending (xvimagesink->xcontext->disp)) { + XNextEvent (xvimagesink->xcontext->disp, &e); + + switch (e.type) { + case ClientMessage:{ + Atom wm_delete; + + wm_delete = XInternAtom (xvimagesink->xcontext->disp, + "WM_DELETE_WINDOW", False); + if (wm_delete == (Atom) e.xclient.data.l[0]) { + /* Handle window deletion by posting an error on the bus */ + GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND, + ("Output window was closed"), (NULL)); + + g_mutex_unlock (xvimagesink->x_lock); + gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); + xvimagesink->xwindow = NULL; + g_mutex_lock (xvimagesink->x_lock); + } + break; + } + default: + break; } } + + g_mutex_unlock (xvimagesink->x_lock); + g_mutex_unlock (xvimagesink->flow_lock); } static void @@ -2114,7 +2149,8 @@ gst_xvimagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf) put the ximage which is in the PRIVATE pointer */ if (GST_IS_XVIMAGE_BUFFER (buf)) { GST_LOG_OBJECT (xvimagesink, "fast put of bufferpool buffer"); - gst_xvimagesink_xvimage_put (xvimagesink, GST_XVIMAGE_BUFFER (buf)); + if (!gst_xvimagesink_xvimage_put (xvimagesink, GST_XVIMAGE_BUFFER (buf))) + goto no_window; } else { GST_LOG_OBJECT (xvimagesink, "slow copy into bufferpool buffer"); /* Else we have to copy the data into our private image, */ @@ -2145,7 +2181,8 @@ gst_xvimagesink_show_frame (GstBaseSink * bsink, GstBuffer * buf) GST_BUFFER_DATA (buf), MIN (GST_BUFFER_SIZE (buf), xvimagesink->xvimage->size)); - gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage); + if (!gst_xvimagesink_xvimage_put (xvimagesink, xvimagesink->xvimage)) + goto no_window; } return GST_FLOW_OK; @@ -2157,6 +2194,12 @@ no_image: GST_WARNING_OBJECT (xvimagesink, "could not create image"); return GST_FLOW_ERROR; } +no_window: + { + /* No Window available to put our image into */ + GST_WARNING_OBJECT (xvimagesink, "could not output image - no window"); + return GST_FLOW_ERROR; + } } /* Buffer management */ -- 2.7.4