diff options
author | Matthias Clasen <maclas@gmx.de> | 2004-07-17 04:58:02 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2004-07-17 04:58:02 +0000 |
commit | fb881018542b3b567177d0a1063d9169b17bab48 (patch) | |
tree | 29a44f0aab7f4b3bc18b41f11eaf1df401c43695 /gtk | |
parent | a5638e82e8f5bef394166fecd997752204299155 (diff) | |
download | gtk+-fb881018542b3b567177d0a1063d9169b17bab48.tar.gz |
Support text/plain selection target (#55117, Owen Taylor)
Sat Jul 17 00:48:27 2004 Matthias Clasen <maclas@gmx.de>
Support text/plain selection target (#55117, Owen Taylor)
* gtk/gtkselection.h:
* gtk/gtkdnd.h:
* gtk/gtkselection.c (gtk_target_list_add_text_targets):
* gtk/gtkdnd.c (gtk_drag_dest_add_text_targets):
* gtk/gtkdnd.c (gtk_drag_source_add_text_targets): New
functions to facilitate handling of text targets.
* gtk/gtkentry.c:
* gtk/gtktextview.c: Use the new text target handling
functions instead of hardwiring the list of supported
text targets everywhere.
* gtk/gtkselection.c (gtk_selection_data_get_text):
(gtk_selection_data_set_text):
Support the targets text/plain, text/plain?charset=utf-8
and text/plain?charset=<LOCALE-CHARSET> as outlined in
#55117:
For text/plain send only ASCII, but accept 8-bit text
and treat it as ISO-8859-1 as specified by the Xdnd spec.
Always send CRLF terminators. Accept either and convert
into the native terminator for the platform.
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtkdnd.c | 37 | ||||
-rw-r--r-- | gtk/gtkdnd.h | 2 | ||||
-rw-r--r-- | gtk/gtkentry.c | 28 | ||||
-rw-r--r-- | gtk/gtkselection.c | 245 | ||||
-rw-r--r-- | gtk/gtkselection.h | 1 | ||||
-rw-r--r-- | gtk/gtktextview.c | 20 |
6 files changed, 284 insertions, 49 deletions
diff --git a/gtk/gtkdnd.c b/gtk/gtkdnd.c index 8e8fa7b7fb..786de4c972 100644 --- a/gtk/gtkdnd.c +++ b/gtk/gtkdnd.c @@ -1024,6 +1024,24 @@ gtk_drag_dest_set_target_list (GtkWidget *widget, site->target_list = target_list; } +/** + * gtk_drag_dest_add_text_targets: + * @widget: a #GtkWidget that's a drag destination + * + * Add the text targets supported by #GtkSelection to + * the target list of the drag destination. + * + * Since: 2.6 + **/ +void +gtk_drag_dest_add_text_targets (GtkWidget *widget) +{ + GtkTargetList *target_list; + + target_list = gtk_drag_dest_get_target_list (widget); + gtk_target_list_add_text_targets (target_list); + gtk_drag_dest_set_target_list (widget, target_list); +} /************************************************************* * _gtk_drag_dest_handle_event: @@ -2172,6 +2190,25 @@ gtk_drag_source_set_target_list (GtkWidget *widget, site->target_list = target_list; } +/** + * gtk_drag_source_add_text_targets: + * @widget: a #GtkWidget that's is a drag source + * + * Add the text targets supported by #GtkSelection to + * the target list of the drag source. + * + * Since: 2.6 + **/ +void +gtk_drag_source_add_text_targets (GtkWidget *widget) +{ + GtkTargetList *target_list; + + target_list = gtk_drag_source_get_target_list (widget); + gtk_target_list_add_text_targets (target_list); + gtk_drag_source_set_target_list (widget, target_list); +} + static void gtk_drag_source_unset_icon (GtkDragSourceSite *site) { diff --git a/gtk/gtkdnd.h b/gtk/gtkdnd.h index 1c8456772b..bfcbb50c37 100644 --- a/gtk/gtkdnd.h +++ b/gtk/gtkdnd.h @@ -85,6 +85,7 @@ GdkAtom gtk_drag_dest_find_target (GtkWidget *widget, GtkTargetList* gtk_drag_dest_get_target_list (GtkWidget *widget); void gtk_drag_dest_set_target_list (GtkWidget *widget, GtkTargetList *target_list); +void gtk_drag_dest_add_text_targets (GtkWidget *widget); /* Source side */ @@ -99,6 +100,7 @@ void gtk_drag_source_unset (GtkWidget *widget); GtkTargetList* gtk_drag_source_get_target_list (GtkWidget *widget); void gtk_drag_source_set_target_list (GtkWidget *widget, GtkTargetList *target_list); +void gtk_drag_source_add_text_targets (GtkWidget *widget); void gtk_drag_source_set_icon (GtkWidget *widget, GdkColormap *colormap, diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c index c797d846d6..fdc658d164 100644 --- a/gtk/gtkentry.c +++ b/gtk/gtkentry.c @@ -112,13 +112,6 @@ typedef enum { CURSOR_DND } CursorType; -static const GtkTargetEntry target_table[] = { - { "UTF8_STRING", 0, 0 }, - { "COMPOUND_TEXT", 0, 0 }, - { "TEXT", 0, 0 }, - { "STRING", 0, 0 } -}; - /* GObject, GtkObject methods */ static void gtk_entry_class_init (GtkEntryClass *klass); @@ -959,8 +952,9 @@ gtk_entry_init (GtkEntry *entry) gtk_drag_dest_set (GTK_WIDGET (entry), GTK_DEST_DEFAULT_HIGHLIGHT, - target_table, G_N_ELEMENTS (target_table), + NULL, 0, GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_drag_dest_add_text_targets (GTK_WIDGET (entry)); /* This object is completely private. No external entity can gain a reference * to it; so we create it here and destroy it in finalize(). @@ -1573,7 +1567,8 @@ gtk_entry_motion_notify (GtkWidget *widget, event->x + entry->scroll_offset, event->y)) { GdkDragContext *context; - GtkTargetList *target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table)); + GtkTargetList *target_list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_text_targets (target_list); guint actions = entry->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY; context = gtk_drag_begin (widget, target_list, actions, @@ -3557,16 +3552,27 @@ primary_clear_cb (GtkClipboard *clipboard, static void gtk_entry_update_primary_selection (GtkEntry *entry) { - static const GtkTargetEntry targets[] = { + static GtkTargetEntry targets[] = { { "UTF8_STRING", 0, 0 }, { "STRING", 0, 0 }, { "TEXT", 0, 0 }, - { "COMPOUND_TEXT", 0, 0 } + { "COMPOUND_TEXT", 0, 0 }, + { "text/plain;charset=utf-8", 0, 0 }, + { NULL, 0, 0 }, + { "text/plain", 0, 0 } }; GtkClipboard *clipboard; gint start, end; + if (targets[5].target == NULL) + { + const gchar *charset; + + g_get_charset (&charset); + targets[5].target = g_strdup_printf ("text/plain;charset=%s", charset); + } + if (!GTK_WIDGET_REALIZED (entry)) return; diff --git a/gtk/gtkselection.c b/gtk/gtkselection.c index a33e63a25c..ad52fe619e 100644 --- a/gtk/gtkselection.c +++ b/gtk/gtkselection.c @@ -222,9 +222,9 @@ gtk_target_list_unref (GtkTargetList *list) void gtk_target_list_add (GtkTargetList *list, - GdkAtom target, - guint flags, - guint info) + GdkAtom target, + guint flags, + guint info) { GtkTargetPair *pair; @@ -238,6 +238,61 @@ gtk_target_list_add (GtkTargetList *list, list->list = g_list_append (list->list, pair); } +static GdkAtom utf8_atom; +static GdkAtom text_atom; +static GdkAtom ctext_atom; +static GdkAtom text_plain_atom; +static GdkAtom text_plain_utf8_atom; +static GdkAtom text_plain_locale_atom; + +static void +init_atoms (void) +{ + gchar *tmp; + const gchar *charset; + + if (!utf8_atom) + { + utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE); + text_atom = gdk_atom_intern ("TEXT", FALSE); + ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); + text_plain_atom = gdk_atom_intern ("text/plain", FALSE); + text_plain_utf8_atom = gdk_atom_intern ("text/plain;charset=utf-8", FALSE); + 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); + } +} + +/** + * gtk_target_list_add_text_targets: + * @list: a #GtkTargetList + * + * Adds the text targets supported by #GtkSelection to + * the target list. The targets are added with both flags + * and info being zero. + * + * Since: 2.6 + **/ +void +gtk_target_list_add_text_targets (GtkTargetList *list) +{ + 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, 0); + gtk_target_list_add (list, ctext_atom, 0, 0); + gtk_target_list_add (list, text_atom, 0, 0); + gtk_target_list_add (list, GDK_TARGET_STRING, 0, 0); + gtk_target_list_add (list, text_plain_utf8_atom, 0, 0); + gtk_target_list_add (list, text_plain_locale_atom, 0, 0); + gtk_target_list_add (list, text_plain_atom, 0, 0); +} + void gtk_target_list_add_table (GtkTargetList *list, const GtkTargetEntry *targets, @@ -803,21 +858,6 @@ gtk_selection_data_set (GtkSelectionData *selection_data, selection_data->length = length; } -static GdkAtom utf8_atom; -static GdkAtom text_atom; -static GdkAtom ctext_atom; - -static void -init_atoms (void) -{ - if (!utf8_atom) - { - utf8_atom = gdk_atom_intern ("UTF8_STRING", FALSE); - text_atom = gdk_atom_intern ("TEXT", FALSE); - ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE); - } -} - static gboolean selection_set_string (GtkSelectionData *selection_data, const gchar *str, @@ -867,6 +907,149 @@ selection_set_compound_text (GtkSelectionData *selection_data, return result; } +/* Normalize \r and \n into \r\n + */ +static gchar * +normalize_to_crlf (const gchar *str, + gint len) +{ + GString *result = g_string_sized_new (len); + const gchar *p = str; + + while (1) + { + if (*p == '\n') + g_string_append_c (result, '\r'); + + if (*p == '\r') + { + g_string_append_c (result, *p); + p++; + if (*p != '\n') + g_string_append_c (result, '\n'); + } + + if (*p == '\0') + break; + + g_string_append_c (result, *p); + p++; + } + + return g_string_free (result, FALSE); +} + +/* Normalize \r and \r\n into \n + */ +static gchar * +normalize_to_lf (gchar *str, + gint len) +{ + GString *result = g_string_sized_new (len); + const gchar *p = str; + + while (1) + { + if (*p == '\r') + { + p++; + if (*p != '\n') + g_string_append_c (result, '\n'); + } + + if (*p == '\0') + break; + + g_string_append_c (result, *p); + p++; + } + + return g_string_free (result, FALSE); +} + +static gboolean +selection_set_text_plain (GtkSelectionData *selection_data, + const gchar *str, + gint len) +{ + const gchar *charset = NULL; + gchar *result; + GError *error = NULL; + + result = normalize_to_crlf (str, len); + if (selection_data->target == text_plain_atom) + charset = "ASCII"; + else if (selection_data->target == text_plain_locale_atom) + g_get_charset (&charset); + + if (charset) + { + gchar *tmp = result; + result = g_convert_with_fallback (tmp, -1, + charset, "UTF-8", + NULL, NULL, NULL, &error); + g_free (tmp); + } + + if (!result) + { + g_warning ("Error converting from UTF-8 to %s: %s", + charset, error->message); + g_error_free (error); + + return FALSE; + } + + gtk_selection_data_set (selection_data, + selection_data->target, + 8, result, strlen (result)); + g_free (result); + + return TRUE; +} + +static gchar * +selection_get_text_plain (GtkSelectionData *selection_data) +{ + const gchar *charset = NULL; + gchar *str, *result; + gint len; + GError *error = NULL; + + str = g_strdup (selection_data->data); + len = selection_data->length; + + if (selection_data->type == text_plain_atom) + charset = "ISO-8859-1"; + else if (selection_data->type == text_plain_locale_atom) + g_get_charset (&charset); + + if (charset) + { + gchar *tmp = str; + str = g_convert_with_fallback (tmp, len, + charset, "UTF-8", + NULL, NULL, &len, &error); + g_free (tmp); + } + + if (!str) + { + g_warning ("Error converting from %s to UTF-8: %s", + charset, error->message); + g_error_free (error); + + return NULL; + } + + + result = normalize_to_lf (str, len); + + g_free (str); + + return result; +} + /** * gtk_selection_data_set_text: * @selection_data: a #GtkSelectionData @@ -909,6 +1092,12 @@ gtk_selection_data_set_text (GtkSelectionData *selection_data, 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; } @@ -951,6 +1140,13 @@ gtk_selection_data_get_text (GtkSelectionData *selection_data) 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; } @@ -1016,14 +1212,19 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data) gint i; gboolean result = 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)) + 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; } diff --git a/gtk/gtkselection.h b/gtk/gtkselection.h index d7b0b4da4f..9e398a8e6d 100644 --- a/gtk/gtkselection.h +++ b/gtk/gtkselection.h @@ -95,6 +95,7 @@ void gtk_target_list_add (GtkTargetList *list, GdkAtom target, guint flags, guint info); +void gtk_target_list_add_text_targets (GtkTargetList *list); void gtk_target_list_add_table (GtkTargetList *list, const GtkTargetEntry *targets, guint ntargets); diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c index 84763ca3ba..f3a7e344c9 100644 --- a/gtk/gtktextview.c +++ b/gtk/gtktextview.c @@ -410,22 +410,8 @@ static gint text_window_get_width (GtkTextWindow *win); static gint text_window_get_height (GtkTextWindow *win); -enum -{ - TARGET_STRING, - TARGET_TEXT, - TARGET_COMPOUND_TEXT, - TARGET_UTF8_STRING, - TARGET_TEXT_BUFFER_CONTENTS -}; - -static const GtkTargetEntry target_table[] = { - { "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP, - TARGET_TEXT_BUFFER_CONTENTS }, - { "UTF8_STRING", 0, TARGET_UTF8_STRING }, - { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, - { "TEXT", 0, TARGET_TEXT }, - { "STRING", 0, TARGET_STRING } +static GtkTargetEntry target_table[] = { + { "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP, 0 }, }; static GtkContainerClass *parent_class = NULL; @@ -1066,6 +1052,7 @@ gtk_text_view_init (GtkTextView *text_view) 0, target_table, G_N_ELEMENTS (target_table), GDK_ACTION_COPY | GDK_ACTION_MOVE); + gtk_drag_dest_add_text_targets (widget); text_view->virtual_cursor_x = -1; text_view->virtual_cursor_y = -1; @@ -5872,6 +5859,7 @@ gtk_text_view_start_selection_dnd (GtkTextView *text_view, target_list = gtk_target_list_new (target_table, G_N_ELEMENTS (target_table)); + gtk_target_list_add_text_targets (target_list); context = gtk_drag_begin (GTK_WIDGET (text_view), target_list, GDK_ACTION_COPY | GDK_ACTION_MOVE, |