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.
This commit is contained in:
Jan Schmidt 2007-05-17 17:35:46 +00:00
parent a18a10e81f
commit cbc95dfb3d
3 changed files with 205 additions and 99 deletions

View file

@ -1,3 +1,23 @@
2007-05-17 Jan Schmidt <thaytan@mad.scientist.com>
* 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 <wim@fluendo.com>
* gst/playback/gstdecodebin2.c: (gst_decode_bin_factory_filter):

View file

@ -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);
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);
}
/* 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);
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);
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);
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

View file

@ -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 */