# HG changeset patch # User Sean Egan # Date 1087432017 0 # Node ID 98f01c233a40f80c912752e8ec37e01a6943d08b # Parent 635f88dc9adf9bf022ad9bb2835e5735b5be6b90 [gaim-migrate @ 10104] Some dnd fixes (I hope). I think this should also allow receivng HTML drops, but I can't figure out why it doesn't from Mozilla. It seems Mozilla is giving the text as a link, but I'm not sure why. Maybe it's a Mozilla bug? Maybe it's my bug. Hopefully someone else can take a look at it. I was unable to find anything else that supported dragging HTML text out to test with. committer: Tailor Script diff -r 635f88dc9adf -r 98f01c233a40 ChangeLog --- a/ChangeLog Wed Jun 16 06:51:24 2004 +0000 +++ b/ChangeLog Thu Jun 17 00:26:57 2004 +0000 @@ -35,6 +35,7 @@ it is only called once. (Evan Schoenberg). * Flashing windows should work again for unix in window managers that support the URGENT hint (Etan Reisner) + * Dragging into conversation windows works better. version 0.78 (05/30/2004): New Features: diff -r 635f88dc9adf -r 98f01c233a40 src/gtkconv.c --- a/src/gtkconv.c Wed Jun 16 06:51:24 2004 +0000 +++ b/src/gtkconv.c Thu Jun 17 00:26:57 2004 +0000 @@ -3801,7 +3801,6 @@ G_CALLBACK(refocus_entry_cb), gtkconv); gaim_setup_imhtml(gtkconv->imhtml); - gtk_widget_show(gtkconv->imhtml); /* Build the right pane. */ @@ -4028,10 +4027,8 @@ gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), gaim_prefs_get_bool("/gaim/gtk/conversations/show_timestamps")); - gaim_setup_imhtml(gtkconv->imhtml); gtk_widget_show(gtkconv->imhtml); - vbox2 = gtk_vbox_new(FALSE, 6); gtk_paned_pack2(GTK_PANED(paned), vbox2, FALSE, TRUE); gtk_widget_show(vbox2); @@ -4127,7 +4124,6 @@ { GaimConvWindow *win = conv->window; GaimConversation *c; - if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE)) { GaimBlistNode *n = NULL; @@ -4174,6 +4170,7 @@ gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); } + gtk_drag_finish(dc, FALSE, FALSE, t); } /************************************************************************** @@ -4387,31 +4384,30 @@ /* Setup drag-and-drop */ gtk_drag_dest_set(pane, - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - te, sizeof(te) / sizeof(GtkTargetEntry), - GDK_ACTION_COPY); - gtk_drag_dest_set(gtkconv->imhtml, - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - te, sizeof(te) / sizeof(GtkTargetEntry), - GDK_ACTION_DEFAULT | GDK_ACTION_COPY | - GDK_ACTION_MOVE); - gtk_drag_dest_set(gtkconv->entry, - GTK_DEST_DEFAULT_MOTION | - GTK_DEST_DEFAULT_DROP, - te, sizeof(te) / sizeof(GtkTargetEntry), - GDK_ACTION_COPY); - + GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_DROP, + te, sizeof(te) / sizeof(GtkTargetEntry), + GDK_ACTION_COPY); + gtk_drag_dest_set(pane, + GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_DROP, + te, sizeof(te) / sizeof(GtkTargetEntry), + GDK_ACTION_COPY); + gtk_drag_dest_set(gtkconv->imhtml, 0, + te, sizeof(te) / sizeof(GtkTargetEntry), + GDK_ACTION_COPY); + + gtk_drag_dest_set(gtkconv->entry, 0, + te, sizeof(te) / sizeof(GtkTargetEntry), + GDK_ACTION_COPY); + g_signal_connect(G_OBJECT(pane), "drag_data_received", - G_CALLBACK(conv_dnd_recv), conv); + G_CALLBACK(conv_dnd_recv), conv); g_signal_connect(G_OBJECT(gtkconv->imhtml), "drag_data_received", - G_CALLBACK(conv_dnd_recv), conv); -#if 0 + G_CALLBACK(conv_dnd_recv), conv); g_signal_connect(G_OBJECT(gtkconv->entry), "drag_data_received", - G_CALLBACK(conv_dnd_recv), conv); -#endif - + G_CALLBACK(conv_dnd_recv), conv); + /* Setup the container for the tab. */ gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, 6); gtk_container_set_border_width(GTK_CONTAINER(tab_cont), 6); diff -r 635f88dc9adf -r 98f01c233a40 src/gtkimhtml.c --- a/src/gtkimhtml.c Wed Jun 16 06:51:24 2004 +0000 +++ b/src/gtkimhtml.c Thu Jun 17 00:26:57 2004 +0000 @@ -71,10 +71,18 @@ #define gtk_widget_get_clipboard(x, y) gtk_clipboard_get(y) #endif +static gboolean +gtk_text_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time); + static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter); +static void gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data); static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml); static void hijack_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data); @@ -96,7 +104,12 @@ }; enum { - DRAG_URL + DRAG_URL, + DRAG_HTML, + DRAG_UTF8_STRING, + DRAG_COMPOUND_TEXT, + DRAG_STRING, + DRAG_TEXT, }; enum { @@ -117,10 +130,16 @@ { "TEXT", 0, TARGET_TEXT}}; GtkTargetEntry link_drag_drop_targets[] = { + {"text/html", 0, DRAG_HTML }, {"x-url/ftp", 0, DRAG_URL}, {"x-url/http", 0, DRAG_URL}, {"text/uri-list", 0, DRAG_URL}, - {"_NETSCAPE_URL", 0, DRAG_URL}}; + {"_NETSCAPE_URL", 0, DRAG_URL}, + { "UTF8_STRING", 0, DRAG_UTF8_STRING }, + { "COMPOUND_TEXT", 0, DRAG_COMPOUND_TEXT }, + { "STRING", 0, DRAG_STRING }, + { "TEXT", 0, DRAG_TEXT}}; + #ifdef _WIN32 /* Win32 clipboard format value, and functions to convert back and @@ -988,7 +1007,7 @@ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gobject_class->finalize = gtk_imhtml_finalize; - + widget_class->drag_motion = gtk_text_view_drag_motion; gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("hyperlink-color", _("Hyperlink color"), _("Color to draw hyperlinks."), @@ -1043,11 +1062,11 @@ g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL); g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml); g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); - gtk_drag_dest_set(GTK_WIDGET(imhtml), 0, link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry), GDK_ACTION_COPY); g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); + g_signal_connect(G_OBJECT(imhtml), "drag_drop", G_CALLBACK(gtk_imhtml_link_drop_cb), imhtml); g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL); @@ -1076,11 +1095,10 @@ imhtml->edit.fontsize = 0; imhtml->edit.link = NULL; - + imhtml->scalables = NULL; gtk_imhtml_set_editable(imhtml, FALSE); - g_signal_connect(G_OBJECT(imhtml), "populate-popup", G_CALLBACK(hijack_menu_cb), NULL); @@ -1241,29 +1259,115 @@ return FALSE; /* Let clicks go through if we didn't catch anything */ } +static gboolean +gtk_text_view_drag_motion (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + guint time) +{ + GdkDragAction suggested_action = 0; + + if (gtk_drag_dest_find_target (widget, context, + gtk_drag_dest_get_target_list (widget)) == GDK_NONE) { + /* can't accept any of the offered targets */ + } else { + GtkWidget *source_widget; + suggested_action = context->suggested_action; + source_widget = gtk_drag_get_source_widget (context); + if (source_widget == widget) { + /* Default to MOVE, unless the user has + * pressed ctrl or alt to affect available actions + */ + if ((context->actions & GDK_ACTION_MOVE) != 0) + suggested_action = GDK_ACTION_MOVE; + } + } + + if (suggested_action != 0) { + gdk_drag_status (context, suggested_action, time); + } else { + gdk_drag_status (context, 0, time); + } + + /* TRUE return means don't propagate the drag motion to parent + * widgets that may also be drop sites. + */ + return TRUE; +} + +static void +gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data) +{ + GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL); + + if (target != GDK_NONE) + gtk_drag_get_data (widget, context, target, time); + else + gtk_drag_finish (context, FALSE, FALSE, time); + + return; +} + static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml) { + gchar **links; + gchar *link; + char *text = sd->data; + GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer); + GtkTextIter iter; + + gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); + + if(gtk_imhtml_get_editable(imhtml) && sd->data){ - gchar **links; - gchar *link; - - gaim_str_strip_cr(sd->data); - - links = g_strsplit(sd->data, "\n", 0); - while((link = *links++) != NULL){ - if(gaim_str_has_prefix(link, "http://") || - gaim_str_has_prefix(link, "https://") || - gaim_str_has_prefix(link, "ftp://")){ - gtk_imhtml_insert_link(imhtml, gtk_text_buffer_get_insert(imhtml->text_buffer), link, link); - } else if (link=='\0') { - /* Ignore blank lines */ - } else { - /* Special reasons, aka images being put in via other tag, etc. */ + switch (info) { + case DRAG_URL: + gaim_str_strip_cr(sd->data); + + links = g_strsplit(sd->data, "\n", 0); + while((link = *links++) != NULL){ + if(gaim_str_has_prefix(link, "http://") || + gaim_str_has_prefix(link, "https://") || + gaim_str_has_prefix(link, "ftp://")){ + gtk_imhtml_insert_link(imhtml, mark, link, link); + } else if (link=='\0') { + /* Ignore blank lines */ + } else { + /* Special reasons, aka images being put in via other tag, etc. */ + } } + break; + case DRAG_HTML: + if (sd->length >= 2 && + (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) { + /* This is UCS-2 */ + char *tmp; + char *utf8 = g_convert(text, sd->length, "UTF-8", "UCS-2", NULL, NULL, NULL); + g_free(text); + text = utf8; + if (!text) { + gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n"); + return; + } + tmp = g_utf8_next_char(text); + memmove(text, tmp, strlen(tmp) + 1); + } + + if (!(*text) || !g_utf8_validate(text, -1, NULL)) { + gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); + g_free(text); + return; + } + gtk_imhtml_insert_html_at_iter(imhtml, text, 0, &iter); + break; + default: + break; } - + + gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); } else { gtk_drag_finish(dc, FALSE, FALSE, t); @@ -1271,8 +1375,7 @@ } /* this isn't used yet -static void -gtk_smiley_tree_remove (GtkSmileyTree *tree, +static void gtk_smiley_tree_remove (GtkSmileyTree *tree, GtkIMHtmlSmiley *smiley) { GtkSmileyTree *t = tree; diff -r 635f88dc9adf -r 98f01c233a40 src/main.c --- a/src/main.c Wed Jun 16 06:51:24 2004 +0000 +++ b/src/main.c Thu Jun 17 00:26:57 2004 +0000 @@ -906,12 +906,13 @@ #ifdef HAVE_STARTUP_NOTIFICATION startup_notification_complete(); #endif - gtk_main(); gaim_sound_shutdown(); #ifdef _WIN32 wgaim_cleanup(); #endif + + return 0; }