comparison src/gtkimhtml.c @ 3922:30f52e7afd1d

[gaim-migrate @ 4094] This is gtkimhtml2--it's a subclass of gtktextview. It's not done yet. It doesn't do smileys or images, and what it does do so far, it doesn't do perfectly. But it's perfectly 100% usable, and like 80,000 times faster than gtkimhtml + Pango. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Fri, 08 Nov 2002 06:10:35 +0000
parents 988485669631
children fb60cd7a2506
comparison
equal deleted inserted replaced
3921:67209a7ee924 3922:30f52e7afd1d
21 21
22 #ifdef HAVE_CONFIG_H 22 #ifdef HAVE_CONFIG_H
23 #include <config.h> 23 #include <config.h>
24 #endif 24 #endif
25 #include "gtkimhtml.h" 25 #include "gtkimhtml.h"
26
27 #ifndef _WIN32
28 #include <X11/Xlib.h>
29 #include <gdk/gdkx.h>
30 #else
31 #include <gdk/gdkwin32.h>
32 #endif
33
34 #include <stdlib.h>
35 #include <gtk/gtk.h> 26 #include <gtk/gtk.h>
36 #include <string.h> 27 #include <string.h>
37 #include <ctype.h> 28 #include <ctype.h>
38 #include <stdio.h> 29 #include <stdio.h>
39 #include <math.h> 30 #include <math.h>
40 #ifdef HAVE_LANGINFO_CODESET 31 #ifdef HAVE_LANGINFO_CODESET
41 #include <langinfo.h> 32 #include <langinfo.h>
42 #include <locale.h> 33 #include <locale.h>
43 #endif 34 #endif
44 35
45 #ifdef _WIN32 36
46 /* GDK_SELECTION_PRIMARY is ignored win32 GTK */ 37 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a
47 #undef GDK_SELECTION_PRIMARY 38 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */
48 #define GDK_SELECTION_PRIMARY GDK_SELECTION_CLIPBOARD
49 #endif
50
51 #include <gdk-pixbuf/gdk-pixbuf.h>
52 #include <gdk-pixbuf/gdk-pixbuf-loader.h>
53
54 #include <pango/pango.h>
55
56 #include "pixmaps/angel.xpm"
57 #include "pixmaps/bigsmile.xpm"
58 #include "pixmaps/burp.xpm"
59 #include "pixmaps/crossedlips.xpm"
60 #include "pixmaps/cry.xpm"
61 #include "pixmaps/embarrassed.xpm"
62 #include "pixmaps/kiss.xpm"
63 #include "pixmaps/moneymouth.xpm"
64 #include "pixmaps/sad.xpm"
65 #include "pixmaps/scream.xpm"
66 #include "pixmaps/smile.xpm"
67 #include "pixmaps/smile8.xpm"
68 #include "pixmaps/think.xpm"
69 #include "pixmaps/tongue.xpm"
70 #include "pixmaps/wink.xpm"
71 #include "pixmaps/yell.xpm"
72
73 #define MAX_FONT_SIZE 7 39 #define MAX_FONT_SIZE 7
74
75 #define POINT_SIZE(x) (_point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) 40 #define POINT_SIZE(x) (_point_sizes [MIN ((x), MAX_FONT_SIZE) - 1])
76 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; 41 static gint _point_sizes [] = { 4, 6, 8, 10, 20, 30, 40 };
77 42
78 #define DEFAULT_PRE_FACE "sans" 43 /* The four elements present in a <FONT> tag contained in a struct */
79
80 #define BORDER_SIZE 2
81 #define TOP_BORDER 10
82 #define MIN_HEIGHT 20
83 #define HR_HEIGHT 2
84 #define TOOLTIP_TIMEOUT 500
85
86 #define DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))
87 #define COLOR_MOD 0x8000
88 #define COLOR_DIFF 0x800
89
90 #define TYPE_TEXT 0
91 #define TYPE_SMILEY 1
92 #define TYPE_IMG 2
93 #define TYPE_SEP 3
94 #define TYPE_BR 4
95 #define TYPE_COMMENT 5
96
97 #define GTK_IMHTML_GET_STYLE_FONT(style) gtk_style_get_font (style)
98
99 #define DRAW_IMG(x) (((x)->type == TYPE_IMG) || (imhtml->smileys && ((x)->type == TYPE_SMILEY)))
100
101 typedef struct _GtkIMHtmlBit GtkIMHtmlBit;
102 typedef struct _FontDetail FontDetail; 44 typedef struct _FontDetail FontDetail;
103
104 struct _GtkSmileyTree {
105 GString *values;
106 GtkSmileyTree **children;
107 gchar **image;
108 };
109
110 /*
111 * PROTOS
112 */
113 extern void debug_printf(char * fmt, ...);
114
115 static GtkSmileyTree*
116 gtk_smiley_tree_new ()
117 {
118 return g_new0 (GtkSmileyTree, 1);
119 }
120
121 static void
122 gtk_smiley_tree_insert (GtkSmileyTree *tree,
123 const gchar *text,
124 gchar **image)
125 {
126 GtkSmileyTree *t = tree;
127 const gchar *x = text;
128
129 if (!strlen (x))
130 return;
131
132 while (*x) {
133 gchar *pos;
134 gint index;
135
136 if (!t->values)
137 t->values = g_string_new ("");
138
139 pos = strchr (t->values->str, *x);
140 if (!pos) {
141 t->values = g_string_append_c (t->values, *x);
142 index = t->values->len - 1;
143 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *));
144 t->children [index] = g_new0 (GtkSmileyTree, 1);
145 } else
146 index = (int) pos - (int) t->values->str;
147
148 t = t->children [index];
149
150 x++;
151 }
152
153 t->image = image;
154 }
155
156 static void
157 gtk_smiley_tree_remove (GtkSmileyTree *tree,
158 const gchar *text)
159 {
160 GtkSmileyTree *t = tree;
161 const gchar *x = text;
162 gint len = 0;
163
164 while (*x) {
165 gchar *pos;
166
167 if (!t->values)
168 return;
169
170 pos = strchr (t->values->str, *x);
171 if (pos)
172 t = t->children [(int) pos - (int) t->values->str];
173 else
174 return;
175
176 x++; len++;
177 }
178
179 if (t->image)
180 t->image = NULL;
181 }
182
183 static gint
184 gtk_smiley_tree_lookup (GtkSmileyTree *tree,
185 const gchar *text)
186 {
187 GtkSmileyTree *t = tree;
188 const gchar *x = text;
189 gint len = 0;
190
191 while (*x) {
192 gchar *pos;
193
194 if (!t->values)
195 break;
196
197 pos = strchr (t->values->str, *x);
198 if (pos)
199 t = t->children [(int) pos - (int) t->values->str];
200 else
201 break;
202
203 x++; len++;
204 }
205
206 if (t->image)
207 return len;
208
209 return 0;
210 }
211
212 static gchar**
213 gtk_smiley_tree_image (GtkSmileyTree *tree,
214 const gchar *text)
215 {
216 GtkSmileyTree *t = tree;
217 const gchar *x = text;
218
219 while (*x) {
220 gchar *pos;
221
222 if (!t->values)
223 return NULL;
224
225 pos = strchr (t->values->str, *x);
226 if (pos) {
227 t = t->children [(int) pos - (int) t->values->str];
228 } else
229 return NULL;
230
231 x++;
232 }
233
234 return t->image;
235 }
236
237 static void
238 gtk_smiley_tree_destroy (GtkSmileyTree *tree)
239 {
240 GSList *list = g_slist_append (NULL, tree);
241
242 while (list) {
243 GtkSmileyTree *t = list->data;
244 gint i;
245 list = g_slist_remove(list, t);
246 if (t->values) {
247 for (i = 0; i < t->values->len; i++)
248 list = g_slist_append (list, t->children [i]);
249 g_string_free (t->values, TRUE);
250 g_free (t->children);
251 }
252 g_free (t);
253 }
254 }
255
256 void
257 gtk_imhtml_remove_smileys (GtkIMHtml *imhtml)
258 {
259 g_return_if_fail (imhtml != NULL);
260 g_return_if_fail (GTK_IS_IMHTML (imhtml));
261
262 gtk_smiley_tree_destroy (imhtml->smiley_data);
263 imhtml->smiley_data = gtk_smiley_tree_new ();
264 }
265
266 void
267 gtk_imhtml_reset_smileys (GtkIMHtml *imhtml)
268 {
269 gtk_imhtml_remove_smileys(imhtml);
270 gtk_imhtml_init_smileys (imhtml);
271 }
272
273
274 struct im_image {
275 gchar *filename;
276
277 gint len;
278 gpointer data;
279
280 gint x,y;
281 gint width,height;
282 GtkIMHtml *imhtml;
283 GtkIMHtmlBit *bit;
284 GdkPixbuf *pb;
285 };
286
287 struct _GtkIMHtmlBit {
288 gint type;
289
290 gchar *text;
291 struct im_image *img;
292 GdkPixmap *pm;
293 GdkBitmap *bm;
294
295 PangoFontDescription *font;
296 GdkColor *fore;
297 GdkColor *back;
298 GdkColor *bg;
299 gboolean underline;
300 gboolean strike;
301 gchar *url;
302
303 GList *chunks;
304 };
305
306 struct _FontDetail { 45 struct _FontDetail {
307 gushort size; 46 gushort size;
308 gchar *face; 47 gchar *face;
309 GdkColor *fore; 48 gchar *fore;
310 GdkColor *back; 49 gchar *back;
311 }; 50 };
312 51
313 struct line_info { 52 /* GtkIMHtml has one signal--URL_CLICKED */
314 gint x;
315 gint y;
316 gint width;
317 gint height;
318 gint ascent;
319
320 gboolean selected;
321 gchar *sel_start;
322 gchar *sel_end;
323
324 gchar *text;
325 GtkIMHtmlBit *bit;
326 };
327
328 struct clickable {
329 gint x;
330 gint y;
331 gint width;
332 gint height;
333 GtkIMHtml *imhtml;
334 GtkIMHtmlBit *bit;
335 };
336
337 static GtkLayoutClass *parent_class = NULL;
338
339 enum {
340 TARGET_STRING,
341 TARGET_TEXT,
342 TARGET_COMPOUND_TEXT
343 };
344
345 enum { 53 enum {
346 URL_CLICKED, 54 URL_CLICKED,
347 LAST_SIGNAL 55 LAST_SIGNAL
348 }; 56 };
349 static guint signals [LAST_SIGNAL] = { 0 }; 57 static guint signals [LAST_SIGNAL] = { 0 };
350 58
351 static void gtk_imhtml_draw_bit (GtkIMHtml *, GtkIMHtmlBit *); 59
352 static GdkColor *gtk_imhtml_get_color (const gchar *); 60 /* Boring GTK stuff */
353 static gint gtk_imhtml_motion_notify_event (GtkWidget *, GdkEventMotion *); 61 static void gtk_imhtml_class_init (GtkIMHtmlClass *class)
354 62 {
355 static void 63 GtkObjectClass *object_class;
356 gtk_imhtml_finalize (GObject *object) 64 object_class = (GtkObjectClass*) class;
357 { 65 signals[URL_CLICKED] = gtk_signal_new("url_clicked",
358 GtkIMHtml *imhtml; 66 GTK_RUN_FIRST,
359 67 GTK_CLASS_TYPE(object_class),
360 imhtml = GTK_IMHTML (object); 68 GTK_SIGNAL_OFFSET(GtkIMHtmlClass, url_clicked),
361 69 gtk_marshal_NONE__POINTER,
362 gtk_imhtml_clear (imhtml); 70 GTK_TYPE_NONE, 1,
363 71 GTK_TYPE_POINTER);
364 if (imhtml->selected_text) 72 }
365 g_string_free (imhtml->selected_text, TRUE); 73
366 74 static void gtk_imhtml_init (GtkIMHtml *imhtml)
367 if (imhtml->default_font) 75 {
368 pango_font_description_free (imhtml->default_font); 76 GtkTextIter iter;
369 if (imhtml->default_fg_color) 77 imhtml->text_buffer = gtk_text_buffer_new(NULL);
370 gdk_color_free (imhtml->default_fg_color); 78 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter);
371 if (imhtml->default_bg_color) 79 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE);
372 gdk_color_free (imhtml->default_bg_color); 80 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer);
373 if (imhtml->default_hl_color) 81 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD);
374 gdk_color_free (imhtml->default_hl_color); 82 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), FALSE);
375 if (imhtml->default_hlfg_color) 83 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5);
376 gdk_color_free (imhtml->default_hlfg_color); 84 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), FALSE);
377 85 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/
378 gdk_cursor_destroy (imhtml->hand_cursor);
379 gdk_cursor_destroy (imhtml->arrow_cursor);
380
381 gtk_smiley_tree_destroy (imhtml->smiley_data);
382
383 G_OBJECT_CLASS (parent_class)->finalize (object);
384 }
385
386 static void
387 gtk_imhtml_realize (GtkWidget *widget)
388 {
389 GtkIMHtml *imhtml;
390 GdkWindowAttr attributes;
391 gint attributes_mask;
392
393 g_return_if_fail (widget != NULL);
394 g_return_if_fail (GTK_IS_IMHTML (widget));
395
396 imhtml = GTK_IMHTML (widget);
397 GTK_WIDGET_SET_FLAGS (imhtml, GTK_REALIZED);
398
399 attributes.window_type = GDK_WINDOW_CHILD;
400 attributes.x = widget->allocation.x;
401 attributes.y = widget->allocation.y;
402 attributes.width = widget->allocation.width;
403 attributes.height = widget->allocation.height;
404 attributes.wclass = GDK_INPUT_OUTPUT;
405 attributes.visual = gtk_widget_get_visual (widget);
406 attributes.colormap = gtk_widget_get_colormap (widget);
407 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK;
408
409 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
410
411 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
412 &attributes, attributes_mask);
413 gdk_window_set_user_data (widget->window, widget);
414
415 attributes.x = widget->style->xthickness + BORDER_SIZE;
416 attributes.y = widget->style->xthickness + BORDER_SIZE;
417 attributes.width = MAX (1, (gint) widget->allocation.width - (gint) attributes.x * 2);
418 attributes.height = MAX (1, (gint) widget->allocation.height - (gint) attributes.y * 2);
419 attributes.event_mask = gtk_widget_get_events (widget)
420 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
421 | GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK;
422
423 GTK_LAYOUT (imhtml)->bin_window = gdk_window_new (widget->window,
424 &attributes, attributes_mask);
425 gdk_window_set_user_data (GTK_LAYOUT (imhtml)->bin_window, widget);
426
427 widget->style = gtk_style_attach (widget->style, widget->window);
428
429 gdk_window_set_cursor (widget->window, imhtml->arrow_cursor);
430
431 imhtml->context = gtk_widget_get_pango_context(widget);
432 imhtml->default_font = pango_font_description_copy(pango_context_get_font_description(imhtml->context));
433
434 gdk_window_set_background (widget->window, &widget->style->base [GTK_STATE_NORMAL]);
435 gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window,
436 &widget->style->base [GTK_STATE_NORMAL]);
437
438 imhtml->default_fg_color = gdk_color_copy (&GTK_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]);
439 imhtml->default_bg_color = gdk_color_copy (&GTK_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]);
440 imhtml->default_hl_color = gdk_color_copy (&GTK_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]);
441 imhtml->default_hlfg_color=gdk_color_copy (&GTK_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]);
442
443 gdk_window_show (GTK_LAYOUT (imhtml)->bin_window);
444 }
445
446 static gboolean
447 similar_colors (GdkColor *bg,
448 GdkColor *fg)
449 {
450 if ((DIFF (bg->red, fg->red) < COLOR_DIFF) &&
451 (DIFF (bg->green, fg->green) < COLOR_DIFF) &&
452 (DIFF (bg->blue, fg->blue) < COLOR_DIFF)) {
453 fg->red = (0xff00 - COLOR_MOD > bg->red) ?
454 bg->red + COLOR_MOD : bg->red - COLOR_MOD;
455 fg->green = (0xff00 - COLOR_MOD > bg->green) ?
456 bg->green + COLOR_MOD : bg->green - COLOR_MOD;
457 fg->blue = (0xff00 - COLOR_MOD > bg->blue) ?
458 bg->blue + COLOR_MOD : bg->blue - COLOR_MOD;
459 return TRUE;
460 }
461 return FALSE;
462 }
463
464 /* This is an expensive function! Don't blame me. I only stole it from eel */
465 static gint
466 text_width(PangoContext *context, PangoFontDescription *desc,
467 const char *text, gint len)
468 {
469 static PangoLayout *layout = NULL;
470 int width;
471
472 if (layout == NULL)
473 layout = pango_layout_new(context);
474
475 pango_layout_set_font_description(layout, desc);
476 pango_layout_set_text(layout, text, len);
477 pango_layout_get_pixel_size(layout, &width, NULL);
478
479 /* g_object_unref(G_OBJECT(layout)); */
480
481 return width;
482 }
483
484 static gint
485 string_width(PangoContext *context, PangoFontDescription *desc,
486 const char *text)
487 {
488 return text_width(context, desc, text, -1);
489 }
490
491 static void
492 set_layout_font(PangoLayout *layout, const char *text, guint len,
493 PangoFontDescription *desc)
494 {
495 PangoAttribute *attr;
496 PangoAttrList *list;
497
498 if (len == -1)
499 len = strlen(text);
500
501 attr = pango_attr_font_desc_new(desc);
502
503 attr->start_index = 0;
504 attr->end_index = len;
505
506 list = pango_attr_list_new();
507 pango_attr_list_insert(list, attr);
508
509 pango_layout_set_attributes(layout, list);
510 pango_attr_list_unref(list);
511
512 pango_layout_set_indent(layout, 0);
513 pango_layout_set_justify(layout, FALSE);
514 pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
515 }
516
517 static gint
518 get_layout_first_baseline(PangoLayout* layout)
519 {
520 PangoLayoutIter* iter = pango_layout_get_iter(layout);
521 gint result = pango_layout_iter_get_baseline(iter) / PANGO_SCALE;
522 pango_layout_iter_free(iter);
523 return result;
524 }
525
526 static void
527 draw_text (GtkIMHtml *imhtml,
528 struct line_info *line)
529 {
530 GtkIMHtmlBit *bit;
531 GdkGC *gc;
532 GdkColormap *cmap;
533 GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window;
534 gfloat xoff, yoff;
535 GdkColor *bg, *fg;
536 PangoLayout *layout;
537 PangoFontMetrics *metrics;
538 gchar *start = NULL, *end = NULL;
539
540 if (GTK_LAYOUT (imhtml)->freeze_count)
541 return;
542
543 bit = line->bit;
544 gc = gdk_gc_new (window);
545 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml));
546 xoff = GTK_LAYOUT (imhtml)->hadjustment->value;
547 yoff = GTK_LAYOUT (imhtml)->vadjustment->value;
548
549 if (bit->bg != NULL) {
550 gdk_color_alloc (cmap, bit->bg);
551 gdk_gc_set_foreground (gc, bit->bg);
552 bg = bit->bg;
553 } else {
554 gdk_color_alloc (cmap, imhtml->default_bg_color);
555 gdk_gc_set_foreground (gc, imhtml->default_bg_color);
556 bg = imhtml->default_bg_color;
557 }
558
559 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff,
560 line->width ? line->width : imhtml->xsize, line->height);
561
562 if (!line->text) {
563 gdk_gc_unref (gc);
564 return;
565 }
566
567 if (bit->back != NULL) {
568 gdk_color_alloc (cmap, bit->back);
569 gdk_gc_set_foreground (gc, bit->back);
570 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff,
571 string_width (imhtml->context, bit->font, line->text), line->height);
572 bg = bit->back;
573 }
574
575 bg = gdk_color_copy (bg);
576
577 if (line->selected) {
578 gint width, x;
579
580 if ((line->sel_start > line->sel_end) && (line->sel_end != NULL)) {
581 start = line->sel_end;
582 end = line->sel_start;
583 } else {
584 start = line->sel_start;
585 end = line->sel_end;
586 }
587
588 if (start == NULL)
589 x = 0;
590 else
591 x = text_width (imhtml->context, bit->font, line->text, start - line->text);
592
593 if (end == NULL)
594 end = strchr(line->text, '\0');
595
596 width = text_width (imhtml->context, bit->font, line->text, end - line->text) - x;
597
598 gdk_gc_set_foreground (gc, imhtml->default_hl_color);
599
600 gdk_draw_rectangle (window, gc, TRUE, x + line->x - xoff, line->y - yoff,
601 width, line->height);
602 gdk_gc_set_foreground (gc, imhtml->default_hlfg_color);
603 fg = gdk_color_copy(imhtml->default_hlfg_color);
604 }
605 if (bit->url) {
606 GdkColor *tc = gtk_imhtml_get_color ("#0000a0");
607 gdk_color_alloc (cmap, tc);
608 gdk_gc_set_foreground (gc, tc);
609 fg = gdk_color_copy (tc);
610 gdk_color_free (tc);
611 } else if (bit->fore) {
612 gdk_color_alloc (cmap, bit->fore);
613 gdk_gc_set_foreground (gc, bit->fore);
614 fg = gdk_color_copy (bit->fore);
615 } else {
616 gdk_color_alloc (cmap, imhtml->default_fg_color);
617 gdk_gc_set_foreground (gc, imhtml->default_fg_color);
618 fg = gdk_color_copy (imhtml->default_fg_color);
619 }
620
621 if (similar_colors (bg, fg)) {
622 gdk_color_alloc (cmap, fg);
623 gdk_gc_set_foreground (gc, fg);
624 }
625 86
626 metrics = pango_context_get_metrics(imhtml->context, bit->font, NULL); 87 /* These tags will be used often and can be reused--we create them on init and then apply them by name
627 88 * other tags (color, size, face, etc.) will have to be created and applied dynamically */
628 if (start) { 89 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL);
629 int offset = 0; 90 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL);
630 91 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL);
631 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), NULL); 92 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL);
632 pango_layout_set_text(layout, line->text, start - line->text); 93 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL);
633 set_layout_font(layout, line->text, start - line->text, bit->font); 94 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL);
634 gdk_draw_layout(window, gc, line->x - xoff, 95 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL);
635 line->y - yoff + line->ascent -
636 get_layout_first_baseline(layout), layout);
637 g_object_unref(G_OBJECT(layout));
638
639 offset = text_width (imhtml->context, bit->font, line->text, start - line->text);
640 if (bit->underline || bit->url)
641 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff,
642 line->y - yoff + line->ascent + 1,
643 offset, 1);
644 if (bit->strike)
645 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff,
646 line->y - yoff + line->ascent -
647 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2),
648 offset, 1);
649 gdk_gc_set_foreground (gc, imhtml->default_hlfg_color);
650
651 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), NULL);
652 pango_layout_set_text(layout, start, end - start);
653 set_layout_font(layout, start, end - start, bit->font);
654 gdk_draw_layout(window, gc, line->x - xoff + offset,
655 line->y - yoff + line->ascent -
656 get_layout_first_baseline(layout), layout);
657 g_object_unref(G_OBJECT(layout));
658
659 if (bit->underline || bit->url)
660 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset,
661 line->y - yoff + line->ascent + 1,
662 text_width (imhtml->context, bit->font, line->text, end - start), 1);
663 if (bit->strike)
664 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset,
665 line->y - yoff + line->ascent -
666 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2),
667 text_width (imhtml->context, bit->font, line->text, end - start), 1);
668 offset = text_width (imhtml->context, bit->font, line->text, end - line->text);
669 gdk_gc_set_foreground (gc, fg);
670
671 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), end);
672 set_layout_font(layout, end, -1, bit->font);
673 gdk_draw_layout(window, gc, line->x - xoff + offset,
674 line->y - yoff + line->ascent -
675 get_layout_first_baseline(layout), layout);
676
677 g_object_unref(G_OBJECT(layout));
678
679 if (bit->underline || bit->url)
680 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset,
681 line->y - yoff + line->ascent + 1,
682 string_width (imhtml->context, bit->font, end), 1);
683 if (bit->strike)
684 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff + offset,
685 line->y - yoff + line->ascent -
686 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2),
687 string_width (imhtml->context, bit->font, end), 1);
688 } else {
689 layout = gtk_widget_create_pango_layout(GTK_WIDGET(imhtml), line->text);
690 set_layout_font(layout, line->text, -1, bit->font);
691 gdk_draw_layout(window, gc, line->x - xoff,
692 line->y - yoff + line->ascent -
693 get_layout_first_baseline(layout), layout);
694 g_object_unref(G_OBJECT(layout));
695
696 if (bit->underline || bit->url)
697 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff + line->ascent + 1,
698 string_width (imhtml->context, bit->font, line->text), 1);
699 if (bit->strike)
700 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff,
701 line->y - yoff + line->ascent -
702 ((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) / 2),
703 string_width (imhtml->context, bit->font, line->text), 1);
704 }
705
706 pango_font_metrics_unref(metrics);
707
708 gdk_color_free (bg);
709 gdk_color_free (fg);
710
711 gdk_gc_unref (gc);
712 }
713
714 static void
715 draw_img (GtkIMHtml *imhtml,
716 struct line_info *line)
717 {
718 GtkIMHtmlBit *bit;
719 GdkGC *gc;
720 GdkColormap *cmap;
721 gint width, height, hoff;
722 GdkWindow *window = GTK_LAYOUT (imhtml)->bin_window;
723 gfloat xoff, yoff;
724
725 if (GTK_LAYOUT (imhtml)->freeze_count)
726 return;
727
728 bit = line->bit;
729 gdk_window_get_size (bit->pm, &width, &height);
730 hoff = (line->height - height) / 2;
731 xoff = GTK_LAYOUT (imhtml)->hadjustment->value;
732 yoff = GTK_LAYOUT (imhtml)->vadjustment->value;
733 gc = gdk_gc_new (window);
734 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml));
735 96
736 if (bit->bg != NULL) { 97 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */
737 gdk_color_alloc (cmap, bit->bg);
738 gdk_gc_set_foreground (gc, bit->bg);
739 } else {
740 gdk_color_alloc (cmap, imhtml->default_bg_color);
741 gdk_gc_set_foreground (gc, imhtml->default_bg_color);
742 }
743
744 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff, line->width, line->height);
745
746 if (line->selected) {
747 gdk_color_alloc (cmap, imhtml->default_hl_color);
748 gdk_gc_set_foreground(gc, imhtml->default_hl_color);
749 gdk_draw_rectangle (window, gc, TRUE, line->x - xoff, line->y - yoff,
750 width, line->height);
751 } else if (bit->back != NULL) {
752 gdk_color_alloc (cmap, bit->back);
753 gdk_gc_set_foreground (gc, bit->back);
754 }
755
756 if (bit->bm) {
757 gdk_gc_set_clip_mask(gc, bit->bm);
758 gdk_gc_set_clip_origin(gc, line->x - xoff, line->y - yoff + hoff);
759 }
760 gdk_draw_pixmap (window, gc, bit->pm, 0, 0, line->x - xoff, line->y - yoff + hoff, -1, -1);
761
762 gdk_gc_unref (gc);
763 }
764
765 static void
766 draw_line (GtkIMHtml *imhtml,
767 struct line_info *line)
768 {
769 GtkIMHtmlBit *bit;
770 GdkDrawable *drawable;
771 GdkColormap *cmap;
772 GdkGC *gc;
773 guint line_height;
774 gfloat xoff, yoff;
775
776 if (GTK_LAYOUT (imhtml)->freeze_count)
777 return;
778
779 xoff = GTK_LAYOUT (imhtml)->hadjustment->value;
780 yoff = GTK_LAYOUT (imhtml)->vadjustment->value;
781 bit = line->bit;
782 drawable = GTK_LAYOUT (imhtml)->bin_window;
783 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml));
784 gc = gdk_gc_new (drawable);
785
786 if (line->selected) {
787 gdk_color_alloc (cmap, imhtml->default_hl_color);
788 gdk_gc_set_foreground (gc, imhtml->default_hl_color);
789 } else if (bit->bg != NULL) {
790 gdk_color_alloc (cmap, bit->bg);
791 gdk_gc_set_foreground (gc, bit->bg);
792 } else {
793 gdk_color_alloc (cmap, imhtml->default_bg_color);
794 gdk_gc_set_foreground (gc, imhtml->default_bg_color);
795 }
796
797 gdk_draw_rectangle (drawable, gc, TRUE, line->x - xoff, line->y - yoff,
798 line->width, line->height);
799
800
801 if (line->selected) {
802 gdk_color_alloc (cmap, imhtml->default_hlfg_color);
803 gdk_gc_set_foreground (gc, imhtml->default_hlfg_color);
804 } else {
805 gdk_color_alloc (cmap, imhtml->default_fg_color);
806 gdk_gc_set_foreground (gc, imhtml->default_fg_color);
807 }
808
809 line_height = line->height / 2;
810
811 gdk_draw_rectangle (drawable, gc, TRUE, line->x - xoff, line->y - yoff + line_height / 2,
812 line->width, line_height);
813
814 gdk_gc_unref (gc);
815 }
816
817 static void
818 gtk_imhtml_draw_focus (GtkWidget *widget)
819 {
820 GtkIMHtml *imhtml;
821 gint x = 0,
822 y = 0,
823 w = 0,
824 h = 0;
825
826 imhtml = GTK_IMHTML (widget);
827
828 if (!GTK_WIDGET_DRAWABLE (widget))
829 return;
830
831 if (GTK_WIDGET_HAS_FOCUS (widget)) {
832 gtk_paint_focus (widget->style, widget->window, GTK_STATE_NORMAL, NULL, widget, "text",
833 0, 0, widget->allocation.width - 1, widget->allocation.height - 1);
834 x = 1; y = 1; w = 2; h = 2;
835 }
836
837 gtk_paint_shadow (widget->style, widget->window, GTK_STATE_NORMAL,
838 GTK_SHADOW_IN, NULL, widget, "text", x, y,
839 widget->allocation.width - w, widget->allocation.height - h);
840 }
841
842 static void
843 gtk_imhtml_draw_exposed (GtkIMHtml *imhtml)
844 {
845 GList *bits;
846 GtkIMHtmlBit *bit;
847 GList *chunks;
848 struct line_info *line;
849 gfloat x, y;
850 guint32 width, height;
851
852 x = GTK_LAYOUT (imhtml)->hadjustment->value;
853 y = GTK_LAYOUT (imhtml)->vadjustment->value;
854 gdk_window_get_size (GTK_LAYOUT (imhtml)->bin_window, &width, &height);
855
856 bits = imhtml->bits;
857
858 while (bits) {
859 bit = bits->data;
860 chunks = bit->chunks;
861 if (DRAW_IMG (bit)) {
862 if (chunks) {
863 line = chunks->data;
864 if ((line->x <= x + width) &&
865 (line->y <= y + height) &&
866 (x <= line->x + line->width) &&
867 (y <= line->y + line->height))
868 draw_img (imhtml, line);
869 }
870 } else if (bit->type == TYPE_SEP) {
871 if (chunks) {
872 line = chunks->data;
873 if ((line->x <= x + width) &&
874 (line->y <= y + height) &&
875 (x <= line->x + line->width) &&
876 (y <= line->y + line->height))
877 draw_line (imhtml, line);
878
879 line = chunks->next->data;
880 if ((line->x <= x + width) &&
881 (line->y <= y + height) &&
882 (x <= line->x + line->width) &&
883 (y <= line->y + line->height))
884 draw_text (imhtml, line);
885 }
886 } else {
887 while (chunks) {
888 line = chunks->data;
889 if ((line->x <= x + width) &&
890 (line->y <= y + height) &&
891 (x <= line->x + line->width) &&
892 (y <= line->y + line->height))
893 draw_text (imhtml, line);
894 chunks = g_list_next (chunks);
895 }
896 }
897 bits = g_list_next (bits);
898 }
899
900 gtk_imhtml_draw_focus (GTK_WIDGET (imhtml));
901 }
902
903 static void
904 gtk_imhtml_style_set (GtkWidget *widget,
905 GtkStyle *style)
906 {
907 GtkIMHtml *imhtml;
908
909 g_return_if_fail (widget != NULL);
910 g_return_if_fail (GTK_IS_IMHTML (widget));
911
912 if (GTK_WIDGET_CLASS (parent_class)->style_set)
913 (* GTK_WIDGET_CLASS (parent_class)->style_set) (widget, style);
914
915 if (!GTK_WIDGET_REALIZED (widget))
916 return;
917
918 imhtml = GTK_IMHTML (widget);
919 if (imhtml->default_fg_color)
920 gdk_color_free(imhtml->default_fg_color);
921 if (imhtml->default_bg_color)
922 gdk_color_free(imhtml->default_bg_color);
923 if (imhtml->default_hl_color)
924 gdk_color_free(imhtml->default_hl_color);
925 if (imhtml->default_hlfg_color)
926 gdk_color_free(imhtml->default_hlfg_color);
927 imhtml->default_fg_color = gdk_color_copy (&GTK_WIDGET (imhtml)->style->fg [GTK_STATE_NORMAL]);
928 imhtml->default_bg_color = gdk_color_copy (&GTK_WIDGET (imhtml)->style->base [GTK_STATE_NORMAL]);
929 imhtml->default_hl_color = gdk_color_copy (&GTK_WIDGET (imhtml)->style->bg [GTK_STATE_SELECTED]);
930 imhtml->default_hlfg_color=gdk_color_copy (&GTK_WIDGET (imhtml)->style->fg [GTK_STATE_SELECTED]);
931 gdk_window_set_background (widget->window, &widget->style->base [GTK_STATE_NORMAL]);
932 gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window,
933 &widget->style->base [GTK_STATE_NORMAL]);
934 gtk_imhtml_draw_exposed (imhtml);
935 }
936
937 static gint
938 gtk_imhtml_expose_event (GtkWidget *widget,
939 GdkEventExpose *event)
940 {
941 GtkIMHtml *imhtml;
942
943 g_return_val_if_fail (widget != NULL, FALSE);
944 g_return_val_if_fail (GTK_IS_IMHTML (widget), FALSE);
945
946 imhtml = GTK_IMHTML (widget);
947 gtk_imhtml_draw_exposed (imhtml);
948
949 return FALSE;
950 }
951
952 static void
953 gtk_imhtml_redraw_all (GtkIMHtml *imhtml)
954 {
955 GList *b;
956 GtkIMHtmlBit *bit;
957 GtkAdjustment *vadj;
958 gfloat oldvalue;
959 gint oldy;
960
961 vadj = GTK_LAYOUT (imhtml)->vadjustment;
962 oldvalue = vadj->value / vadj->upper;
963 oldy = imhtml->y;
964
965 gtk_layout_freeze (GTK_LAYOUT (imhtml));
966
967 g_list_free (imhtml->line);
968 imhtml->line = NULL;
969
970 while (imhtml->click) {
971 g_free (imhtml->click->data);
972 imhtml->click = g_list_remove (imhtml->click, imhtml->click->data);
973 }
974
975 imhtml->x = 0;
976 imhtml->y = TOP_BORDER;
977 imhtml->llheight = 0;
978 imhtml->llascent = 0;
979
980 if (GTK_LAYOUT (imhtml)->vadjustment->value < TOP_BORDER)
981 gdk_window_clear_area (GTK_LAYOUT (imhtml)->bin_window, 0, 0,
982 imhtml->xsize,
983 TOP_BORDER - GTK_LAYOUT (imhtml)->vadjustment->value);
984
985 b = imhtml->bits;
986 while (b) {
987 bit = b->data;
988 b = g_list_next (b);
989 while (bit->chunks) {
990 struct line_info *li = bit->chunks->data;
991 if (li->text)
992 g_free (li->text);
993 bit->chunks = g_list_remove (bit->chunks, li);
994 g_free (li);
995 }
996 gtk_imhtml_draw_bit (imhtml, bit);
997 }
998
999 GTK_LAYOUT (imhtml)->height = imhtml->y;
1000 GTK_LAYOUT (imhtml)->vadjustment->upper = imhtml->y;
1001 gtk_signal_emit_by_name (GTK_OBJECT (GTK_LAYOUT (imhtml)->vadjustment), "changed");
1002
1003 gtk_widget_set_usize (GTK_WIDGET (imhtml), -1, imhtml->y);
1004 gtk_adjustment_set_value (vadj, vadj->upper * oldvalue);
1005
1006 if (GTK_LAYOUT (imhtml)->bin_window && (imhtml->y < oldy)) {
1007 GdkGC *gc;
1008 GdkColormap *cmap;
1009
1010 gc = gdk_gc_new (GTK_LAYOUT (imhtml)->bin_window);
1011 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml));
1012
1013 gdk_color_alloc (cmap, imhtml->default_bg_color);
1014 gdk_gc_set_foreground (gc, imhtml->default_bg_color);
1015
1016 gdk_draw_rectangle (GTK_LAYOUT (imhtml)->bin_window, gc, TRUE,
1017 0, imhtml->y - GTK_LAYOUT (imhtml)->vadjustment->value,
1018 GTK_WIDGET (imhtml)->allocation.width,
1019 oldy - imhtml->y);
1020
1021 gdk_gc_unref (gc);
1022 }
1023
1024 gtk_layout_thaw (GTK_LAYOUT (imhtml));
1025 gtk_imhtml_draw_focus (GTK_WIDGET (imhtml));
1026 }
1027
1028 static void
1029 gtk_imhtml_size_allocate (GtkWidget *widget,
1030 GtkAllocation *allocation)
1031 {
1032 GtkIMHtml *imhtml;
1033 GtkLayout *layout;
1034 gint new_xsize, new_ysize;
1035
1036 g_return_if_fail (widget != NULL);
1037 g_return_if_fail (GTK_IS_IMHTML (widget));
1038 g_return_if_fail (allocation != NULL);
1039
1040 imhtml = GTK_IMHTML (widget);
1041 layout = GTK_LAYOUT (widget);
1042
1043 widget->allocation = *allocation;
1044
1045 new_xsize = MAX (1, (gint) allocation->width -
1046 (gint) (widget->style->xthickness + BORDER_SIZE) * 2);
1047 new_ysize = MAX (1, (gint) allocation->height -
1048 (gint) (widget->style->ythickness + BORDER_SIZE) * 2);
1049
1050 if (GTK_WIDGET_REALIZED (widget)) {
1051 gint x = widget->style->xthickness + BORDER_SIZE;
1052 gint y = widget->style->ythickness + BORDER_SIZE;
1053 gdk_window_move_resize (widget->window,
1054 allocation->x, allocation->y,
1055 allocation->width, allocation->height);
1056 gdk_window_move_resize (layout->bin_window,
1057 x, y, new_xsize, new_ysize);
1058 }
1059
1060 layout->hadjustment->page_size = new_xsize;
1061 layout->hadjustment->page_increment = new_xsize / 2;
1062 layout->hadjustment->lower = 0;
1063 layout->hadjustment->upper = imhtml->x;
1064
1065 layout->vadjustment->page_size = new_ysize;
1066 layout->vadjustment->page_increment = new_ysize / 2;
1067 layout->vadjustment->lower = 0;
1068 layout->vadjustment->upper = imhtml->y;
1069
1070 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
1071 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
1072
1073 if (new_xsize == imhtml->xsize) {
1074 if ((GTK_LAYOUT (imhtml)->vadjustment->value > imhtml->y - new_ysize)) {
1075 if (imhtml->y > new_ysize)
1076 gtk_adjustment_set_value (GTK_LAYOUT (imhtml)->vadjustment,
1077 imhtml->y - new_ysize);
1078 else
1079 gtk_adjustment_set_value (GTK_LAYOUT (imhtml)->vadjustment, 0);
1080 }
1081 return;
1082 }
1083
1084 imhtml->xsize = new_xsize;
1085
1086 if (GTK_WIDGET_REALIZED (widget))
1087 gtk_imhtml_redraw_all (imhtml);
1088 }
1089
1090 static void
1091 gtk_imhtml_select_none (GtkIMHtml *imhtml)
1092 {
1093 GList *bits;
1094 GList *chunks;
1095 GtkIMHtmlBit *bit;
1096 struct line_info *chunk;
1097
1098 g_return_if_fail (GTK_IS_IMHTML (imhtml));
1099
1100 bits = imhtml->bits;
1101 while (bits) {
1102 bit = bits->data;
1103 chunks = bit->chunks;
1104
1105 while (chunks) {
1106 chunk = chunks->data;
1107
1108 if (chunk->selected) {
1109 chunk->selected = FALSE;
1110 chunk->sel_start = chunk->text;
1111 chunk->sel_end = NULL;
1112 if (DRAW_IMG (bit))
1113 draw_img (imhtml, chunk);
1114 else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk))
1115 draw_line (imhtml, chunk);
1116 else if (chunk->width)
1117 draw_text (imhtml, chunk);
1118 }
1119
1120 chunks = g_list_next (chunks);
1121 }
1122
1123 bits = g_list_next (bits);
1124 }
1125 imhtml->sel_endchunk = NULL;
1126 }
1127
1128 static gchar*
1129 get_position (GtkIMHtml *imhtml,
1130 struct line_info *chunk,
1131 gint x,
1132 gboolean smileys)
1133 {
1134 gint width = x - chunk->x;
1135 gchar *text;
1136 gchar *pos;
1137 guint total = 0;
1138
1139 switch (chunk->bit->type) {
1140 case TYPE_TEXT:
1141 case TYPE_COMMENT:
1142 text = chunk->text;
1143 break;
1144 case TYPE_SMILEY:
1145 if (smileys)
1146 return NULL;
1147 else
1148 text = chunk->text;
1149 break;
1150 default:
1151 return NULL;
1152 break;
1153 }
1154
1155 if (width <= 0)
1156 return text;
1157
1158 for (pos = text; *pos != '\0'; pos++) {
1159 gint char_width = text_width (imhtml->context, chunk->bit->font, pos, 1);
1160 if ((width > total) && (width <= total + char_width)) {
1161 if (width < total + (char_width / 2))
1162 return pos;
1163 else
1164 return ++pos;
1165 }
1166 total += char_width;
1167 }
1168
1169 return pos;
1170 }
1171
1172 static GString*
1173 append_to_sel (GString *string,
1174 struct line_info *chunk,
1175 gboolean smileys)
1176 {
1177 GString *new_string;
1178 gchar *buf;
1179 gchar *start;
1180 gint length;
1181
1182 switch (chunk->bit->type) {
1183 case TYPE_TEXT:
1184 case TYPE_COMMENT:
1185 start = (chunk->sel_start == NULL) ? chunk->text : chunk->sel_start;
1186 length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start;
1187 if (length <= 0)
1188 return string;
1189 buf = g_strndup (start, length);
1190 break;
1191 case TYPE_SMILEY:
1192 if (smileys) {
1193 start = (chunk->sel_start == NULL) ? chunk->bit->text : chunk->sel_start;
1194 length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start;
1195 if (length <= 0)
1196 return string;
1197 buf = g_strndup (start, length);
1198 } else {
1199 start = (chunk->sel_start == NULL) ? chunk->text : chunk->sel_start;
1200 length = (chunk->sel_end == NULL) ? strlen (start) : chunk->sel_end - start;
1201 if (length <= 0)
1202 return string;
1203 buf = g_strndup (start, length);
1204 }
1205 break;
1206 case TYPE_BR:
1207 buf = g_strdup ("\n");
1208 break;
1209 default:
1210 return string;
1211 break;
1212 }
1213
1214 new_string = g_string_append (string, buf);
1215 g_free (buf);
1216
1217 return new_string;
1218 }
1219
1220 static void
1221 chunk_select_words (struct line_info *chunk)
1222 {
1223 char *start, *end;
1224
1225 start = chunk->sel_start;
1226 end = chunk->sel_end;
1227
1228 if (start != chunk->text) {
1229 if (isalnum(*start) || *start == '\'')
1230 while (start > chunk->text &&
1231 (isalnum(*(start-1)) || *(start-1) == '\''))
1232 start--;
1233 else if (isspace(*start))
1234 while (start > chunk->text && isspace(*(start-1)))
1235 start--;
1236 else if (ispunct(*start))
1237 while (start > chunk->text && ispunct(*(start-1)))
1238 start--;
1239 }
1240 chunk->sel_start = start;
1241
1242 if (end != NULL) {
1243 if (isalnum(*end) || *end == '\'')
1244 while (*end != '\0' &&
1245 (isalnum(*end) || *end == '\''))
1246 end++;
1247 else if (isspace(*end))
1248 while (*end != '\0' && isspace(*end))
1249 end++;
1250 else if (ispunct(*end))
1251 while (*end != '\0' && ispunct(*end))
1252 end++;
1253 }
1254 chunk->sel_end = end;
1255 }
1256
1257 #define COORDS_IN_CHUNK(xx, yy) (((xx) < chunk->x + chunk->width) && \
1258 ((yy) < chunk->y + chunk->height))
1259
1260 static void
1261 gtk_imhtml_select_bits (GtkIMHtml *imhtml)
1262 {
1263 GList *bits;
1264 GList *chunks;
1265 GtkIMHtmlBit *bit;
1266 struct line_info *chunk;
1267
1268 guint startx = imhtml->sel_startx,
1269 starty = imhtml->sel_starty,
1270 endx = imhtml->sel_endx,
1271 endy = imhtml->sel_endy;
1272 gchar *new_pos;
1273 gint selection = 0;
1274 guint mode = imhtml->sel_mode;
1275 gboolean smileys = imhtml->smileys;
1276 gboolean redraw = FALSE;
1277 gboolean got_start = FALSE;
1278 gboolean got_end = FALSE;
1279
1280 g_return_if_fail (GTK_IS_IMHTML (imhtml));
1281
1282 if (!imhtml->selection)
1283 return;
1284
1285 if (imhtml->selected_text) {
1286 g_string_free (imhtml->selected_text, TRUE);
1287 imhtml->selected_text = g_string_new ("");
1288 }
1289
1290 if (mode == 2)
1291 startx = endx = 0;
1292
1293 bits = imhtml->bits;
1294 while (bits) {
1295 bit = bits->data;
1296 chunks = bit->chunks;
1297
1298 while (chunks) {
1299 chunk = chunks->data;
1300
1301 switch (selection) {
1302 case 0:
1303 if (COORDS_IN_CHUNK (startx, starty)) {
1304 new_pos = get_position (imhtml, chunk, startx, smileys);
1305 if (!chunk->selected ||
1306 (chunk->sel_start != new_pos) ||
1307 (chunk->sel_end != NULL))
1308 redraw = TRUE;
1309 chunk->selected = TRUE;
1310 chunk->sel_start = new_pos;
1311 chunk->sel_end = NULL;
1312 selection++;
1313 got_start = TRUE;
1314 if (mode == 2)
1315 endy += chunk->height;
1316 if (mode == 1)
1317 chunk_select_words (chunk);
1318 }
1319
1320 if (COORDS_IN_CHUNK (endx, endy)) {
1321 if (got_start) {
1322 new_pos = get_position (imhtml, chunk, endx, smileys);
1323 if (chunk->sel_end != new_pos)
1324 redraw = TRUE;
1325 if (chunk->sel_start > new_pos) {
1326 chunk->sel_end = chunk->sel_start;
1327 chunk->sel_start = new_pos;
1328 } else
1329 chunk->sel_end = new_pos;
1330 selection = 2;
1331 imhtml->sel_endchunk = chunk;
1332 got_end = TRUE;
1333 if (mode == 1)
1334 chunk_select_words (chunk);
1335 } else {
1336 new_pos = get_position (imhtml, chunk, endx, smileys);
1337 if ( !chunk->selected ||
1338 (chunk->sel_start != new_pos) ||
1339 (chunk->sel_end != NULL))
1340 redraw = TRUE;
1341 chunk->selected = TRUE;
1342 chunk->sel_start = new_pos;
1343 chunk->sel_end = NULL;
1344 selection++;
1345 imhtml->sel_endchunk = chunk;
1346 got_end = TRUE;
1347 if (mode == 2)
1348 starty += chunk->height;
1349 if (mode == 1)
1350 chunk_select_words (chunk);
1351 }
1352 } else if (!COORDS_IN_CHUNK (startx, starty) && !got_start) {
1353 if (chunk->selected)
1354 redraw = TRUE;
1355 chunk->selected = FALSE;
1356 chunk->sel_start = chunk->text;
1357 chunk->sel_end = NULL;
1358 }
1359
1360 break;
1361 case 1:
1362 if (!got_start && COORDS_IN_CHUNK (startx, starty)) {
1363 new_pos = get_position (imhtml, chunk, startx, smileys);
1364 if ( !chunk->selected ||
1365 (chunk->sel_end != new_pos) ||
1366 (chunk->sel_start != chunk->text))
1367 redraw = TRUE;
1368 chunk->selected = TRUE;
1369 chunk->sel_start = chunk->text;
1370 chunk->sel_end = new_pos;
1371 selection++;
1372 got_start = TRUE;
1373 if (mode == 1)
1374 chunk_select_words (chunk);
1375 } else if (!got_end && COORDS_IN_CHUNK (endx, endy)) {
1376 new_pos = get_position (imhtml, chunk, endx, smileys);
1377 if ( !chunk->selected ||
1378 (chunk->sel_end != new_pos) ||
1379 (chunk->sel_start != chunk->text))
1380 redraw = TRUE;
1381 chunk->selected = TRUE;
1382 chunk->sel_start = chunk->text;
1383 chunk->sel_end = new_pos;
1384 selection++;
1385 imhtml->sel_endchunk = chunk;
1386 got_end = TRUE;
1387 if (mode == 1)
1388 chunk_select_words (chunk);
1389 } else {
1390 if ( !chunk->selected ||
1391 (chunk->sel_end != NULL) ||
1392 (chunk->sel_start != chunk->text))
1393 redraw = TRUE;
1394 chunk->selected = TRUE;
1395 chunk->sel_start = chunk->text;
1396 chunk->sel_end = NULL;
1397 }
1398
1399 break;
1400 case 2:
1401 if (chunk->selected)
1402 redraw = TRUE;
1403 chunk->selected = FALSE;
1404 chunk->sel_start = chunk->text;
1405 chunk->sel_end = NULL;
1406 break;
1407 }
1408
1409 if (chunk->selected == TRUE)
1410 imhtml->selected_text = append_to_sel (imhtml->selected_text,
1411 chunk, smileys);
1412
1413 if (redraw) {
1414 if (DRAW_IMG (bit))
1415 draw_img (imhtml, chunk);
1416 else if ((bit->type == TYPE_SEP) && (bit->chunks->data == chunk))
1417 draw_line (imhtml, chunk);
1418 else if (chunk->width)
1419 draw_text (imhtml, chunk);
1420 redraw = FALSE;
1421 }
1422
1423 chunks = g_list_next (chunks);
1424 }
1425
1426 bits = g_list_next (bits);
1427 }
1428 }
1429
1430 static void
1431 gtk_imhtml_select_in_chunk (GtkIMHtml *imhtml,
1432 struct line_info *chunk)
1433 {
1434 GtkIMHtmlBit *bit = chunk->bit;
1435 gchar *new_pos;
1436 guint endx = imhtml->sel_endx;
1437 guint startx = imhtml->sel_startx;
1438 guint starty = imhtml->sel_starty;
1439 gboolean smileys = imhtml->smileys;
1440 gboolean redraw = FALSE;
1441
1442 new_pos = get_position (imhtml, chunk, endx, smileys);
1443 if ((starty < chunk->y) ||
1444 ((starty < chunk->y + chunk->height) && (startx < endx))) {
1445 if (chunk->sel_end != new_pos)
1446 redraw = TRUE;
1447 chunk->sel_end = new_pos;
1448 } else {
1449 if (chunk->sel_start != new_pos)
1450 redraw = TRUE;
1451 chunk->sel_start = new_pos;
1452 }
1453
1454 if (redraw) {
1455 if (DRAW_IMG (bit))
1456 draw_img (imhtml, chunk);
1457 else if ((bit->type == TYPE_SEP) &&
1458 (bit->chunks->data == chunk))
1459 draw_line (imhtml, chunk);
1460 else if (chunk->width)
1461 draw_text (imhtml, chunk);
1462 }
1463 }
1464
1465 static gint
1466 scroll_timeout (GtkIMHtml *imhtml)
1467 {
1468 GdkEventMotion event;
1469 gint x, y;
1470 GdkModifierType mask;
1471
1472 imhtml->scroll_timer = 0;
1473
1474 gdk_window_get_pointer (GTK_LAYOUT (imhtml)->bin_window, &x, &y, &mask);
1475
1476 if (mask & GDK_BUTTON1_MASK) {
1477 event.is_hint = 0;
1478 event.x = x;
1479 event.y = y;
1480 event.state = mask;
1481
1482 gtk_imhtml_motion_notify_event (GTK_WIDGET (imhtml), &event);
1483 }
1484
1485 return FALSE;
1486 }
1487
1488 static gint
1489 gtk_imhtml_tip_paint (GtkIMHtml *imhtml)
1490 {
1491 int x,y;
1492 GtkStyle *style;
1493 PangoLayout *layout;
1494 if (imhtml->tip_bit->url)
1495 layout = gtk_widget_create_pango_layout (imhtml->tip_window, imhtml->tip_bit->url);
1496 else if (imhtml->tip_bit->img)
1497 layout = gtk_widget_create_pango_layout (imhtml->tip_window, imhtml->tip_bit->img->filename);
1498 else
1499 return FALSE;
1500
1501 style = imhtml->tip_window->style;
1502 pango_layout_get_size (layout, &x, &y);
1503
1504 if (!imhtml->tip_bit)
1505 return FALSE;
1506
1507 gtk_paint_flat_box (style, imhtml->tip_window->window, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
1508 NULL, imhtml->tip_window, "tooltip", 0, 0, -1, -1);
1509
1510 gtk_paint_layout (style, imhtml->tip_window->window, GTK_STATE_NORMAL, TRUE,
1511 NULL, imhtml->tip_window, "tooltip", 4, 4, layout);
1512
1513 g_object_unref (layout);
1514 return FALSE;
1515 }
1516
1517 static gint
1518 gtk_imhtml_tip (gpointer data)
1519 {
1520 GtkIMHtml *imhtml = data;
1521 GtkWidget *widget = GTK_WIDGET (imhtml);
1522 GtkStyle *style;
1523 PangoLayout *layout;
1524 gint x, y, w, h, scr_w, scr_h;
1525
1526 if (!imhtml->tip_bit || !GTK_WIDGET_DRAWABLE (widget)) {
1527 imhtml->tip_timer = 0;
1528 return FALSE;
1529 }
1530
1531 if (imhtml->tip_window)
1532 gtk_widget_destroy (imhtml->tip_window);
1533
1534 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP);
1535 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE);
1536 gtk_window_set_policy (GTK_WINDOW (imhtml->tip_window), FALSE, FALSE, TRUE);
1537 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips");
1538 gtk_signal_connect_object (GTK_OBJECT (imhtml->tip_window), "expose_event",
1539 GTK_SIGNAL_FUNC (gtk_imhtml_tip_paint), GTK_OBJECT (imhtml));
1540
1541 gtk_widget_ensure_style (imhtml->tip_window);
1542 style = imhtml->tip_window->style;
1543 layout = gtk_widget_create_pango_layout(imhtml->tip_window,
1544 imhtml->tip_bit->url ? imhtml->tip_bit->url : imhtml->tip_bit->img->filename);
1545
1546 scr_w = gdk_screen_width ();
1547 scr_h = gdk_screen_height ();
1548
1549 pango_layout_get_size(layout, &w, &h);
1550
1551 w = PANGO_PIXELS(w) + 8;
1552 h = PANGO_PIXELS(h) + 8;
1553
1554 gdk_window_get_pointer (NULL, &x, &y, NULL);
1555 if (GTK_WIDGET_NO_WINDOW (widget))
1556 y += widget->allocation.y;
1557
1558 x -= ((w >> 1) + 4);
1559
1560 if ((x + w) > scr_w)
1561 x -= (x + w) - scr_w;
1562 else if (x < 0)
1563 x = 0;
1564
1565 if ((y + h + + 4) > scr_h)
1566 y = y - h;
1567 else
1568 y = y + h - 4;
1569
1570 gtk_widget_set_usize (imhtml->tip_window, w, h);
1571 gtk_widget_set_uposition (imhtml->tip_window, x, y);
1572 gtk_widget_show (imhtml->tip_window);
1573
1574 imhtml->tip_timer = 0;
1575 g_object_unref(layout);
1576
1577 return FALSE;
1578 }
1579
1580 static gint
1581 gtk_imhtml_motion_notify_event (GtkWidget *widget,
1582 GdkEventMotion *event)
1583 {
1584 gint x, y;
1585 GdkModifierType state;
1586 GtkIMHtml *imhtml = GTK_IMHTML (widget);
1587 GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment;
1588 GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment;
1589
1590 if (event->is_hint)
1591 gdk_window_get_pointer (event->window, &x, &y, &state);
1592 else {
1593 x = event->x + hadj->value;
1594 y = event->y + vadj->value;
1595 state = event->state;
1596 }
1597
1598 if (state & GDK_BUTTON1_MASK) {
1599 gint diff;
1600 gint height = vadj->page_size;
1601 gint yy = y - vadj->value;
1602
1603 if (((yy < 0) || (yy > height)) &&
1604 (imhtml->scroll_timer == 0) &&
1605 (vadj->upper > vadj->page_size)) {
1606 imhtml->scroll_timer = gtk_timeout_add (100,
1607 (GtkFunction) scroll_timeout,
1608 imhtml);
1609 diff = (yy < 0) ? (yy / 2) : ((yy - height) / 2);
1610 gtk_adjustment_set_value (vadj,
1611 MIN (vadj->value + diff, vadj->upper - height));
1612 }
1613
1614 if (imhtml->selection) {
1615 struct line_info *chunk = imhtml->sel_endchunk;
1616 imhtml->sel_endx = MAX (x, 0);
1617 imhtml->sel_endy = MAX (y, 0);
1618 if ((chunk == NULL) ||
1619 (x < chunk->x) ||
1620 (x > chunk->x + chunk->width) ||
1621 (y < chunk->y) ||
1622 (y > chunk->y + chunk->height) ||
1623 (imhtml->sel_mode > 0))
1624 gtk_imhtml_select_bits (imhtml);
1625 else
1626 gtk_imhtml_select_in_chunk (imhtml, chunk);
1627 }
1628 } else {
1629 GList *click = imhtml->click;
1630 struct clickable *uw;
1631
1632 while (click) {
1633 uw = (struct clickable *) click->data;
1634 if ((uw->bit->url) && (x > uw->x) && (x < uw->x + uw->width) &&
1635 (y > uw->y) && (y < uw->y + uw->height) &&
1636 (uw->bit->url || uw->bit->img)) {
1637 if (imhtml->tip_bit != uw->bit) {
1638 imhtml->tip_bit = uw->bit;
1639 if (imhtml->tip_timer != 0)
1640 gtk_timeout_remove (imhtml->tip_timer);
1641 if (imhtml->tip_window) {
1642 gtk_widget_destroy (imhtml->tip_window);
1643 imhtml->tip_window = NULL;
1644 }
1645 imhtml->tip_timer = gtk_timeout_add (TOOLTIP_TIMEOUT,
1646 gtk_imhtml_tip,
1647 imhtml);
1648 }
1649 if (uw->bit->url)
1650 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window,
1651 imhtml->hand_cursor);
1652 return TRUE;
1653 }
1654 click = g_list_next (click);
1655 }
1656 }
1657
1658 if (imhtml->tip_timer) {
1659 gtk_timeout_remove (imhtml->tip_timer);
1660 imhtml->tip_timer = 0;
1661 }
1662 if (imhtml->tip_window) {
1663 gtk_widget_destroy (imhtml->tip_window);
1664 imhtml->tip_window = NULL;
1665 }
1666 imhtml->tip_bit = NULL;
1667
1668 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor);
1669
1670 return TRUE;
1671 }
1672
1673 static gint
1674 gtk_imhtml_leave_notify_event (GtkWidget *widget,
1675 GdkEventCrossing *event)
1676 {
1677 GtkIMHtml *imhtml = GTK_IMHTML (widget);
1678
1679 if (imhtml->tip_timer) {
1680 gtk_timeout_remove (imhtml->tip_timer);
1681 imhtml->tip_timer = 0;
1682 }
1683 if (imhtml->tip_window) {
1684 gtk_widget_destroy (imhtml->tip_window);
1685 imhtml->tip_window = NULL;
1686 }
1687 imhtml->tip_bit = NULL;
1688 return TRUE;
1689 }
1690 struct imgsv {
1691 GtkWidget *savedialog;
1692 struct im_image *img;
1693 };
1694
1695 static void
1696 save_img (GtkObject *object,
1697 gpointer data)
1698 {
1699 struct imgsv *is = data;
1700 struct im_image *img = is->img;
1701 const gchar *filename;
1702 FILE *f;
1703 filename = gtk_file_selection_get_filename(GTK_FILE_SELECTION(is->savedialog));
1704 debug_printf("Saving %s\n", filename);
1705 if (! (f=fopen(filename, "w"))) {
1706 /* There should be some sort of dialog */
1707 debug_printf("Could not open file for writing.\n");
1708 gtk_widget_destroy(is->savedialog);
1709 g_free(is);
1710 return;
1711 }
1712
1713 fwrite(img->data, 1, img->len, f);
1714 fclose(f);
1715 gtk_widget_destroy(is->savedialog);
1716 g_free(is);
1717 }
1718
1719 static void
1720 save_img_dialog (GtkObject *object,
1721 gpointer data)
1722 {
1723 struct imgsv *is = g_malloc(sizeof(struct imgsv));
1724 struct im_image *img = data;
1725 GtkWidget *savedialog = gtk_file_selection_new ("Gaim - Save Image");
1726 gtk_file_selection_set_filename (GTK_FILE_SELECTION(savedialog), img->filename);
1727 gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->cancel_button),
1728 "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy),
1729 (gpointer) savedialog);
1730
1731 is->img = img;
1732 is->savedialog = savedialog;
1733
1734 gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(savedialog)->ok_button),
1735 "clicked", GTK_SIGNAL_FUNC (save_img), is);
1736 gtk_widget_show (savedialog);
1737
1738
1739 }
1740
1741
1742 static void
1743 menu_open_url (GtkObject *object,
1744 gpointer data)
1745 {
1746 struct clickable *uw = data;
1747
1748 gtk_signal_emit (GTK_OBJECT (uw->imhtml), signals [URL_CLICKED], uw->bit->url);
1749 }
1750
1751 static void
1752 menu_copy_link (GtkObject *object,
1753 gpointer data)
1754 {
1755 struct clickable *uw = data;
1756 GtkIMHtml *imhtml = uw->imhtml;
1757
1758 if (imhtml->selected_text)
1759 g_string_free (imhtml->selected_text, TRUE);
1760
1761 gtk_imhtml_select_none (uw->imhtml);
1762
1763 imhtml->selection = TRUE;
1764 imhtml->selected_text = g_string_new (uw->bit->url);
1765
1766 gtk_selection_owner_set (GTK_WIDGET (imhtml), GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME);
1767 }
1768
1769 static gint
1770 gtk_imhtml_button_press_event (GtkWidget *widget,
1771 GdkEventButton *event)
1772 {
1773 GtkIMHtml *imhtml = GTK_IMHTML (widget);
1774 GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment;
1775 GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment;
1776 gint x, y;
1777
1778 x = event->x + hadj->value;
1779 y = event->y + vadj->value;
1780
1781 if (event->button == 1) {
1782 imhtml->sel_startx = imhtml->sel_endx = x;
1783 imhtml->sel_starty = imhtml->sel_endy = y;
1784 imhtml->selection = TRUE;
1785 if (event->type == GDK_BUTTON_PRESS) {
1786 imhtml->sel_mode = 0; /* select by letter */
1787 gtk_imhtml_select_none (imhtml);
1788 } else if (event->type == GDK_2BUTTON_PRESS) {
1789 imhtml->sel_mode = 1; /* select by word */
1790 gtk_imhtml_select_none (imhtml);
1791 } else if (event->type == GDK_3BUTTON_PRESS) {
1792 imhtml->sel_mode = 2; /* select by line */
1793 gtk_imhtml_select_bits (imhtml);
1794 }
1795 }
1796
1797 if (event->button == 3) {
1798 GList *click = imhtml->click;
1799 struct clickable *uw;
1800
1801 while (click) {
1802 uw = click->data;
1803 if ((x > uw->x) && (x < uw->x + uw->width) &&
1804 (y > uw->y) && (y < uw->y + uw->height)) {
1805 static GtkWidget *menu = NULL;
1806 GtkWidget *button;
1807
1808 /*
1809 * If a menu already exists, destroy it before creating a new one,
1810 * thus freeing-up the memory it occupied.
1811 */
1812 if(menu)
1813 gtk_widget_destroy(menu);
1814
1815 menu = gtk_menu_new();
1816
1817 if (uw->bit->url) {
1818 button = gtk_menu_item_new_with_label ("Open URL");
1819 gtk_signal_connect (GTK_OBJECT (button), "activate",
1820 GTK_SIGNAL_FUNC (menu_open_url), uw);
1821 gtk_menu_append (GTK_MENU (menu), button);
1822 gtk_widget_show (button);
1823
1824 button = gtk_menu_item_new_with_label ("Copy Link Location");
1825 gtk_signal_connect (GTK_OBJECT (button), "activate",
1826 GTK_SIGNAL_FUNC (menu_copy_link), uw);
1827 gtk_menu_append (GTK_MENU (menu), button);
1828 gtk_widget_show (button);
1829 }
1830
1831 if (uw->bit->img) {
1832 button = gtk_menu_item_new_with_label ("Save Image");
1833 gtk_signal_connect (GTK_OBJECT (button), "activate",
1834 GTK_SIGNAL_FUNC (save_img_dialog), uw->bit->img);
1835 gtk_menu_append (GTK_MENU (menu), button);
1836 gtk_widget_show (button);
1837 }
1838
1839 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 3, event->time);
1840
1841 if (imhtml->tip_timer) {
1842 gtk_timeout_remove (imhtml->tip_timer);
1843 imhtml->tip_timer = 0;
1844 }
1845 if (imhtml->tip_window) {
1846 gtk_widget_destroy (imhtml->tip_window);
1847 imhtml->tip_window = NULL;
1848 }
1849 imhtml->tip_bit = NULL;
1850
1851 return TRUE;
1852 }
1853 click = g_list_next (click);
1854 }
1855 }
1856
1857 return TRUE;
1858 }
1859
1860 static gint
1861 gtk_imhtml_button_release_event (GtkWidget *widget,
1862 GdkEventButton *event)
1863 {
1864 GtkIMHtml *imhtml = GTK_IMHTML (widget);
1865 GtkAdjustment *vadj = GTK_LAYOUT (widget)->vadjustment;
1866 GtkAdjustment *hadj = GTK_LAYOUT (widget)->hadjustment;
1867 gint x, y;
1868
1869 x = event->x + hadj->value;
1870 y = event->y + vadj->value;
1871
1872 if ((event->button == 1) && imhtml->selection) {
1873 if ((x == imhtml->sel_startx) && (y == imhtml->sel_starty) &&
1874 (imhtml->sel_mode == 0)) {
1875 imhtml->sel_startx = imhtml->sel_starty = 0;
1876 imhtml->selection = FALSE;
1877 gtk_imhtml_select_none (imhtml);
1878 } else {
1879 imhtml->sel_endx = MAX (x, 0);
1880 imhtml->sel_endy = MAX (y, 0);
1881 gtk_imhtml_select_bits (imhtml);
1882 }
1883
1884 gtk_selection_owner_set (widget, GDK_SELECTION_PRIMARY, event->time);
1885 }
1886
1887 if ((event->button == 1) && (imhtml->sel_startx == 0)) {
1888 GList *click = imhtml->click;
1889 struct clickable *uw;
1890
1891 while (click) {
1892 uw = (struct clickable *) click->data;
1893 if ((x > uw->x) && (x < uw->x + uw->width) &&
1894 (y > uw->y) && (y < uw->y + uw->height)) {
1895 gtk_signal_emit (GTK_OBJECT (imhtml), signals [URL_CLICKED],
1896 uw->bit->url);
1897 return TRUE;
1898 }
1899 click = g_list_next (click);
1900 }
1901 }
1902
1903 return TRUE;
1904 }
1905
1906 static void
1907 gtk_imhtml_selection_get (GtkWidget *widget,
1908 GtkSelectionData *sel_data,
1909 guint sel_info,
1910 guint32 time)
1911 {
1912 GtkIMHtml *imhtml;
1913 gchar *string;
1914 gint length;
1915
1916 g_return_if_fail (widget != NULL);
1917 g_return_if_fail (GTK_IS_IMHTML (widget));
1918 g_return_if_fail (sel_data->selection == GDK_SELECTION_PRIMARY);
1919
1920 imhtml = GTK_IMHTML (widget);
1921
1922 g_return_if_fail (imhtml->selected_text != NULL);
1923 g_return_if_fail (imhtml->selected_text->str != NULL);
1924
1925 if (imhtml->selected_text->len <= 0)
1926 return;
1927
1928 string = g_strdup (imhtml->selected_text->str);
1929 length = strlen (string);
1930
1931 if (sel_info == TARGET_STRING) {
1932 gtk_selection_data_set (sel_data,
1933 GDK_SELECTION_TYPE_STRING,
1934 8 * sizeof (gchar),
1935 (guchar *) string,
1936 length);
1937 } else if ((sel_info == TARGET_TEXT) || (sel_info == TARGET_COMPOUND_TEXT)) {
1938 guchar *text;
1939 GdkAtom encoding;
1940 gint format;
1941 gint new_length;
1942
1943 gdk_string_to_compound_text (string, &encoding, &format, &text, &new_length);
1944 gtk_selection_data_set (sel_data, encoding, format, text, new_length);
1945 gdk_free_compound_text (text);
1946 }
1947
1948 g_free (string);
1949 }
1950
1951 static gint
1952 gtk_imhtml_selection_clear_event (GtkWidget *widget,
1953 GdkEventSelection *event)
1954 {
1955 GtkIMHtml *imhtml;
1956
1957 g_return_val_if_fail (widget != NULL, FALSE);
1958 g_return_val_if_fail (GTK_IS_IMHTML (widget), FALSE);
1959 g_return_val_if_fail (event != NULL, FALSE);
1960 g_return_val_if_fail (event->selection == GDK_SELECTION_PRIMARY, TRUE);
1961
1962 if (!gtk_selection_clear (widget, event))
1963 return FALSE;
1964
1965 imhtml = GTK_IMHTML (widget);
1966
1967 gtk_imhtml_select_none (imhtml);
1968
1969 return TRUE;
1970 }
1971
1972 static void
1973 gtk_imhtml_adjustment_changed (GtkAdjustment *adjustment,
1974 GtkIMHtml *imhtml)
1975 {
1976 GtkLayout *layout = GTK_LAYOUT (imhtml);
1977
1978 if (!GTK_WIDGET_MAPPED (imhtml) || !GTK_WIDGET_REALIZED (imhtml))
1979 return;
1980
1981 if (layout->freeze_count)
1982 return;
1983
1984 if (layout->vadjustment->value < TOP_BORDER)
1985 gdk_window_clear_area (layout->bin_window, 0, 0,
1986 imhtml->xsize, TOP_BORDER - layout->vadjustment->value);
1987
1988 gtk_imhtml_draw_exposed (imhtml);
1989 }
1990
1991 static void
1992 gtk_imhtml_set_scroll_adjustments (GtkLayout *layout,
1993 GtkAdjustment *hadj,
1994 GtkAdjustment *vadj)
1995 {
1996 gboolean need_adjust = FALSE;
1997
1998 g_return_if_fail (layout != NULL);
1999 g_return_if_fail (GTK_IS_IMHTML (layout));
2000
2001 if (hadj)
2002 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
2003 else
2004 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2005 if (vadj)
2006 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
2007 else
2008 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
2009
2010 if (layout->hadjustment && (layout->hadjustment != hadj)) {
2011 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
2012 gtk_object_unref (GTK_OBJECT (layout->hadjustment));
2013 }
2014
2015 if (layout->vadjustment && (layout->vadjustment != vadj)) {
2016 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
2017 gtk_object_unref (GTK_OBJECT (layout->vadjustment));
2018 }
2019
2020 if (layout->hadjustment != hadj) {
2021 layout->hadjustment = hadj;
2022 gtk_object_ref (GTK_OBJECT (layout->hadjustment));
2023 gtk_object_sink (GTK_OBJECT (layout->hadjustment));
2024
2025 gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
2026 (GtkSignalFunc) gtk_imhtml_adjustment_changed, layout);
2027 need_adjust = TRUE;
2028 }
2029
2030 if (layout->vadjustment != vadj) {
2031 layout->vadjustment = vadj;
2032 gtk_object_ref (GTK_OBJECT (layout->vadjustment));
2033 gtk_object_sink (GTK_OBJECT (layout->vadjustment));
2034
2035 gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
2036 (GtkSignalFunc) gtk_imhtml_adjustment_changed, layout);
2037 need_adjust = TRUE;
2038 }
2039
2040 if (need_adjust)
2041 gtk_imhtml_adjustment_changed (NULL, GTK_IMHTML (layout));
2042 }
2043
2044 static void
2045 gtk_imhtml_class_init (GtkIMHtmlClass *class)
2046 {
2047 GObjectClass *gobject_class;
2048 GtkObjectClass *object_class;
2049 GtkWidgetClass *widget_class;
2050 GtkLayoutClass *layout_class;
2051
2052 gobject_class = (GObjectClass*) class;
2053 object_class = (GtkObjectClass*) class;
2054 widget_class = (GtkWidgetClass*) class;
2055 layout_class = (GtkLayoutClass*) class;
2056
2057 parent_class = gtk_type_class (GTK_TYPE_LAYOUT);
2058
2059 signals [URL_CLICKED] =
2060 gtk_signal_new ("url_clicked",
2061 GTK_RUN_FIRST,
2062 GTK_CLASS_TYPE (object_class),
2063 GTK_SIGNAL_OFFSET (GtkIMHtmlClass, url_clicked),
2064 gtk_marshal_NONE__POINTER,
2065 GTK_TYPE_NONE, 1,
2066 GTK_TYPE_POINTER);
2067
2068 gobject_class->finalize = gtk_imhtml_finalize;
2069
2070 widget_class->realize = gtk_imhtml_realize;
2071 widget_class->style_set = gtk_imhtml_style_set;
2072 widget_class->expose_event = gtk_imhtml_expose_event;
2073 widget_class->size_allocate = gtk_imhtml_size_allocate;
2074 widget_class->motion_notify_event = gtk_imhtml_motion_notify_event;
2075 widget_class->leave_notify_event = gtk_imhtml_leave_notify_event;
2076 widget_class->button_press_event = gtk_imhtml_button_press_event;
2077 widget_class->button_release_event = gtk_imhtml_button_release_event;
2078 widget_class->selection_get = gtk_imhtml_selection_get;
2079 widget_class->selection_clear_event = gtk_imhtml_selection_clear_event;
2080
2081 layout_class->set_scroll_adjustments = gtk_imhtml_set_scroll_adjustments;
2082 }
2083
2084 /* the font stuff is the most insane stuff. i don't understand it half
2085 * the time. so we're going to comment it. isn't that wonderful. */
2086
2087 /* when you g_strsplit a valid font name, these are the positions of all the various parts of it. */
2088 #define FNDRY 1
2089 #define FMLY 2
2090 #define WGHT 3
2091 #define SLANT 4
2092 #define SWDTH 5
2093 #define ADSTYL 6
2094 #define PXLSZ 7
2095 #define PTSZ 8
2096 #define RESX 9
2097 #define RESY 10
2098 #define SPC 11
2099 #define AVGWDTH 12
2100 #define RGSTRY 13
2101 #define ENCDNG 14
2102
2103 #if 0
2104 static const gchar*
2105 gtk_imhtml_get_font_name (PangoFontDescription *font)
2106 {
2107 return pango_font_description_get_family(font);
2108 }
2109 #endif
2110
2111 static PangoFontDescription *
2112 gtk_imhtml_font_load (GtkIMHtml *imhtml,
2113 gchar *name,
2114 gboolean bold,
2115 gboolean italics,
2116 gint fontsize)
2117 {
2118 PangoFontDescription *default_font = imhtml->default_font;
2119 PangoFontDescription *ret_font;
2120
2121 if (!name && !bold && !italics && !fontsize)
2122 return default_font;
2123 // return pango_font_description_copy(default_font);
2124
2125 ret_font = pango_font_description_copy(default_font);
2126
2127 if (name)
2128 pango_font_description_set_family(ret_font, name);
2129
2130 if (italics)
2131 pango_font_description_set_style(ret_font, PANGO_STYLE_ITALIC);
2132
2133 if (bold)
2134 pango_font_description_set_weight(ret_font, PANGO_WEIGHT_BOLD);
2135
2136 if (fontsize)
2137 {
2138 pango_font_description_set_size(ret_font,
2139 POINT_SIZE(fontsize) * PANGO_SCALE);
2140 }
2141
2142 return ret_font;
2143 }
2144
2145 static void
2146 gtk_imhtml_init (GtkIMHtml *imhtml)
2147 {
2148 static const GtkTargetEntry targets [] = {
2149 { "STRING", 0, TARGET_STRING },
2150 { "TEXT", 0, TARGET_TEXT },
2151 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }
2152 };
2153
2154 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); 98 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2);
2155 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); 99 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR);
2156 100
2157 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (imhtml), GTK_CAN_FOCUS); 101 }
2158 gtk_selection_add_targets (GTK_WIDGET (imhtml), GDK_SELECTION_PRIMARY, targets, 3); 102
2159 } 103 GtkWidget *gtk_imhtml_new(void *a, void *b)
2160 104 {
2161 GtkType 105 return GTK_WIDGET(gtk_type_new(gtk_imhtml_get_type()));
2162 gtk_imhtml_get_type (void) 106 }
2163 { 107
2164 static GtkType imhtml_type = 0; 108 GtkType gtk_imhtml_get_type()
109 {
110 static guint imhtml_type = 0;
2165 111
2166 if (!imhtml_type) { 112 if (!imhtml_type) {
2167 static const GtkTypeInfo imhtml_info = { 113 GtkTypeInfo imhtml_info = {
2168 "GtkIMHtml", 114 "GtkIMHtml",
2169 sizeof (GtkIMHtml), 115 sizeof (GtkIMHtml),
2170 sizeof (GtkIMHtmlClass), 116 sizeof (GtkIMHtmlClass),
2171 (GtkClassInitFunc) gtk_imhtml_class_init, 117 (GtkClassInitFunc) gtk_imhtml_class_init,
2172 (GtkObjectInitFunc) gtk_imhtml_init, 118 (GtkObjectInitFunc) gtk_imhtml_init,
2173 NULL, 119 NULL,
2174 NULL,
2175 NULL 120 NULL
2176 }; 121 };
2177 122
2178 imhtml_type = gtk_type_unique (GTK_TYPE_LAYOUT, &imhtml_info); 123 imhtml_type = gtk_type_unique (gtk_text_view_get_type (), &imhtml_info);
2179 } 124 }
2180 125
2181 return imhtml_type; 126 return imhtml_type;
2182 } 127 }
2183 128
2184 void 129 /* The call back for an event on a link tag. */
2185 gtk_imhtml_init_smileys (GtkIMHtml *imhtml) 130 void tag_event(GtkTextTag *tag, GObject *arg1, GdkEvent *event, GtkTextIter *arg2, char *url) {
2186 { 131 if (event->type == GDK_BUTTON_RELEASE) {
2187 g_return_if_fail (imhtml != NULL); 132 /* A link was clicked--we emit the "url_clicked" signal with the URL as the argument */
2188 g_return_if_fail (GTK_IS_IMHTML (imhtml)); 133 // if ((GdkEventButton)(event)->button == 1)
2189 134 gtk_signal_emit (G_OBJECT(arg1), signals[URL_CLICKED], url);
2190 imhtml->smiley_data = gtk_smiley_tree_new (); 135 } else if (event->type == GDK_ENTER_NOTIFY) {
2191 136 /* make a hand cursor and a tooltip timeout -- if GTK worked as it should */
2192 gtk_imhtml_associate_smiley (imhtml, ":)", smile_xpm); 137 } else if (event->type == GDK_LEAVE_NOTIFY) {
2193 gtk_imhtml_associate_smiley (imhtml, ":-)", smile_xpm); 138 /* clear timeout and make an arrow cursor again --if GTK worked as it should */
2194 139 }
2195 gtk_imhtml_associate_smiley (imhtml, ":(", sad_xpm); 140 }
2196 gtk_imhtml_associate_smiley (imhtml, ":-(", sad_xpm); 141
2197 142 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \
2198 gtk_imhtml_associate_smiley (imhtml, ";)", wink_xpm); 143 *tag = g_strndup (string, strlen (x)); \
2199 gtk_imhtml_associate_smiley (imhtml, ";-)", wink_xpm); 144 *len = strlen (x) + 1; \
2200 145 return TRUE; \
2201 gtk_imhtml_associate_smiley (imhtml, ":-p", tongue_xpm); 146 } \
2202 gtk_imhtml_associate_smiley (imhtml, ":-P", tongue_xpm); 147 (*type)++
2203 148
2204 gtk_imhtml_associate_smiley (imhtml, "=-O", scream_xpm); 149 #define VALID_OPT_TAG(x) if (!g_strncasecmp (string, x " ", strlen (x " "))) { \
2205 gtk_imhtml_associate_smiley (imhtml, "=-o", scream_xpm); 150 const gchar *c = string + strlen (x " "); \
2206 gtk_imhtml_associate_smiley (imhtml, ":-*", kiss_xpm); 151 gchar e = '"'; \
2207 gtk_imhtml_associate_smiley (imhtml, ">:O", yell_xpm); 152 gboolean quote = FALSE; \
2208 gtk_imhtml_associate_smiley (imhtml, ">:o", yell_xpm); 153 while (*c) { \
2209 gtk_imhtml_associate_smiley (imhtml, "8-)", smile8_xpm); 154 if (*c == '"' || *c == '\'') { \
2210 gtk_imhtml_associate_smiley (imhtml, ":-$", moneymouth_xpm); 155 if (quote && (*c == e)) \
2211 gtk_imhtml_associate_smiley (imhtml, ":-!", burp_xpm); 156 quote = !quote; \
2212 gtk_imhtml_associate_smiley (imhtml, ":-[", embarrassed_xpm); 157 else if (!quote) { \
2213 gtk_imhtml_associate_smiley (imhtml, ":'(", cry_xpm); 158 quote = !quote; \
2214 159 e = *c; \
2215 gtk_imhtml_associate_smiley (imhtml, ":-/", think_xpm); 160 } \
2216 gtk_imhtml_associate_smiley (imhtml, ":-\\", think_xpm); 161 } else if (!quote && (*c == '>')) \
2217 162 break; \
2218 gtk_imhtml_associate_smiley (imhtml, ":-X", crossedlips_xpm); 163 c++; \
2219 gtk_imhtml_associate_smiley (imhtml, ":-x", crossedlips_xpm); 164 } \
2220 gtk_imhtml_associate_smiley (imhtml, ":-D", bigsmile_xpm); 165 if (*c) { \
2221 gtk_imhtml_associate_smiley (imhtml, ":-d", bigsmile_xpm); 166 *tag = g_strndup (string, c - string); \
2222 gtk_imhtml_associate_smiley (imhtml, "O:-)", angel_xpm); 167 *len = c - string + 1; \
2223 } 168 return TRUE; \
2224 169 } \
2225 GtkWidget* 170 } \
2226 gtk_imhtml_new (GtkAdjustment *hadj, 171 (*type)++
2227 GtkAdjustment *vadj) 172
2228 {
2229 GtkIMHtml *imhtml = gtk_type_new (GTK_TYPE_IMHTML);
2230
2231 gtk_imhtml_set_adjustments (imhtml, hadj, vadj);
2232
2233 imhtml->im_images = NULL;
2234
2235 imhtml->bits = NULL;
2236 imhtml->click = NULL;
2237
2238 imhtml->x = 0;
2239 imhtml->y = TOP_BORDER;
2240 imhtml->llheight = 0;
2241 imhtml->llascent = 0;
2242 imhtml->line = NULL;
2243
2244 imhtml->selected_text = g_string_new ("");
2245 imhtml->scroll_timer = 0;
2246
2247 imhtml->img = NULL;
2248
2249 imhtml->smileys = TRUE;
2250 imhtml->comments = FALSE;
2251
2252 gtk_imhtml_init_smileys (imhtml);
2253
2254 return GTK_WIDGET (imhtml);
2255 }
2256
2257 void
2258 gtk_imhtml_set_adjustments (GtkIMHtml *imhtml,
2259 GtkAdjustment *hadj,
2260 GtkAdjustment *vadj)
2261 {
2262 gtk_layout_set_hadjustment (GTK_LAYOUT (imhtml), hadj);
2263 gtk_layout_set_vadjustment (GTK_LAYOUT (imhtml), vadj);
2264 }
2265
2266 void
2267 gtk_imhtml_set_defaults (GtkIMHtml *imhtml,
2268 PangoFontDescription *font,
2269 GdkColor *fg_color,
2270 GdkColor *bg_color)
2271 {
2272 g_return_if_fail (imhtml != NULL);
2273 g_return_if_fail (GTK_IS_IMHTML (imhtml));
2274
2275 if (font) {
2276 if (imhtml->default_font)
2277 pango_font_description_free(imhtml->default_font);
2278 imhtml->default_font = pango_font_description_copy(font);
2279 }
2280
2281 if (fg_color) {
2282 if (imhtml->default_fg_color)
2283 gdk_color_free (imhtml->default_fg_color);
2284 imhtml->default_fg_color = gdk_color_copy (fg_color);
2285 }
2286
2287 if (bg_color) {
2288 if (imhtml->default_bg_color)
2289 gdk_color_free (imhtml->default_bg_color);
2290 imhtml->default_bg_color = gdk_color_copy (bg_color);
2291 gdk_window_set_background (GTK_LAYOUT (imhtml)->bin_window, imhtml->default_bg_color);
2292 }
2293 }
2294
2295 void
2296 gtk_imhtml_set_img_handler (GtkIMHtml *imhtml,
2297 GtkIMHtmlImage handler)
2298 {
2299 g_return_if_fail (imhtml != NULL);
2300 g_return_if_fail (GTK_IS_IMHTML (imhtml));
2301
2302 imhtml->img = handler;
2303 }
2304
2305 void
2306 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml,
2307 gchar *text,
2308 gchar **xpm)
2309 {
2310 g_return_if_fail (imhtml != NULL);
2311 g_return_if_fail (GTK_IS_IMHTML (imhtml));
2312 g_return_if_fail (text != NULL);
2313
2314 if (xpm == NULL)
2315 gtk_smiley_tree_remove (imhtml->smiley_data, text);
2316 else
2317 gtk_smiley_tree_insert (imhtml->smiley_data, text, xpm);
2318 }
2319
2320 static void
2321 new_line (GtkIMHtml *imhtml)
2322 {
2323 GList *last = g_list_last (imhtml->line);
2324 struct line_info *li;
2325
2326 if (last) {
2327 li = last->data;
2328 if (li->x + li->width != imhtml->xsize)
2329 li->width = imhtml->xsize - li->x;
2330 }
2331
2332 last = imhtml->line;
2333 if (last) {
2334 li = last->data;
2335 if (li->height < MIN_HEIGHT) {
2336 while (last) {
2337 gint diff;
2338 li = last->data;
2339 diff = MIN_HEIGHT - li->height;
2340 li->height = MIN_HEIGHT;
2341 li->ascent += diff / 2;
2342 last = g_list_next (last);
2343 }
2344 imhtml->llheight = MIN_HEIGHT;
2345 }
2346 }
2347
2348 g_list_free (imhtml->line);
2349 imhtml->line = NULL;
2350
2351 imhtml->x = 0;
2352 imhtml->y += imhtml->llheight;
2353 imhtml->llheight = 0;
2354 imhtml->llascent = 0;
2355 }
2356
2357 static void
2358 backwards_update (GtkIMHtml *imhtml,
2359 GtkIMHtmlBit *bit,
2360 gint height,
2361 gint ascent)
2362 {
2363 gint diff;
2364 GList *ls = NULL;
2365 struct line_info *li;
2366 struct clickable *uw;
2367 struct im_image *img;
2368
2369 if (height > imhtml->llheight) {
2370 diff = height - imhtml->llheight;
2371
2372 ls = imhtml->line;
2373 while (ls) {
2374 li = ls->data;
2375 li->height += diff;
2376 if (ascent)
2377 li->ascent = ascent;
2378 else
2379 li->ascent += diff / 2;
2380 ls = g_list_next (ls);
2381 }
2382
2383 ls = imhtml->click;
2384 while (ls) {
2385 uw = ls->data;
2386 if (uw->y + diff > imhtml->y)
2387 uw->y += diff;
2388 ls = g_list_next (ls);
2389 }
2390
2391 ls = imhtml->im_images;
2392 while(ls) {
2393 img = ls->data;
2394 if (img->y + diff > imhtml->y)
2395 img->y += diff;
2396 ls = g_list_next(ls);
2397 }
2398
2399 imhtml->llheight = height;
2400 if (ascent)
2401 imhtml->llascent = ascent;
2402 else
2403 imhtml->llascent += diff / 2;
2404 }
2405 }
2406
2407 static void
2408 add_text_renderer (GtkIMHtml *imhtml,
2409 GtkIMHtmlBit *bit,
2410 gchar *text)
2411 {
2412 struct line_info *li;
2413 struct clickable *uw;
2414 PangoFontMetrics *metrics;
2415 gint width;
2416
2417 if (text)
2418 width = string_width (imhtml->context, bit->font, text);
2419 else
2420 width = 0;
2421
2422 li = g_new0 (struct line_info, 1);
2423 li->x = imhtml->x;
2424 li->y = imhtml->y;
2425 li->width = width;
2426 li->height = imhtml->llheight;
2427 if (text) {
2428 metrics = pango_context_get_metrics(imhtml->context, bit->font, NULL);
2429 li->ascent = MAX (imhtml->llascent, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE);
2430 pango_font_metrics_unref(metrics);
2431 } else
2432 li->ascent = 0;
2433 li->text = text;
2434 li->bit = bit;
2435
2436 if (bit->url) {
2437 uw = g_new0 (struct clickable, 1);
2438 uw->x = imhtml->x;
2439 uw->y = imhtml->y;
2440 uw->width = width;
2441 uw->height = imhtml->llheight;
2442 uw->imhtml = imhtml;
2443 uw->bit = bit;
2444 imhtml->click = g_list_append (imhtml->click, uw);
2445 }
2446
2447 bit->chunks = g_list_append (bit->chunks, li);
2448 imhtml->line = g_list_append (imhtml->line, li);
2449 }
2450
2451 static void
2452 add_img_renderer (GtkIMHtml *imhtml,
2453 GtkIMHtmlBit *bit)
2454 {
2455 struct line_info *li;
2456 struct clickable *uw;
2457 gint width;
2458
2459 gdk_window_get_size (bit->pm, &width, NULL);
2460
2461 li = g_new0 (struct line_info, 1);
2462 li->x = imhtml->x;
2463 li->y = imhtml->y;
2464 li->width = width;
2465 li->height = imhtml->llheight;
2466 li->ascent = 0;
2467 li->bit = bit;
2468
2469
2470 if (bit->url || bit->img) {
2471 uw = g_new0 (struct clickable, 1);
2472 uw->x = imhtml->x;
2473 uw->y = imhtml->y;
2474 uw->width = width;
2475 uw->height = imhtml->llheight;
2476 uw->imhtml = imhtml;
2477 uw->bit = bit;
2478 imhtml->click = g_list_append (imhtml->click, uw);
2479 }
2480
2481 bit->chunks = g_list_append (bit->chunks, li);
2482 imhtml->line = g_list_append (imhtml->line, li);
2483
2484 imhtml->x += width;
2485 }
2486
2487 static void
2488 gtk_imhtml_draw_bit (GtkIMHtml *imhtml,
2489 GtkIMHtmlBit *bit)
2490 {
2491 PangoFontMetrics *metrics;
2492 gint width, height;
2493
2494 g_return_if_fail (imhtml != NULL);
2495 g_return_if_fail (GTK_IS_IMHTML (imhtml));
2496 g_return_if_fail (bit != NULL);
2497
2498
2499 if ( ((bit->type == TYPE_TEXT) ||
2500 ((bit->type == TYPE_SMILEY) && !imhtml->smileys) ||
2501 ((bit->type == TYPE_COMMENT) && imhtml->comments)) &&
2502 bit->text) {
2503 gchar *copy = g_strdup (bit->text);
2504 gint pos = 0;
2505 gboolean seenspace = FALSE;
2506 gchar *tmp;
2507
2508 metrics = pango_context_get_metrics(imhtml->context, bit->font, NULL);
2509 height = (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) / PANGO_SCALE;
2510 width = string_width (imhtml->context, bit->font, bit->text);
2511
2512 if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize)) {
2513 gint remain = imhtml->xsize - imhtml->x;
2514 while (text_width (imhtml->context, bit->font, copy, pos) < remain) {
2515 if (copy [pos] == ' ')
2516 seenspace = TRUE;
2517 pos++;
2518 }
2519 if (seenspace) {
2520 while (copy [pos - 1] != ' ') pos--;
2521
2522 tmp = g_strndup (copy, pos);
2523
2524 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE);
2525 add_text_renderer (imhtml, bit, tmp);
2526 } else
2527 pos = 0;
2528 seenspace = FALSE;
2529 new_line (imhtml);
2530 }
2531
2532 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE);
2533
2534 while (pos < strlen (bit->text)) {
2535 width = string_width (imhtml->context, bit->font, copy + pos);
2536 if (imhtml->x + width > imhtml->xsize) {
2537 gint newpos = 0;
2538 gint remain = imhtml->xsize - imhtml->x;
2539 while (text_width (imhtml->context, bit->font, copy + pos, newpos) < remain) {
2540 if (copy [pos + newpos] == ' ')
2541 seenspace = TRUE;
2542 newpos++;
2543 }
2544
2545 if (seenspace)
2546 while (copy [pos + newpos - 1] != ' ') newpos--;
2547
2548 if (newpos == 0)
2549 break;
2550
2551 tmp = g_strndup (copy + pos, newpos);
2552 pos += newpos;
2553
2554 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE);
2555 add_text_renderer (imhtml, bit, tmp);
2556
2557 seenspace = FALSE;
2558 new_line (imhtml);
2559 } else {
2560 tmp = g_strdup (copy + pos);
2561
2562 backwards_update (imhtml, bit, height, pango_font_metrics_get_ascent(metrics) / PANGO_SCALE);
2563 add_text_renderer (imhtml, bit, tmp);
2564
2565 pos = strlen (bit->text);
2566
2567 imhtml->x += width;
2568 }
2569 }
2570
2571 pango_font_metrics_unref(metrics);
2572 g_free(copy);
2573 } else if ((bit->type == TYPE_SMILEY) || (bit->type == TYPE_IMG)) {
2574 if (bit->img) {
2575 GdkPixbuf *imagepb = bit->img->pb;
2576 GdkPixbuf *tmp = NULL;
2577 if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize - imhtml->x)
2578 new_line (imhtml);
2579
2580 if (gdk_pixbuf_get_width(imagepb) > imhtml->xsize) {
2581 tmp = gdk_pixbuf_scale_simple(imagepb, imhtml->xsize,
2582 gdk_pixbuf_get_height(imagepb) *
2583 imhtml->xsize/
2584 gdk_pixbuf_get_width(imagepb),
2585 GDK_INTERP_TILES);
2586 if (bit->pm)
2587 gdk_pixmap_unref (bit->pm);
2588 if (bit->bm)
2589 gdk_bitmap_unref (bit->bm);
2590 gdk_pixbuf_render_pixmap_and_mask(tmp, &(bit->pm), &(bit->bm), 100);
2591 gdk_pixbuf_unref(tmp);
2592 }
2593 else {
2594 if (bit->pm)
2595 gdk_pixmap_unref (bit->pm);
2596 if (bit->bm)
2597 gdk_bitmap_unref (bit->bm);
2598 gdk_pixbuf_render_pixmap_and_mask(imagepb, &(bit->pm), &(bit->bm), 100);
2599 }
2600 }
2601
2602 gdk_window_get_size (bit->pm, &width, &height);
2603
2604 if ((imhtml->x != 0) && ((imhtml->x + width) > imhtml->xsize))
2605 new_line (imhtml);
2606 else
2607 backwards_update (imhtml, bit, height, 0);
2608
2609 add_img_renderer (imhtml, bit);
2610 } else if (bit->type == TYPE_BR) {
2611 new_line (imhtml);
2612 add_text_renderer (imhtml, bit, NULL);
2613 } else if (bit->type == TYPE_SEP) {
2614 struct line_info *li;
2615 if (imhtml->llheight)
2616 new_line (imhtml);
2617
2618 li = g_new0 (struct line_info, 1);
2619 li->x = imhtml->x;
2620 li->y = imhtml->y;
2621 li->width = imhtml->xsize;
2622 li->height = HR_HEIGHT * 2;
2623 li->ascent = 0;
2624 li->text = NULL;
2625 li->bit = bit;
2626
2627 bit->chunks = g_list_append (bit->chunks, li);
2628
2629 imhtml->llheight = HR_HEIGHT * 2;
2630 new_line (imhtml);
2631 add_text_renderer (imhtml, bit, NULL);
2632 }
2633
2634 }
2635
2636 void
2637 gtk_imhtml_show_smileys (GtkIMHtml *imhtml,
2638 gboolean show)
2639 {
2640 g_return_if_fail (imhtml != NULL);
2641 g_return_if_fail (GTK_IS_IMHTML (imhtml));
2642
2643 imhtml->smileys = show;
2644
2645 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (imhtml)))
2646 gtk_imhtml_redraw_all (imhtml);
2647 }
2648
2649 void
2650 gtk_imhtml_show_comments (GtkIMHtml *imhtml,
2651 gboolean show)
2652 {
2653 g_return_if_fail (imhtml != NULL);
2654 g_return_if_fail (GTK_IS_IMHTML (imhtml));
2655
2656 imhtml->comments = show;
2657
2658 if (GTK_WIDGET_VISIBLE (GTK_WIDGET (imhtml)))
2659 gtk_imhtml_redraw_all (imhtml);
2660 }
2661
2662 static GdkColor *
2663 gtk_imhtml_get_color (const gchar *color)
2664 {
2665 GdkColor c;
2666
2667 if (!gdk_color_parse (color, &c))
2668 return NULL;
2669
2670 return gdk_color_copy (&c);
2671 }
2672
2673 static gboolean
2674 gtk_imhtml_is_smiley (GtkIMHtml *imhtml,
2675 const gchar *text,
2676 gint *len)
2677 {
2678 *len = gtk_smiley_tree_lookup (imhtml->smiley_data, text);
2679 return (*len > 0);
2680 }
2681
2682 static GtkIMHtmlBit *
2683 gtk_imhtml_new_bit (GtkIMHtml *imhtml,
2684 gint type,
2685 gchar *text,
2686 gint bold,
2687 gint italics,
2688 gint underline,
2689 gint strike,
2690 FontDetail *font,
2691 GdkColor *bg,
2692 gchar *url,
2693 gint pre,
2694 gint sub,
2695 gint sup)
2696 {
2697 GtkIMHtmlBit *bit = NULL;
2698
2699 g_return_val_if_fail (imhtml != NULL, NULL);
2700 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL);
2701
2702 if ((type == TYPE_TEXT) && ((text == NULL) || (strlen (text) == 0)))
2703 return NULL;
2704
2705 bit = g_new0 (GtkIMHtmlBit, 1);
2706 bit->type = type;
2707
2708 if ((text != NULL) && (strlen (text) != 0))
2709 bit->text = g_strdup (text);
2710
2711 if ((font != NULL) || bold || italics || pre) {
2712 if (font && (bold || italics || font->size || font->face || pre)) {
2713 if (pre) {
2714 bit->font = gtk_imhtml_font_load (imhtml, DEFAULT_PRE_FACE, bold, italics, font->size);
2715 } else {
2716 bit->font = gtk_imhtml_font_load (imhtml, font->face, bold, italics, font->size);
2717 }
2718 } else if (bold || italics || pre) {
2719 if (pre) {
2720 bit->font = gtk_imhtml_font_load (imhtml, DEFAULT_PRE_FACE, bold, italics, 0);
2721 } else {
2722 bit->font = gtk_imhtml_font_load (imhtml, NULL, bold, italics, 0);
2723 }
2724 }
2725
2726 if (font && (type != TYPE_BR)) {
2727 if (font->fore != NULL)
2728 bit->fore = gdk_color_copy (font->fore);
2729
2730 if (font->back != NULL)
2731 bit->back = gdk_color_copy (font->back);
2732 }
2733 }
2734
2735 if (((bit->type == TYPE_TEXT) || (bit->type == TYPE_SMILEY) || (bit->type == TYPE_COMMENT)) &&
2736 (bit->font == NULL))
2737 bit->font = pango_font_description_copy (imhtml->default_font);
2738
2739 if (bg != NULL)
2740 bit->bg = gdk_color_copy (bg);
2741
2742 bit->underline = underline;
2743 bit->strike = strike;
2744
2745 if (url != NULL)
2746 bit->url = g_strdup (url);
2747
2748 if (type == TYPE_SMILEY) {
2749 GdkColor *clr;
2750
2751 if ((font != NULL) && (font->back != NULL))
2752 clr = font->back;
2753 else
2754 clr = (bg != NULL) ? bg : imhtml->default_bg_color;
2755
2756 bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window,
2757 &bit->bm,
2758 clr,
2759 gtk_smiley_tree_image (imhtml->smiley_data, text));
2760 }
2761
2762 return bit;
2763 }
2764
2765 #define NEW_TEXT_BIT gtk_imhtml_new_bit (imhtml, TYPE_TEXT, ws, bold, italics, underline, strike, \
2766 fonts ? fonts->data : NULL, bg, url, pre, sub, sup)
2767 #define NEW_SMILEY_BIT gtk_imhtml_new_bit (imhtml, TYPE_SMILEY, ws, bold, italics, underline, strike, \
2768 fonts ? fonts->data : NULL, bg, url, pre, sub, sup)
2769 #define NEW_SEP_BIT gtk_imhtml_new_bit (imhtml, TYPE_SEP, NULL, 0, 0, 0, 0, NULL, bg, NULL, 0, 0, 0)
2770 #define NEW_BR_BIT gtk_imhtml_new_bit (imhtml, TYPE_BR, NULL, 0, 0, 0, 0, \
2771 fonts ? fonts->data : NULL, bg, NULL, 0, 0, 0)
2772 #define NEW_COMMENT_BIT gtk_imhtml_new_bit (imhtml, TYPE_COMMENT, ws, bold, italics, underline, strike, \
2773 fonts ? fonts->data : NULL, bg, url, pre, sub, sup)
2774
2775 #define NEW_BIT(bit) ws [wpos] = '\0'; \
2776 { GtkIMHtmlBit *tmp = bit; if (tmp != NULL) \
2777 newbits = g_list_append (newbits, tmp); } \
2778 wpos = 0; ws [wpos] = '\0'
2779
2780 #define UPDATE_BG_COLORS \
2781 { \
2782 GdkColormap *cmap; \
2783 GList *rev; \
2784 cmap = gtk_widget_get_colormap (GTK_WIDGET (imhtml)); \
2785 rev = g_list_last (newbits); \
2786 while (rev) { \
2787 GtkIMHtmlBit *bit = rev->data; \
2788 if (bit->bg) \
2789 gdk_color_free (bit->bg); \
2790 bit->bg = gdk_color_copy (bg); \
2791 if (bit->type == TYPE_BR) \
2792 break; \
2793 rev = g_list_previous (rev); \
2794 } \
2795 if (!rev) { \
2796 rev = g_list_last (imhtml->bits); \
2797 while (rev) { \
2798 GtkIMHtmlBit *bit = rev->data; \
2799 if (bit->bg) \
2800 gdk_color_free (bit->bg); \
2801 bit->bg = gdk_color_copy (bg); \
2802 gdk_color_alloc (cmap, bit->bg); \
2803 if (bit->type == TYPE_BR) \
2804 break; \
2805 rev = g_list_previous (rev); \
2806 } \
2807 } \
2808 }
2809 173
2810 static gboolean 174 static gboolean
2811 gtk_imhtml_is_amp_escape (const gchar *string, 175 gtk_imhtml_is_amp_escape (const gchar *string,
2812 gchar *replace, 176 gchar *replace,
2813 gint *length) 177 gint *length)
2853 return FALSE; 217 return FALSE;
2854 } 218 }
2855 219
2856 return TRUE; 220 return TRUE;
2857 } 221 }
2858
2859 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \
2860 *tag = g_strndup (string, strlen (x)); \
2861 *len = strlen (x) + 1; \
2862 return TRUE; \
2863 } \
2864 (*type)++
2865
2866 #define VALID_OPT_TAG(x) if (!g_strncasecmp (string, x " ", strlen (x " "))) { \
2867 const gchar *c = string + strlen (x " "); \
2868 gchar e = '"'; \
2869 gboolean quote = FALSE; \
2870 while (*c) { \
2871 if (*c == '"' || *c == '\'') { \
2872 if (quote && (*c == e)) \
2873 quote = !quote; \
2874 else if (!quote) { \
2875 quote = !quote; \
2876 e = *c; \
2877 } \
2878 } else if (!quote && (*c == '>')) \
2879 break; \
2880 c++; \
2881 } \
2882 if (*c) { \
2883 *tag = g_strndup (string, c - string); \
2884 *len = c - string + 1; \
2885 return TRUE; \
2886 } \
2887 } \
2888 (*type)++
2889 222
2890 static gboolean 223 static gboolean
2891 gtk_imhtml_is_tag (const gchar *string, 224 gtk_imhtml_is_tag (const gchar *string,
2892 gchar **tag, 225 gchar **tag,
2893 gint *len, 226 gint *len,
2996 while (*e && !isspace ((gint) *e)) e++; 329 while (*e && !isspace ((gint) *e)) e++;
2997 return g_strndup (a, e - a); 330 return g_strndup (a, e - a);
2998 } 331 }
2999 } 332 }
3000 333
3001 GString* 334
3002 gtk_imhtml_append_text (GtkIMHtml *imhtml, 335
3003 const gchar *text, 336 #define NEW_TEXT_BIT 0
3004 gint len, 337 #define NEW_HR_BIT 1
3005 GtkIMHtmlOptions options) 338 #define NEW_BIT(x) ws [wpos] = '\0'; \
3006 { 339 mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \
340 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \
341 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
342 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \
343 gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \
344 if (bold) \
345 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \
346 if (italics) \
347 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \
348 if (underline) \
349 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \
350 if (strike) \
351 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &siter, &iter); \
352 if (sub) \
353 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUB", &siter, &iter); \
354 if (sup) \
355 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUP", &siter, &iter); \
356 if (pre) \
357 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "PRE", &siter, &iter); \
358 if (bg) { \
359 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \
360 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
361 } \
362 if (fonts) { \
363 FontDetail *fd = fonts->data; \
364 if (fd->fore) { \
365 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \
366 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
367 } \
368 if (fd->back) { \
369 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); \
370 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
371 } \
372 if (fd->face) { \
373 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "font", fd->face, NULL); \
374 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
375 } \
376 if (fd->size) { \
377 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "size-points", (double)POINT_SIZE(fd->size), NULL); \
378 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
379 } \
380 } \
381 if (url) { \
382 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \
383 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), strdup(url)); \
384 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \
385 } \
386 wpos = 0; \
387 ws[0] = 0; \
388 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \
389
390
391 /* if (x == NEW_HR_BIT) { \
392 sep = gtk_hseparator_new(); \
393 gtk_widget_size_request(GTK_WIDGET(imhtml), &req); \
394 gtk_widget_set_size_request(sep, 20, -1); \
395 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); \
396 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), sep, anchor); \
397 gtk_widget_show(sep); \
398 } */
399
400 GString* gtk_imhtml_append_text (GtkIMHtml *imhtml,
401 const gchar *text,
402 gint len,
403 GtkIMHtmlOptions options)
404 {
405 gint pos = 0;
406 GString *str = NULL;
407 GtkTextIter iter, siter;
408 GtkTextMark *mark, *mark2;
409 GtkTextChildAnchor *anchor;
410 GtkTextTag *texttag;
411 GtkWidget *sep;
412 GtkRequisition req;
413 gchar *ws;
414 gchar *tag;
415 gchar *url = NULL;
416 gchar *bg = NULL;
417 gint tlen, wpos=0;
418 gint type;
3007 const gchar *c; 419 const gchar *c;
3008 gboolean binary = TRUE;
3009 gchar *ws;
3010 gint pos = 0;
3011 gint wpos = 0;
3012
3013 gchar *tag;
3014 gint tlen;
3015 gint type;
3016
3017 gchar amp; 420 gchar amp;
3018
3019 gint smilelen;
3020
3021 GList *newbits = NULL;
3022 421
3023 guint bold = 0, 422 guint bold = 0,
3024 italics = 0, 423 italics = 0,
3025 underline = 0, 424 underline = 0,
3026 strike = 0, 425 strike = 0,
3027 sub = 0, 426 sub = 0,
3028 sup = 0, 427 sup = 0,
3029 title = 0, 428 title = 0,
3030 pre = 0; 429 pre = 0;
430
3031 GSList *fonts = NULL; 431 GSList *fonts = NULL;
3032 GdkColor *bg = NULL;
3033 gchar *url = NULL;
3034
3035 GtkAdjustment *vadj;
3036 gboolean scrolldown = TRUE;
3037
3038 GString *retval = NULL;
3039 432
3040 g_return_val_if_fail (imhtml != NULL, NULL); 433 g_return_val_if_fail (imhtml != NULL, NULL);
3041 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); 434 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL);
3042 g_return_val_if_fail (text != NULL, NULL); 435 g_return_val_if_fail (text != NULL, NULL);
436 g_return_val_if_fail (len != 0, NULL);
437
438 c = text;
439 if (len == -1)
440 len = strlen(text);
441 ws = g_malloc(len + 1);
442 ws[0] = 0;
3043 443
3044 if (options & GTK_IMHTML_RETURN_LOG) 444 if (options & GTK_IMHTML_RETURN_LOG)
3045 retval = g_string_new (""); 445 str = g_string_new("");
3046 446
3047 vadj = GTK_LAYOUT (imhtml)->vadjustment; 447 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter);
3048 if ((vadj->value < imhtml->y - GTK_WIDGET (imhtml)->allocation.height) && 448 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE);
3049 (vadj->upper >= GTK_WIDGET (imhtml)->allocation.height))
3050 scrolldown = FALSE;
3051
3052 c = text;
3053 if (len == -1) {
3054 binary = FALSE;
3055 len = strlen (text);
3056 }
3057
3058 ws = g_malloc (len + 1);
3059 ws [0] = '\0';
3060
3061 while (pos < len) { 449 while (pos < len) {
3062 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { 450 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) {
3063 c++; 451 c++;
3064 pos++; 452 pos++;
3065 switch (type) { 453 switch (type)
3066 case 1: /* B */ 454 {
3067 case 2: /* BOLD */ 455 case 1: /* B */
3068 NEW_BIT (NEW_TEXT_BIT); 456 case 2: /* BOLD */
3069 bold++; 457 NEW_BIT (NEW_TEXT_BIT);
458 bold++;
459 break;
460 case 3: /* /B */
461 case 4: /* /BOLD */
462 NEW_BIT (NEW_TEXT_BIT);
463 if (bold)
464 bold--;
465 break;
466 case 5: /* I */
467 case 6: /* ITALIC */
468 NEW_BIT (NEW_TEXT_BIT);
469 italics++;
470 break;
471 case 7: /* /I */
472 case 8: /* /ITALIC */
473 NEW_BIT (NEW_TEXT_BIT);
474 if (italics)
475 italics--;
476 break;
477 case 9: /* U */
478 case 10: /* UNDERLINE */
479 NEW_BIT (NEW_TEXT_BIT);
480 underline++;
481 break;
482 case 11: /* /U */
483 case 12: /* /UNDERLINE */
484 NEW_BIT (NEW_TEXT_BIT);
485 if (underline)
486 underline--;
487 break;
488 case 13: /* S */
489 case 14: /* STRIKE */
490 NEW_BIT (NEW_TEXT_BIT);
491 strike++;
492 break;
493 case 15: /* /S */
494 case 16: /* /STRIKE */
495 NEW_BIT (NEW_TEXT_BIT);
496 if (strike)
497 strike--;
498 break;
499 case 17: /* SUB */
500 NEW_BIT (NEW_TEXT_BIT);
501 sub++;
502 break;
503 case 18: /* /SUB */
504 NEW_BIT (NEW_TEXT_BIT);
505 if (sub)
506 sub--;
507 break;
508 case 19: /* SUP */
509 NEW_BIT (NEW_TEXT_BIT);
510 sup++;
3070 break; 511 break;
3071 case 3: /* /B */ 512 case 20: /* /SUP */
3072 case 4: /* /BOLD */ 513 NEW_BIT (NEW_TEXT_BIT);
3073 NEW_BIT (NEW_TEXT_BIT); 514 if (sup)
3074 if (bold) 515 sup--;
3075 bold--; 516 break;
3076 break; 517 case 21: /* PRE */
3077 case 5: /* I */ 518 NEW_BIT (NEW_TEXT_BIT);
3078 case 6: /* ITALIC */ 519 pre++;
3079 NEW_BIT (NEW_TEXT_BIT); 520 break;
3080 italics++; 521 case 22: /* /PRE */
3081 break; 522 NEW_BIT (NEW_TEXT_BIT);
3082 case 7: /* /I */ 523 if (pre)
3083 case 8: /* /ITALIC */ 524 pre--;
3084 NEW_BIT (NEW_TEXT_BIT); 525 break;
3085 if (italics) 526 case 23: /* TITLE */
3086 italics--; 527 NEW_BIT (NEW_TEXT_BIT);
3087 break; 528 title++;
3088 case 9: /* U */ 529 break;
3089 case 10: /* UNDERLINE */ 530 case 24: /* /TITLE */
3090 NEW_BIT (NEW_TEXT_BIT); 531 if (title) {
3091 underline++; 532 if (options & GTK_IMHTML_NO_TITLE) {
3092 break; 533 wpos = 0;
3093 case 11: /* /U */ 534 ws [wpos] = '\0';
3094 case 12: /* /UNDERLINE */ 535 }
3095 NEW_BIT (NEW_TEXT_BIT); 536 title--;
3096 if (underline)
3097 underline--;
3098 break;
3099 case 13: /* S */
3100 case 14: /* STRIKE */
3101 NEW_BIT (NEW_TEXT_BIT);
3102 strike++;
3103 break;
3104 case 15: /* /S */
3105 case 16: /* /STRIKE */
3106 NEW_BIT (NEW_TEXT_BIT);
3107 if (strike)
3108 strike--;
3109 break;
3110 case 17: /* SUB */
3111 NEW_BIT (NEW_TEXT_BIT);
3112 sub++;
3113 break;
3114 case 18: /* /SUB */
3115 NEW_BIT (NEW_TEXT_BIT);
3116 if (sub)
3117 sub--;
3118 break;
3119 case 19: /* SUP */
3120 NEW_BIT (NEW_TEXT_BIT);
3121 sup++;
3122 break;
3123 case 20: /* /SUP */
3124 NEW_BIT (NEW_TEXT_BIT);
3125 if (sup)
3126 sup--;
3127 break;
3128 case 21: /* PRE */
3129 NEW_BIT (NEW_TEXT_BIT);
3130 pre++;
3131 break;
3132 case 22: /* /PRE */
3133 NEW_BIT (NEW_TEXT_BIT);
3134 if (pre)
3135 pre--;
3136 break;
3137 case 23: /* TITLE */
3138 NEW_BIT (NEW_TEXT_BIT);
3139 title++;
3140 break;
3141 case 24: /* /TITLE */
3142 if (title) {
3143 if (options & GTK_IMHTML_NO_TITLE) {
3144 wpos = 0;
3145 ws [wpos] = '\0';
3146 } 537 }
3147 title--; 538 break;
3148 } 539 case 25: /* BR */
3149 break; 540 ws[wpos] = '\n';
3150 case 25: /* BR */ 541 wpos++;
3151 NEW_BIT (NEW_TEXT_BIT); 542 NEW_BIT (NEW_TEXT_BIT);
3152 NEW_BIT (NEW_BR_BIT); 543 break;
3153 break; 544 case 26: /* HR */
3154 case 26: /* HR */ 545 case 42: /* HR (opt) */
3155 NEW_BIT (NEW_TEXT_BIT); 546 ws[wpos++] = '\n';
3156 NEW_BIT (NEW_SEP_BIT); 547 NEW_BIT(NEW_HR_BIT);
3157 break; 548 break;
3158 case 27: /* /FONT */ 549 case 27: /* /FONT */
3159 if (fonts) { 550 if (fonts) {
3160 FontDetail *font = fonts->data; 551 FontDetail *font = fonts->data;
3161 NEW_BIT (NEW_TEXT_BIT); 552 NEW_BIT (NEW_TEXT_BIT);
3162 fonts = g_slist_remove (fonts, font); 553 fonts = g_slist_remove (fonts, font);
3163 if (font->face) 554 if (font->face)
3164 g_free (font->face); 555 g_free (font->face);
3165 if (font->fore) 556 if (font->fore)
3166 gdk_color_free (font->fore); 557 g_free (font->fore);
3167 if (font->back) 558 if (font->back)
3168 gdk_color_free (font->back); 559 g_free (font->back);
3169 g_free (font); 560 g_free (font);
3170 } 561 }
3171 break; 562 break;
3172 case 28: /* /A */ 563 case 28: /* /A */
3173 if (url) { 564 if (url) {
3174 NEW_BIT (NEW_TEXT_BIT); 565 NEW_BIT(NEW_TEXT_BIT);
3175 g_free (url); 566 g_free(url);
3176 url = NULL; 567 url = NULL;
3177 }
3178 break;
3179 case 29: /* P */
3180 case 30: /* /P */
3181 case 31: /* H3 */
3182 case 32: /* /H3 */
3183 case 33: /* HTML */
3184 case 34: /* /HTML */
3185 case 35: /* BODY */
3186 case 36: /* /BODY */
3187 case 37: /* FONT */
3188 case 38: /* HEAD */
3189 case 39: /* /HEAD */
3190 break;
3191 case 40: /* BINARY */
3192
3193 NEW_BIT (NEW_TEXT_BIT);
3194 while (pos < len) {
3195 if (!g_strncasecmp("</BINARY>", c, strlen("</BINARY>")))
3196 break; 568 break;
3197 else {
3198 c++;
3199 pos++;
3200 } 569 }
3201 } 570 case 29: /* P */
3202 c = c - tlen; /* Because it will add this later */ 571 case 30: /* /P */
3203 break; 572 case 31: /* H3 */
3204 case 41: /* /BINARY */ 573 case 32: /* /H3 */
3205 break; 574 case 33: /* HTML */
3206 575 case 34: /* /HTML */
3207 case 42: /* HR (opt) */ 576 case 35: /* BODY */
3208 NEW_BIT (NEW_TEXT_BIT); 577 case 36: /* /BODY */
3209 NEW_BIT (NEW_SEP_BIT); 578 case 37: /* FONT */
3210 break; 579 case 38: /* HEAD */
3211 case 43: /* FONT (opt) */ 580 case 39: /* /HEAD */
3212 { 581 break;
3213 gchar *color, *back, *face, *size; 582 case 40: /* BINARY */
3214 FontDetail *font; 583 case 41: /* /BINARY */
3215 584 break;
3216 color = gtk_imhtml_get_html_opt (tag, "COLOR="); 585 case 43: /* FONT (opt) */
3217 back = gtk_imhtml_get_html_opt (tag, "BACK="); 586 {
3218 face = gtk_imhtml_get_html_opt (tag, "FACE="); 587 gchar *color, *back, *face, *size;
3219 size = gtk_imhtml_get_html_opt (tag, "SIZE="); 588 FontDetail *font, *oldfont = NULL;
3220 589 color = gtk_imhtml_get_html_opt (tag, "COLOR=");
3221 if (!(color || back || face || size)) 590 back = gtk_imhtml_get_html_opt (tag, "BACK=");
3222 break; 591 face = gtk_imhtml_get_html_opt (tag, "FACE=");
3223 592 size = gtk_imhtml_get_html_opt (tag, "SIZE=");
3224 NEW_BIT (NEW_TEXT_BIT); 593
3225 594 if (!(color || back || face || size))
3226 font = g_new0 (FontDetail, 1); 595 break;
3227 if (color && !(options & GTK_IMHTML_NO_COLOURS)) 596
3228 font->fore = gtk_imhtml_get_color (color); 597 NEW_BIT (NEW_TEXT_BIT);
3229 if (back && !(options & GTK_IMHTML_NO_COLOURS)) 598
3230 font->back = gtk_imhtml_get_color (back); 599 font = g_new0 (FontDetail, 1);
3231 if (face && !(options & GTK_IMHTML_NO_FONTS)) 600 if (fonts)
3232 font->face = g_strdup (face); 601 oldfont = fonts->data;
3233 if (size && !(options & GTK_IMHTML_NO_SIZES)) { 602
3234 if (*size == '+') { 603 if (color && !(options & GTK_IMHTML_NO_COLOURS))
3235 sscanf (size + 1, "%hd", &font->size); 604 font->fore = color;
3236 font->size += 3; 605 else if (oldfont && oldfont->fore)
3237 } else if (*size == '-') { 606 font->fore = g_strdup(oldfont->fore);
3238 sscanf (size + 1, "%hd", &font->size); 607
3239 font->size = MAX (0, 3 - font->size); 608 if (back && !(options & GTK_IMHTML_NO_COLOURS))
3240 } else if (isdigit (*size)) { 609 font->back = back;
3241 sscanf (size, "%hd", &font->size); 610 else if (oldfont && oldfont->back)
611 font->back = g_strdup(oldfont->back);
612
613 if (face && !(options & GTK_IMHTML_NO_FONTS))
614 font->face = face;
615 else if (oldfont && oldfont->face)
616 font->face = g_strdup(oldfont->face);
617
618 if (size && !(options & GTK_IMHTML_NO_SIZES)) {
619 if (*size == '+') {
620 sscanf (size + 1, "%hd", &font->size);
621 font->size += 3;
622 } else if (*size == '-') {
623 sscanf (size + 1, "%hd", &font->size);
624 font->size = MAX (0, 3 - font->size);
625 } else if (isdigit (*size)) {
626 sscanf (size, "%hd", &font->size);
627 }
628 } else if (oldfont)
629 font->size = oldfont->size;
630 g_free(size);
631 fonts = g_slist_prepend (fonts, font);
3242 } 632 }
3243 } 633 break;
3244 634 case 44: /* BODY (opt) */
3245 g_free (color); 635 if (!(options & GTK_IMHTML_NO_COLOURS)) {
3246 g_free (back); 636 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR=");
3247 g_free (face); 637 if (bgcolor) {
3248 g_free (size); 638 NEW_BIT(NEW_TEXT_BIT);
3249 639 if (bg)
3250 if (fonts) { 640 g_free(bg);
3251 FontDetail *oldfont = fonts->data; 641 bg = bgcolor;
3252 if (!font->size)
3253 font->size = oldfont->size;
3254 if (!font->face && oldfont->face)
3255 font->face = g_strdup (oldfont->face);
3256 if (!font->fore && oldfont->fore)
3257 font->fore = gdk_color_copy (oldfont->fore);
3258 if (!font->back && oldfont->back)
3259 font->back = gdk_color_copy (oldfont->back);
3260 }
3261
3262 fonts = g_slist_prepend (fonts, font);
3263 }
3264 break;
3265 case 44: /* BODY (opt) */
3266 if (!(options & GTK_IMHTML_NO_COLOURS)) {
3267 gchar *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR=");
3268 if (bgcolor) {
3269 GdkColor *tmp = gtk_imhtml_get_color (bgcolor);
3270 g_free (bgcolor);
3271 if (tmp) {
3272 NEW_BIT (NEW_TEXT_BIT);
3273 bg = tmp;
3274 UPDATE_BG_COLORS;
3275 } 642 }
3276 } 643 }
644 break;
645 case 45: /* A (opt) */
646 {
647 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF=");
648 if (href) {
649 NEW_BIT (NEW_TEXT_BIT);
650 if (url)
651 g_free (url);
652 url = href;
653 }
654 }
655 break;
656 case 47: /* P (opt) */
657 case 48: /* H3 (opt) */
658 break;
659 case 49: /* comment */
660 NEW_BIT (NEW_TEXT_BIT);
661 wpos = g_snprintf (ws, len, "%s", tag);
662 NEW_BIT (NEW_COMMENT_BIT);
663 break;
664 default:
665 break;
3277 } 666 }
3278 break;
3279 case 45: /* A (opt) */
3280 {
3281 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF=");
3282 if (href) {
3283 NEW_BIT (NEW_TEXT_BIT);
3284 g_free (url);
3285 url = href;
3286 }
3287 }
3288 break;
3289 case 46: /* IMG (opt) */
3290 {
3291 gchar *src = gtk_imhtml_get_html_opt (tag, "SRC=");
3292 gchar *id = gtk_imhtml_get_html_opt (tag, "ID=");
3293 gchar *datasize = gtk_imhtml_get_html_opt (tag, "DATASIZE=");
3294 gchar **xpm;
3295 GdkColor *clr;
3296 GtkIMHtmlBit *bit;
3297
3298 if (!src)
3299 break;
3300
3301 if (!imhtml->img && id && datasize) { /* This is an embedded IM image */
3302 char *tmp, *imagedata, *e;
3303 const gchar *alltext;
3304 struct im_image *img;
3305 GdkPixbufLoader *load;
3306 GdkPixbuf *imagepb = NULL;
3307 GError *err;
3308 NEW_BIT (NEW_TEXT_BIT);
3309 if (!id || !datasize)
3310 break;
3311 tmp = g_malloc(strlen("<DATA ID=\"\" SIZE=\"\">") +
3312 strlen(id) + strlen(datasize));
3313 g_snprintf(tmp, strlen("<DATA ID=\"\" SIZE=\"\">") +
3314 strlen(id) + strlen(datasize) + 1,
3315 "<DATA ID=\"%s\" SIZE=\"%s\">", id, datasize);
3316 alltext = c;
3317 while (g_strncasecmp(alltext, tmp, strlen(tmp)) && alltext < (c + len))
3318 alltext++;
3319 alltext = alltext + strlen("<DATA ID=\"\" SIZE=\"\">") + strlen(id) + strlen(datasize);
3320 g_free(tmp);
3321 if (atoi(datasize) > len - pos)
3322 break;
3323 imagedata = g_malloc(atoi(datasize));
3324 memcpy(imagedata, alltext, atoi(datasize));
3325
3326 if (!GTK_WIDGET_REALIZED (imhtml))
3327 gtk_widget_realize (GTK_WIDGET (imhtml));
3328
3329 img = g_new0 (struct im_image, 1);
3330 tmp = e = src;
3331 while (*tmp){
3332 if (*tmp == '/' || *tmp == '\\') {
3333 tmp++;
3334 src = tmp;
3335 } else
3336 tmp++;
3337 }
3338
3339 *tmp = '\0';
3340
3341 img->filename = g_strdup(src);
3342 img->len = atoi(datasize);
3343 if (img->len) {
3344 img->data = g_malloc(img->len);
3345 memcpy(img->data, imagedata, img->len);
3346 load = gdk_pixbuf_loader_new();
3347
3348 if (!gdk_pixbuf_loader_write(load, imagedata,
3349 img->len, &err))
3350 debug_printf("IM Image corrupt or unreadable.\n");
3351 else
3352 imagepb = gdk_pixbuf_loader_get_pixbuf(load);
3353 img->pb = imagepb;
3354 }
3355 if (imagepb) {
3356 bit = g_new0 (GtkIMHtmlBit, 1);
3357 bit->type = TYPE_IMG;
3358 bit->img = img;
3359 if (url)
3360 bit->url = g_strdup (url);
3361
3362 NEW_BIT (bit);
3363 } else {
3364 g_free(img->filename);
3365 g_free(img->data);
3366 }
3367 g_free(imagedata);
3368 g_free(e);
3369 g_free(id);
3370 g_free(datasize);
3371
3372 break;
3373 }
3374
3375 if (!imhtml->img || ((xpm = imhtml->img (src)) == NULL)) {
3376 g_free (src);
3377 break;
3378 }
3379
3380 if (!fonts || ((clr = ((FontDetail *) fonts->data)->back) == NULL))
3381 clr = (bg != NULL) ? bg : imhtml->default_bg_color;
3382
3383 if (!GTK_WIDGET_REALIZED (imhtml))
3384 gtk_widget_realize (GTK_WIDGET (imhtml));
3385
3386 bit = g_new0 (GtkIMHtmlBit, 1);
3387 bit->type = TYPE_IMG;
3388 bit->pm = gdk_pixmap_create_from_xpm_d (GTK_WIDGET (imhtml)->window,
3389 &bit->bm, clr, xpm);
3390 if (url)
3391 bit->url = g_strdup (url);
3392
3393 NEW_BIT (bit);
3394
3395 g_free (src);
3396 }
3397 break;
3398 case 47: /* P (opt) */
3399 case 48: /* H3 (opt) */
3400 break;
3401 case 49: /* comment */
3402 NEW_BIT (NEW_TEXT_BIT);
3403 wpos = g_snprintf (ws, len, "%s", tag);
3404 NEW_BIT (NEW_COMMENT_BIT);
3405 break;
3406 default:
3407 break;
3408 }
3409 g_free (tag);
3410 c += tlen; 667 c += tlen;
3411 pos += tlen; 668 pos += tlen;
3412 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &amp, &tlen)) { 669 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &amp, &tlen)) {
3413 ws [wpos++] = amp; 670 ws [wpos++] = amp;
3414 c += tlen; 671 c += tlen;
3415 pos += tlen; 672 pos += tlen;
3416 } else if (*c == '\n') { 673 } else if (*c == '\n') {
3417 if (!(options & GTK_IMHTML_NO_NEWLINE)) { 674 if (!(options & GTK_IMHTML_NO_NEWLINE)) {
675 ws[wpos] = '\n';
676 wpos++;
3418 NEW_BIT (NEW_TEXT_BIT); 677 NEW_BIT (NEW_TEXT_BIT);
3419 NEW_BIT (NEW_BR_BIT);
3420 } 678 }
3421 c++; 679 c++;
3422 pos++; 680 pos++;
3423 } else if (gtk_imhtml_is_smiley (imhtml, c, &smilelen)) {
3424 NEW_BIT (NEW_TEXT_BIT);
3425 wpos = g_snprintf (ws, smilelen + 1, "%s", c);
3426 NEW_BIT (NEW_SMILEY_BIT);
3427 c += smilelen;
3428 pos += smilelen;
3429 } else if (*c) { 681 } else if (*c) {
3430 ws [wpos++] = *c++; 682 ws [wpos++] = *c++;
3431 pos++; 683 pos++;
3432 } else { 684 } else {
3433 break; 685 break;
3434 } 686 }
3435 } 687 }
3436 688
3437 NEW_BIT (NEW_TEXT_BIT); 689 NEW_BIT(NEW_TEXT_BIT);
3438
3439 while (newbits) {
3440 GtkIMHtmlBit *bit = newbits->data;
3441 imhtml->bits = g_list_append (imhtml->bits, bit);
3442 newbits = g_list_remove (newbits, bit);
3443 gtk_imhtml_draw_bit (imhtml, bit);
3444 }
3445
3446 GTK_LAYOUT (imhtml)->height = imhtml->y;
3447 GTK_LAYOUT (imhtml)->vadjustment->upper = imhtml->y;
3448 gtk_signal_emit_by_name (GTK_OBJECT (GTK_LAYOUT (imhtml)->vadjustment), "changed");
3449
3450 gtk_widget_set_usize (GTK_WIDGET (imhtml), -1, imhtml->y);
3451
3452 if (!(options & GTK_IMHTML_NO_SCROLL) &&
3453 scrolldown &&
3454 (imhtml->y >= MAX (1,
3455 (GTK_WIDGET (imhtml)->allocation.height -
3456 (GTK_WIDGET (imhtml)->style->ythickness + BORDER_SIZE) * 2))))
3457 gtk_adjustment_set_value (vadj, imhtml->y -
3458 MAX (1, (GTK_WIDGET (imhtml)->allocation.height -
3459 (GTK_WIDGET (imhtml)->style->ythickness +
3460 BORDER_SIZE) * 2)));
3461
3462 if (url) { 690 if (url) {
3463 g_free (url); 691 g_free (url);
3464 if (retval) 692 if (str)
3465 retval = g_string_append (retval, "</A>"); 693 str = g_string_append (str, "</A>");
3466 } 694 }
3467 if (bg) 695
3468 gdk_color_free (bg); 696 if (str) {
3469 while (fonts) {
3470 FontDetail *font = fonts->data;
3471 fonts = g_slist_remove (fonts, font);
3472 if (font->face)
3473 g_free (font->face);
3474 if (font->fore)
3475 gdk_color_free (font->fore);
3476 if (font->back)
3477 gdk_color_free (font->back);
3478 g_free (font);
3479 if (retval)
3480 retval = g_string_append (retval, "</FONT>");
3481 }
3482 if (retval) {
3483 while (bold) { 697 while (bold) {
3484 retval = g_string_append (retval, "</B>"); 698 str = g_string_append (str, "</B>");
3485 bold--; 699 bold--;
3486 } 700 }
3487 while (italics) { 701 while (italics) {
3488 retval = g_string_append (retval, "</I>"); 702 str = g_string_append (str, "</I>");
3489 italics--; 703 italics--;
3490 } 704 }
3491 while (underline) { 705 while (underline) {
3492 retval = g_string_append (retval, "</U>"); 706 str = g_string_append (str, "</U>");
3493 underline--; 707 underline--;
3494 } 708 }
3495 while (strike) { 709 while (strike) {
3496 retval = g_string_append (retval, "</S>"); 710 str = g_string_append (str, "</S>");
3497 strike--; 711 strike--;
3498 } 712 }
3499 while (sub) { 713 while (sub) {
3500 retval = g_string_append (retval, "</SUB>"); 714 str = g_string_append (str, "</SUB>");
3501 sub--; 715 sub--;
3502 } 716 }
3503 while (sup) { 717 while (sup) {
3504 retval = g_string_append (retval, "</SUP>"); 718 str = g_string_append (str, "</SUP>");
3505 sup--; 719 sup--;
3506 } 720 }
3507 while (title) { 721 while (title) {
3508 retval = g_string_append (retval, "</TITLE>"); 722 str = g_string_append (str, "</TITLE>");
3509 title--; 723 title--;
3510 } 724 }
3511 while (pre) { 725 while (pre) {
3512 retval = g_string_append (retval, "</PRE>"); 726 str = g_string_append (str, "</PRE>");
3513 pre--; 727 pre--;
3514 } 728 }
3515 } 729 }
3516 g_free (ws); 730 //g_free (ws);
3517 731 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark,
3518 return retval; 732 0, TRUE, 0.0, 1.0);
3519 } 733 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark);
734 return str;
735 }
736
737 void gtk_imhtml_set_adjustments (GtkIMHtml *imhtml,
738 GtkAdjustment *hadj,
739 GtkAdjustment *vadj){}
740
741 void gtk_imhtml_set_defaults (GtkIMHtml *imhtml,
742 PangoFontDescription *font,
743 GdkColor *fg_color,
744 GdkColor *bg_color){}
745
746 void gtk_imhtml_set_img_handler (GtkIMHtml *imhtml,
747 GtkIMHtmlImage handler){}
748
749 void gtk_imhtml_associate_smiley (GtkIMHtml *imhtml,
750 gchar *text,
751 gchar **xpm){}
752 void gtk_imhtml_init_smileys (GtkIMHtml *imhtml){}
753 void gtk_imhtml_remove_smileys (GtkIMHtml *imhtml){}
754 void gtk_imhtml_reset_smileys (GtkIMHtml *imhtml){}
755 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml,
756 gboolean show){}
757
758 void gtk_imhtml_show_comments (GtkIMHtml *imhtml,
759 gboolean show){}
3520 760
3521 void 761 void
3522 gtk_imhtml_clear (GtkIMHtml *imhtml) 762 gtk_imhtml_clear (GtkIMHtml *imhtml)
3523 { 763 {
3524 GtkLayout *layout; 764 GtkTextIter start, end;
3525
3526 g_return_if_fail (imhtml != NULL);
3527 g_return_if_fail (GTK_IS_IMHTML (imhtml));
3528
3529 layout = GTK_LAYOUT (imhtml);
3530
3531 while (imhtml->bits) {
3532 GtkIMHtmlBit *bit = imhtml->bits->data;
3533 imhtml->bits = g_list_remove (imhtml->bits, bit);
3534 if (bit->text)
3535 g_free (bit->text);
3536 if (bit->font)
3537 pango_font_description_free(bit->font);
3538 //gdk_font_unref (bit->font);
3539 if (bit->fore)
3540 gdk_color_free (bit->fore);
3541 if (bit->back)
3542 gdk_color_free (bit->back);
3543 if (bit->bg)
3544 gdk_color_free (bit->bg);
3545 if (bit->url)
3546 g_free (bit->url);
3547 if (bit->pm)
3548 gdk_pixmap_unref (bit->pm);
3549 if (bit->bm)
3550 gdk_bitmap_unref (bit->bm);
3551 if (bit->img) {
3552 g_free(bit->img->filename);
3553 g_free(bit->img->data);
3554 gdk_pixbuf_unref(bit->img->pb);
3555 g_free(bit->img);
3556 }
3557
3558 while (bit->chunks) {
3559 struct line_info *li = bit->chunks->data;
3560 if (li->text)
3561 g_free (li->text);
3562 bit->chunks = g_list_remove (bit->chunks, li);
3563 g_free (li);
3564 }
3565 g_free (bit);
3566 }
3567
3568 while (imhtml->click) {
3569 g_free (imhtml->click->data);
3570 imhtml->click = g_list_remove (imhtml->click, imhtml->click->data);
3571 }
3572 765
3573 while (imhtml->im_images) { 766 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start);
3574 imhtml->im_images = g_list_remove(imhtml->im_images, imhtml->im_images->data); 767 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end);
3575 } 768 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end);
3576 769 }
3577 if (imhtml->selected_text) { 770
3578 g_string_free (imhtml->selected_text, TRUE); 771 void gtk_imhtml_page_up (GtkIMHtml *imhtml){}
3579 imhtml->selected_text = g_string_new (""); 772 void gtk_imhtml_page_down (GtkIMHtml *imhtml){}
3580 }
3581
3582 imhtml->sel_startx = 0;
3583 imhtml->sel_starty = 0;
3584 imhtml->sel_endx = 0;
3585 imhtml->sel_endx = 0;
3586 imhtml->sel_endchunk = NULL;
3587
3588 if (imhtml->tip_timer) {
3589 gtk_timeout_remove (imhtml->tip_timer);
3590 imhtml->tip_timer = 0;
3591 }
3592 if (imhtml->tip_window) {
3593 gtk_widget_destroy (imhtml->tip_window);
3594 imhtml->tip_window = NULL;
3595 }
3596 imhtml->tip_bit = NULL;
3597
3598 if (imhtml->scroll_timer) {
3599 gtk_timeout_remove (imhtml->scroll_timer);
3600 imhtml->scroll_timer = 0;
3601 }
3602
3603 g_list_free(imhtml->im_images);
3604 imhtml->im_images = NULL;
3605
3606 imhtml->x = 0;
3607 imhtml->y = TOP_BORDER;
3608 imhtml->xsize = 0;
3609 imhtml->llheight = 0;
3610 imhtml->llascent = 0;
3611 if (imhtml->line)
3612 g_list_free (imhtml->line);
3613 imhtml->line = NULL;
3614
3615 layout->hadjustment->page_size = 0;
3616 layout->hadjustment->page_increment = 0;
3617 layout->hadjustment->lower = 0;
3618 layout->hadjustment->upper = imhtml->x;
3619 gtk_adjustment_set_value (layout->hadjustment, 0);
3620
3621 layout->vadjustment->page_size = 0;
3622 layout->vadjustment->page_increment = 0;
3623 layout->vadjustment->lower = 0;
3624 layout->vadjustment->upper = imhtml->y;
3625 gtk_adjustment_set_value (layout->vadjustment, 0);
3626
3627 if (GTK_WIDGET_REALIZED (GTK_WIDGET (imhtml))) {
3628 gdk_window_set_cursor (GTK_LAYOUT (imhtml)->bin_window, imhtml->arrow_cursor);
3629 gdk_window_clear (GTK_LAYOUT (imhtml)->bin_window);
3630 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
3631 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
3632 }
3633 }
3634
3635 void
3636 gtk_imhtml_page_up (GtkIMHtml *imhtml)
3637 {
3638 GtkAdjustment *vadj;
3639
3640 g_return_if_fail (imhtml != NULL);
3641 g_return_if_fail (GTK_IS_IMHTML (imhtml));
3642
3643 vadj = GTK_LAYOUT (imhtml)->vadjustment;
3644 gtk_adjustment_set_value (vadj, MAX (vadj->value - vadj->page_increment,
3645 vadj->lower));
3646 gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed");
3647 }
3648
3649 void
3650 gtk_imhtml_page_down (GtkIMHtml *imhtml)
3651 {
3652 GtkAdjustment *vadj;
3653
3654 g_return_if_fail (imhtml != NULL);
3655 g_return_if_fail (GTK_IS_IMHTML (imhtml));
3656
3657 vadj = GTK_LAYOUT (imhtml)->vadjustment;
3658 gtk_adjustment_set_value (vadj, MIN (vadj->value + vadj->page_increment,
3659 vadj->upper - vadj->page_size));
3660 gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed");
3661 }
3662
3663 void
3664 gtk_imhtml_to_bottom (GtkIMHtml *imhtml)
3665 {
3666 GtkAdjustment *vadj;
3667
3668 g_return_if_fail (imhtml != NULL);
3669 g_return_if_fail (GTK_IS_IMHTML (imhtml));
3670
3671 vadj = GTK_LAYOUT (imhtml)->vadjustment;
3672 gtk_adjustment_set_value (vadj, vadj->upper - vadj->page_size);
3673 gtk_signal_emit_by_name (GTK_OBJECT (vadj), "changed");
3674 }