Mercurial > pidgin
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; |