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