Mercurial > pidgin
annotate src/gtkimhtml.c @ 7735:edebf99a5ec4
[gaim-migrate @ 8380]
WYSIWYGation of the smileys. These will only WYSIWYG when you use the select
smiley dialog, although with the smiley tree being so perfect for something
like lookup smiley while you search, we could easily auto-replace smileys.
But then we would have to worry about stuff like :) and :)) being different.
I'm going to leave it this way for now.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Thu, 04 Dec 2003 05:06:59 +0000 |
parents | e11cef6aabba |
children | 662a33ce4343 |
rev | line source |
---|---|
1428 | 1 /* |
2 * GtkIMHtml | |
3 * | |
4 * Copyright (C) 2000, Eric Warmenhoven <warmenhoven@yahoo.com> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 | |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
22 #ifdef HAVE_CONFIG_H |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
23 #include <config.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
24 #endif |
1428 | 25 #include "gtkimhtml.h" |
7358 | 26 #include "gtksourceiter.h" |
1428 | 27 #include <gtk/gtk.h> |
4895 | 28 #include <glib/gerror.h> |
4046 | 29 #include <gdk/gdkkeysyms.h> |
1428 | 30 #include <string.h> |
31 #include <ctype.h> | |
32 #include <stdio.h> | |
4629 | 33 #include <stdlib.h> |
1428 | 34 #include <math.h> |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
35 #ifdef HAVE_LANGINFO_CODESET |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
36 #include <langinfo.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
37 #include <locale.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
38 #endif |
1428 | 39 |
4417 | 40 #ifdef ENABLE_NLS |
41 # include <libintl.h> | |
42 # define _(x) gettext(x) | |
43 # ifdef gettext_noop | |
44 # define N_(String) gettext_noop (String) | |
45 # else | |
46 # define N_(String) (String) | |
47 # endif | |
48 #else | |
49 # define N_(String) (String) | |
50 # define _(x) (x) | |
51 #endif | |
52 | |
4735 | 53 #include <pango/pango-font.h> |
54 | |
5105 | 55 /* GTK+ < 2.2.2 hack, see ui.h for details. */ |
56 #ifndef GTK_WRAP_WORD_CHAR | |
57 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD | |
58 #endif | |
59 | |
4735 | 60 #define TOOLTIP_TIMEOUT 500 |
61 | |
7694 | 62 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); |
63 | |
3922 | 64 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
65 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | |
66 #define MAX_FONT_SIZE 7 | |
5367 | 67 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
3928 | 68 static gint _point_sizes [] = { 8, 10, 12, 14, 20, 30, 40 }; |
2349
60c716c32c40
[gaim-migrate @ 2362]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2348
diff
changeset
|
69 |
4032 | 70 static GtkSmileyTree* |
71 gtk_smiley_tree_new () | |
72 { | |
73 return g_new0 (GtkSmileyTree, 1); | |
74 } | |
75 | |
76 static void | |
77 gtk_smiley_tree_insert (GtkSmileyTree *tree, | |
4263 | 78 GtkIMHtmlSmiley *smiley) |
4032 | 79 { |
80 GtkSmileyTree *t = tree; | |
4263 | 81 const gchar *x = smiley->smile; |
4032 | 82 |
83 if (!strlen (x)) | |
84 return; | |
85 | |
86 while (*x) { | |
87 gchar *pos; | |
88 gint index; | |
89 | |
90 if (!t->values) | |
91 t->values = g_string_new (""); | |
92 | |
93 pos = strchr (t->values->str, *x); | |
94 if (!pos) { | |
95 t->values = g_string_append_c (t->values, *x); | |
96 index = t->values->len - 1; | |
97 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); | |
98 t->children [index] = g_new0 (GtkSmileyTree, 1); | |
99 } else | |
7386 | 100 index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str); |
4032 | 101 |
102 t = t->children [index]; | |
103 | |
104 x++; | |
105 } | |
106 | |
4263 | 107 t->image = smiley; |
4032 | 108 } |
4041 | 109 |
4263 | 110 |
4264 | 111 void gtk_smiley_tree_destroy (GtkSmileyTree *tree) |
4032 | 112 { |
113 GSList *list = g_slist_append (NULL, tree); | |
114 | |
115 while (list) { | |
116 GtkSmileyTree *t = list->data; | |
117 gint i; | |
118 list = g_slist_remove(list, t); | |
7384 | 119 if (t && t->values) { |
4032 | 120 for (i = 0; i < t->values->len; i++) |
121 list = g_slist_append (list, t->children [i]); | |
122 g_string_free (t->values, TRUE); | |
123 g_free (t->children); | |
124 } | |
125 g_free (t); | |
126 } | |
127 } | |
128 | |
5967 | 129 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) |
130 { | |
131 GdkRectangle rect; | |
132 | |
133 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
134 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
135 GList *iter = GTK_IMHTML(widget)->scalables; | |
136 | |
137 while(iter){ | |
138 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
139 scale->scale(scale, rect.width, rect.height); | |
140 | |
141 iter = iter->next; | |
142 } | |
143 } | |
144 | |
145 widget->old_rect = rect; | |
146 return FALSE; | |
147 } | |
148 | |
149 static gint | |
150 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
151 { | |
152 PangoLayout *layout; | |
153 | |
154 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
155 | |
156 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
157 | |
158 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, | |
159 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, | |
160 "tooltip", 0, 0, -1, -1); | |
161 | |
162 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
163 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
164 | |
165 g_object_unref(layout); | |
166 return FALSE; | |
167 } | |
168 | |
169 static gint | |
170 gtk_imhtml_tip (gpointer data) | |
171 { | |
172 GtkIMHtml *imhtml = data; | |
173 PangoFontMetrics *font; | |
174 PangoLayout *layout; | |
175 | |
176 gint gap, x, y, h, w, scr_w, baseline_skip; | |
177 | |
178 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
179 | |
180 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
181 imhtml->tip_timer = 0; | |
182 return FALSE; | |
183 } | |
184 | |
185 if (imhtml->tip_window){ | |
186 gtk_widget_destroy (imhtml->tip_window); | |
187 imhtml->tip_window = NULL; | |
188 } | |
189 | |
190 imhtml->tip_timer = 0; | |
191 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
192 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
193 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
194 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
195 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
196 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
197 | |
198 gtk_widget_ensure_style (imhtml->tip_window); | |
199 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
200 font = pango_font_get_metrics(pango_context_load_font(pango_layout_get_context(layout), | |
201 imhtml->tip_window->style->font_desc), | |
202 NULL); | |
203 | |
204 | |
205 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
206 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + | |
207 pango_font_metrics_get_descent(font))/ 4); | |
208 | |
209 if (gap < 2) | |
210 gap = 2; | |
211 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
212 pango_font_metrics_get_descent(font)); | |
213 w = 8 + scr_w; | |
214 h = 8 + baseline_skip; | |
215 | |
216 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
217 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
218 y += GTK_WIDGET(imhtml)->allocation.y; | |
219 | |
220 scr_w = gdk_screen_width(); | |
221 | |
222 x -= ((w >> 1) + 4); | |
223 | |
224 if ((x + w) > scr_w) | |
225 x -= (x + w) - scr_w; | |
226 else if (x < 0) | |
227 x = 0; | |
228 | |
229 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
230 pango_font_metrics_get_descent(font)); | |
231 | |
232 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
233 gtk_widget_show (imhtml->tip_window); | |
234 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
235 | |
236 pango_font_metrics_unref(font); | |
237 g_object_unref(layout); | |
238 | |
239 return FALSE; | |
240 } | |
241 | |
242 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
243 { | |
244 GtkTextIter iter; | |
245 GdkWindow *win = event->window; | |
246 int x, y; | |
247 char *tip = NULL; | |
248 GSList *tags = NULL, *templist = NULL; | |
249 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
250 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
251 event->x, event->y, &x, &y); | |
252 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
253 tags = gtk_text_iter_get_tags(&iter); | |
254 | |
255 templist = tags; | |
256 while (templist) { | |
257 GtkTextTag *tag = templist->data; | |
258 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
259 if (tip) | |
260 break; | |
261 templist = templist->next; | |
262 } | |
263 | |
264 if (GTK_IMHTML(imhtml)->tip) { | |
265 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
266 return FALSE; | |
267 } | |
268 /* We've left the cell. Remove the timeout and create a new one below */ | |
269 if (GTK_IMHTML(imhtml)->tip_window) { | |
270 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
271 GTK_IMHTML(imhtml)->tip_window = NULL; | |
272 } | |
7694 | 273 if (GTK_IMHTML(imhtml)->editable) |
274 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->text_cursor); | |
275 else | |
276 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 277 if (GTK_IMHTML(imhtml)->tip_timer) |
278 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
279 GTK_IMHTML(imhtml)->tip_timer = 0; | |
280 } | |
281 | |
282 if(tip){ | |
7709 | 283 if (!GTK_IMHTML(imhtml)->editable) |
7707 | 284 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); |
5967 | 285 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, |
286 gtk_imhtml_tip, imhtml); | |
287 } | |
288 | |
289 GTK_IMHTML(imhtml)->tip = tip; | |
290 g_slist_free(tags); | |
291 return FALSE; | |
292 } | |
293 | |
294 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
295 { | |
296 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
297 if (GTK_IMHTML(imhtml)->tip_window) { | |
298 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
299 GTK_IMHTML(imhtml)->tip_window = NULL; | |
300 } | |
301 if (GTK_IMHTML(imhtml)->tip_timer) { | |
302 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
303 GTK_IMHTML(imhtml)->tip_timer = 0; | |
304 } | |
7694 | 305 if (GTK_IMHTML(imhtml)->editable) |
306 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->text_cursor); | |
307 else | |
308 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 309 |
310 /* propogate the event normally */ | |
311 return FALSE; | |
312 } | |
313 | |
6066 | 314 /* |
315 * XXX - This should be removed eventually. | |
316 * | |
317 * This function exists to work around a gross bug in GtkTextView. | |
318 * Basically, we short circuit ctrl+a and ctrl+end because they make | |
319 * el program go boom. | |
320 * | |
321 * It's supposed to be fixed in gtk2.2. You can view the bug report at | |
322 * http://bugzilla.gnome.org/show_bug.cgi?id=107939 | |
323 */ | |
324 gboolean gtk_key_pressed_cb(GtkWidget *imhtml, GdkEventKey *event, gpointer data) | |
325 { | |
326 if (event->state & GDK_CONTROL_MASK) | |
327 switch (event->keyval) { | |
328 case 'a': | |
329 return TRUE; | |
330 break; | |
331 | |
332 case GDK_Home: | |
333 return TRUE; | |
334 break; | |
335 | |
336 case GDK_End: | |
337 return TRUE; | |
338 break; | |
339 } | |
340 | |
341 return FALSE; | |
342 } | |
343 | |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
344 #if GTK_CHECK_VERSION(2,2,0) |
7346 | 345 static GtkIMHtmlCopyable *gtk_imhtml_copyable_new(GtkIMHtml *imhtml, GtkTextMark *mark, const gchar *text) |
346 { | |
347 GtkIMHtmlCopyable *copy = g_malloc(sizeof(GtkIMHtmlCopyable)); | |
348 copy->mark = mark; | |
349 copy->text = g_strdup(text); | |
350 imhtml->copyables = g_slist_append(imhtml->copyables, copy); | |
351 return copy; | |
352 } | |
353 | |
354 static void copy_clipboard_cb(GtkIMHtml *imhtml, GtkClipboard *clipboard) | |
355 { | |
356 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
357 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
358 GtkTextIter start, end, smiley, last; | |
359 GString *str = g_string_new(NULL); | |
360 char *text; | |
361 | |
362 GSList *copyables; | |
363 | |
364 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); | |
365 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
366 | |
367 if (gtk_text_iter_equal(&start, &end)) | |
368 return; | |
369 | |
370 gtk_text_iter_order(&start, &end); | |
371 last = start; | |
372 | |
373 for (copyables = imhtml->copyables; copyables != NULL; copyables = copyables->next) { | |
374 GtkIMHtmlCopyable *copy = GTK_IMHTML_COPYABLE(copyables->data); | |
375 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &smiley, copy->mark); | |
376 if (gtk_text_iter_compare(&end, &smiley) < 0) { | |
377 break; | |
378 } | |
379 if (gtk_text_iter_compare(&last, &smiley) <= 0) { | |
380 text = gtk_text_buffer_get_text(imhtml->text_buffer, &last, &smiley, FALSE); | |
381 str = g_string_append(str, text); | |
382 str = g_string_append(str, copy->text); | |
383 last = smiley; | |
384 g_free(text); | |
385 } | |
386 } | |
387 text = gtk_text_buffer_get_text(imhtml->text_buffer, &last, &end, FALSE); | |
388 str = g_string_append(str, text); | |
389 g_free(text); | |
7353 | 390 |
7354 | 391 if (!gtk_text_iter_equal(&start, &last)) |
392 gtk_clipboard_set_text(clipboard ? clipboard : | |
393 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), | |
394 str->str, str->len); | |
7346 | 395 g_string_free(str, TRUE); |
396 } | |
397 | |
398 static gboolean button_release_cb(GtkIMHtml *imhtml, GdkEventButton event, gpointer the_foibles_of_man) | |
399 { | |
400 copy_clipboard_cb(imhtml, gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY)); | |
401 return FALSE; | |
402 } | |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
403 #endif |
5967 | 404 |
4263 | 405 |
4032 | 406 static GtkTextViewClass *parent_class = NULL; |
407 | |
3922 | 408 /* GtkIMHtml has one signal--URL_CLICKED */ |
1428 | 409 enum { |
410 URL_CLICKED, | |
411 LAST_SIGNAL | |
412 }; | |
413 static guint signals [LAST_SIGNAL] = { 0 }; | |
414 | |
4032 | 415 static void |
416 gtk_imhtml_finalize (GObject *object) | |
417 { | |
418 GtkIMHtml *imhtml = GTK_IMHTML(object); | |
4895 | 419 GList *scalables; |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
420 #if GTK_CHECK_VERSION(2,2,0) |
7346 | 421 GSList *copyables; |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
422 #endif |
7346 | 423 |
4138 | 424 g_hash_table_destroy(imhtml->smiley_data); |
4032 | 425 gtk_smiley_tree_destroy(imhtml->default_smilies); |
4138 | 426 gdk_cursor_unref(imhtml->hand_cursor); |
427 gdk_cursor_unref(imhtml->arrow_cursor); | |
7694 | 428 gdk_cursor_unref(imhtml->text_cursor); |
4735 | 429 if(imhtml->tip_window){ |
430 gtk_widget_destroy(imhtml->tip_window); | |
431 } | |
432 if(imhtml->tip_timer) | |
433 gtk_timeout_remove(imhtml->tip_timer); | |
434 | |
4895 | 435 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) { |
436 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); | |
437 scale->free(scale); | |
438 } | |
7346 | 439 |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
440 #if GTK_CHECK_VERSION(2,2,0) |
7346 | 441 for (copyables = imhtml->copyables; copyables; copyables = copyables->next) { |
442 GtkIMHtmlCopyable *copy = GTK_IMHTML_COPYABLE(copyables->data); | |
443 g_free(copy->text); | |
444 g_free(copy); | |
445 } | |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
446 #endif |
4895 | 447 g_list_free(imhtml->scalables); |
4032 | 448 G_OBJECT_CLASS(parent_class)->finalize (object); |
449 } | |
1428 | 450 |
3922 | 451 /* Boring GTK stuff */ |
452 static void gtk_imhtml_class_init (GtkIMHtmlClass *class) | |
1428 | 453 { |
3922 | 454 GtkObjectClass *object_class; |
4032 | 455 GObjectClass *gobject_class; |
3922 | 456 object_class = (GtkObjectClass*) class; |
4032 | 457 gobject_class = (GObjectClass*) class; |
458 parent_class = gtk_type_class(GTK_TYPE_TEXT_VIEW); | |
4417 | 459 signals[URL_CLICKED] = g_signal_new("url_clicked", |
460 G_TYPE_FROM_CLASS(gobject_class), | |
461 G_SIGNAL_RUN_FIRST, | |
462 G_STRUCT_OFFSET(GtkIMHtmlClass, url_clicked), | |
463 NULL, | |
464 0, | |
465 g_cclosure_marshal_VOID__POINTER, | |
466 G_TYPE_NONE, 1, | |
467 G_TYPE_POINTER); | |
4032 | 468 gobject_class->finalize = gtk_imhtml_finalize; |
1428 | 469 } |
470 | |
3922 | 471 static void gtk_imhtml_init (GtkIMHtml *imhtml) |
1428 | 472 { |
3922 | 473 GtkTextIter iter; |
474 imhtml->text_buffer = gtk_text_buffer_new(NULL); | |
475 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); | |
476 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); | |
477 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); | |
5105 | 478 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); |
3922 | 479 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); |
480 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ | |
3465 | 481 |
3922 | 482 /* These tags will be used often and can be reused--we create them on init and then apply them by name |
483 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ | |
484 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); | |
485 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); | |
486 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); | |
487 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); | |
488 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); | |
489 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); | |
490 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); | |
7295 | 491 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); |
7707 | 492 gtk_text_buffer_create_tag(imhtml->text_buffer, "LINK", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
3922 | 493 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
494 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | |
495 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | |
7694 | 496 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); |
2993 | 497 |
4253 | 498 imhtml->show_smileys = TRUE; |
6124 | 499 imhtml->show_comments = TRUE; |
4253 | 500 |
4892 | 501 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 502 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4032 | 503 imhtml->default_smilies = gtk_smiley_tree_new(); |
4735 | 504 |
4944 | 505 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); |
4735 | 506 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); |
4944 | 507 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); |
6066 | 508 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); |
7694 | 509 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
510 #if GTK_CHECK_VERSION(2,2,0) |
7353 | 511 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); |
7346 | 512 g_signal_connect(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml); |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
513 #endif |
4944 | 514 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); |
4735 | 515 |
516 imhtml->tip = NULL; | |
517 imhtml->tip_timer = 0; | |
518 imhtml->tip_window = NULL; | |
4895 | 519 |
7694 | 520 imhtml->edit.bold = NULL; |
521 imhtml->edit.italic = NULL; | |
522 imhtml->edit.underline = NULL; | |
7714 | 523 imhtml->edit.forecolor = NULL; |
524 imhtml->edit.backcolor = NULL; | |
7717 | 525 imhtml->edit.fontface = NULL; |
7714 | 526 |
7694 | 527 imhtml->format_spans = NULL; |
528 | |
4895 | 529 imhtml->scalables = NULL; |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
530 #if GTK_CHECK_VERSION(2,2,0) |
7346 | 531 imhtml->copyables = NULL; |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
532 #endif |
7694 | 533 gtk_imhtml_set_editable(imhtml, FALSE); |
2993 | 534 } |
535 | |
3922 | 536 GtkWidget *gtk_imhtml_new(void *a, void *b) |
1428 | 537 { |
4635 | 538 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); |
1428 | 539 } |
540 | |
4635 | 541 GType gtk_imhtml_get_type() |
1428 | 542 { |
4635 | 543 static GType imhtml_type = 0; |
1428 | 544 |
545 if (!imhtml_type) { | |
4635 | 546 static const GTypeInfo imhtml_info = { |
547 sizeof(GtkIMHtmlClass), | |
548 NULL, | |
549 NULL, | |
550 (GClassInitFunc) gtk_imhtml_class_init, | |
551 NULL, | |
552 NULL, | |
1428 | 553 sizeof (GtkIMHtml), |
4635 | 554 0, |
555 (GInstanceInitFunc) gtk_imhtml_init | |
1428 | 556 }; |
4635 | 557 |
558 imhtml_type = g_type_register_static(gtk_text_view_get_type(), | |
559 "GtkIMHtml", &imhtml_info, 0); | |
1428 | 560 } |
561 | |
562 return imhtml_type; | |
563 } | |
564 | |
4417 | 565 struct url_data { |
566 GObject *object; | |
567 gchar *url; | |
568 }; | |
569 | |
570 static void url_open(GtkWidget *w, struct url_data *data) { | |
571 if(!data) return; | |
572 | |
573 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); | |
574 | |
575 g_object_unref(data->object); | |
576 g_free(data->url); | |
577 g_free(data); | |
578 } | |
5582 | 579 |
4417 | 580 static void url_copy(GtkWidget *w, gchar *url) { |
581 GtkClipboard *clipboard; | |
582 | |
5293
ead927e2543f
[gaim-migrate @ 5665]
Christian Hammond <chipx86@chipx86.com>
parents:
5282
diff
changeset
|
583 clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
4417 | 584 gtk_clipboard_set_text(clipboard, url, -1); |
5582 | 585 |
586 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | |
587 gtk_clipboard_set_text(clipboard, url, -1); | |
4417 | 588 } |
589 | |
590 /* The callback for an event on a link tag. */ | |
5091 | 591 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) { |
4417 | 592 GdkEventButton *event_button = (GdkEventButton *) event; |
593 | |
3922 | 594 if (event->type == GDK_BUTTON_RELEASE) { |
4417 | 595 if (event_button->button == 1) { |
596 GtkTextIter start, end; | |
597 /* we shouldn't open a URL if the user has selected something: */ | |
598 gtk_text_buffer_get_selection_bounds( | |
599 gtk_text_iter_get_buffer(arg2), &start, &end); | |
600 if(gtk_text_iter_get_offset(&start) != | |
601 gtk_text_iter_get_offset(&end)) | |
602 return FALSE; | |
603 | |
604 /* A link was clicked--we emit the "url_clicked" signal | |
605 * with the URL as the argument */ | |
5091 | 606 g_signal_emit(imhtml, signals[URL_CLICKED], 0, url); |
4417 | 607 return FALSE; |
608 } else if(event_button->button == 3) { | |
4745 | 609 GtkWidget *img, *item, *menu; |
4417 | 610 struct url_data *tempdata = g_new(struct url_data, 1); |
5091 | 611 tempdata->object = g_object_ref(imhtml); |
4417 | 612 tempdata->url = g_strdup(url); |
4745 | 613 |
5091 | 614 /* Don't want the tooltip around if user right-clicked on link */ |
615 if (GTK_IMHTML(imhtml)->tip_window) { | |
616 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
617 GTK_IMHTML(imhtml)->tip_window = NULL; | |
618 } | |
619 if (GTK_IMHTML(imhtml)->tip_timer) { | |
620 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
621 GTK_IMHTML(imhtml)->tip_timer = 0; | |
622 } | |
7694 | 623 if (GTK_IMHTML(imhtml)->editable) |
624 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); | |
625 else | |
626 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
4417 | 627 menu = gtk_menu_new(); |
4745 | 628 |
4417 | 629 /* buttons and such */ |
630 | |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
631 if (!strncmp(url, "mailto:", 7)) |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
632 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
633 /* Copy E-Mail Address */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
634 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
635 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
636 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
637 _("_Copy E-Mail Address")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
638 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
639 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
640 G_CALLBACK(url_copy), url + 7); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
641 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
642 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
643 else |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
644 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
645 /* Copy Link Location */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
646 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
647 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
648 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
649 _("_Copy Link Location")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
650 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
651 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
652 G_CALLBACK(url_copy), url); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
653 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
654 |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
655 /* Open Link in Browser */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
656 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
657 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
658 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
659 _("_Open Link in Browser")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
660 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
661 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
662 G_CALLBACK(url_open), tempdata); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
663 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
664 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
665 |
4756 | 666 |
4417 | 667 gtk_widget_show_all(menu); |
4756 | 668 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
669 event_button->button, event_button->time); | |
4745 | 670 |
4417 | 671 return TRUE; |
672 } | |
1428 | 673 } |
4417 | 674 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) |
675 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
676 be caught by the regular GtkTextView menu */ | |
677 else | |
678 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1428 | 679 } |
680 | |
4298 | 681 /* this isn't used yet |
4032 | 682 static void |
4263 | 683 gtk_smiley_tree_remove (GtkSmileyTree *tree, |
684 GtkIMHtmlSmiley *smiley) | |
4032 | 685 { |
686 GtkSmileyTree *t = tree; | |
4263 | 687 const gchar *x = smiley->smile; |
4032 | 688 gint len = 0; |
689 | |
690 while (*x) { | |
691 gchar *pos; | |
692 | |
693 if (!t->values) | |
694 return; | |
695 | |
696 pos = strchr (t->values->str, *x); | |
697 if (pos) | |
698 t = t->children [(int) pos - (int) t->values->str]; | |
699 else | |
700 return; | |
701 | |
702 x++; len++; | |
703 } | |
704 | |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
705 if (t->image) { |
4032 | 706 t->image = NULL; |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
707 } |
4032 | 708 } |
4298 | 709 */ |
710 | |
4032 | 711 |
712 static gint | |
713 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
714 const gchar *text) | |
715 { | |
716 GtkSmileyTree *t = tree; | |
717 const gchar *x = text; | |
718 gint len = 0; | |
719 | |
720 while (*x) { | |
721 gchar *pos; | |
722 | |
723 if (!t->values) | |
724 break; | |
725 | |
726 pos = strchr (t->values->str, *x); | |
727 if (pos) | |
7371 | 728 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 729 else |
730 break; | |
731 | |
732 x++; len++; | |
733 } | |
734 | |
735 if (t->image) | |
736 return len; | |
737 | |
738 return 0; | |
739 } | |
740 | |
741 void | |
4263 | 742 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
743 gchar *sml, | |
744 GtkIMHtmlSmiley *smiley) | |
4032 | 745 { |
746 GtkSmileyTree *tree; | |
747 g_return_if_fail (imhtml != NULL); | |
748 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
7371 | 749 |
4032 | 750 if (sml == NULL) |
751 tree = imhtml->default_smilies; | |
752 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
753 } else { | |
754 tree = gtk_smiley_tree_new(); | |
4892 | 755 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 756 } |
757 | |
4263 | 758 gtk_smiley_tree_insert (tree, smiley); |
4032 | 759 } |
760 | |
761 static gboolean | |
762 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
763 GSList *fonts, | |
764 const gchar *text, | |
765 gint *len) | |
766 { | |
767 GtkSmileyTree *tree; | |
5967 | 768 GtkIMHtmlFontDetail *font; |
4032 | 769 char *sml = NULL; |
770 | |
771 if (fonts) { | |
772 font = fonts->data; | |
773 sml = font->sml; | |
774 } | |
775 | |
776 if (sml == NULL) | |
777 tree = imhtml->default_smilies; | |
778 else { | |
779 tree = g_hash_table_lookup(imhtml->smiley_data, sml); | |
780 } | |
781 if (tree == NULL) | |
782 return FALSE; | |
7371 | 783 |
4032 | 784 *len = gtk_smiley_tree_lookup (tree, text); |
785 return (*len > 0); | |
786 } | |
787 | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
788 GdkPixbufAnimation * |
4032 | 789 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
790 const gchar *sml, | |
791 const gchar *text) | |
792 { | |
793 GtkSmileyTree *t; | |
794 const gchar *x = text; | |
795 if (sml == NULL) | |
796 t = imhtml->default_smilies; | |
7371 | 797 else |
4032 | 798 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
7371 | 799 |
4032 | 800 |
801 if (t == NULL) | |
802 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
803 | |
804 while (*x) { | |
805 gchar *pos; | |
806 | |
807 if (!t->values) { | |
808 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
809 } | |
7371 | 810 |
4032 | 811 pos = strchr (t->values->str, *x); |
812 if (pos) { | |
7371 | 813 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 814 } else { |
815 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
816 } | |
817 x++; | |
818 } | |
819 | |
4263 | 820 if (!t->image->icon) |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
821 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
4263 | 822 |
823 return t->image->icon; | |
4032 | 824 } |
4793 | 825 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 826 *tag = g_strndup (string, strlen (x)); \ |
827 *len = strlen (x) + 1; \ | |
828 return TRUE; \ | |
829 } \ | |
830 (*type)++ | |
1428 | 831 |
4793 | 832 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 833 const gchar *c = string + strlen (x " "); \ |
834 gchar e = '"'; \ | |
835 gboolean quote = FALSE; \ | |
836 while (*c) { \ | |
837 if (*c == '"' || *c == '\'') { \ | |
838 if (quote && (*c == e)) \ | |
839 quote = !quote; \ | |
840 else if (!quote) { \ | |
841 quote = !quote; \ | |
842 e = *c; \ | |
843 } \ | |
844 } else if (!quote && (*c == '>')) \ | |
845 break; \ | |
846 c++; \ | |
847 } \ | |
848 if (*c) { \ | |
849 *tag = g_strndup (string, c - string); \ | |
850 *len = c - string + 1; \ | |
851 return TRUE; \ | |
852 } \ | |
853 } \ | |
854 (*type)++ | |
1428 | 855 |
856 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
857 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
858 gtk_imhtml_is_amp_escape (const gchar *string, |
7280 | 859 gchar **replace, |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
860 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
861 { |
7287 | 862 static char buf[7]; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
863 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
864 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
865 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
866 |
4793 | 867 if (!g_ascii_strncasecmp (string, "&", 5)) { |
7280 | 868 *replace = "&"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
869 *length = 5; |
4793 | 870 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
7280 | 871 *replace = "<"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
872 *length = 4; |
4793 | 873 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
7280 | 874 *replace = ">"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
875 *length = 4; |
4793 | 876 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
7280 | 877 *replace = " "; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
878 *length = 6; |
4793 | 879 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
7280 | 880 *replace = "©"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
881 *length = 6; |
4793 | 882 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
7280 | 883 *replace = "\""; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
884 *length = 6; |
4793 | 885 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
7280 | 886 *replace = "®"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
887 *length = 5; |
5093 | 888 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
7280 | 889 *replace = "\'"; |
5093 | 890 *length = 6; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
891 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
892 guint pound = 0; |
3004 | 893 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
7287 | 894 int buflen; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
895 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
896 return FALSE; |
7287 | 897 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
898 buf[buflen] = '\0'; | |
7280 | 899 *replace = buf; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
900 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
901 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
902 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
903 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
904 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
905 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
906 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
907 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
908 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
909 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
910 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
911 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
912 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
913 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
914 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
915 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
916 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
917 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
918 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
919 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
920 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
921 if (!strchr (string, '>')) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
922 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
923 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
924 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
925 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
926 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
927 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
928 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
929 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
930 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
931 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
932 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
933 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
934 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
935 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
936 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
937 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
938 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
939 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
940 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
941 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
942 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
943 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
944 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
945 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
946 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
947 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
948 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
949 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
950 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
951 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
952 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
953 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
954 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
955 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
956 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
957 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
958 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
959 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
960 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
961 VALID_TAG ("HEAD"); |
2993 | 962 VALID_TAG ("/HEAD"); |
963 VALID_TAG ("BINARY"); | |
964 VALID_TAG ("/BINARY"); | |
5093 | 965 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
966 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
967 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
968 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
969 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
970 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
971 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
972 VALID_OPT_TAG ("H3"); |
5093 | 973 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
974 |
5101 | 975 VALID_TAG ("CITE"); |
976 VALID_TAG ("/CITE"); | |
977 VALID_TAG ("EM"); | |
978 VALID_TAG ("/EM"); | |
979 VALID_TAG ("STRONG"); | |
980 VALID_TAG ("/STRONG"); | |
981 | |
5104 | 982 VALID_OPT_TAG ("SPAN"); |
983 VALID_TAG ("/SPAN"); | |
5174 | 984 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
6982 | 985 VALID_TAG ("IMG"); |
5104 | 986 |
4793 | 987 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
988 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
989 if (e) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
990 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
991 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
992 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
993 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
994 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
995 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
996 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
997 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
998 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
999 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1000 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1001 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1002 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1003 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1004 gchar *e, *a; |
5177 | 1005 gchar *val; |
1006 gint len; | |
7280 | 1007 gchar *c; |
5177 | 1008 GString *ret; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1009 |
4793 | 1010 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1011 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1012 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1013 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1014 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1015 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1016 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1017 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1018 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1019 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1020 |
4793 | 1021 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1022 t += strlen (opt); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1023 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1024 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1025 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1026 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1027 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1028 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1029 while (*e && (*e != *(t - 1))) e++; |
2993 | 1030 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1031 return NULL; |
5177 | 1032 } else |
1033 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1034 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1035 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1036 while (*e && !isspace ((gint) *e)) e++; |
5177 | 1037 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1038 } |
5177 | 1039 |
1040 ret = g_string_new(""); | |
1041 e = val; | |
1042 while(*e) { | |
1043 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
7280 | 1044 ret = g_string_append(ret, c); |
5177 | 1045 e += len; |
1046 } else { | |
1047 ret = g_string_append_c(ret, *e); | |
1048 e++; | |
1049 } | |
1050 } | |
1051 | |
1052 g_free(val); | |
1053 val = ret->str; | |
1054 g_string_free(ret, FALSE); | |
1055 return val; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1056 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1057 |
3922 | 1058 |
1059 | |
1060 #define NEW_TEXT_BIT 0 | |
4343 | 1061 #define NEW_COMMENT_BIT 2 |
4895 | 1062 #define NEW_SCALABLE_BIT 1 |
3922 | 1063 #define NEW_BIT(x) ws [wpos] = '\0'; \ |
1064 mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \ | |
1065 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \ | |
4895 | 1066 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ |
3922 | 1067 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \ |
1068 gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \ | |
1069 if (bold) \ | |
1070 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \ | |
4895 | 1071 if (italics) \ |
3922 | 1072 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \ |
1073 if (underline) \ | |
1074 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \ | |
1075 if (strike) \ | |
1076 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &siter, &iter); \ | |
1077 if (sub) \ | |
1078 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUB", &siter, &iter); \ | |
1079 if (sup) \ | |
1080 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUP", &siter, &iter); \ | |
1081 if (pre) \ | |
1082 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "PRE", &siter, &iter); \ | |
1083 if (bg) { \ | |
1084 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \ | |
1085 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
1086 } \ | |
1087 if (fonts) { \ | |
5967 | 1088 GtkIMHtmlFontDetail *fd = fonts->data; \ |
3922 | 1089 if (fd->fore) { \ |
1090 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \ | |
1091 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
1092 } \ | |
1093 if (fd->back) { \ | |
1094 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); \ | |
1095 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
1096 } \ | |
1097 if (fd->face) { \ | |
6648 | 1098 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", fd->face, NULL); \ |
3922 | 1099 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
1100 } \ | |
1101 if (fd->size) { \ | |
5118 | 1102 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "size-points", (double)POINT_SIZE(fd->size), NULL); \ |
3922 | 1103 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
1104 } \ | |
1105 } \ | |
1106 if (url) { \ | |
7732 | 1107 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "LINK", &siter, &iter); \ |
1108 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ | |
5012 | 1109 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), g_strdup(url)); \ |
7732 | 1110 g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \ |
4735 | 1111 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
3922 | 1112 } \ |
1113 wpos = 0; \ | |
1114 ws[0] = 0; \ | |
1115 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | |
4895 | 1116 if (x == NEW_SCALABLE_BIT) { \ |
1117 GdkRectangle rect; \ | |
1118 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); \ | |
1119 scalable->add_to(scalable, imhtml, &iter); \ | |
1120 scalable->scale(scalable, rect.width, rect.height); \ | |
1121 imhtml->scalables = g_list_append(imhtml->scalables, scalable); \ | |
1122 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | |
4343 | 1123 } \ |
3922 | 1124 |
4895 | 1125 |
1126 | |
6982 | 1127 GString* gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, |
1128 const gchar *text, | |
1129 GtkIMHtmlOptions options, | |
1130 GSList *images) | |
1428 | 1131 { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1132 gint pos = 0; |
3922 | 1133 GString *str = NULL; |
1134 GtkTextIter iter, siter; | |
1135 GtkTextMark *mark, *mark2; | |
7707 | 1136 GtkTextTag *texttag = NULL; |
3922 | 1137 gchar *ws; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1138 gchar *tag; |
3922 | 1139 gchar *url = NULL; |
1140 gchar *bg = NULL; | |
6982 | 1141 gint len; |
4032 | 1142 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1143 gint type; |
3922 | 1144 const gchar *c; |
7280 | 1145 gchar *amp; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1146 |
1428 | 1147 guint bold = 0, |
1148 italics = 0, | |
1149 underline = 0, | |
1150 strike = 0, | |
1151 sub = 0, | |
1152 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1153 title = 0, |
3922 | 1154 pre = 0; |
1428 | 1155 |
3922 | 1156 GSList *fonts = NULL; |
1428 | 1157 |
4612 | 1158 GdkRectangle rect; |
1159 int y, height; | |
1160 | |
4895 | 1161 GtkIMHtmlScalable *scalable = NULL; |
1162 | |
1428 | 1163 g_return_val_if_fail (imhtml != NULL, NULL); |
1164 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); | |
1165 g_return_val_if_fail (text != NULL, NULL); | |
6982 | 1166 |
3922 | 1167 c = text; |
6982 | 1168 len = strlen(text); |
3922 | 1169 ws = g_malloc(len + 1); |
1170 ws[0] = 0; | |
1428 | 1171 |
1172 if (options & GTK_IMHTML_RETURN_LOG) | |
3922 | 1173 str = g_string_new(""); |
1428 | 1174 |
3922 | 1175 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); |
1176 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE); | |
4612 | 1177 |
1178 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1179 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
1180 | |
1181 if(((y + height) - (rect.y + rect.height)) > height | |
1182 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
1183 options |= GTK_IMHTML_NO_SCROLL; | |
1184 } | |
1185 | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1186 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1187 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1188 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1189 pos++; |
3922 | 1190 switch (type) |
1191 { | |
1192 case 1: /* B */ | |
1193 case 2: /* BOLD */ | |
5101 | 1194 case 54: /* STRONG */ |
3922 | 1195 NEW_BIT (NEW_TEXT_BIT); |
1196 bold++; | |
1197 break; | |
1198 case 3: /* /B */ | |
1199 case 4: /* /BOLD */ | |
5101 | 1200 case 55: /* /STRONG */ |
3922 | 1201 NEW_BIT (NEW_TEXT_BIT); |
1202 if (bold) | |
1203 bold--; | |
1204 break; | |
1205 case 5: /* I */ | |
1206 case 6: /* ITALIC */ | |
5101 | 1207 case 52: /* EM */ |
3922 | 1208 NEW_BIT (NEW_TEXT_BIT); |
1209 italics++; | |
1210 break; | |
1211 case 7: /* /I */ | |
1212 case 8: /* /ITALIC */ | |
5101 | 1213 case 53: /* /EM */ |
3922 | 1214 NEW_BIT (NEW_TEXT_BIT); |
1215 if (italics) | |
1216 italics--; | |
1217 break; | |
1218 case 9: /* U */ | |
1219 case 10: /* UNDERLINE */ | |
1220 NEW_BIT (NEW_TEXT_BIT); | |
1221 underline++; | |
1222 break; | |
1223 case 11: /* /U */ | |
1224 case 12: /* /UNDERLINE */ | |
1225 NEW_BIT (NEW_TEXT_BIT); | |
1226 if (underline) | |
1227 underline--; | |
1228 break; | |
1229 case 13: /* S */ | |
1230 case 14: /* STRIKE */ | |
1231 NEW_BIT (NEW_TEXT_BIT); | |
1232 strike++; | |
1233 break; | |
1234 case 15: /* /S */ | |
1235 case 16: /* /STRIKE */ | |
1236 NEW_BIT (NEW_TEXT_BIT); | |
1237 if (strike) | |
1238 strike--; | |
1239 break; | |
1240 case 17: /* SUB */ | |
1241 NEW_BIT (NEW_TEXT_BIT); | |
1242 sub++; | |
1243 break; | |
1244 case 18: /* /SUB */ | |
1245 NEW_BIT (NEW_TEXT_BIT); | |
1246 if (sub) | |
1247 sub--; | |
1248 break; | |
1249 case 19: /* SUP */ | |
1250 NEW_BIT (NEW_TEXT_BIT); | |
1251 sup++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1252 break; |
3922 | 1253 case 20: /* /SUP */ |
1254 NEW_BIT (NEW_TEXT_BIT); | |
1255 if (sup) | |
1256 sup--; | |
1257 break; | |
1258 case 21: /* PRE */ | |
1259 NEW_BIT (NEW_TEXT_BIT); | |
1260 pre++; | |
1261 break; | |
1262 case 22: /* /PRE */ | |
1263 NEW_BIT (NEW_TEXT_BIT); | |
1264 if (pre) | |
1265 pre--; | |
1266 break; | |
1267 case 23: /* TITLE */ | |
1268 NEW_BIT (NEW_TEXT_BIT); | |
1269 title++; | |
1270 break; | |
1271 case 24: /* /TITLE */ | |
1272 if (title) { | |
1273 if (options & GTK_IMHTML_NO_TITLE) { | |
1274 wpos = 0; | |
1275 ws [wpos] = '\0'; | |
1276 } | |
1277 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1278 } |
3922 | 1279 break; |
1280 case 25: /* BR */ | |
5174 | 1281 case 58: /* BR/ */ |
3922 | 1282 ws[wpos] = '\n'; |
1283 wpos++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1284 NEW_BIT (NEW_TEXT_BIT); |
6982 | 1285 break; |
3922 | 1286 case 26: /* HR */ |
1287 case 42: /* HR (opt) */ | |
1288 ws[wpos++] = '\n'; | |
5967 | 1289 scalable = gtk_imhtml_hr_new(); |
4895 | 1290 NEW_BIT(NEW_SCALABLE_BIT); |
4343 | 1291 ws[wpos++] = '\n'; |
3922 | 1292 break; |
1293 case 27: /* /FONT */ | |
1294 if (fonts) { | |
5967 | 1295 GtkIMHtmlFontDetail *font = fonts->data; |
3922 | 1296 NEW_BIT (NEW_TEXT_BIT); |
1297 fonts = g_slist_remove (fonts, font); | |
1298 if (font->face) | |
1299 g_free (font->face); | |
1300 if (font->fore) | |
1301 g_free (font->fore); | |
1302 if (font->back) | |
1303 g_free (font->back); | |
4032 | 1304 if (font->sml) |
1305 g_free (font->sml); | |
3922 | 1306 g_free (font); |
1307 } | |
1308 break; | |
1309 case 28: /* /A */ | |
1310 if (url) { | |
1311 NEW_BIT(NEW_TEXT_BIT); | |
1312 g_free(url); | |
1313 url = NULL; | |
2993 | 1314 break; |
1315 } | |
3922 | 1316 case 29: /* P */ |
1317 case 30: /* /P */ | |
1318 case 31: /* H3 */ | |
1319 case 32: /* /H3 */ | |
1320 case 33: /* HTML */ | |
1321 case 34: /* /HTML */ | |
1322 case 35: /* BODY */ | |
1323 case 36: /* /BODY */ | |
1324 case 37: /* FONT */ | |
1325 case 38: /* HEAD */ | |
1326 case 39: /* /HEAD */ | |
6982 | 1327 case 40: /* BINARY */ |
1328 case 41: /* /BINARY */ | |
3922 | 1329 break; |
1330 case 43: /* FONT (opt) */ | |
1331 { | |
4032 | 1332 gchar *color, *back, *face, *size, *sml; |
5967 | 1333 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 1334 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
1335 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
1336 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
1337 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 1338 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
1339 if (!(color || back || face || size || sml)) | |
3922 | 1340 break; |
1341 | |
1342 NEW_BIT (NEW_TEXT_BIT); | |
1343 | |
5967 | 1344 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 1345 if (fonts) |
1346 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1347 |
3922 | 1348 if (color && !(options & GTK_IMHTML_NO_COLOURS)) |
1349 font->fore = color; | |
1350 else if (oldfont && oldfont->fore) | |
1351 font->fore = g_strdup(oldfont->fore); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1352 |
3922 | 1353 if (back && !(options & GTK_IMHTML_NO_COLOURS)) |
1354 font->back = back; | |
1355 else if (oldfont && oldfont->back) | |
1356 font->back = g_strdup(oldfont->back); | |
1357 | |
1358 if (face && !(options & GTK_IMHTML_NO_FONTS)) | |
1359 font->face = face; | |
1360 else if (oldfont && oldfont->face) | |
1361 font->face = g_strdup(oldfont->face); | |
4629 | 1362 if (font->face && (atoi(font->face) > 100)) { |
1363 g_free(font->face); | |
1364 font->face = g_strdup("100"); | |
1365 } | |
4032 | 1366 |
1367 if (sml) | |
1368 font->sml = sml; | |
1369 else if (oldfont && oldfont->sml) | |
1370 font->sml = g_strdup(oldfont->sml); | |
1371 | |
3922 | 1372 if (size && !(options & GTK_IMHTML_NO_SIZES)) { |
1373 if (*size == '+') { | |
1374 sscanf (size + 1, "%hd", &font->size); | |
1375 font->size += 3; | |
1376 } else if (*size == '-') { | |
1377 sscanf (size + 1, "%hd", &font->size); | |
1378 font->size = MAX (0, 3 - font->size); | |
1379 } else if (isdigit (*size)) { | |
1380 sscanf (size, "%hd", &font->size); | |
1381 } | |
6042 | 1382 if (font->size > 100) |
1383 font->size = 100; | |
3922 | 1384 } else if (oldfont) |
1385 font->size = oldfont->size; | |
1386 g_free(size); | |
1387 fonts = g_slist_prepend (fonts, font); | |
1388 } | |
1389 break; | |
1390 case 44: /* BODY (opt) */ | |
1391 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
1392 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
1393 if (bgcolor) { | |
1394 NEW_BIT(NEW_TEXT_BIT); | |
1395 if (bg) | |
1396 g_free(bg); | |
1397 bg = bgcolor; | |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
1398 } |
1428 | 1399 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1400 break; |
3922 | 1401 case 45: /* A (opt) */ |
1402 { | |
1403 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
1404 if (href) { | |
1405 NEW_BIT (NEW_TEXT_BIT); | |
1406 if (url) | |
1407 g_free (url); | |
1408 url = href; | |
1409 } | |
2993 | 1410 } |
3922 | 1411 break; |
4895 | 1412 case 46: /* IMG (opt) */ |
6982 | 1413 case 59: /* IMG */ |
4895 | 1414 { |
6982 | 1415 GdkPixbuf *img = NULL; |
1416 const gchar *filename = NULL; | |
4895 | 1417 |
6982 | 1418 if (images && images->data) { |
1419 img = images->data; | |
1420 images = images->next; | |
1421 filename = g_object_get_data(G_OBJECT(img), "filename"); | |
1422 g_object_ref(G_OBJECT(img)); | |
1423 } else { | |
1424 img = gtk_widget_render_icon(GTK_WIDGET(imhtml), | |
1425 GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON, | |
1426 "gtkimhtml-missing-image"); | |
1427 } | |
4895 | 1428 |
6982 | 1429 scalable = gtk_imhtml_image_new(img, filename); |
1430 NEW_BIT(NEW_SCALABLE_BIT); | |
1431 g_object_unref(G_OBJECT(img)); | |
4895 | 1432 } |
3922 | 1433 case 47: /* P (opt) */ |
1434 case 48: /* H3 (opt) */ | |
5093 | 1435 case 49: /* HTML (opt) */ |
5101 | 1436 case 50: /* CITE */ |
1437 case 51: /* /CITE */ | |
5104 | 1438 case 56: /* SPAN */ |
1439 case 57: /* /SPAN */ | |
2993 | 1440 break; |
6982 | 1441 case 60: /* comment */ |
3922 | 1442 NEW_BIT (NEW_TEXT_BIT); |
6124 | 1443 if (imhtml->show_comments) |
1444 wpos = g_snprintf (ws, len, "%s", tag); | |
3922 | 1445 NEW_BIT (NEW_COMMENT_BIT); |
1446 break; | |
1447 default: | |
6882 | 1448 break; |
2993 | 1449 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1450 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1451 pos += tlen; |
4138 | 1452 if(tag) |
1453 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1454 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
7280 | 1455 while(*amp) { |
1456 ws [wpos++] = *amp++; | |
1457 } | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1458 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1459 pos += tlen; |
1428 | 1460 } else if (*c == '\n') { |
1461 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 1462 ws[wpos] = '\n'; |
1463 wpos++; | |
1428 | 1464 NEW_BIT (NEW_TEXT_BIT); |
1465 } | |
1466 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1467 pos++; |
4253 | 1468 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1469 GtkTextChildAnchor *anchor; |
6882 | 1470 GtkWidget *icon = NULL; |
7344 | 1471 GtkTextIter copy; |
6882 | 1472 GdkPixbufAnimation *annipixbuf = NULL; |
1473 GdkPixbuf *pixbuf = NULL; | |
5967 | 1474 GtkIMHtmlFontDetail *fd; |
7346 | 1475 |
4032 | 1476 gchar *sml = NULL; |
1477 if (fonts) { | |
1478 fd = fonts->data; | |
1479 sml = fd->sml; | |
1480 } | |
1481 NEW_BIT (NEW_TEXT_BIT); | |
1482 wpos = g_snprintf (ws, smilelen + 1, "%s", c); | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1483 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); |
6882 | 1484 annipixbuf = gtk_smiley_tree_image(imhtml, sml, ws); |
1485 if(annipixbuf) { | |
1486 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
1487 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
1488 if(pixbuf) | |
1489 icon = gtk_image_new_from_pixbuf(pixbuf); | |
1490 } else { | |
1491 icon = gtk_image_new_from_animation(annipixbuf); | |
1492 } | |
1493 } | |
1494 | |
1495 if (icon) { | |
6839
bdc4e73f354d
[gaim-migrate @ 7384]
Christian Hammond <chipx86@chipx86.com>
parents:
6814
diff
changeset
|
1496 gtk_widget_show(icon); |
bdc4e73f354d
[gaim-migrate @ 7384]
Christian Hammond <chipx86@chipx86.com>
parents:
6814
diff
changeset
|
1497 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
1498 #if GTK_CHECK_VERSION(2,2,0) |
7346 | 1499 gtk_imhtml_copyable_new(imhtml, |
1500 gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE), | |
1501 ws); | |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
1502 #endif |
6839
bdc4e73f354d
[gaim-migrate @ 7384]
Christian Hammond <chipx86@chipx86.com>
parents:
6814
diff
changeset
|
1503 } |
7344 | 1504 |
1505 copy = iter; | |
1506 gtk_text_iter_backward_char(©); | |
1507 if (bg) { | |
1508 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); | |
1509 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &iter, ©); | |
1510 } | |
1511 if (fonts) { | |
1512 GtkIMHtmlFontDetail *fd = fonts->data; | |
1513 if (fd->back) { | |
1514 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); | |
1515 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &iter, ©); | |
1516 } | |
1517 } | |
4032 | 1518 c += smilelen; |
1519 pos += smilelen; | |
1520 wpos = 0; | |
1521 ws[0] = 0; | |
1522 } else if (*c) { | |
1428 | 1523 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1524 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1525 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1526 break; |
1428 | 1527 } |
1528 } | |
3922 | 1529 |
1530 NEW_BIT(NEW_TEXT_BIT); | |
1428 | 1531 if (url) { |
1532 g_free (url); | |
3922 | 1533 if (str) |
1534 str = g_string_append (str, "</A>"); | |
1428 | 1535 } |
3922 | 1536 |
4032 | 1537 while (fonts) { |
5967 | 1538 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 1539 fonts = g_slist_remove (fonts, font); |
1540 if (font->face) | |
1541 g_free (font->face); | |
1542 if (font->fore) | |
1543 g_free (font->fore); | |
1544 if (font->back) | |
1545 g_free (font->back); | |
1546 if (font->sml) | |
1547 g_free (font->sml); | |
1548 g_free (font); | |
1549 if (str) | |
1550 str = g_string_append (str, "</FONT>"); | |
1551 } | |
1552 | |
3922 | 1553 if (str) { |
1428 | 1554 while (bold) { |
3922 | 1555 str = g_string_append (str, "</B>"); |
1428 | 1556 bold--; |
1557 } | |
1558 while (italics) { | |
3922 | 1559 str = g_string_append (str, "</I>"); |
1428 | 1560 italics--; |
1561 } | |
1562 while (underline) { | |
3922 | 1563 str = g_string_append (str, "</U>"); |
1428 | 1564 underline--; |
1565 } | |
1566 while (strike) { | |
3922 | 1567 str = g_string_append (str, "</S>"); |
1428 | 1568 strike--; |
1569 } | |
1570 while (sub) { | |
3922 | 1571 str = g_string_append (str, "</SUB>"); |
1428 | 1572 sub--; |
1573 } | |
1574 while (sup) { | |
3922 | 1575 str = g_string_append (str, "</SUP>"); |
1428 | 1576 sup--; |
1577 } | |
1578 while (title) { | |
3922 | 1579 str = g_string_append (str, "</TITLE>"); |
1428 | 1580 title--; |
1581 } | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1582 while (pre) { |
3922 | 1583 str = g_string_append (str, "</PRE>"); |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1584 pre--; |
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1585 } |
1428 | 1586 } |
4032 | 1587 g_free (ws); |
4630 | 1588 if(bg) |
1589 g_free(bg); | |
4032 | 1590 if (!(options & GTK_IMHTML_NO_SCROLL)) |
1591 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, | |
1592 0, TRUE, 0.0, 1.0); | |
3922 | 1593 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); |
1594 return str; | |
1595 } | |
1596 | |
4892 | 1597 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
1598 { | |
4288 | 1599 g_hash_table_destroy(imhtml->smiley_data); |
1600 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 1601 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 1602 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 1603 imhtml->default_smilies = gtk_smiley_tree_new(); |
1604 } | |
3922 | 1605 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml, |
4253 | 1606 gboolean show) |
1607 { | |
1608 imhtml->show_smileys = show; | |
1609 } | |
3922 | 1610 |
1611 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, | |
4253 | 1612 gboolean show) |
1613 { | |
6124 | 1614 imhtml->show_comments = show; |
4253 | 1615 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1616 |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1617 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1618 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1619 { |
3922 | 1620 GtkTextIter start, end; |
7700 | 1621 GList *del = imhtml->format_spans; |
2993 | 1622 |
3922 | 1623 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
1624 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
1625 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
7694 | 1626 |
1627 while (imhtml->format_spans) { | |
1628 GtkIMHtmlFormatSpan *span = imhtml->format_spans->data; | |
1629 if (span->start_tag) | |
1630 g_free(span->start_tag); | |
1631 if (span->end_tag) | |
1632 g_free(span->end_tag); | |
1633 g_free(span); | |
1634 imhtml->format_spans = imhtml->format_spans->next; | |
1635 } | |
7700 | 1636 g_list_free(del); |
7694 | 1637 imhtml->edit.bold = NULL; |
1638 imhtml->edit.italic = NULL; | |
1639 imhtml->edit.underline = NULL; | |
7717 | 1640 imhtml->edit.fontface = NULL; |
7728 | 1641 imhtml->edit.forecolor = NULL; |
1642 imhtml->edit.backcolor = NULL; | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1643 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
1644 |
4046 | 1645 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
1646 { | |
5282 | 1647 GdkRectangle rect; |
1648 GtkTextIter iter; | |
4046 | 1649 |
5282 | 1650 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
1651 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
1652 rect.y - rect.height); | |
1653 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
1654 | |
4046 | 1655 } |
5282 | 1656 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
1657 { | |
1658 GdkRectangle rect; | |
1659 GtkTextIter iter; | |
1660 | |
1661 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1662 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
1663 rect.y + rect.height); | |
1664 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
1665 } | |
4735 | 1666 |
5967 | 1667 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
6982 | 1668 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename) |
4735 | 1669 { |
5967 | 1670 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 1671 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 1672 |
5967 | 1673 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
1674 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
1675 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 1676 |
1677 im_image->pixbuf = img; | |
5012 | 1678 im_image->image = image; |
4895 | 1679 im_image->width = gdk_pixbuf_get_width(img); |
1680 im_image->height = gdk_pixbuf_get_height(img); | |
1681 im_image->mark = NULL; | |
6982 | 1682 im_image->filename = filename ? g_strdup(filename) : NULL; |
4895 | 1683 |
5046 | 1684 g_object_ref(img); |
4895 | 1685 return GTK_IMHTML_SCALABLE(im_image); |
1686 } | |
1687 | |
5967 | 1688 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 1689 { |
5967 | 1690 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 1691 |
1692 if(image->width > width || image->height > height){ | |
1693 GdkPixbuf *new_image = NULL; | |
1694 float factor; | |
1695 int new_width = image->width, new_height = image->height; | |
1696 | |
1697 if(image->width > width){ | |
1698 factor = (float)(width)/image->width; | |
1699 new_width = width; | |
1700 new_height = image->height * factor; | |
1701 } | |
1702 if(new_height > height){ | |
1703 factor = (float)(height)/new_height; | |
1704 new_height = height; | |
1705 new_width = new_width * factor; | |
1706 } | |
1707 | |
5046 | 1708 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 1709 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 1710 g_object_unref(G_OBJECT(new_image)); |
1711 } | |
1712 } | |
1713 | |
5012 | 1714 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) |
1715 { | |
1716 const gchar *filename = gtk_file_selection_get_filename(sel); | |
5967 | 1717 gchar *dirname; |
1718 GtkIMHtmlImage *image = g_object_get_data(G_OBJECT(sel), "GtkIMHtmlImage"); | |
5012 | 1719 gchar *type = NULL; |
5019 | 1720 GError *error = NULL; |
5015 | 1721 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 1722 GSList *formats = gdk_pixbuf_get_formats(); |
6162 | 1723 #else |
1724 char *basename = g_path_get_basename(filename); | |
1725 char *ext = strrchr(basename, '.'); | |
5959 | 1726 #endif |
5012 | 1727 |
5967 | 1728 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { |
1729 /* append a / if needed */ | |
1730 if (filename[strlen(filename) - 1] != '/') { | |
1731 dirname = g_strconcat(filename, "/", NULL); | |
1732 } else { | |
1733 dirname = g_strdup(filename); | |
1734 } | |
1735 gtk_file_selection_set_filename(sel, dirname); | |
1736 g_free(dirname); | |
5959 | 1737 return; |
5967 | 1738 } |
5959 | 1739 |
1740 #if GTK_CHECK_VERSION(2,2,0) | |
5012 | 1741 while(formats){ |
1742 GdkPixbufFormat *format = formats->data; | |
1743 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
1744 gpointer p = extensions; | |
1745 | |
1746 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
1747 gchar *fmt_ext = extensions[0]; | |
1748 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
1749 | |
1750 if(!strcmp(fmt_ext, file_ext)){ | |
1751 type = gdk_pixbuf_format_get_name(format); | |
1752 break; | |
1753 } | |
1754 | |
1755 extensions++; | |
1756 } | |
1757 | |
1758 g_strfreev(p); | |
1759 | |
1760 if(type) | |
1761 break; | |
1762 | |
1763 formats = formats->next; | |
1764 } | |
1765 | |
5020 | 1766 g_slist_free(formats); |
1767 #else | |
1768 /* this is really ugly code, but I think it will work */ | |
1769 if(ext) { | |
1770 ext++; | |
1771 if(!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) | |
1772 type = g_strdup("jpeg"); | |
1773 else if(!g_ascii_strcasecmp(ext, "png")) | |
1774 type = g_strdup("png"); | |
1775 } | |
1776 | |
1777 g_free(basename); | |
1778 #endif | |
1779 | |
5012 | 1780 /* If I can't find a valid type, I will just tell the user about it and then assume |
1781 it's a png */ | |
1782 if(!type){ | |
1783 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
5967 | 1784 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
5012 | 1785 type = g_strdup("png"); |
1786 } | |
1787 | |
5046 | 1788 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 1789 |
1790 if(error){ | |
1791 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
1792 _("Error saving image: %s"), error->message); | |
1793 g_error_free(error); | |
1794 } | |
1795 | |
1796 g_free(type); | |
1797 } | |
1798 | |
5967 | 1799 static void gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) |
5012 | 1800 { |
5967 | 1801 GtkWidget *sel = gtk_file_selection_new(_("Save Image")); |
5012 | 1802 |
6982 | 1803 if (image->filename) |
1804 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); | |
5967 | 1805 g_object_set_data(G_OBJECT(sel), "GtkIMHtmlImage", image); |
5012 | 1806 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
1807 G_CALLBACK(write_img_to_file), sel); | |
1808 | |
1809 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | |
1810 G_CALLBACK(gtk_widget_destroy), sel); | |
1811 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", | |
1812 G_CALLBACK(gtk_widget_destroy), sel); | |
1813 | |
1814 gtk_widget_show(sel); | |
1815 } | |
1816 | |
5967 | 1817 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 1818 { |
1819 GdkEventButton *event_button = (GdkEventButton *) event; | |
1820 | |
1821 if (event->type == GDK_BUTTON_RELEASE) { | |
1822 if(event_button->button == 3) { | |
1823 GtkWidget *img, *item, *menu; | |
1824 gchar *text = g_strdup_printf(_("_Save Image...")); | |
1825 menu = gtk_menu_new(); | |
1826 | |
1827 /* buttons and such */ | |
1828 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
1829 item = gtk_image_menu_item_new_with_mnemonic(text); | |
1830 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 1831 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 1832 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
1833 | |
1834 gtk_widget_show_all(menu); | |
1835 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
1836 event_button->button, event_button->time); | |
1837 | |
1838 g_free(text); | |
1839 return TRUE; | |
1840 } | |
1841 } | |
1842 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
1843 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
1844 be caught by the regular GtkTextView menu */ | |
1845 else | |
1846 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1847 | |
1848 } | |
5967 | 1849 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
1850 { | |
1851 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
1852 | |
1853 g_object_unref(image->pixbuf); | |
6982 | 1854 if (image->filename) |
1855 g_free(image->filename); | |
5967 | 1856 g_free(scale); |
1857 } | |
1858 | |
1859 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1860 { | |
1861 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
1862 GtkWidget *box = gtk_event_box_new(); | |
1863 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1864 | |
1865 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
1866 | |
1867 gtk_widget_show(GTK_WIDGET(image->image)); | |
1868 gtk_widget_show(box); | |
1869 | |
1870 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); | |
1871 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
1872 } | |
1873 | |
1874 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
1875 { | |
1876 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
1877 | |
1878 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
1879 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
1880 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
1881 | |
1882 hr->sep = gtk_hseparator_new(); | |
1883 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
1884 gtk_widget_show(hr->sep); | |
1885 | |
1886 return GTK_IMHTML_SCALABLE(hr); | |
1887 } | |
1888 | |
1889 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
1890 { | |
1891 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width, 2); | |
1892 } | |
1893 | |
1894 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1895 { | |
1896 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
1897 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1898 | |
1899 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); | |
1900 } | |
1901 | |
1902 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
1903 { | |
1904 g_free(scale); | |
1905 } | |
7295 | 1906 |
1907 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
1908 { | |
1909 GtkTextIter iter, start, end; | |
1910 gboolean new_search = TRUE; | |
1911 | |
1912 g_return_val_if_fail(imhtml != NULL, FALSE); | |
1913 g_return_val_if_fail(text != NULL, FALSE); | |
1914 | |
1915 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) | |
1916 new_search = FALSE; | |
1917 | |
1918 | |
1919 if (new_search) { | |
1920 gtk_imhtml_search_clear(imhtml); | |
1921 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
1922 } else { | |
1923 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
1924 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); | |
1925 } | |
1926 imhtml->search_string = g_strdup(text); | |
1927 | |
7358 | 1928 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
1929 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 1930 &start, &end, NULL)) { |
1931 | |
1932 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
1933 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
1934 if (new_search) { | |
1935 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
1936 do | |
1937 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
7358 | 1938 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
1939 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
1940 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 1941 &start, &end, NULL)); |
1942 } | |
1943 return TRUE; | |
1944 } | |
1945 return FALSE; | |
1946 } | |
1947 | |
1948 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
1949 { | |
1950 GtkTextIter start, end; | |
1951 | |
1952 g_return_if_fail(imhtml != NULL); | |
1953 | |
1954 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
1955 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
1956 | |
1957 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
1958 if (imhtml->search_string) | |
1959 g_free(imhtml->search_string); | |
1960 imhtml->search_string = NULL; | |
1961 } | |
7694 | 1962 |
1963 /* Editable stuff */ | |
1964 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
1965 { | |
1966 GtkIMHtmlFormatSpan *span = NULL; | |
7734 | 1967 GtkTextIter end; |
1968 | |
7717 | 1969 gtk_text_iter_forward_chars(iter, len); |
7734 | 1970 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); |
1971 gtk_text_iter_forward_char(&end); | |
1972 | |
1973 if (!gtk_text_iter_equal(&end, iter)) | |
1974 return; | |
7694 | 1975 |
1976 if (!imhtml->editable) | |
1977 return; | |
1978 | |
1979 if ((span = imhtml->edit.bold)) { | |
1980 GtkTextIter bold; | |
1981 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &bold, span->start); | |
1982 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &bold, iter); | |
1983 } | |
7729 | 1984 |
7694 | 1985 if ((span = imhtml->edit.italic)) { |
1986 GtkTextIter italic; | |
1987 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &italic, span->start); | |
7729 | 1988 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &italic, |
1989 iter); | |
7694 | 1990 } |
7729 | 1991 |
1992 if ((span = imhtml->edit.underline)) { | |
1993 GtkTextIter underline; | |
1994 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &underline, span->start); | |
1995 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &underline, | |
1996 iter); | |
1997 } | |
1998 | |
7714 | 1999 if ((span = imhtml->edit.forecolor)) { |
2000 GtkTextIter fore; | |
2001 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &fore, span->start); | |
2002 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &fore, iter); | |
7694 | 2003 } |
7729 | 2004 |
7714 | 2005 if ((span = imhtml->edit.backcolor)) { |
2006 GtkTextIter back; | |
2007 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &back, span->start); | |
2008 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &back, iter); | |
2009 } | |
7729 | 2010 |
7717 | 2011 if ((span = imhtml->edit.fontface)) { |
2012 GtkTextIter face; | |
2013 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &face, span->start); | |
2014 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &face, iter); | |
2015 } | |
7694 | 2016 } |
2017 | |
2018 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
2019 { | |
2020 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
2021 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); | |
2022 imhtml->editable = editable; | |
2023 } | |
2024 | |
2025 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) | |
2026 { | |
2027 return imhtml->editable; | |
2028 } | |
2029 | |
2030 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) | |
2031 { | |
7707 | 2032 GtkIMHtmlFormatSpan *span; |
7694 | 2033 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2034 GtkTextIter iter; | |
2035 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2036 if (!imhtml->edit.bold) { | |
7707 | 2037 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); |
7694 | 2038 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2039 span->start_tag = g_strdup("<b>"); | |
2040 span->end = NULL; | |
2041 span->end_tag = g_strdup("</b>"); | |
2042 span->buffer = imhtml->text_buffer; | |
7714 | 2043 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "BOLD"); |
7694 | 2044 imhtml->edit.bold = span; |
2045 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2046 } else { | |
2047 span = imhtml->edit.bold; | |
2048 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2049 imhtml->edit.bold = NULL; | |
2050 } | |
2051 return imhtml->edit.bold != NULL; | |
2052 } | |
2053 | |
2054 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
2055 { | |
7707 | 2056 GtkIMHtmlFormatSpan *span; |
7694 | 2057 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2058 GtkTextIter iter; | |
2059 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2060 if (!imhtml->edit.italic) { | |
7707 | 2061 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); |
7694 | 2062 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2063 span->start_tag = g_strdup("<i>"); | |
2064 span->end = NULL; | |
2065 span->end_tag = g_strdup("</i>"); | |
2066 span->buffer = imhtml->text_buffer; | |
7714 | 2067 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "ITALIC"); |
7694 | 2068 imhtml->edit.italic = span; |
2069 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2070 } else { | |
2071 span = imhtml->edit.italic; | |
2072 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2073 imhtml->edit.italic = NULL; | |
2074 } | |
2075 return imhtml->edit.italic != NULL; | |
2076 } | |
7714 | 2077 |
7694 | 2078 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) |
2079 { | |
7707 | 2080 GtkIMHtmlFormatSpan *span; |
7694 | 2081 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2082 GtkTextIter iter; | |
2083 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2084 if (!imhtml->edit.underline) { | |
7707 | 2085 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); |
7694 | 2086 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2087 span->start_tag = g_strdup("<u>"); | |
2088 span->end = NULL; | |
2089 span->end_tag = g_strdup("</u>"); | |
2090 span->buffer = imhtml->text_buffer; | |
7714 | 2091 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "UNDERLINE"); |
7694 | 2092 imhtml->edit.underline = span; |
2093 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2094 } else { | |
7697 | 2095 span = imhtml->edit.underline; |
7694 | 2096 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2097 imhtml->edit.underline = NULL; | |
2098 } | |
2099 return imhtml->edit.underline != NULL; | |
2100 } | |
2101 | |
7714 | 2102 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) |
2103 { | |
2104 GtkIMHtmlFormatSpan *span; | |
2105 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2106 GtkTextIter iter; | |
2107 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2108 if (!imhtml->edit.forecolor) { | |
2109 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); | |
2110 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2111 span->start_tag = g_strdup_printf("<font color='%s'>", color); | |
2112 span->end = NULL; | |
2113 span->end_tag = g_strdup("</font>"); | |
2114 span->buffer = imhtml->text_buffer; | |
2115 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", color, NULL); | |
2116 imhtml->edit.forecolor = span; | |
2117 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2118 } else { | |
2119 span = imhtml->edit.forecolor; | |
2120 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2121 imhtml->edit.forecolor = NULL; | |
2122 } | |
2123 return imhtml->edit.forecolor != NULL; | |
2124 } | |
2125 | |
2126 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
2127 { | |
2128 GtkIMHtmlFormatSpan *span; | |
2129 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2130 GtkTextIter iter; | |
2131 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2132 if (!imhtml->edit.backcolor) { | |
2133 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); | |
2134 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2135 span->start_tag = g_strdup_printf("<body bgcolor='%s'>", color); | |
2136 span->end = NULL; | |
2137 span->end_tag = g_strdup("</font>"); | |
2138 span->buffer = imhtml->text_buffer; | |
2139 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", color, NULL); | |
2140 imhtml->edit.backcolor = span; | |
2141 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2142 } else { | |
2143 span = imhtml->edit.backcolor; | |
2144 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2145 imhtml->edit.backcolor = NULL; | |
2146 } | |
2147 return imhtml->edit.backcolor != NULL; | |
2148 } | |
2149 | |
7717 | 2150 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) |
2151 { | |
2152 GtkIMHtmlFormatSpan *span; | |
2153 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2154 GtkTextIter iter; | |
2155 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2156 if (!imhtml->edit.fontface) { | |
2157 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); | |
2158 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2159 span->start_tag = g_strdup_printf("<font face='%s'>", face); | |
2160 span->end = NULL; | |
2161 span->end_tag = g_strdup("</font>"); | |
2162 span->buffer = imhtml->text_buffer; | |
2163 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", face, NULL); | |
2164 imhtml->edit.fontface = span; | |
2165 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2166 } else { | |
2167 span = imhtml->edit.fontface; | |
2168 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2169 imhtml->edit.fontface = NULL; | |
2170 } | |
2171 return imhtml->edit.fontface != NULL; | |
2172 } | |
2173 | |
7707 | 2174 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, const char *url, const char *text) |
2175 { | |
2176 GtkIMHtmlFormatSpan *span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); | |
2177 GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2178 GtkTextIter iter; | |
2179 GtkTextTag *tag, *linktag; | |
2180 | |
2181 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); | |
2182 g_object_set_data(G_OBJECT(tag), "link_url", g_strdup(url)); | |
2183 | |
2184 linktag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "LINK"); | |
2185 | |
2186 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
2187 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2188 span->buffer = imhtml->text_buffer; | |
2189 span->start_tag = g_strdup_printf("<a href='%s'>", url); | |
2190 span->end_tag = g_strdup("</a>"); | |
2191 | |
2192 gtk_text_buffer_insert_with_tags(imhtml->text_buffer, &iter, text, strlen(text), linktag, tag, NULL); | |
2193 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2194 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2195 } | |
2196 | |
7735 | 2197 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *smiley) |
2198 { | |
2199 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2200 GtkTextIter iter; | |
2201 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2202 GdkPixbuf *pixbuf = NULL; | |
2203 GdkPixbufAnimation *annipixbuf = NULL; | |
2204 GtkWidget *icon = NULL; | |
2205 | |
2206 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); | |
2207 g_object_set_data(G_OBJECT(anchor), "text_tag", smiley); | |
2208 annipixbuf = gtk_smiley_tree_image(imhtml, NULL, smiley); | |
2209 if(annipixbuf) { | |
2210 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
2211 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
2212 if(pixbuf) | |
2213 icon = gtk_image_new_from_pixbuf(pixbuf); | |
2214 } else { | |
2215 icon = gtk_image_new_from_animation(annipixbuf); | |
2216 } | |
2217 } | |
2218 | |
2219 if (icon) { | |
2220 gtk_widget_show(icon); | |
2221 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
2222 #if GTK_CHECK_VERSION(2,2,0) | |
2223 gtk_imhtml_copyable_new(imhtml, | |
2224 gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE), | |
2225 smiley); | |
2226 #endif | |
2227 } | |
2228 } | |
2229 | |
7694 | 2230 int span_compare_begin(const GtkIMHtmlFormatSpan *a, const GtkIMHtmlFormatSpan *b, GtkTextBuffer *buffer) |
2231 { | |
2232 GtkTextIter ia, ib; | |
2233 gtk_text_buffer_get_iter_at_mark(buffer, &ia, a->start); | |
2234 gtk_text_buffer_get_iter_at_mark(buffer, &ib, b->start); | |
2235 return gtk_text_iter_compare(&ia, &ib); | |
2236 } | |
2237 | |
2238 int span_compare_end(GtkIMHtmlFormatSpan *a, GtkIMHtmlFormatSpan *b) | |
2239 { | |
2240 GtkTextIter ia, ib; | |
2241 gtk_text_buffer_get_iter_at_mark(a->buffer, &ia, a->start); | |
2242 gtk_text_buffer_get_iter_at_mark(b->buffer, &ib, b->start); | |
2243 return gtk_text_iter_compare(&ia, &ib); | |
2244 } | |
2245 | |
2246 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
2247 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
2248 * check the list of formatted strings, sorted by the position of the starting tags and apply them as | |
2249 * needed. After applying the start tags, add the end tags to the "closers" list, which is sorted by | |
2250 * location of ending tags. These get applied in a similar fashion. Finally, replace <, >, &, and " | |
2251 * with their HTML equivilent. */ | |
2252 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
2253 { | |
2254 gunichar c; | |
2255 GtkIMHtmlFormatSpan *sspan = NULL, *espan = NULL; | |
2256 GtkTextIter iter, siter, eiter; | |
2257 GList *starters = imhtml->format_spans; | |
2258 GList *closers = NULL;; | |
2259 GString *str = g_string_new(""); | |
2260 g_list_sort_with_data(starters, (GCompareDataFunc)span_compare_begin, imhtml->text_buffer); | |
2261 | |
2262 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
2263 | |
2264 /* Initialize these to the end iter */ | |
2265 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); | |
2266 eiter = siter; | |
2267 | |
2268 if (starters) { | |
2269 sspan = (GtkIMHtmlFormatSpan*)starters->data; | |
2270 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); | |
2271 } | |
2272 | |
2273 while ((c = gtk_text_iter_get_char(&iter)) != 0) { | |
2274 if (c == 0xFFFC) { | |
7735 | 2275 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); |
2276 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); | |
2277 str = g_string_append(str, text); | |
7694 | 2278 } else { |
2279 while (gtk_text_iter_equal(&eiter, &iter)) { | |
2280 /* This is where we shall insert the ending tag of | |
2281 * this format span */ | |
2282 str = g_string_append(str, espan->end_tag); | |
2283 closers = g_list_remove(closers, espan); | |
2284 if (closers) { | |
2285 espan = (GtkIMHtmlFormatSpan*)closers->data; | |
2286 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); | |
2287 } else { | |
2288 espan = NULL; | |
2289 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &eiter); | |
2290 } | |
2291 } | |
2292 while (gtk_text_iter_equal(&siter, &iter)) { | |
2293 /* This is where we shall insert the starting tag of | |
2294 * this format span */ | |
2295 str = g_string_append(str, sspan->start_tag); | |
2296 if (sspan->end) { | |
2297 espan = sspan; | |
2298 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); | |
2299 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end); | |
2300 } | |
2301 starters = starters->next; | |
2302 if (starters) { | |
2303 sspan = (GtkIMHtmlFormatSpan*)starters->data; | |
2304 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); | |
2305 } else { | |
2306 sspan = NULL; | |
2307 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); | |
2308 } | |
2309 | |
2310 } | |
7715 | 2311 |
2312 if (c == '<') | |
2313 str = g_string_append(str, "<"); | |
2314 else if (c == '>') | |
2315 str = g_string_append(str, ">"); | |
2316 else if (c == '&') | |
2317 str = g_string_append(str, "&"); | |
2318 else if (c == '"') | |
2319 str = g_string_append(str, """); | |
7716 | 2320 else |
2321 str = g_string_append_unichar(str, c); | |
7694 | 2322 } |
2323 gtk_text_iter_forward_char(&iter); | |
2324 } | |
2325 return g_string_free(str, FALSE); | |
2326 } | |
2327 | |
2328 char *gtk_imhtml_get_text(GtkIMHtml *imhtml) | |
2329 { | |
2330 GtkTextIter start_iter, end_iter; | |
2331 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start_iter); | |
2332 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end_iter); | |
2333 return gtk_text_buffer_get_text(imhtml->text_buffer, &start_iter, &end_iter, FALSE); | |
2334 | |
2335 } |