mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 13:11:13 +00:00
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.
This commit is contained in:
parent
888e5257e0
commit
12ca641ff5
@ -26,6 +26,7 @@
|
||||
#include "gdkcontentproviderprivate.h"
|
||||
#include "gdkdisplay.h"
|
||||
#include "gdkintl.h"
|
||||
#include "gdkpipeiostreamprivate.h"
|
||||
|
||||
typedef struct _GdkClipboardPrivate GdkClipboardPrivate;
|
||||
|
||||
@ -123,6 +124,20 @@ gdk_clipboard_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (gdk_clipboard_parent_class)->finalize (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,
|
||||
@ -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;
|
||||
}
|
||||
|
||||
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,
|
||||
_("No compatible formats to transfer clipboard contents."));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("Reading local content via streams not supported yet."));
|
||||
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);
|
||||
}
|
||||
@ -769,6 +811,86 @@ gdk_clipboard_new (GdkDisplay *display)
|
||||
NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -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
|
||||
|
||||
|
476
gdk/gdkpipeiostream.c
Normal file
476
gdk/gdkpipeiostream.c
Normal file
@ -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);
|
||||
}
|
33
gdk/gdkpipeiostreamprivate.h
Normal file
33
gdk/gdkpipeiostreamprivate.h
Normal file
@ -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__ */
|
@ -28,6 +28,7 @@ gdk_public_sources = files([
|
||||
'gdkmonitor.c',
|
||||
'gdkpango.c',
|
||||
'gdkpixbuf-drawable.c',
|
||||
'gdkpipeiostream.c',
|
||||
'gdkproperty.c',
|
||||
'gdkrectangle.c',
|
||||
'gdkrgba.c',
|
||||
|
@ -182,7 +182,7 @@ get_button_list (GdkClipboard *clipboard)
|
||||
add_provider_button (box,
|
||||
gdk_content_provider_new_for_value (&value),
|
||||
clipboard,
|
||||
"Icon");
|
||||
"GdkPixbuf");
|
||||
g_value_unset (&value);
|
||||
|
||||
g_value_init (&value, G_TYPE_STRING);
|
||||
@ -190,9 +190,16 @@ get_button_list (GdkClipboard *clipboard)
|
||||
add_provider_button (box,
|
||||
gdk_content_provider_new_for_value (&value),
|
||||
clipboard,
|
||||
"Text");
|
||||
"gchararry");
|
||||
g_value_unset (&value);
|
||||
|
||||
add_provider_button (box,
|
||||
gdk_content_provider_new_for_bytes ("text/plain;charset=utf-8",
|
||||
g_bytes_new_static ("𝕳𝖊𝖑𝖑𝖔 𝖀𝖓𝖎𝖈𝖔𝖉𝖊",
|
||||
strlen ("𝕳𝖊𝖑𝖑𝖔 𝖀𝖓𝖎𝖈𝖔𝖉𝖊") + 1)),
|
||||
clipboard,
|
||||
"text/plain");
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user