X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkselection.c;h=67a774f7683107abffe95c8d9a9ddef0e1b6f7f7;hb=ea043cab5718304d9b6170afa2d3f959fc99c718;hp=cb5e872ca289f91c391470254b4458f17c8255d1;hpb=8cdee385b98c09c732c2fd494b9ea845f4e74272;p=~andy%2Fgtk diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c index cb5e872ca..67a774f76 100644 --- a/gtk/gtkselection.c +++ b/gtk/gtkselection.c @@ -12,9 +12,7 @@ * 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. + * License along with this library. If not, see . */ /* This file implements most of the work of the ICCCM selection protocol. @@ -51,13 +49,45 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ -#include +/** + * SECTION:gtkselection + * @Title: Selections + * @Short_description: Functions for handling inter-process communication + * via selections + * @See_also: #GtkWidget - Much of the operation of selections happens via + * signals for #GtkWidget. In particular, if you are using the functions + * in this section, you may need to pay attention to + * #GtkWidget::selection-get, #GtkWidget::selection-received and + * #GtkWidget::selection-clear-event signals + * + * The selection mechanism provides the basis for different types + * of communication between processes. In particular, drag and drop and + * #GtkClipboard work via selections. You will very seldom or + * never need to use most of the functions in this section directly; + * #GtkClipboard provides a nicer interface to the same functionality. + * + * Some of the datatypes defined this section are used in + * the #GtkClipboard and drag-and-drop API's as well. The + * #GtkTargetEntry structure and #GtkTargetList objects represent + * lists of data types that are supported when sending or + * receiving data. The #GtkSelectionData object is used to + * store a chunk of data along with the data type and other + * associated information. + */ + +#include "config.h" + +#include "gtkselection.h" +#include "gtkselectionprivate.h" + #include #include #include "gdk.h" #include "gtkmain.h" -#include "gtkselection.h" +#include "gtkdebug.h" +#include "gtktextbufferrichtext.h" +#include "gtkintl.h" #include "gdk-pixbuf/gdk-pixbuf.h" #ifdef GDK_WINDOWING_X11 @@ -68,8 +98,6 @@ #include "win32/gdkwin32.h" #endif -#include "gtkalias.h" - #undef DEBUG_SELECTION /* Maximum size of a sent chunk, in bytes. Also the default size of @@ -92,6 +120,7 @@ enum { MULTIPLE, TARGETS, TIMESTAMP, + SAVE_TARGETS, LAST_ATOM }; @@ -150,8 +179,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, @@ -185,18 +214,18 @@ static const char gtk_selection_handler_key[] = "gtk-selection-handlers"; /** * gtk_target_list_new: - * @targets: Pointer to an array of #GtkTargetEntry - * @ntargets: number of entries in @targets. + * @targets: (array length=ntargets): 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. + * Return value: (transfer full): the new #GtkTargetList. **/ GtkTargetList * gtk_target_list_new (const GtkTargetEntry *targets, guint ntargets) { - GtkTargetList *result = g_new (GtkTargetList, 1); + GtkTargetList *result = g_slice_new (GtkTargetList); result->list = NULL; result->ref_count = 1; @@ -212,13 +241,16 @@ gtk_target_list_new (const GtkTargetEntry *targets, * * Increases the reference count of a #GtkTargetList by one. * + * Return value: the passed in #GtkTargetList. **/ -void +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; } /** @@ -241,13 +273,13 @@ gtk_target_list_unref (GtkTargetList *list) while (tmp_list) { GtkTargetPair *pair = tmp_list->data; - g_free (pair); + g_slice_free (GtkTargetPair, pair); tmp_list = tmp_list->next; } g_list_free (list->list); - g_free (list); + g_slice_free (GtkTargetList, list); } } @@ -270,7 +302,7 @@ gtk_target_list_add (GtkTargetList *list, g_return_if_fail (list != NULL); - pair = g_new (GtkTargetPair, 1); + pair = g_slice_new (GtkTargetPair); pair->target = target; pair->flags = flags; pair->info = info; @@ -294,17 +326,17 @@ 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); - text_plain_atom = gdk_atom_intern ("text/plain", FALSE); - text_plain_utf8_atom = gdk_atom_intern ("text/plain;charset=utf-8", FALSE); + 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 ("text/uri-list", FALSE); + text_uri_list_atom = gdk_atom_intern_static_string ("text/uri-list"); } } @@ -333,10 +365,50 @@ gtk_target_list_add_text_targets (GtkTargetList *list, 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); + if (!g_get_charset (NULL)) + 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 @@ -425,7 +497,7 @@ gtk_target_list_add_uri_targets (GtkTargetList *list, /** * gtk_target_list_add_table: * @list: a #GtkTargetList - * @targets: the table of #GtkTargetEntry + * @targets: (array length=ntargets): the table of #GtkTargetEntry * @ntargets: number of targets in the table * * Prepends a table of #GtkTargetEntry to a target list. @@ -439,7 +511,7 @@ gtk_target_list_add_table (GtkTargetList *list, for (i=ntargets-1; i >= 0; i--) { - GtkTargetPair *pair = g_new (GtkTargetPair, 1); + GtkTargetPair *pair = g_slice_new (GtkTargetPair); pair->target = gdk_atom_intern (targets[i].target, FALSE); pair->flags = targets[i].flags; pair->info = targets[i].info; @@ -470,7 +542,7 @@ gtk_target_list_remove (GtkTargetList *list, if (pair->target == target) { - g_free (pair); + g_slice_free (GtkTargetPair, pair); list->list = g_list_remove_link (list->list, tmp_list); g_list_free_1 (tmp_list); @@ -486,10 +558,11 @@ 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 - * + * @info: a pointer to the location to store application info for target, + * or %NULL + * * Looks up a given target in a #GtkTargetList. - * + * * Return value: %TRUE if the target was found, otherwise %FALSE **/ gboolean @@ -497,26 +570,99 @@ gtk_target_list_find (GtkTargetList *list, GdkAtom target, guint *info) { - GList *tmp_list = list->list; + GList *tmp_list; + + g_return_val_if_fail (list != NULL, FALSE); + + tmp_list = list->list; while (tmp_list) { GtkTargetPair *pair = tmp_list->data; if (pair->target == target) { - *info = pair->info; + if (info) + *info = pair->info; + return TRUE; } + tmp_list = tmp_list->next; } return FALSE; } +/** + * gtk_target_table_new_from_list: + * @list: a #GtkTargetList + * @n_targets: (out): 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: (array length=n_targets) (transfer full): 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: (array length=n_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 - * @widget: new selection owner (a #GdkWidget), or %NULL. + * @display: the #GdkDisplay where the selection is set + * @widget: (allow-none): new selection owner (a #GtkWidget), or %NULL. * @selection: an interned atom representing the selection to claim. * @time_: timestamp with which to claim the selection * @@ -540,13 +686,13 @@ gtk_selection_owner_set_for_display (GdkDisplay *display, g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE); g_return_val_if_fail (selection != GDK_NONE, FALSE); - g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE); + g_return_val_if_fail (widget == NULL || gtk_widget_get_realized (widget), FALSE); g_return_val_if_fail (widget == NULL || gtk_widget_get_display (widget) == display, FALSE); if (widget == NULL) window = NULL; else - window = widget->window; + window = gtk_widget_get_window (widget); tmp_list = current_selections; while (tmp_list) @@ -572,14 +718,14 @@ gtk_selection_owner_set_for_display (GdkDisplay *display, current_selections = g_list_remove_link (current_selections, tmp_list); g_list_free (tmp_list); - g_free (selection_info); + g_slice_free (GtkSelectionInfo, selection_info); } } else { if (selection_info == NULL) { - selection_info = g_new (GtkSelectionInfo, 1); + selection_info = g_slice_new (GtkSelectionInfo); selection_info->selection = selection; selection_info->widget = widget; selection_info->time = time; @@ -601,8 +747,8 @@ gtk_selection_owner_set_for_display (GdkDisplay *display, if (old_owner && old_owner != widget) { GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR); - - event->selection.window = g_object_ref (old_owner->window); + + event->selection.window = g_object_ref (gtk_widget_get_window (old_owner)); event->selection.selection = selection; event->selection.time = time; @@ -618,7 +764,7 @@ gtk_selection_owner_set_for_display (GdkDisplay *display, /** * gtk_selection_owner_set: - * @widget: a #GtkWidget, or %NULL. + * @widget: (allow-none): a #GtkWidget, or %NULL. * @selection: an interned atom representing the selection to claim * @time_: timestamp with which to claim the selection * @@ -634,7 +780,7 @@ gtk_selection_owner_set (GtkWidget *widget, { GdkDisplay *display; - g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE); + g_return_val_if_fail (widget == NULL || gtk_widget_get_realized (widget), FALSE); g_return_val_if_fail (selection != GDK_NONE, FALSE); if (widget) @@ -677,12 +823,12 @@ gtk_selection_target_list_get (GtkWidget *widget, tmp_list = tmp_list->next; } - sellist = g_new (GtkSelectionTargetList, 1); + sellist = g_slice_new (GtkSelectionTargetList); sellist->selection = selection; 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; } @@ -703,12 +849,12 @@ gtk_selection_target_list_remove (GtkWidget *widget) gtk_target_list_unref (sellist->list); - g_free (sellist); + g_slice_free (GtkSelectionTargetList, sellist); tmp_list = tmp_list->next; } 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); } /** @@ -740,7 +886,7 @@ gtk_selection_clear_targets (GtkWidget *widget, { lists = g_list_delete_link (lists, tmp_list); gtk_target_list_unref (sellist->list); - g_free (sellist); + g_slice_free (GtkSelectionTargetList, sellist); break; } @@ -748,7 +894,7 @@ 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); } /** @@ -775,7 +921,7 @@ 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); + gdk_win32_selection_add_targets (gtk_widget_get_window (widget), selection, 1, &target); #endif } @@ -783,7 +929,7 @@ gtk_selection_add_target (GtkWidget *widget, * gtk_selection_add_targets: * @widget: a #GtkWidget * @selection: the selection - * @targets: a table of targets to add + * @targets: (array length=ntargets): a table of targets to add * @ntargets: number of entries in @targets * * Prepends a table of targets to the list of supported targets @@ -811,7 +957,7 @@ gtk_selection_add_targets (GtkWidget *widget, 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); + gdk_win32_selection_add_targets (gtk_widget_get_window (widget), selection, ntargets, atoms); g_free (atoms); } #endif @@ -833,7 +979,9 @@ gtk_selection_remove_all (GtkWidget *widget) GList *tmp_list; GList *next; GtkSelectionInfo *selection_info; - + + g_return_if_fail (GTK_IS_WIDGET (widget)); + /* Remove pending requests/incrs for this widget */ tmp_list = current_retrievals; @@ -867,7 +1015,7 @@ gtk_selection_remove_all (GtkWidget *widget) current_selections = g_list_remove_link (current_selections, tmp_list); g_list_free (tmp_list); - g_free (selection_info); + g_slice_free (GtkSelectionInfo, selection_info); } tmp_list = next; @@ -887,7 +1035,7 @@ gtk_selection_remove_all (GtkWidget *widget) In emergency, you could use #GDK_CURRENT_TIME * * Requests the contents of a selection. When received, - * a "selection_received" signal will be generated. + * 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 @@ -910,7 +1058,7 @@ gtk_selection_convert (GtkWidget *widget, if (initialize) gtk_selection_init (); - if (!GTK_WIDGET_REALIZED (widget)) + if (!gtk_widget_get_realized (widget)) gtk_widget_realize (widget); /* Check to see if there are already any retrievals in progress for @@ -928,7 +1076,7 @@ gtk_selection_convert (GtkWidget *widget, tmp_list = tmp_list->next; } - info = g_new (GtkRetrievalInfo, 1); + info = g_slice_new (GtkRetrievalInfo); info->widget = widget; info->selection = selection; @@ -946,15 +1094,16 @@ gtk_selection_convert (GtkWidget *widget, if (owner_window != NULL) { GtkWidget *owner_widget; - GtkSelectionData selection_data; + gpointer owner_widget_ptr; + GtkSelectionData selection_data = {0}; selection_data.selection = selection; selection_data.target = target; - selection_data.data = NULL; selection_data.length = -1; selection_data.display = display; - gdk_window_get_user_data (owner_window, (gpointer *)&owner_widget); + gdk_window_get_user_data (owner_window, &owner_widget_ptr); + owner_widget = owner_widget_ptr; if (owner_widget != NULL) { @@ -970,8 +1119,10 @@ gtk_selection_convert (GtkWidget *widget, time_); g_free (selection_data.data); + selection_data.data = NULL; + selection_data.length = -1; - g_free (info); + g_slice_free (GtkRetrievalInfo, info); return TRUE; } } @@ -979,19 +1130,168 @@ 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 (gtk_widget_get_window (widget), selection, target, time_); + gdk_threads_add_timeout (1000, + (GSourceFunc) gtk_selection_retrieval_timeout, info); return TRUE; } +/** + * gtk_selection_data_get_selection: + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the selection #GdkAtom of the selection data. + * + * Returns: (transfer none): the selection #GdkAtom of the selection data. + * + * Since: 2.16 + **/ +GdkAtom +gtk_selection_data_get_selection (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, 0); + + return selection_data->selection; +} + +/** + * gtk_selection_data_get_target: + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the target of the selection. + * + * Returns: (transfer none): the target of the selection. + * + * Since: 2.14 + **/ +GdkAtom +gtk_selection_data_get_target (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, 0); + + return selection_data->target; +} + +/** + * gtk_selection_data_get_data_type: + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the data type of the selection. + * + * Returns: (transfer none): the data type of the selection. + * + * Since: 2.14 + **/ +GdkAtom +gtk_selection_data_get_data_type (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, 0); + + return selection_data->type; +} + +/** + * gtk_selection_data_get_format: + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the format of the selection. + * + * Returns: the format of the selection. + * + * Since: 2.14 + **/ +gint +gtk_selection_data_get_format (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, 0); + + return selection_data->format; +} + +/** + * gtk_selection_data_get_data: (skip) + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the raw data of the selection. + * + * Returns: the raw data of the selection. + * + * Since: 2.14 + **/ +const guchar* +gtk_selection_data_get_data (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, NULL); + + return selection_data->data; +} + +/** + * gtk_selection_data_get_length: + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the length of the raw data of the selection. + * + * Returns: the length of the data of the selection. + * + * Since: 2.14 + */ +gint +gtk_selection_data_get_length (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, -1); + + return selection_data->length; +} + +/** + * gtk_selection_data_get_data_with_length: + * @selection_data: a pointer to a #GtkSelectionData structure + * @length: (out): return location for length of the data segment + * + * Retrieves the raw data of the selection along with its length. + * + * Returns: (array length=length): the raw data of the selection + * + * Rename to: gtk_selection_data_get_data + * Since: 3.0 + */ +const guchar* +gtk_selection_data_get_data_with_length (const GtkSelectionData *selection_data, + gint *length) +{ + g_return_val_if_fail (selection_data != NULL, NULL); + + *length = selection_data->length; + + return selection_data->data; +} + +/** + * gtk_selection_data_get_display: + * @selection_data: a pointer to a #GtkSelectionData structure. + * + * Retrieves the display of the selection. + * + * Returns: (transfer none): the display of the selection. + * + * Since: 2.14 + **/ +GdkDisplay * +gtk_selection_data_get_display (const GtkSelectionData *selection_data) +{ + g_return_val_if_fail (selection_data != NULL, NULL); + + return selection_data->display; +} /** * 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) + * @data: (array length=length): pointer to the data (will be copied) * @length: length of the data * * Stores new data into a #GtkSelectionData object. Should @@ -1005,8 +1305,9 @@ gtk_selection_data_set (GtkSelectionData *selection_data, const guchar *data, gint length) { - if (selection_data->data) - g_free (selection_data->data); + g_return_if_fail (selection_data != NULL); + + g_free (selection_data->data); selection_data->type = type; selection_data->format = format; @@ -1024,7 +1325,7 @@ gtk_selection_data_set (GtkSelectionData *selection_data, if (length < 0) selection_data->data = NULL; else - selection_data->data = g_strdup(""); + selection_data->data = (guchar *) g_strdup (""); } selection_data->length = length; @@ -1043,7 +1344,7 @@ selection_set_string (GtkSelectionData *selection_data, { gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING, - 8, latin1, strlen (latin1)); + 8, (guchar *) latin1, strlen (latin1)); g_free (latin1); return TRUE; @@ -1063,18 +1364,22 @@ selection_set_compound_text (GtkSelectionData *selection_data, gint format; gint new_length; gboolean result = FALSE; - - tmp = g_strndup (str, len); - if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp, - &encoding, &format, &text, &new_length)) + +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY (selection_data->display)) { - gtk_selection_data_set (selection_data, encoding, format, text, new_length); - gdk_free_compound_text (text); - - result = TRUE; - } + tmp = g_strndup (str, len); + if (gdk_x11_display_utf8_to_compound_text (selection_data->display, tmp, + &encoding, &format, &text, &new_length)) + { + gtk_selection_data_set (selection_data, encoding, format, text, new_length); + gdk_x11_free_compound_text (text); - g_free (tmp); + result = TRUE; + } + g_free (tmp); + } +#endif return result; } @@ -1087,8 +1392,9 @@ normalize_to_crlf (const gchar *str, { GString *result = g_string_sized_new (len); const gchar *p = str; + const gchar *end = str + len; - while (1) + while (p < end) { if (*p == '\n') g_string_append_c (result, '\r'); @@ -1097,13 +1403,12 @@ normalize_to_crlf (const gchar *str, { g_string_append_c (result, *p); p++; - if (*p != '\n') + if (p == end || *p != '\n') g_string_append_c (result, '\n'); + if (p == end) + break; } - if (*p == '\0') - break; - g_string_append_c (result, *p); p++; } @@ -1165,8 +1470,8 @@ selection_set_text_plain (GtkSelectionData *selection_data, if (!result) { - g_warning ("Error converting from UTF-8 to %s: %s", - charset, error->message); + g_warning ("Error converting from %s to %s: %s", + "UTF-8", charset, error->message); g_error_free (error); return FALSE; @@ -1174,21 +1479,21 @@ selection_set_text_plain (GtkSelectionData *selection_data, gtk_selection_data_set (selection_data, selection_data->target, - 8, result, strlen (result)); + 8, (guchar *) result, strlen (result)); g_free (result); return TRUE; } -static gchar * -selection_get_text_plain (GtkSelectionData *selection_data) +static guchar * +selection_get_text_plain (const GtkSelectionData *selection_data) { const gchar *charset = NULL; gchar *str, *result; gsize len; GError *error = NULL; - str = g_strdup (selection_data->data); + str = g_strdup ((const gchar *) selection_data->data); len = selection_data->length; if (selection_data->type == text_plain_atom) @@ -1200,14 +1505,14 @@ selection_get_text_plain (GtkSelectionData *selection_data) { gchar *tmp = str; str = g_convert_with_fallback (tmp, len, - charset, "UTF-8", + "UTF-8", charset, NULL, NULL, &len, &error); g_free (tmp); if (!str) { - g_warning ("Error converting from %s to UTF-8: %s", - charset, error->message); + g_warning ("Error converting from %s to %s: %s", + charset, "UTF-8", error->message); g_error_free (error); return NULL; @@ -1215,7 +1520,8 @@ selection_get_text_plain (GtkSelectionData *selection_data) } else if (!g_utf8_validate (str, -1, NULL)) { - g_warning ("Error converting from text/plain;charset=utf-8 to UTF-8"); + g_warning ("Error converting from %s to %s: %s", + "text/plain;charset=utf-8", "UTF-8", "invalid UTF-8"); g_free (str); return NULL; @@ -1224,7 +1530,7 @@ selection_get_text_plain (GtkSelectionData *selection_data) result = normalize_to_lf (str, len); g_free (str); - return result; + return (guchar *) result; } /** @@ -1245,6 +1551,8 @@ gtk_selection_data_set_text (GtkSelectionData *selection_data, const gchar *str, gint len) { + g_return_val_if_fail (selection_data != NULL, FALSE); + if (len < 0) len = strlen (str); @@ -1285,16 +1593,18 @@ gtk_selection_data_set_text (GtkSelectionData *selection_data, * * 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. + * Return value: (type utf8): 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) +gtk_selection_data_get_text (const GtkSelectionData *selection_data) { guchar *result = NULL; + g_return_val_if_fail (selection_data != NULL, NULL); + init_atoms (); if (selection_data->length >= 0 && @@ -1311,7 +1621,7 @@ gtk_selection_data_get_text (GtkSelectionData *selection_data) selection_data->length, &list); if (count > 0) - result = list[0]; + result = (guchar *) list[0]; for (i = 1; i < count; i++) g_free (list[i]); @@ -1353,6 +1663,9 @@ gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data, gchar *str, *type; gsize len; + g_return_val_if_fail (selection_data != NULL, FALSE); + g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE); + formats = gdk_pixbuf_get_formats (); for (f = formats; f; f = f->next) @@ -1398,7 +1711,7 @@ gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data, * * Gets the contents of the selection data as a #GdkPixbuf. * - * Return value: if the selection data contained a recognized + * Return value: (transfer full): 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(). @@ -1406,25 +1719,27 @@ gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data, * Since: 2.6 **/ GdkPixbuf * -gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data) +gtk_selection_data_get_pixbuf (const GtkSelectionData *selection_data) { GdkPixbufLoader *loader; GdkPixbuf *result = NULL; + g_return_val_if_fail (selection_data != NULL, NULL); + if (selection_data->length > 0) { loader = gdk_pixbuf_loader_new (); - if (gdk_pixbuf_loader_write (loader, - selection_data->data, - selection_data->length, - NULL)) - result = gdk_pixbuf_loader_get_pixbuf (loader); + 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); - gdk_pixbuf_loader_close (loader, NULL); g_object_unref (loader); } @@ -1434,7 +1749,8 @@ gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data) /** * gtk_selection_data_set_uris: * @selection_data: a #GtkSelectionData - * @uris: a %NULL-terminated array of strings hilding URIs + * @uris: (array zero-terminated=1): a %NULL-terminated array of + * strings holding URIs * * Sets the contents of the selection from a list of URIs. * The string is converted to the form determined by @@ -1449,6 +1765,9 @@ gboolean gtk_selection_data_set_uris (GtkSelectionData *selection_data, gchar **uris) { + g_return_val_if_fail (selection_data != NULL, FALSE); + g_return_val_if_fail (uris != NULL, FALSE); + init_atoms (); if (selection_data->target == text_uri_list_atom) @@ -1476,6 +1795,8 @@ gtk_selection_data_set_uris (GtkSelectionData *selection_data, text_uri_list_atom, 8, (guchar *)result, length); + g_free (result); + return TRUE; } } @@ -1488,26 +1809,28 @@ gtk_selection_data_set_uris (GtkSelectionData *selection_data, * @selection_data: a #GtkSelectionData * * Gets the contents of the selection data as array of URIs. - * - * Return value: if the selection data contains a list of + * + * Return value: (array zero-terminated=1) (element-type utf8) (transfer full): 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 + * containing the URIs, otherwise %NULL. If the result is * non-%NULL it must be freed with g_strfreev(). * * Since: 2.6 **/ gchar ** -gtk_selection_data_get_uris (GtkSelectionData *selection_data) +gtk_selection_data_get_uris (const GtkSelectionData *selection_data) { gchar **result = NULL; + g_return_val_if_fail (selection_data != NULL, NULL); + init_atoms (); if (selection_data->length >= 0 && selection_data->type == text_uri_list_atom) { gchar **list; - gint i; gint count = gdk_text_property_to_utf8_list_for_display (selection_data->display, utf8_atom, selection_data->format, @@ -1517,9 +1840,7 @@ gtk_selection_data_get_uris (GtkSelectionData *selection_data) if (count > 0) result = g_uri_list_extract_uris (list[0]); - for (i = 1; i < count; i++) - g_free (list[i]); - g_free (list); + g_strfreev (list); } return result; @@ -1529,8 +1850,9 @@ gtk_selection_data_get_uris (GtkSelectionData *selection_data) /** * gtk_selection_data_get_targets: * @selection_data: a #GtkSelectionData object - * @targets: location to store an array of targets. The result - * stored here must be freed with g_free(). + * @targets: (out) (array length=n_atoms) (transfer container): + * location to store an array of targets. The result stored + * here must be freed with g_free(). * @n_atoms: location to store number of items in @targets. * * Gets the contents of @selection_data as an array of targets. @@ -1542,10 +1864,12 @@ gtk_selection_data_get_uris (GtkSelectionData *selection_data) * array of targets, otherwise %FALSE. **/ gboolean -gtk_selection_data_get_targets (GtkSelectionData *selection_data, - GdkAtom **targets, - gint *n_atoms) +gtk_selection_data_get_targets (const GtkSelectionData *selection_data, + GdkAtom **targets, + gint *n_atoms) { + g_return_val_if_fail (selection_data != NULL, FALSE); + if (selection_data->length >= 0 && selection_data->format == 32 && selection_data->type == GDK_SELECTION_TYPE_ATOM) @@ -1568,6 +1892,101 @@ gtk_selection_data_get_targets (GtkSelectionData *selection_data, } } +/** + * gtk_targets_include_text: + * @targets: (array length=n_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; + + g_return_val_if_fail (targets != NULL || n_targets == 0, 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: (array length=n_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 (targets != NULL || n_targets == 0, 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 @@ -1580,38 +1999,108 @@ gtk_selection_data_get_targets (GtkSelectionData *selection_data, * and a suitable target for text is included, otherwise %FALSE. **/ gboolean -gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) +gtk_selection_data_targets_include_text (const GtkSelectionData *selection_data) +{ + GdkAtom *targets; + gint n_targets; + gboolean result = FALSE; + + g_return_val_if_fail (selection_data != NULL, 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 (const GtkSelectionData *selection_data, + GtkTextBuffer *buffer) { GdkAtom *targets; gint n_targets; - gint i; gboolean result = FALSE; + g_return_val_if_fail (selection_data != NULL, 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)) { - for (i=0; i < n_targets; i++) + result = gtk_targets_include_rich_text (targets, n_targets, buffer); + g_free (targets); + } + + return result; +} + +/** + * gtk_targets_include_image: + * @targets: (array length=n_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; + + g_return_val_if_fail (targets != NULL || n_targets == 0, 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) { - 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) + GtkTargetPair *pair = (GtkTargetPair *)l->data; + if (pair->target == targets[i]) { result = TRUE; break; } } - - g_free (targets); } + gtk_target_list_unref (list); return result; } - + /** * gtk_selection_data_targets_include_image: * @selection_data: a #GtkSelectionData object @@ -1628,37 +2117,98 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) * Since: 2.6 **/ gboolean -gtk_selection_data_targets_include_image (GtkSelectionData *selection_data, - gboolean writable) +gtk_selection_data_targets_include_image (const GtkSelectionData *selection_data, + gboolean writable) { GdkAtom *targets; gint n_targets; - gint i; gboolean result = FALSE; - GtkTargetList *list; - GList *l; + + g_return_val_if_fail (selection_data != NULL, FALSE); init_atoms (); if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) { - list = gtk_target_list_new (NULL, 0); - gtk_target_list_add_image_targets (list, 0, writable); - for (i=0; i < n_targets && !result; i++) + result = gtk_targets_include_image (targets, n_targets, writable); + g_free (targets); + } + + return result; +} + +/** + * gtk_targets_include_uri: + * @targets: (array length=n_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; + + g_return_val_if_fail (targets != NULL || n_targets == 0, 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) { - for (l = list->list; l && !result; l = l->next) - { - GtkTargetPair *pair = (GtkTargetPair *)l->data; - if (pair->target == targets[i]) - result = TRUE; - } + result = TRUE; + break; } - gtk_target_list_unref (list); + } + + 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 URI lists is included, otherwise %FALSE. + * + * Since: 2.10 + **/ +gboolean +gtk_selection_data_targets_include_uri (const GtkSelectionData *selection_data) +{ + GdkAtom *targets; + gint n_targets; + gboolean result = FALSE; + + g_return_val_if_fail (selection_data != NULL, 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: @@ -1671,32 +2221,27 @@ gtk_selection_data_targets_include_image (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"); + gtk_selection_atoms[SAVE_TARGETS] = gdk_atom_intern_static_string ("SAVE_TARGETS"); initialize = FALSE; } /** - * gtk_selection_clear: + * _gtk_selection_clear: * @widget: a #GtkWidget * @event: the event * - * The default handler for the GtkWidget::selection_clear_event + * The default handler for the #GtkWidget::selection-clear-event * signal. * * Return value: %TRUE if the event was handled, otherwise false - * - * Since: 2.2 - * - * Deprecated: Instead of calling this function, chain up from - * your selection_clear_event handler. Calling this function - * from any other context is illegal. **/ gboolean -gtk_selection_clear (GtkWidget *widget, +_gtk_selection_clear (GtkWidget *widget, GdkEventSelection *event) { /* Note that we filter clear events in gdkselection-x11.c, so @@ -1722,7 +2267,7 @@ gtk_selection_clear (GtkWidget *widget, { current_selections = g_list_remove_link (current_selections, tmp_list); g_list_free (tmp_list); - g_free (selection_info); + g_slice_free (GtkSelectionInfo, selection_info); } return TRUE; @@ -1770,23 +2315,15 @@ _gtk_selection_request (GtkWidget *widget, if (tmp_list == NULL) return FALSE; - info = g_new (GtkIncrInfo, 1); + info = g_slice_new (GtkIncrInfo); g_object_ref (widget); - + info->selection = event->selection; info->num_incrs = 0; - - /* Create GdkWindow structure for the requestor */ - - info->requestor = gdk_window_lookup_for_display (display, - event->requestor); - if (!info->requestor) - info->requestor = gdk_window_foreign_new_for_display (display, - event->requestor); - + info->requestor = g_object_ref (event->requestor); + /* Determine conversions we need to perform */ - if (event->target == gtk_selection_atoms[MULTIPLE]) { GdkAtom type; @@ -1808,10 +2345,11 @@ _gtk_selection_request (GtkWidget *widget, GDK_NONE, event->time); g_free (mult_atoms); - g_free (info); + g_slice_free (GtkIncrInfo, info); + gdk_error_trap_pop_ignored (); return TRUE; } - gdk_error_trap_pop (); + gdk_error_trap_pop_ignored (); /* This is annoying; the ICCCM doesn't specify the property type * used for the property contents, so the autoconversion for @@ -1819,7 +2357,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); @@ -1831,6 +2369,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 @@ -1843,6 +2383,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 */ @@ -1875,7 +2417,6 @@ _gtk_selection_request (GtkWidget *widget, #endif gtk_selection_invoke_handler (widget, &data, event->time); - if (data.length < 0) { info->conversions[i].property = GDK_NONE; @@ -1936,7 +2477,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 @@ -1951,7 +2492,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); @@ -1981,7 +2522,7 @@ _gtk_selection_request (GtkWidget *widget, if (info->num_incrs == 0) { g_free (info->conversions); - g_free (info); + g_slice_free (GtkIncrInfo, info); } g_object_unref (widget); @@ -2023,7 +2564,7 @@ _gtk_selection_incr_event (GdkWindow *window, g_message ("PropertyDelete, property %ld", event->atom); #endif - selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_drawable_get_display (window)); + selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_window_get_display (window)); /* Now find the appropriate ongoing INCR */ tmp_list = current_incrs; @@ -2073,7 +2614,7 @@ _gtk_selection_incr_event (GdkWindow *window, #ifdef DEBUG_SELECTION g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld", num_bytes, info->conversions[i].offset, - GDK_WINDOW_XWINDOW(info->requestor), event->atom); + GDK_WINDOW_XID(info->requestor), event->atom); #endif bytes_per_item = gtk_selection_bytes_per_item (info->conversions[i].data.format); @@ -2125,8 +2666,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 */ @@ -2151,7 +2690,7 @@ gtk_selection_incr_timeout (GtkIncrInfo *info) /* FIXME: we should check if requestor window is still in use, and if not, remove it? */ - g_free (info); + g_slice_free (GtkIncrInfo, info); retval = FALSE; /* remove timeout */ } @@ -2162,14 +2701,12 @@ gtk_selection_incr_timeout (GtkIncrInfo *info) retval = TRUE; /* timeout will happen again */ } - GDK_THREADS_LEAVE (); - return retval; } /************************************************************* * _gtk_selection_notify: - * Handler for "selection_notify_event" signals on windows + * Handler for "selection-notify-event" signals on windows * where a retrieval is currently in process. The selection * owner has responded to our conversion request. * arguments: @@ -2181,21 +2718,24 @@ gtk_selection_incr_timeout (GtkIncrInfo *info) *************************************************************/ gboolean -_gtk_selection_notify (GtkWidget *widget, +_gtk_selection_notify (GtkWidget *widget, GdkEventSelection *event) { GList *tmp_list; GtkRetrievalInfo *info = NULL; + GdkWindow *window; guchar *buffer = NULL; gint length; GdkAtom type; gint format; - + #ifdef DEBUG_SELECTION g_message ("Initial receipt of selection %ld, target %ld (property = %ld)", event->selection, event->target, event->property); #endif - + + window = gtk_widget_get_window (widget); + tmp_list = current_retrievals; while (tmp_list) { @@ -2209,7 +2749,7 @@ _gtk_selection_notify (GtkWidget *widget, return FALSE; if (event->property != GDK_NONE) - length = gdk_selection_property_get (widget->window, &buffer, + length = gdk_selection_property_get (window, &buffer, &type, &format); else length = 0; /* silence gcc */ @@ -2233,8 +2773,8 @@ _gtk_selection_notify (GtkWidget *widget, info->notify_time = event->time; info->idle_time = 0; info->offset = 0; /* Mark as OK to proceed */ - gdk_window_set_events (widget->window, - gdk_window_get_events (widget->window) + gdk_window_set_events (window, + gdk_window_get_events (window) | GDK_PROPERTY_CHANGE_MASK); } else @@ -2248,9 +2788,9 @@ _gtk_selection_notify (GtkWidget *widget, type, format, buffer, length, event->time); } - - gdk_property_delete (widget->window, event->property); - + + gdk_property_delete (window, event->property); + g_free (buffer); return TRUE; @@ -2258,7 +2798,7 @@ _gtk_selection_notify (GtkWidget *widget, /************************************************************* * _gtk_selection_property_notify: - * Handler for "property_notify_event" signals on windows + * Handler for "property-notify-event" signals on windows * where a retrieval is currently in process. The selection * owner has added more data. * arguments: @@ -2275,6 +2815,7 @@ _gtk_selection_property_notify (GtkWidget *widget, { GList *tmp_list; GtkRetrievalInfo *info = NULL; + GdkWindow *window; guchar *new_buffer; int length; GdkAtom type; @@ -2285,7 +2826,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; @@ -2311,11 +2852,12 @@ _gtk_selection_property_notify (GtkWidget *widget, return FALSE; info->idle_time = 0; - - length = gdk_selection_property_get (widget->window, &new_buffer, + + window = gtk_widget_get_window (widget); + length = gdk_selection_property_get (window, &new_buffer, &type, &format); - gdk_property_delete (widget->window, event->atom); - + gdk_property_delete (window, event->atom); + /* We could do a lot better efficiency-wise by paying attention to what length was sent in the initial INCR transaction, instead of doing memory allocation at every step. But its only guaranteed to @@ -2369,14 +2911,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 */ @@ -2399,7 +2939,7 @@ gtk_selection_retrieval_timeout (GtkRetrievalInfo *info) } g_free (info->buffer); - g_free (info); + g_slice_free (GtkRetrievalInfo, info); retval = FALSE; /* remove timeout */ } @@ -2410,14 +2950,12 @@ gtk_selection_retrieval_timeout (GtkRetrievalInfo *info) retval = TRUE; /* timeout will happen again */ } - GDK_THREADS_LEAVE (); - return retval; } /************************************************************* * gtk_selection_retrieval_report: - * Emits a "selection_received" signal. + * Emits a "selection-received" signal. * arguments: * info: information about the retrieval that completed * buffer: buffer containing data (NULL => errror) @@ -2443,7 +2981,7 @@ gtk_selection_retrieval_report (GtkRetrievalInfo *info, data.display = gtk_widget_get_display (info->widget); g_signal_emit_by_name (info->widget, - "selection_received", + "selection-received", &data, time); } @@ -2474,11 +3012,12 @@ gtk_selection_invoke_handler (GtkWidget *widget, g_return_if_fail (widget != NULL); target_list = gtk_selection_target_list_get (widget, data->selection); - if (target_list && + if (data->target != gtk_selection_atoms[SAVE_TARGETS] && + target_list && gtk_target_list_find (target_list, data->target, &info)) { g_signal_emit_by_name (widget, - "selection_get", + "selection-get", data, info, time); } @@ -2567,6 +3106,12 @@ gtk_selection_default_handler (GtkWidget *widget, tmp_list = tmp_list->next; } } + else if (data->target == gtk_selection_atoms[SAVE_TARGETS]) + { + gtk_selection_data_set (data, + gdk_atom_intern_static_string ("NULL"), + 32, NULL, 0); + } else { data->length = -1; @@ -2583,13 +3128,13 @@ gtk_selection_default_handler (GtkWidget *widget, * Return value: a pointer to a copy of @data. **/ GtkSelectionData* -gtk_selection_data_copy (GtkSelectionData *data) +gtk_selection_data_copy (const GtkSelectionData *data) { GtkSelectionData *new_data; g_return_val_if_fail (data != NULL, NULL); - new_data = g_new (GtkSelectionData, 1); + new_data = g_slice_new (GtkSelectionData); *new_data = *data; if (data->data) @@ -2613,26 +3158,86 @@ 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); + g_slice_free (GtkSelectionData, data); } -GType -gtk_selection_data_get_type (void) +/** + * gtk_target_entry_new: + * @target: String identifier for target + * @flags: Set of flags, see #GtkTargetFlags + * @info: an ID that will be passed back to the application + * + * Makes a new #GtkTargetEntry structure. + * + * Return value: a pointer to a new GtkTargetEntry structure. + * Free with gtk_target_entry_free() + **/ +GtkTargetEntry * +gtk_target_entry_new (const char *target, + guint flags, + guint info) { - static GType our_type = 0; - - if (our_type == 0) - our_type = g_boxed_type_register_static ("GtkSelectionData", - (GBoxedCopyFunc) gtk_selection_data_copy, - (GBoxedFreeFunc) gtk_selection_data_free); + GtkTargetEntry entry = { (char *) target, flags, info }; + return gtk_target_entry_copy (&entry); +} - return our_type; +/** + * gtk_target_entry_copy: + * @data: a pointer to a #GtkTargetEntry structure. + * + * Makes a copy of a #GtkTargetEntry structure and its data. + * + * Return value: a pointer to a copy of @data. + * Free with gtk_target_entry_free() + **/ +GtkTargetEntry * +gtk_target_entry_copy (GtkTargetEntry *data) +{ + GtkTargetEntry *new_data; + + g_return_val_if_fail (data != NULL, NULL); + + new_data = g_slice_new (GtkTargetEntry); + new_data->target = g_strdup (data->target); + new_data->flags = data->flags; + new_data->info = data->info; + + return new_data; +} + +/** + * gtk_target_entry_free: + * @data: a pointer to a #GtkTargetEntry structure. + * + * Frees a #GtkTargetEntry structure returned from + * gtk_target_entry_new() or gtk_target_entry_copy(). + **/ +void +gtk_target_entry_free (GtkTargetEntry *data) +{ + g_return_if_fail (data != NULL); + + g_free (data->target); + + g_slice_free (GtkTargetEntry, data); } -static int + +G_DEFINE_BOXED_TYPE (GtkSelectionData, gtk_selection_data, + gtk_selection_data_copy, + gtk_selection_data_free) + +G_DEFINE_BOXED_TYPE (GtkTargetList, gtk_target_list, + gtk_target_list_ref, + gtk_target_list_unref) + +G_DEFINE_BOXED_TYPE (GtkTargetEntry, gtk_target_entry, + gtk_target_entry_copy, + gtk_target_entry_free) + +static int gtk_selection_bytes_per_item (gint format) { switch (format) @@ -2651,6 +3256,3 @@ gtk_selection_bytes_per_item (gint format) } return 0; } - -#define __GTK_SELECTION_C__ -#include "gtkaliasdef.c"