summaryrefslogtreecommitdiff
path: root/gtk/gtkclipboard.c
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2000-09-14 16:41:20 +0000
committerOwen Taylor <otaylor@src.gnome.org>2000-09-14 16:41:20 +0000
commit39339f14f5e9470c8007e1627517a1e7054f5fee (patch)
tree7ed176adde69fa4e4eac2f948ae10ce51e4aad36 /gtk/gtkclipboard.c
parent42e44b9fa50707b9cfbfcfb51fcc88fbd3e5e2b1 (diff)
downloadgtk+-39339f14f5e9470c8007e1627517a1e7054f5fee.tar.gz
Remove g_convert (moved to glib) and now useless utf_to_latin1()
Thu Sep 14 12:21:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtktexttypes.[ch]: Remove g_convert (moved to glib) and now useless utf_to_latin1() latin1_to_utf() * gtk/gtktextview.[ch]: Change ::move_insert and ::delete_text action signals to ::move and ::delete; create the signals with the right enumeration type, not GTK_TYPE_ENUM so that bindings work. Add C-d, M-d, C-v bindings, change Home, End to move to beginning/end of line, Add C-Home C-End to move to beginning/end of buffer. Change ::cut_text to ::cut_clipboard, etc; combine ::scroll_text into ::move; use new GtkSelectionData functions to simplify DND text handling. * gtk/gtkenums.h gtk/gtktextview.h: Move movement, deletion enumerations here, rename enumeration values to be consistently plural. * gtk/gtktextbuffer.c: Use new clipboard interfaces for cut/copy/paste and primary selection. * gtk/gtktextbuffer.[ch]: Remove excess time and 'interactive' arguments from cut/copy/paste; rename cut to cut_clipboard, etc; remove gtk_text_buffer_get_clipboard_contents(). * gtk/gtktextlayout.[ch]: Add gtk_text_layout_move_iter_to_line_end() to move the iter to line ends. * gtk/gtkselection.[ch] (gtk_selection_data_set/get_text): Functions to set or get a UTF-8 string on the selection data. * gtk/gtkclipboard.[ch]: New, simplified selection handling interfaces. * gtk/gtkinvisible.c (gtk_invisible_new): Realize newly created widgets - one of these is useless if we don't. * gtk/gtkselection.[ch] (gtk_selection_clear_targets): Export a public function clear all targets registered for the widget. * gtk/gtkselection.c (gtk_selection_owner_set) docs/Changes-2.0.txt: Never call gtk_widget_realize() - that was just asking for bizarre side-effects. * gtk/gtkselection.c (gtk_selection_owner_set): Call gdk_selection_owner_set even if the widget is the same so that we reliably update the timestamp on the server. * gdk/x11/gdkevents-x11.c gdk/x11/gdkx.h: Add a gdk_x11_get_server_time() function. * gdk/x11/gdkevents-x11.c gdk/x11/gdkprivate-x11.h gdk/x11/gdkselection-x11.c gdk/x11/gdkwindow-x11.h: Add some tricky filtering on serial numbers for selection clear events to fix up long-standard race condition FIXME's in gtkselection.c. * gdk/gdkproperty.h gdk/x11/gdkselection-x11.h: Add routines to convert from utf8 to compound text or STRING and from a text property to UTF-8. * gtk/gtkmain.[ch] (gtk_get_current_event_time): Add a convenience function gdk_get_current_event_time(). * gtk/gtkselection.c (gtk_selection_data_copy/free): Copy and free selection_data->data properly
Diffstat (limited to 'gtk/gtkclipboard.c')
-rw-r--r--gtk/gtkclipboard.c806
1 files changed, 806 insertions, 0 deletions
diff --git a/gtk/gtkclipboard.c b/gtk/gtkclipboard.c
new file mode 100644
index 0000000000..6df1843cfb
--- /dev/null
+++ b/gtk/gtkclipboard.c
@@ -0,0 +1,806 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2000 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Global clipboard abstraction.
+ */
+
+#include <string.h>
+
+#include "gtkclipboard.h"
+#include "gtkinvisible.h"
+#include "gtkmain.h"
+#include "gtksignal.h"
+
+#ifdef GDK_WINDOWING_X11
+#include "x11/gdkx.h"
+#endif
+
+typedef struct _RequestContentsInfo RequestContentsInfo;
+typedef struct _RequestTextInfo RequestTextInfo;
+
+struct _GtkClipboard
+{
+ GdkAtom selection;
+
+ GtkClipboardGetFunc get_func;
+ GtkClipboardClearFunc clear_func;
+ gpointer user_data;
+ gboolean have_owner;
+
+ guint32 timestamp;
+
+ gboolean have_selection;
+};
+
+struct _RequestContentsInfo
+{
+ GtkClipboardReceivedFunc callback;
+ gpointer user_data;
+};
+
+struct _RequestTextInfo
+{
+ GtkClipboardTextReceivedFunc callback;
+ gpointer user_data;
+};
+
+static void clipboard_unset (GtkClipboard *clipboard);
+static void selection_received (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint time);
+
+static GSList *clipboards;
+static GtkWidget *clipboard_widget;
+
+enum {
+ TARGET_STRING,
+ TARGET_TEXT,
+ TARGET_COMPOUND_TEXT,
+ TARGET_UTF8_STRING
+};
+
+static const gchar *request_contents_key = "gtk-request-contents";
+static GQuark request_contents_key_id = 0;
+
+static const gchar *clipboards_owned_key = "gtk-clipboards-owned";
+static GQuark clipboards_owned_key_id = 0;
+
+
+/**
+ * gtk_clipboard_get:
+ * @selection: a #GdkAtom which identifies the clipboard
+ * to use. A value of GDK_NONE here is the
+ * same as gdk_atom_intern ("CLIPBOARD", FALSE),
+ * and provides the default clipboard. Another
+ * common value is GDK_SELECTION_PRIMARY, which
+ * identifies the primary X selection.
+ *
+ * Returns the clipboard object for the given selection.
+ *
+ * Return value: the appropriate clipboard object. If no
+ * clipboard already exists, a new one will
+ * be created. Once a clipboard object has
+ * been created, it is persistant for all time.
+ **/
+GtkClipboard *
+gtk_clipboard_get (GdkAtom selection)
+{
+ GtkClipboard *clipboard = NULL;
+ GSList *tmp_list;
+
+ if (selection == GDK_NONE)
+ selection = gdk_atom_intern ("CLIPBOARD", FALSE);
+
+ tmp_list = clipboards;
+ while (tmp_list)
+ {
+ clipboard = tmp_list->data;
+ if (clipboard->selection == selection)
+ break;
+
+ tmp_list = tmp_list->next;
+ }
+
+ if (!tmp_list)
+ {
+ clipboard = g_new0 (GtkClipboard, 1);
+ clipboard->selection = selection;
+ clipboards = g_slist_prepend (clipboards, clipboard);
+ }
+
+ return clipboard;
+}
+
+static void
+selection_get_cb (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint time,
+ guint info)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get (selection_data->selection);
+
+ if (clipboard && clipboard->get_func)
+ clipboard->get_func (clipboard, selection_data, info, clipboard->user_data);
+}
+
+static gboolean
+selection_clear_event_cb (GtkWidget *widget,
+ GdkEventSelection *event)
+{
+ GtkClipboard *clipboard = gtk_clipboard_get (event->selection);
+
+ if (clipboard)
+ {
+ clipboard_unset (clipboard);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+GtkWidget *
+make_clipboard_widget (gboolean provider)
+{
+ GtkWidget *widget = gtk_invisible_new ();
+
+ gtk_signal_connect (GTK_OBJECT (widget), "selection_received",
+ GTK_SIGNAL_FUNC (selection_received), NULL);
+
+ if (provider)
+ {
+ /* We need this for gdk_x11_get_server_time() */
+ gtk_widget_add_events (widget, GDK_PROPERTY_CHANGE_MASK);
+
+ gtk_signal_connect (GTK_OBJECT (widget), "selection_get",
+ GTK_SIGNAL_FUNC (selection_get_cb), NULL);
+ gtk_signal_connect (GTK_OBJECT (widget), "selection_clear_event",
+ GTK_SIGNAL_FUNC (selection_clear_event_cb), NULL);
+ }
+
+ return widget;
+}
+
+
+void
+ensure_clipboard_widget ()
+{
+ if (!clipboard_widget)
+ clipboard_widget = make_clipboard_widget (TRUE);
+}
+
+/* This function makes a very good guess at what the correct
+ * timestamp for a selection request should be. If there is
+ * a currently processed event, it uses the timestamp for that
+ * event, otherwise it uses the current server time. However,
+ * if the time resulting from that is older than the time used
+ * last time, it uses the time used last time instead.
+ *
+ * In order implement this correctly, we never use CurrentTime,
+ * but actually retrieve the actual timestamp from the server.
+ * This is a little slower but allows us to make the guarantee
+ * that the times used by this application will always ascend
+ * and we won't get selections being rejected just because
+ * we are using a correct timestamp from an event, but used
+ * CurrentTime previously.
+ */
+static guint32
+clipboard_get_timestamp (GtkClipboard *clipboard)
+{
+ guint32 timestamp = gtk_get_current_event_time ();
+
+ ensure_clipboard_widget ();
+
+ if (timestamp == GDK_CURRENT_TIME)
+ {
+ timestamp = gdk_x11_get_server_time (clipboard_widget->window);
+ }
+ else
+ {
+ if (clipboard->timestamp != GDK_CURRENT_TIME)
+ {
+ /* Check to see if clipboard->timestamp is newer than
+ * timestamp, accounting for wraparound.
+ */
+
+ guint32 max = timestamp + 0x80000000;
+
+ if ((max > timestamp &&
+ (clipboard->timestamp > timestamp &&
+ clipboard->timestamp <= max)) ||
+ (max <= timestamp &&
+ (clipboard->timestamp > timestamp ||
+ clipboard->timestamp <= max)))
+ {
+ timestamp = clipboard->timestamp;
+ }
+ }
+ }
+
+ clipboard->timestamp = timestamp;
+
+ return timestamp;
+}
+
+static void
+clipboard_owner_destroyed (gpointer data)
+{
+ GSList *clipboards = data;
+ GSList *tmp_list;
+
+ tmp_list = clipboards;
+ while (tmp_list)
+ {
+ GtkClipboard *clipboard = tmp_list->data;
+
+ clipboard->get_func = NULL;
+ clipboard->clear_func = NULL;
+ clipboard->user_data = NULL;
+ clipboard->have_owner = FALSE;
+
+ gtk_clipboard_clear (clipboard);
+
+ tmp_list = tmp_list->next;
+ }
+
+ g_slist_free (clipboards);
+}
+
+static void
+clipboard_add_owner_notify (GtkClipboard *clipboard)
+{
+ if (!clipboards_owned_key_id)
+ clipboards_owned_key_id = g_quark_from_static_string (clipboards_owned_key);
+
+ if (clipboard->have_owner)
+ g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
+ g_slist_prepend (g_object_steal_qdata (clipboard->user_data,
+ clipboards_owned_key_id),
+ clipboard),
+ clipboard_owner_destroyed);
+}
+
+static void
+clipboard_remove_owner_notify (GtkClipboard *clipboard)
+{
+ if (clipboard->have_owner)
+ g_object_set_qdata_full (clipboard->user_data, clipboards_owned_key_id,
+ g_slist_remove (g_object_steal_qdata (clipboard->user_data,
+ clipboards_owned_key_id),
+ clipboard),
+ clipboard_owner_destroyed);
+}
+
+static gboolean
+gtk_clipboard_set_contents (GtkClipboard *clipboard,
+ const GtkTargetEntry *targets,
+ guint n_targets,
+ GtkClipboardGetFunc get_func,
+ GtkClipboardClearFunc clear_func,
+ gpointer user_data,
+ gboolean have_owner)
+{
+ ensure_clipboard_widget ();
+
+ if (gtk_selection_owner_set (clipboard_widget, clipboard->selection,
+ clipboard_get_timestamp (clipboard)))
+ {
+ clipboard->have_selection = TRUE;
+
+ if (!(clipboard->have_owner && have_owner) ||
+ clipboard->user_data != user_data)
+ {
+ clipboard_unset (clipboard);
+
+ if (clipboard->get_func)
+ {
+ /* Calling unset() caused the clipboard contents to be reset!
+ * Avoid leaking and return
+ */
+ if (!(clipboard->have_owner && have_owner) ||
+ clipboard->user_data != user_data)
+ {
+ (*clear_func) (clipboard, user_data);
+ return FALSE;
+ }
+ else
+ return TRUE;
+ }
+ else
+ {
+ clipboard->user_data = user_data;
+ clipboard->have_owner = have_owner;
+ if (have_owner)
+ clipboard_add_owner_notify (clipboard);
+ }
+
+ }
+
+ clipboard->get_func = get_func;
+ clipboard->clear_func = clear_func;
+
+ gtk_selection_clear_targets (clipboard_widget, clipboard->selection);
+ gtk_selection_add_targets (clipboard_widget, clipboard->selection,
+ targets, n_targets);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/**
+ * gtk_clipboard_set_with_data:
+ * @clipboard: a #GtkClipboard
+ * @targets: array containing information about the available forms for the
+ * clipboard data
+ * @n_targets: number of elements in @targets
+ * @get_func: function to call to get the actual clipboard data
+ * @clear_func: when the clipboard contents are set again, this function will
+ * be called, and get_func will not be subsequently called.
+ * @user_data: user data to pass to @get_func and @clear_func.
+ *
+ * Virtually set the contents of the specified clipboard by providing
+ * a list of supported formats for the clipboard data and a function
+ * to call to get the actual data when it is requested.
+ *
+ * Return value: %TRUE if setting the clipboard data succeeded. If setting
+ * the clipboard data failed the provided callback functions
+ * will be ignored.
+ **/
+gboolean
+gtk_clipboard_set_with_data (GtkClipboard *clipboard,
+ const GtkTargetEntry *targets,
+ guint n_targets,
+ GtkClipboardGetFunc get_func,
+ GtkClipboardClearFunc clear_func,
+ gpointer user_data)
+{
+ g_return_val_if_fail (clipboard != NULL, FALSE);
+ g_return_val_if_fail (targets != NULL, FALSE);
+ g_return_val_if_fail (get_func != NULL, FALSE);
+
+ return gtk_clipboard_set_contents (clipboard, targets, n_targets,
+ get_func, clear_func, user_data,
+ FALSE);
+}
+
+/**
+ * gtk_clipboard_set_with_owner:
+ * @clipboard: a #GtkClipboard
+ * @targets: array containing information about the available forms for the
+ * clipboard data
+ * @n_targets: number of elements in @targets
+ * @get_func: function to call to get the actual clipboard data
+ * @clear_func: when the clipboard contents are set again, this function will
+ * be called, and get_func will not be subsequently called.
+ * @owner: an object that "owns" the data. This object will be passed
+ * to the callbacks when called.
+ *
+ * Virtually set the contents of the specified clipboard by providing
+ * a list of supported formats for the clipboard data and a function
+ * to call to get the actual data when it is requested.
+ *
+ * The difference between this function and gtk_clipboard_set_with_data
+ * is that instead of an generic @user_data pointer, a #GObject is passed
+ * in. Because of this,
+ *
+ * Return value: %TRUE if setting the clipboard data succeeded. If setting
+ * the clipboard data failed the provided callback functions
+ * will be ignored.
+ **/
+gboolean
+gtk_clipboard_set_with_owner (GtkClipboard *clipboard,
+ const GtkTargetEntry *targets,
+ guint n_targets,
+ GtkClipboardGetFunc get_func,
+ GtkClipboardClearFunc clear_func,
+ GObject *owner)
+{
+ g_return_val_if_fail (clipboard != NULL, FALSE);
+ g_return_val_if_fail (targets != NULL, FALSE);
+ g_return_val_if_fail (get_func != NULL, FALSE);
+ g_return_val_if_fail (G_IS_OBJECT (owner), FALSE);
+
+ return gtk_clipboard_set_contents (clipboard, targets, n_targets,
+ get_func, clear_func, owner,
+ TRUE);
+}
+
+/**
+ * gtk_clipboard_get_owner:
+ * @clipboard: a #GtkClipboard
+ *
+ * If the clipboard contents callbacks were set with gtk_clipboard_set_owner(),
+ * and the gtk_clipboard_set_with_data() or gtk_clipboard_clear() has not
+ * subsequently called, returns the @owner set by gtk_clipboard_set_owner().
+ *
+ * Return value: the owner of the clipboard, if any; otherwise %NULL.
+ **/
+GObject *
+gtk_clipboard_get_owner (GtkClipboard *clipboard)
+{
+ g_return_val_if_fail (clipboard != NULL, NULL);
+
+ if (clipboard->have_owner)
+ return clipboard->user_data;
+ else
+ return NULL;
+}
+
+static void
+clipboard_unset (GtkClipboard *clipboard)
+{
+ GtkClipboardClearFunc old_clear_func;
+ gpointer old_data;
+
+ old_clear_func = clipboard->clear_func;
+ old_data = clipboard->user_data;
+
+ if (clipboard->have_owner)
+ {
+ clipboard_remove_owner_notify (clipboard);
+ clipboard->have_owner = FALSE;
+ }
+
+ clipboard->get_func = NULL;
+ clipboard->clear_func = NULL;
+ clipboard->user_data = NULL;
+
+ if (old_clear_func)
+ old_clear_func (clipboard, old_data);
+}
+
+/**
+ * gtk_clipboard_clear:
+ * @clipboard: a #GtkClipboard
+ *
+ * Clear the contents of the clipboard. Generally this should only
+ * be called between the time you call gtk_clipboard_set_contents(),
+ * and when the @clear_func you supplied is called. Otherwise, the
+ * clipboard may be owned by someone else.
+ **/
+void
+gtk_clipboard_clear (GtkClipboard *clipboard)
+{
+ g_return_if_fail (clipboard != NULL);
+
+ if (clipboard->have_selection)
+ gtk_selection_owner_set (NULL, clipboard->selection,
+ clipboard_get_timestamp (clipboard));
+}
+
+void
+text_get_func (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ guint info,
+ gpointer data)
+{
+ gtk_selection_data_set_text (selection_data, data);
+}
+
+void
+text_clear_func (GtkClipboard *clipboard,
+ gpointer data)
+{
+ g_free (data);
+}
+
+/**
+ * gtk_clipboard_set_text:
+ * @clipboard: a #GtkClipboard object
+ * @text: a UTF-8 string.
+ * @len: length of @text, in bytes, or -1, in which case
+ * the length will be determined with strlen().
+ *
+ * Set the contents of the clipboard to the given UTF-8 string. GTK+ will
+ * make a copy of the text and take responsibility for responding
+ * for requests for the text, and for converting the text into
+ * the requested format.
+ **/
+void
+gtk_clipboard_set_text (GtkClipboard *clipboard,
+ const gchar *text,
+ gint len)
+{
+ static const GtkTargetEntry targets[] = {
+ { "STRING", 0, TARGET_STRING },
+ { "TEXT", 0, TARGET_TEXT },
+ { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
+ { "UTF8_STRING", 0, TARGET_UTF8_STRING }
+ };
+
+ g_return_if_fail (clipboard != NULL);
+ g_return_if_fail (text != NULL);
+
+ if (len < 0)
+ len = strlen (text);
+
+ gtk_clipboard_set_with_data (clipboard,
+ targets, G_N_ELEMENTS (targets),
+ text_get_func, text_clear_func,
+ g_strndup (text, len));
+}
+
+static void
+set_request_contents_info (GtkWidget *widget,
+ RequestContentsInfo *info)
+{
+ if (!request_contents_key_id)
+ request_contents_key_id = g_quark_from_static_string (request_contents_key);
+
+ gtk_object_set_data_by_id (GTK_OBJECT (widget),
+ request_contents_key_id,
+ info);
+}
+
+static RequestContentsInfo *
+get_request_contents_info (GtkWidget *widget)
+{
+ if (!request_contents_key_id)
+ return NULL;
+ else
+ return gtk_object_get_data_by_id (GTK_OBJECT (widget),
+ request_contents_key_id);
+}
+
+static void
+selection_received (GtkWidget *widget,
+ GtkSelectionData *selection_data,
+ guint time)
+{
+ RequestContentsInfo *request_info = get_request_contents_info (widget);
+ set_request_contents_info (widget, NULL);
+
+ request_info->callback (gtk_clipboard_get (selection_data->selection),
+ selection_data,
+ request_info->user_data);
+
+ g_free (request_info);
+
+ if (widget != clipboard_widget)
+ gtk_widget_destroy (widget);
+}
+
+/**
+ * gtk_clipboard_request_contents:
+ * @clipboard: a #GtkClipboard
+ * @target: an atom representing the form into which the clipboard
+ * owner should convert the selection.
+ * @callback: A function to call when the results are received
+ * (or the retrieval fails.) If the retrieval fails
+ * the length field of @selection_data will be
+ * negative.
+ * @user_data: user data to pass to @callback
+ *
+ * Requests the contents of clipboard as the given target.
+ * When the results of the result are later received the supplied callback
+ * will be called.
+ **/
+void
+gtk_clipboard_request_contents (GtkClipboard *clipboard,
+ GdkAtom target,
+ GtkClipboardReceivedFunc callback,
+ gpointer user_data)
+{
+ RequestContentsInfo *info;
+ GtkWidget *widget;
+
+ g_return_if_fail (clipboard != NULL);
+ g_return_if_fail (target != GDK_NONE);
+ g_return_if_fail (callback != NULL);
+
+ ensure_clipboard_widget ();
+
+ if (get_request_contents_info (clipboard_widget))
+ widget = make_clipboard_widget (FALSE);
+ else
+ widget = clipboard_widget;
+
+ info = g_new (RequestContentsInfo, 1);
+ info->callback = callback;
+ info->user_data = user_data;
+
+ set_request_contents_info (widget, info);
+
+ gtk_selection_convert (widget, clipboard->selection, target,
+ clipboard_get_timestamp (clipboard));
+}
+
+static void
+request_text_received_func (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ gpointer data)
+{
+ RequestTextInfo *info = data;
+ gchar *result = NULL;
+
+ result = gtk_selection_data_get_text (selection_data);
+
+ if (!result)
+ {
+ /* If we asked for UTF8 and didn't get it, try text; if we asked
+ * for text and didn't get it, try string. If we asked for
+ * anything else and didn't get it, give up.
+ */
+ if (selection_data->target == gdk_atom_intern ("UTF8_STRING", FALSE))
+ {
+ gtk_clipboard_request_contents (clipboard,
+ gdk_atom_intern ("TEXT", FALSE),
+ request_text_received_func, info);
+ return;
+ }
+ else if (selection_data->target == gdk_atom_intern ("TEXT", FALSE))
+ {
+ gtk_clipboard_request_contents (clipboard,
+ GDK_TARGET_STRING,
+ request_text_received_func, info);
+ return;
+ }
+ }
+
+ info->callback (clipboard, result, info->user_data);
+ g_free (info);
+ g_free (result);
+}
+
+/**
+ * gtk_clipboard_request_text:
+ * @clipboard: a #GtkClipboard
+ * @callback: a function to call when the text is received,
+ * or the retrieval fails. (It will always be called
+ * one way or the other.)
+ * @user_data: user data to pass to @callback.
+ *
+ * Requests the contents of the clipboard as text. When the text is
+ * later received, it will be converted to UTF-8 if necessary, and
+ * @callback will be called.
+ *
+ * The @text parameter to @callback will contain the resulting text if
+ * the request succeeded, or %NULL if it failed. This could happen for
+ * various reasons, in particular if the clipboard was empty or if the
+ * contents of the clipboard could not be converted into text form.
+ **/
+void
+gtk_clipboard_request_text (GtkClipboard *clipboard,
+ GtkClipboardTextReceivedFunc callback,
+ gpointer user_data)
+{
+ RequestTextInfo *info;
+
+ g_return_if_fail (clipboard != NULL);
+ g_return_if_fail (callback != NULL);
+
+ info = g_new (RequestTextInfo, 1);
+ info->callback = callback;
+ info->user_data = user_data;
+
+ gtk_clipboard_request_contents (clipboard, gdk_atom_intern ("UTF8_STRING", FALSE),
+ request_text_received_func,
+ info);
+}
+
+
+typedef struct
+{
+ GMainLoop *loop;
+ gpointer data;
+} WaitResults;
+
+static void
+clipboard_received_func (GtkClipboard *clipboard,
+ GtkSelectionData *selection_data,
+ gpointer data)
+{
+ WaitResults *results = data;
+
+ if (selection_data->length >= 0)
+ results->data = gtk_selection_data_copy (selection_data);
+
+ g_main_quit (results->loop);
+}
+
+/**
+ * gtk_clipboard_wait_for_contents:
+ * @clipboard: a #GtkClipboard
+ * @target: an atom representing the form into which the clipboard
+ * owner should convert the selection.
+ *
+ * Requests the contents of the clipboard using the given target.
+ * This function waits for the data to be received using the main
+ * loop, so events, timeouts, etc, may be dispatched during the wait.
+ *
+ * Return value: a newly allocated #GtkSelectionData object or %NULL
+ * if retrieving the given target failed. If non-%NULL,
+ * this value freed with gtk_selection_data_free() when
+ * you are finished with it.
+ **/
+GtkSelectionData *
+gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
+ GdkAtom target)
+{
+ WaitResults results;
+
+ g_return_val_if_fail (clipboard != NULL, NULL);
+ g_return_val_if_fail (target != GDK_NONE, NULL);
+
+ results.data = NULL;
+ results.loop = g_main_new (TRUE);
+
+ gtk_clipboard_request_contents (clipboard, target,
+ clipboard_received_func,
+ &results);
+
+ if (g_main_is_running (results.loop))
+ g_main_run (results.loop);
+
+ g_main_destroy (results.loop);
+
+ return results.data;
+}
+
+static void
+clipboard_text_received_func (GtkClipboard *clipboard,
+ const gchar *text,
+ gpointer data)
+{
+ WaitResults *results = data;
+
+ results->data = g_strdup (text);
+ g_main_quit (results->loop);
+}
+
+
+/**
+ * gtk_clipboard_wait_for_text:
+ * @clipboard: a #GtkClipboard
+ *
+ * Requests the contents of the clipboard as text and converts
+ * the result to UTF-8 if necessary. This function waits for
+ * the data to be received using the main loop, so events,
+ * timeouts, etc, may be dispatched during the wait.
+ *
+ * Return value: a newly allocated UTF-8 string which must
+ * be freed with g_free(), or %NULL if retrieving
+ * the selection data failed. (This could happen
+ * for various reasons, in particular if the
+ * clipboard was empty or if the contents of the
+ * clipboard could not be converted into text form.)
+ **/
+gchar *
+gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
+{
+ WaitResults results;
+
+ g_return_val_if_fail (clipboard != NULL, NULL);
+ g_return_val_if_fail (clipboard != NULL, NULL);
+
+ results.data = NULL;
+ results.loop = g_main_new (TRUE);
+
+ gtk_clipboard_request_text (clipboard,
+ clipboard_text_received_func,
+ &results);
+
+ if (g_main_is_running (results.loop))
+ g_main_run (results.loop);
+
+ g_main_destroy (results.loop);
+
+ return results.data;
+}
+