X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkselection.c;h=b76090be200499f7ef0b1e96d4157ee2b7d7d56a;hb=a8698a24c7a53fe4d34211053529f14747f7ce5f;hp=7314e3f22f11550ac4e2712160042bc4ea3faf57;hpb=6139c61d220c441de0002bae58ca216ef6f6fba1;p=~andy%2Fgtk diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c index 7314e3f22..b76090be2 100644 --- a/gtk/gtkselection.c +++ b/gtk/gtkselection.c @@ -17,12 +17,12 @@ * Boston, MA 02111-1307, USA. */ -/* This file implements most of the work of the ICCM selection protocol. +/* This file implements most of the work of the ICCCM selection protocol. * The code was written after an intensive study of the equivalent part * of John Ousterhout's Tk toolkit, and does many things in much the * same way. * - * The one thing in the ICCM that isn't fully supported here (or in Tk) + * The one thing in the ICCCM that isn't fully supported here (or in Tk) * is side effects targets. For these to be handled properly, MULTIPLE * targets need to be done in the order specified. This cannot be * guaranteed with the way we do things, since if we are doing INCR @@ -51,29 +51,43 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include #include #include #include "gdk.h" #include "gtkmain.h" #include "gtkselection.h" +#include "gtktextbufferrichtext.h" +#include "gtkintl.h" +#include "gdk-pixbuf/gdk-pixbuf.h" #ifdef GDK_WINDOWING_X11 #include "x11/gdkx.h" #endif -/* #define DEBUG_SELECTION */ +#ifdef GDK_WINDOWING_WIN32 +#include "win32/gdkwin32.h" +#endif + +#include "gtkalias.h" + +#undef DEBUG_SELECTION /* Maximum size of a sent chunk, in bytes. Also the default size of our buffers */ -#ifdef GDK_WINDOWING_WIN32 -/* No chunks on Win32 */ -#define GTK_SELECTION_MAX_SIZE G_MAXINT +#ifdef GDK_WINDOWING_X11 +#define GTK_SELECTION_MAX_SIZE(display) \ + MIN(262144, \ + XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) == 0 \ + ? XMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100 \ + : XExtendedMaxRequestSize (GDK_DISPLAY_XDISPLAY (display)) - 100) #else -#define GTK_SELECTION_MAX_SIZE 4000 +/* No chunks on Win32 */ +#define GTK_SELECTION_MAX_SIZE(display) G_MAXINT #endif -#define IDLE_ABORT_TIME 300 +#define IDLE_ABORT_TIME 30 enum { INCR, @@ -138,8 +152,8 @@ struct _GtkRetrievalInfo /* Local Functions */ static void gtk_selection_init (void); -static gint gtk_selection_incr_timeout (GtkIncrInfo *info); -static gint gtk_selection_retrieval_timeout (GtkRetrievalInfo *info); +static gboolean gtk_selection_incr_timeout (GtkIncrInfo *info); +static gboolean gtk_selection_retrieval_timeout (GtkRetrievalInfo *info); static void gtk_selection_retrieval_report (GtkRetrievalInfo *info, GdkAtom type, gint format, @@ -170,6 +184,16 @@ static const char gtk_selection_handler_key[] = "gtk-selection-handlers"; * Target lists */ + +/** + * gtk_target_list_new: + * @targets: Pointer to an array of #GtkTargetEntry + * @ntargets: number of entries in @targets. + * + * Creates a new #GtkTargetList from an array of #GtkTargetEntry. + * + * Return value: the new #GtkTargetList. + **/ GtkTargetList * gtk_target_list_new (const GtkTargetEntry *targets, guint ntargets) @@ -184,14 +208,31 @@ gtk_target_list_new (const GtkTargetEntry *targets, return result; } -void +/** + * gtk_target_list_ref: + * @list: a #GtkTargetList + * + * Increases the reference count of a #GtkTargetList by one. + * + * Return value: the passed in #GtkTargetList. + **/ +GtkTargetList * gtk_target_list_ref (GtkTargetList *list) { - g_return_if_fail (list != NULL); + g_return_val_if_fail (list != NULL, NULL); list->ref_count++; + + return list; } +/** + * gtk_target_list_unref: + * @list: a #GtkTargetList + * + * Decreases the reference count of a #GtkTargetList by one. + * If the resulting reference count is zero, frees the list. + **/ void gtk_target_list_unref (GtkTargetList *list) { @@ -215,11 +256,20 @@ gtk_target_list_unref (GtkTargetList *list) } } +/** + * gtk_target_list_add: + * @list: a #GtkTargetList + * @target: the interned atom representing the target + * @flags: the flags for this target + * @info: an ID that will be passed back to the application + * + * Appends another target to a #GtkTargetList. + **/ void gtk_target_list_add (GtkTargetList *list, - GdkAtom target, - guint flags, - guint info) + GdkAtom target, + guint flags, + guint info) { GtkTargetPair *pair; @@ -233,6 +283,197 @@ gtk_target_list_add (GtkTargetList *list, list->list = g_list_append (list->list, pair); } +static GdkAtom utf8_atom; +static GdkAtom text_atom; +static GdkAtom ctext_atom; +static GdkAtom text_plain_atom; +static GdkAtom text_plain_utf8_atom; +static GdkAtom text_plain_locale_atom; +static GdkAtom text_uri_list_atom; + +static void +init_atoms (void) +{ + gchar *tmp; + const gchar *charset; + + if (!utf8_atom) + { + utf8_atom = gdk_atom_intern_static_string ("UTF8_STRING"); + text_atom = gdk_atom_intern_static_string ("TEXT"); + ctext_atom = gdk_atom_intern_static_string ("COMPOUND_TEXT"); + text_plain_atom = gdk_atom_intern_static_string ("text/plain"); + text_plain_utf8_atom = gdk_atom_intern_static_string ("text/plain;charset=utf-8"); + g_get_charset (&charset); + tmp = g_strdup_printf ("text/plain;charset=%s", charset); + text_plain_locale_atom = gdk_atom_intern (tmp, FALSE); + g_free (tmp); + + text_uri_list_atom = gdk_atom_intern_static_string ("text/uri-list"); + } +} + +/** + * gtk_target_list_add_text_targets: + * @list: a #GtkTargetList + * @info: an ID that will be passed back to the application + * + * Appends the text targets supported by #GtkSelection to + * the target list. All targets are added with the same @info. + * + * Since: 2.6 + **/ +void +gtk_target_list_add_text_targets (GtkTargetList *list, + guint info) +{ + g_return_if_fail (list != NULL); + + init_atoms (); + + /* Keep in sync with gtk_selection_data_targets_include_text() + */ + gtk_target_list_add (list, utf8_atom, 0, info); + gtk_target_list_add (list, ctext_atom, 0, info); + gtk_target_list_add (list, text_atom, 0, info); + gtk_target_list_add (list, GDK_TARGET_STRING, 0, info); + gtk_target_list_add (list, text_plain_utf8_atom, 0, info); + gtk_target_list_add (list, text_plain_locale_atom, 0, info); + gtk_target_list_add (list, text_plain_atom, 0, info); +} + +/** + * gtk_target_list_add_rich_text_targets: + * @list: a #GtkTargetList + * @info: an ID that will be passed back to the application + * @deserializable: if %TRUE, then deserializable rich text formats + * will be added, serializable formats otherwise. + * @buffer: a #GtkTextBuffer. + * + * Appends the rich text targets registered with + * gtk_text_buffer_register_serialize_format() or + * gtk_text_buffer_register_deserialize_format() to the target list. All + * targets are added with the same @info. + * + * Since: 2.10 + **/ +void +gtk_target_list_add_rich_text_targets (GtkTargetList *list, + guint info, + gboolean deserializable, + GtkTextBuffer *buffer) +{ + GdkAtom *atoms; + gint n_atoms; + gint i; + + g_return_if_fail (list != NULL); + g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer)); + + if (deserializable) + atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms); + else + atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_atoms); + + for (i = 0; i < n_atoms; i++) + gtk_target_list_add (list, atoms[i], 0, info); + + g_free (atoms); +} + +/** + * gtk_target_list_add_image_targets: + * @list: a #GtkTargetList + * @info: an ID that will be passed back to the application + * @writable: whether to add only targets for which GTK+ knows + * how to convert a pixbuf into the format + * + * Appends the image targets supported by #GtkSelection to + * the target list. All targets are added with the same @info. + * + * Since: 2.6 + **/ +void +gtk_target_list_add_image_targets (GtkTargetList *list, + guint info, + gboolean writable) +{ + GSList *formats, *f; + gchar **mimes, **m; + GdkAtom atom; + + g_return_if_fail (list != NULL); + + formats = gdk_pixbuf_get_formats (); + + /* Make sure png comes first */ + for (f = formats; f; f = f->next) + { + GdkPixbufFormat *fmt = f->data; + gchar *name; + + name = gdk_pixbuf_format_get_name (fmt); + if (strcmp (name, "png") == 0) + { + formats = g_slist_delete_link (formats, f); + formats = g_slist_prepend (formats, fmt); + + g_free (name); + + break; + } + + g_free (name); + } + + for (f = formats; f; f = f->next) + { + GdkPixbufFormat *fmt = f->data; + + if (writable && !gdk_pixbuf_format_is_writable (fmt)) + continue; + + mimes = gdk_pixbuf_format_get_mime_types (fmt); + for (m = mimes; *m; m++) + { + atom = gdk_atom_intern (*m, FALSE); + gtk_target_list_add (list, atom, 0, info); + } + g_strfreev (mimes); + } + + g_slist_free (formats); +} + +/** + * gtk_target_list_add_uri_targets: + * @list: a #GtkTargetList + * @info: an ID that will be passed back to the application + * + * Appends the URI targets supported by #GtkSelection to + * the target list. All targets are added with the same @info. + * + * Since: 2.6 + **/ +void +gtk_target_list_add_uri_targets (GtkTargetList *list, + guint info) +{ + g_return_if_fail (list != NULL); + + init_atoms (); + + gtk_target_list_add (list, text_uri_list_atom, 0, info); +} + +/** + * gtk_target_list_add_table: + * @list: a #GtkTargetList + * @targets: the table of #GtkTargetEntry + * @ntargets: number of targets in the table + * + * Prepends a table of #GtkTargetEntry to a target list. + **/ void gtk_target_list_add_table (GtkTargetList *list, const GtkTargetEntry *targets, @@ -251,6 +492,13 @@ gtk_target_list_add_table (GtkTargetList *list, } } +/** + * gtk_target_list_remove: + * @list: a #GtkTargetList + * @target: the interned atom representing the target + * + * Removes a target from a target list. + **/ void gtk_target_list_remove (GtkTargetList *list, GdkAtom target) @@ -278,6 +526,16 @@ gtk_target_list_remove (GtkTargetList *list, } } +/** + * gtk_target_list_find: + * @list: a #GtkTargetList + * @target: an interned atom representing the target to search for + * @info: a pointer to the location to store application info for target + * + * Looks up a given target in a #GtkTargetList. + * + * Return value: %TRUE if the target was found, otherwise %FALSE + **/ gboolean gtk_target_list_find (GtkTargetList *list, GdkAtom target, @@ -299,6 +557,72 @@ gtk_target_list_find (GtkTargetList *list, return FALSE; } +/** + * gtk_target_table_new_from_list: + * @list: a #GtkTargetList + * @n_targets: return location for the number ot targets in the table + * + * This function creates an #GtkTargetEntry array that contains the + * same targets as the passed %list. The returned table is newly + * allocated and should be freed using gtk_target_table_free() when no + * longer needed. + * + * Return value: the new table. + * + * Since: 2.10 + **/ +GtkTargetEntry * +gtk_target_table_new_from_list (GtkTargetList *list, + gint *n_targets) +{ + GtkTargetEntry *targets; + GList *tmp_list; + gint i; + + g_return_val_if_fail (list != NULL, NULL); + g_return_val_if_fail (n_targets != NULL, NULL); + + *n_targets = g_list_length (list->list); + targets = g_new0 (GtkTargetEntry, *n_targets); + + for (i = 0, tmp_list = list->list; + i < *n_targets; + i++, tmp_list = g_list_next (tmp_list)) + { + GtkTargetPair *pair = tmp_list->data; + + targets[i].target = gdk_atom_name (pair->target); + targets[i].flags = pair->flags; + targets[i].info = pair->info; + } + + return targets; +} + +/** + * gtk_target_table_free: + * @targets: a #GtkTargetEntry array + * @n_targets: the number of entries in the array + * + * This function frees a target table as returned by + * gtk_target_table_new_from_list() + * + * Since: 2.10 + **/ +void +gtk_target_table_free (GtkTargetEntry *targets, + gint n_targets) +{ + gint i; + + g_return_if_fail (targets == NULL || n_targets > 0); + + for (i = 0; i < n_targets; i++) + g_free (targets[i].target); + + g_free (targets); +} + /** * gtk_selection_owner_set_for_display: * @display: the #Gdkdisplay where the selection is set @@ -437,19 +761,6 @@ gtk_selection_owner_set (GtkWidget *widget, selection, time); } -/************************************************************* - * gtk_selection_add_target - * Add specified target to list of supported targets - * - * arguments: - * widget: The widget for which this target applies - * selection: - * target: - * info: guint to pass to to the selection_get signal - * - * results: - *************************************************************/ - typedef struct _GtkSelectionTargetList GtkSelectionTargetList; struct _GtkSelectionTargetList { @@ -481,7 +792,7 @@ gtk_selection_target_list_get (GtkWidget *widget, sellist->list = gtk_target_list_new (NULL, 0); lists = g_list_prepend (lists, sellist); - g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists); + g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists); return sellist->list; } @@ -507,7 +818,7 @@ gtk_selection_target_list_remove (GtkWidget *widget) } g_list_free (lists); - g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, NULL); + g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), NULL); } /** @@ -547,9 +858,19 @@ gtk_selection_clear_targets (GtkWidget *widget, tmp_list = tmp_list->next; } - g_object_set_data (G_OBJECT (widget), gtk_selection_handler_key, lists); + g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists); } +/** + * gtk_selection_add_target: + * @widget: a #GtkTarget + * @selection: the selection + * @target: target to add. + * @info: A unsigned integer which will be passed back to the application. + * + * Appends a specified target to the list of supported targets for a + * given widget and selection. + **/ void gtk_selection_add_target (GtkWidget *widget, GdkAtom selection, @@ -563,8 +884,21 @@ gtk_selection_add_target (GtkWidget *widget, list = gtk_selection_target_list_get (widget, selection); gtk_target_list_add (list, target, 0, info); +#ifdef GDK_WINDOWING_WIN32 + gdk_win32_selection_add_targets (widget->window, selection, 1, &target); +#endif } +/** + * gtk_selection_add_targets: + * @widget: a #GtkWidget + * @selection: the selection + * @targets: a table of targets to add + * @ntargets: number of entries in @targets + * + * Prepends a table of targets to the list of supported targets + * for a given widget and selection. + **/ void gtk_selection_add_targets (GtkWidget *widget, GdkAtom selection, @@ -579,20 +913,30 @@ gtk_selection_add_targets (GtkWidget *widget, list = gtk_selection_target_list_get (widget, selection); gtk_target_list_add_table (list, targets, ntargets); + +#ifdef GDK_WINDOWING_WIN32 + { + int i; + GdkAtom *atoms = g_new (GdkAtom, ntargets); + + for (i = 0; i < ntargets; ++i) + atoms[i] = gdk_atom_intern (targets[i].target, FALSE); + gdk_win32_selection_add_targets (widget->window, selection, ntargets, atoms); + g_free (atoms); + } +#endif } -/************************************************************* +/** * gtk_selection_remove_all: - * Removes all handlers and unsets ownership of all - * selections for a widget. Called when widget is being - * destroyed - * - * arguments: - * widget: The widget - * results: - *************************************************************/ - + * @widget: a #GtkWidget + * + * Removes all handlers and unsets ownership of all + * selections for a widget. Called when widget is being + * destroyed. This function will not generally be + * called by applications. + **/ void gtk_selection_remove_all (GtkWidget *widget) { @@ -643,29 +987,27 @@ gtk_selection_remove_all (GtkWidget *widget) gtk_selection_target_list_remove (widget); } -/************************************************************* - * gtk_selection_convert: - * Request the contents of a selection. When received, - * a "selection_received" signal will be generated. - * - * arguments: - * widget: The widget which acts as requestor - * selection: Which selection to get - * target: Form of information desired (e.g., STRING) - * time: Time of request (usually of triggering event) - * In emergency, you could use GDK_CURRENT_TIME - * - * results: - * TRUE if requested succeeded. FALSE if we could not process - * request. (e.g., there was already a request in process for - * this widget). - *************************************************************/ +/** + * gtk_selection_convert: + * @widget: The widget which acts as requestor + * @selection: Which selection to get + * @target: Form of information desired (e.g., STRING) + * @time_: Time of request (usually of triggering event) + In emergency, you could use #GDK_CURRENT_TIME + * + * Requests the contents of a selection. When received, + * a "selection_received" signal will be generated. + * + * Return value: %TRUE if requested succeeded. %FALSE if we could not process + * request. (e.g., there was already a request in process for + * this widget). + **/ gboolean gtk_selection_convert (GtkWidget *widget, GdkAtom selection, GdkAtom target, - guint32 time) + guint32 time_) { GtkRetrievalInfo *info; GList *tmp_list; @@ -728,14 +1070,14 @@ gtk_selection_convert (GtkWidget *widget, { gtk_selection_invoke_handler (owner_widget, &selection_data, - time); + time_); gtk_selection_retrieval_report (info, selection_data.type, selection_data.format, selection_data.data, selection_data.length, - time); + time_); g_free (selection_data.data); @@ -747,25 +1089,26 @@ gtk_selection_convert (GtkWidget *widget, /* Otherwise, we need to go through X */ current_retrievals = g_list_append (current_retrievals, info); - gdk_selection_convert (widget->window, selection, target, time); - g_timeout_add (1000, (GSourceFunc) gtk_selection_retrieval_timeout, info); + gdk_selection_convert (widget->window, selection, target, time_); + gdk_threads_add_timeout (1000, + (GSourceFunc) gtk_selection_retrieval_timeout, info); return TRUE; } -/************************************************************* - * gtk_selection_data_set: - * Store new data into a GtkSelectionData object. Should - * _only_ by called from a selection handler callback. - * Null terminates the stored data. - * arguments: - * type: the type of selection data - * format: format (number of bits in a unit) - * data: pointer to the data (will be copied) - * length: length of the data - * results: - *************************************************************/ +/** + * gtk_selection_data_set: + * @selection_data: a pointer to a #GtkSelectionData structure. + * @type: the type of selection data + * @format: format (number of bits in a unit) + * @data: pointer to the data (will be copied) + * @length: length of the data + * + * Stores new data into a #GtkSelectionData object. Should + * only be called from a selection handler callback. + * Zero-terminates the stored data. + **/ void gtk_selection_data_set (GtkSelectionData *selection_data, GdkAtom type, @@ -773,8 +1116,7 @@ gtk_selection_data_set (GtkSelectionData *selection_data, const guchar *data, gint length) { - if (selection_data->data) - g_free (selection_data->data); + g_free (selection_data->data); selection_data->type = type; selection_data->format = format; @@ -798,21 +1140,6 @@ gtk_selection_data_set (GtkSelectionData *selection_data, selection_data->length = length; } -static GdkAtom utf8_atom; -static GdkAtom text_atom; -static GdkAtom ctext_atom; - -static void -init_atoms (void) -{ - if (!utf8_atom) - { - utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE); - text_atom = gdk_atom_intern ("TEXT", FALSE); - ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); - } -} - static gboolean selection_set_string (GtkSelectionData *selection_data, const gchar *str, @@ -862,94 +1189,453 @@ selection_set_compound_text (GtkSelectionData *selection_data, return result; } +/* Normalize \r and \n into \r\n + */ +static gchar * +normalize_to_crlf (const gchar *str, + gint len) +{ + GString *result = g_string_sized_new (len); + const gchar *p = str; + + while (1) + { + if (*p == '\n') + g_string_append_c (result, '\r'); + + if (*p == '\r') + { + g_string_append_c (result, *p); + p++; + if (*p != '\n') + g_string_append_c (result, '\n'); + } + + if (*p == '\0') + break; + + g_string_append_c (result, *p); + p++; + } + + return g_string_free (result, FALSE); +} + +/* Normalize \r and \r\n into \n + */ +static gchar * +normalize_to_lf (gchar *str, + gint len) +{ + GString *result = g_string_sized_new (len); + const gchar *p = str; + + while (1) + { + if (*p == '\r') + { + p++; + if (*p != '\n') + g_string_append_c (result, '\n'); + } + + if (*p == '\0') + break; + + g_string_append_c (result, *p); + p++; + } + + return g_string_free (result, FALSE); +} + +static gboolean +selection_set_text_plain (GtkSelectionData *selection_data, + const gchar *str, + gint len) +{ + const gchar *charset = NULL; + gchar *result; + GError *error = NULL; + + result = normalize_to_crlf (str, len); + if (selection_data->target == text_plain_atom) + charset = "ASCII"; + else if (selection_data->target == text_plain_locale_atom) + g_get_charset (&charset); + + if (charset) + { + gchar *tmp = result; + result = g_convert_with_fallback (tmp, -1, + charset, "UTF-8", + NULL, NULL, NULL, &error); + g_free (tmp); + } + + if (!result) + { + g_warning ("Error converting from %s to %s: %s", + "UTF-8", charset, error->message); + g_error_free (error); + + return FALSE; + } + + gtk_selection_data_set (selection_data, + selection_data->target, + 8, result, strlen (result)); + g_free (result); + + return TRUE; +} + +static gchar * +selection_get_text_plain (GtkSelectionData *selection_data) +{ + const gchar *charset = NULL; + gchar *str, *result; + gsize len; + GError *error = NULL; + + str = g_strdup (selection_data->data); + len = selection_data->length; + + if (selection_data->type == text_plain_atom) + charset = "ISO-8859-1"; + else if (selection_data->type == text_plain_locale_atom) + g_get_charset (&charset); + + if (charset) + { + gchar *tmp = str; + str = g_convert_with_fallback (tmp, len, + "UTF-8", charset, + NULL, NULL, &len, &error); + g_free (tmp); + + if (!str) + { + g_warning ("Error converting from %s to %s: %s", + charset, "UTF-8", error->message); + g_error_free (error); + + return NULL; + } + } + else if (!g_utf8_validate (str, -1, NULL)) + { + g_warning ("Error converting from %s to %s: %s", + "text/plain;charset=utf-8", "UTF-8", "invalid UTF-8"); + g_free (str); + + return NULL; + } + + result = normalize_to_lf (str, len); + g_free (str); + + return result; +} + /** * gtk_selection_data_set_text: * @selection_data: a #GtkSelectionData * @str: a UTF-8 string * @len: the length of @str, or -1 if @str is nul-terminated. * - * Sets the contents of the selection from a UTF-8 encoded string. + * Sets the contents of the selection from a UTF-8 encoded string. + * The string is converted to the form determined by + * @selection_data->target. + * + * Return value: %TRUE if the selection was successfully set, + * otherwise %FALSE. + **/ +gboolean +gtk_selection_data_set_text (GtkSelectionData *selection_data, + const gchar *str, + gint len) +{ + if (len < 0) + len = strlen (str); + + init_atoms (); + + if (selection_data->target == utf8_atom) + { + gtk_selection_data_set (selection_data, + utf8_atom, + 8, (guchar *)str, len); + return TRUE; + } + else if (selection_data->target == GDK_TARGET_STRING) + { + return selection_set_string (selection_data, str, len); + } + else if (selection_data->target == ctext_atom || + selection_data->target == text_atom) + { + if (selection_set_compound_text (selection_data, str, len)) + return TRUE; + else if (selection_data->target == text_atom) + return selection_set_string (selection_data, str, len); + } + else if (selection_data->target == text_plain_atom || + selection_data->target == text_plain_utf8_atom || + selection_data->target == text_plain_locale_atom) + { + return selection_set_text_plain (selection_data, str, len); + } + + return FALSE; +} + +/** + * gtk_selection_data_get_text: + * @selection_data: a #GtkSelectionData + * + * Gets the contents of the selection data as a UTF-8 string. + * + * Return value: if the selection data contained a recognized + * text type and it could be converted to UTF-8, a newly allocated + * string containing the converted text, otherwise %NULL. + * If the result is non-%NULL it must be freed with g_free(). + **/ +guchar * +gtk_selection_data_get_text (GtkSelectionData *selection_data) +{ + guchar *result = NULL; + + init_atoms (); + + if (selection_data->length >= 0 && + (selection_data->type == GDK_TARGET_STRING || + selection_data->type == ctext_atom || + selection_data->type == utf8_atom)) + { + gchar **list; + gint i; + gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display, + selection_data->type, + selection_data->format, + selection_data->data, + selection_data->length, + &list); + if (count > 0) + result = list[0]; + + for (i = 1; i < count; i++) + g_free (list[i]); + g_free (list); + } + else if (selection_data->length >= 0 && + (selection_data->type == text_plain_atom || + selection_data->type == text_plain_utf8_atom || + selection_data->type == text_plain_locale_atom)) + { + result = selection_get_text_plain (selection_data); + } + + return result; +} + +/** + * gtk_selection_data_set_pixbuf: + * @selection_data: a #GtkSelectionData + * @pixbuf: a #GdkPixbuf + * + * Sets the contents of the selection from a #GdkPixbuf + * The pixbuf is converted to the form determined by + * @selection_data->target. + * + * Return value: %TRUE if the selection was successfully set, + * otherwise %FALSE. + * + * Since: 2.6 + **/ +gboolean +gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data, + GdkPixbuf *pixbuf) +{ + GSList *formats, *f; + gchar **mimes, **m; + GdkAtom atom; + gboolean result; + gchar *str, *type; + gsize len; + + formats = gdk_pixbuf_get_formats (); + + for (f = formats; f; f = f->next) + { + GdkPixbufFormat *fmt = f->data; + + mimes = gdk_pixbuf_format_get_mime_types (fmt); + for (m = mimes; *m; m++) + { + atom = gdk_atom_intern (*m, FALSE); + if (selection_data->target == atom) + { + str = NULL; + type = gdk_pixbuf_format_get_name (fmt); + result = gdk_pixbuf_save_to_buffer (pixbuf, &str, &len, + type, NULL, + ((strcmp (type, "png") == 0) ? + "compression" : NULL), "2", + NULL); + if (result) + gtk_selection_data_set (selection_data, + atom, 8, (guchar *)str, len); + g_free (type); + g_free (str); + g_strfreev (mimes); + g_slist_free (formats); + + return result; + } + } + + g_strfreev (mimes); + } + + g_slist_free (formats); + + return FALSE; +} + +/** + * gtk_selection_data_get_pixbuf: + * @selection_data: a #GtkSelectionData + * + * Gets the contents of the selection data as a #GdkPixbuf. + * + * Return value: if the selection data contained a recognized + * image type and it could be converted to a #GdkPixbuf, a + * newly allocated pixbuf is returned, otherwise %NULL. + * If the result is non-%NULL it must be freed with g_object_unref(). + * + * Since: 2.6 + **/ +GdkPixbuf * +gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data) +{ + GdkPixbufLoader *loader; + GdkPixbuf *result = NULL; + + if (selection_data->length > 0) + { + loader = gdk_pixbuf_loader_new (); + + gdk_pixbuf_loader_write (loader, + selection_data->data, + selection_data->length, + NULL); + gdk_pixbuf_loader_close (loader, NULL); + result = gdk_pixbuf_loader_get_pixbuf (loader); + + if (result) + g_object_ref (result); + + g_object_unref (loader); + } + + return result; +} + +/** + * gtk_selection_data_set_uris: + * @selection_data: a #GtkSelectionData + * @uris: a %NULL-terminated array of strings hilding URIs + * + * Sets the contents of the selection from a list of URIs. * The string is converted to the form determined by * @selection_data->target. * * Return value: %TRUE if the selection was successfully set, * otherwise %FALSE. + * + * Since: 2.6 **/ gboolean -gtk_selection_data_set_text (GtkSelectionData *selection_data, - const gchar *str, - gint len) +gtk_selection_data_set_uris (GtkSelectionData *selection_data, + gchar **uris) { - if (len < 0) - len = strlen (str); - init_atoms (); - if (selection_data->target == utf8_atom) - { - gtk_selection_data_set (selection_data, - utf8_atom, - 8, (guchar *)str, len); - return TRUE; - } - else if (selection_data->target == GDK_TARGET_STRING) + if (selection_data->target == text_uri_list_atom) { - return selection_set_string (selection_data, str, len); - } - else if (selection_data->target == ctext_atom || - selection_data->target == text_atom) - { - if (selection_set_compound_text (selection_data, str, len)) - return TRUE; - else if (selection_data->target == text_atom) - return selection_set_string (selection_data, str, len); + GString *list; + gint i; + gchar *result; + gsize length; + + list = g_string_new (NULL); + for (i = 0; uris[i]; i++) + { + g_string_append (list, uris[i]); + g_string_append (list, "\r\n"); + } + + result = g_convert (list->str, list->len, + "ASCII", "UTF-8", + NULL, &length, NULL); + g_string_free (list, TRUE); + + if (result) + { + gtk_selection_data_set (selection_data, + text_uri_list_atom, + 8, (guchar *)result, length); + + g_free (result); + + return TRUE; + } } return FALSE; } /** - * gtk_selection_data_get_text: + * gtk_selection_data_get_uris: * @selection_data: a #GtkSelectionData * - * Gets the contents of the selection data as a UTF-8 string. + * Gets the contents of the selection data as array of URIs. * - * Return value: if the selection data contained a recognized - * text type and it could be converted to UTF-8, a newly allocated - * string containing the converted text, otherwise %NULL. - * If the result is non-%NULL it must be freed with g_free(). + * Return value: if the selection data contains a list of + * URIs, a newly allocated %NULL-terminated string array + * containing the URIs, otherwise %NULL. If the result is + * non-%NULL it must be freed with g_strfreev(). + * + * Since: 2.6 **/ -guchar * -gtk_selection_data_get_text (GtkSelectionData *selection_data) +gchar ** +gtk_selection_data_get_uris (GtkSelectionData *selection_data) { - guchar *result = NULL; + gchar **result = NULL; init_atoms (); if (selection_data->length >= 0 && - (selection_data->type == GDK_TARGET_STRING || - selection_data->type == ctext_atom || - selection_data->type == utf8_atom)) + selection_data->type == text_uri_list_atom) { gchar **list; - gint i; gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display, - selection_data->type, + utf8_atom, selection_data->format, selection_data->data, selection_data->length, &list); if (count > 0) - result = list[0]; - - for (i = 1; i < count; i++) - g_free (list[i]); - g_free (list); + result = g_uri_list_extract_uris (list[0]); + + g_strfreev (list); } return result; } + /** * gtk_selection_data_get_targets: * @selection_data: a #GtkSelectionData object @@ -992,6 +1678,98 @@ gtk_selection_data_get_targets (GtkSelectionData *selection_data, } } +/** + * gtk_targets_include_text: + * @targets: an array of #GdkAtoms + * @n_targets: the length of @targets + * + * Determines if any of the targets in @targets can be used to + * provide text. + * + * Return value: %TRUE if @targets include a suitable target for text, + * otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_targets_include_text (GdkAtom *targets, + gint n_targets) +{ + gint i; + gboolean result = FALSE; + + /* Keep in sync with gtk_target_list_add_text_targets() + */ + + init_atoms (); + + for (i = 0; i < n_targets; i++) + { + if (targets[i] == utf8_atom || + targets[i] == text_atom || + targets[i] == GDK_TARGET_STRING || + targets[i] == ctext_atom || + targets[i] == text_plain_atom || + targets[i] == text_plain_utf8_atom || + targets[i] == text_plain_locale_atom) + { + result = TRUE; + break; + } + } + + return result; +} + +/** + * gtk_targets_include_rich_text: + * @targets: an array of #GdkAtoms + * @n_targets: the length of @targets + * @buffer: a #GtkTextBuffer + * + * Determines if any of the targets in @targets can be used to + * provide rich text. + * + * Return value: %TRUE if @targets include a suitable target for rich text, + * otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_targets_include_rich_text (GdkAtom *targets, + gint n_targets, + GtkTextBuffer *buffer) +{ + GdkAtom *rich_targets; + gint n_rich_targets; + gint i, j; + gboolean result = FALSE; + + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); + + init_atoms (); + + rich_targets = gtk_text_buffer_get_deserialize_formats (buffer, + &n_rich_targets); + + for (i = 0; i < n_targets; i++) + { + for (j = 0; j < n_rich_targets; j++) + { + if (targets[i] == rich_targets[j]) + { + result = TRUE; + goto done; + } + } + } + + done: + g_free (rich_targets); + + return result; +} + /** * gtk_selection_data_targets_include_text: * @selection_data: a #GtkSelectionData object @@ -1008,25 +1786,201 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) { GdkAtom *targets; gint n_targets; + gboolean result = FALSE; + + init_atoms (); + + if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) + { + result = gtk_targets_include_text (targets, n_targets); + g_free (targets); + } + + return result; +} + +/** + * gtk_selection_data_targets_include_rich_text: + * @selection_data: a #GtkSelectionData object + * @buffer: a #GtkTextBuffer + * + * Given a #GtkSelectionData object holding a list of targets, + * determines if any of the targets in @targets can be used to + * provide rich text. + * + * Return value: %TRUE if @selection_data holds a list of targets, + * and a suitable target for rich text is included, + * otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data, + GtkTextBuffer *buffer) +{ + GdkAtom *targets; + gint n_targets; + gboolean result = FALSE; + + g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE); + + init_atoms (); + + if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) + { + result = gtk_targets_include_rich_text (targets, n_targets, buffer); + g_free (targets); + } + + return result; +} + +/** + * gtk_targets_include_image: + * @targets: an array of #GdkAtoms + * @n_targets: the length of @targets + * @writable: whether to accept only targets for which GTK+ knows + * how to convert a pixbuf into the format + * + * Determines if any of the targets in @targets can be used to + * provide a #GdkPixbuf. + * + * Return value: %TRUE if @targets include a suitable target for images, + * otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_targets_include_image (GdkAtom *targets, + gint n_targets, + gboolean writable) +{ + GtkTargetList *list; + GList *l; gint i; gboolean result = FALSE; + list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_image_targets (list, 0, writable); + for (i = 0; i < n_targets && !result; i++) + { + for (l = list->list; l; l = l->next) + { + GtkTargetPair *pair = (GtkTargetPair *)l->data; + if (pair->target == targets[i]) + { + result = TRUE; + break; + } + } + } + gtk_target_list_unref (list); + + return result; +} + +/** + * gtk_selection_data_targets_include_image: + * @selection_data: a #GtkSelectionData object + * @writable: whether to accept only targets for which GTK+ knows + * how to convert a pixbuf into the format + * + * Given a #GtkSelectionData object holding a list of targets, + * determines if any of the targets in @targets can be used to + * provide a #GdkPixbuf. + * + * Return value: %TRUE if @selection_data holds a list of targets, + * and a suitable target for images is included, otherwise %FALSE. + * + * Since: 2.6 + **/ +gboolean +gtk_selection_data_targets_include_image (GtkSelectionData *selection_data, + gboolean writable) +{ + GdkAtom *targets; + gint n_targets; + gboolean result = FALSE; + + init_atoms (); + if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) { - for (i=0; i < n_targets; i++) + result = gtk_targets_include_image (targets, n_targets, writable); + g_free (targets); + } + + return result; +} + +/** + * gtk_targets_include_uri: + * @targets: an array of #GdkAtoms + * @n_targets: the length of @targets + * + * Determines if any of the targets in @targets can be used to + * provide an uri list. + * + * Return value: %TRUE if @targets include a suitable target for uri lists, + * otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_targets_include_uri (GdkAtom *targets, + gint n_targets) +{ + gint i; + gboolean result = FALSE; + + /* Keep in sync with gtk_target_list_add_uri_targets() + */ + + init_atoms (); + + for (i = 0; i < n_targets; i++) + { + if (targets[i] == text_uri_list_atom) { - if (targets[i] == gdk_atom_intern ("STRING", FALSE) || - targets[i] == gdk_atom_intern ("TEXT", FALSE) || - targets[i] == gdk_atom_intern ("COMPOUND_TEXT", FALSE) || - targets[i] == gdk_atom_intern ("UTF8_STRING", FALSE)) - result = TRUE; + result = TRUE; + break; } + } + + return result; +} + +/** + * gtk_selection_data_targets_include_uri: + * @selection_data: a #GtkSelectionData object + * + * Given a #GtkSelectionData object holding a list of targets, + * determines if any of the targets in @targets can be used to + * provide a list or URIs. + * + * Return value: %TRUE if @selection_data holds a list of targets, + * and a suitable target for text is included, otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_selection_data_targets_include_uri (GtkSelectionData *selection_data) +{ + GdkAtom *targets; + gint n_targets; + gboolean result = FALSE; + + init_atoms (); + if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) + { + result = gtk_targets_include_uri (targets, n_targets); g_free (targets); } return result; } + /************************************************************* * gtk_selection_init: @@ -1039,10 +1993,10 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) static void gtk_selection_init (void) { - gtk_selection_atoms[INCR] = gdk_atom_intern ("INCR", FALSE); - gtk_selection_atoms[MULTIPLE] = gdk_atom_intern ("MULTIPLE", FALSE); - gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern ("TIMESTAMP", FALSE); - gtk_selection_atoms[TARGETS] = gdk_atom_intern ("TARGETS", FALSE); + gtk_selection_atoms[INCR] = gdk_atom_intern_static_string ("INCR"); + gtk_selection_atoms[MULTIPLE] = gdk_atom_intern_static_string ("MULTIPLE"); + gtk_selection_atoms[TIMESTAMP] = gdk_atom_intern_static_string ("TIMESTAMP"); + gtk_selection_atoms[TARGETS] = gdk_atom_intern_static_string ("TARGETS"); initialize = FALSE; } @@ -1059,7 +2013,7 @@ gtk_selection_init (void) * * Since: 2.2 * - * Deprecated: Instead of calling this function, chain up from + * Deprecated: 2.4: Instead of calling this function, chain up from * your selection_clear_event handler. Calling this function * from any other context is illegal. **/ @@ -1114,10 +2068,13 @@ _gtk_selection_request (GtkWidget *widget, GtkIncrInfo *info; GList *tmp_list; int i; - + gulong selection_max_size; + if (initialize) gtk_selection_init (); + selection_max_size = GTK_SELECTION_MAX_SIZE (display); + /* Check if we own selection */ tmp_list = current_selections; @@ -1163,7 +2120,7 @@ _gtk_selection_request (GtkWidget *widget, gdk_error_trap_push (); if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */ - 0, GTK_SELECTION_MAX_SIZE, FALSE, + 0, selection_max_size, FALSE, &type, &format, &length, &mult_atoms)) { gdk_selection_send_notify_for_display (display, @@ -1174,6 +2131,7 @@ _gtk_selection_request (GtkWidget *widget, event->time); g_free (mult_atoms); g_free (info); + gdk_error_trap_pop (); return TRUE; } gdk_error_trap_pop (); @@ -1184,7 +2142,7 @@ _gtk_selection_request (GtkWidget *widget, */ #ifdef GDK_WINDOWING_X11 if (type != GDK_SELECTION_TYPE_ATOM && - type != gdk_atom_intern ("ATOM_PAIR", FALSE)) + type != gdk_atom_intern_static_string ("ATOM_PAIR")) { info->num_conversions = length / (2*sizeof (glong)); info->conversions = g_new (GtkIncrConversion, info->num_conversions); @@ -1196,6 +2154,8 @@ _gtk_selection_request (GtkWidget *widget, info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display, ((glong *)mult_atoms)[2*i + 1]); } + + g_free (mult_atoms); } else #endif @@ -1208,6 +2168,8 @@ _gtk_selection_request (GtkWidget *widget, info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i]; info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1]; } + + g_free (mult_atoms); } } else /* only a single conversion */ @@ -1233,9 +2195,10 @@ _gtk_selection_request (GtkWidget *widget, #ifdef DEBUG_SELECTION g_message ("Selection %ld, target %ld (%s) requested by 0x%x (property = %ld)", - event->selection, info->conversions[i].target, + event->selection, + info->conversions[i].target, gdk_atom_name (info->conversions[i].target), - event->requestor, event->property); + event->requestor, info->conversions[i].property); #endif gtk_selection_invoke_handler (widget, &data, event->time); @@ -1250,9 +2213,13 @@ _gtk_selection_request (GtkWidget *widget, items = data.length / gtk_selection_bytes_per_item (data.format); - if (data.length > GTK_SELECTION_MAX_SIZE) + if (data.length > selection_max_size) { /* Sending via INCR */ +#ifdef DEBUG_SELECTION + g_message ("Target larger (%d) than max. request size (%ld), sending incrementally\n", + data.length, selection_max_size); +#endif info->conversions[i].offset = 0; info->conversions[i].data = data; @@ -1296,7 +2263,7 @@ _gtk_selection_request (GtkWidget *widget, gdk_window_get_events (info->requestor) | GDK_PROPERTY_CHANGE_MASK); current_incrs = g_list_append (current_incrs, info); - g_timeout_add (1000, (GSourceFunc) gtk_selection_incr_timeout, info); + gdk_threads_add_timeout (1000, (GSourceFunc) gtk_selection_incr_timeout, info); } /* If it was a MULTIPLE request, set the property to indicate which @@ -1311,7 +2278,7 @@ _gtk_selection_request (GtkWidget *widget, } gdk_property_change (info->requestor, event->property, - gdk_atom_intern ("ATOM_PAIR", FALSE), 32, + gdk_atom_intern_static_string ("ATOM_PAIR"), 32, GDK_PROP_MODE_REPLACE, (guchar *)mult_atoms, 2*info->num_conversions); g_free (mult_atoms); @@ -1372,6 +2339,7 @@ _gtk_selection_incr_event (GdkWindow *window, GtkIncrInfo *info = NULL; gint num_bytes; guchar *buffer; + gulong selection_max_size; int i; @@ -1381,7 +2349,9 @@ _gtk_selection_incr_event (GdkWindow *window, #ifdef DEBUG_SELECTION g_message ("PropertyDelete, property %ld", event->atom); #endif - + + selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window)); + /* Now find the appropriate ongoing INCR */ tmp_list = current_incrs; while (tmp_list) @@ -1419,10 +2389,10 @@ _gtk_selection_incr_event (GdkWindow *window, buffer = info->conversions[i].data.data + info->conversions[i].offset; - if (num_bytes > GTK_SELECTION_MAX_SIZE) + if (num_bytes > selection_max_size) { - num_bytes = GTK_SELECTION_MAX_SIZE; - info->conversions[i].offset += GTK_SELECTION_MAX_SIZE; + num_bytes = selection_max_size; + info->conversions[i].offset += selection_max_size; } else info->conversions[i].offset = -2; @@ -1453,7 +2423,6 @@ _gtk_selection_incr_event (GdkWindow *window, info->conversions[i].offset = -1; } } - break; } /* Check if we're finished with all the targets */ @@ -1483,8 +2452,6 @@ gtk_selection_incr_timeout (GtkIncrInfo *info) GList *tmp_list; gboolean retval; - GDK_THREADS_ENTER (); - /* Determine if retrieval has finished by checking if it still in list of pending retrievals */ @@ -1520,8 +2487,6 @@ gtk_selection_incr_timeout (GtkIncrInfo *info) retval = TRUE; /* timeout will happen again */ } - GDK_THREADS_LEAVE (); - return retval; } @@ -1643,7 +2608,7 @@ _gtk_selection_property_notify (GtkWidget *widget, #if defined(GDK_WINDOWING_WIN32) || defined(GDK_WINDOWING_X11) if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */ - (event->atom != gdk_atom_intern ("GDK_SELECTION", FALSE))) /* not the right property */ + (event->atom != gdk_atom_intern_static_string ("GDK_SELECTION"))) /* not the right property */ #endif return FALSE; @@ -1727,14 +2692,12 @@ _gtk_selection_property_notify (GtkWidget *widget, * results: *************************************************************/ -static gint +static gboolean gtk_selection_retrieval_timeout (GtkRetrievalInfo *info) { GList *tmp_list; gboolean retval; - GDK_THREADS_ENTER (); - /* Determine if retrieval has finished by checking if it still in list of pending retrievals */ @@ -1768,8 +2731,6 @@ gtk_selection_retrieval_timeout (GtkRetrievalInfo *info) retval = TRUE; /* timeout will happen again */ } - GDK_THREADS_LEAVE (); - return retval; } @@ -1932,32 +2893,46 @@ gtk_selection_default_handler (GtkWidget *widget, } +/** + * gtk_selection_data_copy: + * @data: a pointer to a #GtkSelectionData structure. + * + * Makes a copy of a #GtkSelectionData structure and its data. + * + * Return value: a pointer to a copy of @data. + **/ GtkSelectionData* -gtk_selection_data_copy (GtkSelectionData *selection_data) +gtk_selection_data_copy (GtkSelectionData *data) { GtkSelectionData *new_data; - g_return_val_if_fail (selection_data != NULL, NULL); + g_return_val_if_fail (data != NULL, NULL); new_data = g_new (GtkSelectionData, 1); - *new_data = *selection_data; + *new_data = *data; - if (selection_data->data) + if (data->data) { - new_data->data = g_malloc (selection_data->length + 1); - memcpy (new_data->data, selection_data->data, selection_data->length + 1); + new_data->data = g_malloc (data->length + 1); + memcpy (new_data->data, data->data, data->length + 1); } return new_data; } +/** + * gtk_selection_data_free: + * @data: a pointer to a #GtkSelectionData structure. + * + * Frees a #GtkSelectionData structure returned from + * gtk_selection_data_copy(). + **/ void gtk_selection_data_free (GtkSelectionData *data) { g_return_if_fail (data != NULL); - if (data->data) - g_free (data->data); + g_free (data->data); g_free (data); } @@ -1968,13 +2943,26 @@ gtk_selection_data_get_type (void) static GType our_type = 0; if (our_type == 0) - our_type = g_boxed_type_register_static ("GtkSelectionData", + our_type = g_boxed_type_register_static (I_("GtkSelectionData"), (GBoxedCopyFunc) gtk_selection_data_copy, (GBoxedFreeFunc) gtk_selection_data_free); return our_type; } +GType +gtk_target_list_get_type (void) +{ + static GType our_type = 0; + + if (our_type == 0) + our_type = g_boxed_type_register_static (I_("GtkTargetList"), + (GBoxedCopyFunc) gtk_target_list_ref, + (GBoxedFreeFunc) gtk_target_list_unref); + + return our_type; +} + static int gtk_selection_bytes_per_item (gint format) { @@ -1994,3 +2982,6 @@ gtk_selection_bytes_per_item (gint format) } return 0; } + +#define __GTK_SELECTION_C__ +#include "gtkaliasdef.c"