* 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 <http://www.gnu.org/licenses/>.
*/
-/* 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
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
+/**
+ * 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 <stdarg.h>
#include <string.h>
#include "gdk.h"
#include "gtkmain.h"
-#include "gtkselection.h"
-#include "gtksignal.h"
+#include "gtkdebug.h"
+#include "gtktextbufferrichtext.h"
+#include "gtkintl.h"
+#include "gdk-pixbuf/gdk-pixbuf.h"
+
+#ifdef GDK_WINDOWING_X11
+#include "x11/gdkx.h"
+#endif
+
+#ifdef GDK_WINDOWING_WIN32
+#include "win32/gdkwin32.h"
+#endif
-/* #define DEBUG_SELECTION */
+#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 30
+
enum {
INCR,
MULTIPLE,
TARGETS,
TIMESTAMP,
+ SAVE_TARGETS,
LAST_ATOM
};
/* 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,
static GList *current_selections = NULL;
static GdkAtom gtk_selection_atoms[LAST_ATOM];
-static const char *gtk_selection_handler_key = "gtk-selection-handlers";
+static const char gtk_selection_handler_key[] = "gtk-selection-handlers";
/****************
* Target Lists *
* Target lists
*/
+
+/**
+ * gtk_target_list_new:
+ * @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: (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;
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)
{
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);
}
}
+/**
+ * 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;
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;
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);
+ 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
+ * @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: (array length=ntargets): 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,
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;
}
}
+/**
+ * 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)
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);
}
}
+/**
+ * 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,
+ * or %NULL
+ *
+ * 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,
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
+ * @time_: timestamp with which to claim the selection
*
* Claim ownership of a given selection for a particular widget, or,
* if @widget is %NULL, release ownership of the selection.
*
* Return value: TRUE if the operation succeeded
+ *
+ * Since: 2.2
*/
gboolean
gtk_selection_owner_set_for_display (GdkDisplay *display,
GdkWindow *window;
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
- g_return_val_if_fail (widget == NULL || GTK_WIDGET_REALIZED (widget), FALSE);
+ g_return_val_if_fail (selection != GDK_NONE, 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)
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;
*/
if (old_owner && old_owner != widget)
{
- GdkEventSelection event;
-
- event.type = GDK_SELECTION_CLEAR;
- event.window = old_owner->window;
- event.selection = selection;
- event.time = time;
+ GdkEvent *event = gdk_event_new (GDK_SELECTION_CLEAR);
+
+ event->selection.window = g_object_ref (gtk_widget_get_window (old_owner));
+ event->selection.selection = selection;
+ event->selection.time = time;
- gtk_widget_event (old_owner, (GdkEvent *) &event);
+ gtk_widget_event (old_owner, event);
+
+ gdk_event_free (event);
}
return TRUE;
}
/**
* 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
+ * @time_: timestamp with which to claim the selection
*
* Claims ownership of a given selection for a particular widget,
* or, if @widget is %NULL, release ownership of the selection.
{
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)
display = gtk_widget_get_display (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 {
GList *tmp_list;
GList *lists;
- lists = gtk_object_get_data (GTK_OBJECT (widget), gtk_selection_handler_key);
+ lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
tmp_list = lists;
while (tmp_list)
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);
- gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, lists);
+ g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), lists);
return sellist->list;
}
GList *tmp_list;
GList *lists;
- lists = gtk_object_get_data (GTK_OBJECT (widget), gtk_selection_handler_key);
+ lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
tmp_list = lists;
while (tmp_list)
gtk_target_list_unref (sellist->list);
- g_free (sellist);
+ g_slice_free (GtkSelectionTargetList, sellist);
tmp_list = tmp_list->next;
}
g_list_free (lists);
- gtk_object_set_data (GTK_OBJECT (widget), gtk_selection_handler_key, NULL);
+ g_object_set_data (G_OBJECT (widget), I_(gtk_selection_handler_key), NULL);
}
/**
GList *tmp_list;
GList *lists;
- lists = gtk_object_get_data (GTK_OBJECT (widget), gtk_selection_handler_key);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (selection != GDK_NONE);
+
+ lists = g_object_get_data (G_OBJECT (widget), gtk_selection_handler_key);
tmp_list = lists;
while (tmp_list)
{
lists = g_list_delete_link (lists, tmp_list);
gtk_target_list_unref (sellist->list);
- g_free (sellist);
+ g_slice_free (GtkSelectionTargetList, sellist);
break;
}
tmp_list = tmp_list->next;
}
- gtk_object_set_data (GTK_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,
{
GtkTargetList *list;
- g_return_if_fail (widget != NULL);
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (selection != GDK_NONE);
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 (gtk_widget_get_window (widget), selection, 1, &target);
+#endif
}
+/**
+ * gtk_selection_add_targets:
+ * @widget: a #GtkWidget
+ * @selection: the selection
+ * @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
+ * for a given widget and selection.
+ **/
void
gtk_selection_add_targets (GtkWidget *widget,
GdkAtom selection,
guint ntargets)
{
GtkTargetList *list;
-
- g_return_if_fail (widget != NULL);
+
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (selection != GDK_NONE);
g_return_if_fail (targets != NULL);
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 (gtk_widget_get_window (widget), 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)
{
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;
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;
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;
GdkWindow *owner_window;
GdkDisplay *display;
- g_return_val_if_fail (widget != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+ g_return_val_if_fail (selection != GDK_NONE, FALSE);
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
tmp_list = tmp_list->next;
}
- info = g_new (GtkRetrievalInfo, 1);
+ info = g_slice_new (GtkRetrievalInfo);
info->widget = widget;
info->selection = selection;
info->target = target;
+ info->idle_time = 0;
info->buffer = NULL;
info->offset = -1;
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)
{
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);
+ selection_data.data = NULL;
+ selection_data.length = -1;
- g_free (info);
+ g_slice_free (GtkRetrievalInfo, info);
return TRUE;
}
}
/* Otherwise, we need to go through X */
current_retrievals = g_list_append (current_retrievals, info);
- gdk_selection_convert (widget->window, selection, target, time);
- gtk_timeout_add (1000, (GtkFunction) 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_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:
- *************************************************************/
-
-void
-gtk_selection_data_set (GtkSelectionData *selection_data,
- GdkAtom type,
- gint format,
- const guchar *data,
- gint length)
+/**
+ * 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)
{
- if (selection_data->data)
- g_free (selection_data->data);
-
- selection_data->type = type;
- selection_data->format = format;
-
- if (data)
- {
- selection_data->data = g_new (guchar, length+1);
- memcpy (selection_data->data, data, length);
- selection_data->data[length] = 0;
- }
- else
- {
- g_return_if_fail (length <= 0);
-
- if (length < 0)
- selection_data->data = NULL;
- else
- selection_data->data = g_strdup("");
- }
-
- selection_data->length = length;
+ g_return_val_if_fail (selection_data != NULL, 0);
+
+ return selection_data->selection;
}
-static GdkAtom utf8_atom;
-static GdkAtom text_atom;
-static GdkAtom ctext_atom;
+/**
+ * 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: (array length=length): pointer to the data (will be copied)
+ * @length: length of the data
+ *
+ * Stores new data into a #GtkSelectionData object. Should
+ * <emphasis>only</emphasis> be called from a selection handler callback.
+ * Zero-terminates the stored data.
+ **/
+void
+gtk_selection_data_set (GtkSelectionData *selection_data,
+ GdkAtom type,
+ gint format,
+ const guchar *data,
+ gint length)
+{
+ g_return_if_fail (selection_data != NULL);
+
+ g_free (selection_data->data);
+
+ selection_data->type = type;
+ selection_data->format = format;
+
+ if (data)
+ {
+ selection_data->data = g_new (guchar, length+1);
+ memcpy (selection_data->data, data, length);
+ selection_data->data[length] = 0;
+ }
+ else
+ {
+ g_return_if_fail (length <= 0);
+
+ if (length < 0)
+ selection_data->data = NULL;
+ else
+ selection_data->data = (guchar *) g_strdup ("");
+ }
+
+ selection_data->length = length;
+}
+
+static gboolean
+selection_set_string (GtkSelectionData *selection_data,
+ const gchar *str,
+ gint len)
+{
+ gchar *tmp = g_strndup (str, len);
+ gchar *latin1 = gdk_utf8_to_string_target (tmp);
+ g_free (tmp);
+
+ if (latin1)
+ {
+ gtk_selection_data_set (selection_data,
+ GDK_SELECTION_TYPE_STRING,
+ 8, (guchar *) latin1, strlen (latin1));
+ g_free (latin1);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+selection_set_compound_text (GtkSelectionData *selection_data,
+ const gchar *str,
+ gint len)
+{
+ gchar *tmp;
+ guchar *text;
+ GdkAtom encoding;
+ gint format;
+ gint new_length;
+ gboolean result = FALSE;
+
+#ifdef GDK_WINDOWING_X11
+ if (GDK_IS_X11_DISPLAY (selection_data->display))
+ {
+ 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);
+
+ result = TRUE;
+ }
+ g_free (tmp);
+ }
+#endif
+
+ 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;
+ const gchar *end = str + len;
+
+ while (p < end)
+ {
+ if (*p == '\n')
+ g_string_append_c (result, '\r');
+
+ if (*p == '\r')
+ {
+ g_string_append_c (result, *p);
+ p++;
+ if (p == end || *p != '\n')
+ g_string_append_c (result, '\n');
+ if (p == end)
+ 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, (guchar *) result, strlen (result));
+ g_free (result);
+
+ return TRUE;
+}
+
+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 ((const gchar *) 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 (guchar *) 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.
+ * 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)
+{
+ g_return_val_if_fail (selection_data != NULL, FALSE);
+
+ 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: (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 (const GtkSelectionData *selection_data)
+{
+ guchar *result = NULL;
+
+ g_return_val_if_fail (selection_data != NULL, 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 = (guchar *) 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;
+
+ 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)
+ {
+ 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: (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().
+ *
+ * Since: 2.6
+ **/
+GdkPixbuf *
+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 ();
+
+ 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: (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
+ * @selection_data->target.
+ *
+ * Return value: %TRUE if the selection was successfully set,
+ * otherwise %FALSE.
+ *
+ * Since: 2.6
+ **/
+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)
+ {
+ 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_uris:
+ * @selection_data: a #GtkSelectionData
+ *
+ * Gets the contents of the selection data as array of URIs.
+ *
+ * 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
+ * non-%NULL it must be freed with g_strfreev().
+ *
+ * Since: 2.6
+ **/
+gchar **
+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 count = gdk_text_property_to_utf8_list_for_display (selection_data->display,
+ utf8_atom,
+ selection_data->format,
+ selection_data->data,
+ selection_data->length,
+ &list);
+ if (count > 0)
+ result = g_uri_list_extract_uris (list[0]);
+
+ g_strfreev (list);
+ }
+
+ return result;
+}
+
+
+/**
+ * gtk_selection_data_get_targets:
+ * @selection_data: a #GtkSelectionData object
+ * @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.
+ * This can be used to interpret the results of getting
+ * the standard TARGETS target that is always supplied for
+ * any selection.
+ *
+ * Return value: %TRUE if @selection_data contains a valid
+ * array of targets, otherwise %FALSE.
+ **/
+gboolean
+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)
+ {
+ if (targets)
+ *targets = g_memdup (selection_data->data, selection_data->length);
+ if (n_atoms)
+ *n_atoms = selection_data->length / sizeof (GdkAtom);
+
+ return TRUE;
+ }
+ else
+ {
+ if (targets)
+ *targets = NULL;
+ if (n_atoms)
+ *n_atoms = -1;
+
+ return FALSE;
+ }
+}
+
+/**
+ * gtk_targets_include_text:
+ * @targets: (array length=n_targets): an array of #GdkAtom<!-- -->s
+ * @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 #GdkAtom<!-- -->s
+ * @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
+ *
+ * Given a #GtkSelectionData object holding a list of targets,
+ * determines if any of the targets in @targets can be used to
+ * provide text.
+ *
+ * Return value: %TRUE if @selection_data holds a list of targets,
+ * and a suitable target for text is included, otherwise %FALSE.
+ **/
+gboolean
+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;
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (selection_data != NULL, FALSE);
+ g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
-static void
-init_atoms (void)
-{
- if (!utf8_atom)
+ init_atoms ();
+
+ if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
{
- utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE);
- text_atom = gdk_atom_intern ("TEXT", FALSE);
- ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
+ result = gtk_targets_include_rich_text (targets, n_targets, buffer);
+ g_free (targets);
}
+
+ 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.
+ * gtk_targets_include_image:
+ * @targets: (array length=n_targets): an array of #GdkAtom<!-- -->s
+ * @n_targets: the length of @targets
+ * @writable: whether to accept only targets for which GTK+ knows
+ * how to convert a pixbuf into the format
*
- * Sets the contents of the selection from a UTF-8 encoded string.
- * The string is converted to the form determined by
- * @selection_data->target.
+ * Determines if any of the targets in @targets can be used to
+ * provide a #GdkPixbuf.
*
- * Return value: %TRUE if the selection was successfully set,
+ * Return value: %TRUE if @targets include a suitable target for images,
* otherwise %FALSE.
+ *
+ * Since: 2.10
**/
-gboolean
-gtk_selection_data_set_text (GtkSelectionData *selection_data,
- const gchar *str,
- gint len)
+gboolean
+gtk_targets_include_image (GdkAtom *targets,
+ gint n_targets,
+ gboolean writable)
{
+ GtkTargetList *list;
+ GList *l;
+ gint i;
gboolean result = FALSE;
-
- 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);
- result = TRUE;
- }
- else if (selection_data->target == GDK_TARGET_STRING)
- {
- gchar *tmp = g_strndup (str, len);
- gchar *latin1 = gdk_utf8_to_string_target (tmp);
- g_free (tmp);
- if (latin1)
- {
- gtk_selection_data_set (selection_data,
- GDK_SELECTION_TYPE_STRING,
- 8, latin1, strlen (latin1));
- g_free (latin1);
-
- result = TRUE;
- }
+ g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
- }
- else if (selection_data->target == ctext_atom ||
- selection_data->target == text_atom)
+ list = gtk_target_list_new (NULL, 0);
+ gtk_target_list_add_image_targets (list, 0, writable);
+ for (i = 0; i < n_targets && !result; i++)
{
- gchar *tmp;
- guchar *text;
- GdkAtom encoding;
- gint format;
- gint new_length;
-
- tmp = g_strndup (str, len);
- if (gdk_utf8_to_compound_text_for_display (selection_data->display, tmp,
- &encoding, &format, &text, &new_length))
+ for (l = list->list; l; l = l->next)
{
- gtk_selection_data_set (selection_data, encoding, format, text, new_length);
- gdk_free_compound_text (text);
-
- result = TRUE;
+ GtkTargetPair *pair = (GtkTargetPair *)l->data;
+ if (pair->target == targets[i])
+ {
+ result = TRUE;
+ break;
+ }
}
-
- g_free (tmp);
}
-
+ gtk_target_list_unref (list);
+
return result;
}
-
+
/**
- * gtk_selection_data_get_text:
- * @selection_data: a #GtkSelectionData
+ * 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
*
- * Gets the contents of the selection data as a UTF-8 string.
+ * 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: 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: %TRUE if @selection_data holds a list of targets,
+ * and a suitable target for images is included, otherwise %FALSE.
+ *
+ * Since: 2.6
**/
-guchar *
-gtk_selection_data_get_text (GtkSelectionData *selection_data)
+gboolean
+gtk_selection_data_targets_include_image (const GtkSelectionData *selection_data,
+ gboolean writable)
{
- guchar *result = NULL;
+ GdkAtom *targets;
+ gint n_targets;
+ gboolean result = FALSE;
+
+ g_return_val_if_fail (selection_data != NULL, FALSE);
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);
+ if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
+ {
+ result = gtk_targets_include_image (targets, n_targets, writable);
+ g_free (targets);
}
return result;
}
/**
- * 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().
- * @n_atoms: location to store number of items in @targets.
+ * gtk_targets_include_uri:
+ * @targets: (array length=n_targets): an array of #GdkAtom<!-- -->s
+ * @n_targets: the length of @targets
*
- * Gets the contents of @selection_data as an array of targets.
- * This can be used to interpret the results of getting
- * the standard TARGETS target that is always supplied for
- * any selection.
+ * Determines if any of the targets in @targets can be used to
+ * provide an uri list.
*
- * Return value: %TRUE if @selection_data contains a valid
- * array of targets, otherwise %FALSE.
+ * Return value: %TRUE if @targets include a suitable target for uri lists,
+ * otherwise %FALSE.
+ *
+ * Since: 2.10
**/
-gboolean
-gtk_selection_data_get_targets (GtkSelectionData *selection_data,
- GdkAtom **targets,
- gint *n_atoms)
+gboolean
+gtk_targets_include_uri (GdkAtom *targets,
+ gint n_targets)
{
- if (selection_data->length >= 0 &&
- selection_data->format == 32 &&
- selection_data->type == GDK_SELECTION_TYPE_ATOM)
- {
- if (targets)
- *targets = g_memdup (selection_data->data, selection_data->length);
- if (n_atoms)
- *n_atoms = selection_data->length / sizeof (GdkAtom);
+ gint i;
+ gboolean result = FALSE;
- return TRUE;
- }
- else
- {
- if (targets)
- *targets = NULL;
- if (n_atoms)
- *n_atoms = -1;
+ g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
- return 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)
+ {
+ result = TRUE;
+ break;
+ }
}
+
+ return result;
}
/**
- * gtk_selection_data_targets_include_text:
+ * 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 text.
+ * 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.
+ * and a suitable target for URI lists is included, otherwise %FALSE.
+ *
+ * Since: 2.10
**/
gboolean
-gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
+gtk_selection_data_targets_include_uri (const GtkSelectionData *selection_data)
{
GdkAtom *targets;
gint n_targets;
- gint i;
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))
{
- for (i=0; i < n_targets; i++)
- {
- 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 = gtk_targets_include_uri (targets, n_targets);
g_free (targets);
}
return result;
}
+
/*************************************************************
* gtk_selection_init:
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
- * signal. Instead of calling this function, chain up from
- * your selection_clear_event handler. Calling this function
- * from any other context is illegal. This function will
- * be deprecated in future versions of GTK+.
+ * The default handler for the #GtkWidget::selection-clear-event
+ * signal.
*
* Return value: %TRUE if the event was handled, otherwise false
**/
gboolean
-gtk_selection_clear (GtkWidget *widget,
+_gtk_selection_clear (GtkWidget *widget,
GdkEventSelection *event)
{
/* Note that we filter clear events in gdkselection-x11.c, so
{
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;
_gtk_selection_request (GtkWidget *widget,
GdkEventSelection *event)
{
+ GdkDisplay *display = gtk_widget_get_display (widget);
GtkIncrInfo *info;
GList *tmp_list;
- guchar *mult_atoms;
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;
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 (gtk_widget_get_display (widget),
- event->requestor);
- if (!info->requestor)
- info->requestor = gdk_window_foreign_new_for_display (gtk_widget_get_display (widget),
- event->requestor);
-
+ info->requestor = g_object_ref (event->requestor);
+
/* Determine conversions we need to perform */
-
if (event->target == gtk_selection_atoms[MULTIPLE])
{
GdkAtom type;
+ guchar *mult_atoms;
gint format;
gint length;
mult_atoms = NULL;
gdk_error_trap_push ();
- if (!gdk_property_get (info->requestor, event->property, 0, /* AnyPropertyType */
- 0, GTK_SELECTION_MAX_SIZE, FALSE,
+ if (!gdk_property_get (info->requestor, event->property, GDK_NONE, /* AnyPropertyType */
+ 0, selection_max_size, FALSE,
&type, &format, &length, &mult_atoms))
{
- gdk_selection_send_notify_for_display (gtk_widget_get_display (widget),
+ gdk_selection_send_notify_for_display (display,
event->requestor,
event->selection,
event->target,
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 ();
-
- info->num_conversions = length / (2*sizeof (GdkAtom));
- info->conversions = g_new (GtkIncrConversion, info->num_conversions);
-
- for (i=0; i<info->num_conversions; i++)
+ 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
+ * ATOM / ATOM_PAIR in GDK doesn't work properly.
+ */
+#ifdef GDK_WINDOWING_X11
+ if (type != GDK_SELECTION_TYPE_ATOM &&
+ type != gdk_atom_intern_static_string ("ATOM_PAIR"))
+ {
+ info->num_conversions = length / (2*sizeof (glong));
+ info->conversions = g_new (GtkIncrConversion, info->num_conversions);
+
+ for (i=0; i<info->num_conversions; i++)
+ {
+ info->conversions[i].target = gdk_x11_xatom_to_atom_for_display (display,
+ ((glong *)mult_atoms)[2*i]);
+ info->conversions[i].property = gdk_x11_xatom_to_atom_for_display (display,
+ ((glong *)mult_atoms)[2*i + 1]);
+ }
+
+ g_free (mult_atoms);
+ }
+ else
+#endif
{
- info->conversions[i].target = ((GdkAtom *)mult_atoms)[2*i];
- info->conversions[i].property = ((GdkAtom *)mult_atoms)[2*i+1];
+ info->num_conversions = length / (2*sizeof (GdkAtom));
+ info->conversions = g_new (GtkIncrConversion, info->num_conversions);
+
+ for (i=0; i<info->num_conversions; i++)
+ {
+ 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 */
info->num_conversions = 1;
info->conversions[0].target = event->target;
info->conversions[0].property = event->property;
- mult_atoms = (guchar *)info->conversions;
}
/* Loop through conversions and determine which of these are big
#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);
-
if (data.length < 0)
{
- ((GdkAtom *)mult_atoms)[2*i+1] = GDK_NONE;
info->conversions[i].property = GDK_NONE;
continue;
}
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;
gdk_window_get_events (info->requestor) |
GDK_PROPERTY_CHANGE_MASK);
current_incrs = g_list_append (current_incrs, info);
- gtk_timeout_add (1000, (GtkFunction)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
conversions succeeded */
if (event->target == gtk_selection_atoms[MULTIPLE])
{
+ GdkAtom *mult_atoms = g_new (GdkAtom, 2 * info->num_conversions);
+ for (i = 0; i < info->num_conversions; i++)
+ {
+ mult_atoms[2*i] = info->conversions[i].target;
+ mult_atoms[2*i+1] = info->conversions[i].property;
+ }
+
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,
- mult_atoms, 2*info->num_conversions);
+ (guchar *)mult_atoms, 2*info->num_conversions);
g_free (mult_atoms);
}
if (info->num_incrs == 0)
{
g_free (info->conversions);
- g_free (info);
+ g_slice_free (GtkIncrInfo, info);
}
g_object_unref (widget);
GtkIncrInfo *info = NULL;
gint num_bytes;
guchar *buffer;
+ gulong selection_max_size;
int i;
#ifdef DEBUG_SELECTION
g_message ("PropertyDelete, property %ld", event->atom);
#endif
-
+
+ selection_max_size = GTK_SELECTION_MAX_SIZE (gdk_window_get_display (window));
+
/* Now find the appropriate ongoing INCR */
tmp_list = current_incrs;
while (tmp_list)
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;
#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);
info->conversions[i].offset = -1;
}
}
- break;
}
/* Check if we're finished with all the targets */
GList *tmp_list;
gboolean retval;
- GDK_THREADS_ENTER ();
-
/* Determine if retrieval has finished by checking if it still in
list of pending retrievals */
}
/* If retrieval is finished */
- if (!tmp_list || info->idle_time >= 5)
+ if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
{
- if (tmp_list && info->idle_time >= 5)
+ if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
{
current_incrs = g_list_remove_link (current_incrs, tmp_list);
g_list_free (tmp_list);
/* 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 */
}
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:
*************************************************************/
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)
{
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 */
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
type, format,
buffer, length, event->time);
}
-
- gdk_property_delete (widget->window, event->property);
-
+
+ gdk_property_delete (window, event->property);
+
g_free (buffer);
return TRUE;
/*************************************************************
* _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:
{
GList *tmp_list;
GtkRetrievalInfo *info = NULL;
+ GdkWindow *window;
guchar *new_buffer;
int length;
GdkAtom type;
#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;
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
* 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 */
}
/* If retrieval is finished */
- if (!tmp_list || info->idle_time >= 5)
+ if (!tmp_list || info->idle_time >= IDLE_ABORT_TIME)
{
- if (tmp_list && info->idle_time >= 5)
+ if (tmp_list && info->idle_time >= IDLE_ABORT_TIME)
{
current_retrievals = g_list_remove_link (current_retrievals, tmp_list);
g_list_free (tmp_list);
}
g_free (info->buffer);
- g_free (info);
+ g_slice_free (GtkRetrievalInfo, info);
retval = FALSE; /* remove timeout */
}
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)
data.data = buffer;
data.display = gtk_widget_get_display (info->widget);
- gtk_signal_emit_by_name (GTK_OBJECT(info->widget),
- "selection_received",
- &data, time);
+ g_signal_emit_by_name (info->widget,
+ "selection-received",
+ &data, time);
}
/*************************************************************
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))
{
- gtk_signal_emit_by_name (GTK_OBJECT (widget),
- "selection_get",
- data,
- info, time);
+ g_signal_emit_by_name (widget,
+ "selection-get",
+ data,
+ info, time);
}
else
gtk_selection_default_handler (widget, data);
data->type = GDK_SELECTION_TYPE_ATOM;
data->format = 32;
data->length = count * sizeof (GdkAtom);
-
- p = g_new (GdkAtom, count);
+
+ /* selection data is always terminated by a trailing \0
+ */
+ p = g_malloc (data->length + 1);
data->data = (guchar *)p;
+ data->data[data->length] = '\0';
*p++ = gtk_selection_atoms[TIMESTAMP];
*p++ = gtk_selection_atoms[TARGETS];
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;
}
+/**
+ * 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 (const 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 = g_slice_new (GtkSelectionData);
+ *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);
+ 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);
+}
+
+/**
+ * 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);
- return our_type;
+ 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)