Mercurial > pidgin.yaz
annotate src/gtkimhtml.c @ 6128:3de23c9ca1e4
[gaim-migrate @ 6602]
Fixed HTTP redirect handling. If a redirect specified a path without a URL
(as is often the case), our redirect handling would crash and burn. Now it
only skids along the ground and manages to save itself and retrieve the
file. Think Indiana Jones, but with HTTP redirects and giant smileys.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Tue, 15 Jul 2003 03:03:02 +0000 |
parents | 16fd7811effd |
children | 7e967f2d6721 |
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" |
26 #include <gtk/gtk.h> | |
4895 | 27 #include <glib/gerror.h> |
4046 | 28 #include <gdk/gdkkeysyms.h> |
1428 | 29 #include <string.h> |
30 #include <ctype.h> | |
31 #include <stdio.h> | |
4629 | 32 #include <stdlib.h> |
1428 | 33 #include <math.h> |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
34 #ifdef HAVE_LANGINFO_CODESET |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
35 #include <langinfo.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
36 #include <locale.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
37 #endif |
1428 | 38 |
4417 | 39 #ifdef ENABLE_NLS |
40 # include <libintl.h> | |
41 # define _(x) gettext(x) | |
42 # ifdef gettext_noop | |
43 # define N_(String) gettext_noop (String) | |
44 # else | |
45 # define N_(String) (String) | |
46 # endif | |
47 #else | |
48 # define N_(String) (String) | |
49 # define _(x) (x) | |
50 #endif | |
51 | |
4735 | 52 #include <pango/pango-font.h> |
53 | |
5105 | 54 /* GTK+ < 2.2.2 hack, see ui.h for details. */ |
55 #ifndef GTK_WRAP_WORD_CHAR | |
56 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD | |
57 #endif | |
58 | |
4735 | 59 #define TOOLTIP_TIMEOUT 500 |
60 | |
3922 | 61 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
62 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | |
63 #define MAX_FONT_SIZE 7 | |
5367 | 64 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
3928 | 65 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
|
66 |
4032 | 67 static GtkSmileyTree* |
68 gtk_smiley_tree_new () | |
69 { | |
70 return g_new0 (GtkSmileyTree, 1); | |
71 } | |
72 | |
73 static void | |
74 gtk_smiley_tree_insert (GtkSmileyTree *tree, | |
4263 | 75 GtkIMHtmlSmiley *smiley) |
4032 | 76 { |
77 GtkSmileyTree *t = tree; | |
4263 | 78 const gchar *x = smiley->smile; |
4032 | 79 |
80 if (!strlen (x)) | |
81 return; | |
82 | |
83 while (*x) { | |
84 gchar *pos; | |
85 gint index; | |
86 | |
87 if (!t->values) | |
88 t->values = g_string_new (""); | |
89 | |
90 pos = strchr (t->values->str, *x); | |
91 if (!pos) { | |
92 t->values = g_string_append_c (t->values, *x); | |
93 index = t->values->len - 1; | |
94 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); | |
95 t->children [index] = g_new0 (GtkSmileyTree, 1); | |
96 } else | |
97 index = (int) pos - (int) t->values->str; | |
98 | |
99 t = t->children [index]; | |
100 | |
101 x++; | |
102 } | |
103 | |
4263 | 104 t->image = smiley; |
4032 | 105 } |
4041 | 106 |
4263 | 107 |
4264 | 108 void gtk_smiley_tree_destroy (GtkSmileyTree *tree) |
4032 | 109 { |
110 GSList *list = g_slist_append (NULL, tree); | |
111 | |
112 while (list) { | |
113 GtkSmileyTree *t = list->data; | |
114 gint i; | |
115 list = g_slist_remove(list, t); | |
116 if (t->values) { | |
117 for (i = 0; i < t->values->len; i++) | |
118 list = g_slist_append (list, t->children [i]); | |
119 g_string_free (t->values, TRUE); | |
120 g_free (t->children); | |
121 } | |
122 g_free (t); | |
123 } | |
124 } | |
125 | |
5967 | 126 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) |
127 { | |
128 GdkRectangle rect; | |
129 | |
130 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
131 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
132 GList *iter = GTK_IMHTML(widget)->scalables; | |
133 | |
134 while(iter){ | |
135 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
136 scale->scale(scale, rect.width, rect.height); | |
137 | |
138 iter = iter->next; | |
139 } | |
140 } | |
141 | |
142 widget->old_rect = rect; | |
143 return FALSE; | |
144 } | |
145 | |
146 static gint | |
147 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
148 { | |
149 PangoLayout *layout; | |
150 | |
151 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
152 | |
153 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
154 | |
155 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, | |
156 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, | |
157 "tooltip", 0, 0, -1, -1); | |
158 | |
159 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
160 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
161 | |
162 g_object_unref(layout); | |
163 return FALSE; | |
164 } | |
165 | |
166 static gint | |
167 gtk_imhtml_tip (gpointer data) | |
168 { | |
169 GtkIMHtml *imhtml = data; | |
170 PangoFontMetrics *font; | |
171 PangoLayout *layout; | |
172 | |
173 gint gap, x, y, h, w, scr_w, baseline_skip; | |
174 | |
175 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
176 | |
177 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
178 imhtml->tip_timer = 0; | |
179 return FALSE; | |
180 } | |
181 | |
182 if (imhtml->tip_window){ | |
183 gtk_widget_destroy (imhtml->tip_window); | |
184 imhtml->tip_window = NULL; | |
185 } | |
186 | |
187 imhtml->tip_timer = 0; | |
188 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
189 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
190 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
191 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
192 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
193 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
194 | |
195 gtk_widget_ensure_style (imhtml->tip_window); | |
196 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
197 font = pango_font_get_metrics(pango_context_load_font(pango_layout_get_context(layout), | |
198 imhtml->tip_window->style->font_desc), | |
199 NULL); | |
200 | |
201 | |
202 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
203 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + | |
204 pango_font_metrics_get_descent(font))/ 4); | |
205 | |
206 if (gap < 2) | |
207 gap = 2; | |
208 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
209 pango_font_metrics_get_descent(font)); | |
210 w = 8 + scr_w; | |
211 h = 8 + baseline_skip; | |
212 | |
213 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
214 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
215 y += GTK_WIDGET(imhtml)->allocation.y; | |
216 | |
217 scr_w = gdk_screen_width(); | |
218 | |
219 x -= ((w >> 1) + 4); | |
220 | |
221 if ((x + w) > scr_w) | |
222 x -= (x + w) - scr_w; | |
223 else if (x < 0) | |
224 x = 0; | |
225 | |
226 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + | |
227 pango_font_metrics_get_descent(font)); | |
228 | |
229 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
230 gtk_widget_show (imhtml->tip_window); | |
231 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
232 | |
233 pango_font_metrics_unref(font); | |
234 g_object_unref(layout); | |
235 | |
236 return FALSE; | |
237 } | |
238 | |
239 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
240 { | |
241 GtkTextIter iter; | |
242 GdkWindow *win = event->window; | |
243 int x, y; | |
244 char *tip = NULL; | |
245 GSList *tags = NULL, *templist = NULL; | |
246 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
247 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
248 event->x, event->y, &x, &y); | |
249 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
250 tags = gtk_text_iter_get_tags(&iter); | |
251 | |
252 templist = tags; | |
253 while (templist) { | |
254 GtkTextTag *tag = templist->data; | |
255 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
256 if (tip) | |
257 break; | |
258 templist = templist->next; | |
259 } | |
260 | |
261 if (GTK_IMHTML(imhtml)->tip) { | |
262 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
263 return FALSE; | |
264 } | |
265 /* We've left the cell. Remove the timeout and create a new one below */ | |
266 if (GTK_IMHTML(imhtml)->tip_window) { | |
267 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
268 GTK_IMHTML(imhtml)->tip_window = NULL; | |
269 } | |
270 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
271 if (GTK_IMHTML(imhtml)->tip_timer) | |
272 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
273 GTK_IMHTML(imhtml)->tip_timer = 0; | |
274 } | |
275 | |
276 if(tip){ | |
277 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
278 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, | |
279 gtk_imhtml_tip, imhtml); | |
280 } | |
281 | |
282 GTK_IMHTML(imhtml)->tip = tip; | |
283 g_slist_free(tags); | |
284 return FALSE; | |
285 } | |
286 | |
287 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
288 { | |
289 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
290 if (GTK_IMHTML(imhtml)->tip_window) { | |
291 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
292 GTK_IMHTML(imhtml)->tip_window = NULL; | |
293 } | |
294 if (GTK_IMHTML(imhtml)->tip_timer) { | |
295 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
296 GTK_IMHTML(imhtml)->tip_timer = 0; | |
297 } | |
298 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
299 | |
300 /* propogate the event normally */ | |
301 return FALSE; | |
302 } | |
303 | |
6066 | 304 /* |
305 * XXX - This should be removed eventually. | |
306 * | |
307 * This function exists to work around a gross bug in GtkTextView. | |
308 * Basically, we short circuit ctrl+a and ctrl+end because they make | |
309 * el program go boom. | |
310 * | |
311 * It's supposed to be fixed in gtk2.2. You can view the bug report at | |
312 * http://bugzilla.gnome.org/show_bug.cgi?id=107939 | |
313 */ | |
314 gboolean gtk_key_pressed_cb(GtkWidget *imhtml, GdkEventKey *event, gpointer data) | |
315 { | |
316 if (event->state & GDK_CONTROL_MASK) | |
317 switch (event->keyval) { | |
318 case 'a': | |
319 return TRUE; | |
320 break; | |
321 | |
322 case GDK_Home: | |
323 return TRUE; | |
324 break; | |
325 | |
326 case GDK_End: | |
327 return TRUE; | |
328 break; | |
329 } | |
330 | |
331 return FALSE; | |
332 } | |
333 | |
5967 | 334 |
4263 | 335 |
4032 | 336 static GtkTextViewClass *parent_class = NULL; |
337 | |
3922 | 338 /* GtkIMHtml has one signal--URL_CLICKED */ |
1428 | 339 enum { |
340 URL_CLICKED, | |
341 LAST_SIGNAL | |
342 }; | |
343 static guint signals [LAST_SIGNAL] = { 0 }; | |
344 | |
4032 | 345 static void |
346 gtk_imhtml_finalize (GObject *object) | |
347 { | |
348 GtkIMHtml *imhtml = GTK_IMHTML(object); | |
4895 | 349 GList *scalables; |
350 | |
4138 | 351 g_hash_table_destroy(imhtml->smiley_data); |
4032 | 352 gtk_smiley_tree_destroy(imhtml->default_smilies); |
4138 | 353 gdk_cursor_unref(imhtml->hand_cursor); |
354 gdk_cursor_unref(imhtml->arrow_cursor); | |
4735 | 355 if(imhtml->tip_window){ |
356 gtk_widget_destroy(imhtml->tip_window); | |
357 } | |
358 if(imhtml->tip_timer) | |
359 gtk_timeout_remove(imhtml->tip_timer); | |
360 | |
4895 | 361 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) { |
362 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); | |
363 scale->free(scale); | |
364 } | |
365 | |
366 g_list_free(imhtml->scalables); | |
4032 | 367 G_OBJECT_CLASS(parent_class)->finalize (object); |
368 } | |
1428 | 369 |
3922 | 370 /* Boring GTK stuff */ |
371 static void gtk_imhtml_class_init (GtkIMHtmlClass *class) | |
1428 | 372 { |
3922 | 373 GtkObjectClass *object_class; |
4032 | 374 GObjectClass *gobject_class; |
3922 | 375 object_class = (GtkObjectClass*) class; |
4032 | 376 gobject_class = (GObjectClass*) class; |
377 parent_class = gtk_type_class(GTK_TYPE_TEXT_VIEW); | |
4417 | 378 signals[URL_CLICKED] = g_signal_new("url_clicked", |
379 G_TYPE_FROM_CLASS(gobject_class), | |
380 G_SIGNAL_RUN_FIRST, | |
381 G_STRUCT_OFFSET(GtkIMHtmlClass, url_clicked), | |
382 NULL, | |
383 0, | |
384 g_cclosure_marshal_VOID__POINTER, | |
385 G_TYPE_NONE, 1, | |
386 G_TYPE_POINTER); | |
4032 | 387 gobject_class->finalize = gtk_imhtml_finalize; |
1428 | 388 } |
389 | |
3922 | 390 static void gtk_imhtml_init (GtkIMHtml *imhtml) |
1428 | 391 { |
3922 | 392 GtkTextIter iter; |
393 imhtml->text_buffer = gtk_text_buffer_new(NULL); | |
394 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); | |
395 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); | |
396 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); | |
5105 | 397 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); |
3922 | 398 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), FALSE); |
399 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); | |
400 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), FALSE); | |
401 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ | |
3465 | 402 |
3922 | 403 /* These tags will be used often and can be reused--we create them on init and then apply them by name |
404 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ | |
405 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); | |
406 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); | |
407 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); | |
408 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); | |
409 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); | |
410 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); | |
411 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); | |
3465 | 412 |
3922 | 413 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
414 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | |
415 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | |
2993 | 416 |
4253 | 417 imhtml->show_smileys = TRUE; |
6124 | 418 imhtml->show_comments = TRUE; |
4253 | 419 |
4892 | 420 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 421 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4032 | 422 imhtml->default_smilies = gtk_smiley_tree_new(); |
4735 | 423 |
4944 | 424 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); |
4735 | 425 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); |
4944 | 426 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); |
6066 | 427 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); |
4944 | 428 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); |
4735 | 429 |
430 imhtml->tip = NULL; | |
431 imhtml->tip_timer = 0; | |
432 imhtml->tip_window = NULL; | |
4895 | 433 |
434 imhtml->scalables = NULL; | |
2993 | 435 } |
436 | |
3922 | 437 GtkWidget *gtk_imhtml_new(void *a, void *b) |
1428 | 438 { |
4635 | 439 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); |
1428 | 440 } |
441 | |
4635 | 442 GType gtk_imhtml_get_type() |
1428 | 443 { |
4635 | 444 static GType imhtml_type = 0; |
1428 | 445 |
446 if (!imhtml_type) { | |
4635 | 447 static const GTypeInfo imhtml_info = { |
448 sizeof(GtkIMHtmlClass), | |
449 NULL, | |
450 NULL, | |
451 (GClassInitFunc) gtk_imhtml_class_init, | |
452 NULL, | |
453 NULL, | |
1428 | 454 sizeof (GtkIMHtml), |
4635 | 455 0, |
456 (GInstanceInitFunc) gtk_imhtml_init | |
1428 | 457 }; |
4635 | 458 |
459 imhtml_type = g_type_register_static(gtk_text_view_get_type(), | |
460 "GtkIMHtml", &imhtml_info, 0); | |
1428 | 461 } |
462 | |
463 return imhtml_type; | |
464 } | |
465 | |
4417 | 466 struct url_data { |
467 GObject *object; | |
468 gchar *url; | |
469 }; | |
470 | |
471 static void url_open(GtkWidget *w, struct url_data *data) { | |
472 if(!data) return; | |
473 | |
474 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); | |
475 | |
476 g_object_unref(data->object); | |
477 g_free(data->url); | |
478 g_free(data); | |
479 } | |
5582 | 480 |
4417 | 481 static void url_copy(GtkWidget *w, gchar *url) { |
482 GtkClipboard *clipboard; | |
483 | |
5293
ead927e2543f
[gaim-migrate @ 5665]
Christian Hammond <chipx86@chipx86.com>
parents:
5282
diff
changeset
|
484 clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
4417 | 485 gtk_clipboard_set_text(clipboard, url, -1); |
5582 | 486 |
487 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | |
488 gtk_clipboard_set_text(clipboard, url, -1); | |
4417 | 489 } |
490 | |
491 /* The callback for an event on a link tag. */ | |
5091 | 492 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) { |
4417 | 493 GdkEventButton *event_button = (GdkEventButton *) event; |
494 | |
3922 | 495 if (event->type == GDK_BUTTON_RELEASE) { |
4417 | 496 if (event_button->button == 1) { |
497 GtkTextIter start, end; | |
498 /* we shouldn't open a URL if the user has selected something: */ | |
499 gtk_text_buffer_get_selection_bounds( | |
500 gtk_text_iter_get_buffer(arg2), &start, &end); | |
501 if(gtk_text_iter_get_offset(&start) != | |
502 gtk_text_iter_get_offset(&end)) | |
503 return FALSE; | |
504 | |
505 /* A link was clicked--we emit the "url_clicked" signal | |
506 * with the URL as the argument */ | |
5091 | 507 g_signal_emit(imhtml, signals[URL_CLICKED], 0, url); |
4417 | 508 return FALSE; |
509 } else if(event_button->button == 3) { | |
4745 | 510 GtkWidget *img, *item, *menu; |
4417 | 511 struct url_data *tempdata = g_new(struct url_data, 1); |
5091 | 512 tempdata->object = g_object_ref(imhtml); |
4417 | 513 tempdata->url = g_strdup(url); |
4745 | 514 |
5091 | 515 /* Don't want the tooltip around if user right-clicked on link */ |
516 if (GTK_IMHTML(imhtml)->tip_window) { | |
517 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
518 GTK_IMHTML(imhtml)->tip_window = NULL; | |
519 } | |
520 if (GTK_IMHTML(imhtml)->tip_timer) { | |
521 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
522 GTK_IMHTML(imhtml)->tip_timer = 0; | |
523 } | |
524 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
4417 | 525 menu = gtk_menu_new(); |
4745 | 526 |
4417 | 527 /* buttons and such */ |
528 img = gtk_image_new_from_stock(GTK_STOCK_COPY, GTK_ICON_SIZE_MENU); | |
4420 | 529 item = gtk_image_menu_item_new_with_mnemonic(_("_Copy Link Location")); |
4417 | 530 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
531 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_copy), | |
532 url); | |
533 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
534 | |
535 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, GTK_ICON_SIZE_MENU); | |
4420 | 536 item = gtk_image_menu_item_new_with_mnemonic(_("_Open Link in Browser")); |
4417 | 537 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); |
538 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(url_open), | |
539 tempdata); | |
540 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); | |
4756 | 541 |
4417 | 542 gtk_widget_show_all(menu); |
4756 | 543 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
544 event_button->button, event_button->time); | |
4745 | 545 |
4417 | 546 return TRUE; |
547 } | |
1428 | 548 } |
4417 | 549 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) |
550 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
551 be caught by the regular GtkTextView menu */ | |
552 else | |
553 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1428 | 554 } |
555 | |
4298 | 556 /* this isn't used yet |
4032 | 557 static void |
4263 | 558 gtk_smiley_tree_remove (GtkSmileyTree *tree, |
559 GtkIMHtmlSmiley *smiley) | |
4032 | 560 { |
561 GtkSmileyTree *t = tree; | |
4263 | 562 const gchar *x = smiley->smile; |
4032 | 563 gint len = 0; |
564 | |
565 while (*x) { | |
566 gchar *pos; | |
567 | |
568 if (!t->values) | |
569 return; | |
570 | |
571 pos = strchr (t->values->str, *x); | |
572 if (pos) | |
573 t = t->children [(int) pos - (int) t->values->str]; | |
574 else | |
575 return; | |
576 | |
577 x++; len++; | |
578 } | |
579 | |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
580 if (t->image) { |
4032 | 581 t->image = NULL; |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
582 } |
4032 | 583 } |
4298 | 584 */ |
585 | |
4032 | 586 |
587 static gint | |
588 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
589 const gchar *text) | |
590 { | |
591 GtkSmileyTree *t = tree; | |
592 const gchar *x = text; | |
593 gint len = 0; | |
594 | |
595 while (*x) { | |
596 gchar *pos; | |
597 | |
598 if (!t->values) | |
599 break; | |
600 | |
601 pos = strchr (t->values->str, *x); | |
602 if (pos) | |
603 t = t->children [(int) pos - (int) t->values->str]; | |
604 else | |
605 break; | |
606 | |
607 x++; len++; | |
608 } | |
609 | |
610 if (t->image) | |
611 return len; | |
612 | |
613 return 0; | |
614 } | |
615 | |
616 void | |
4263 | 617 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
618 gchar *sml, | |
619 GtkIMHtmlSmiley *smiley) | |
4032 | 620 { |
621 GtkSmileyTree *tree; | |
622 g_return_if_fail (imhtml != NULL); | |
623 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
4263 | 624 |
4032 | 625 if (sml == NULL) |
626 tree = imhtml->default_smilies; | |
627 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
628 } else { | |
629 tree = gtk_smiley_tree_new(); | |
4892 | 630 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 631 } |
632 | |
4263 | 633 gtk_smiley_tree_insert (tree, smiley); |
4032 | 634 } |
635 | |
636 static gboolean | |
637 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
638 GSList *fonts, | |
639 const gchar *text, | |
640 gint *len) | |
641 { | |
642 GtkSmileyTree *tree; | |
5967 | 643 GtkIMHtmlFontDetail *font; |
4032 | 644 char *sml = NULL; |
645 | |
646 if (fonts) { | |
647 font = fonts->data; | |
648 sml = font->sml; | |
649 } | |
650 | |
651 if (sml == NULL) | |
652 tree = imhtml->default_smilies; | |
653 else { | |
654 tree = g_hash_table_lookup(imhtml->smiley_data, sml); | |
655 } | |
656 if (tree == NULL) | |
657 return FALSE; | |
658 | |
659 *len = gtk_smiley_tree_lookup (tree, text); | |
660 return (*len > 0); | |
661 } | |
662 | |
4263 | 663 GdkPixbuf* |
4032 | 664 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
665 const gchar *sml, | |
666 const gchar *text) | |
667 { | |
668 GtkSmileyTree *t; | |
669 const gchar *x = text; | |
670 if (sml == NULL) | |
671 t = imhtml->default_smilies; | |
672 else | |
673 t = g_hash_table_lookup(imhtml->smiley_data, sml); | |
674 | |
675 | |
676 if (t == NULL) | |
677 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
678 | |
679 while (*x) { | |
680 gchar *pos; | |
681 | |
682 if (!t->values) { | |
683 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
684 } | |
685 | |
686 pos = strchr (t->values->str, *x); | |
687 if (pos) { | |
688 t = t->children [(int) pos - (int) t->values->str]; | |
689 } else { | |
690 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
691 } | |
692 x++; | |
693 } | |
694 | |
4263 | 695 if (!t->image->icon) |
696 t->image->icon = gdk_pixbuf_new_from_file(t->image->file, NULL); | |
697 | |
698 return t->image->icon; | |
4032 | 699 } |
4793 | 700 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 701 *tag = g_strndup (string, strlen (x)); \ |
702 *len = strlen (x) + 1; \ | |
703 return TRUE; \ | |
704 } \ | |
705 (*type)++ | |
1428 | 706 |
4793 | 707 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 708 const gchar *c = string + strlen (x " "); \ |
709 gchar e = '"'; \ | |
710 gboolean quote = FALSE; \ | |
711 while (*c) { \ | |
712 if (*c == '"' || *c == '\'') { \ | |
713 if (quote && (*c == e)) \ | |
714 quote = !quote; \ | |
715 else if (!quote) { \ | |
716 quote = !quote; \ | |
717 e = *c; \ | |
718 } \ | |
719 } else if (!quote && (*c == '>')) \ | |
720 break; \ | |
721 c++; \ | |
722 } \ | |
723 if (*c) { \ | |
724 *tag = g_strndup (string, c - string); \ | |
725 *len = c - string + 1; \ | |
726 return TRUE; \ | |
727 } \ | |
728 } \ | |
729 (*type)++ | |
1428 | 730 |
731 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
732 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
733 gtk_imhtml_is_amp_escape (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
734 gchar *replace, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
735 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
736 { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
737 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
738 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
739 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
740 |
4793 | 741 if (!g_ascii_strncasecmp (string, "&", 5)) { |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
742 *replace = '&'; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
743 *length = 5; |
4793 | 744 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
745 *replace = '<'; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
746 *length = 4; |
4793 | 747 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
748 *replace = '>'; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
749 *length = 4; |
4793 | 750 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
751 *replace = ' '; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
752 *length = 6; |
4793 | 753 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
3717
988485669631
[gaim-migrate @ 3850]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
3705
diff
changeset
|
754 *replace = '©'; /* was: '©' */ |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
755 *length = 6; |
4793 | 756 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
757 *replace = '\"'; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
758 *length = 6; |
4793 | 759 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
3717
988485669631
[gaim-migrate @ 3850]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
3705
diff
changeset
|
760 *replace = '®'; /* was: '®' */ |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
761 *length = 5; |
5093 | 762 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
763 *replace = '\''; | |
764 *length = 6; | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
765 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
766 guint pound = 0; |
3004 | 767 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
768 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
769 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
770 *replace = (gchar)pound; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
771 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
772 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
773 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
774 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
775 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
776 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
777 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
778 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
779 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
780 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
781 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
782 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
783 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
784 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
785 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
786 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
787 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
788 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
789 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
790 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
791 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
792 if (!strchr (string, '>')) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
793 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
794 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
795 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
796 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
797 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
798 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
799 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
800 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
801 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
802 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
803 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
804 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
805 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
806 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
807 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
808 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
809 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
810 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
811 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
812 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
813 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
814 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
815 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
816 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
817 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
818 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
819 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
820 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
821 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
822 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
823 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
824 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
825 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
826 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
827 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
828 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
829 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
830 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
831 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
832 VALID_TAG ("HEAD"); |
2993 | 833 VALID_TAG ("/HEAD"); |
834 VALID_TAG ("BINARY"); | |
835 VALID_TAG ("/BINARY"); | |
5093 | 836 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
837 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
838 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
839 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
840 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
841 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
842 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
843 VALID_OPT_TAG ("H3"); |
5093 | 844 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
845 |
5101 | 846 VALID_TAG ("CITE"); |
847 VALID_TAG ("/CITE"); | |
848 VALID_TAG ("EM"); | |
849 VALID_TAG ("/EM"); | |
850 VALID_TAG ("STRONG"); | |
851 VALID_TAG ("/STRONG"); | |
852 | |
5104 | 853 VALID_OPT_TAG ("SPAN"); |
854 VALID_TAG ("/SPAN"); | |
5174 | 855 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
5104 | 856 |
4793 | 857 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
858 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
859 if (e) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
860 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
861 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
862 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
863 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
864 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
865 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
866 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
867 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
868 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
869 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
870 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
871 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
872 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
873 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
874 gchar *e, *a; |
5177 | 875 gchar *val; |
876 gint len; | |
877 gchar c; | |
878 GString *ret; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
879 |
4793 | 880 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
881 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
882 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
883 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
884 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
885 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
886 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
887 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
888 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
889 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
890 |
4793 | 891 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
892 t += strlen (opt); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
893 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
894 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
895 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
896 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
897 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
898 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
899 while (*e && (*e != *(t - 1))) e++; |
2993 | 900 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
901 return NULL; |
5177 | 902 } else |
903 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
904 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
905 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
906 while (*e && !isspace ((gint) *e)) e++; |
5177 | 907 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
908 } |
5177 | 909 |
910 ret = g_string_new(""); | |
911 e = val; | |
912 while(*e) { | |
913 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
914 ret = g_string_append_c(ret, c); | |
915 e += len; | |
916 } else { | |
917 ret = g_string_append_c(ret, *e); | |
918 e++; | |
919 } | |
920 } | |
921 | |
922 g_free(val); | |
923 val = ret->str; | |
924 g_string_free(ret, FALSE); | |
925 return val; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
926 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
927 |
3922 | 928 |
929 | |
930 #define NEW_TEXT_BIT 0 | |
4343 | 931 #define NEW_COMMENT_BIT 2 |
4895 | 932 #define NEW_SCALABLE_BIT 1 |
3922 | 933 #define NEW_BIT(x) ws [wpos] = '\0'; \ |
934 mark2 = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); \ | |
935 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, -1); \ | |
4895 | 936 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ |
3922 | 937 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, mark2); \ |
938 gtk_text_buffer_delete_mark(imhtml->text_buffer, mark2); \ | |
939 if (bold) \ | |
940 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &siter, &iter); \ | |
4895 | 941 if (italics) \ |
3922 | 942 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &siter, &iter); \ |
943 if (underline) \ | |
944 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &siter, &iter); \ | |
945 if (strike) \ | |
946 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &siter, &iter); \ | |
947 if (sub) \ | |
948 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUB", &siter, &iter); \ | |
949 if (sup) \ | |
950 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "SUP", &siter, &iter); \ | |
951 if (pre) \ | |
952 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "PRE", &siter, &iter); \ | |
953 if (bg) { \ | |
954 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", bg, NULL); \ | |
955 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
956 } \ | |
957 if (fonts) { \ | |
5967 | 958 GtkIMHtmlFontDetail *fd = fonts->data; \ |
3922 | 959 if (fd->fore) { \ |
960 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", fd->fore, NULL); \ | |
961 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
962 } \ | |
963 if (fd->back) { \ | |
964 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", fd->back, NULL); \ | |
965 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
966 } \ | |
967 if (fd->face) { \ | |
968 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "font", fd->face, NULL); \ | |
969 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
970 } \ | |
971 if (fd->size) { \ | |
5118 | 972 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "size-points", (double)POINT_SIZE(fd->size), NULL); \ |
3922 | 973 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
974 } \ | |
975 } \ | |
976 if (url) { \ | |
977 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); \ | |
5012 | 978 g_signal_connect(G_OBJECT(texttag), "event", G_CALLBACK(tag_event), g_strdup(url)); \ |
3922 | 979 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ |
4735 | 980 texttag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); \ |
981 g_object_set_data(G_OBJECT(texttag), "link_url", g_strdup(url)); \ | |
982 gtk_text_buffer_apply_tag(imhtml->text_buffer, texttag, &siter, &iter); \ | |
3922 | 983 } \ |
984 wpos = 0; \ | |
985 ws[0] = 0; \ | |
986 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | |
4895 | 987 if (x == NEW_SCALABLE_BIT) { \ |
988 GdkRectangle rect; \ | |
989 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); \ | |
990 scalable->add_to(scalable, imhtml, &iter); \ | |
991 scalable->scale(scalable, rect.width, rect.height); \ | |
992 imhtml->scalables = g_list_append(imhtml->scalables, scalable); \ | |
993 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); \ | |
4343 | 994 } \ |
3922 | 995 |
4895 | 996 |
997 | |
3922 | 998 GString* gtk_imhtml_append_text (GtkIMHtml *imhtml, |
999 const gchar *text, | |
1000 gint len, | |
1001 GtkIMHtmlOptions options) | |
1428 | 1002 { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1003 gint pos = 0; |
3922 | 1004 GString *str = NULL; |
1005 GtkTextIter iter, siter; | |
1006 GtkTextMark *mark, *mark2; | |
1007 GtkTextTag *texttag; | |
1008 gchar *ws; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1009 gchar *tag; |
3922 | 1010 gchar *url = NULL; |
1011 gchar *bg = NULL; | |
4032 | 1012 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1013 gint type; |
3922 | 1014 const gchar *c; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1015 gchar amp; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1016 |
1428 | 1017 guint bold = 0, |
1018 italics = 0, | |
1019 underline = 0, | |
1020 strike = 0, | |
1021 sub = 0, | |
1022 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1023 title = 0, |
3922 | 1024 pre = 0; |
1428 | 1025 |
3922 | 1026 GSList *fonts = NULL; |
1428 | 1027 |
4612 | 1028 GdkRectangle rect; |
1029 int y, height; | |
1030 | |
4895 | 1031 GtkIMHtmlScalable *scalable = NULL; |
1032 | |
1428 | 1033 g_return_val_if_fail (imhtml != NULL, NULL); |
1034 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); | |
1035 g_return_val_if_fail (text != NULL, NULL); | |
3922 | 1036 g_return_val_if_fail (len != 0, NULL); |
1037 | |
1038 c = text; | |
1039 if (len == -1) | |
1040 len = strlen(text); | |
1041 ws = g_malloc(len + 1); | |
1042 ws[0] = 0; | |
1428 | 1043 |
1044 if (options & GTK_IMHTML_RETURN_LOG) | |
3922 | 1045 str = g_string_new(""); |
1428 | 1046 |
3922 | 1047 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); |
1048 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE); | |
4612 | 1049 |
1050 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1051 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
1052 | |
1053 if(((y + height) - (rect.y + rect.height)) > height | |
1054 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
1055 options |= GTK_IMHTML_NO_SCROLL; | |
1056 } | |
1057 | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1058 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1059 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1060 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1061 pos++; |
3922 | 1062 switch (type) |
1063 { | |
1064 case 1: /* B */ | |
1065 case 2: /* BOLD */ | |
5101 | 1066 case 54: /* STRONG */ |
3922 | 1067 NEW_BIT (NEW_TEXT_BIT); |
1068 bold++; | |
1069 break; | |
1070 case 3: /* /B */ | |
1071 case 4: /* /BOLD */ | |
5101 | 1072 case 55: /* /STRONG */ |
3922 | 1073 NEW_BIT (NEW_TEXT_BIT); |
1074 if (bold) | |
1075 bold--; | |
1076 break; | |
1077 case 5: /* I */ | |
1078 case 6: /* ITALIC */ | |
5101 | 1079 case 52: /* EM */ |
3922 | 1080 NEW_BIT (NEW_TEXT_BIT); |
1081 italics++; | |
1082 break; | |
1083 case 7: /* /I */ | |
1084 case 8: /* /ITALIC */ | |
5101 | 1085 case 53: /* /EM */ |
3922 | 1086 NEW_BIT (NEW_TEXT_BIT); |
1087 if (italics) | |
1088 italics--; | |
1089 break; | |
1090 case 9: /* U */ | |
1091 case 10: /* UNDERLINE */ | |
1092 NEW_BIT (NEW_TEXT_BIT); | |
1093 underline++; | |
1094 break; | |
1095 case 11: /* /U */ | |
1096 case 12: /* /UNDERLINE */ | |
1097 NEW_BIT (NEW_TEXT_BIT); | |
1098 if (underline) | |
1099 underline--; | |
1100 break; | |
1101 case 13: /* S */ | |
1102 case 14: /* STRIKE */ | |
1103 NEW_BIT (NEW_TEXT_BIT); | |
1104 strike++; | |
1105 break; | |
1106 case 15: /* /S */ | |
1107 case 16: /* /STRIKE */ | |
1108 NEW_BIT (NEW_TEXT_BIT); | |
1109 if (strike) | |
1110 strike--; | |
1111 break; | |
1112 case 17: /* SUB */ | |
1113 NEW_BIT (NEW_TEXT_BIT); | |
1114 sub++; | |
1115 break; | |
1116 case 18: /* /SUB */ | |
1117 NEW_BIT (NEW_TEXT_BIT); | |
1118 if (sub) | |
1119 sub--; | |
1120 break; | |
1121 case 19: /* SUP */ | |
1122 NEW_BIT (NEW_TEXT_BIT); | |
1123 sup++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1124 break; |
3922 | 1125 case 20: /* /SUP */ |
1126 NEW_BIT (NEW_TEXT_BIT); | |
1127 if (sup) | |
1128 sup--; | |
1129 break; | |
1130 case 21: /* PRE */ | |
1131 NEW_BIT (NEW_TEXT_BIT); | |
1132 pre++; | |
1133 break; | |
1134 case 22: /* /PRE */ | |
1135 NEW_BIT (NEW_TEXT_BIT); | |
1136 if (pre) | |
1137 pre--; | |
1138 break; | |
1139 case 23: /* TITLE */ | |
1140 NEW_BIT (NEW_TEXT_BIT); | |
1141 title++; | |
1142 break; | |
1143 case 24: /* /TITLE */ | |
1144 if (title) { | |
1145 if (options & GTK_IMHTML_NO_TITLE) { | |
1146 wpos = 0; | |
1147 ws [wpos] = '\0'; | |
1148 } | |
1149 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1150 } |
3922 | 1151 break; |
1152 case 25: /* BR */ | |
5174 | 1153 case 58: /* BR/ */ |
3922 | 1154 ws[wpos] = '\n'; |
1155 wpos++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1156 NEW_BIT (NEW_TEXT_BIT); |
3922 | 1157 break; |
1158 case 26: /* HR */ | |
1159 case 42: /* HR (opt) */ | |
1160 ws[wpos++] = '\n'; | |
5967 | 1161 scalable = gtk_imhtml_hr_new(); |
4895 | 1162 NEW_BIT(NEW_SCALABLE_BIT); |
4343 | 1163 ws[wpos++] = '\n'; |
3922 | 1164 break; |
1165 case 27: /* /FONT */ | |
1166 if (fonts) { | |
5967 | 1167 GtkIMHtmlFontDetail *font = fonts->data; |
3922 | 1168 NEW_BIT (NEW_TEXT_BIT); |
1169 fonts = g_slist_remove (fonts, font); | |
1170 if (font->face) | |
1171 g_free (font->face); | |
1172 if (font->fore) | |
1173 g_free (font->fore); | |
1174 if (font->back) | |
1175 g_free (font->back); | |
4032 | 1176 if (font->sml) |
1177 g_free (font->sml); | |
3922 | 1178 g_free (font); |
1179 } | |
1180 break; | |
1181 case 28: /* /A */ | |
1182 if (url) { | |
1183 NEW_BIT(NEW_TEXT_BIT); | |
1184 g_free(url); | |
1185 url = NULL; | |
2993 | 1186 break; |
1187 } | |
3922 | 1188 case 29: /* P */ |
1189 case 30: /* /P */ | |
1190 case 31: /* H3 */ | |
1191 case 32: /* /H3 */ | |
1192 case 33: /* HTML */ | |
1193 case 34: /* /HTML */ | |
1194 case 35: /* BODY */ | |
1195 case 36: /* /BODY */ | |
1196 case 37: /* FONT */ | |
1197 case 38: /* HEAD */ | |
1198 case 39: /* /HEAD */ | |
1199 break; | |
1200 case 40: /* BINARY */ | |
4895 | 1201 NEW_BIT (NEW_TEXT_BIT); |
4997 | 1202 while (pos < len && g_ascii_strncasecmp("</BINARY>", c, strlen("</BINARY>"))) { |
1203 c++; | |
1204 pos++; | |
1205 } | |
1206 c = c - tlen; /* Because it will add this later */ | |
4895 | 1207 break; |
3922 | 1208 case 41: /* /BINARY */ |
1209 break; | |
1210 case 43: /* FONT (opt) */ | |
1211 { | |
4032 | 1212 gchar *color, *back, *face, *size, *sml; |
5967 | 1213 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 1214 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
1215 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
1216 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
1217 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 1218 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
1219 if (!(color || back || face || size || sml)) | |
3922 | 1220 break; |
1221 | |
1222 NEW_BIT (NEW_TEXT_BIT); | |
1223 | |
5967 | 1224 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 1225 if (fonts) |
1226 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1227 |
3922 | 1228 if (color && !(options & GTK_IMHTML_NO_COLOURS)) |
1229 font->fore = color; | |
1230 else if (oldfont && oldfont->fore) | |
1231 font->fore = g_strdup(oldfont->fore); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1232 |
3922 | 1233 if (back && !(options & GTK_IMHTML_NO_COLOURS)) |
1234 font->back = back; | |
1235 else if (oldfont && oldfont->back) | |
1236 font->back = g_strdup(oldfont->back); | |
1237 | |
1238 if (face && !(options & GTK_IMHTML_NO_FONTS)) | |
1239 font->face = face; | |
1240 else if (oldfont && oldfont->face) | |
1241 font->face = g_strdup(oldfont->face); | |
4629 | 1242 if (font->face && (atoi(font->face) > 100)) { |
1243 g_free(font->face); | |
1244 font->face = g_strdup("100"); | |
1245 } | |
4032 | 1246 |
1247 if (sml) | |
1248 font->sml = sml; | |
1249 else if (oldfont && oldfont->sml) | |
1250 font->sml = g_strdup(oldfont->sml); | |
1251 | |
3922 | 1252 if (size && !(options & GTK_IMHTML_NO_SIZES)) { |
1253 if (*size == '+') { | |
1254 sscanf (size + 1, "%hd", &font->size); | |
1255 font->size += 3; | |
1256 } else if (*size == '-') { | |
1257 sscanf (size + 1, "%hd", &font->size); | |
1258 font->size = MAX (0, 3 - font->size); | |
1259 } else if (isdigit (*size)) { | |
1260 sscanf (size, "%hd", &font->size); | |
1261 } | |
6042 | 1262 if (font->size > 100) |
1263 font->size = 100; | |
3922 | 1264 } else if (oldfont) |
1265 font->size = oldfont->size; | |
1266 g_free(size); | |
1267 fonts = g_slist_prepend (fonts, font); | |
1268 } | |
1269 break; | |
1270 case 44: /* BODY (opt) */ | |
1271 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
1272 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
1273 if (bgcolor) { | |
1274 NEW_BIT(NEW_TEXT_BIT); | |
1275 if (bg) | |
1276 g_free(bg); | |
1277 bg = bgcolor; | |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
1278 } |
1428 | 1279 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1280 break; |
3922 | 1281 case 45: /* A (opt) */ |
1282 { | |
1283 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
1284 if (href) { | |
1285 NEW_BIT (NEW_TEXT_BIT); | |
1286 if (url) | |
1287 g_free (url); | |
1288 url = href; | |
1289 } | |
2993 | 1290 } |
3922 | 1291 break; |
4895 | 1292 case 46: /* IMG (opt) */ |
1293 { | |
1294 gchar *src = gtk_imhtml_get_html_opt (tag, "SRC="); | |
1295 gchar *id = gtk_imhtml_get_html_opt (tag, "ID="); | |
1296 gchar *datasize = gtk_imhtml_get_html_opt (tag, "DATASIZE="); | |
1297 gint im_len = datasize?atoi(datasize):0; | |
1298 | |
1299 if (src && id && im_len && im_len <= len - pos) { | |
1300 /* This is an embedded IM image, or is it? */ | |
1301 char *tmp = NULL; | |
1302 const char *alltext; | |
1303 guchar *imagedata = NULL; | |
1304 | |
1305 GdkPixbufLoader *load; | |
1306 GdkPixbuf *imagepb = NULL; | |
1307 GError *error = NULL; | |
1308 | |
1309 tmp = g_strdup_printf("<DATA ID=\"%s\" SIZE=\"%s\">", id, datasize); | |
1310 alltext = strstr(c, tmp); | |
1311 imagedata = g_memdup(alltext + strlen(tmp), im_len); | |
1312 | |
1313 g_free(tmp); | |
1314 | |
1315 load = gdk_pixbuf_loader_new(); | |
1316 if (!gdk_pixbuf_loader_write(load, imagedata, im_len, &error)){ | |
1317 fprintf(stderr, "IM Image corrupted or unreadable.: %s\n", error->message); | |
1318 } else { | |
1319 imagepb = gdk_pixbuf_loader_get_pixbuf(load); | |
1320 if (imagepb) { | |
5967 | 1321 scalable = gtk_imhtml_image_new(imagepb, g_strdup(src)); |
4895 | 1322 NEW_BIT(NEW_SCALABLE_BIT); |
5012 | 1323 g_object_unref(imagepb); |
4895 | 1324 } |
1325 } | |
1326 | |
1327 gdk_pixbuf_loader_close(load, NULL); | |
1328 | |
1329 | |
1330 g_free(imagedata); | |
1331 g_free(id); | |
1332 g_free(datasize); | |
1333 g_free(src); | |
1334 | |
1335 break; | |
1336 } | |
1337 g_free(id); | |
1338 g_free(datasize); | |
1339 g_free(src); | |
1340 } | |
3922 | 1341 case 47: /* P (opt) */ |
1342 case 48: /* H3 (opt) */ | |
5093 | 1343 case 49: /* HTML (opt) */ |
5101 | 1344 case 50: /* CITE */ |
1345 case 51: /* /CITE */ | |
5104 | 1346 case 56: /* SPAN */ |
1347 case 57: /* /SPAN */ | |
2993 | 1348 break; |
5174 | 1349 case 59: /* comment */ |
3922 | 1350 NEW_BIT (NEW_TEXT_BIT); |
6124 | 1351 if (imhtml->show_comments) |
1352 wpos = g_snprintf (ws, len, "%s", tag); | |
3922 | 1353 NEW_BIT (NEW_COMMENT_BIT); |
1354 break; | |
1355 default: | |
1356 break; | |
2993 | 1357 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1358 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1359 pos += tlen; |
4138 | 1360 if(tag) |
1361 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1362 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1363 ws [wpos++] = amp; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1364 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1365 pos += tlen; |
1428 | 1366 } else if (*c == '\n') { |
1367 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 1368 ws[wpos] = '\n'; |
1369 wpos++; | |
1428 | 1370 NEW_BIT (NEW_TEXT_BIT); |
1371 } | |
1372 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1373 pos++; |
4253 | 1374 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { |
5967 | 1375 GtkIMHtmlFontDetail *fd; |
4032 | 1376 gchar *sml = NULL; |
1377 if (fonts) { | |
1378 fd = fonts->data; | |
1379 sml = fd->sml; | |
1380 } | |
1381 NEW_BIT (NEW_TEXT_BIT); | |
1382 wpos = g_snprintf (ws, smilelen + 1, "%s", c); | |
4263 | 1383 gtk_text_buffer_insert_pixbuf(imhtml->text_buffer, &iter, gtk_smiley_tree_image (imhtml, sml, ws)); |
4032 | 1384 c += smilelen; |
1385 pos += smilelen; | |
1386 wpos = 0; | |
1387 ws[0] = 0; | |
1388 } else if (*c) { | |
1428 | 1389 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1390 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1391 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1392 break; |
1428 | 1393 } |
1394 } | |
3922 | 1395 |
1396 NEW_BIT(NEW_TEXT_BIT); | |
1428 | 1397 if (url) { |
1398 g_free (url); | |
3922 | 1399 if (str) |
1400 str = g_string_append (str, "</A>"); | |
1428 | 1401 } |
3922 | 1402 |
4032 | 1403 while (fonts) { |
5967 | 1404 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 1405 fonts = g_slist_remove (fonts, font); |
1406 if (font->face) | |
1407 g_free (font->face); | |
1408 if (font->fore) | |
1409 g_free (font->fore); | |
1410 if (font->back) | |
1411 g_free (font->back); | |
1412 if (font->sml) | |
1413 g_free (font->sml); | |
1414 g_free (font); | |
1415 if (str) | |
1416 str = g_string_append (str, "</FONT>"); | |
1417 } | |
1418 | |
3922 | 1419 if (str) { |
1428 | 1420 while (bold) { |
3922 | 1421 str = g_string_append (str, "</B>"); |
1428 | 1422 bold--; |
1423 } | |
1424 while (italics) { | |
3922 | 1425 str = g_string_append (str, "</I>"); |
1428 | 1426 italics--; |
1427 } | |
1428 while (underline) { | |
3922 | 1429 str = g_string_append (str, "</U>"); |
1428 | 1430 underline--; |
1431 } | |
1432 while (strike) { | |
3922 | 1433 str = g_string_append (str, "</S>"); |
1428 | 1434 strike--; |
1435 } | |
1436 while (sub) { | |
3922 | 1437 str = g_string_append (str, "</SUB>"); |
1428 | 1438 sub--; |
1439 } | |
1440 while (sup) { | |
3922 | 1441 str = g_string_append (str, "</SUP>"); |
1428 | 1442 sup--; |
1443 } | |
1444 while (title) { | |
3922 | 1445 str = g_string_append (str, "</TITLE>"); |
1428 | 1446 title--; |
1447 } | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1448 while (pre) { |
3922 | 1449 str = g_string_append (str, "</PRE>"); |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1450 pre--; |
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1451 } |
1428 | 1452 } |
4032 | 1453 g_free (ws); |
4630 | 1454 if(bg) |
1455 g_free(bg); | |
4032 | 1456 if (!(options & GTK_IMHTML_NO_SCROLL)) |
1457 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, | |
1458 0, TRUE, 0.0, 1.0); | |
3922 | 1459 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); |
1460 return str; | |
1461 } | |
1462 | |
4892 | 1463 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
1464 { | |
4288 | 1465 g_hash_table_destroy(imhtml->smiley_data); |
1466 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 1467 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 1468 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 1469 imhtml->default_smilies = gtk_smiley_tree_new(); |
1470 } | |
3922 | 1471 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml, |
4253 | 1472 gboolean show) |
1473 { | |
1474 imhtml->show_smileys = show; | |
1475 } | |
3922 | 1476 |
1477 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, | |
4253 | 1478 gboolean show) |
1479 { | |
6124 | 1480 imhtml->show_comments = show; |
4253 | 1481 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1482 |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1483 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1484 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1485 { |
3922 | 1486 GtkTextIter start, end; |
2993 | 1487 |
3922 | 1488 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
1489 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
1490 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
1491 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
1492 |
4046 | 1493 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
1494 { | |
5282 | 1495 GdkRectangle rect; |
1496 GtkTextIter iter; | |
4046 | 1497 |
5282 | 1498 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
1499 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
1500 rect.y - rect.height); | |
1501 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
1502 | |
4046 | 1503 } |
5282 | 1504 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
1505 { | |
1506 GdkRectangle rect; | |
1507 GtkTextIter iter; | |
1508 | |
1509 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1510 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
1511 rect.y + rect.height); | |
1512 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
1513 } | |
4735 | 1514 |
5967 | 1515 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
1516 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, gchar *filename) | |
4735 | 1517 { |
5967 | 1518 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 1519 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 1520 |
5967 | 1521 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
1522 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
1523 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 1524 |
1525 im_image->pixbuf = img; | |
5012 | 1526 im_image->image = image; |
4895 | 1527 im_image->width = gdk_pixbuf_get_width(img); |
1528 im_image->height = gdk_pixbuf_get_height(img); | |
1529 im_image->mark = NULL; | |
5012 | 1530 im_image->filename = filename; |
4895 | 1531 |
5046 | 1532 g_object_ref(img); |
4895 | 1533 return GTK_IMHTML_SCALABLE(im_image); |
1534 } | |
1535 | |
5967 | 1536 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 1537 { |
5967 | 1538 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 1539 |
1540 if(image->width > width || image->height > height){ | |
1541 GdkPixbuf *new_image = NULL; | |
1542 float factor; | |
1543 int new_width = image->width, new_height = image->height; | |
1544 | |
1545 if(image->width > width){ | |
1546 factor = (float)(width)/image->width; | |
1547 new_width = width; | |
1548 new_height = image->height * factor; | |
1549 } | |
1550 if(new_height > height){ | |
1551 factor = (float)(height)/new_height; | |
1552 new_height = height; | |
1553 new_width = new_width * factor; | |
1554 } | |
1555 | |
5046 | 1556 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 1557 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 1558 g_object_unref(G_OBJECT(new_image)); |
1559 } | |
1560 } | |
1561 | |
5012 | 1562 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) |
1563 { | |
1564 const gchar *filename = gtk_file_selection_get_filename(sel); | |
5967 | 1565 gchar *dirname; |
1566 GtkIMHtmlImage *image = g_object_get_data(G_OBJECT(sel), "GtkIMHtmlImage"); | |
5012 | 1567 gchar *type = NULL; |
5019 | 1568 GError *error = NULL; |
5015 | 1569 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 1570 GSList *formats = gdk_pixbuf_get_formats(); |
5959 | 1571 #endif |
5012 | 1572 |
5967 | 1573 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { |
1574 /* append a / if needed */ | |
1575 if (filename[strlen(filename) - 1] != '/') { | |
1576 dirname = g_strconcat(filename, "/", NULL); | |
1577 } else { | |
1578 dirname = g_strdup(filename); | |
1579 } | |
1580 gtk_file_selection_set_filename(sel, dirname); | |
1581 g_free(dirname); | |
5959 | 1582 return; |
5967 | 1583 } |
5959 | 1584 |
1585 #if GTK_CHECK_VERSION(2,2,0) | |
5012 | 1586 while(formats){ |
1587 GdkPixbufFormat *format = formats->data; | |
1588 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
1589 gpointer p = extensions; | |
1590 | |
1591 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
1592 gchar *fmt_ext = extensions[0]; | |
1593 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
1594 | |
1595 if(!strcmp(fmt_ext, file_ext)){ | |
1596 type = gdk_pixbuf_format_get_name(format); | |
1597 break; | |
1598 } | |
1599 | |
1600 extensions++; | |
1601 } | |
1602 | |
1603 g_strfreev(p); | |
1604 | |
1605 if(type) | |
1606 break; | |
1607 | |
1608 formats = formats->next; | |
1609 } | |
1610 | |
5020 | 1611 g_slist_free(formats); |
1612 #else | |
1613 /* this is really ugly code, but I think it will work */ | |
1614 char *basename = g_path_get_basename(filename); | |
1615 char *ext = strrchr(basename, '.'); | |
1616 | |
1617 if(ext) { | |
1618 ext++; | |
1619 if(!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) | |
1620 type = g_strdup("jpeg"); | |
1621 else if(!g_ascii_strcasecmp(ext, "png")) | |
1622 type = g_strdup("png"); | |
1623 } | |
1624 | |
1625 g_free(basename); | |
1626 #endif | |
1627 | |
5012 | 1628 /* If I can't find a valid type, I will just tell the user about it and then assume |
1629 it's a png */ | |
1630 if(!type){ | |
1631 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
5967 | 1632 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
5012 | 1633 type = g_strdup("png"); |
1634 } | |
1635 | |
5046 | 1636 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 1637 |
1638 if(error){ | |
1639 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
1640 _("Error saving image: %s"), error->message); | |
1641 g_error_free(error); | |
1642 } | |
1643 | |
1644 g_free(type); | |
1645 } | |
1646 | |
5967 | 1647 static void gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) |
5012 | 1648 { |
5967 | 1649 GtkWidget *sel = gtk_file_selection_new(_("Save Image")); |
5012 | 1650 |
1651 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); | |
5967 | 1652 g_object_set_data(G_OBJECT(sel), "GtkIMHtmlImage", image); |
5012 | 1653 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
1654 G_CALLBACK(write_img_to_file), sel); | |
1655 | |
1656 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | |
1657 G_CALLBACK(gtk_widget_destroy), sel); | |
1658 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", | |
1659 G_CALLBACK(gtk_widget_destroy), sel); | |
1660 | |
1661 gtk_widget_show(sel); | |
1662 } | |
1663 | |
5967 | 1664 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 1665 { |
1666 GdkEventButton *event_button = (GdkEventButton *) event; | |
1667 | |
1668 if (event->type == GDK_BUTTON_RELEASE) { | |
1669 if(event_button->button == 3) { | |
1670 GtkWidget *img, *item, *menu; | |
1671 gchar *text = g_strdup_printf(_("_Save Image...")); | |
1672 menu = gtk_menu_new(); | |
1673 | |
1674 /* buttons and such */ | |
1675 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
1676 item = gtk_image_menu_item_new_with_mnemonic(text); | |
1677 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 1678 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 1679 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
1680 | |
1681 gtk_widget_show_all(menu); | |
1682 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
1683 event_button->button, event_button->time); | |
1684 | |
1685 g_free(text); | |
1686 return TRUE; | |
1687 } | |
1688 } | |
1689 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
1690 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
1691 be caught by the regular GtkTextView menu */ | |
1692 else | |
1693 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1694 | |
1695 } | |
5967 | 1696 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
1697 { | |
1698 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
1699 | |
1700 g_object_unref(image->pixbuf); | |
1701 g_free(image->filename); | |
1702 g_free(scale); | |
1703 } | |
1704 | |
1705 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1706 { | |
1707 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
1708 GtkWidget *box = gtk_event_box_new(); | |
1709 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1710 | |
1711 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
1712 | |
1713 gtk_widget_show(GTK_WIDGET(image->image)); | |
1714 gtk_widget_show(box); | |
1715 | |
1716 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); | |
1717 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
1718 } | |
1719 | |
1720 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
1721 { | |
1722 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
1723 | |
1724 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
1725 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
1726 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
1727 | |
1728 hr->sep = gtk_hseparator_new(); | |
1729 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
1730 gtk_widget_show(hr->sep); | |
1731 | |
1732 return GTK_IMHTML_SCALABLE(hr); | |
1733 } | |
1734 | |
1735 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
1736 { | |
1737 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width, 2); | |
1738 } | |
1739 | |
1740 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
1741 { | |
1742 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
1743 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
1744 | |
1745 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); | |
1746 } | |
1747 | |
1748 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
1749 { | |
1750 /* gtk_widget_destroy(((GtkIMHtmlHr *)scale)->sep); */ | |
1751 g_free(scale); | |
1752 } |