core: Cater for reading selection in chunks

For the cases where we read a fixed size from the selection (eg. imposing
limits for the clipboard manager), g_input_stream_read_bytes_async() might
not read up to this given size if the other side is spoonfeeding it content.

Cater for multiple read/write cycles here, until (maximum) transfer size is
reached.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1198

(cherry picked from commit 4bdf9a1e70)
This commit is contained in:
Carlos Garnacho 2020-04-14 14:01:40 +02:00 committed by Robert Mader
parent 20cf6b630d
commit 456e6f345d

View File

@ -50,6 +50,9 @@ static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE (MetaSelection, meta_selection, G_TYPE_OBJECT) G_DEFINE_TYPE (MetaSelection, meta_selection, G_TYPE_OBJECT)
static void read_selection_source_async (GTask *task,
TransferRequest *request);
static void static void
meta_selection_dispose (GObject *object) meta_selection_dispose (GObject *object)
{ {
@ -216,6 +219,7 @@ write_cb (GOutputStream *stream,
GAsyncResult *result, GAsyncResult *result,
GTask *task) GTask *task)
{ {
TransferRequest *request;
GError *error = NULL; GError *error = NULL;
g_output_stream_write_bytes_finish (stream, result, &error); g_output_stream_write_bytes_finish (stream, result, &error);
@ -226,8 +230,17 @@ write_cb (GOutputStream *stream,
return; return;
} }
g_task_return_boolean (task, TRUE); request = g_task_get_task_data (task);
g_object_unref (task);
if (request->len > 0)
{
read_selection_source_async (task, request);
}
else
{
g_task_return_boolean (task, TRUE);
g_object_unref (task);
}
} }
static void static void
@ -246,8 +259,26 @@ read_cb (GInputStream *stream,
g_object_unref (task); g_object_unref (task);
return; return;
} }
else if (g_bytes_get_size (bytes) == 0)
{
g_task_return_boolean (task, TRUE);
g_object_unref (task);
return;
}
request = g_task_get_task_data (task); request = g_task_get_task_data (task);
if (request->len < g_bytes_get_size (bytes))
{
GBytes *copy;
/* Trim content */
copy = g_bytes_new_from_bytes (bytes, 0, request->len);
g_bytes_unref (bytes);
bytes = copy;
}
request->len -= g_bytes_get_size (bytes);
g_output_stream_write_bytes_async (request->ostream, g_output_stream_write_bytes_async (request->ostream,
bytes, bytes,
G_PRIORITY_DEFAULT, G_PRIORITY_DEFAULT,
@ -257,6 +288,18 @@ read_cb (GInputStream *stream,
g_bytes_unref (bytes); g_bytes_unref (bytes);
} }
static void
read_selection_source_async (GTask *task,
TransferRequest *request)
{
g_input_stream_read_bytes_async (request->istream,
(gsize) request->len,
G_PRIORITY_DEFAULT,
g_task_get_cancellable (task),
(GAsyncReadyCallback) read_cb,
task);
}
static void static void
source_read_cb (MetaSelectionSource *source, source_read_cb (MetaSelectionSource *source,
GAsyncResult *result, GAsyncResult *result,
@ -290,12 +333,7 @@ source_read_cb (MetaSelectionSource *source,
} }
else else
{ {
g_input_stream_read_bytes_async (request->istream, read_selection_source_async (task, request);
(gsize) request->len,
G_PRIORITY_DEFAULT,
g_task_get_cancellable (task),
(GAsyncReadyCallback) read_cb,
task);
} }
} }