comparison src/gtkimhtml.c @ 7988:d9e831876c28

[gaim-migrate @ 8665] Here's my best attempt to rip WYSIWYG editing out of gaim, kicking and screaming all the way. We'll be releasing 0.75 in the very near future, once the translators are alerted, and any bugs from this dissection show themselves. committer: Tailor Script <tailor@pidgin.im>
author Nathan Walp <nwalp@pidgin.im>
date Sun, 04 Jan 2004 06:59:09 +0000
parents aca39f227ea0
children 096562205906
comparison
equal deleted inserted replaced
7987:fc6b362f9c26 7988:d9e831876c28
57 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD 57 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD
58 #endif 58 #endif
59 59
60 #define TOOLTIP_TIMEOUT 500 60 #define TOOLTIP_TIMEOUT 500
61 61
62 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml);
63 void gtk_imhtml_close_tags(GtkIMHtml *imhtml);
64
65 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a 62 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a
66 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ 63 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */
67 #define MAX_FONT_SIZE 7 64 #define MAX_FONT_SIZE 7
68 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) 65 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1])
69 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; 66 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 };
70
71 enum {
72 TARGET_HTML,
73 TARGET_UTF8_STRING,
74 TARGET_COMPOUND_TEXT,
75 TARGET_STRING,
76 TARGET_TEXT
77 };
78
79 GtkTargetEntry selection_targets[] = {
80 { "text/html", 0, TARGET_HTML },
81 { "UTF8_STRING", 0, TARGET_UTF8_STRING },
82 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
83 { "STRING", 0, TARGET_STRING },
84 { "TEXT", 0, TARGET_TEXT}};
85 67
86 static GtkSmileyTree* 68 static GtkSmileyTree*
87 gtk_smiley_tree_new () 69 gtk_smiley_tree_new ()
88 { 70 {
89 return g_new0 (GtkSmileyTree, 1); 71 return g_new0 (GtkSmileyTree, 1);
112 index = t->values->len - 1; 94 index = t->values->len - 1;
113 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); 95 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *));
114 t->children [index] = g_new0 (GtkSmileyTree, 1); 96 t->children [index] = g_new0 (GtkSmileyTree, 1);
115 } else 97 } else
116 index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str); 98 index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str);
117 99
118 t = t->children [index]; 100 t = t->children [index];
119 101
120 x++; 102 x++;
121 } 103 }
122 104
123 t->image = smiley; 105 t->image = smiley;
124 } 106 }
125 107
126 108
127 void gtk_smiley_tree_destroy (GtkSmileyTree *tree) 109 void gtk_smiley_tree_destroy (GtkSmileyTree *tree)
169 151
170 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); 152 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE);
171 153
172 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); 154 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip);
173 155
174 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, 156 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window,
175 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, 157 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window,
176 "tooltip", 0, 0, -1, -1); 158 "tooltip", 0, 0, -1, -1);
177 159
178 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, 160 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL,
179 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); 161 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout);
195 177
196 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { 178 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) {
197 imhtml->tip_timer = 0; 179 imhtml->tip_timer = 0;
198 return FALSE; 180 return FALSE;
199 } 181 }
200 182
201 if (imhtml->tip_window){ 183 if (imhtml->tip_window){
202 gtk_widget_destroy (imhtml->tip_window); 184 gtk_widget_destroy (imhtml->tip_window);
203 imhtml->tip_window = NULL; 185 imhtml->tip_window = NULL;
204 } 186 }
205 187
217 imhtml->tip_window->style->font_desc), 199 imhtml->tip_window->style->font_desc),
218 NULL); 200 NULL);
219 201
220 202
221 pango_layout_get_pixel_size(layout, &scr_w, NULL); 203 pango_layout_get_pixel_size(layout, &scr_w, NULL);
222 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + 204 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) +
223 pango_font_metrics_get_descent(font))/ 4); 205 pango_font_metrics_get_descent(font))/ 4);
224 206
225 if (gap < 2) 207 if (gap < 2)
226 gap = 2; 208 gap = 2;
227 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + 209 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) +
228 pango_font_metrics_get_descent(font)); 210 pango_font_metrics_get_descent(font));
229 w = 8 + scr_w; 211 w = 8 + scr_w;
230 h = 8 + baseline_skip; 212 h = 8 + baseline_skip;
231 213
232 gdk_window_get_pointer (NULL, &x, &y, NULL); 214 gdk_window_get_pointer (NULL, &x, &y, NULL);
240 if ((x + w) > scr_w) 222 if ((x + w) > scr_w)
241 x -= (x + w) - scr_w; 223 x -= (x + w) - scr_w;
242 else if (x < 0) 224 else if (x < 0)
243 x = 0; 225 x = 0;
244 226
245 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + 227 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) +
246 pango_font_metrics_get_descent(font)); 228 pango_font_metrics_get_descent(font));
247 229
248 gtk_widget_set_size_request (imhtml->tip_window, w, h); 230 gtk_widget_set_size_request (imhtml->tip_window, w, h);
249 gtk_widget_show (imhtml->tip_window); 231 gtk_widget_show (imhtml->tip_window);
250 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); 232 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y);
254 236
255 return FALSE; 237 return FALSE;
256 } 238 }
257 239
258 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) 240 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data)
259 { 241 {
260 GtkTextIter iter; 242 GtkTextIter iter;
261 GdkWindow *win = event->window; 243 GdkWindow *win = event->window;
262 int x, y; 244 int x, y;
263 char *tip = NULL; 245 char *tip = NULL;
264 GSList *tags = NULL, *templist = NULL; 246 GSList *tags = NULL, *templist = NULL;
274 tip = g_object_get_data(G_OBJECT(tag), "link_url"); 256 tip = g_object_get_data(G_OBJECT(tag), "link_url");
275 if (tip) 257 if (tip)
276 break; 258 break;
277 templist = templist->next; 259 templist = templist->next;
278 } 260 }
279 261
280 if (GTK_IMHTML(imhtml)->tip) { 262 if (GTK_IMHTML(imhtml)->tip) {
281 if ((tip == GTK_IMHTML(imhtml)->tip)) { 263 if ((tip == GTK_IMHTML(imhtml)->tip)) {
282 return FALSE; 264 return FALSE;
283 } 265 }
284 /* We've left the cell. Remove the timeout and create a new one below */ 266 /* We've left the cell. Remove the timeout and create a new one below */
285 if (GTK_IMHTML(imhtml)->tip_window) { 267 if (GTK_IMHTML(imhtml)->tip_window) {
286 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); 268 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window);
287 GTK_IMHTML(imhtml)->tip_window = NULL; 269 GTK_IMHTML(imhtml)->tip_window = NULL;
288 } 270 }
289 if (GTK_IMHTML(imhtml)->editable) 271 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor);
290 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->text_cursor);
291 else
292 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor);
293 if (GTK_IMHTML(imhtml)->tip_timer) 272 if (GTK_IMHTML(imhtml)->tip_timer)
294 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); 273 g_source_remove(GTK_IMHTML(imhtml)->tip_timer);
295 GTK_IMHTML(imhtml)->tip_timer = 0; 274 GTK_IMHTML(imhtml)->tip_timer = 0;
296 } 275 }
297 276
298 if(tip){ 277 if(tip){
299 if (!GTK_IMHTML(imhtml)->editable) 278 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor);
300 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); 279 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT,
301 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT,
302 gtk_imhtml_tip, imhtml); 280 gtk_imhtml_tip, imhtml);
303 } 281 }
304 282
305 GTK_IMHTML(imhtml)->tip = tip; 283 GTK_IMHTML(imhtml)->tip = tip;
306 g_slist_free(tags); 284 g_slist_free(tags);
307 return FALSE; 285 return FALSE;
308 } 286 }
309 287
316 } 294 }
317 if (GTK_IMHTML(imhtml)->tip_timer) { 295 if (GTK_IMHTML(imhtml)->tip_timer) {
318 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); 296 g_source_remove(GTK_IMHTML(imhtml)->tip_timer);
319 GTK_IMHTML(imhtml)->tip_timer = 0; 297 GTK_IMHTML(imhtml)->tip_timer = 0;
320 } 298 }
321 if (GTK_IMHTML(imhtml)->editable) 299 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor);
322 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->text_cursor);
323 else
324 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor);
325 300
326 /* propogate the event normally */ 301 /* propogate the event normally */
327 return FALSE; 302 return FALSE;
328 } 303 }
329 304
330 /* 305 /*
331 * XXX - This should be removed eventually. 306 * XXX - This should be removed eventually.
332 * 307 *
333 * This function exists to work around a gross bug in GtkTextView. 308 * This function exists to work around a gross bug in GtkTextView.
334 * Basically, we short circuit ctrl+a and ctrl+end because they make 309 * Basically, we short circuit ctrl+a and ctrl+end because they make
335 * el program go boom. 310 * el program go boom.
336 * 311 *
337 * It's supposed to be fixed in gtk2.2. You can view the bug report at 312 * It's supposed to be fixed in gtk2.2. You can view the bug report at
338 * http://bugzilla.gnome.org/show_bug.cgi?id=107939 313 * http://bugzilla.gnome.org/show_bug.cgi?id=107939
339 */ 314 */
340 gboolean gtk_key_pressed_cb(GtkWidget *imhtml, GdkEventKey *event, gpointer data) 315 gboolean gtk_key_pressed_cb(GtkWidget *imhtml, GdkEventKey *event, gpointer data)
341 { 316 {
342 if (event->state & GDK_CONTROL_MASK) 317 if (event->state & GDK_CONTROL_MASK)
356 331
357 return FALSE; 332 return FALSE;
358 } 333 }
359 334
360 #if GTK_CHECK_VERSION(2,2,0) 335 #if GTK_CHECK_VERSION(2,2,0)
361 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { 336 static GtkIMHtmlCopyable *gtk_imhtml_copyable_new(GtkIMHtml *imhtml, GtkTextMark *mark, const gchar *text)
362 GtkTextIter start, end; 337 {
338 GtkIMHtmlCopyable *copy = g_malloc(sizeof(GtkIMHtmlCopyable));
339 copy->mark = mark;
340 copy->text = g_strdup(text);
341 imhtml->copyables = g_slist_append(imhtml->copyables, copy);
342 return copy;
343 }
344
345 static void copy_clipboard_cb(GtkIMHtml *imhtml, GtkClipboard *clipboard)
346 {
363 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); 347 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer);
364 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 348 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
349 GtkTextIter start, end, smiley, last;
350 GString *str = g_string_new(NULL);
365 char *text; 351 char *text;
352
353 GSList *copyables;
354
366 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); 355 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel);
367 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); 356 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins);
368 357
369 358 if (gtk_text_iter_equal(&start, &end))
370 if (info == TARGET_HTML) { 359 return;
371 int len; 360
372 GString *str = g_string_new(NULL); 361 gtk_text_iter_order(&start, &end);
373 text = gtk_imhtml_get_markup_range(imhtml, &start, &end); 362 last = start;
374 363
375 /* Mozilla asks that we start our text/html with the Unicode byte order mark */ 364 for (copyables = imhtml->copyables; copyables != NULL; copyables = copyables->next) {
376 str = g_string_append_unichar(str, 0xfeff); 365 GtkIMHtmlCopyable *copy = GTK_IMHTML_COPYABLE(copyables->data);
377 str = g_string_append(str, text); 366 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &smiley, copy->mark);
378 str = g_string_append_unichar(str, 0x0000); 367 if (gtk_text_iter_compare(&end, &smiley) < 0) {
379 char *selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL); 368 break;
380 gtk_selection_data_set (selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len); 369 }
381 g_string_free(str, TRUE); 370 if (gtk_text_iter_compare(&last, &smiley) <= 0) {
382 g_free(selection); 371 text = gtk_text_buffer_get_text(imhtml->text_buffer, &last, &smiley, FALSE);
383 } else { 372 str = g_string_append(str, text);
384 text = gtk_text_buffer_get_text(imhtml->text_buffer, &start, &end, FALSE); 373 str = g_string_append(str, copy->text);
385 gtk_selection_data_set_text(selection_data, text, strlen(text)); 374 last = smiley;
386 } 375 g_free(text);
376 }
377 }
378 text = gtk_text_buffer_get_text(imhtml->text_buffer, &last, &end, FALSE);
379 str = g_string_append(str, text);
387 g_free(text); 380 g_free(text);
388 } 381
389 382 if (!gtk_text_iter_equal(&start, &last))
390 static void gtk_imhtml_primary_clipboard_clear(GtkClipboard *clipboard, GtkIMHtml *imhtml) 383 gtk_clipboard_set_text(clipboard ? clipboard :
391 { 384 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
392 GtkTextIter insert; 385 str->str, str->len);
393 GtkTextIter selection_bound; 386 g_string_free(str, TRUE);
394
395 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &insert,
396 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"));
397 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &selection_bound,
398 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"));
399
400 if (!gtk_text_iter_equal (&insert, &selection_bound))
401 gtk_text_buffer_move_mark (imhtml->text_buffer,
402 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"),
403 &insert);
404 }
405
406 static void copy_clipboard_cb(GtkIMHtml *imhtml, GtkClipboard *clipboard)
407 {
408 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD),
409 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
410 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
411 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml));
412
413 g_signal_stop_emission_by_name(imhtml, "copy-clipboard");
414 }
415
416 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data)
417 {
418 char *text;
419 guint16 c;
420 GtkIMHtml *imhtml = data;
421
422 if (selection_data->length < 0) {
423 text = gtk_clipboard_wait_for_text(clipboard);
424 } else {
425 text = g_malloc((selection_data->format / 8) * selection_data->length);
426 memcpy(text, selection_data->data, selection_data->length * (selection_data->format / 8));
427 }
428
429 memcpy (&c, text, 2);
430 if (c == 0xfeff) {
431 /* This is UCS2 */
432 char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL);
433 g_free(text);
434 text = utf8;
435 }
436 gtk_imhtml_close_tags(imhtml);
437 gtk_imhtml_append_text_with_images(imhtml, text, GTK_IMHTML_NO_NEWLINE, NULL);
438 }
439
440
441 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah)
442 {
443
444 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD);
445 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE),
446 paste_received_cb, imhtml);
447 g_signal_stop_emission_by_name(imhtml, "paste-clipboard");
448 } 387 }
449 388
450 static gboolean button_release_cb(GtkIMHtml *imhtml, GdkEventButton event, gpointer the_foibles_of_man) 389 static gboolean button_release_cb(GtkIMHtml *imhtml, GdkEventButton event, gpointer the_foibles_of_man)
451 { 390 {
452 GtkClipboard *clipboard; 391 copy_clipboard_cb(imhtml, gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY));
453 if (event.button == 1) {
454 if ((clipboard = gtk_widget_get_clipboard (GTK_WIDGET (imhtml),
455 GDK_SELECTION_PRIMARY)))
456 gtk_text_buffer_remove_selection_clipboard (imhtml->text_buffer, clipboard);
457 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY),
458 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry),
459 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get,
460 (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml));
461 }
462 return FALSE; 392 return FALSE;
463 } 393 }
464 #endif 394 #endif
465 395
466 396
476 static void 406 static void
477 gtk_imhtml_finalize (GObject *object) 407 gtk_imhtml_finalize (GObject *object)
478 { 408 {
479 GtkIMHtml *imhtml = GTK_IMHTML(object); 409 GtkIMHtml *imhtml = GTK_IMHTML(object);
480 GList *scalables; 410 GList *scalables;
481 411 #if GTK_CHECK_VERSION(2,2,0)
412 GSList *copyables;
413 #endif
414
482 g_hash_table_destroy(imhtml->smiley_data); 415 g_hash_table_destroy(imhtml->smiley_data);
483 gtk_smiley_tree_destroy(imhtml->default_smilies); 416 gtk_smiley_tree_destroy(imhtml->default_smilies);
484 gdk_cursor_unref(imhtml->hand_cursor); 417 gdk_cursor_unref(imhtml->hand_cursor);
485 gdk_cursor_unref(imhtml->arrow_cursor); 418 gdk_cursor_unref(imhtml->arrow_cursor);
486 gdk_cursor_unref(imhtml->text_cursor);
487 if(imhtml->tip_window){ 419 if(imhtml->tip_window){
488 gtk_widget_destroy(imhtml->tip_window); 420 gtk_widget_destroy(imhtml->tip_window);
489 } 421 }
490 if(imhtml->tip_timer) 422 if(imhtml->tip_timer)
491 gtk_timeout_remove(imhtml->tip_timer); 423 gtk_timeout_remove(imhtml->tip_timer);
492 424
493 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) { 425 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) {
494 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); 426 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data);
495 scale->free(scale); 427 scale->free(scale);
496 } 428 }
497 429
430 #if GTK_CHECK_VERSION(2,2,0)
431 for (copyables = imhtml->copyables; copyables; copyables = copyables->next) {
432 GtkIMHtmlCopyable *copy = GTK_IMHTML_COPYABLE(copyables->data);
433 g_free(copy->text);
434 g_free(copy);
435 }
436 #endif
498 g_list_free(imhtml->scalables); 437 g_list_free(imhtml->scalables);
499 G_OBJECT_CLASS(parent_class)->finalize (object); 438 G_OBJECT_CLASS(parent_class)->finalize (object);
500 } 439 }
501 440
502 /* Boring GTK stuff */ 441 /* Boring GTK stuff */
525 imhtml->text_buffer = gtk_text_buffer_new(NULL); 464 imhtml->text_buffer = gtk_text_buffer_new(NULL);
526 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); 465 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter);
527 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); 466 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE);
528 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); 467 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer);
529 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); 468 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR);
469 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), FALSE);
530 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); 470 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5);
531 /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/ 471 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), FALSE);
532 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ 472 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/
533 473
534 /* These tags will be used often and can be reused--we create them on init and then apply them by name 474 /* These tags will be used often and can be reused--we create them on init and then apply them by name
535 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ 475 * other tags (color, size, face, etc.) will have to be created and applied dynamically */
536 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); 476 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL);
537 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); 477 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL);
538 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); 478 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL);
539 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); 479 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL);
540 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); 480 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL);
541 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); 481 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL);
542 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); 482 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL);
543 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); 483 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL);
544 gtk_text_buffer_create_tag(imhtml->text_buffer, "LINK", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); 484
545 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ 485 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */
546 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); 486 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2);
547 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); 487 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR);
548 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM);
549 488
550 imhtml->show_smileys = TRUE; 489 imhtml->show_smileys = TRUE;
551 imhtml->show_comments = TRUE; 490 imhtml->show_comments = TRUE;
552 491
553 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, 492 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal,
556 495
557 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); 496 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL);
558 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); 497 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL);
559 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); 498 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL);
560 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); 499 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL);
561 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml);
562 #if GTK_CHECK_VERSION(2,2,0) 500 #if GTK_CHECK_VERSION(2,2,0)
563 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); 501 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL);
564 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL);
565 g_signal_connect(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml); 502 g_signal_connect(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml);
566 #endif 503 #endif
567 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); 504 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK);
568 505
569 imhtml->tip = NULL; 506 imhtml->tip = NULL;
570 imhtml->tip_timer = 0; 507 imhtml->tip_timer = 0;
571 imhtml->tip_window = NULL; 508 imhtml->tip_window = NULL;
572 509
573 imhtml->edit.bold = NULL;
574 imhtml->edit.italic = NULL;
575 imhtml->edit.underline = NULL;
576 imhtml->edit.forecolor = NULL;
577 imhtml->edit.backcolor = NULL;
578 imhtml->edit.fontface = NULL;
579 imhtml->edit.sizespan = NULL;
580 imhtml->edit.fontsize = 3;
581
582 imhtml->format_spans = NULL;
583
584 imhtml->scalables = NULL; 510 imhtml->scalables = NULL;
585 511 #if GTK_CHECK_VERSION(2,2,0)
586 gtk_imhtml_set_editable(imhtml, FALSE); 512 imhtml->copyables = NULL;
587 513 #endif
588 } 514 }
589 515
590 GtkWidget *gtk_imhtml_new(void *a, void *b) 516 GtkWidget *gtk_imhtml_new(void *a, void *b)
591 { 517 {
592 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); 518 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL));
621 gchar *url; 547 gchar *url;
622 }; 548 };
623 549
624 static void url_open(GtkWidget *w, struct url_data *data) { 550 static void url_open(GtkWidget *w, struct url_data *data) {
625 if(!data) return; 551 if(!data) return;
552
626 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); 553 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url);
627 554
628 g_object_unref(data->object); 555 g_object_unref(data->object);
629 g_free(data->url); 556 g_free(data->url);
630 g_free(data); 557 g_free(data);
631 } 558 }
632 559
641 } 568 }
642 569
643 /* The callback for an event on a link tag. */ 570 /* The callback for an event on a link tag. */
644 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) { 571 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) {
645 GdkEventButton *event_button = (GdkEventButton *) event; 572 GdkEventButton *event_button = (GdkEventButton *) event;
646 if (GTK_IMHTML(imhtml)->editable) 573
647 return FALSE;
648 if (event->type == GDK_BUTTON_RELEASE) { 574 if (event->type == GDK_BUTTON_RELEASE) {
649 if (event_button->button == 1) { 575 if (event_button->button == 1) {
650 GtkTextIter start, end; 576 GtkTextIter start, end;
651 /* we shouldn't open a URL if the user has selected something: */ 577 /* we shouldn't open a URL if the user has selected something: */
652 gtk_text_buffer_get_selection_bounds( 578 gtk_text_buffer_get_selection_bounds(
653 gtk_text_iter_get_buffer(arg2), &start, &end); 579 gtk_text_iter_get_buffer(arg2), &start, &end);
654 if(gtk_text_iter_get_offset(&start) != 580 if(gtk_text_iter_get_offset(&start) !=
672 } 598 }
673 if (GTK_IMHTML(imhtml)->tip_timer) { 599 if (GTK_IMHTML(imhtml)->tip_timer) {
674 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); 600 g_source_remove(GTK_IMHTML(imhtml)->tip_timer);
675 GTK_IMHTML(imhtml)->tip_timer = 0; 601 GTK_IMHTML(imhtml)->tip_timer = 0;
676 } 602 }
677 if (GTK_IMHTML(imhtml)->editable) 603 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor);
678 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor);
679 else
680 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor);
681 menu = gtk_menu_new(); 604 menu = gtk_menu_new();
682 605
683 /* buttons and such */ 606 /* buttons and such */
684 607
685 if (!strncmp(url, "mailto:", 7)) 608 if (!strncmp(url, "mailto:", 7))
968 gtk_imhtml_is_tag (const gchar *string, 891 gtk_imhtml_is_tag (const gchar *string,
969 gchar **tag, 892 gchar **tag,
970 gint *len, 893 gint *len,
971 gint *type) 894 gint *type)
972 { 895 {
973 char *close;
974 *type = 1; 896 *type = 1;
975 897
976 898 if (!strchr (string, '>'))
977 if (!(close = strchr (string, '>')))
978 return FALSE; 899 return FALSE;
979 900
980 VALID_TAG ("B"); 901 VALID_TAG ("B");
981 VALID_TAG ("BOLD"); 902 VALID_TAG ("BOLD");
982 VALID_TAG ("/B"); 903 VALID_TAG ("/B");
1037 958
1038 VALID_OPT_TAG ("SPAN"); 959 VALID_OPT_TAG ("SPAN");
1039 VALID_TAG ("/SPAN"); 960 VALID_TAG ("/SPAN");
1040 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ 961 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */
1041 VALID_TAG ("IMG"); 962 VALID_TAG ("IMG");
1042 VALID_OPT_TAG ("BR"); /* see comment 2 lines up */ 963
1043
1044 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { 964 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) {
1045 gchar *e = strstr (string + strlen("!--"), "-->"); 965 gchar *e = strstr (string + strlen("!--"), "-->");
1046 if (e) { 966 if (e) {
1047 *len = e - string + strlen ("-->"); 967 *len = e - string + strlen ("-->");
1048 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); 968 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->"));
1049 return TRUE; 969 return TRUE;
1050 } 970 }
1051 } 971 }
1052 972
1053 *type = -1; 973 return FALSE;
1054 *len = close - string + 1;
1055 *tag = g_strndup(string, *len - 1);
1056 return TRUE;
1057 } 974 }
1058 975
1059 static gchar* 976 static gchar*
1060 gtk_imhtml_get_html_opt (gchar *tag, 977 gtk_imhtml_get_html_opt (gchar *tag,
1061 const gchar *opt) 978 const gchar *opt)
1114 g_string_free(ret, FALSE); 1031 g_string_free(ret, FALSE);
1115 return val; 1032 return val;
1116 } 1033 }
1117 1034
1118 1035
1036
1037 #define NEW_TEXT_BIT 0
1038 #define NEW_COMMENT_BIT 2
1039 #define NEW_SCALABLE_BIT 1
1040 #define NEW_BIT(x) ws [wpos] = '\0'; \
1041 mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \
1042 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \
1043 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
1044 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \
1045 gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \
1046 if (bold) \
1047 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \
1048 if (italics) \
1049 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \
1050 if (underline) \
1051 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \
1052 if (strike) \
1053 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &siter, &iter); \
1054 if (sub) \
1055 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUB", &siter, &iter); \
1056 if (sup) \
1057 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUP", &siter, &iter); \
1058 if (pre) \
1059 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "PRE", &siter, &iter); \
1060 if (bg) { \
1061 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \
1062 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1063 } \
1064 if (fonts) { \
1065 GtkIMHtmlFontDetail *fd = fonts->data; \
1066 if (fd->fore) { \
1067 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \
1068 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1069 } \
1070 if (fd->back) { \
1071 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); \
1072 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1073 } \
1074 if (fd->face) { \
1075 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", fd->face, NULL); \
1076 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1077 } \
1078 if (fd->size) { \
1079 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "size-points", (double)POINT_SIZE(fd->size), NULL); \
1080 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1081 } \
1082 } \
1083 if (url) { \
1084 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \
1085 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), g_strdup(url)); \
1086 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1087 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); \
1088 g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \
1089 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
1090 } \
1091 wpos = 0; \
1092 ws[0] = 0; \
1093 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
1094 if (x == NEW_SCALABLE_BIT) { \
1095 GdkRectangle rect; \
1096 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); \
1097 scalable->add_to(scalable, imhtml, &iter); \
1098 scalable->scale(scalable, rect.width, rect.height); \
1099 imhtml->scalables = g_list_append(imhtml->scalables, scalable); \
1100 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
1101 } \
1102
1103
1104
1119 GString* gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, 1105 GString* gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml,
1120 const gchar *text, 1106 const gchar *text,
1121 GtkIMHtmlOptions options, 1107 GtkIMHtmlOptions options,
1122 GSList *images) 1108 GSList *images)
1123 { 1109 {
1124 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
1125 GtkTextIter insert;
1126 GdkRectangle rect;
1127 gint pos = 0; 1110 gint pos = 0;
1128 GString *str = NULL; 1111 GString *str = NULL;
1129 GtkTextIter iter; 1112 GtkTextIter iter, siter;
1130 GtkTextMark *mark; 1113 GtkTextMark *mark, *mark2;
1114 GtkTextTag *texttag;
1131 gchar *ws; 1115 gchar *ws;
1132 gchar *tag; 1116 gchar *tag;
1133 gchar *url = NULL; 1117 gchar *url = NULL;
1134 gchar *bg = NULL; 1118 gchar *bg = NULL;
1135 gint len; 1119 gint len;
1143 underline = 0, 1127 underline = 0,
1144 strike = 0, 1128 strike = 0,
1145 sub = 0, 1129 sub = 0,
1146 sup = 0, 1130 sup = 0,
1147 title = 0, 1131 title = 0,
1148 pre = 0; 1132 pre = 0;
1149 1133
1150 GSList *fonts = NULL; 1134 GSList *fonts = NULL;
1135
1136 GdkRectangle rect;
1137 int y, height;
1138
1151 GtkIMHtmlScalable *scalable = NULL; 1139 GtkIMHtmlScalable *scalable = NULL;
1152 int y, height;
1153
1154 1140
1155 g_return_val_if_fail (imhtml != NULL, NULL); 1141 g_return_val_if_fail (imhtml != NULL, NULL);
1156 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); 1142 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL);
1157 g_return_val_if_fail (text != NULL, NULL); 1143 g_return_val_if_fail (text != NULL, NULL);
1158 printf("Appending: %s\n", text); 1144
1159 c = text; 1145 c = text;
1160 len = strlen(text); 1146 len = strlen(text);
1161 ws = g_malloc(len + 1); 1147 ws = g_malloc(len + 1);
1162 ws[0] = 0; 1148 ws[0] = 0;
1163 1149
1164 if (options & GTK_IMHTML_RETURN_LOG) 1150 if (options & GTK_IMHTML_RETURN_LOG)
1165 str = g_string_new(""); 1151 str = g_string_new("");
1166 1152
1167 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &insert, ins);
1168
1169 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); 1153 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter);
1170 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE); 1154 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE);
1171 1155
1172 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); 1156 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
1173 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); 1157 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height);
1174 1158
1175 #if GTK_CHECK_VERSION(2,2,0) 1159 if(((y + height) - (rect.y + rect.height)) > height
1176 gtk_imhtml_primary_clipboard_clear(NULL, imhtml);
1177 #endif
1178 gtk_text_buffer_move_mark (imhtml->text_buffer,
1179 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"),
1180 &iter);
1181
1182 if(((y + height) - (rect.y + rect.height)) > height
1183 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ 1160 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){
1184 options |= GTK_IMHTML_NO_SCROLL; 1161 options |= GTK_IMHTML_NO_SCROLL;
1185 } 1162 }
1186 1163
1187 while (pos < len) { 1164 while (pos < len) {
1188 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { 1165 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) {
1189 c++; 1166 c++;
1190 pos++; 1167 pos++;
1191 ws[wpos] = '\0'; 1168 switch (type)
1192 switch (type)
1193 { 1169 {
1194 case 1: /* B */ 1170 case 1: /* B */
1195 case 2: /* BOLD */ 1171 case 2: /* BOLD */
1196 case 54: /* STRONG */ 1172 case 54: /* STRONG */
1197 if (url) 1173 NEW_BIT (NEW_TEXT_BIT);
1198 gtk_imhtml_insert_link(imhtml, url, ws);
1199 else
1200 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1201 if (bold == 0)
1202 gtk_imhtml_toggle_bold(imhtml);
1203 bold++; 1174 bold++;
1204 ws[0] = '\0'; wpos = 0;
1205 break; 1175 break;
1206 case 3: /* /B */ 1176 case 3: /* /B */
1207 case 4: /* /BOLD */ 1177 case 4: /* /BOLD */
1208 case 55: /* /STRONG */ 1178 case 55: /* /STRONG */
1209 if (url) 1179 NEW_BIT (NEW_TEXT_BIT);
1210 gtk_imhtml_insert_link(imhtml, url, ws);
1211 else
1212 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1213 ws[0] = '\0'; wpos = 0;
1214
1215 if (bold) 1180 if (bold)
1216 bold--; 1181 bold--;
1217 if (bold == 0)
1218 gtk_imhtml_toggle_bold(imhtml);
1219 break; 1182 break;
1220 case 5: /* I */ 1183 case 5: /* I */
1221 case 6: /* ITALIC */ 1184 case 6: /* ITALIC */
1222 case 52: /* EM */ 1185 case 52: /* EM */
1223 if (url) 1186 NEW_BIT (NEW_TEXT_BIT);
1224 gtk_imhtml_insert_link(imhtml, url, ws);
1225 else
1226 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1227 ws[0] = '\0'; wpos = 0;
1228 if (italics == 0)
1229 gtk_imhtml_toggle_italic(imhtml);
1230 italics++; 1187 italics++;
1231 break; 1188 break;
1232 case 7: /* /I */ 1189 case 7: /* /I */
1233 case 8: /* /ITALIC */ 1190 case 8: /* /ITALIC */
1234 case 53: /* /EM */ 1191 case 53: /* /EM */
1235 if (url) 1192 NEW_BIT (NEW_TEXT_BIT);
1236 gtk_imhtml_insert_link(imhtml, url, ws);
1237 else
1238 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1239 ws[0] = '\0'; wpos = 0;
1240 if (italics) 1193 if (italics)
1241 italics--; 1194 italics--;
1242 if (italics == 0)
1243 gtk_imhtml_toggle_italic(imhtml);
1244 break; 1195 break;
1245 case 9: /* U */ 1196 case 9: /* U */
1246 case 10: /* UNDERLINE */ 1197 case 10: /* UNDERLINE */
1247 if (url) 1198 NEW_BIT (NEW_TEXT_BIT);
1248 gtk_imhtml_insert_link(imhtml, url, ws);
1249 else
1250 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1251 ws[0] = '\0'; wpos = 0;
1252 if (underline == 0)
1253 gtk_imhtml_toggle_underline(imhtml);
1254 underline++; 1199 underline++;
1255 break; 1200 break;
1256 case 11: /* /U */ 1201 case 11: /* /U */
1257 case 12: /* /UNDERLINE */ 1202 case 12: /* /UNDERLINE */
1258 if (url) 1203 NEW_BIT (NEW_TEXT_BIT);
1259 gtk_imhtml_insert_link(imhtml, url, ws);
1260 else
1261 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1262 ws[0] = '\0'; wpos = 0;
1263 if (underline) 1204 if (underline)
1264 underline--; 1205 underline--;
1265 if (underline == 0)
1266 gtk_imhtml_toggle_underline(imhtml);
1267 break; 1206 break;
1268 case 13: /* S */ 1207 case 13: /* S */
1269 case 14: /* STRIKE */ 1208 case 14: /* STRIKE */
1270 //NEW_BIT (NEW_TEXT_BIT); 1209 NEW_BIT (NEW_TEXT_BIT);
1271 strike++; 1210 strike++;
1272 break; 1211 break;
1273 case 15: /* /S */ 1212 case 15: /* /S */
1274 case 16: /* /STRIKE */ 1213 case 16: /* /STRIKE */
1275 //NEW_BIT (NEW_TEXT_BIT); 1214 NEW_BIT (NEW_TEXT_BIT);
1276 if (strike) 1215 if (strike)
1277 strike--; 1216 strike--;
1278 break; 1217 break;
1279 case 17: /* SUB */ 1218 case 17: /* SUB */
1280 //NEW_BIT (NEW_TEXT_BIT); 1219 NEW_BIT (NEW_TEXT_BIT);
1281 sub++; 1220 sub++;
1282 break; 1221 break;
1283 case 18: /* /SUB */ 1222 case 18: /* /SUB */
1284 //NEW_BIT (NEW_TEXT_BIT); 1223 NEW_BIT (NEW_TEXT_BIT);
1285 if (sub) 1224 if (sub)
1286 sub--; 1225 sub--;
1287 break; 1226 break;
1288 case 19: /* SUP */ 1227 case 19: /* SUP */
1289 //NEW_BIT (NEW_TEXT_BIT); 1228 NEW_BIT (NEW_TEXT_BIT);
1290 sup++; 1229 sup++;
1291 break; 1230 break;
1292 case 20: /* /SUP */ 1231 case 20: /* /SUP */
1293 //NEW_BIT (NEW_TEXT_BIT); 1232 NEW_BIT (NEW_TEXT_BIT);
1294 if (sup) 1233 if (sup)
1295 sup--; 1234 sup--;
1296 break; 1235 break;
1297 case 21: /* PRE */ 1236 case 21: /* PRE */
1298 //NEW_BIT (NEW_TEXT_BIT); 1237 NEW_BIT (NEW_TEXT_BIT);
1299 pre++; 1238 pre++;
1300 break; 1239 break;
1301 case 22: /* /PRE */ 1240 case 22: /* /PRE */
1302 //NEW_BIT (NEW_TEXT_BIT); 1241 NEW_BIT (NEW_TEXT_BIT);
1303 if (pre) 1242 if (pre)
1304 pre--; 1243 pre--;
1305 break; 1244 break;
1306 case 23: /* TITLE */ 1245 case 23: /* TITLE */
1307 //NEW_BIT (NEW_TEXT_BIT); 1246 NEW_BIT (NEW_TEXT_BIT);
1308 title++; 1247 title++;
1309 break; 1248 break;
1310 case 24: /* /TITLE */ 1249 case 24: /* /TITLE */
1311 if (title) { 1250 if (title) {
1312 if (options & GTK_IMHTML_NO_TITLE) { 1251 if (options & GTK_IMHTML_NO_TITLE) {
1316 title--; 1255 title--;
1317 } 1256 }
1318 break; 1257 break;
1319 case 25: /* BR */ 1258 case 25: /* BR */
1320 case 58: /* BR/ */ 1259 case 58: /* BR/ */
1321 case 60: /* BR (opt) */
1322 ws[wpos] = '\n'; 1260 ws[wpos] = '\n';
1323 wpos++; 1261 wpos++;
1324 //NEW_BIT (NEW_TEXT_BIT); 1262 NEW_BIT (NEW_TEXT_BIT);
1325 break; 1263 break;
1326 case 26: /* HR */ 1264 case 26: /* HR */
1327 case 42: /* HR (opt) */ 1265 case 42: /* HR (opt) */
1328 ws[wpos++] = '\n'; 1266 ws[wpos++] = '\n';
1329 if (url)
1330 gtk_imhtml_insert_link(imhtml, url, ws);
1331 else
1332 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1333 scalable = gtk_imhtml_hr_new(); 1267 scalable = gtk_imhtml_hr_new();
1334 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); 1268 NEW_BIT(NEW_SCALABLE_BIT);
1335 scalable->add_to(scalable, imhtml, &iter);
1336 scalable->scale(scalable, rect.width, rect.height);
1337 imhtml->scalables = g_list_append(imhtml->scalables, scalable);
1338 ws[0] = '\0'; wpos = 0;
1339 ws[wpos++] = '\n'; 1269 ws[wpos++] = '\n';
1340
1341 break; 1270 break;
1342 case 27: /* /FONT */ 1271 case 27: /* /FONT */
1343 if (fonts) { 1272 if (fonts) {
1344 GtkIMHtmlFontDetail *font = fonts->data; 1273 GtkIMHtmlFontDetail *font = fonts->data;
1345 if (url) 1274 NEW_BIT (NEW_TEXT_BIT);
1346 gtk_imhtml_insert_link(imhtml, url, ws);
1347 else
1348 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1349 ws[0] = '\0'; wpos = 0;
1350 //NEW_BIT (NEW_TEXT_BIT);
1351 fonts = g_slist_remove (fonts, font); 1275 fonts = g_slist_remove (fonts, font);
1352 if (font->face) { 1276 if (font->face)
1353 gtk_imhtml_toggle_fontface(imhtml, NULL);
1354 g_free (font->face); 1277 g_free (font->face);
1355 } 1278 if (font->fore)
1356 if (font->fore) {
1357 gtk_imhtml_toggle_forecolor(imhtml, NULL);
1358 g_free (font->fore); 1279 g_free (font->fore);
1359 } 1280 if (font->back)
1360 if (font->back) {
1361 gtk_imhtml_toggle_backcolor(imhtml, NULL);
1362 g_free (font->back); 1281 g_free (font->back);
1363 }
1364 if (font->sml) 1282 if (font->sml)
1365 g_free (font->sml); 1283 g_free (font->sml);
1366 g_free (font); 1284 g_free (font);
1367 } 1285 }
1368 break; 1286 break;
1369 case 28: /* /A */ 1287 case 28: /* /A */
1370 if (url) { 1288 if (url) {
1371 gtk_imhtml_insert_link(imhtml, url, ws); 1289 NEW_BIT(NEW_TEXT_BIT);
1372 g_free(url); 1290 g_free(url);
1373 ws[0] = '\0'; wpos = 0;
1374 url = NULL; 1291 url = NULL;
1375 ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 1292 break;
1376 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
1377 } 1293 }
1378 break;
1379
1380 case 29: /* P */ 1294 case 29: /* P */
1381 case 30: /* /P */ 1295 case 30: /* /P */
1382 case 31: /* H3 */ 1296 case 31: /* H3 */
1383 case 32: /* /H3 */ 1297 case 32: /* /H3 */
1384 case 33: /* HTML */ 1298 case 33: /* HTML */
1400 face = gtk_imhtml_get_html_opt (tag, "FACE="); 1314 face = gtk_imhtml_get_html_opt (tag, "FACE=");
1401 size = gtk_imhtml_get_html_opt (tag, "SIZE="); 1315 size = gtk_imhtml_get_html_opt (tag, "SIZE=");
1402 sml = gtk_imhtml_get_html_opt (tag, "SML="); 1316 sml = gtk_imhtml_get_html_opt (tag, "SML=");
1403 if (!(color || back || face || size || sml)) 1317 if (!(color || back || face || size || sml))
1404 break; 1318 break;
1405 1319
1406 if (url) 1320 NEW_BIT (NEW_TEXT_BIT);
1407 gtk_imhtml_insert_link(imhtml, url, ws); 1321
1408 else
1409 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1410 ws[0] = '\0'; wpos = 0;
1411
1412 font = g_new0 (GtkIMHtmlFontDetail, 1); 1322 font = g_new0 (GtkIMHtmlFontDetail, 1);
1413 if (fonts) 1323 if (fonts)
1414 oldfont = fonts->data; 1324 oldfont = fonts->data;
1415 1325
1416 if (color && !(options & GTK_IMHTML_NO_COLOURS)) 1326 if (color && !(options & GTK_IMHTML_NO_COLOURS))
1417 font->fore = color; 1327 font->fore = color;
1418 else if (oldfont && oldfont->fore) 1328 else if (oldfont && oldfont->fore)
1419 font->fore = g_strdup(oldfont->fore); 1329 font->fore = g_strdup(oldfont->fore);
1420 if (font->fore)
1421 gtk_imhtml_toggle_forecolor(imhtml, font->fore);
1422 1330
1423 if (back && !(options & GTK_IMHTML_NO_COLOURS)) 1331 if (back && !(options & GTK_IMHTML_NO_COLOURS))
1424 font->back = back; 1332 font->back = back;
1425 else if (oldfont && oldfont->back) 1333 else if (oldfont && oldfont->back)
1426 font->back = g_strdup(oldfont->back); 1334 font->back = g_strdup(oldfont->back);
1427 if (font->back) 1335
1428 gtk_imhtml_toggle_backcolor(imhtml, font->back);
1429
1430 if (face && !(options & GTK_IMHTML_NO_FONTS)) 1336 if (face && !(options & GTK_IMHTML_NO_FONTS))
1431 font->face = face; 1337 font->face = face;
1432 else if (oldfont && oldfont->face) 1338 else if (oldfont && oldfont->face)
1433 font->face = g_strdup(oldfont->face); 1339 font->face = g_strdup(oldfont->face);
1434 if (font->face) 1340 if (font->face && (atoi(font->face) > 100)) {
1435 gtk_imhtml_toggle_fontface(imhtml, font->face); 1341 g_free(font->face);
1342 font->face = g_strdup("100");
1343 }
1436 1344
1437 if (sml) 1345 if (sml)
1438 font->sml = sml; 1346 font->sml = sml;
1439 else if (oldfont && oldfont->sml) 1347 else if (oldfont && oldfont->sml)
1440 font->sml = g_strdup(oldfont->sml); 1348 font->sml = g_strdup(oldfont->sml);
1446 } else if (*size == '-') { 1354 } else if (*size == '-') {
1447 sscanf (size + 1, "%hd", &font->size); 1355 sscanf (size + 1, "%hd", &font->size);
1448 font->size = MAX (0, 3 - font->size); 1356 font->size = MAX (0, 3 - font->size);
1449 } else if (isdigit (*size)) { 1357 } else if (isdigit (*size)) {
1450 sscanf (size, "%hd", &font->size); 1358 sscanf (size, "%hd", &font->size);
1451 } 1359 }
1452 if (font->size > 100) 1360 if (font->size > 100)
1453 font->size = 100; 1361 font->size = 100;
1454 } else if (oldfont) 1362 } else if (oldfont)
1455 font->size = oldfont->size; 1363 font->size = oldfont->size;
1456 // gtk_imhtml_font_set_size(imhtml, font->size);
1457 g_free(size); 1364 g_free(size);
1458 fonts = g_slist_prepend (fonts, font); 1365 fonts = g_slist_prepend (fonts, font);
1459 } 1366 }
1460 break; 1367 break;
1461 case 44: /* BODY (opt) */ 1368 case 44: /* BODY (opt) */
1462 if (!(options & GTK_IMHTML_NO_COLOURS)) { 1369 if (!(options & GTK_IMHTML_NO_COLOURS)) {
1463 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); 1370 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR=");
1464 if (bgcolor) { 1371 if (bgcolor) {
1465 if (url) 1372 NEW_BIT(NEW_TEXT_BIT);
1466 gtk_imhtml_insert_link(imhtml, url, ws);
1467 else
1468 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1469 ws[0] = '\0'; wpos = 0;
1470 // NEW_BIT(NEW_TEXT_BIT);
1471 if (bg) 1373 if (bg)
1472 g_free(bg); 1374 g_free(bg);
1473 bg = bgcolor; 1375 bg = bgcolor;
1474 gtk_imhtml_toggle_backcolor(imhtml, bg);
1475 } 1376 }
1476 } 1377 }
1477 break; 1378 break;
1478 case 45: /* A (opt) */ 1379 case 45: /* A (opt) */
1479 { 1380 {
1480 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); 1381 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF=");
1481 if (href) { 1382 if (href) {
1482 if (url) { 1383 NEW_BIT (NEW_TEXT_BIT);
1483 gtk_imhtml_insert_link(imhtml, url, ws); 1384 if (url)
1484 g_free(url); 1385 g_free (url);
1485 } else
1486 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1487 ws[0] = '\0'; wpos = 0;
1488 url = href; 1386 url = href;
1489 } 1387 }
1490 } 1388 }
1491 break; 1389 break;
1492 case 46: /* IMG (opt) */ 1390 case 46: /* IMG (opt) */
1505 GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON, 1403 GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON,
1506 "gtkimhtml-missing-image"); 1404 "gtkimhtml-missing-image");
1507 } 1405 }
1508 1406
1509 scalable = gtk_imhtml_image_new(img, filename); 1407 scalable = gtk_imhtml_image_new(img, filename);
1510 //NEW_BIT(NEW_SCALABLE_BIT); 1408 NEW_BIT(NEW_SCALABLE_BIT);
1511 g_object_unref(G_OBJECT(img)); 1409 g_object_unref(G_OBJECT(img));
1512 } 1410 }
1513 case 47: /* P (opt) */ 1411 case 47: /* P (opt) */
1514 case 48: /* H3 (opt) */ 1412 case 48: /* H3 (opt) */
1515 case 49: /* HTML (opt) */ 1413 case 49: /* HTML (opt) */
1516 case 50: /* CITE */ 1414 case 50: /* CITE */
1517 case 51: /* /CITE */ 1415 case 51: /* /CITE */
1518 case 56: /* SPAN */ 1416 case 56: /* SPAN */
1519 case 57: /* /SPAN */ 1417 case 57: /* /SPAN */
1520 break; 1418 break;
1521 case 61: /* comment */ 1419 case 60: /* comment */
1522 //NEW_BIT (NEW_TEXT_BIT); 1420 NEW_BIT (NEW_TEXT_BIT);
1523 if (imhtml->show_comments) 1421 if (imhtml->show_comments)
1524 wpos = g_snprintf (ws, len, "%s", tag); 1422 wpos = g_snprintf (ws, len, "%s", tag);
1525 // NEW_BIT (NEW_COMMENT_BIT); 1423 NEW_BIT (NEW_COMMENT_BIT);
1526 break; 1424 break;
1527 default: 1425 default:
1528 break; 1426 break;
1529 } 1427 }
1530 c += tlen; 1428 c += tlen;
1539 pos += tlen; 1437 pos += tlen;
1540 } else if (*c == '\n') { 1438 } else if (*c == '\n') {
1541 if (!(options & GTK_IMHTML_NO_NEWLINE)) { 1439 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
1542 ws[wpos] = '\n'; 1440 ws[wpos] = '\n';
1543 wpos++; 1441 wpos++;
1544 if (url) 1442 NEW_BIT (NEW_TEXT_BIT);
1545 gtk_imhtml_insert_link(imhtml, url, ws);
1546 else
1547 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1548 ws[0] = '\0';
1549 wpos = 0;
1550 //NEW_BIT (NEW_TEXT_BIT);
1551 } 1443 }
1552 c++; 1444 c++;
1553 pos++; 1445 pos++;
1554 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { 1446 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) {
1447 GtkTextChildAnchor *anchor;
1448 GtkWidget *icon = NULL;
1449 GtkTextIter copy;
1450 GdkPixbufAnimation *annipixbuf = NULL;
1451 GdkPixbuf *pixbuf = NULL;
1555 GtkIMHtmlFontDetail *fd; 1452 GtkIMHtmlFontDetail *fd;
1556 1453
1557 gchar *sml = NULL; 1454 gchar *sml = NULL;
1558 if (fonts) { 1455 if (fonts) {
1559 fd = fonts->data; 1456 fd = fonts->data;
1560 sml = fd->sml; 1457 sml = fd->sml;
1561 } 1458 }
1562 if (url) 1459 NEW_BIT (NEW_TEXT_BIT);
1563 gtk_imhtml_insert_link(imhtml, url, ws); 1460 wpos = g_snprintf (ws, smilelen + 1, "%s", c);
1564 else { 1461 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter);
1565 printf("Inserting %s\n", ws); 1462 annipixbuf = gtk_smiley_tree_image(imhtml, sml, ws);
1566 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); 1463 if(annipixbuf) {
1464 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) {
1465 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf);
1466 if(pixbuf)
1467 icon = gtk_image_new_from_pixbuf(pixbuf);
1468 } else {
1469 icon = gtk_image_new_from_animation(annipixbuf);
1470 }
1567 } 1471 }
1568 wpos = g_snprintf (ws, smilelen + 1, "%s", c); 1472
1569 gtk_imhtml_insert_smiley(imhtml, sml, ws); 1473 if (icon) {
1570 1474 gtk_widget_show(icon);
1571 ins = gtk_text_buffer_get_insert(imhtml->text_buffer); 1475 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor);
1572 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); 1476 #if GTK_CHECK_VERSION(2,2,0)
1573 1477 gtk_imhtml_copyable_new(imhtml,
1478 gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE),
1479 ws);
1480 #endif
1481 }
1482
1483 copy = iter;
1484 gtk_text_iter_backward_char(&copy);
1485 if (bg) {
1486 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL);
1487 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &iter, &copy);
1488 }
1489 if (fonts) {
1490 GtkIMHtmlFontDetail *fd = fonts->data;
1491 if (fd->back) {
1492 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL);
1493 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &iter, &copy);
1494 }
1495 }
1574 c += smilelen; 1496 c += smilelen;
1575 pos += smilelen; 1497 pos += smilelen;
1576 wpos = 0; 1498 wpos = 0;
1577 ws[0] = 0; 1499 ws[0] = 0;
1578 } else if (*c) { 1500 } else if (*c) {
1579 ws [wpos++] = *c++; 1501 ws [wpos++] = *c++;
1580 pos++; 1502 pos++;
1581 } else { 1503 } else {
1582 break; 1504 break;
1583 } 1505 }
1584 } 1506 }
1585 if (url) 1507
1586 gtk_imhtml_insert_link(imhtml, url, ws); 1508 NEW_BIT(NEW_TEXT_BIT);
1587 else
1588 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos);
1589 ws[0] = '\0'; wpos = 0;
1590
1591 //NEW_BIT(NEW_TEXT_BIT);
1592 if (url) { 1509 if (url) {
1593 g_free (url); 1510 g_free (url);
1594 if (str) 1511 if (str)
1595 str = g_string_append (str, "</A>"); 1512 str = g_string_append (str, "</A>");
1596 } 1513 }
1597 1514
1598 while (fonts) { 1515 while (fonts) {
1599 GtkIMHtmlFontDetail *font = fonts->data; 1516 GtkIMHtmlFontDetail *font = fonts->data;
1600 fonts = g_slist_remove (fonts, font); 1517 fonts = g_slist_remove (fonts, font);
1601 if (font->face) 1518 if (font->face)
1602 g_free (font->face); 1519 g_free (font->face);
1646 } 1563 }
1647 } 1564 }
1648 g_free (ws); 1565 g_free (ws);
1649 if(bg) 1566 if(bg)
1650 g_free(bg); 1567 g_free(bg);
1651 gtk_imhtml_close_tags(imhtml);
1652 if (!(options & GTK_IMHTML_NO_SCROLL)) 1568 if (!(options & GTK_IMHTML_NO_SCROLL))
1653 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, 1569 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark,
1654 0, TRUE, 0.0, 1.0); 1570 0, TRUE, 0.0, 1.0);
1655 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); 1571 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark);
1656 gtk_text_buffer_move_mark (imhtml->text_buffer,
1657 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"),
1658 &iter);
1659 return str; 1572 return str;
1660 } 1573 }
1661 1574
1662 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) 1575 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml)
1663 { 1576 {
1681 1594
1682 void 1595 void
1683 gtk_imhtml_clear (GtkIMHtml *imhtml) 1596 gtk_imhtml_clear (GtkIMHtml *imhtml)
1684 { 1597 {
1685 GtkTextIter start, end; 1598 GtkTextIter start, end;
1686 GList *del = imhtml->format_spans; 1599
1687
1688 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); 1600 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
1689 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); 1601 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
1690 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); 1602 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end);
1691
1692 while (imhtml->format_spans) {
1693 GtkIMHtmlFormatSpan *span = imhtml->format_spans->data;
1694 if (span->start_tag)
1695 g_free(span->start_tag);
1696 if (span->end_tag)
1697 g_free(span->end_tag);
1698 g_free(span);
1699 imhtml->format_spans = imhtml->format_spans->next;
1700 }
1701 g_list_free(del);
1702
1703 del = imhtml->scalables;
1704 while (del) {
1705 GtkIMHtmlScalable *scale = del->data;
1706 scale->free(scale);
1707 del = del->next;
1708 }
1709 g_list_free(imhtml->scalables);
1710 imhtml->scalables = NULL;
1711
1712 imhtml->edit.bold = NULL;
1713 imhtml->edit.italic = NULL;
1714 imhtml->edit.underline = NULL;
1715 imhtml->edit.fontface = NULL;
1716 imhtml->edit.forecolor = NULL;
1717 imhtml->edit.backcolor = NULL;
1718 imhtml->edit.sizespan = NULL;
1719 imhtml->edit.fontsize = 3;
1720 } 1603 }
1721 1604
1722 void gtk_imhtml_page_up (GtkIMHtml *imhtml) 1605 void gtk_imhtml_page_up (GtkIMHtml *imhtml)
1723 { 1606 {
1724 GdkRectangle rect; 1607 GdkRectangle rect;
1726 1609
1727 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); 1610 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
1728 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, 1611 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x,
1729 rect.y - rect.height); 1612 rect.y - rect.height);
1730 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); 1613 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0);
1731 1614
1732 } 1615 }
1733 void gtk_imhtml_page_down (GtkIMHtml *imhtml) 1616 void gtk_imhtml_page_down (GtkIMHtml *imhtml)
1734 { 1617 {
1735 GdkRectangle rect; 1618 GdkRectangle rect;
1736 GtkTextIter iter; 1619 GtkTextIter iter;
1884 G_CALLBACK(write_img_to_file), sel); 1767 G_CALLBACK(write_img_to_file), sel);
1885 1768
1886 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", 1769 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked",
1887 G_CALLBACK(gtk_widget_destroy), sel); 1770 G_CALLBACK(gtk_widget_destroy), sel);
1888 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", 1771 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked",
1889 G_CALLBACK(gtk_widget_destroy), sel); 1772 G_CALLBACK(gtk_widget_destroy), sel);
1890 1773
1891 gtk_widget_show(sel); 1774 gtk_widget_show(sel);
1892 } 1775 }
1893 1776
1894 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) 1777 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image)
1970 1853
1971 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) 1854 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter)
1972 { 1855 {
1973 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; 1856 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale;
1974 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); 1857 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter);
1975 g_object_set_data(G_OBJECT(anchor), "text_tag", "<hr>"); 1858
1976 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); 1859 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor);
1977 } 1860 }
1978 1861
1979 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) 1862 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale)
1980 { 1863 {
1986 GtkTextIter iter, start, end; 1869 GtkTextIter iter, start, end;
1987 gboolean new_search = TRUE; 1870 gboolean new_search = TRUE;
1988 1871
1989 g_return_val_if_fail(imhtml != NULL, FALSE); 1872 g_return_val_if_fail(imhtml != NULL, FALSE);
1990 g_return_val_if_fail(text != NULL, FALSE); 1873 g_return_val_if_fail(text != NULL, FALSE);
1991 1874
1992 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) 1875 if (imhtml->search_string && !strcmp(text, imhtml->search_string))
1993 new_search = FALSE; 1876 new_search = FALSE;
1994 1877
1878
1995 if (new_search) { 1879 if (new_search) {
1996 gtk_imhtml_search_clear(imhtml); 1880 gtk_imhtml_search_clear(imhtml);
1997 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); 1881 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter);
1998 } else { 1882 } else {
1999 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, 1883 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter,
2000 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); 1884 gtk_text_buffer_get_mark(imhtml->text_buffer, "search"));
2001 } 1885 }
2002 imhtml->search_string = g_strdup(text); 1886 imhtml->search_string = g_strdup(text);
2003 1887
2004 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, 1888 if (gtk_source_iter_forward_search(&iter, imhtml->search_string,
2005 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, 1889 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE,
2007 1891
2008 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); 1892 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0);
2009 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); 1893 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE);
2010 if (new_search) { 1894 if (new_search) {
2011 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); 1895 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end);
2012 do 1896 do
2013 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); 1897 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end);
2014 while (gtk_source_iter_forward_search(&end, imhtml->search_string, 1898 while (gtk_source_iter_forward_search(&end, imhtml->search_string,
2015 GTK_SOURCE_SEARCH_VISIBLE_ONLY | 1899 GTK_SOURCE_SEARCH_VISIBLE_ONLY |
2016 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, 1900 GTK_SOURCE_SEARCH_CASE_INSENSITIVE,
2017 &start, &end, NULL)); 1901 &start, &end, NULL));
2018 } 1902 }
2019 return TRUE; 1903 return TRUE;
2020 } 1904 }
2021
2022 gtk_imhtml_search_clear(imhtml);
2023
2024 return FALSE; 1905 return FALSE;
2025 } 1906 }
2026 1907
2027 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) 1908 void gtk_imhtml_search_clear(GtkIMHtml *imhtml)
2028 { 1909 {
2029 GtkTextIter start, end; 1910 GtkTextIter start, end;
2030 1911
2031 g_return_if_fail(imhtml != NULL); 1912 g_return_if_fail(imhtml != NULL);
2032 1913
2033 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); 1914 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
2034 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); 1915 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
2035 1916
2036 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); 1917 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end);
2037 if (imhtml->search_string) 1918 if (imhtml->search_string)
2038 g_free(imhtml->search_string); 1919 g_free(imhtml->search_string);
2039 imhtml->search_string = NULL; 1920 imhtml->search_string = NULL;
2040 } 1921 }
2041
2042 /* Editable stuff */
2043 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml)
2044 {
2045 GtkIMHtmlFormatSpan *span = NULL;
2046 GtkTextIter end;
2047
2048 gtk_text_iter_forward_chars(iter, len);
2049 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
2050 gtk_text_iter_forward_char(&end);
2051
2052 if (!gtk_text_iter_equal(&end, iter))
2053 return;
2054
2055
2056 if ((span = imhtml->edit.bold)) {
2057 GtkTextIter bold;
2058 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &bold, span->start);
2059 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &bold, iter);
2060 }
2061
2062 if ((span = imhtml->edit.italic)) {
2063 GtkTextIter italic;
2064 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &italic, span->start);
2065 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &italic,
2066 iter);
2067 }
2068
2069 if ((span = imhtml->edit.underline)) {
2070 GtkTextIter underline;
2071 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &underline, span->start);
2072 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &underline,
2073 iter);
2074 }
2075
2076 if ((span = imhtml->edit.forecolor)) {
2077 GtkTextIter fore;
2078 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &fore, span->start);
2079 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &fore, iter);
2080 }
2081
2082 if ((span = imhtml->edit.backcolor)) {
2083 GtkTextIter back;
2084 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &back, span->start);
2085 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &back, iter);
2086 }
2087
2088 if ((span = imhtml->edit.fontface)) {
2089 GtkTextIter face;
2090 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &face, span->start);
2091 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &face, iter);
2092 }
2093
2094 if ((span = imhtml->edit.sizespan)) {
2095 GtkTextIter size;
2096 /* We create the tags here so that one can grow font or shrink font several times
2097 * in a row without creating unnecessary tags */
2098 if (span->tag == NULL) {
2099 span->tag = gtk_text_buffer_create_tag
2100 (imhtml->text_buffer, NULL, "size-points", (double)_point_sizes [imhtml->edit.fontsize-1], NULL);
2101 span->start_tag = g_strdup_printf("<font size=\"%d\">", imhtml->edit.fontsize);
2102 span->end_tag = g_strdup("</font>");
2103 }
2104 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &size, span->start);
2105 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &size, iter);
2106 }
2107 }
2108
2109 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable)
2110 {
2111 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable);
2112 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable);
2113 imhtml->editable = editable;
2114 }
2115
2116 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml)
2117 {
2118 return imhtml->editable;
2119 }
2120
2121 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml)
2122 {
2123 GtkIMHtmlFormatSpan *span;
2124 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2125 GtkTextIter iter;
2126 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2127 if (!imhtml->edit.bold) {
2128 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2129 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2130 span->start_tag = g_strdup("<b>");
2131 span->end = NULL;
2132 span->end_tag = g_strdup("</b>");
2133 span->buffer = imhtml->text_buffer;
2134 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "BOLD");
2135 imhtml->edit.bold = span;
2136 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2137 } else {
2138 span = imhtml->edit.bold;
2139 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2140 imhtml->edit.bold = NULL;
2141 }
2142 return imhtml->edit.bold != NULL;
2143 }
2144
2145 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml)
2146 {
2147 GtkIMHtmlFormatSpan *span;
2148 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2149 GtkTextIter iter;
2150 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2151 if (!imhtml->edit.italic) {
2152 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2153 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2154 span->start_tag = g_strdup("<i>");
2155 span->end = NULL;
2156 span->end_tag = g_strdup("</i>");
2157 span->buffer = imhtml->text_buffer;
2158 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "ITALIC");
2159 imhtml->edit.italic = span;
2160 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2161 } else {
2162 span = imhtml->edit.italic;
2163 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2164 imhtml->edit.italic = NULL;
2165 }
2166 return imhtml->edit.italic != NULL;
2167 }
2168
2169 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml)
2170 {
2171 GtkIMHtmlFormatSpan *span;
2172 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2173 GtkTextIter iter;
2174 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2175 if (!imhtml->edit.underline) {
2176 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2177 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2178 span->start_tag = g_strdup("<u>");
2179 span->end = NULL;
2180 span->end_tag = g_strdup("</u>");
2181 span->buffer = imhtml->text_buffer;
2182 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "UNDERLINE");
2183 imhtml->edit.underline = span;
2184 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2185 } else {
2186 span = imhtml->edit.underline;
2187 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2188 imhtml->edit.underline = NULL;
2189 }
2190 return imhtml->edit.underline != NULL;
2191 }
2192
2193 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size)
2194 {
2195 GtkIMHtmlFormatSpan *span;
2196 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2197 GtkTextIter iter;
2198 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2199
2200 imhtml->edit.fontsize = size;
2201
2202 if (imhtml->edit.sizespan) {
2203 GtkTextIter iter2;
2204 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start);
2205 if (gtk_text_iter_equal(&iter2, &iter))
2206 return;
2207 span = imhtml->edit.sizespan;
2208 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2209 }
2210 if (size != -1) {
2211 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2212 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2213 span->end = NULL;
2214 span->buffer = imhtml->text_buffer;
2215 span->tag = NULL;
2216 imhtml->edit.sizespan = span;
2217 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2218 }
2219 }
2220
2221 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml)
2222 {
2223 GtkIMHtmlFormatSpan *span;
2224 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2225 GtkTextIter iter;
2226 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2227 if (imhtml->edit.fontsize == 1)
2228 return;
2229
2230 imhtml->edit.fontsize--;
2231
2232 if (imhtml->edit.sizespan) {
2233 GtkTextIter iter2;
2234 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start);
2235 if (gtk_text_iter_equal(&iter2, &iter))
2236 return;
2237 span = imhtml->edit.sizespan;
2238 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2239 }
2240
2241 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2242 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2243 span->end = NULL;
2244 span->buffer = imhtml->text_buffer;
2245 span->tag = NULL;
2246 imhtml->edit.sizespan = span;
2247 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2248 }
2249
2250 void gtk_imhtml_font_grow(GtkIMHtml *imhtml)
2251 {
2252 GtkIMHtmlFormatSpan *span;
2253 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2254 GtkTextIter iter;
2255 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2256 if (imhtml->edit.fontsize == MAX_FONT_SIZE)
2257 return;
2258
2259 imhtml->edit.fontsize++;
2260
2261 if (imhtml->edit.sizespan) {
2262 GtkTextIter iter2;
2263 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start);
2264 if (gtk_text_iter_equal(&iter2, &iter))
2265 return;
2266 span = imhtml->edit.sizespan;
2267 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2268 }
2269
2270 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2271 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2272 span->end = NULL;
2273 span->tag = NULL;
2274 span->buffer = imhtml->text_buffer;
2275 imhtml->edit.sizespan = span;
2276 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2277 }
2278
2279 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color)
2280 {
2281 GtkIMHtmlFormatSpan *span;
2282 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2283 GtkTextIter iter;
2284 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2285 if (!imhtml->edit.forecolor) {
2286 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2287 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2288 span->start_tag = g_strdup_printf("<font color=\"%s\">", color);
2289 span->end = NULL;
2290 span->end_tag = g_strdup("</font>");
2291 span->buffer = imhtml->text_buffer;
2292 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", color, NULL);
2293 imhtml->edit.forecolor = span;
2294 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2295 } else {
2296 span = imhtml->edit.forecolor;
2297 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2298 imhtml->edit.forecolor = NULL;
2299 }
2300
2301
2302 return imhtml->edit.forecolor != NULL;
2303 }
2304
2305 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color)
2306 {
2307 GtkIMHtmlFormatSpan *span;
2308 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2309 GtkTextIter iter;
2310 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2311 if (!imhtml->edit.backcolor) {
2312 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2313 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2314 span->start_tag = g_strdup_printf("<font back=\"%s\">", color);
2315 span->end = NULL;
2316 span->end_tag = g_strdup("</font>");
2317 span->buffer = imhtml->text_buffer;
2318 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", color, NULL);
2319 imhtml->edit.backcolor = span;
2320 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2321 } else {
2322 span = imhtml->edit.backcolor;
2323 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2324 imhtml->edit.backcolor = NULL;
2325 }
2326 return imhtml->edit.backcolor != NULL;
2327 }
2328
2329 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face)
2330 {
2331 GtkIMHtmlFormatSpan *span;
2332 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2333 GtkTextIter iter;
2334 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2335 if (!imhtml->edit.fontface) {
2336 span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2337 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2338 span->start_tag = g_strdup_printf("<font face=\"%s\">", face);
2339 span->end = NULL;
2340 span->end_tag = g_strdup("</font>");
2341 span->buffer = imhtml->text_buffer;
2342 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", face, NULL);
2343 imhtml->edit.fontface = span;
2344 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2345 } else {
2346 span = imhtml->edit.fontface;
2347 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2348 imhtml->edit.fontface = NULL;
2349 }
2350 return imhtml->edit.fontface != NULL;
2351 }
2352
2353 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, const char *url, const char *text)
2354 {
2355 GtkIMHtmlFormatSpan *span = g_malloc(sizeof(GtkIMHtmlFormatSpan));
2356 GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer);
2357 GtkTextIter iter;
2358 GtkTextTag *tag, *linktag;
2359
2360 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL);
2361 g_object_set_data(G_OBJECT(tag), "link_url", g_strdup(url));
2362
2363 linktag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "LINK");
2364
2365 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark);
2366 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2367 span->buffer = imhtml->text_buffer;
2368 span->start_tag = g_strdup_printf("<a href=\"%s\">", url);
2369 span->end_tag = g_strdup("</a>");
2370 g_signal_connect(G_OBJECT(tag), "event", G_CALLBACK(tag_event), g_strdup(url));
2371
2372 gtk_text_buffer_insert_with_tags(imhtml->text_buffer, &iter, text, strlen(text), linktag, tag, NULL);
2373 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE);
2374 imhtml->format_spans = g_list_append(imhtml->format_spans, span);
2375 }
2376
2377 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley)
2378 {
2379 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer);
2380 GtkTextIter iter;
2381 GdkPixbuf *pixbuf = NULL;
2382 GdkPixbufAnimation *annipixbuf = NULL;
2383 GtkWidget *icon = NULL;
2384 GtkTextChildAnchor *anchor;
2385
2386 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins);
2387 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter);
2388 g_object_set_data(G_OBJECT(anchor), "text_tag", g_strdup(smiley));
2389
2390 annipixbuf = gtk_smiley_tree_image(imhtml, sml, smiley);
2391 if(annipixbuf) {
2392 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) {
2393 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf);
2394 if(pixbuf)
2395 icon = gtk_image_new_from_pixbuf(pixbuf);
2396 } else {
2397 icon = gtk_image_new_from_animation(annipixbuf);
2398 }
2399 }
2400
2401 if (icon) {
2402 gtk_widget_show(icon);
2403 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor);
2404 }
2405 }
2406
2407 int span_compare_begin(const GtkIMHtmlFormatSpan *a, const GtkIMHtmlFormatSpan *b, GtkTextBuffer *buffer)
2408 {
2409 GtkTextIter ia, ib;
2410 gtk_text_buffer_get_iter_at_mark(buffer, &ia, a->start);
2411 gtk_text_buffer_get_iter_at_mark(buffer, &ib, b->start);
2412 return gtk_text_iter_compare(&ia, &ib);
2413 }
2414
2415 int span_compare_end(GtkIMHtmlFormatSpan *a, GtkIMHtmlFormatSpan *b)
2416 {
2417 GtkTextIter ia, ib;
2418 gtk_text_buffer_get_iter_at_mark(a->buffer, &ia, a->start);
2419 gtk_text_buffer_get_iter_at_mark(b->buffer, &ib, b->start);
2420 /* The -1 here makes it so that if I have two spans that close at the same point, the
2421 * span added second will be closed first, as in <b><i>Hello</i></b>. Without this,
2422 * it would be <b><i>Hello</b></i> */
2423 return gtk_text_iter_compare(&ia, &ib) - 1;
2424 }
2425
2426 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such
2427 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else
2428 * check the list of formatted strings, sorted by the position of the starting tags and apply them as
2429 * needed. After applying the start tags, add the end tags to the "closers" list, which is sorted by
2430 * location of ending tags. These get applied in a similar fashion. Finally, replace <, >, &, and "
2431 * with their HTML equivilent. */
2432 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end)
2433 {
2434 gunichar c;
2435 GtkIMHtmlFormatSpan *sspan = NULL, *espan = NULL;
2436 GtkTextIter iter, siter, eiter;
2437 GList *starters = imhtml->format_spans;
2438 GList *closers = NULL;
2439 GString *str = g_string_new("");
2440 g_list_sort_with_data(starters, (GCompareDataFunc)span_compare_begin, imhtml->text_buffer);
2441
2442 gtk_text_iter_order(start, end);
2443 iter = *start;
2444
2445
2446 /* Initialize these to the end iter */
2447 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter);
2448 eiter = siter;
2449
2450 if (starters) {
2451 while (starters) {
2452 GtkTextIter tagend;
2453 sspan = (GtkIMHtmlFormatSpan*)starters->data;
2454 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start);
2455 if (gtk_text_iter_compare(&siter, start) > 0)
2456 break;
2457 if (sspan->end)
2458 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &tagend, sspan->end);
2459 if (sspan->end == NULL || gtk_text_iter_compare(&tagend, start) > 0) {
2460 str = g_string_append(str, sspan->start_tag);
2461 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end);
2462 espan = (GtkIMHtmlFormatSpan*)closers->data;
2463 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end);
2464 }
2465 sspan = (GtkIMHtmlFormatSpan*)starters->data;
2466 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start);
2467 starters = starters->next;
2468 }
2469 if (!starters) {
2470 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter);
2471 sspan = NULL;
2472 }
2473 }
2474
2475 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) {
2476 if (c == 0xFFFC) {
2477 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter);
2478 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag");
2479 str = g_string_append(str, text);
2480 } else {
2481 while (gtk_text_iter_equal(&eiter, &iter)) {
2482 /* This is where we shall insert the ending tag of
2483 * this format span */
2484 str = g_string_append(str, espan->end_tag);
2485 closers = g_list_remove(closers, espan);
2486 if (!closers) {
2487 espan = NULL;
2488 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &eiter);
2489 } else {
2490 espan = (GtkIMHtmlFormatSpan*)closers->data;
2491 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end);
2492 }
2493 }
2494 while (gtk_text_iter_equal(&siter, &iter)) {
2495 /* This is where we shall insert the starting tag of
2496 * this format span */
2497 str = g_string_append(str, sspan->start_tag);
2498 if (sspan->end) {
2499 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end);
2500 espan = (GtkIMHtmlFormatSpan*)closers->data;
2501 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end);
2502
2503 }
2504 starters = starters->next;
2505 if (starters) {
2506 sspan = (GtkIMHtmlFormatSpan*)starters->data;
2507 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start);
2508 } else {
2509 sspan = NULL;
2510 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter);
2511 }
2512
2513 }
2514
2515 if (c == '<')
2516 str = g_string_append(str, "&lt;");
2517 else if (c == '>')
2518 str = g_string_append(str, "&gt;");
2519 else if (c == '&')
2520 str = g_string_append(str, "&amp;");
2521 else if (c == '"')
2522 str = g_string_append(str, "&quot;");
2523 else if (c == '\n')
2524 str = g_string_append(str, "<br>");
2525 else
2526 str = g_string_append_unichar(str, c);
2527 }
2528 gtk_text_iter_forward_char(&iter);
2529 }
2530 while (closers) {
2531 GtkIMHtmlFormatSpan *span = (GtkIMHtmlFormatSpan*)closers->data;
2532 str = g_string_append(str, span->end_tag);
2533 closers = g_list_remove(closers, span);
2534
2535 }
2536 printf("Gotten: %s\n", str->str);
2537 return g_string_free(str, FALSE);
2538 }
2539
2540 void gtk_imhtml_close_tags(GtkIMHtml *imhtml)
2541 {
2542
2543 if (imhtml->edit.bold)
2544 gtk_imhtml_toggle_bold(imhtml);
2545
2546 if (imhtml->edit.italic)
2547 gtk_imhtml_toggle_italic(imhtml);
2548
2549 if (imhtml->edit.underline)
2550 gtk_imhtml_toggle_underline(imhtml);
2551
2552 if (imhtml->edit.forecolor)
2553 gtk_imhtml_toggle_forecolor(imhtml, NULL);
2554
2555 if (imhtml->edit.backcolor)
2556 gtk_imhtml_toggle_backcolor(imhtml, NULL);
2557
2558 if (imhtml->edit.fontface)
2559 gtk_imhtml_toggle_fontface(imhtml, NULL);
2560
2561 if (imhtml->edit.sizespan)
2562 gtk_imhtml_font_set_size(imhtml, -1);
2563
2564 }
2565
2566 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml)
2567 {
2568 GtkTextIter start, end;
2569
2570 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
2571 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
2572 return gtk_imhtml_get_markup_range(imhtml, &start, &end);
2573 }
2574
2575 char *gtk_imhtml_get_text(GtkIMHtml *imhtml)
2576 {
2577 GtkTextIter start_iter, end_iter;
2578 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start_iter);
2579 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end_iter);
2580 return gtk_text_buffer_get_text(imhtml->text_buffer, &start_iter, &end_iter, FALSE);
2581
2582 }
2583