comparison src/gtkimhtml.c @ 2856:b1e300a85678

[gaim-migrate @ 2869] rewrote the html parser in gtkimhtml. yes, that's really all i did. the reason for the massive change is because i added a length argument, which then needed to be propogated down to everything that would ever receive anything that would get drawn to the window. the new parser isn't any faster. that wasn't my goal. it's much more understandable now (hopefully, anyway). committer: Tailor Script <tailor@pidgin.im>
author Eric Warmenhoven <eric@warmenhoven.org>
date Sat, 08 Dec 2001 09:48:52 +0000
parents d00066b2f71a
children 450392752988
comparison
equal deleted inserted replaced
2855:19f786779b08 2856:b1e300a85678
34 #include <langinfo.h> 34 #include <langinfo.h>
35 #include <locale.h> 35 #include <locale.h>
36 #endif 36 #endif
37 37
38 #if GTK_CHECK_VERSION(1,3,0) 38 #if GTK_CHECK_VERSION(1,3,0)
39 #define GTK_IMHTML_GET_STYLE_FONT(style) gtk_style_get_font (style) 39 # define GTK_IMHTML_GET_STYLE_FONT(style) gtk_style_get_font (style)
40 #else 40 #else
41 #define GTK_IMHTML_GET_STYLE_FONT(style) (style)->font 41 # define GTK_IMHTML_GET_STYLE_FONT(style) (style)->font
42 #define GTK_CLASS_TYPE(class) (class)->type 42 # define GTK_CLASS_TYPE(class) (class)->type
43 #endif 43 #endif
44 44
45 #include "pixmaps/angel.xpm" 45 #include "pixmaps/angel.xpm"
46 #include "pixmaps/bigsmile.xpm" 46 #include "pixmaps/bigsmile.xpm"
47 #include "pixmaps/burp.xpm" 47 #include "pixmaps/burp.xpm"
287 287
288 gchar *text; 288 gchar *text;
289 GtkIMHtmlBit *bit; 289 GtkIMHtmlBit *bit;
290 }; 290 };
291 291
292 struct url_widget { 292 struct clickable {
293 gint x; 293 gint x;
294 gint y; 294 gint y;
295 gint width; 295 gint width;
296 gint height; 296 gint height;
297 GtkIMHtml *imhtml; 297 GtkIMHtml *imhtml;
325 { 325 {
326 GtkIMHtml *imhtml; 326 GtkIMHtml *imhtml;
327 327
328 imhtml = GTK_IMHTML (object); 328 imhtml = GTK_IMHTML (object);
329 329
330 while (imhtml->bits) { 330 gtk_imhtml_clear (imhtml);
331 GtkIMHtmlBit *bit = imhtml->bits->data;
332 imhtml->bits = g_list_remove (imhtml->bits, bit);
333 if (bit->text)
334 g_free (bit->text);
335 if (bit->font)
336 gdk_font_unref (bit->font);
337 if (bit->fore)
338 gdk_color_free (bit->fore);
339 if (bit->back)
340 gdk_color_free (bit->back);
341 if (bit->bg)
342 gdk_color_free (bit->bg);
343 if (bit->url)
344 g_free (bit->url);
345 if (bit->pm)
346 gdk_pixmap_unref (bit->pm);
347 if (bit->bm)
348 gdk_bitmap_unref (bit->bm);
349 while (bit->chunks) {
350 struct line_info *li = bit->chunks->data;
351 if (li->text)
352 g_free (li->text);
353 bit->chunks = g_list_remove (bit->chunks, li);
354 g_free (li);
355 }
356 g_free (bit);
357 }
358
359 if (imhtml->line)
360 g_list_free (imhtml->line);
361
362 while (imhtml->urls) {
363 g_free (imhtml->urls->data);
364 imhtml->urls = g_list_remove (imhtml->urls, imhtml->urls->data);
365 }
366 331
367 if (imhtml->selected_text) 332 if (imhtml->selected_text)
368 g_string_free (imhtml->selected_text, TRUE); 333 g_string_free (imhtml->selected_text, TRUE);
369
370 if (imhtml->tip_timer) {
371 gtk_timeout_remove (imhtml->tip_timer);
372 imhtml->tip_timer = 0;
373 }
374 if (imhtml->tip_window) {
375 gtk_widget_destroy (imhtml->tip_window);
376 imhtml->tip_window = NULL;
377 }
378 imhtml->tip_bit = NULL;
379 334
380 if (imhtml->default_font) 335 if (imhtml->default_font)
381 gdk_font_unref (imhtml->default_font); 336 gdk_font_unref (imhtml->default_font);
382 if (imhtml->default_fg_color) 337 if (imhtml->default_fg_color)
383 gdk_color_free (imhtml->default_fg_color); 338 gdk_color_free (imhtml->default_fg_color);
829 gtk_layout_freeze (GTK_LAYOUT (imhtml)); 784 gtk_layout_freeze (GTK_LAYOUT (imhtml));
830 785
831 g_list_free (imhtml->line); 786 g_list_free (imhtml->line);
832 imhtml->line = NULL; 787 imhtml->line = NULL;
833 788
834 while (imhtml->urls) { 789 while (imhtml->click) {
835 g_free (imhtml->urls->data); 790 g_free (imhtml->click->data);
836 imhtml->urls = g_list_remove (imhtml->urls, imhtml->urls->data); 791 imhtml->click = g_list_remove (imhtml->click, imhtml->click->data);
837 } 792 }
838 793
839 imhtml->x = 0; 794 imhtml->x = 0;
840 imhtml->y = TOP_BORDER; 795 imhtml->y = TOP_BORDER;
841 imhtml->llheight = 0; 796 imhtml->llheight = 0;
1452 gtk_imhtml_select_bits (imhtml); 1407 gtk_imhtml_select_bits (imhtml);
1453 else 1408 else
1454 gtk_imhtml_select_in_chunk (imhtml, chunk); 1409 gtk_imhtml_select_in_chunk (imhtml, chunk);
1455 } 1410 }
1456 } else { 1411 } else {
1457 GList *urls = imhtml->urls; 1412 GList *click = imhtml->click;
1458 struct url_widget *uw; 1413 struct clickable *uw;
1459 1414
1460 while (urls) { 1415 while (click) {
1461 uw = (struct url_widget *) urls->data; 1416 uw = (struct clickable *) click->data;
1462 if ((x > uw->x) && (x < uw->x + uw->width) && 1417 if ((x > uw->x) && (x < uw->x + uw->width) &&
1463 (y > uw->y) && (y < uw->y + uw->height)) { 1418 (y > uw->y) && (y < uw->y + uw->height)) {
1464 if (imhtml->tip_bit != uw->bit) { 1419 if (imhtml->tip_bit != uw->bit) {
1465 imhtml->tip_bit = uw->bit; 1420 imhtml->tip_bit = uw->bit;
1466 if (imhtml->tip_timer != 0) 1421 if (imhtml->tip_timer != 0)
1475 } 1430 }
1476 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, 1431 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window,
1477 imhtml->hand_cursor); 1432 imhtml->hand_cursor);
1478 return TRUE; 1433 return TRUE;
1479 } 1434 }
1480 urls = g_list_next (urls); 1435 click = g_list_next (click);
1481 } 1436 }
1482 } 1437 }
1483 1438
1484 if (imhtml->tip_timer) { 1439 if (imhtml->tip_timer) {
1485 gtk_timeout_remove (imhtml->tip_timer); 1440 gtk_timeout_remove (imhtml->tip_timer);
1517 1472
1518 static void 1473 static void
1519 menu_open_url (GtkObject *object, 1474 menu_open_url (GtkObject *object,
1520 gpointer data) 1475 gpointer data)
1521 { 1476 {
1522 struct url_widget *uw = data; 1477 struct clickable *uw = data;
1523 1478
1524 gtk_signal_emit (GTK_OBJECT (uw->imhtml), signals [URL_CLICKED], uw->bit->url); 1479 gtk_signal_emit (GTK_OBJECT (uw->imhtml), signals [URL_CLICKED], uw->bit->url);
1525 } 1480 }
1526 1481
1527 static void 1482 static void
1528 menu_copy_link (GtkObject *object, 1483 menu_copy_link (GtkObject *object,
1529 gpointer data) 1484 gpointer data)
1530 { 1485 {
1531 struct url_widget *uw = data; 1486 struct clickable *uw = data;
1532 GtkIMHtml *imhtml = uw->imhtml; 1487 GtkIMHtml *imhtml = uw->imhtml;
1533 1488
1534 if (imhtml->selected_text) 1489 if (imhtml->selected_text)
1535 g_string_free (imhtml->selected_text, TRUE); 1490 g_string_free (imhtml->selected_text, TRUE);
1536 1491
1560 imhtml->selection = TRUE; 1515 imhtml->selection = TRUE;
1561 gtk_imhtml_select_none (imhtml); 1516 gtk_imhtml_select_none (imhtml);
1562 } 1517 }
1563 1518
1564 if (event->button == 3) { 1519 if (event->button == 3) {
1565 GList *urls = imhtml->urls; 1520 GList *click = imhtml->click;
1566 struct url_widget *uw; 1521 struct clickable *uw;
1567 1522
1568 while (urls) { 1523 while (click) {
1569 uw = urls->data; 1524 uw = click->data;
1570 if ((x > uw->x) && (x < uw->x + uw->width) && 1525 if ((x > uw->x) && (x < uw->x + uw->width) &&
1571 (y > uw->y) && (y < uw->y + uw->height)) { 1526 (y > uw->y) && (y < uw->y + uw->height)) {
1572 GtkWidget *menu = gtk_menu_new (); 1527 GtkWidget *menu = gtk_menu_new ();
1573 1528 GtkWidget *button;
1574 GtkWidget *button = gtk_menu_item_new_with_label ("Open URL"); 1529
1575 gtk_signal_connect (GTK_OBJECT (button), "activate", 1530 if (uw->bit->url) {
1576 GTK_SIGNAL_FUNC (menu_open_url), uw); 1531 button = gtk_menu_item_new_with_label ("Open URL");
1577 gtk_menu_append (GTK_MENU (menu), button); 1532 gtk_signal_connect (GTK_OBJECT (button), "activate",
1578 gtk_widget_show (button); 1533 GTK_SIGNAL_FUNC (menu_open_url), uw);
1579 1534 gtk_menu_append (GTK_MENU (menu), button);
1580 button = gtk_menu_item_new_with_label ("Copy Link Location"); 1535 gtk_widget_show (button);
1581 gtk_signal_connect (GTK_OBJECT (button), "activate", 1536
1582 GTK_SIGNAL_FUNC (menu_copy_link), uw); 1537 button = gtk_menu_item_new_with_label ("Copy Link Location");
1583 gtk_menu_append (GTK_MENU (menu), button); 1538 gtk_signal_connect (GTK_OBJECT (button), "activate",
1584 gtk_widget_show (button); 1539 GTK_SIGNAL_FUNC (menu_copy_link), uw);
1585 1540 gtk_menu_append (GTK_MENU (menu), button);
1586 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 1541 gtk_widget_show (button);
1587 3, event->time); 1542 }
1543
1544 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time);
1588 1545
1589 if (imhtml->tip_timer) { 1546 if (imhtml->tip_timer) {
1590 gtk_timeout_remove (imhtml->tip_timer); 1547 gtk_timeout_remove (imhtml->tip_timer);
1591 imhtml->tip_timer = 0; 1548 imhtml->tip_timer = 0;
1592 } 1549 }
1596 } 1553 }
1597 imhtml->tip_bit = NULL; 1554 imhtml->tip_bit = NULL;
1598 1555
1599 return TRUE; 1556 return TRUE;
1600 } 1557 }
1601 urls = g_list_next (urls); 1558 click = g_list_next (click);
1602 } 1559 }
1603 } 1560 }
1604 1561
1605 return TRUE; 1562 return TRUE;
1606 } 1563 }
1630 1587
1631 gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time); 1588 gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time);
1632 } 1589 }
1633 1590
1634 if ((event->button == 1) && (imhtml->sel_startx == 0)) { 1591 if ((event->button == 1) && (imhtml->sel_startx == 0)) {
1635 GList *urls = imhtml->urls; 1592 GList *click = imhtml->click;
1636 struct url_widget *uw; 1593 struct clickable *uw;
1637 1594
1638 while (urls) { 1595 while (click) {
1639 uw = (struct url_widget *) urls->data; 1596 uw = (struct clickable *) click->data;
1640 if ((x > uw->x) && (x < uw->x + uw->width) && 1597 if ((x > uw->x) && (x < uw->x + uw->width) &&
1641 (y > uw->y) && (y < uw->y + uw->height)) { 1598 (y > uw->y) && (y < uw->y + uw->height)) {
1642 gtk_signal_emit (GTK_OBJECT (imhtml), signals [URL_CLICKED], 1599 gtk_signal_emit (GTK_OBJECT (imhtml), signals [URL_CLICKED],
1643 uw->bit->url); 1600 uw->bit->url);
1644 return TRUE; 1601 return TRUE;
1645 } 1602 }
1646 urls = g_list_next (urls); 1603 click = g_list_next (click);
1647 } 1604 }
1648 } 1605 }
1649 1606
1650 return TRUE; 1607 return TRUE;
1651 } 1608 }
2090 GtkIMHtml *imhtml = gtk_type_new (GTK_TYPE_IMHTML); 2047 GtkIMHtml *imhtml = gtk_type_new (GTK_TYPE_IMHTML);
2091 2048
2092 gtk_imhtml_set_adjustments (imhtml, hadj, vadj); 2049 gtk_imhtml_set_adjustments (imhtml, hadj, vadj);
2093 2050
2094 imhtml->bits = NULL; 2051 imhtml->bits = NULL;
2095 imhtml->urls = NULL; 2052 imhtml->click = NULL;
2096 2053
2097 imhtml->x = 0; 2054 imhtml->x = 0;
2098 imhtml->y = TOP_BORDER; 2055 imhtml->y = TOP_BORDER;
2099 imhtml->llheight = 0; 2056 imhtml->llheight = 0;
2100 imhtml->llascent = 0; 2057 imhtml->llascent = 0;
2220 gint ascent) 2177 gint ascent)
2221 { 2178 {
2222 gint diff; 2179 gint diff;
2223 GList *ls = NULL; 2180 GList *ls = NULL;
2224 struct line_info *li; 2181 struct line_info *li;
2225 struct url_widget *uw; 2182 struct clickable *uw;
2226 2183
2227 if (height > imhtml->llheight) { 2184 if (height > imhtml->llheight) {
2228 diff = height - imhtml->llheight; 2185 diff = height - imhtml->llheight;
2229 2186
2230 ls = imhtml->line; 2187 ls = imhtml->line;
2236 else 2193 else
2237 li->ascent += diff / 2; 2194 li->ascent += diff / 2;
2238 ls = g_list_next (ls); 2195 ls = g_list_next (ls);
2239 } 2196 }
2240 2197
2241 ls = imhtml->urls; 2198 ls = imhtml->click;
2242 while (ls) { 2199 while (ls) {
2243 uw = ls->data; 2200 uw = ls->data;
2244 if (uw->y + diff > imhtml->y) 2201 if (uw->y + diff > imhtml->y)
2245 uw->y += diff; 2202 uw->y += diff;
2246 ls = g_list_next (ls); 2203 ls = g_list_next (ls);
2258 add_text_renderer (GtkIMHtml *imhtml, 2215 add_text_renderer (GtkIMHtml *imhtml,
2259 GtkIMHtmlBit *bit, 2216 GtkIMHtmlBit *bit,
2260 gchar *text) 2217 gchar *text)
2261 { 2218 {
2262 struct line_info *li; 2219 struct line_info *li;
2263 struct url_widget *uw; 2220 struct clickable *uw;
2264 gint width; 2221 gint width;
2265 2222
2266 if (text) 2223 if (text)
2267 width = gdk_string_width (bit->font, text); 2224 width = gdk_string_width (bit->font, text);
2268 else 2225 else
2279 li->ascent = 0; 2236 li->ascent = 0;
2280 li->text = text; 2237 li->text = text;
2281 li->bit = bit; 2238 li->bit = bit;
2282 2239
2283 if (bit->url) { 2240 if (bit->url) {
2284 uw = g_new0 (struct url_widget, 1); 2241 uw = g_new0 (struct clickable, 1);
2285 uw->x = imhtml->x; 2242 uw->x = imhtml->x;
2286 uw->y = imhtml->y; 2243 uw->y = imhtml->y;
2287 uw->width = width; 2244 uw->width = width;
2288 uw->height = imhtml->llheight; 2245 uw->height = imhtml->llheight;
2289 uw->imhtml = imhtml; 2246 uw->imhtml = imhtml;
2290 uw->bit = bit; 2247 uw->bit = bit;
2291 imhtml->urls = g_list_append (imhtml->urls, uw); 2248 imhtml->click = g_list_append (imhtml->click, uw);
2292 } 2249 }
2293 2250
2294 bit->chunks = g_list_append (bit->chunks, li); 2251 bit->chunks = g_list_append (bit->chunks, li);
2295 imhtml->line = g_list_append (imhtml->line, li); 2252 imhtml->line = g_list_append (imhtml->line, li);
2296 } 2253 }
2298 static void 2255 static void
2299 add_img_renderer (GtkIMHtml *imhtml, 2256 add_img_renderer (GtkIMHtml *imhtml,
2300 GtkIMHtmlBit *bit) 2257 GtkIMHtmlBit *bit)
2301 { 2258 {
2302 struct line_info *li; 2259 struct line_info *li;
2303 struct url_widget *uw; 2260 struct clickable *uw;
2304 gint width; 2261 gint width;
2305 2262
2306 gdk_window_get_size (bit->pm, &width, NULL); 2263 gdk_window_get_size (bit->pm, &width, NULL);
2307 2264
2308 li = g_new0 (struct line_info, 1); 2265 li = g_new0 (struct line_info, 1);
2312 li->height = imhtml->llheight; 2269 li->height = imhtml->llheight;
2313 li->ascent = 0; 2270 li->ascent = 0;
2314 li->bit = bit; 2271 li->bit = bit;
2315 2272
2316 if (bit->url) { 2273 if (bit->url) {
2317 uw = g_new0 (struct url_widget, 1); 2274 uw = g_new0 (struct clickable, 1);
2318 uw->x = imhtml->x; 2275 uw->x = imhtml->x;
2319 uw->y = imhtml->y; 2276 uw->y = imhtml->y;
2320 uw->width = width; 2277 uw->width = width;
2321 uw->height = imhtml->llheight; 2278 uw->height = imhtml->llheight;
2322 uw->imhtml = imhtml; 2279 uw->imhtml = imhtml;
2323 uw->bit = bit; 2280 uw->bit = bit;
2324 imhtml->urls = g_list_append (imhtml->urls, uw); 2281 imhtml->click = g_list_append (imhtml->click, uw);
2325 } 2282 }
2326 2283
2327 bit->chunks = g_list_append (bit->chunks, li); 2284 bit->chunks = g_list_append (bit->chunks, li);
2328 imhtml->line = g_list_append (imhtml->line, li); 2285 imhtml->line = g_list_append (imhtml->line, li);
2329 2286
2480 return NULL; 2437 return NULL;
2481 2438
2482 return gdk_color_copy (&c); 2439 return gdk_color_copy (&c);
2483 } 2440 }
2484 2441
2485 static gint 2442 static gboolean
2486 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, 2443 gtk_imhtml_is_smiley (GtkIMHtml *imhtml,
2487 const gchar *text) 2444 const gchar *text,
2488 { 2445 gint *len)
2489 return gtk_smiley_tree_lookup (imhtml->smiley_data, text); 2446 {
2447 *len = gtk_smiley_tree_lookup (imhtml->smiley_data, text);
2448 return (*len > 0);
2490 } 2449 }
2491 2450
2492 static GtkIMHtmlBit * 2451 static GtkIMHtmlBit *
2493 gtk_imhtml_new_bit (GtkIMHtml *imhtml, 2452 gtk_imhtml_new_bit (GtkIMHtml *imhtml,
2494 gint type, 2453 gint type,
2498 gint underline, 2457 gint underline,
2499 gint strike, 2458 gint strike,
2500 FontDetail *font, 2459 FontDetail *font,
2501 GdkColor *bg, 2460 GdkColor *bg,
2502 gchar *url, 2461 gchar *url,
2503 gint pre) 2462 gint pre,
2463 gint sub,
2464 gint sup)
2504 { 2465 {
2505 GtkIMHtmlBit *bit = NULL; 2466 GtkIMHtmlBit *bit = NULL;
2506 2467
2507 g_return_val_if_fail (imhtml != NULL, NULL); 2468 g_return_val_if_fail (imhtml != NULL, NULL);
2508 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); 2469 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL);
2569 2530
2570 return bit; 2531 return bit;
2571 } 2532 }
2572 2533
2573 #define NEW_TEXT_BIT gtk_imhtml_new_bit (imhtml, TYPE_TEXT, ws, bold, italics, underline, strike, \ 2534 #define NEW_TEXT_BIT gtk_imhtml_new_bit (imhtml, TYPE_TEXT, ws, bold, italics, underline, strike, \
2574 fonts ? fonts->data : NULL, bg, url, pre) 2535 fonts ? fonts->data : NULL, bg, url, pre, sub, sup)
2575 #define NEW_SMILEY_BIT gtk_imhtml_new_bit (imhtml, TYPE_SMILEY, ws, bold, italics, underline, strike, \ 2536 #define NEW_SMILEY_BIT gtk_imhtml_new_bit (imhtml, TYPE_SMILEY, ws, bold, italics, underline, strike, \
2576 fonts ? fonts->data : NULL, bg, url, pre) 2537 fonts ? fonts->data : NULL, bg, url, pre, sub, sup)
2577 #define NEW_SEP_BIT gtk_imhtml_new_bit (imhtml, TYPE_SEP, NULL, 0, 0, 0, 0, NULL, bg, NULL, 0) 2538 #define NEW_SEP_BIT gtk_imhtml_new_bit (imhtml, TYPE_SEP, NULL, 0, 0, 0, 0, NULL, bg, NULL, 0, 0, 0)
2578 #define NEW_BR_BIT gtk_imhtml_new_bit (imhtml, TYPE_BR, NULL, 0, 0, 0, 0, \ 2539 #define NEW_BR_BIT gtk_imhtml_new_bit (imhtml, TYPE_BR, NULL, 0, 0, 0, 0, \
2579 fonts ? fonts->data : NULL, bg, NULL, 0) 2540 fonts ? fonts->data : NULL, bg, NULL, 0, 0, 0)
2580 #define NEW_COMMENT_BIT gtk_imhtml_new_bit (imhtml, TYPE_COMMENT, ws, bold, italics, underline, strike, \ 2541 #define NEW_COMMENT_BIT gtk_imhtml_new_bit (imhtml, TYPE_COMMENT, ws, bold, italics, underline, strike, \
2581 fonts ? fonts->data : NULL, bg, url, pre) 2542 fonts ? fonts->data : NULL, bg, url, pre, sub, sup)
2582 2543
2583 #define NEW_BIT(bit) { GtkIMHtmlBit *tmp = bit; if (tmp != NULL) \ 2544 #define NEW_BIT(bit) ws [wpos] = '\0'; \
2584 newbits = g_list_append (newbits, tmp); } 2545 { GtkIMHtmlBit *tmp = bit; if (tmp != NULL) \
2546 newbits = g_list_append (newbits, tmp); } \
2547 wpos = 0; ws [wpos] = '\0'
2585 2548
2586 #define UPDATE_BG_COLORS \ 2549 #define UPDATE_BG_COLORS \
2587 { \ 2550 { \
2588 GdkColormap *cmap; \ 2551 GdkColormap *cmap; \
2589 GList *rev; \ 2552 GList *rev; \
2612 } \ 2575 } \
2613 } \ 2576 } \
2614 } 2577 }
2615 2578
2616 static gboolean 2579 static gboolean
2617 is_amp_escape (const gchar *string, 2580 gtk_imhtml_is_amp_escape (const gchar *string,
2618 gchar *replace, 2581 gchar *replace,
2619 gint *length) 2582 gint *length)
2620 { 2583 {
2621 g_return_val_if_fail (string != NULL, FALSE); 2584 g_return_val_if_fail (string != NULL, FALSE);
2622 g_return_val_if_fail (replace != NULL, FALSE); 2585 g_return_val_if_fail (replace != NULL, FALSE);
2623 g_return_val_if_fail (length != NULL, FALSE); 2586 g_return_val_if_fail (length != NULL, FALSE);
2624 2587
2660 } 2623 }
2661 2624
2662 return TRUE; 2625 return TRUE;
2663 } 2626 }
2664 2627
2628 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \
2629 *tag = g_strndup (string, strlen (x)); \
2630 *len = strlen (x) + 1; \
2631 return TRUE; \
2632 } \
2633 (*type)++
2634
2635 #define VALID_OPT_TAG(x) if (!g_strncasecmp (string, x " ", strlen (x " "))) { \
2636 const gchar *c = string + strlen (x " "); \
2637 gchar e = '"'; \
2638 gboolean quote = FALSE; \
2639 while (*c) { \
2640 if (*c == '"' || *c == '\'') { \
2641 if (quote && (*c == e)) \
2642 quote = !quote; \
2643 else if (!quote) { \
2644 quote = !quote; \
2645 e = *c; \
2646 } \
2647 } else if (!quote && (*c == '>')) \
2648 break; \
2649 c++; \
2650 } \
2651 if (*c) { \
2652 *tag = g_strndup (string, c - string); \
2653 *len = c - string + 1; \
2654 return TRUE; \
2655 } \
2656 } \
2657 (*type)++
2658
2659 static gboolean
2660 gtk_imhtml_is_tag (const gchar *string,
2661 gchar **tag,
2662 gint *len,
2663 gint *type)
2664 {
2665 *type = 1;
2666
2667 if (!strchr (string, '>'))
2668 return FALSE;
2669
2670 VALID_TAG ("B");
2671 VALID_TAG ("BOLD");
2672 VALID_TAG ("/B");
2673 VALID_TAG ("/BOLD");
2674 VALID_TAG ("I");
2675 VALID_TAG ("ITALIC");
2676 VALID_TAG ("/I");
2677 VALID_TAG ("/ITALIC");
2678 VALID_TAG ("U");
2679 VALID_TAG ("UNDERLINE");
2680 VALID_TAG ("/U");
2681 VALID_TAG ("/UNDERLINE");
2682 VALID_TAG ("S");
2683 VALID_TAG ("STRIKE");
2684 VALID_TAG ("/S");
2685 VALID_TAG ("/STRIKE");
2686 VALID_TAG ("SUB");
2687 VALID_TAG ("/SUB");
2688 VALID_TAG ("SUP");
2689 VALID_TAG ("/SUP");
2690 VALID_TAG ("PRE");
2691 VALID_TAG ("/PRE");
2692 VALID_TAG ("TITLE");
2693 VALID_TAG ("/TITLE");
2694 VALID_TAG ("BR");
2695 VALID_TAG ("HR");
2696 VALID_TAG ("/FONT");
2697 VALID_TAG ("/A");
2698 VALID_TAG ("P");
2699 VALID_TAG ("/P");
2700 VALID_TAG ("H3");
2701 VALID_TAG ("/H3");
2702 VALID_TAG ("HTML");
2703 VALID_TAG ("/HTML");
2704 VALID_TAG ("BODY");
2705 VALID_TAG ("/BODY");
2706 VALID_TAG ("FONT");
2707 VALID_TAG ("HEAD");
2708 VALID_TAG ("HEAD");
2709
2710 VALID_OPT_TAG ("HR");
2711 VALID_OPT_TAG ("FONT");
2712 VALID_OPT_TAG ("BODY");
2713 VALID_OPT_TAG ("A");
2714 VALID_OPT_TAG ("IMG");
2715 VALID_OPT_TAG ("P");
2716 VALID_OPT_TAG ("H3");
2717
2718 if (!g_strncasecmp(string, "!--", strlen ("!--"))) {
2719 gchar *e = strstr (string, "-->");
2720 if (e) {
2721 *len = e - string + strlen ("-->");
2722 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->"));
2723 return TRUE;
2724 }
2725 }
2726
2727 return FALSE;
2728 }
2729
2730 static gchar*
2731 gtk_imhtml_get_html_opt (gchar *tag,
2732 const gchar *opt)
2733 {
2734 gchar *t = tag;
2735 gchar *e, *a;
2736
2737 while (g_strncasecmp (t, opt, strlen (opt))) {
2738 gboolean quote = FALSE;
2739 if (*t == '\0') break;
2740 while (*t && !((*t == ' ') && !quote)) {
2741 if (*t == '\"')
2742 quote = ! quote;
2743 t++;
2744 }
2745 while (*t && (*t == ' ')) t++;
2746 }
2747
2748 if (!g_strncasecmp (t, opt, strlen (opt))) {
2749 t += strlen (opt);
2750 } else {
2751 return NULL;
2752 }
2753
2754 if ((*t == '\"') || (*t == '\'')) {
2755 e = a = ++t;
2756 while (*e && (*e != *(t - 1))) e++;
2757 if (*e != '\0') {
2758 *e = '\0';
2759 return g_strdup (a);
2760 } else {
2761 return NULL;
2762 }
2763 } else {
2764 e = a = t;
2765 while (*e && !isspace ((gint) *e)) e++;
2766 *e = '\0';
2767 return g_strdup (a);
2768 }
2769 }
2770
2665 GString* 2771 GString*
2666 gtk_imhtml_append_text (GtkIMHtml *imhtml, 2772 gtk_imhtml_append_text (GtkIMHtml *imhtml,
2667 const gchar *text, 2773 const gchar *text,
2774 gint len,
2668 GtkIMHtmlOptions options) 2775 GtkIMHtmlOptions options)
2669 { 2776 {
2670 const gchar *c; 2777 const gchar *c;
2671 gboolean intag = FALSE; 2778 gboolean binary = TRUE;
2672 gint tagquote = 0;
2673 gboolean incomment = FALSE;
2674 gchar *ws; 2779 gchar *ws;
2780 gint pos = 0;
2781 gint wpos = 0;
2782
2675 gchar *tag; 2783 gchar *tag;
2676 gint wpos = 0; 2784 gint tlen;
2677 gint tpos = 0; 2785 gint type;
2786
2787 gchar amp;
2788
2678 int smilelen; 2789 int smilelen;
2790
2679 GList *newbits = NULL; 2791 GList *newbits = NULL;
2680 2792
2681 guint bold = 0, 2793 guint bold = 0,
2682 italics = 0, 2794 italics = 0,
2683 underline = 0, 2795 underline = 0,
2706 if ((vadj->value < imhtml->y - GTK_WIDGET (imhtml)->allocation.height) && 2818 if ((vadj->value < imhtml->y - GTK_WIDGET (imhtml)->allocation.height) &&
2707 (vadj->upper >= GTK_WIDGET (imhtml)->allocation.height)) 2819 (vadj->upper >= GTK_WIDGET (imhtml)->allocation.height))
2708 scrolldown = FALSE; 2820 scrolldown = FALSE;
2709 2821
2710 c = text; 2822 c = text;
2711 ws = g_malloc (strlen (text) + 1); 2823 if (len == -1) {
2712 tag = g_malloc (strlen (text) + 1); 2824 binary = FALSE;
2713 2825 len = strlen (text);
2826 }
2827
2828 ws = g_malloc (len + 1);
2714 ws [0] = '\0'; 2829 ws [0] = '\0';
2715 2830
2716 while (*c) { 2831 while (pos < len) {
2717 if (*c == '<') { 2832 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) {
2718 if (intag && (tagquote != 1)) { 2833 c++;
2719 char *d; 2834 pos++;
2720 tag [tpos] = 0; 2835 switch (type) {
2721 d = tag; 2836 case 1: /* B */
2722 while (*d) { 2837 case 2: /* BOLD */
2723 if ((smilelen = gtk_imhtml_is_smiley (imhtml, d)) != 0) {
2724 ws [wpos] = 0;
2725 wpos = 0;
2726 NEW_BIT (NEW_TEXT_BIT);
2727 g_snprintf (ws, smilelen + 1, "%s", d);
2728 NEW_BIT (NEW_SMILEY_BIT);
2729 d += smilelen;
2730 } else if (*d == '&') {
2731 gchar replace;
2732 gint length;
2733 if (is_amp_escape (d, &replace, &length)) {
2734 ws [wpos++] = replace;
2735 d += length;
2736 } else {
2737 ws [wpos++] = *d++;
2738 }
2739 } else if (*d == '\n') {
2740 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
2741 ws [wpos] = 0;
2742 wpos = 0;
2743 NEW_BIT (NEW_TEXT_BIT);
2744 NEW_BIT (NEW_BR_BIT);
2745 }
2746 d++;
2747 } else {
2748 ws [wpos++] = *d++;
2749 }
2750 }
2751 tpos = 0;
2752 }
2753
2754 if (incomment) {
2755 ws [wpos++] = *c++;
2756 continue;
2757 }
2758
2759 if (!g_strncasecmp (c, "<!--", strlen ("<!--"))) {
2760 if (!(options & GTK_IMHTML_NO_COMMENTS)) {
2761 ws [wpos] = 0;
2762 wpos = 0;
2763 tag [tpos] = 0;
2764 strcat (tag, ws);
2765 incomment = TRUE;
2766 intag = FALSE;
2767 }
2768 ws [wpos++] = *c++;
2769 ws [wpos++] = *c++;
2770 ws [wpos++] = *c++;
2771 ws [wpos++] = *c++;
2772 continue;
2773 }
2774
2775 tag [tpos++] = *c++;
2776 intag = TRUE;
2777 tagquote = 0;
2778 } else if (incomment && (*c == '-') && !g_strncasecmp (c, "-->", strlen ("-->"))) {
2779 gchar *tmp;
2780 ws [wpos] = 0;
2781 wpos = 0;
2782 tmp = g_strdup (ws);
2783 ws [wpos] = 0;
2784 strcat (ws, tag);
2785 NEW_BIT (NEW_TEXT_BIT);
2786 ws [wpos] = 0;
2787 strcat (ws, tmp + strlen ("<!--"));
2788 g_free (tmp);
2789 NEW_BIT (NEW_COMMENT_BIT);
2790 incomment = FALSE;
2791 c += strlen ("-->");
2792 } else if (*c == '>' && intag && (tagquote != 1)) {
2793 gboolean got_tag = FALSE;
2794 tag [tpos++] = *c++;
2795 tag [tpos] = 0;
2796 ws [wpos] = 0;
2797
2798 if (!g_strcasecmp (tag, "<B>") || !g_strcasecmp (tag, "<BOLD>")) {
2799 got_tag = TRUE;
2800 NEW_BIT (NEW_TEXT_BIT); 2838 NEW_BIT (NEW_TEXT_BIT);
2801 bold++; 2839 bold++;
2802 } else if (!g_strcasecmp (tag, "</B>") || !g_strcasecmp (tag, "</BOLD>")) { 2840 break;
2803 got_tag = TRUE; 2841 case 3: /* /B */
2842 case 4: /* /BOLD */
2804 NEW_BIT (NEW_TEXT_BIT); 2843 NEW_BIT (NEW_TEXT_BIT);
2805 if (bold) { 2844 if (bold)
2806 bold--; 2845 bold--;
2807 } 2846 break;
2808 } else if (!g_strcasecmp (tag, "<I>") || !g_strcasecmp (tag, "<ITALIC>")) { 2847 case 5: /* I */
2809 got_tag = TRUE; 2848 case 6: /* ITALIC */
2810 NEW_BIT (NEW_TEXT_BIT); 2849 NEW_BIT (NEW_TEXT_BIT);
2811 italics++; 2850 italics++;
2812 } else if (!g_strcasecmp (tag, "</I>") || !g_strcasecmp (tag, "</ITALIC>")) { 2851 break;
2813 got_tag = TRUE; 2852 case 7: /* /I */
2853 case 8: /* /ITALIC */
2814 NEW_BIT (NEW_TEXT_BIT); 2854 NEW_BIT (NEW_TEXT_BIT);
2815 if (italics) { 2855 if (italics)
2816 italics--; 2856 italics--;
2817 } 2857 break;
2818 } else if (!g_strcasecmp (tag, "<U>") || !g_strcasecmp (tag, "<UNDERLINE>")) { 2858 case 9: /* U */
2819 got_tag = TRUE; 2859 case 10: /* UNDERLINE */
2820 NEW_BIT (NEW_TEXT_BIT); 2860 NEW_BIT (NEW_TEXT_BIT);
2821 underline++; 2861 underline++;
2822 } else if (!g_strcasecmp (tag, "</U>") || !g_strcasecmp (tag, "</UNDERLINE>")) { 2862 break;
2823 got_tag = TRUE; 2863 case 11: /* /U */
2864 case 12: /* /UNDERLINE */
2824 NEW_BIT (NEW_TEXT_BIT); 2865 NEW_BIT (NEW_TEXT_BIT);
2825 if (underline) { 2866 if (underline)
2826 underline--; 2867 underline--;
2827 } 2868 break;
2828 } else if (!g_strcasecmp (tag, "<S>") || !g_strcasecmp (tag, "<STRIKE>")) { 2869 case 13: /* S */
2829 got_tag = TRUE; 2870 case 14: /* STRIKE */
2830 NEW_BIT (NEW_TEXT_BIT); 2871 NEW_BIT (NEW_TEXT_BIT);
2831 strike++; 2872 strike++;
2832 } else if (!g_strcasecmp (tag, "</S>") || !g_strcasecmp (tag, "</STRIKE>")) { 2873 break;
2833 got_tag = TRUE; 2874 case 15: /* /S */
2875 case 16: /* /STRIKE */
2834 NEW_BIT (NEW_TEXT_BIT); 2876 NEW_BIT (NEW_TEXT_BIT);
2835 if (strike) { 2877 if (strike)
2836 strike--; 2878 strike--;
2837 } 2879 break;
2838 } else if (!g_strcasecmp (tag, "<SUB>")) { 2880 case 17: /* SUB */
2839 got_tag = TRUE;
2840 NEW_BIT (NEW_TEXT_BIT); 2881 NEW_BIT (NEW_TEXT_BIT);
2841 sub++; 2882 sub++;
2842 } else if (!g_strcasecmp (tag, "</SUB>")) { 2883 break;
2843 got_tag = TRUE; 2884 case 18: /* /SUB */
2844 NEW_BIT (NEW_TEXT_BIT); 2885 NEW_BIT (NEW_TEXT_BIT);
2845 if (sub) { 2886 if (sub)
2846 sub--; 2887 sub--;
2847 } 2888 break;
2848 } else if (!g_strcasecmp (tag, "<SUP>")) { 2889 case 19: /* SUP */
2849 got_tag = TRUE;
2850 NEW_BIT (NEW_TEXT_BIT); 2890 NEW_BIT (NEW_TEXT_BIT);
2851 sup++; 2891 sup++;
2852 } else if (!g_strcasecmp (tag, "</SUP>")) { 2892 break;
2853 got_tag = TRUE; 2893 case 20: /* /SUP */
2854 NEW_BIT (NEW_TEXT_BIT); 2894 NEW_BIT (NEW_TEXT_BIT);
2855 if (sup) { 2895 if (sup)
2856 sup--; 2896 sup--;
2857 } 2897 break;
2858 } else if (!g_strcasecmp (tag, "<PRE>")) { 2898 case 21: /* PRE */
2859 got_tag = TRUE;
2860 NEW_BIT (NEW_TEXT_BIT); 2899 NEW_BIT (NEW_TEXT_BIT);
2861 pre++; 2900 pre++;
2862 } else if (!g_strcasecmp (tag, "</PRE>")) { 2901 break;
2863 got_tag = TRUE; 2902 case 22: /* /PRE */
2864 NEW_BIT (NEW_TEXT_BIT); 2903 NEW_BIT (NEW_TEXT_BIT);
2865 if (pre) { 2904 if (pre)
2866 pre--; 2905 pre--;
2906 break;
2907 case 23: /* TITLE */
2908 NEW_BIT (NEW_TEXT_BIT);
2909 title++;
2910 break;
2911 case 24: /* /TITLE */
2912 if (title) {
2913 if (options & GTK_IMHTML_NO_TITLE) {
2914 wpos = 0;
2915 ws [wpos] = '\0';
2916 }
2917 title--;
2867 } 2918 }
2868 } else if (!g_strcasecmp (tag, "<TITLE>")) { 2919 break;
2869 if (options & GTK_IMHTML_NO_TITLE) { 2920 case 25: /* BR */
2870 got_tag = TRUE;
2871 NEW_BIT (NEW_TEXT_BIT);
2872 title++;
2873 } else {
2874 intag = FALSE;
2875 tpos = 0;
2876 continue;
2877 }
2878 } else if (!g_strcasecmp (tag, "</TITLE>")) {
2879 if (title) {
2880 got_tag = TRUE;
2881 wpos = 0;
2882 ws [wpos] = '\0';
2883 title--;
2884 } else {
2885 intag = FALSE;
2886 tpos = 0;
2887 continue;
2888 }
2889 } else if (!g_strcasecmp (tag, "<BR>")) {
2890 got_tag = TRUE;
2891 NEW_BIT (NEW_TEXT_BIT); 2921 NEW_BIT (NEW_TEXT_BIT);
2892 NEW_BIT (NEW_BR_BIT); 2922 NEW_BIT (NEW_BR_BIT);
2893 } else if (!g_strcasecmp (tag, "<HR>") || 2923 break;
2894 !g_strncasecmp (tag, "<HR ", strlen ("<HR "))) { 2924 case 26: /* HR */
2895 got_tag = TRUE;
2896 NEW_BIT (NEW_TEXT_BIT); 2925 NEW_BIT (NEW_TEXT_BIT);
2897 NEW_BIT (NEW_SEP_BIT); 2926 NEW_BIT (NEW_SEP_BIT);
2898 } else if (!g_strncasecmp (tag, "<FONT ", strlen ("<FONT "))) { 2927 break;
2899 gchar *t, *e, *a, *value; 2928 case 27: /* /FONT */
2900 FontDetail *font = NULL; 2929 if (fonts) {
2901 GdkColor *clr; 2930 FontDetail *font = fonts->data;
2902 gint saw; 2931 NEW_BIT (NEW_TEXT_BIT);
2903 gint i; 2932 fonts = g_slist_remove (fonts, font);
2904 2933 if (font->face)
2905 t = tag + strlen ("<FONT "); 2934 g_free (font->face);
2906 2935 if (font->fore)
2907 while (*t != '\0') { 2936 gdk_color_free (font->fore);
2908 value = NULL; 2937 if (font->back)
2909 saw = 0; 2938 gdk_color_free (font->back);
2910 2939 g_free (font);
2911 while (g_strncasecmp (t, "COLOR=", strlen ("COLOR="))
2912 && g_strncasecmp (t, "BACK=", strlen ("BACK="))
2913 && g_strncasecmp (t, "FACE=", strlen ("FACE="))
2914 && g_strncasecmp (t, "SIZE=", strlen ("SIZE="))) {
2915 gboolean quote = FALSE;
2916 if (*t == '\0') break;
2917 while (*t && !((*t == ' ') && !quote)) {
2918 if (*t == '\"')
2919 quote = ! quote;
2920 t++;
2921 }
2922 while (*t && (*t == ' ')) t++;
2923 }
2924
2925 if (!g_strncasecmp (t, "COLOR=", strlen ("COLOR="))) {
2926 t += strlen ("COLOR=");
2927 saw = 1;
2928 } else if (!g_strncasecmp (t, "BACK=", strlen ("BACK="))) {
2929 t += strlen ("BACK=");
2930 saw = 2;
2931 } else if (!g_strncasecmp (t, "FACE=", strlen ("FACE="))) {
2932 t += strlen ("FACE=");
2933 saw = 3;
2934 } else if (!g_strncasecmp (t, "SIZE=", strlen ("SIZE="))) {
2935 t += strlen ("SIZE=");
2936 saw = 4;
2937 }
2938
2939 if (!saw)
2940 continue;
2941
2942 if ((*t == '\"') || (*t == '\'')) {
2943 e = a = ++t;
2944 while (*e && (*e != *(t - 1))) e++;
2945 if (*e != '\0') {
2946 *e = '\0';
2947 t = e + 1;
2948 value = g_strdup (a);
2949 } else {
2950 *t = '\0';
2951 }
2952 } else {
2953 e = a = t;
2954 while (*e && !isspace ((gint) *e)) e++;
2955 if (*e == '\0') e--;
2956 *e = '\0';
2957 t = e + 1;
2958 value = g_strdup (a);
2959 }
2960
2961 if (value == NULL)
2962 continue;
2963
2964 if (font == NULL)
2965 font = g_new0 (FontDetail, 1);
2966
2967 switch (saw) {
2968 case 1:
2969 clr = gtk_imhtml_get_color (value);
2970 if (clr != NULL) {
2971 if ( (font->fore == NULL) &&
2972 !(options & GTK_IMHTML_NO_COLOURS))
2973 font->fore = clr;
2974 }
2975 break;
2976 case 2:
2977 clr = gtk_imhtml_get_color (value);
2978 if (clr != NULL) {
2979 if ( (font->back == NULL) &&
2980 !(options & GTK_IMHTML_NO_COLOURS))
2981 font->back = clr;
2982 }
2983 break;
2984 case 3:
2985 if ( (font->face == NULL) &&
2986 !(options & GTK_IMHTML_NO_FONTS))
2987 font->face = g_strdup (value);
2988 break;
2989 case 4:
2990 if ((font->size != 0) ||
2991 (options & GTK_IMHTML_NO_SIZES))
2992 break;
2993
2994 if (isdigit ((gint) value [0])) {
2995 for (i = 0; i < strlen (value); i++)
2996 if (!isdigit ((gint) value [i]))
2997 break;
2998 if (i != strlen (value))
2999 break;
3000
3001 sscanf (value, "%hd", &font->size);
3002 break;
3003 }
3004
3005 if ((value [0] == '+') && (value [1] != '\0')) {
3006 for (i = 1; i < strlen (value); i++)
3007 if (!isdigit ((gint) value [i]))
3008 break;
3009 if (i != strlen (value))
3010 break;
3011
3012 sscanf (value + 1, "%hd", &font->size);
3013 font->size += DEFAULT_FONT_SIZE;
3014 break;
3015 }
3016
3017 if ((value [0] == '-') && (value [1] != '\0')) {
3018 for (i = 1; i < strlen (value); i++)
3019 if (!isdigit ((gint) value [i]))
3020 break;
3021 if (i != strlen (value))
3022 break;
3023
3024 sscanf (value + 1, "%hd", &font->size);
3025 font->size = MIN (font->size, 2);
3026 font->size = DEFAULT_FONT_SIZE - font->size;
3027 break;
3028 }
3029
3030 break;
3031 }
3032
3033 g_free (value);
3034 } 2940 }
3035 2941 break;
3036 if (!font || !(font->size || font->face || font->fore || font->back)) { 2942 case 28: /* /A */
3037 g_free (font); 2943 if (url) {
3038 intag = FALSE; 2944 NEW_BIT (NEW_TEXT_BIT);
3039 tpos = 0; 2945 g_free (url);
3040 continue; 2946 url = NULL;
3041 } 2947 }
3042 2948 break;
2949 case 29: /* P */
2950 case 30: /* /P */
2951 case 31: /* H3 */
2952 case 32: /* /H3 */
2953 case 33: /* HTML */
2954 case 34: /* /HTML */
2955 case 35: /* BODY */
2956 case 36: /* /BODY */
2957 case 37: /* FONT */
2958 case 38: /* HEAD */
2959 case 39: /* /HEAD */
2960 break;
2961
2962 case 40: /* HR (opt) */
3043 NEW_BIT (NEW_TEXT_BIT); 2963 NEW_BIT (NEW_TEXT_BIT);
2964 NEW_BIT (NEW_SEP_BIT);
2965 break;
2966 case 41: /* FONT (opt) */
2967 {
2968 gchar *color, *back, *face, *size;
2969 FontDetail *font;
2970
2971 color = gtk_imhtml_get_html_opt (tag, "COLOR=");
2972 back = gtk_imhtml_get_html_opt (tag, "BACK=");
2973 face = gtk_imhtml_get_html_opt (tag, "FACE=");
2974 size = gtk_imhtml_get_html_opt (tag, "SIZE=");
2975
2976 if (!(color || back || face || size))
2977 break;
2978
2979 NEW_BIT (NEW_TEXT_BIT);
2980
2981 font = g_new0 (FontDetail, 1);
2982 if (color && !(options & GTK_IMHTML_NO_COLOURS))
2983 font->fore = gtk_imhtml_get_color (color);
2984 if (back && !(options & GTK_IMHTML_NO_COLOURS))
2985 font->back = gtk_imhtml_get_color (back);
2986 if (face && !(options & GTK_IMHTML_NO_FONTS))
2987 font->face = g_strdup (face);
2988 if (size && !(options & GTK_IMHTML_NO_SIZES))
2989 sscanf (size, "%hd", &font->size);
2990
2991 g_free (color);
2992 g_free (back);
2993 g_free (face);
2994 g_free (size);
3044 2995
3045 if (fonts) { 2996 if (fonts) {
3046 FontDetail *oldfont = fonts->data; 2997 FontDetail *oldfont = fonts->data;
3047 if (!font->size) 2998 if (!font->size)
3048 font->size = oldfont->size; 2999 font->size = oldfont->size;
3049 if (!font->face && oldfont->face) 3000 if (!font->face && oldfont->face)
3050 font->face = g_strdup (oldfont->face); 3001 font->face = g_strdup (oldfont->face);
3051 if (!font->fore && oldfont->fore) 3002 if (!font->fore && oldfont->fore)
3052 font->fore = gdk_color_copy (oldfont->fore); 3003 font->fore = gdk_color_copy (oldfont->fore);
3053 if (!font->back && oldfont->back) 3004 if (!font->back && oldfont->back)
3054 font->back = gdk_color_copy (oldfont->back); 3005 font->back = gdk_color_copy (oldfont->back);
3056 if (!font->size) 3007 if (!font->size)
3057 font->size = DEFAULT_FONT_SIZE; 3008 font->size = DEFAULT_FONT_SIZE;
3058 } 3009 }
3059 3010
3060 fonts = g_slist_prepend (fonts, font); 3011 fonts = g_slist_prepend (fonts, font);
3061 got_tag = TRUE; 3012 }
3062 } else if (!g_strcasecmp (tag, "</FONT>")) { 3013 break;
3063 FontDetail *font; 3014 case 42: /* BODY (opt) */
3064 3015 {
3065 if (fonts) { 3016 gchar *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR=");
3066 got_tag = TRUE; 3017 if (bgcolor) {
3067 NEW_BIT (NEW_TEXT_BIT); 3018 GdkColor *tmp = gtk_imhtml_get_color (bgcolor);
3068 font = fonts->data; 3019 g_free (bgcolor);
3069 fonts = g_slist_remove (fonts, font); 3020 if (tmp) {
3070 if (font->face) 3021 NEW_BIT (NEW_TEXT_BIT);
3071 g_free (font->face); 3022 bg = tmp;
3072 if (font->fore) 3023 UPDATE_BG_COLORS;
3073 gdk_color_free (font->fore);
3074 if (font->back)
3075 gdk_color_free (font->back);
3076 g_free (font);
3077 } else {
3078 intag = FALSE;
3079 tpos = 0;
3080 continue;
3081 }
3082 } else if (!g_strncasecmp (tag, "<BODY ", strlen ("<BODY "))) {
3083 gchar *t, *e, *color = NULL;
3084 GdkColor *tmp;
3085
3086 got_tag = TRUE;
3087
3088 if (!(options & GTK_IMHTML_NO_COLOURS)) {
3089 t = tag + strlen ("<BODY");
3090 do {
3091 gboolean quote = FALSE;
3092 if (*t == '\0') break;
3093 while (*t && !((*t == ' ') && !quote)) {
3094 if (*t == '\"')
3095 quote = ! quote;
3096 t++;
3097 }
3098 while (*t && (*t == ' ')) t++;
3099 } while (g_strncasecmp (t, "BGCOLOR=", strlen ("BGCOLOR=")));
3100
3101 if (!g_strncasecmp (t, "BGCOLOR=", strlen ("BGCOLOR="))) {
3102 t += strlen ("BGCOLOR=");
3103 if ((*t == '\"') || (*t == '\'')) {
3104 e = ++t;
3105 while (*e && (*e != *(t - 1))) e++;
3106 if (*e != '\0') {
3107 *e = '\0';
3108 color = g_strdup (t);
3109 }
3110 } else {
3111 e = t;
3112 while (*e && !isspace ((gint) *e)) e++;
3113 if (*e == '\0') e--;
3114 *e = '\0';
3115 color = g_strdup (t);
3116 }
3117
3118 if (color != NULL) {
3119 tmp = gtk_imhtml_get_color (color);
3120 g_free (color);
3121 if (tmp != NULL) {
3122 NEW_BIT (NEW_TEXT_BIT);
3123 bg = tmp;
3124 UPDATE_BG_COLORS;
3125 }
3126 }
3127 } 3024 }
3128 } 3025 }
3129 } else if (!g_strncasecmp (tag, "<A ", strlen ("<A "))) { 3026 }
3130 gchar *t, *e; 3027 break;
3131 3028 case 43: /* A (opt) */
3132 got_tag = TRUE; 3029 {
3133 NEW_BIT (NEW_TEXT_BIT); 3030 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF=");
3134 3031 if (href) {
3135 if (url != NULL)
3136 g_free (url);
3137 url = NULL;
3138
3139 t = tag + strlen ("<A");
3140 do {
3141 gboolean quote = FALSE;
3142 if (*t == '\0') break;
3143 while (*t && !((*t == ' ') && !quote)) {
3144 if (*t == '\"')
3145 quote = ! quote;
3146 t++;
3147 }
3148 while (*t && (*t == ' ')) t++;
3149 } while (g_strncasecmp (t, "HREF=", strlen ("HREF=")));
3150
3151 if (!g_strncasecmp (t, "HREF=", strlen ("HREF="))) {
3152 t += strlen ("HREF=");
3153 if ((*t == '\"') || (*t == '\'')) {
3154 e = ++t;
3155 while (*e && (*e != *(t - 1))) e++;
3156 if (*e != '\0') {
3157 *e = '\0';
3158 url = g_strdup (t);
3159 }
3160 } else {
3161 e = t;
3162 while (*e && !isspace ((gint) *e)) e++;
3163 if (*e == '\0') e--;
3164 *e = '\0';
3165 url = g_strdup (t);
3166 }
3167 }
3168 } else if (!g_strcasecmp (tag, "</A>")) {
3169 if (url != NULL) {
3170 got_tag = TRUE;
3171 NEW_BIT (NEW_TEXT_BIT); 3032 NEW_BIT (NEW_TEXT_BIT);
3172 g_free (url); 3033 g_free (url);
3173 url = NULL; 3034 url = href;
3174 } else {
3175 intag = FALSE;
3176 tpos = 0;
3177 continue;
3178 } 3035 }
3179 } else if (!g_strncasecmp (tag, "<IMG ", strlen ("<IMG "))) { 3036 }
3180 gchar *t, *e, *src = NULL; 3037 break;
3181 gchar *copy = g_strdup (tag); 3038 case 44: /* IMG (opt) */
3039 {
3040 gchar *src = gtk_imhtml_get_html_opt (tag, "SRC=");
3182 gchar **xpm; 3041 gchar **xpm;
3183 GdkColor *clr = NULL; 3042 GdkColor *clr;
3184 GtkIMHtmlBit *bit; 3043 GtkIMHtmlBit *bit;
3185 3044
3186 intag = FALSE; 3045 if (!src)
3187 tpos = 0; 3046 break;
3188 3047
3189 if (imhtml->img == NULL) { 3048 if (!imhtml->img || ((xpm = imhtml->img (src)) == NULL)) {
3190 ws [wpos] = 0; 3049 g_free (src);
3191 strcat (ws, copy); 3050 break;
3192 wpos = strlen (ws);
3193 g_free (copy);
3194 continue;
3195 } 3051 }
3196
3197 t = tag + strlen ("<IMG");
3198 do {
3199 gboolean quote = FALSE;
3200 if (*t == '\0') break;
3201 while (*t && !((*t == ' ') && !quote)) {
3202 if (*t == '\"')
3203 quote = ! quote;
3204 t++;
3205 }
3206 while (*t && (*t == ' ')) t++;
3207 } while (g_strncasecmp (t, "SRC=", strlen ("SRC=")));
3208
3209 if (!g_strncasecmp (t, "SRC=", strlen ("SRC="))) {
3210 t += strlen ("SRC=");
3211 if ((*t == '\"') || (*t == '\'')) {
3212 e = ++t;
3213 while (*e && (*e != *(t - 1))) e++;
3214 if (*e != '\0') {
3215 *e = '\0';
3216 src = g_strdup (t);
3217 }
3218 } else {
3219 e = t;
3220 while (*e && !isspace ((gint) *e)) e++;
3221 if (*e == '\0') e--;
3222 *e = '\0';
3223 src = g_strdup (t);
3224 }
3225 }
3226
3227 if (src == NULL) {
3228 ws [wpos] = 0;
3229 strcat (ws, copy);
3230 wpos = strlen (ws);
3231 g_free (copy);
3232 continue;
3233 }
3234
3235 xpm = (* imhtml->img) (src);
3236 if (xpm == NULL) {
3237 g_free (src);
3238 ws [wpos] = 0;
3239 strcat (ws, copy);
3240 wpos = strlen (ws);
3241 g_free (copy);
3242 continue;
3243 }
3244
3245 g_free (copy);
3246 3052
3247 if (!fonts || ((clr = ((FontDetail *) fonts->data)->back) == NULL)) 3053 if (!fonts || ((clr = ((FontDetail *) fonts->data)->back) == NULL))
3248 clr = (bg != NULL) ? bg : imhtml->default_bg_color; 3054 clr = (bg != NULL) ? bg : imhtml->default_bg_color;
3249 3055
3250 if (!GTK_WIDGET_REALIZED (imhtml)) 3056 if (!GTK_WIDGET_REALIZED (imhtml))
3251 gtk_widget_realize (GTK_WIDGET (imhtml)); 3057 gtk_widget_realize (GTK_WIDGET (imhtml));
3252 3058
3253 bit = g_new0 (GtkIMHtmlBit, 1); 3059 bit = g_new0 (GtkIMHtmlBit, 1);
3254 bit->type = TYPE_IMG; 3060 bit->type = TYPE_IMG;
3255 bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window, 3061 bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window,
3256 &bit->bm, 3062 &bit->bm, clr, xpm);
3257 clr,
3258 xpm);
3259 if (url) 3063 if (url)
3260 bit->url = g_strdup (url); 3064 bit->url = g_strdup (url);
3261 3065
3262 NEW_BIT (bit); 3066 NEW_BIT (bit);
3263 3067
3264 g_free (src); 3068 g_free (src);
3265
3266 continue;
3267 } else if (!g_strcasecmp (tag, "<P>") ||
3268 !g_strcasecmp (tag, "</P>") ||
3269 !g_strncasecmp (tag, "<P ", strlen ("<P ")) ||
3270 !g_strcasecmp (tag, "<H3>") ||
3271 !g_strncasecmp (tag, "<H3 ", strlen ("<H3 ")) ||
3272 !g_strcasecmp (tag, "</H3>") ||
3273 !g_strcasecmp (tag, "<HTML>") ||
3274 !g_strcasecmp (tag, "</HTML>") ||
3275 !g_strcasecmp (tag, "<BODY>") ||
3276 !g_strcasecmp (tag, "</BODY>") ||
3277 !g_strcasecmp (tag, "<FONT>") ||
3278 !g_strcasecmp (tag, "<HEAD>") ||
3279 !g_strcasecmp (tag, "</HEAD>")) {
3280 intag = FALSE;
3281 tpos = 0;
3282 continue;
3283 } 3069 }
3284 3070 break;
3285 if (!got_tag) { 3071 case 45: /* P (opt) */
3286 char *d; 3072 case 46: /* H3 (opt) */
3287 tag [tpos] = 0; 3073 break;
3288 d = tag; 3074 case 47: /* comment */
3289 while (*d) { 3075 NEW_BIT (NEW_TEXT_BIT);
3290 if ((smilelen = gtk_imhtml_is_smiley (imhtml, d)) != 0) { 3076 wpos = g_snprintf (ws, len, "%s", tag);
3291 ws [wpos] = 0; 3077 NEW_BIT (NEW_COMMENT_BIT);
3292 wpos = 0; 3078 break;
3293 NEW_BIT (NEW_TEXT_BIT); 3079 default:
3294 g_snprintf (ws, smilelen + 1, "%s", d); 3080 break;
3295 NEW_BIT (NEW_SMILEY_BIT);
3296 d += smilelen;
3297 } else if (*d == '&') {
3298 gchar replace;
3299 gint length;
3300 if (is_amp_escape (d, &replace, &length)) {
3301 ws [wpos++] = replace;
3302 d += length;
3303 } else {
3304 ws [wpos++] = *d++;
3305 }
3306 } else if (*d == '\n') {
3307 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
3308 ws [wpos] = 0;
3309 wpos = 0;
3310 NEW_BIT (NEW_TEXT_BIT);
3311 NEW_BIT (NEW_BR_BIT);
3312 }
3313 d++;
3314 } else {
3315 ws [wpos++] = *d++;
3316 }
3317 }
3318 tpos = 0;
3319 } else {
3320 wpos = 0;
3321 } 3081 }
3322 intag = FALSE; 3082 g_free (tag);
3323 tpos = 0; 3083 c += tlen;
3324 } else if (*c == '&' && !intag) { 3084 pos += tlen;
3325 gchar replace; 3085 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &amp, &tlen)) {
3326 gint length; 3086 ws [wpos++] = amp;
3327 if (is_amp_escape (c, &replace, &length)) { 3087 c += tlen;
3328 ws [wpos++] = replace; 3088 pos += tlen;
3329 c += length;
3330 } else {
3331 ws [wpos++] = *c++;
3332 }
3333 } else if (intag) {
3334 if (*c == '\"')
3335 tagquote++;
3336 tag [tpos++] = *c++;
3337 } else if (incomment) {
3338 ws [wpos++] = *c++;
3339 } else if (((smilelen = gtk_imhtml_is_smiley (imhtml, c)) != 0)) {
3340 ws [wpos] = 0;
3341 wpos = 0;
3342 NEW_BIT (NEW_TEXT_BIT);
3343 g_snprintf (ws, smilelen + 1, "%s", c);
3344 NEW_BIT (NEW_SMILEY_BIT);
3345 c += smilelen;
3346 } else if (*c == '\n') { 3089 } else if (*c == '\n') {
3347 if (!(options & GTK_IMHTML_NO_NEWLINE)) { 3090 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
3348 ws [wpos] = 0; 3091 ws [wpos] = 0;
3349 wpos = 0; 3092 wpos = 0;
3350 NEW_BIT (NEW_TEXT_BIT); 3093 NEW_BIT (NEW_TEXT_BIT);
3351 NEW_BIT (NEW_BR_BIT); 3094 NEW_BIT (NEW_BR_BIT);
3352 } 3095 }
3353 c++; 3096 c++;
3097 pos++;
3098 } else if (gtk_imhtml_is_smiley (imhtml, c, &smilelen)) {
3099 ws [wpos] = 0;
3100 wpos = 0;
3101 NEW_BIT (NEW_TEXT_BIT);
3102 g_snprintf (ws, smilelen + 1, "%s", c);
3103 wpos = smilelen + 1;
3104 NEW_BIT (NEW_SMILEY_BIT);
3105 c += smilelen;
3106 pos += smilelen;
3107 } else if (*c) {
3108 ws [wpos++] = *c++;
3109 pos++;
3354 } else { 3110 } else {
3355 ws [wpos++] = *c++; 3111 break;
3356 }
3357 }
3358
3359 if (intag) {
3360 tag [tpos] = 0;
3361 c = tag;
3362 while (*c) {
3363 if ((smilelen = gtk_imhtml_is_smiley (imhtml, c)) != 0) {
3364 ws [wpos] = 0;
3365 wpos = 0;
3366 NEW_BIT (NEW_TEXT_BIT);
3367 g_snprintf (ws, smilelen + 1, "%s", c);
3368 NEW_BIT (NEW_SMILEY_BIT);
3369 c += smilelen;
3370 } else if (*c == '&') {
3371 gchar replace;
3372 gint length;
3373 if (is_amp_escape (c, &replace, &length)) {
3374 ws [wpos++] = replace;
3375 c += length;
3376 } else {
3377 ws [wpos++] = *c++;
3378 }
3379 } else if (*c == '\n') {
3380 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
3381 ws [wpos] = 0;
3382 wpos = 0;
3383 NEW_BIT (NEW_TEXT_BIT);
3384 NEW_BIT (NEW_BR_BIT);
3385 }
3386 c++;
3387 } else {
3388 ws [wpos++] = *c++;
3389 }
3390 }
3391 } else if (incomment) {
3392 ws [wpos] = 0;
3393 wpos = 0;
3394 strcat (tag, ws);
3395 ws [wpos] = 0;
3396 c = tag;
3397 while (*c) {
3398 if ((smilelen = gtk_imhtml_is_smiley (imhtml, c)) != 0) {
3399 ws [wpos] = 0;
3400 wpos = 0;
3401 NEW_BIT (NEW_TEXT_BIT);
3402 g_snprintf (ws, smilelen + 1, "%s", c);
3403 NEW_BIT (NEW_SMILEY_BIT);
3404 c += smilelen;
3405 } else if (*c == '&') {
3406 gchar replace;
3407 gint length;
3408 if (is_amp_escape (c, &replace, &length)) {
3409 ws [wpos++] = replace;
3410 c += length;
3411 } else {
3412 ws [wpos++] = *c++;
3413 }
3414 } else if (*c == '\n') {
3415 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
3416 ws [wpos] = 0;
3417 wpos = 0;
3418 NEW_BIT (NEW_TEXT_BIT);
3419 NEW_BIT (NEW_BR_BIT);
3420 }
3421 c++;
3422 } else {
3423 ws [wpos++] = *c++;
3424 }
3425 } 3112 }
3426 } 3113 }
3427 3114
3428 ws [wpos] = 0; 3115 ws [wpos] = 0;
3429 NEW_BIT (NEW_TEXT_BIT); 3116 NEW_BIT (NEW_TEXT_BIT);
3516 retval = g_string_append (retval, "</PRE>"); 3203 retval = g_string_append (retval, "</PRE>");
3517 pre--; 3204 pre--;
3518 } 3205 }
3519 } 3206 }
3520 g_free (ws); 3207 g_free (ws);
3521 g_free (tag);
3522 3208
3523 return retval; 3209 return retval;
3524 } 3210 }
3525 3211
3526 void 3212 void
3560 g_free (li); 3246 g_free (li);
3561 } 3247 }
3562 g_free (bit); 3248 g_free (bit);
3563 } 3249 }
3564 3250
3565 while (imhtml->urls) { 3251 while (imhtml->click) {
3566 g_free (imhtml->urls->data); 3252 g_free (imhtml->click->data);
3567 imhtml->urls = g_list_remove (imhtml->urls, imhtml->urls->data); 3253 imhtml->click = g_list_remove (imhtml->click, imhtml->click->data);
3568 } 3254 }
3569 3255
3570 if (imhtml->selected_text) { 3256 if (imhtml->selected_text) {
3571 g_string_free (imhtml->selected_text, TRUE); 3257 g_string_free (imhtml->selected_text, TRUE);
3572 imhtml->selected_text = g_string_new (""); 3258 imhtml->selected_text = g_string_new ("");
3590 3276
3591 if (imhtml->scroll_timer) { 3277 if (imhtml->scroll_timer) {
3592 gtk_timeout_remove (imhtml->scroll_timer); 3278 gtk_timeout_remove (imhtml->scroll_timer);
3593 imhtml->scroll_timer = 0; 3279 imhtml->scroll_timer = 0;
3594 } 3280 }
3595
3596 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor);
3597 3281
3598 imhtml->x = 0; 3282 imhtml->x = 0;
3599 imhtml->y = TOP_BORDER; 3283 imhtml->y = TOP_BORDER;
3600 imhtml->xsize = 0; 3284 imhtml->xsize = 0;
3601 imhtml->llheight = 0; 3285 imhtml->llheight = 0;
3614 layout->vadjustment->page_increment = 0; 3298 layout->vadjustment->page_increment = 0;
3615 layout->vadjustment->lower = 0; 3299 layout->vadjustment->lower = 0;
3616 layout->vadjustment->upper = imhtml->y; 3300 layout->vadjustment->upper = imhtml->y;
3617 gtk_adjustment_set_value (layout->vadjustment, 0); 3301 gtk_adjustment_set_value (layout->vadjustment, 0);
3618 3302
3619 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed"); 3303 if (GTK_WIDGET_REALIZED (GTK_WIDGET (imhtml))) {
3620 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed"); 3304 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor);
3621
3622 if (GTK_WIDGET_REALIZED (GTK_WIDGET (imhtml)))
3623 gdk_window_clear (GTK_LAYOUT (imhtml)->bin_window); 3305 gdk_window_clear (GTK_LAYOUT (imhtml)->bin_window);
3306 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
3307 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
3308 }
3624 } 3309 }
3625 3310
3626 void 3311 void
3627 gtk_imhtml_page_up (GtkIMHtml *imhtml) 3312 gtk_imhtml_page_up (GtkIMHtml *imhtml)
3628 { 3313 {