comparison src/gtkimhtml.c @ 9300:98f01c233a40

[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 <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Thu, 17 Jun 2004 00:26:57 +0000
parents 2fa81d44ee6f
children b726aba28229
comparison
equal deleted inserted replaced
9299:635f88dc9adf 9300:98f01c233a40
69 /* GTK+ 2.0 hack */ 69 /* GTK+ 2.0 hack */
70 #if (!GTK_CHECK_VERSION(2,2,0)) 70 #if (!GTK_CHECK_VERSION(2,2,0))
71 #define gtk_widget_get_clipboard(x, y) gtk_clipboard_get(y) 71 #define gtk_widget_get_clipboard(x, y) gtk_clipboard_get(y)
72 #endif 72 #endif
73 73
74 static gboolean
75 gtk_text_view_drag_motion (GtkWidget *widget,
76 GdkDragContext *context,
77 gint x,
78 gint y,
79 guint time);
80
74 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); 81 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
75 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); 82 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
76 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); 83 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length);
77 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter); 84 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter);
85 static void gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data);
78 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); 86 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml);
79 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml); 87 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml);
80 static void hijack_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data); 88 static void hijack_menu_cb(GtkIMHtml *imhtml, GtkMenu *menu, gpointer data);
81 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data); 89 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data);
82 static void paste_plaintext_received_cb (GtkClipboard *clipboard, const gchar *text, gpointer data); 90 static void paste_plaintext_received_cb (GtkClipboard *clipboard, const gchar *text, gpointer data);
94 TARGET_STRING, 102 TARGET_STRING,
95 TARGET_TEXT 103 TARGET_TEXT
96 }; 104 };
97 105
98 enum { 106 enum {
99 DRAG_URL 107 DRAG_URL,
108 DRAG_HTML,
109 DRAG_UTF8_STRING,
110 DRAG_COMPOUND_TEXT,
111 DRAG_STRING,
112 DRAG_TEXT,
100 }; 113 };
101 114
102 enum { 115 enum {
103 URL_CLICKED, 116 URL_CLICKED,
104 BUTTONS_UPDATE, 117 BUTTONS_UPDATE,
115 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, 128 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
116 { "STRING", 0, TARGET_STRING }, 129 { "STRING", 0, TARGET_STRING },
117 { "TEXT", 0, TARGET_TEXT}}; 130 { "TEXT", 0, TARGET_TEXT}};
118 131
119 GtkTargetEntry link_drag_drop_targets[] = { 132 GtkTargetEntry link_drag_drop_targets[] = {
133 {"text/html", 0, DRAG_HTML },
120 {"x-url/ftp", 0, DRAG_URL}, 134 {"x-url/ftp", 0, DRAG_URL},
121 {"x-url/http", 0, DRAG_URL}, 135 {"x-url/http", 0, DRAG_URL},
122 {"text/uri-list", 0, DRAG_URL}, 136 {"text/uri-list", 0, DRAG_URL},
123 {"_NETSCAPE_URL", 0, DRAG_URL}}; 137 {"_NETSCAPE_URL", 0, DRAG_URL},
138 { "UTF8_STRING", 0, DRAG_UTF8_STRING },
139 { "COMPOUND_TEXT", 0, DRAG_COMPOUND_TEXT },
140 { "STRING", 0, DRAG_STRING },
141 { "TEXT", 0, DRAG_TEXT}};
142
124 143
125 #ifdef _WIN32 144 #ifdef _WIN32
126 /* Win32 clipboard format value, and functions to convert back and 145 /* Win32 clipboard format value, and functions to convert back and
127 * forth between HTML and the clipboard format. 146 * forth between HTML and the clipboard format.
128 */ 147 */
986 NULL, 1005 NULL,
987 0, 1006 0,
988 g_cclosure_marshal_VOID__VOID, 1007 g_cclosure_marshal_VOID__VOID,
989 G_TYPE_NONE, 0); 1008 G_TYPE_NONE, 0);
990 gobject_class->finalize = gtk_imhtml_finalize; 1009 gobject_class->finalize = gtk_imhtml_finalize;
991 1010 widget_class->drag_motion = gtk_text_view_drag_motion;
992 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("hyperlink-color", 1011 gtk_widget_class_install_style_property(widget_class, g_param_spec_boxed("hyperlink-color",
993 _("Hyperlink color"), 1012 _("Hyperlink color"),
994 _("Color to draw hyperlinks."), 1013 _("Color to draw hyperlinks."),
995 GDK_TYPE_COLOR, G_PARAM_READABLE)); 1014 GDK_TYPE_COLOR, G_PARAM_READABLE));
996 } 1015 }
1041 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); 1060 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL);
1042 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); 1061 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL);
1043 g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL); 1062 g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL);
1044 g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml); 1063 g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml);
1045 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); 1064 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml);
1046
1047 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0, 1065 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0,
1048 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry), 1066 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry),
1049 GDK_ACTION_COPY); 1067 GDK_ACTION_COPY);
1050 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); 1068 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml);
1069 g_signal_connect(G_OBJECT(imhtml), "drag_drop", G_CALLBACK(gtk_imhtml_link_drop_cb), imhtml);
1051 1070
1052 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); 1071 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL);
1053 g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL); 1072 g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL);
1054 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); 1073 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL);
1055 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL); 1074 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL);
1074 imhtml->edit.backcolor = NULL; 1093 imhtml->edit.backcolor = NULL;
1075 imhtml->edit.fontface = NULL; 1094 imhtml->edit.fontface = NULL;
1076 imhtml->edit.fontsize = 0; 1095 imhtml->edit.fontsize = 0;
1077 imhtml->edit.link = NULL; 1096 imhtml->edit.link = NULL;
1078 1097
1079 1098
1080 imhtml->scalables = NULL; 1099 imhtml->scalables = NULL;
1081 1100
1082 gtk_imhtml_set_editable(imhtml, FALSE); 1101 gtk_imhtml_set_editable(imhtml, FALSE);
1083
1084 g_signal_connect(G_OBJECT(imhtml), "populate-popup", 1102 g_signal_connect(G_OBJECT(imhtml), "populate-popup",
1085 G_CALLBACK(hijack_menu_cb), NULL); 1103 G_CALLBACK(hijack_menu_cb), NULL);
1086 1104
1087 #ifdef _WIN32 1105 #ifdef _WIN32
1088 /* Register HTML Format as desired clipboard format */ 1106 /* Register HTML Format as desired clipboard format */
1239 be caught by the regular GtkTextView menu */ 1257 be caught by the regular GtkTextView menu */
1240 else 1258 else
1241 return FALSE; /* Let clicks go through if we didn't catch anything */ 1259 return FALSE; /* Let clicks go through if we didn't catch anything */
1242 } 1260 }
1243 1261
1262 static gboolean
1263 gtk_text_view_drag_motion (GtkWidget *widget,
1264 GdkDragContext *context,
1265 gint x,
1266 gint y,
1267 guint time)
1268 {
1269 GdkDragAction suggested_action = 0;
1270
1271 if (gtk_drag_dest_find_target (widget, context,
1272 gtk_drag_dest_get_target_list (widget)) == GDK_NONE) {
1273 /* can't accept any of the offered targets */
1274 } else {
1275 GtkWidget *source_widget;
1276 suggested_action = context->suggested_action;
1277 source_widget = gtk_drag_get_source_widget (context);
1278 if (source_widget == widget) {
1279 /* Default to MOVE, unless the user has
1280 * pressed ctrl or alt to affect available actions
1281 */
1282 if ((context->actions & GDK_ACTION_MOVE) != 0)
1283 suggested_action = GDK_ACTION_MOVE;
1284 }
1285 }
1286
1287 if (suggested_action != 0) {
1288 gdk_drag_status (context, suggested_action, time);
1289 } else {
1290 gdk_drag_status (context, 0, time);
1291 }
1292
1293 /* TRUE return means don't propagate the drag motion to parent
1294 * widgets that may also be drop sites.
1295 */
1296 return TRUE;
1297 }
1298
1299 static void
1300 gtk_imhtml_link_drop_cb(GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, gpointer user_data)
1301 {
1302 GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
1303
1304 if (target != GDK_NONE)
1305 gtk_drag_get_data (widget, context, target, time);
1306 else
1307 gtk_drag_finish (context, FALSE, FALSE, time);
1308
1309 return;
1310 }
1311
1244 static void 1312 static void
1245 gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, 1313 gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y,
1246 GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml) 1314 GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml)
1247 { 1315 {
1316 gchar **links;
1317 gchar *link;
1318 char *text = sd->data;
1319 GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer);
1320 GtkTextIter iter;
1321
1322 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark);
1323
1324
1248 if(gtk_imhtml_get_editable(imhtml) && sd->data){ 1325 if(gtk_imhtml_get_editable(imhtml) && sd->data){
1249 gchar **links; 1326 switch (info) {
1250 gchar *link; 1327 case DRAG_URL:
1251 1328 gaim_str_strip_cr(sd->data);
1252 gaim_str_strip_cr(sd->data); 1329
1253 1330 links = g_strsplit(sd->data, "\n", 0);
1254 links = g_strsplit(sd->data, "\n", 0); 1331 while((link = *links++) != NULL){
1255 while((link = *links++) != NULL){ 1332 if(gaim_str_has_prefix(link, "http://") ||
1256 if(gaim_str_has_prefix(link, "http://") || 1333 gaim_str_has_prefix(link, "https://") ||
1257 gaim_str_has_prefix(link, "https://") || 1334 gaim_str_has_prefix(link, "ftp://")){
1258 gaim_str_has_prefix(link, "ftp://")){ 1335 gtk_imhtml_insert_link(imhtml, mark, link, link);
1259 gtk_imhtml_insert_link(imhtml, gtk_text_buffer_get_insert(imhtml->text_buffer), link, link); 1336 } else if (link=='\0') {
1260 } else if (link=='\0') { 1337 /* Ignore blank lines */
1261 /* Ignore blank lines */ 1338 } else {
1262 } else { 1339 /* Special reasons, aka images being put in via other tag, etc. */
1263 /* Special reasons, aka images being put in via other tag, etc. */ 1340 }
1264 } 1341 }
1265 } 1342 break;
1266 1343 case DRAG_HTML:
1344 if (sd->length >= 2 &&
1345 (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) {
1346 /* This is UCS-2 */
1347 char *tmp;
1348 char *utf8 = g_convert(text, sd->length, "UTF-8", "UCS-2", NULL, NULL, NULL);
1349 g_free(text);
1350 text = utf8;
1351 if (!text) {
1352 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n");
1353 return;
1354 }
1355 tmp = g_utf8_next_char(text);
1356 memmove(text, tmp, strlen(tmp) + 1);
1357 }
1358
1359 if (!(*text) || !g_utf8_validate(text, -1, NULL)) {
1360 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n");
1361 g_free(text);
1362 return;
1363 }
1364 gtk_imhtml_insert_html_at_iter(imhtml, text, 0, &iter);
1365 break;
1366 default:
1367 break;
1368 }
1369
1370
1267 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); 1371 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
1268 } else { 1372 } else {
1269 gtk_drag_finish(dc, FALSE, FALSE, t); 1373 gtk_drag_finish(dc, FALSE, FALSE, t);
1270 } 1374 }
1271 } 1375 }
1272 1376
1273 /* this isn't used yet 1377 /* this isn't used yet
1274 static void 1378 static void gtk_smiley_tree_remove (GtkSmileyTree *tree,
1275 gtk_smiley_tree_remove (GtkSmileyTree *tree,
1276 GtkIMHtmlSmiley *smiley) 1379 GtkIMHtmlSmiley *smiley)
1277 { 1380 {
1278 GtkSmileyTree *t = tree; 1381 GtkSmileyTree *t = tree;
1279 const gchar *x = smiley->smile; 1382 const gchar *x = smiley->smile;
1280 gint len = 0; 1383 gint len = 0;