From 1c8e6a0e4fe16dcb9dafc5f1c90bc34bd7b3a9c4 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 31 Oct 2004 05:40:25 +0000 Subject: [PATCH] Add api for image transfer via copy-and-paste (#156408) 2004-10-31 Matthias Clasen Add api for image transfer via copy-and-paste (#156408) * gtk/gtkclipboard.c (gtk_clipboard_set_image) (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) (gtk_clipboard_wait_is_image_available): New functions for image transfer. * gtk/gtkselection.h: * gtk/gtkselection.c (gtk_selection_data_targets_include_image): New function, similar to gtk_selection_data_targets_include_text(). --- ChangeLog | 11 ++ ChangeLog.pre-2-10 | 11 ++ ChangeLog.pre-2-6 | 11 ++ ChangeLog.pre-2-8 | 11 ++ docs/reference/gtk/gtk-sections.txt | 5 + gtk/gtkclipboard.c | 252 ++++++++++++++++++++++++++-- gtk/gtkclipboard.h | 10 ++ gtk/gtkselection.c | 53 +++++- gtk/gtkselection.h | 8 +- 9 files changed, 358 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3fb4d9189b..4d9f121d30 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2004-10-31 Matthias Clasen + Add api for image transfer via copy-and-paste (#156408) + + * gtk/gtkclipboard.c (gtk_clipboard_set_image) + (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) + (gtk_clipboard_wait_is_image_available): New functions for image + transfer. + + * gtk/gtkselection.h: + * gtk/gtkselection.c (gtk_selection_data_targets_include_image): + New function, similar to gtk_selection_data_targets_include_text(). + * gtk/gtkprogressbar.[hc]: Add an ellipsize property with getter and setter. (#156845, Morten Welinder) diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 3fb4d9189b..4d9f121d30 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,5 +1,16 @@ 2004-10-31 Matthias Clasen + Add api for image transfer via copy-and-paste (#156408) + + * gtk/gtkclipboard.c (gtk_clipboard_set_image) + (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) + (gtk_clipboard_wait_is_image_available): New functions for image + transfer. + + * gtk/gtkselection.h: + * gtk/gtkselection.c (gtk_selection_data_targets_include_image): + New function, similar to gtk_selection_data_targets_include_text(). + * gtk/gtkprogressbar.[hc]: Add an ellipsize property with getter and setter. (#156845, Morten Welinder) diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 3fb4d9189b..4d9f121d30 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,5 +1,16 @@ 2004-10-31 Matthias Clasen + Add api for image transfer via copy-and-paste (#156408) + + * gtk/gtkclipboard.c (gtk_clipboard_set_image) + (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) + (gtk_clipboard_wait_is_image_available): New functions for image + transfer. + + * gtk/gtkselection.h: + * gtk/gtkselection.c (gtk_selection_data_targets_include_image): + New function, similar to gtk_selection_data_targets_include_text(). + * gtk/gtkprogressbar.[hc]: Add an ellipsize property with getter and setter. (#156845, Morten Welinder) diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 3fb4d9189b..4d9f121d30 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,5 +1,16 @@ 2004-10-31 Matthias Clasen + Add api for image transfer via copy-and-paste (#156408) + + * gtk/gtkclipboard.c (gtk_clipboard_set_image) + (gtk_clipboard_request_image, gtk_clipboard_wait_for_image) + (gtk_clipboard_wait_is_image_available): New functions for image + transfer. + + * gtk/gtkselection.h: + * gtk/gtkselection.c (gtk_selection_data_targets_include_image): + New function, similar to gtk_selection_data_targets_include_text(). + * gtk/gtkprogressbar.[hc]: Add an ellipsize property with getter and setter. (#156845, Morten Welinder) diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt index b235fdd7ac..7127b856b9 100644 --- a/docs/reference/gtk/gtk-sections.txt +++ b/docs/reference/gtk/gtk-sections.txt @@ -5033,6 +5033,7 @@ gtk_selection_data_get_pixbuf gtk_selection_data_set_uris gtk_selection_data_get_uris gtk_selection_data_get_targets +gtk_selection_data_targets_include_image gtk_selection_data_targets_include_text gtk_selection_remove_all gtk_selection_clear @@ -5062,12 +5063,16 @@ gtk_clipboard_set_with_owner gtk_clipboard_get_owner gtk_clipboard_clear gtk_clipboard_set_text +gtk_clipboard_set_image gtk_clipboard_request_contents gtk_clipboard_request_text +gtk_clipboard_request_image gtk_clipboard_request_targets gtk_clipboard_wait_for_contents gtk_clipboard_wait_for_text +gtk_clipboard_wait_for_image gtk_clipboard_wait_is_text_available +gtk_clipboard_wait_is_image_available gtk_clipboard_wait_for_targets gtk_clipboard_wait_is_target_available gtk_clipboard_set_can_store diff --git a/gtk/gtkclipboard.c b/gtk/gtkclipboard.c index cc78e1f847..6a23db7e83 100644 --- a/gtk/gtkclipboard.c +++ b/gtk/gtkclipboard.c @@ -46,6 +46,7 @@ typedef struct _GtkClipboardClass GtkClipboardClass; typedef struct _RequestContentsInfo RequestContentsInfo; typedef struct _RequestTextInfo RequestTextInfo; +typedef struct _RequestImageInfo RequestImageInfo; typedef struct _RequestTargetsInfo RequestTargetsInfo; struct _GtkClipboard @@ -95,6 +96,12 @@ struct _RequestTextInfo gpointer user_data; }; +struct _RequestImageInfo +{ + GtkClipboardImageReceivedFunc callback; + gpointer user_data; +}; + struct _RequestTargetsInfo { GtkClipboardTargetsReceivedFunc callback; @@ -702,6 +709,7 @@ text_clear_func (GtkClipboard *clipboard, g_free (data); } + /** * gtk_clipboard_set_text: * @clipboard: a #GtkClipboard object @@ -731,15 +739,13 @@ gtk_clipboard_set_text (GtkClipboard *clipboard, gtk_target_list_add_text_targets (list, 0); n_targets = g_list_length (list->list); - targets = g_new (GtkTargetEntry, n_targets); + targets = g_new0 (GtkTargetEntry, n_targets); for (l = list->list, i = 0; l; l = l->next, i++) { GtkTargetPair *pair = (GtkTargetPair *)l->data; targets[i].target = gdk_atom_name (pair->target); - targets[i].flags = 0; - targets[i].info = 0; } - + if (len < 0) len = strlen (text); @@ -753,6 +759,67 @@ gtk_clipboard_set_text (GtkClipboard *clipboard, gtk_target_list_unref (list); } +static void +pixbuf_get_func (GtkClipboard *clipboard, + GtkSelectionData *selection_data, + guint info, + gpointer data) +{ + gtk_selection_data_set_pixbuf (selection_data, data); +} + +static void +pixbuf_clear_func (GtkClipboard *clipboard, + gpointer data) +{ + g_object_unref (data); +} + +/** + * gtk_clipboard_set_image: + * @clipboard: a #GtkClipboard object + * @pixbuf: a #GdkPixbuf + * + * Sets the contents of the clipboard to the given #GdkPixbuf. + * GTK+ will take responsibility for responding for requests + * for the image, and for converting the image into the + * requested format. + * + * Since: 2.6 + **/ +void +gtk_clipboard_set_image (GtkClipboard *clipboard, + GdkPixbuf *pixbuf) +{ + GtkTargetList *list; + GList *l; + GtkTargetEntry *targets; + gint n_targets, i; + + g_return_if_fail (clipboard != NULL); + g_return_if_fail (GDK_IS_PIXBUF (pixbuf)); + + list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_image_targets (list, 0, TRUE); + + n_targets = g_list_length (list->list); + targets = g_new0 (GtkTargetEntry, n_targets); + for (l = list->list, i = 0; l; l = l->next, i++) + { + GtkTargetPair *pair = (GtkTargetPair *)l->data; + targets[i].target = gdk_atom_name (pair->target); + } + + gtk_clipboard_set_with_data (clipboard, + targets, n_targets, + pixbuf_get_func, pixbuf_clear_func, + g_object_ref (pixbuf)); + gtk_clipboard_set_can_store (clipboard, NULL, 0); + + g_free (targets); + gtk_target_list_unref (list); +} + static void set_request_contents_info (GtkWidget *widget, RequestContentsInfo *info) @@ -909,6 +976,83 @@ gtk_clipboard_request_text (GtkClipboard *clipboard, info); } +static void +request_image_received_func (GtkClipboard *clipboard, + GtkSelectionData *selection_data, + gpointer data) +{ + RequestImageInfo *info = data; + GdkPixbuf *result = NULL; + + result = gtk_selection_data_get_pixbuf (selection_data); + + if (!result) + { + /* If we asked for image/png and didn't get it, try image/jpeg; + * if we asked for image/jpeg and didn't get it, try image/gif; + * If we asked for anything else and didn't get it, give up. + */ + if (selection_data->target == gdk_atom_intern ("image/png", FALSE)) + { + gtk_clipboard_request_contents (clipboard, + gdk_atom_intern ("image/jpeg", FALSE), + request_image_received_func, info); + return; + } + else if (selection_data->target == gdk_atom_intern ("image/jpeg", FALSE)) + { + gtk_clipboard_request_contents (clipboard, + gdk_atom_intern ("image/gif", FALSE), + request_text_received_func, info); + return; + } + } + + info->callback (clipboard, result, info->user_data); + g_free (info); + g_object_unref (result); +} + +/** + * gtk_clipboard_request_image: + * @clipboard: a #GtkClipboard + * @callback: a function to call when the image is received, + * or the retrieval fails. (It will always be called + * one way or the other.) + * @user_data: user data to pass to @callback. + * + * Requests the contents of the clipboard as image. When the image is + * later received, it will be converted to a #GdkPixbuf, and + * @callback will be called. + * + * The @pixbuf parameter to @callback will contain the resulting + * #GdkPixbuf if the request succeeded, or %NULL if it failed. This + * could happen for various reasons, in particular if the clipboard + * was empty or if the contents of the clipboard could not be + * converted into an image. + * + * Since: 2.6 + **/ +void +gtk_clipboard_request_image (GtkClipboard *clipboard, + GtkClipboardImageReceivedFunc callback, + gpointer user_data) +{ + RequestImageInfo *info; + + g_return_if_fail (clipboard != NULL); + g_return_if_fail (callback != NULL); + + info = g_new (RequestImageInfo, 1); + info->callback = callback; + info->user_data = user_data; + + gtk_clipboard_request_contents (clipboard, + gdk_atom_intern ("image/png", FALSE), + request_image_received_func, + info); +} + static void request_targets_received_func (GtkClipboard *clipboard, GtkSelectionData *selection_data, @@ -1042,7 +1186,6 @@ clipboard_text_received_func (GtkClipboard *clipboard, g_main_loop_quit (results->loop); } - /** * gtk_clipboard_wait_for_text: * @clipboard: a #GtkClipboard @@ -1064,7 +1207,6 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard) { WaitResults results; - g_return_val_if_fail (clipboard != NULL, NULL); g_return_val_if_fail (clipboard != NULL, NULL); results.data = NULL; @@ -1085,6 +1227,62 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard) return results.data; } + +static void +clipboard_image_received_func (GtkClipboard *clipboard, + GdkPixbuf *pixbuf, + gpointer data) +{ + WaitResults *results = data; + + results->data = g_object_ref (pixbuf); + g_main_loop_quit (results->loop); +} + +/** + * gtk_clipboard_wait_for_image: + * @clipboard: a #GtkClipboard + * + * Requests the contents of the clipboard as image and converts + * the result to a #GdkPixbuf. This function waits for + * the data to be received using the main loop, so events, + * timeouts, etc, may be dispatched during the wait. + * + * Return value: a newly-allocated #GdkPixbuf object which must + * be disposed with g_object_unref(), or %NULL if + * retrieving the selection data failed. (This + * could happen for various reasons, in particular + * if the clipboard was empty or if the contents of + * the clipboard could not be converted into an image.) + * + * Since: 2.6 + **/ +GdkPixbuf * +gtk_clipboard_wait_for_image (GtkClipboard *clipboard) +{ + WaitResults results; + + g_return_val_if_fail (clipboard != NULL, NULL); + + results.data = NULL; + results.loop = g_main_loop_new (NULL, TRUE); + + gtk_clipboard_request_image (clipboard, + clipboard_image_received_func, + &results); + + if (g_main_loop_is_running (results.loop)) + { + GDK_THREADS_LEAVE (); + g_main_loop_run (results.loop); + GDK_THREADS_ENTER (); + } + + g_main_loop_unref (results.loop); + + return results.data; +} + /** * gtk_clipboard_get_display: * @clipboard: a #GtkClipboard @@ -1109,10 +1307,9 @@ gtk_clipboard_get_display (GtkClipboard *clipboard) * * Test to see if there is text available to be pasted * This is done by requesting the TARGETS atom and checking - * if it contains any of the names: STRING, TEXT, COMPOUND_TEXT, - * UTF8_STRING. This function waits for the data to be received - * using the main loop, so events, timeouts, etc, may be dispatched - * during the wait. + * if it contains any of the supported text targets. This function + * waits for the data to be received using the main loop, so events, + * timeouts, etc, may be dispatched during the wait. * * This function is a little faster than calling * gtk_clipboard_wait_for_text() since it doesn't need to retrieve @@ -1136,6 +1333,41 @@ gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard) return result; } +/** + * gtk_clipboard_wait_is_image_available: + * @clipboard: a #GtkClipboard + * + * Test to see if there is an image available to be pasted + * This is done by requesting the TARGETS atom and checking + * if it contains any of the supported image targets. This function + * waits for the data to be received using the main loop, so events, + * timeouts, etc, may be dispatched during the wait. + * + * This function is a little faster than calling + * gtk_clipboard_wait_for_image() since it doesn't need to retrieve + * the actual image data. + * + * Return value: %TRUE is there is an image available, %FALSE otherwise. + * + * Since: 2.6 + **/ +gboolean +gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard) +{ + GtkSelectionData *data; + gboolean result = FALSE; + + data = gtk_clipboard_wait_for_contents (clipboard, + gdk_atom_intern ("TARGETS", FALSE)); + if (data) + { + result = gtk_selection_data_targets_include_image (data, FALSE); + gtk_selection_data_free (data); + } + + return result; +} + /** * gtk_clipboard_wait_for_targets * @clipboard: a #GtkClipboard diff --git a/gtk/gtkclipboard.h b/gtk/gtkclipboard.h index c05e63cc4f..319c38aca6 100644 --- a/gtk/gtkclipboard.h +++ b/gtk/gtkclipboard.h @@ -38,6 +38,9 @@ typedef void (* GtkClipboardReceivedFunc) (GtkClipboard *clipboard, typedef void (* GtkClipboardTextReceivedFunc) (GtkClipboard *clipboard, const gchar *text, gpointer data); +typedef void (* GtkClipboardImageReceivedFunc) (GtkClipboard *clipboard, + GdkPixbuf *pixbuf, + gpointer data); typedef void (* GtkClipboardTargetsReceivedFunc) (GtkClipboard *clipboard, GdkAtom *atoms, gint n_atoms, @@ -82,6 +85,8 @@ void gtk_clipboard_clear (GtkClipboard *clipboard); void gtk_clipboard_set_text (GtkClipboard *clipboard, const gchar *text, gint len); +void gtk_clipboard_set_image (GtkClipboard *clipboard, + GdkPixbuf *pixbuf); void gtk_clipboard_request_contents (GtkClipboard *clipboard, GdkAtom target, @@ -90,6 +95,9 @@ void gtk_clipboard_request_contents (GtkClipboard *clipboard, void gtk_clipboard_request_text (GtkClipboard *clipboard, GtkClipboardTextReceivedFunc callback, gpointer user_data); +void gtk_clipboard_request_image (GtkClipboard *clipboard, + GtkClipboardImageReceivedFunc callback, + gpointer user_data); void gtk_clipboard_request_targets (GtkClipboard *clipboard, GtkClipboardTargetsReceivedFunc callback, gpointer user_data); @@ -97,11 +105,13 @@ void gtk_clipboard_request_targets (GtkClipboard *clipboard, GtkSelectionData *gtk_clipboard_wait_for_contents (GtkClipboard *clipboard, GdkAtom target); gchar * gtk_clipboard_wait_for_text (GtkClipboard *clipboard); +GdkPixbuf * gtk_clipboard_wait_for_image (GtkClipboard *clipboard); gboolean gtk_clipboard_wait_for_targets (GtkClipboard *clipboard, GdkAtom **targets, gint *n_targets); gboolean gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard); +gboolean gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard); gboolean gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard, GdkAtom target); diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c index ac8836975b..ab60873811 100644 --- a/gtk/gtkselection.c +++ b/gtk/gtkselection.c @@ -1496,7 +1496,10 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) targets[i] == text_plain_atom || targets[i] == text_plain_utf8_atom || targets[i] == text_plain_locale_atom) - result = TRUE; + { + result = TRUE; + break; + } } g_free (targets); @@ -1504,6 +1507,54 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) return result; } + +/** + * gtk_selection_data_targets_include_image: + * @selection_data: a #GtkSelectionData object + * @writable: whether to accept only targets for which GTK+ knows + * how to convert a pixbuf into the format + * + * Given a #GtkSelectionData object holding a list of targets, + * determines if any of the targets in @targets can be used to + * provide a #GdkPixbuf. + * + * Return value: %TRUE if @selection_data holds a list of targets, + * and a suitable target for images is included, otherwise %FALSE. + * + * Since: 2.6 + **/ +gboolean +gtk_selection_data_targets_include_image (GtkSelectionData *selection_data, + gboolean writable) +{ + GdkAtom *targets; + gint n_targets; + gint i; + gboolean result = FALSE; + GtkTargetList *list; + GList *l; + + 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++) + { + for (l = list->list; l && !result; l = l->next) + { + GtkTargetPair *pair = (GtkTargetPair *)l->data; + if (pair->target == targets[i]) + result = TRUE; + } + } + gtk_target_list_unref (list); + g_free (targets); + } + + return result; +} /************************************************************* * gtk_selection_init: diff --git a/gtk/gtkselection.h b/gtk/gtkselection.h index 5623b440e4..f3df99e10b 100644 --- a/gtk/gtkselection.h +++ b/gtk/gtkselection.h @@ -144,9 +144,9 @@ gboolean gtk_selection_data_set_text (GtkSelectionData *selection_data, const gchar *str, gint len); guchar * gtk_selection_data_get_text (GtkSelectionData *selection_data); -gboolean gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data, - GdkPixbuf *pixbuf); -GdkPixbuf *gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data); +gboolean gtk_selection_data_set_pixbuf (GtkSelectionData *selection_data, + GdkPixbuf *pixbuf); +GdkPixbuf *gtk_selection_data_get_pixbuf (GtkSelectionData *selection_data); gboolean gtk_selection_data_set_uris (GtkSelectionData *selection_data, gchar **uris); gchar **gtk_selection_data_get_uris (GtkSelectionData *selection_data); @@ -155,6 +155,8 @@ gboolean gtk_selection_data_get_targets (GtkSelectionData *selection_d GdkAtom **targets, gint *n_atoms); gboolean gtk_selection_data_targets_include_text (GtkSelectionData *selection_data); +gboolean gtk_selection_data_targets_include_image (GtkSelectionData *selection_data, + gboolean writable); /* Called when a widget is destroyed */