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