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