x11: Handle windowing errors while writing selection INCR data
This error was just logged but not raised. Do as the code comment said and raise a pipe error at that moment, and for subsequent operations on the output stream (although none besides close() should be expected after propagating the error properly). Related: https://gitlab.gnome.org/GNOME/mutter/issues/1065
This commit is contained in:
parent
a13d60aae5
commit
2ecbf6d746
@ -53,6 +53,7 @@ struct _MetaX11SelectionOutputStreamPrivate
|
|||||||
|
|
||||||
guint incr : 1;
|
guint incr : 1;
|
||||||
guint delete_pending : 1;
|
guint delete_pending : 1;
|
||||||
|
guint pipe_error : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE_WITH_PRIVATE (MetaX11SelectionOutputStream,
|
G_DEFINE_TYPE_WITH_PRIVATE (MetaX11SelectionOutputStream,
|
||||||
@ -167,6 +168,25 @@ get_element_size (int format)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_x11_selection_output_stream_check_pipe (MetaX11SelectionOutputStream *stream,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MetaX11SelectionOutputStreamPrivate *priv =
|
||||||
|
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||||
|
|
||||||
|
if (priv->pipe_error)
|
||||||
|
{
|
||||||
|
g_set_error (error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_BROKEN_PIPE,
|
||||||
|
"Connection with client was broken");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *stream)
|
meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *stream)
|
||||||
{
|
{
|
||||||
@ -174,6 +194,7 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
|
|||||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||||
Display *xdisplay;
|
Display *xdisplay;
|
||||||
size_t element_size, n_elements;
|
size_t element_size, n_elements;
|
||||||
|
int error_code;
|
||||||
|
|
||||||
g_assert (!priv->delete_pending);
|
g_assert (!priv->delete_pending);
|
||||||
|
|
||||||
@ -230,18 +251,28 @@ meta_x11_selection_output_stream_perform_flush (MetaX11SelectionOutputStream *st
|
|||||||
g_cond_broadcast (&priv->cond);
|
g_cond_broadcast (&priv->cond);
|
||||||
g_mutex_unlock (&priv->mutex);
|
g_mutex_unlock (&priv->mutex);
|
||||||
|
|
||||||
/* XXX: handle failure here and report EPIPE for future operations on the stream? */
|
error_code = meta_x11_error_trap_pop_with_return (priv->x11_display);
|
||||||
if (meta_x11_error_trap_pop_with_return (priv->x11_display))
|
|
||||||
g_warning ("Failed to flush selection output stream");
|
|
||||||
|
|
||||||
if (priv->pending_task)
|
if (error_code != Success)
|
||||||
|
{
|
||||||
|
char error_str[100];
|
||||||
|
|
||||||
|
XGetErrorText (xdisplay, error_code, error_str, sizeof (error_str));
|
||||||
|
g_task_return_new_error (priv->pending_task,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_BROKEN_PIPE,
|
||||||
|
"Failed to flush selection output stream: %s",
|
||||||
|
error_str);
|
||||||
|
g_clear_object (&priv->pending_task);
|
||||||
|
priv->pipe_error = TRUE;
|
||||||
|
}
|
||||||
|
else if (priv->pending_task)
|
||||||
{
|
{
|
||||||
size_t result;
|
size_t result;
|
||||||
|
|
||||||
result = GPOINTER_TO_SIZE (g_task_get_task_data (priv->pending_task));
|
result = GPOINTER_TO_SIZE (g_task_get_task_data (priv->pending_task));
|
||||||
g_task_return_int (priv->pending_task, result);
|
g_task_return_int (priv->pending_task, result);
|
||||||
g_object_unref (priv->pending_task);
|
g_clear_object (&priv->pending_task);
|
||||||
priv->pending_task = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +301,9 @@ meta_x11_selection_output_stream_write (GOutputStream *output_stream,
|
|||||||
MetaX11SelectionOutputStreamPrivate *priv =
|
MetaX11SelectionOutputStreamPrivate *priv =
|
||||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||||
|
|
||||||
|
if (!meta_x11_selection_output_stream_check_pipe (stream, error))
|
||||||
|
return -1;
|
||||||
|
|
||||||
g_mutex_lock (&priv->mutex);
|
g_mutex_lock (&priv->mutex);
|
||||||
g_byte_array_append (priv->data, buffer, count);
|
g_byte_array_append (priv->data, buffer, count);
|
||||||
g_mutex_unlock (&priv->mutex);
|
g_mutex_unlock (&priv->mutex);
|
||||||
@ -297,12 +331,19 @@ meta_x11_selection_output_stream_write_async (GOutputStream *output_stream
|
|||||||
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
|
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
|
||||||
MetaX11SelectionOutputStreamPrivate *priv =
|
MetaX11SelectionOutputStreamPrivate *priv =
|
||||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||||
|
GError *error = NULL;
|
||||||
GTask *task;
|
GTask *task;
|
||||||
|
|
||||||
task = g_task_new (stream, cancellable, callback, user_data);
|
task = g_task_new (stream, cancellable, callback, user_data);
|
||||||
g_task_set_source_tag (task, meta_x11_selection_output_stream_write_async);
|
g_task_set_source_tag (task, meta_x11_selection_output_stream_write_async);
|
||||||
g_task_set_priority (task, io_priority);
|
g_task_set_priority (task, io_priority);
|
||||||
|
|
||||||
|
if (!meta_x11_selection_output_stream_check_pipe (stream, &error))
|
||||||
|
{
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_mutex_lock (&priv->mutex);
|
g_mutex_lock (&priv->mutex);
|
||||||
g_byte_array_append (priv->data, buffer, count);
|
g_byte_array_append (priv->data, buffer, count);
|
||||||
g_mutex_unlock (&priv->mutex);
|
g_mutex_unlock (&priv->mutex);
|
||||||
@ -369,6 +410,8 @@ meta_x11_selection_output_stream_flush (GOutputStream *output_stream,
|
|||||||
MetaX11SelectionOutputStreamPrivate *priv =
|
MetaX11SelectionOutputStreamPrivate *priv =
|
||||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||||
|
|
||||||
|
if (!meta_x11_selection_output_stream_check_pipe (stream, error))
|
||||||
|
return FALSE;
|
||||||
if (!meta_x11_selection_output_request_flush (stream))
|
if (!meta_x11_selection_output_request_flush (stream))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
@ -394,12 +437,19 @@ meta_x11_selection_output_stream_flush_async (GOutputStream *output_stream
|
|||||||
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
|
META_X11_SELECTION_OUTPUT_STREAM (output_stream);
|
||||||
MetaX11SelectionOutputStreamPrivate *priv =
|
MetaX11SelectionOutputStreamPrivate *priv =
|
||||||
meta_x11_selection_output_stream_get_instance_private (stream);
|
meta_x11_selection_output_stream_get_instance_private (stream);
|
||||||
|
GError *error = NULL;
|
||||||
GTask *task;
|
GTask *task;
|
||||||
|
|
||||||
task = g_task_new (stream, cancellable, callback, user_data);
|
task = g_task_new (stream, cancellable, callback, user_data);
|
||||||
g_task_set_source_tag (task, meta_x11_selection_output_stream_flush_async);
|
g_task_set_source_tag (task, meta_x11_selection_output_stream_flush_async);
|
||||||
g_task_set_priority (task, io_priority);
|
g_task_set_priority (task, io_priority);
|
||||||
|
|
||||||
|
if (!meta_x11_selection_output_stream_check_pipe (stream, &error))
|
||||||
|
{
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!meta_x11_selection_output_stream_can_flush (stream))
|
if (!meta_x11_selection_output_stream_can_flush (stream))
|
||||||
{
|
{
|
||||||
if (meta_x11_selection_output_request_flush (stream))
|
if (meta_x11_selection_output_request_flush (stream))
|
||||||
|
Loading…
Reference in New Issue
Block a user