comparison src/gtkimhtml.c @ 4032:2b3a9d8f168e

[gaim-migrate @ 4238] Smileys. These are just the default smileys--I'm adding the prpl-specific smileys right now. If you want to help by creating some png's, IM me. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Tue, 03 Dec 2002 02:02:16 +0000
parents 23c430e780eb
children 3a36ec242415
comparison
equal deleted inserted replaced
4031:ec7e8c93c2ee 4032:2b3a9d8f168e
45 struct _FontDetail { 45 struct _FontDetail {
46 gushort size; 46 gushort size;
47 gchar *face; 47 gchar *face;
48 gchar *fore; 48 gchar *fore;
49 gchar *back; 49 gchar *back;
50 gchar *sml;
50 }; 51 };
52
53 struct _GtkSmileyTree {
54 GString *values;
55 GtkSmileyTree **children;
56 gchar *image;
57 };
58
59 static GtkSmileyTree*
60 gtk_smiley_tree_new ()
61 {
62 return g_new0 (GtkSmileyTree, 1);
63 }
64
65 static void
66 gtk_smiley_tree_insert (GtkSmileyTree *tree,
67 const gchar *text,
68 const gchar *path)
69 {
70 GtkSmileyTree *t = tree;
71 const gchar *x = text;
72
73 if (!strlen (x))
74 return;
75
76 while (*x) {
77 gchar *pos;
78 gint index;
79
80 if (!t->values)
81 t->values = g_string_new ("");
82
83 pos = strchr (t->values->str, *x);
84 if (!pos) {
85 t->values = g_string_append_c (t->values, *x);
86 index = t->values->len - 1;
87 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *));
88 t->children [index] = g_new0 (GtkSmileyTree, 1);
89 } else
90 index = (int) pos - (int) t->values->str;
91
92 t = t->children [index];
93
94 x++;
95 }
96
97 t->image = path;
98 }
99 gtk_smiley_tree_destroy (GtkSmileyTree *tree)
100 {
101 GSList *list = g_slist_append (NULL, tree);
102
103 while (list) {
104 GtkSmileyTree *t = list->data;
105 gint i;
106 list = g_slist_remove(list, t);
107 if (t->values) {
108 for (i = 0; i < t->values->len; i++)
109 list = g_slist_append (list, t->children [i]);
110 g_string_free (t->values, TRUE);
111 g_free (t->children);
112 }
113 g_free (t);
114 }
115 }
116
117 static GtkTextViewClass *parent_class = NULL;
118
51 119
52 /* GtkIMHtml has one signal--URL_CLICKED */ 120 /* GtkIMHtml has one signal--URL_CLICKED */
53 enum { 121 enum {
54 URL_CLICKED, 122 URL_CLICKED,
55 LAST_SIGNAL 123 LAST_SIGNAL
56 }; 124 };
57 static guint signals [LAST_SIGNAL] = { 0 }; 125 static guint signals [LAST_SIGNAL] = { 0 };
58 126
127 static void
128 gtk_imhtml_finalize (GObject *object)
129 {
130 GtkIMHtml *imhtml = GTK_IMHTML(object);
131
132 g_hash_table_foreach_remove(imhtml->smiley_data, gtk_smiley_tree_destroy, NULL);
133 gtk_smiley_tree_destroy(imhtml->default_smilies);
134 G_OBJECT_CLASS(parent_class)->finalize (object);
135 }
59 136
60 /* Boring GTK stuff */ 137 /* Boring GTK stuff */
61 static void gtk_imhtml_class_init (GtkIMHtmlClass *class) 138 static void gtk_imhtml_class_init (GtkIMHtmlClass *class)
62 { 139 {
63 GtkObjectClass *object_class; 140 GtkObjectClass *object_class;
141 GObjectClass *gobject_class;
64 object_class = (GtkObjectClass*) class; 142 object_class = (GtkObjectClass*) class;
143 gobject_class = (GObjectClass*) class;
144 parent_class = gtk_type_class(GTK_TYPE_TEXT_VIEW);
65 signals[URL_CLICKED] = gtk_signal_new("url_clicked", 145 signals[URL_CLICKED] = gtk_signal_new("url_clicked",
66 GTK_RUN_FIRST, 146 GTK_RUN_FIRST,
67 GTK_CLASS_TYPE(object_class), 147 GTK_CLASS_TYPE(object_class),
68 GTK_SIGNAL_OFFSET(GtkIMHtmlClass, url_clicked), 148 GTK_SIGNAL_OFFSET(GtkIMHtmlClass, url_clicked),
69 gtk_marshal_NONE__POINTER, 149 gtk_marshal_NONE__POINTER,
70 GTK_TYPE_NONE, 1, 150 GTK_TYPE_NONE, 1,
71 GTK_TYPE_POINTER); 151 GTK_TYPE_POINTER);
152 gobject_class->finalize = gtk_imhtml_finalize;
72 } 153 }
73 154
74 static void gtk_imhtml_init (GtkIMHtml *imhtml) 155 static void gtk_imhtml_init (GtkIMHtml *imhtml)
75 { 156 {
76 GtkTextIter iter; 157 GtkTextIter iter;
96 177
97 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ 178 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */
98 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); 179 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2);
99 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); 180 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR);
100 181
182 imhtml->smiley_data = g_hash_table_new (g_str_hash, g_str_equal);
183 imhtml->default_smilies = gtk_smiley_tree_new();
101 } 184 }
102 185
103 GtkWidget *gtk_imhtml_new(void *a, void *b) 186 GtkWidget *gtk_imhtml_new(void *a, void *b)
104 { 187 {
105 return GTK_WIDGET(gtk_type_new(gtk_imhtml_get_type())); 188 return GTK_WIDGET(gtk_type_new(gtk_imhtml_get_type()));
137 } else if (event->type == GDK_LEAVE_NOTIFY) { 220 } else if (event->type == GDK_LEAVE_NOTIFY) {
138 /* clear timeout and make an arrow cursor again --if GTK worked as it should */ 221 /* clear timeout and make an arrow cursor again --if GTK worked as it should */
139 } 222 }
140 } 223 }
141 224
225 static void
226 gtk_smiley_tree_remove (GtkSmileyTree *tree,
227 const gchar *text)
228 {
229 GtkSmileyTree *t = tree;
230 const gchar *x = text;
231 gint len = 0;
232
233 while (*x) {
234 gchar *pos;
235
236 if (!t->values)
237 return;
238
239 pos = strchr (t->values->str, *x);
240 if (pos)
241 t = t->children [(int) pos - (int) t->values->str];
242 else
243 return;
244
245 x++; len++;
246 }
247
248 if (t->image)
249 t->image = NULL;
250 }
251
252 static gint
253 gtk_smiley_tree_lookup (GtkSmileyTree *tree,
254 const gchar *text)
255 {
256 GtkSmileyTree *t = tree;
257 const gchar *x = text;
258 gint len = 0;
259
260 while (*x) {
261 gchar *pos;
262
263 if (!t->values)
264 break;
265
266 pos = strchr (t->values->str, *x);
267 if (pos)
268 t = t->children [(int) pos - (int) t->values->str];
269 else
270 break;
271
272 x++; len++;
273 }
274
275 if (t->image)
276 return len;
277
278 return 0;
279 }
280
281 void
282 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml,
283 gchar *text,
284 gchar *sml,
285 gchar *path)
286 {
287 GtkSmileyTree *tree;
288 g_return_if_fail (imhtml != NULL);
289 g_return_if_fail (GTK_IS_IMHTML (imhtml));
290 g_return_if_fail (text != NULL);
291
292 if (sml == NULL)
293 tree = imhtml->default_smilies;
294 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) {
295 } else {
296 tree = gtk_smiley_tree_new();
297 g_hash_table_insert(imhtml->smiley_data, sml, tree);
298 }
299
300 if (path == NULL)
301 gtk_smiley_tree_remove (tree, text);
302 else
303 gtk_smiley_tree_insert (tree, text, path);
304 }
305
306 static gboolean
307 gtk_imhtml_is_smiley (GtkIMHtml *imhtml,
308 GSList *fonts,
309 const gchar *text,
310 gint *len)
311 {
312 GtkSmileyTree *tree;
313 FontDetail *font;
314 char *sml = NULL;
315
316 if (fonts) {
317 font = fonts->data;
318 sml = font->sml;
319 }
320
321 if (sml == NULL)
322 tree = imhtml->default_smilies;
323 else {
324 tree = g_hash_table_lookup(imhtml->smiley_data, sml);
325 }
326 if (tree == NULL)
327 return FALSE;
328
329 *len = gtk_smiley_tree_lookup (tree, text);
330 return (*len > 0);
331 }
332
333 static gchar*
334 gtk_smiley_tree_image (GtkIMHtml *imhtml,
335 const gchar *sml,
336 const gchar *text)
337 {
338 GtkSmileyTree *t;
339 const gchar *x = text;
340
341 if (sml == NULL)
342 t = imhtml->default_smilies;
343 else
344 t = g_hash_table_lookup(imhtml->smiley_data, sml);
345
346
347 if (t == NULL)
348 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL;
349
350 while (*x) {
351 gchar *pos;
352
353 if (!t->values) {
354 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL;
355 }
356
357 pos = strchr (t->values->str, *x);
358 if (pos) {
359 t = t->children [(int) pos - (int) t->values->str];
360 } else {
361 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL;
362 }
363 x++;
364 }
365
366 return t->image;
367 }
142 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \ 368 #define VALID_TAG(x) if (!g_strncasecmp (string, x ">", strlen (x ">"))) { \
143 *tag = g_strndup (string, strlen (x)); \ 369 *tag = g_strndup (string, strlen (x)); \
144 *len = strlen (x) + 1; \ 370 *len = strlen (x) + 1; \
145 return TRUE; \ 371 return TRUE; \
146 } \ 372 } \
412 GtkRequisition req; 638 GtkRequisition req;
413 gchar *ws; 639 gchar *ws;
414 gchar *tag; 640 gchar *tag;
415 gchar *url = NULL; 641 gchar *url = NULL;
416 gchar *bg = NULL; 642 gchar *bg = NULL;
417 gint tlen, wpos=0; 643 gint tlen, smilelen, wpos=0;
418 gint type; 644 gint type;
419 const gchar *c; 645 const gchar *c;
420 gchar amp; 646 gchar amp;
421 647
422 guint bold = 0, 648 guint bold = 0,
555 g_free (font->face); 781 g_free (font->face);
556 if (font->fore) 782 if (font->fore)
557 g_free (font->fore); 783 g_free (font->fore);
558 if (font->back) 784 if (font->back)
559 g_free (font->back); 785 g_free (font->back);
786 if (font->sml)
787 g_free (font->sml);
560 g_free (font); 788 g_free (font);
561 } 789 }
562 break; 790 break;
563 case 28: /* /A */ 791 case 28: /* /A */
564 if (url) { 792 if (url) {
582 case 40: /* BINARY */ 810 case 40: /* BINARY */
583 case 41: /* /BINARY */ 811 case 41: /* /BINARY */
584 break; 812 break;
585 case 43: /* FONT (opt) */ 813 case 43: /* FONT (opt) */
586 { 814 {
587 gchar *color, *back, *face, *size; 815 gchar *color, *back, *face, *size, *sml;
588 FontDetail *font, *oldfont = NULL; 816 FontDetail *font, *oldfont = NULL;
589 color = gtk_imhtml_get_html_opt (tag, "COLOR="); 817 color = gtk_imhtml_get_html_opt (tag, "COLOR=");
590 back = gtk_imhtml_get_html_opt (tag, "BACK="); 818 back = gtk_imhtml_get_html_opt (tag, "BACK=");
591 face = gtk_imhtml_get_html_opt (tag, "FACE="); 819 face = gtk_imhtml_get_html_opt (tag, "FACE=");
592 size = gtk_imhtml_get_html_opt (tag, "SIZE="); 820 size = gtk_imhtml_get_html_opt (tag, "SIZE=");
593 821 sml = gtk_imhtml_get_html_opt (tag, "SML=");
594 if (!(color || back || face || size)) 822 if (!(color || back || face || size || sml))
595 break; 823 break;
596 824
597 NEW_BIT (NEW_TEXT_BIT); 825 NEW_BIT (NEW_TEXT_BIT);
598 826
599 font = g_new0 (FontDetail, 1); 827 font = g_new0 (FontDetail, 1);
612 840
613 if (face && !(options & GTK_IMHTML_NO_FONTS)) 841 if (face && !(options & GTK_IMHTML_NO_FONTS))
614 font->face = face; 842 font->face = face;
615 else if (oldfont && oldfont->face) 843 else if (oldfont && oldfont->face)
616 font->face = g_strdup(oldfont->face); 844 font->face = g_strdup(oldfont->face);
617 845
846 if (sml)
847 font->sml = sml;
848 else if (oldfont && oldfont->sml)
849 font->sml = g_strdup(oldfont->sml);
850
618 if (size && !(options & GTK_IMHTML_NO_SIZES)) { 851 if (size && !(options & GTK_IMHTML_NO_SIZES)) {
619 if (*size == '+') { 852 if (*size == '+') {
620 sscanf (size + 1, "%hd", &font->size); 853 sscanf (size + 1, "%hd", &font->size);
621 font->size += 3; 854 font->size += 3;
622 } else if (*size == '-') { 855 } else if (*size == '-') {
676 wpos++; 909 wpos++;
677 NEW_BIT (NEW_TEXT_BIT); 910 NEW_BIT (NEW_TEXT_BIT);
678 } 911 }
679 c++; 912 c++;
680 pos++; 913 pos++;
681 } else if (*c) { 914 } else if (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen)) {
915 FontDetail *fd;
916 gchar *sml = NULL;
917 if (fonts) {
918 fd = fonts->data;
919 sml = fd->sml;
920 }
921 NEW_BIT (NEW_TEXT_BIT);
922 wpos = g_snprintf (ws, smilelen + 1, "%s", c);
923 gtk_text_buffer_insert_pixbuf(imhtml->text_buffer, &iter, gdk_pixbuf_new_from_file(gtk_smiley_tree_image (imhtml, sml, ws), NULL));
924 c += smilelen;
925 pos += smilelen;
926 wpos = 0;
927 ws[0] = 0;
928 } else if (*c) {
682 ws [wpos++] = *c++; 929 ws [wpos++] = *c++;
683 pos++; 930 pos++;
684 } else { 931 } else {
685 break; 932 break;
686 } 933 }
691 g_free (url); 938 g_free (url);
692 if (str) 939 if (str)
693 str = g_string_append (str, "</A>"); 940 str = g_string_append (str, "</A>");
694 } 941 }
695 942
943 while (fonts) {
944 FontDetail *font = fonts->data;
945 fonts = g_slist_remove (fonts, font);
946 if (font->face)
947 g_free (font->face);
948 if (font->fore)
949 g_free (font->fore);
950 if (font->back)
951 g_free (font->back);
952 if (font->sml)
953 g_free (font->sml);
954 g_free (font);
955 if (str)
956 str = g_string_append (str, "</FONT>");
957 }
958
696 if (str) { 959 if (str) {
697 while (bold) { 960 while (bold) {
698 str = g_string_append (str, "</B>"); 961 str = g_string_append (str, "</B>");
699 bold--; 962 bold--;
700 } 963 }
725 while (pre) { 988 while (pre) {
726 str = g_string_append (str, "</PRE>"); 989 str = g_string_append (str, "</PRE>");
727 pre--; 990 pre--;
728 } 991 }
729 } 992 }
730 g_free(ws); 993 g_free (ws);
731 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, 994 if (!(options & GTK_IMHTML_NO_SCROLL))
732 0, TRUE, 0.0, 1.0); 995 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark,
996 0, TRUE, 0.0, 1.0);
733 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); 997 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark);
734 return str; 998 return str;
735 } 999 }
736 1000
737 void gtk_imhtml_set_adjustments (GtkIMHtml *imhtml, 1001 void gtk_imhtml_set_adjustments (GtkIMHtml *imhtml,
744 GdkColor *bg_color){} 1008 GdkColor *bg_color){}
745 1009
746 void gtk_imhtml_set_img_handler (GtkIMHtml *imhtml, 1010 void gtk_imhtml_set_img_handler (GtkIMHtml *imhtml,
747 GtkIMHtmlImage handler){} 1011 GtkIMHtmlImage handler){}
748 1012
749 void gtk_imhtml_associate_smiley (GtkIMHtml *imhtml,
750 gchar *text,
751 gchar **xpm){}
752 void gtk_imhtml_init_smileys (GtkIMHtml *imhtml){} 1013 void gtk_imhtml_init_smileys (GtkIMHtml *imhtml){}
753 void gtk_imhtml_remove_smileys (GtkIMHtml *imhtml){} 1014 void gtk_imhtml_remove_smileys (GtkIMHtml *imhtml){}
754 void gtk_imhtml_reset_smileys (GtkIMHtml *imhtml){} 1015 void gtk_imhtml_reset_smileys (GtkIMHtml *imhtml){}
755 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml, 1016 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml,
756 gboolean show){} 1017 gboolean show){}