diff options
author | Benjamin Otte <otte@redhat.com> | 2017-11-24 10:13:23 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2017-12-03 05:46:47 +0100 |
commit | 12ca641ff5f901f72cd44bee5f9075b675fbc3e1 (patch) | |
tree | aa46c999da8437bb9ec1b1e016f0338a5472a0bc /gdk | |
parent | 888e5257e074c33f316d83213b57f2f2a77d6150 (diff) | |
download | gtk+-12ca641ff5f901f72cd44bee5f9075b675fbc3e1.tar.gz |
clipboard: Implement local fallback clipboard transfers
This requires implementing a "pipe" so we can have 2 streams running:
contentprovider => serializer => outputstream
inputstream => deserializer => reader
And the pipe shoves the data from the outputstream into the inputstream.
Diffstat (limited to 'gdk')
-rw-r--r-- | gdk/gdkclipboard.c | 130 | ||||
-rw-r--r-- | gdk/gdkclipboardprivate.h | 10 | ||||
-rw-r--r-- | gdk/gdkpipeiostream.c | 476 | ||||
-rw-r--r-- | gdk/gdkpipeiostreamprivate.h | 33 | ||||
-rw-r--r-- | gdk/meson.build | 1 |
5 files changed, 646 insertions, 4 deletions
diff --git a/gdk/gdkclipboard.c b/gdk/gdkclipboard.c index 7ba9632991..b19b0904aa 100644 --- a/gdk/gdkclipboard.c +++ b/gdk/gdkclipboard.c @@ -26,6 +26,7 @@ #include "gdkcontentproviderprivate.h" #include "gdkdisplay.h" #include "gdkintl.h" +#include "gdkpipeiostreamprivate.h" typedef struct _GdkClipboardPrivate GdkClipboardPrivate; @@ -124,6 +125,20 @@ gdk_clipboard_finalize (GObject *object) } static void +gdk_clipboard_read_local_write_done (GObject *clipboard, + GAsyncResult *result, + gpointer stream) +{ + /* we don't care about the error, we just want to clean up */ + gdk_clipboard_write_finish (GDK_CLIPBOARD (clipboard), result, NULL); + + /* XXX: Do we need to close_async() here? */ + g_output_stream_close (stream, NULL, NULL); + + g_object_unref (stream); +} + +static void gdk_clipboard_read_local_async (GdkClipboard *clipboard, GdkContentFormats *formats, int io_priority, @@ -132,24 +147,51 @@ gdk_clipboard_read_local_async (GdkClipboard *clipboard, gpointer user_data) { GdkClipboardPrivate *priv = gdk_clipboard_get_instance_private (clipboard); + GdkContentFormats *content_formats; + const char *mime_type; GTask *task; task = g_task_new (clipboard, cancellable, callback, user_data); g_task_set_priority (task, io_priority); g_task_set_source_tag (task, gdk_clipboard_read_local_async); - g_task_set_task_data (task, gdk_content_formats_ref (formats), (GDestroyNotify) gdk_content_formats_unref); if (priv->content == NULL) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Cannot read from empty clipboard.")); + g_object_unref (task); + return; } - else + + content_formats = gdk_content_provider_ref_formats (priv->content); + + if (!gdk_content_formats_match (content_formats, formats, NULL, &mime_type) + || mime_type == NULL) { g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - _("Reading local content via streams not supported yet.")); + _("No compatible formats to transfer clipboard contents.")); + } + else + { + GOutputStream *output_stream; + GIOStream *stream; + + stream = gdk_pipe_io_stream_new (); + output_stream = g_io_stream_get_output_stream (stream); + gdk_clipboard_write_async (clipboard, + mime_type, + output_stream, + io_priority, + cancellable, + gdk_clipboard_read_local_write_done, + g_object_ref (output_stream)); + g_task_set_task_data (task, (gpointer) mime_type, NULL); + g_task_return_pointer (task, g_object_ref (g_io_stream_get_input_stream (stream)), g_object_unref); + + g_object_unref (stream); } + gdk_content_formats_unref (content_formats); g_object_unref (task); } @@ -163,7 +205,7 @@ gdk_clipboard_read_local_finish (GdkClipboard *clipboard, g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_clipboard_read_local_async, NULL); if (out_mime_type) - *out_mime_type = NULL; + *out_mime_type = g_task_get_task_data (G_TASK (result)); return g_task_propagate_pointer (G_TASK (result), error); } @@ -770,6 +812,86 @@ gdk_clipboard_new (GdkDisplay *display) } static void +gdk_clipboard_write_done (GObject *content, + GAsyncResult *result, + gpointer task) +{ + GError *error = NULL; + + if (gdk_content_provider_write_mime_type_finish (GDK_CONTENT_PROVIDER (content), result, &error)) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); + + g_object_unref (task); +} + +void +gdk_clipboard_write_async (GdkClipboard *clipboard, + const char *mime_type, + GOutputStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GdkClipboardPrivate *priv = gdk_clipboard_get_instance_private (clipboard); + GdkContentFormats *formats; + GTask *task; + + g_return_if_fail (GDK_IS_CLIPBOARD (clipboard)); + g_return_if_fail (priv->local); + g_return_if_fail (mime_type != NULL); + g_return_if_fail (mime_type == g_intern_string (mime_type)); + g_return_if_fail (G_IS_OUTPUT_STREAM (stream)); + g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); + g_return_if_fail (callback != NULL); + + task = g_task_new (clipboard, cancellable, callback, user_data); + g_task_set_priority (task, io_priority); + g_task_set_source_tag (task, gdk_clipboard_write_async); + + if (priv->content == NULL) + { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + _("Cannot read from empty clipboard.")); + g_object_unref (task); + return; + } + + formats = gdk_content_provider_ref_formats (priv->content); + if (gdk_content_formats_contain_mime_type (formats, mime_type)) + { + gdk_content_provider_write_mime_type_async (priv->content, + mime_type, + stream, + io_priority, + cancellable, + gdk_clipboard_write_done, + task); + gdk_content_formats_unref (formats); + return; + } + + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("FIXME: Implement serializing.")); + gdk_content_formats_unref (formats); + g_object_unref (task); + return; +} + +gboolean +gdk_clipboard_write_finish (GdkClipboard *clipboard, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, clipboard), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gdk_clipboard_write_async, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +static void gdk_clipboard_content_changed_cb (GdkContentProvider *provider, GdkClipboard *clipboard); diff --git a/gdk/gdkclipboardprivate.h b/gdk/gdkclipboardprivate.h index b171068a5f..73b198eacf 100644 --- a/gdk/gdkclipboardprivate.h +++ b/gdk/gdkclipboardprivate.h @@ -57,6 +57,16 @@ GdkClipboard * gdk_clipboard_new (GdkDisplay void gdk_clipboard_claim_remote (GdkClipboard *clipboard, GdkContentFormats *formats); +void gdk_clipboard_write_async (GdkClipboard *clipboard, + const char *mime_type, + GOutputStream *stream, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean gdk_clipboard_write_finish (GdkClipboard *clipboard, + GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/gdk/gdkpipeiostream.c b/gdk/gdkpipeiostream.c new file mode 100644 index 0000000000..c7e0b6c32e --- /dev/null +++ b/gdk/gdkpipeiostream.c @@ -0,0 +1,476 @@ +/* GDK - The GIMP Drawing Kit + * + * Copyright (C) 2017 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include "gdkpipeiostreamprivate.h" + +#include <string.h> + +/* PIPE */ + +typedef enum { + GDK_IO_PIPE_EMPTY, + GDK_IO_PIPE_INPUT_BUFFER, + GDK_IO_PIPE_OUTPUT_BUFFER +} GdkIOPipeState; + +typedef struct _GdkIOPipe GdkIOPipe; + +struct _GdkIOPipe +{ + gint ref_count; + + GMutex mutex; + GCond cond; + guchar *buffer; + gsize size; + GdkIOPipeState state : 2; + guint input_closed : 1; + guint output_closed : 1; +}; + +static GdkIOPipe * +gdk_io_pipe_new (void) +{ + GdkIOPipe *pipe; + + pipe = g_slice_new0 (GdkIOPipe); + pipe->ref_count = 1; + + g_mutex_init (&pipe->mutex); + g_cond_init (&pipe->cond); + + return pipe; +} + +static GdkIOPipe * +gdk_io_pipe_ref (GdkIOPipe *pipe) +{ + g_atomic_int_inc (&pipe->ref_count); + + return pipe; +} + +static void +gdk_io_pipe_unref (GdkIOPipe *pipe) +{ + if (!g_atomic_int_dec_and_test (&pipe->ref_count)) + return; + + g_cond_clear (&pipe->cond); + g_mutex_clear (&pipe->mutex); +} + +static void +gdk_io_pipe_lock (GdkIOPipe *pipe) +{ + g_mutex_lock (&pipe->mutex); +} + +static void +gdk_io_pipe_unlock (GdkIOPipe *pipe) +{ + g_mutex_unlock (&pipe->mutex); +} + +/* INPUT STREAM */ + +#define GDK_TYPE_PIPE_INPUT_STREAM (gdk_pipe_input_stream_get_type ()) +#define GDK_PIPE_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PIPE_INPUT_STREAM, GdkPipeInputStream)) +#define GDK_IS_PIPE_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PIPE_INPUT_STREAM)) +#define GDK_PIPE_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIPE_INPUT_STREAM, GdkPipeInputStreamClass)) +#define GDK_IS_PIPE_INPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIPE_INPUT_STREAM)) +#define GDK_PIPE_INPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIPE_INPUT_STREAM, GdkPipeInputStreamClass)) + +typedef struct _GdkPipeInputStream GdkPipeInputStream; +typedef struct _GdkPipeInputStreamClass GdkPipeInputStreamClass; + +struct _GdkPipeInputStream +{ + GInputStream parent; + + GdkIOPipe *pipe; +}; + +struct _GdkPipeInputStreamClass +{ + GInputStreamClass parent_class; +}; + +GType gdk_pipe_input_stream_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE (GdkPipeInputStream, gdk_pipe_input_stream, G_TYPE_INPUT_STREAM) + +static void +gdk_pipe_input_stream_finalize (GObject *object) +{ + GdkPipeInputStream *pipe = GDK_PIPE_INPUT_STREAM (object); + + g_clear_pointer (&pipe->pipe, gdk_io_pipe_unref); + + G_OBJECT_CLASS (gdk_pipe_input_stream_parent_class)->finalize (object); +} + +static gssize +gdk_pipe_input_stream_read (GInputStream *stream, + void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + GdkPipeInputStream *pipe_stream = GDK_PIPE_INPUT_STREAM (stream); + GdkIOPipe *pipe = pipe_stream->pipe; + gsize amount; + + gdk_io_pipe_lock (pipe); + + switch (pipe->state) + { + case GDK_IO_PIPE_EMPTY: + if (pipe->output_closed) + { + amount = 0; + break; + } + pipe->buffer = buffer; + pipe->size = count; + pipe->state = GDK_IO_PIPE_INPUT_BUFFER; + do + g_cond_wait (&pipe->cond, &pipe->mutex); + while (pipe->size == count && + pipe->state == GDK_IO_PIPE_INPUT_BUFFER && + !pipe->output_closed); + if (pipe->state == GDK_IO_PIPE_INPUT_BUFFER) + { + amount = count - pipe->size; + pipe->state = GDK_IO_PIPE_EMPTY; + pipe->size = 0; + } + else + { + amount = count; + } + break; + + case GDK_IO_PIPE_OUTPUT_BUFFER: + amount = MIN (count, pipe->size); + + memcpy (buffer, pipe->buffer, amount); + count -= amount; + pipe->size -= amount; + + if (pipe->size == 0) + pipe->state = GDK_IO_PIPE_EMPTY; + else + pipe->buffer += amount; + break; + + case GDK_IO_PIPE_INPUT_BUFFER: + default: + g_assert_not_reached (); + amount = 0; + break; + } + + g_cond_broadcast (&pipe->cond); + gdk_io_pipe_unlock (pipe); + + return amount; +} + +static gboolean +gdk_pipe_input_stream_close (GInputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GdkPipeInputStream *pipe_stream = GDK_PIPE_INPUT_STREAM (stream); + GdkIOPipe *pipe = pipe_stream->pipe; + + gdk_io_pipe_lock (pipe); + + pipe->input_closed = TRUE; + g_cond_broadcast (&pipe->cond); + + gdk_io_pipe_unlock (pipe); + + return TRUE; +} + +static void +gdk_pipe_input_stream_class_init (GdkPipeInputStreamClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GInputStreamClass *input_stream_class = G_INPUT_STREAM_CLASS (class); + + object_class->finalize = gdk_pipe_input_stream_finalize; + + input_stream_class->read_fn = gdk_pipe_input_stream_read; + input_stream_class->close_fn = gdk_pipe_input_stream_close; +} + +static void +gdk_pipe_input_stream_init (GdkPipeInputStream *pipe) +{ +} + +/* OUTPUT STREAM */ + +#define GDK_TYPE_PIPE_OUTPUT_STREAM (gdk_pipe_output_stream_get_type ()) +#define GDK_PIPE_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PIPE_OUTPUT_STREAM, GdkPipeOutputStream)) +#define GDK_IS_PIPE_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PIPE_OUTPUT_STREAM)) +#define GDK_PIPE_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIPE_OUTPUT_STREAM, GdkPipeOutputStreamClass)) +#define GDK_IS_PIPE_OUTPUT_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIPE_OUTPUT_STREAM)) +#define GDK_PIPE_OUTPUT_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIPE_OUTPUT_STREAM, GdkPipeOutputStreamClass)) + +typedef struct _GdkPipeOutputStream GdkPipeOutputStream; +typedef struct _GdkPipeOutputStreamClass GdkPipeOutputStreamClass; + +struct _GdkPipeOutputStream +{ + GOutputStream parent; + + GdkIOPipe *pipe; +}; + +struct _GdkPipeOutputStreamClass +{ + GOutputStreamClass parent_class; +}; + +GType gdk_pipe_output_stream_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE (GdkPipeOutputStream, gdk_pipe_output_stream, G_TYPE_OUTPUT_STREAM) + +static void +gdk_pipe_output_stream_finalize (GObject *object) +{ + GdkPipeOutputStream *pipe = GDK_PIPE_OUTPUT_STREAM (object); + + g_clear_pointer (&pipe->pipe, gdk_io_pipe_unref); + + G_OBJECT_CLASS (gdk_pipe_output_stream_parent_class)->finalize (object); +} + +static gssize +gdk_pipe_output_stream_write (GOutputStream *stream, + const void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + GdkPipeOutputStream *pipe_stream = GDK_PIPE_OUTPUT_STREAM (stream); + GdkIOPipe *pipe = pipe_stream->pipe; + gsize amount; + + gdk_io_pipe_lock (pipe); + + switch (pipe->state) + { + case GDK_IO_PIPE_EMPTY: + pipe->buffer = (void *) buffer; + pipe->size = count; + pipe->state = GDK_IO_PIPE_OUTPUT_BUFFER; + while (pipe->size == count && + pipe->state == GDK_IO_PIPE_OUTPUT_BUFFER && + !pipe->input_closed) + g_cond_wait (&pipe->cond, &pipe->mutex); + if (pipe->state == GDK_IO_PIPE_OUTPUT_BUFFER) + { + amount = count - pipe->size; + pipe->state = GDK_IO_PIPE_EMPTY; + pipe->size = 0; + if (pipe->input_closed && amount == 0) + amount = count; + } + else + { + amount = count; + } + break; + + case GDK_IO_PIPE_INPUT_BUFFER: + amount = MIN (count, pipe->size); + + memcpy (pipe->buffer, buffer, amount); + count -= amount; + pipe->size -= amount; + + if (pipe->size == 0) + pipe->state = GDK_IO_PIPE_EMPTY; + else + pipe->buffer += amount; + break; + + case GDK_IO_PIPE_OUTPUT_BUFFER: + default: + g_assert_not_reached (); + amount = 0; + break; + } + + g_cond_broadcast (&pipe->cond); + gdk_io_pipe_unlock (pipe); + + return amount; +} + +static gboolean +gdk_pipe_output_stream_close (GOutputStream *stream, + GCancellable *cancellable, + GError **error) +{ + GdkPipeOutputStream *pipe_stream = GDK_PIPE_OUTPUT_STREAM (stream); + GdkIOPipe *pipe = pipe_stream->pipe; + + gdk_io_pipe_lock (pipe); + + pipe->output_closed = TRUE; + + g_cond_broadcast (&pipe->cond); + gdk_io_pipe_unlock (pipe); + + return TRUE; +} + +static void +gdk_pipe_output_stream_class_init (GdkPipeOutputStreamClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GOutputStreamClass *output_stream_class = G_OUTPUT_STREAM_CLASS (class); + + object_class->finalize = gdk_pipe_output_stream_finalize; + + output_stream_class->write_fn = gdk_pipe_output_stream_write; + output_stream_class->close_fn = gdk_pipe_output_stream_close; +} + +static void +gdk_pipe_output_stream_init (GdkPipeOutputStream *pipe) +{ +} + +/* IOSTREAM */ + +#define GDK_TYPE_PIPE_IO_STREAM (gdk_pipe_io_stream_get_type ()) +#define GDK_PIPE_IO_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_PIPE_IO_STREAM, GdkPipeIOStream)) +#define GDK_IS_PIPE_IO_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_PIPE_IO_STREAM)) +#define GDK_PIPE_IO_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_PIPE_IO_STREAM, GdkPipeIOStreamClass)) +#define GDK_IS_PIPE_IO_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_PIPE_IO_STREAM)) +#define GDK_PIPE_IO_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_PIPE_IO_STREAM, GdkPipeIOStreamClass)) + +typedef struct _GdkPipeIOStream GdkPipeIOStream; +typedef struct _GdkPipeIOStreamClass GdkPipeIOStreamClass; + +struct _GdkPipeIOStream +{ + GIOStream parent; + + GInputStream *input_stream; + GOutputStream *output_stream; + GdkIOPipe *pipe; +}; + +struct _GdkPipeIOStreamClass +{ + GIOStreamClass parent_class; +}; + +GType gdk_pipe_io_stream_get_type (void) G_GNUC_CONST; + +G_DEFINE_TYPE (GdkPipeIOStream, gdk_pipe_io_stream, G_TYPE_IO_STREAM) + +static void +gdk_pipe_io_stream_finalize (GObject *object) +{ + GdkPipeIOStream *pipe = GDK_PIPE_IO_STREAM (object); + + g_clear_object (&pipe->input_stream); + g_clear_object (&pipe->output_stream); + g_clear_pointer (&pipe->pipe, gdk_io_pipe_unref); + + G_OBJECT_CLASS (gdk_pipe_io_stream_parent_class)->finalize (object); +} + +static GInputStream * +gdk_pipe_io_stream_get_input_stream (GIOStream *stream) +{ + GdkPipeIOStream *pipe = GDK_PIPE_IO_STREAM (stream); + + return pipe->input_stream; +} + +static GOutputStream * +gdk_pipe_io_stream_get_output_stream (GIOStream *stream) +{ + GdkPipeIOStream *pipe = GDK_PIPE_IO_STREAM (stream); + + return pipe->output_stream; +} + +static gboolean +gdk_pipe_io_stream_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) +{ + /* overwrite so we don't close the 2 streams */ + return TRUE; +} + +static void +gdk_pipe_io_stream_class_init (GdkPipeIOStreamClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GIOStreamClass *io_class = G_IO_STREAM_CLASS (class); + + object_class->finalize = gdk_pipe_io_stream_finalize; + + io_class->get_input_stream = gdk_pipe_io_stream_get_input_stream; + io_class->get_output_stream = gdk_pipe_io_stream_get_output_stream; + io_class->close_fn = gdk_pipe_io_stream_close; +} + +static void +gdk_pipe_io_stream_init (GdkPipeIOStream *pipe) +{ + pipe->pipe = gdk_io_pipe_new (); + + pipe->input_stream = g_object_new (GDK_TYPE_PIPE_INPUT_STREAM, NULL); + GDK_PIPE_INPUT_STREAM (pipe->input_stream)->pipe = gdk_io_pipe_ref (pipe->pipe); + + pipe->output_stream = g_object_new (GDK_TYPE_PIPE_OUTPUT_STREAM, NULL); + GDK_PIPE_OUTPUT_STREAM (pipe->output_stream)->pipe = gdk_io_pipe_ref (pipe->pipe); +} + +/** + * gdk_pipe_io_stream_new: + * + * Creates a #GIOStream whose input- and output-stream behave like a pipe. + * Data written into the output stream becomes available for reading on + * the input stream. + * + * Note that this is data transfer in the opposite direction to + * g_output_stream_splice(). + * + * Returns: a new #GIOStream + **/ +GIOStream * +gdk_pipe_io_stream_new (void) +{ + return g_object_new (GDK_TYPE_PIPE_IO_STREAM, NULL); +} diff --git a/gdk/gdkpipeiostreamprivate.h b/gdk/gdkpipeiostreamprivate.h new file mode 100644 index 0000000000..50af59defe --- /dev/null +++ b/gdk/gdkpipeiostreamprivate.h @@ -0,0 +1,33 @@ +/* GDK - The GIMP Drawing Kit + * + * Copyright (C) 2017 Benjamin Otte <otte@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GDK_PIPE_IO_STREAM_H__ +#define __GDK_PIPE_IO_STREAM_H__ + +#include <gdk/gdkversionmacros.h> +#include <gio/gio.h> + +G_BEGIN_DECLS + + +GIOStream * gdk_pipe_io_stream_new (void); + + +G_END_DECLS + +#endif /* __GDK_PIPE_IO_STREAM_H__ */ diff --git a/gdk/meson.build b/gdk/meson.build index 968dd5d14f..b13e9c79da 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -28,6 +28,7 @@ gdk_public_sources = files([ 'gdkmonitor.c', 'gdkpango.c', 'gdkpixbuf-drawable.c', + 'gdkpipeiostream.c', 'gdkproperty.c', 'gdkrectangle.c', 'gdkrgba.c', |