comparison src/gtkimhtml.c @ 8061:ea073d234191

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