[gtk+/wip/otte/clipboard: 2/2] x11: Improve fallbacks for text
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/otte/clipboard: 2/2] x11: Improve fallbacks for text
- Date: Thu, 23 Nov 2017 01:09:14 +0000 (UTC)
commit fbc40d167bd2686db20886341c52f0a73adbb81f
Author: Benjamin Otte <otte redhat com>
Date: Thu Nov 23 01:59:19 2017 +0100
x11: Improve fallbacks for text
(1) Try all passed in formats in order if one of them fails.
(2) Don't blindly accept all formats, make sure they are mime types
(3) Add a bunch of special non-mime types that plug converters to
get to mime types
gdk/x11/gdkclipboard-x11.c | 233 +++++++++++++++++++++++++++++----
gdk/x11/gdkselectioninputstream-x11.c | 28 ++++-
gdk/x11/gdkselectioninputstream-x11.h | 2 +
gdk/x11/gdktextlistconverter-x11.c | 169 ++++++++++++++++++++++++
gdk/x11/gdktextlistconverter-x11.h | 44 ++++++
gdk/x11/meson.build | 1 +
6 files changed, 444 insertions(+), 33 deletions(-)
---
diff --git a/gdk/x11/gdkclipboard-x11.c b/gdk/x11/gdkclipboard-x11.c
index 31b3bfe..ea710d5 100644
--- a/gdk/x11/gdkclipboard-x11.c
+++ b/gdk/x11/gdkclipboard-x11.c
@@ -19,8 +19,11 @@
#include "gdkclipboardprivate.h"
#include "gdkclipboard-x11.h"
-#include "gdkselectioninputstream-x11.h"
+
+#include "gdkintl.h"
#include "gdkprivate-x11.h"
+#include "gdkselectioninputstream-x11.h"
+#include "gdktextlistconverter-x11.h"
#include <string.h>
#include <X11/Xatom.h>
@@ -57,6 +60,121 @@ G_DEFINE_TYPE (GdkX11Clipboard, gdk_x11_clipboard, GDK_TYPE_CLIPBOARD)
? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \
: XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100)
+static GInputStream *
+text_list_convert (GdkX11Clipboard *cb,
+ GInputStream *stream,
+ const char *encoding,
+ int format)
+{
+ GInputStream *converter_stream;
+ GConverter *converter;
+
+ converter = gdk_x11_text_list_converter_to_utf8_new (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
+ encoding,
+ format);
+ converter_stream = g_converter_input_stream_new (stream, converter);
+
+ g_object_unref (converter);
+ g_object_unref (stream);
+
+ return converter_stream;
+}
+
+static GInputStream *
+no_convert (GdkX11Clipboard *cb,
+ GInputStream *stream,
+ const char *encoding,
+ int format)
+{
+ return stream;
+}
+
+static const struct {
+ const char *x_target;
+ const char *mime_type;
+ GInputStream * (* convert) (GdkX11Clipboard *, GInputStream *, const char *, int);
+} special_targets[] = {
+ { "UTF8_STRING", "text/plain;charset=utf-8", no_convert },
+ { "COMPOUND_TEXT", "text/plain;charset=utf-8", text_list_convert },
+ { "TEXT", "text/plain;charset=utf-8", text_list_convert },
+ { "STRING", "text/plain;charset=utf-8", text_list_convert }
+};
+
+static void
+print_atoms (GdkX11Clipboard *cb,
+ const char *prefix,
+ const Atom *atoms,
+ gsize n_atoms)
+{
+ GDK_NOTE(CLIPBOARD,
+ GdkDisplay *display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+ gsize i;
+
+ g_printerr ("%s: %s [ ", cb->selection, prefix);
+ for (i = 0; i < n_atoms; i++)
+ {
+ g_printerr ("%s%s", i > 0 ? ", " : "", gdk_x11_get_xatom_name_for_display (display ,
atoms[i]));
+ }
+ g_printerr (" ]\n");
+ );
+}
+
+static GSList *
+gdk_x11_clipboard_formats_to_targets (GdkContentFormats *formats)
+{
+ GSList *targets;
+ const char * const *mime_types;
+ gsize i, j, n_mime_types;
+
+ targets = NULL;
+ mime_types = gdk_content_formats_get_mime_types (formats, &n_mime_types);
+
+ for (i = 0; i < n_mime_types; i++)
+ {
+ for (j = 0; j < G_N_ELEMENTS (special_targets); j++)
+ {
+ if (g_str_equal (mime_types[i], special_targets[j].mime_type))
+ targets = g_slist_prepend (targets, (gpointer) g_intern_string (special_targets[i].x_target));
+ }
+ targets = g_slist_prepend (targets, (gpointer) mime_types[i]);
+ }
+
+ return g_slist_reverse (targets);
+}
+
+static GdkContentFormats *
+gdk_x11_clipboard_formats_from_atoms (GdkDisplay *display,
+ const Atom *atoms,
+ gsize n_atoms)
+{
+ GdkContentFormatsBuilder *builder;
+ gsize i, j;
+
+ builder = gdk_content_formats_builder_new ();
+ for (i = 0; i < n_atoms; i++)
+ {
+ const char *name;
+
+ name = gdk_x11_get_xatom_name_for_display (display , atoms[i]);
+ if (strchr (name, '/'))
+ {
+ gdk_content_formats_builder_add_mime_type (builder, name);
+ continue;
+ }
+
+ for (j = 0; j < G_N_ELEMENTS (special_targets); j++)
+ {
+ if (g_str_equal (name, special_targets[j].x_target))
+ {
+ gdk_content_formats_builder_add_mime_type (builder, special_targets[j].mime_type);
+ break;
+ }
+ }
+ }
+
+ return gdk_content_formats_builder_free (builder);
+}
+
static void
gdk_x11_clipboard_request_targets_finish (GObject *source_object,
GAsyncResult *res,
@@ -66,11 +184,8 @@ gdk_x11_clipboard_request_targets_finish (GObject *source_object,
GdkX11Clipboard *cb = user_data;
GdkDisplay *display;
GdkContentFormats *formats;
- GdkContentFormatsBuilder *builder;
GBytes *bytes;
GError *error = NULL;
- const Atom *atoms;
- guint i, n_atoms;
bytes = g_input_stream_read_bytes_finish (stream, res, &error);
if (bytes == NULL)
@@ -88,17 +203,15 @@ gdk_x11_clipboard_request_targets_finish (GObject *source_object,
return;
}
- display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+ print_atoms (cb,
+ "received targets",
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes) / sizeof (Atom));
- atoms = g_bytes_get_data (bytes, NULL);
- n_atoms = g_bytes_get_size (bytes) / sizeof (Atom);
- builder = gdk_content_formats_builder_new ();
- for (i = 0; i < n_atoms; i++)
- {
- gdk_content_formats_builder_add_mime_type (builder, gdk_x11_get_xatom_name_for_display (display ,
atoms[i]));
- }
- gdk_content_formats_builder_add_formats (builder, gdk_clipboard_get_formats (GDK_CLIPBOARD (cb)));
- formats = gdk_content_formats_builder_free (builder);
+ display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
+ formats = gdk_x11_clipboard_formats_from_atoms (display,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes) / sizeof (Atom));
GDK_NOTE(CLIPBOARD, char *s = gdk_content_formats_to_string (formats); g_printerr ("%s: got formats:
%s\n", cb->selection, s); g_free (s));
/* union with previously loaded formats */
@@ -122,13 +235,22 @@ gdk_x11_clipboard_request_targets_got_stream (GObject *source,
GInputStream *stream;
GdkDisplay *display;
GError *error = NULL;
+ const char *type;
+ int format;
- stream = gdk_x11_selection_input_stream_new_finish (result, &error);
+ stream = gdk_x11_selection_input_stream_new_finish (result, &type, &format, &error);
if (stream == NULL)
{
g_object_unref (cb);
return;
}
+ else if (!g_str_equal (type, "ATOM") || format != 32)
+ {
+ g_input_stream_close (stream, NULL, NULL);
+ g_object_unref (stream);
+ g_object_unref (cb);
+ return;
+ }
display = gdk_clipboard_get_display (GDK_CLIPBOARD (cb));
@@ -213,13 +335,61 @@ gdk_x11_clipboard_read_got_stream (GObject *source,
GTask *task = data;
GError *error = NULL;
GInputStream *stream;
+ const char *type;
+ int format;
- stream = gdk_x11_selection_input_stream_new_finish (res, &error);
- /* XXX: We could try more types here */
+ stream = gdk_x11_selection_input_stream_new_finish (res, &type, &format, &error);
if (stream == NULL)
- g_task_return_error (task, error);
+ {
+ GSList *targets, *next;
+
+ targets = g_task_get_task_data (task);
+ next = targets->next;
+ if (next)
+ {
+ GdkX11Clipboard *cb = GDK_X11_CLIPBOARD (g_task_get_source_object (task));
+
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: reading %s failed, trying %s next\n",
+ cb->selection, (char *) targets->data, (char *) next->data));
+ targets->next = NULL;
+ g_task_set_task_data (task, next, (GDestroyNotify) g_slist_free);
+ gdk_x11_selection_input_stream_new_async (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
+ cb->selection,
+ next->data,
+ cb->timestamp,
+ g_task_get_priority (task),
+ g_task_get_cancellable (task),
+ gdk_x11_clipboard_read_got_stream,
+ task);
+ g_error_free (error);
+ return;
+ }
+
+ g_task_return_error (task, error);
+ }
else
- g_task_return_pointer (task, stream, g_object_unref);
+ {
+ GdkX11Clipboard *cb = GDK_X11_CLIPBOARD (g_task_get_source_object (task));
+ const char *mime_type = ((GSList *) g_task_get_task_data (task))->data;
+ gsize i;
+
+ for (i = 0; i < G_N_ELEMENTS (special_targets); i++)
+ {
+ if (g_str_equal (mime_type, special_targets[i].x_target))
+ {
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: reading with converter from %s to %s\n",
+ cb->selection, mime_type, special_targets[i].mime_type));
+ mime_type = g_intern_string (special_targets[i].mime_type);
+ g_task_set_task_data (task, g_slist_prepend (NULL, (gpointer) mime_type), (GDestroyNotify)
g_slist_free);
+ stream = special_targets[i].convert (cb, stream, type, format);
+ break;
+ }
+ }
+
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: reading clipboard as %s now\n",
+ cb->selection, mime_type));
+ g_task_return_pointer (task, stream, g_object_unref);
+ }
g_object_unref (task);
}
@@ -233,20 +403,27 @@ gdk_x11_clipboard_read_async (GdkClipboard *clipboard,
gpointer user_data)
{
GdkX11Clipboard *cb = GDK_X11_CLIPBOARD (clipboard);
- const char * const *mime_types;
+ GSList *targets;
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_async);
- g_task_set_task_data (task, gdk_content_formats_ref (formats), (GDestroyNotify) gdk_content_formats_unref);
- /* XXX: Sort differently? */
- mime_types = gdk_content_formats_get_mime_types (formats, NULL);
+ targets = gdk_x11_clipboard_formats_to_targets (formats);
+ g_task_set_task_data (task, targets, (GDestroyNotify) g_slist_free);
+ if (targets == NULL)
+ {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("No compatible transfer format found"));
+ return;
+ }
+ GDK_NOTE(CLIPBOARD, g_printerr ("%s: new read for %s (%u other options)\n",
+ cb->selection, (char *) targets->data, g_slist_length (targets->next)));
gdk_x11_selection_input_stream_new_async (gdk_clipboard_get_display (GDK_CLIPBOARD (cb)),
cb->selection,
- mime_types[0],
+ targets->data,
cb->timestamp,
io_priority,
cancellable,
@@ -273,12 +450,10 @@ gdk_x11_clipboard_read_finish (GdkClipboard *clipboard,
{
if (out_mime_type)
{
- GdkContentFormats *formats;
- const char * const *mime_types;
+ GSList *targets;
- formats = g_task_get_task_data (task);
- mime_types = gdk_content_formats_get_mime_types (formats, NULL);
- *out_mime_type = mime_types[0];
+ targets = g_task_get_task_data (task);
+ *out_mime_type = targets->data;
}
g_object_ref (stream);
}
diff --git a/gdk/x11/gdkselectioninputstream-x11.c b/gdk/x11/gdkselectioninputstream-x11.c
index f03b3d9..e62db50 100644
--- a/gdk/x11/gdkselectioninputstream-x11.c
+++ b/gdk/x11/gdkselectioninputstream-x11.c
@@ -40,6 +40,9 @@ struct GdkX11SelectionInputStreamPrivate {
Atom xtarget;
char *property;
Atom xproperty;
+ const char *type;
+ Atom xtype;
+ int format;
GTask *pending_task;
guchar *pending_data;
@@ -150,6 +153,8 @@ gdk_x11_selection_input_stream_complete (GdkX11SelectionInputStream *stream)
if (priv->complete)
return;
+ GDK_NOTE(SELECTION, g_printerr ("%s:%s: transfer complete\n",
+ priv->selection, priv->target));
priv->complete = TRUE;
g_async_queue_push (priv->chunks, g_bytes_new (NULL, 0));
@@ -457,7 +462,8 @@ gdk_x11_selection_input_stream_filter_event (GdkXEvent *xev,
}
else
{
- bytes = get_selection_property (xdisplay, xwindow, xevent->xselection.property, &type, &format);
+ bytes = get_selection_property (xdisplay, xwindow, xevent->xselection.property, &priv->xtype,
&priv->format);
+ priv->type = gdk_x11_get_xatom_name_for_display (priv->display, priv->xtype);
g_task_return_pointer (task, g_object_ref (stream), g_object_unref);
@@ -477,6 +483,9 @@ gdk_x11_selection_input_stream_filter_event (GdkXEvent *xev,
}
else
{
+ GDK_NOTE(SELECTION, g_printerr ("%s:%s: reading %zu bytes\n",
+ priv->selection, priv->target,
+ g_bytes_get_size (bytes)));
g_async_queue_push (priv->chunks, bytes);
gdk_x11_selection_input_stream_complete (stream);
@@ -536,9 +545,11 @@ gdk_x11_selection_input_stream_new_async (GdkDisplay *display,
GInputStream *
gdk_x11_selection_input_stream_new_finish (GAsyncResult *result,
+ const char **type,
+ int *format,
GError **error)
{
- GInputStream *stream;
+ GdkX11SelectionInputStream *stream;
GTask *task;
g_return_val_if_fail (g_task_is_valid (result, NULL), NULL);
@@ -547,7 +558,16 @@ gdk_x11_selection_input_stream_new_finish (GAsyncResult *result,
stream = g_task_propagate_pointer (task, error);
if (stream)
- g_object_ref (stream);
- return stream;
+ {
+ GdkX11SelectionInputStreamPrivate *priv = gdk_x11_selection_input_stream_get_instance_private (stream);
+
+ if (type)
+ *type = priv->type;
+ if (format)
+ *format = priv->format;
+ g_object_ref (stream);
+ }
+
+ return G_INPUT_STREAM (stream);
}
diff --git a/gdk/x11/gdkselectioninputstream-x11.h b/gdk/x11/gdkselectioninputstream-x11.h
index c8bd19d..18c0763 100644
--- a/gdk/x11/gdkselectioninputstream-x11.h
+++ b/gdk/x11/gdkselectioninputstream-x11.h
@@ -59,6 +59,8 @@ void gdk_x11_selection_input_stream_new_async (GdkDisplay
GAsyncReadyCallback callback,
gpointer user_data);
GInputStream * gdk_x11_selection_input_stream_new_finish (GAsyncResult *result,
+ const char **type,
+ int *format,
GError **error);
diff --git a/gdk/x11/gdktextlistconverter-x11.c b/gdk/x11/gdktextlistconverter-x11.c
new file mode 100644
index 0000000..7fe56d1
--- /dev/null
+++ b/gdk/x11/gdktextlistconverter-x11.c
@@ -0,0 +1,169 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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.1 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/>.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include "gdktextlistconverter-x11.h"
+
+#include "gdkintl.h"
+#include "gdkprivate-x11.h"
+
+#define GDK_X11_TEXT_LIST_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k),
GDK_TYPE_X11_TEXT_LIST_CONVERTER, GdkX11TextListConverterClass))
+#define GDK_IS_X11_TEXT_LIST_CONVERTER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GDK_TYPE_X11_TEXT_LIST_CONVERTER))
+#define GDK_X11_TEXT_LIST_CONVERTER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GDK_TYPE_X11_TEXT_LIST_CONVERTER, GdkX11TextListConverterClass))
+
+typedef struct _GdkX11TextListConverterClass GdkX11TextListConverterClass;
+
+struct _GdkX11TextListConverter
+{
+ GObject parent_instance;
+
+ GdkDisplay *display;
+
+ const char *encoding; /* interned */
+ gint format;
+};
+
+struct _GdkX11TextListConverterClass
+{
+ GObjectClass parent_class;
+};
+
+static GConverterResult
+gdk_x11_text_list_converter_convert (GConverter *converter,
+ const void *inbuf,
+ gsize inbuf_size,
+ void *outbuf,
+ gsize outbuf_size,
+ GConverterFlags flags,
+ gsize *bytes_read,
+ gsize *bytes_written,
+ GError **error)
+{
+ GdkX11TextListConverter *conv = GDK_X11_TEXT_LIST_CONVERTER (converter);
+ gint count;
+ char **list;
+
+ if (!(flags & G_CONVERTER_INPUT_AT_END))
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PARTIAL_INPUT,
+ _("Need complete input to do conversion"));
+ return G_CONVERTER_ERROR;
+ }
+
+ count = _gdk_x11_display_text_property_to_utf8_list (conv->display,
+ conv->encoding,
+ conv->format,
+ inbuf,
+ inbuf_size,
+ &list);
+ if (count < 0)
+ {
+ /* XXX: add error handling from gdkselection-x11.c */
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space in destination"));
+ return G_CONVERTER_ERROR;
+ }
+ else if (count == 0)
+ {
+ if (outbuf_size < 1)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space in destination"));
+ return G_CONVERTER_ERROR;
+ }
+ ((gchar *) outbuf)[0] = 0;
+ *bytes_read = inbuf_size;
+ *bytes_written = 1;
+ return G_CONVERTER_FINISHED;
+ }
+ else
+ {
+ gsize len = strlen (list[0]) + 1;
+
+ if (outbuf_size < len)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NO_SPACE,
+ _("Not enough space in destination"));
+ return G_CONVERTER_ERROR;
+ }
+ memcpy (outbuf, list[0], len);
+ g_strfreev (list);
+ *bytes_read = inbuf_size;
+ *bytes_written = len;
+ return G_CONVERTER_FINISHED;
+ }
+}
+
+static void
+gdk_x11_text_list_converter_reset (GConverter *converter)
+{
+}
+
+static void
+gdk_x11_text_list_converter_iface_init (GConverterIface *iface)
+{
+ iface->convert = gdk_x11_text_list_converter_convert;
+ iface->reset = gdk_x11_text_list_converter_reset;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GdkX11TextListConverter, gdk_x11_text_list_converter, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_CONVERTER,
+ gdk_x11_text_list_converter_iface_init))
+
+static void
+gdk_x11_text_list_converter_finalize (GObject *object)
+{
+ GdkX11TextListConverter *conv = GDK_X11_TEXT_LIST_CONVERTER (object);
+
+ g_object_unref (conv->display);
+
+ G_OBJECT_CLASS (gdk_x11_text_list_converter_parent_class)->finalize (object);
+}
+
+static void
+gdk_x11_text_list_converter_class_init (GdkX11TextListConverterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_x11_text_list_converter_finalize;
+}
+
+static void
+gdk_x11_text_list_converter_init (GdkX11TextListConverter *local)
+{
+}
+
+GConverter *
+gdk_x11_text_list_converter_to_utf8_new (GdkDisplay *display,
+ const char *encoding,
+ int format)
+{
+ GdkX11TextListConverter *conv;
+
+ conv = g_object_new (GDK_TYPE_X11_TEXT_LIST_CONVERTER, NULL);
+
+ conv->display = g_object_ref (display);
+ conv->encoding = g_intern_string (encoding);
+ conv->format = format;
+
+ return G_CONVERTER (conv);
+}
+
diff --git a/gdk/x11/gdktextlistconverter-x11.h b/gdk/x11/gdktextlistconverter-x11.h
new file mode 100644
index 0000000..9017a8b
--- /dev/null
+++ b/gdk/x11/gdktextlistconverter-x11.h
@@ -0,0 +1,44 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * 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.1 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/>.
+ *
+ * Author: Benjamin Otte <otte gnome org>
+ */
+
+#ifndef __GDK_X11_TEXT_LIST_CONVERTER_H__
+#define __GDK_X11_TEXT_LIST_CONVERTER_H__
+
+#include <gio/gio.h>
+#include <gdk/gdktypes.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_X11_TEXT_LIST_CONVERTER (gdk_x11_text_list_converter_get_type ())
+#define GDK_X11_TEXT_LIST_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GDK_TYPE_X11_TEXT_LIST_CONVERTER, GdkX11TextListConverter))
+#define GDK_IS_X11_TEXT_LIST_CONVERTER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GDK_TYPE_X11_TEXT_LIST_CONVERTER))
+
+typedef struct _GdkX11TextListConverter GdkX11TextListConverter;
+
+GType gdk_x11_text_list_converter_get_type (void) G_GNUC_CONST;
+
+GConverter * gdk_x11_text_list_converter_to_utf8_new (GdkDisplay *display,
+ const char *encoding,
+ int format);
+
+
+G_END_DECLS
+
+#endif /* __GDK_X11_TEXT_LIST_CONVERTER_H__ */
diff --git a/gdk/x11/meson.build b/gdk/x11/meson.build
index 57ed429..db74295 100644
--- a/gdk/x11/meson.build
+++ b/gdk/x11/meson.build
@@ -22,6 +22,7 @@ gdk_x11_sources = files([
'gdkscreen-x11.c',
'gdkselection-x11.c',
'gdkselectioninputstream-x11.c',
+ 'gdktextlistconverter-x11.c',
'gdkvisual-x11.c',
'gdkvulkancontext-x11.c',
'gdkwindow-x11.c',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]