Mercurial > pidgin.yaz
annotate src/gtkimhtml.c @ 8519:f8ab826e11ad
[gaim-migrate @ 9258]
" this patch will return the text for the smileys instead
of skipping them. This patch also gets rid of two
members in the gtkimhtml stuct that weren't being used
anywhere. They were gboolean smileys, comments; which
got replace with show_smileys, and show_comments. Also
an fixes the gtk_imhtml_class_init so that if it's
being compiled in c++, it will compile..." --Gary Kramlich
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Mon, 29 Mar 2004 16:20:30 +0000 |
parents | 5b25f72c4723 |
children | 2f81f6478bae |
rev | line source |
---|---|
1428 | 1 /* |
2 * GtkIMHtml | |
3 * | |
8046 | 4 * Gaim is the legal property of its developers, whose names are too numerous |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
1428 | 7 * |
8 * This program is free software; you can redistribute it and/or modify | |
9 * under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 * | |
22 */ | |
23 | |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
24 #ifdef HAVE_CONFIG_H |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
25 #include <config.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
26 #endif |
8091 | 27 #include "util.h" |
1428 | 28 #include "gtkimhtml.h" |
7358 | 29 #include "gtksourceiter.h" |
1428 | 30 #include <gtk/gtk.h> |
4895 | 31 #include <glib/gerror.h> |
4046 | 32 #include <gdk/gdkkeysyms.h> |
1428 | 33 #include <string.h> |
34 #include <ctype.h> | |
35 #include <stdio.h> | |
4629 | 36 #include <stdlib.h> |
1428 | 37 #include <math.h> |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
38 #ifdef HAVE_LANGINFO_CODESET |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
39 #include <langinfo.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
40 #include <locale.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
41 #endif |
1428 | 42 |
4417 | 43 #ifdef ENABLE_NLS |
44 # include <libintl.h> | |
45 # define _(x) gettext(x) | |
46 # ifdef gettext_noop | |
47 # define N_(String) gettext_noop (String) | |
48 # else | |
49 # define N_(String) (String) | |
50 # endif | |
51 #else | |
52 # define N_(String) (String) | |
53 # define _(x) (x) | |
54 #endif | |
55 | |
4735 | 56 #include <pango/pango-font.h> |
57 | |
5105 | 58 /* GTK+ < 2.2.2 hack, see ui.h for details. */ |
59 #ifndef GTK_WRAP_WORD_CHAR | |
60 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD | |
61 #endif | |
62 | |
4735 | 63 #define TOOLTIP_TIMEOUT 500 |
64 | |
8061 | 65 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); |
8505 | 66 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); |
8061 | 67 void gtk_imhtml_close_tags(GtkIMHtml *imhtml); |
8091 | 68 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); |
8061 | 69 |
3922 | 70 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
71 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | |
72 #define MAX_FONT_SIZE 7 | |
5367 | 73 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
8380 | 74 static gdouble _point_sizes [] = { .69444444, .8333333, 1, 1.2, 1.44, 1.728, 2.0736}; |
2349
60c716c32c40
[gaim-migrate @ 2362]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2348
diff
changeset
|
75 |
8498 | 76 enum { |
77 TARGET_HTML, | |
8061 | 78 TARGET_UTF8_STRING, |
79 TARGET_COMPOUND_TEXT, | |
80 TARGET_STRING, | |
81 TARGET_TEXT | |
82 }; | |
83 | |
8091 | 84 enum { |
85 DRAG_URL | |
86 }; | |
87 | |
8420 | 88 enum { |
89 URL_CLICKED, | |
90 BUTTONS_UPDATE, | |
91 TOGGLE_FORMAT, | |
8427 | 92 CLEAR_FORMAT, |
8506 | 93 UPDATE_FORMAT, |
8420 | 94 LAST_SIGNAL |
95 }; | |
96 static guint signals [LAST_SIGNAL] = { 0 }; | |
97 | |
8061 | 98 GtkTargetEntry selection_targets[] = { |
8498 | 99 /* { "text/html", 0, TARGET_HTML },*/ |
8061 | 100 { "UTF8_STRING", 0, TARGET_UTF8_STRING }, |
101 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, | |
102 { "STRING", 0, TARGET_STRING }, | |
103 { "TEXT", 0, TARGET_TEXT}}; | |
104 | |
8091 | 105 GtkTargetEntry link_drag_drop_targets[] = { |
106 {"x-url/ftp", 0, DRAG_URL}, | |
107 {"x-url/http", 0, DRAG_URL}, | |
108 {"text/uri-list", 0, DRAG_URL}, | |
109 {"_NETSCAPE_URL", 0, DRAG_URL}}; | |
110 | |
4032 | 111 static GtkSmileyTree* |
112 gtk_smiley_tree_new () | |
113 { | |
114 return g_new0 (GtkSmileyTree, 1); | |
115 } | |
116 | |
117 static void | |
118 gtk_smiley_tree_insert (GtkSmileyTree *tree, | |
4263 | 119 GtkIMHtmlSmiley *smiley) |
4032 | 120 { |
121 GtkSmileyTree *t = tree; | |
4263 | 122 const gchar *x = smiley->smile; |
4032 | 123 |
124 if (!strlen (x)) | |
125 return; | |
126 | |
127 while (*x) { | |
128 gchar *pos; | |
129 gint index; | |
130 | |
131 if (!t->values) | |
132 t->values = g_string_new (""); | |
133 | |
134 pos = strchr (t->values->str, *x); | |
135 if (!pos) { | |
136 t->values = g_string_append_c (t->values, *x); | |
137 index = t->values->len - 1; | |
138 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); | |
139 t->children [index] = g_new0 (GtkSmileyTree, 1); | |
140 } else | |
7386 | 141 index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str); |
8061 | 142 |
4032 | 143 t = t->children [index]; |
8061 | 144 |
4032 | 145 x++; |
146 } | |
8061 | 147 |
4263 | 148 t->image = smiley; |
4032 | 149 } |
4041 | 150 |
4263 | 151 |
4264 | 152 void gtk_smiley_tree_destroy (GtkSmileyTree *tree) |
4032 | 153 { |
154 GSList *list = g_slist_append (NULL, tree); | |
155 | |
156 while (list) { | |
157 GtkSmileyTree *t = list->data; | |
158 gint i; | |
159 list = g_slist_remove(list, t); | |
7384 | 160 if (t && t->values) { |
4032 | 161 for (i = 0; i < t->values->len; i++) |
162 list = g_slist_append (list, t->children [i]); | |
163 g_string_free (t->values, TRUE); | |
164 g_free (t->children); | |
165 } | |
166 g_free (t); | |
167 } | |
168 } | |
169 | |
5967 | 170 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) |
171 { | |
172 GdkRectangle rect; | |
173 | |
174 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
175 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
176 GList *iter = GTK_IMHTML(widget)->scalables; | |
177 | |
178 while(iter){ | |
179 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
180 scale->scale(scale, rect.width, rect.height); | |
181 | |
182 iter = iter->next; | |
183 } | |
184 } | |
185 | |
186 widget->old_rect = rect; | |
187 return FALSE; | |
188 } | |
189 | |
190 static gint | |
191 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
192 { | |
193 PangoLayout *layout; | |
194 | |
195 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
196 | |
197 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
198 | |
8061 | 199 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, |
5967 | 200 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, |
201 "tooltip", 0, 0, -1, -1); | |
202 | |
203 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
204 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
205 | |
206 g_object_unref(layout); | |
207 return FALSE; | |
208 } | |
209 | |
210 static gint | |
211 gtk_imhtml_tip (gpointer data) | |
212 { | |
213 GtkIMHtml *imhtml = data; | |
214 PangoFontMetrics *font; | |
215 PangoLayout *layout; | |
216 | |
217 gint gap, x, y, h, w, scr_w, baseline_skip; | |
218 | |
219 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
220 | |
221 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
222 imhtml->tip_timer = 0; | |
223 return FALSE; | |
224 } | |
8061 | 225 |
5967 | 226 if (imhtml->tip_window){ |
227 gtk_widget_destroy (imhtml->tip_window); | |
228 imhtml->tip_window = NULL; | |
229 } | |
230 | |
231 imhtml->tip_timer = 0; | |
232 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
233 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
234 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
235 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
236 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
237 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
238 | |
239 gtk_widget_ensure_style (imhtml->tip_window); | |
240 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
241 font = pango_font_get_metrics(pango_context_load_font(pango_layout_get_context(layout), | |
8309 | 242 imhtml->tip_window->style->font_desc), |
243 NULL); | |
244 | |
5967 | 245 |
246 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
8061 | 247 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font) + |
5967 | 248 pango_font_metrics_get_descent(font))/ 4); |
249 | |
250 if (gap < 2) | |
251 gap = 2; | |
8061 | 252 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font) + |
5967 | 253 pango_font_metrics_get_descent(font)); |
254 w = 8 + scr_w; | |
255 h = 8 + baseline_skip; | |
256 | |
257 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
258 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
259 y += GTK_WIDGET(imhtml)->allocation.y; | |
260 | |
261 scr_w = gdk_screen_width(); | |
262 | |
263 x -= ((w >> 1) + 4); | |
264 | |
265 if ((x + w) > scr_w) | |
266 x -= (x + w) - scr_w; | |
267 else if (x < 0) | |
268 x = 0; | |
269 | |
8061 | 270 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font) + |
5967 | 271 pango_font_metrics_get_descent(font)); |
272 | |
273 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
274 gtk_widget_show (imhtml->tip_window); | |
275 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
276 | |
277 pango_font_metrics_unref(font); | |
278 g_object_unref(layout); | |
279 | |
280 return FALSE; | |
281 } | |
282 | |
283 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
8061 | 284 { |
5967 | 285 GtkTextIter iter; |
286 GdkWindow *win = event->window; | |
287 int x, y; | |
288 char *tip = NULL; | |
289 GSList *tags = NULL, *templist = NULL; | |
290 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
291 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
292 event->x, event->y, &x, &y); | |
293 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
294 tags = gtk_text_iter_get_tags(&iter); | |
295 | |
296 templist = tags; | |
297 while (templist) { | |
298 GtkTextTag *tag = templist->data; | |
299 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
300 if (tip) | |
301 break; | |
302 templist = templist->next; | |
303 } | |
8061 | 304 |
5967 | 305 if (GTK_IMHTML(imhtml)->tip) { |
306 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
307 return FALSE; | |
308 } | |
309 /* We've left the cell. Remove the timeout and create a new one below */ | |
310 if (GTK_IMHTML(imhtml)->tip_window) { | |
311 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
312 GTK_IMHTML(imhtml)->tip_window = NULL; | |
313 } | |
8061 | 314 if (GTK_IMHTML(imhtml)->editable) |
315 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->text_cursor); | |
316 else | |
317 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 318 if (GTK_IMHTML(imhtml)->tip_timer) |
319 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
320 GTK_IMHTML(imhtml)->tip_timer = 0; | |
321 } | |
8061 | 322 |
5967 | 323 if(tip){ |
8061 | 324 if (!GTK_IMHTML(imhtml)->editable) |
325 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
326 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, | |
5967 | 327 gtk_imhtml_tip, imhtml); |
328 } | |
8061 | 329 |
5967 | 330 GTK_IMHTML(imhtml)->tip = tip; |
331 g_slist_free(tags); | |
332 return FALSE; | |
333 } | |
334 | |
335 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
336 { | |
337 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
338 if (GTK_IMHTML(imhtml)->tip_window) { | |
339 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
340 GTK_IMHTML(imhtml)->tip_window = NULL; | |
341 } | |
342 if (GTK_IMHTML(imhtml)->tip_timer) { | |
343 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
344 GTK_IMHTML(imhtml)->tip_timer = 0; | |
345 } | |
8061 | 346 if (GTK_IMHTML(imhtml)->editable) |
347 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->text_cursor); | |
348 else | |
349 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 350 |
351 /* propogate the event normally */ | |
352 return FALSE; | |
353 } | |
354 | |
6066 | 355 /* |
356 * XXX - This should be removed eventually. | |
357 * | |
8061 | 358 * This function exists to work around a gross bug in GtkTextView. |
359 * Basically, we short circuit ctrl+a and ctrl+end because they make | |
6066 | 360 * el program go boom. |
361 * | |
8061 | 362 * It's supposed to be fixed in gtk2.2. You can view the bug report at |
6066 | 363 * http://bugzilla.gnome.org/show_bug.cgi?id=107939 |
364 */ | |
8317 | 365 |
366 /* | |
367 * I'm adding some keyboard shortcuts too. | |
368 */ | |
369 | |
370 gboolean gtk_key_pressed_cb(GtkIMHtml *imhtml, GdkEventKey *event, gpointer data) | |
371 { | |
372 char buf[7]; | |
373 buf[0] = '\0'; | |
374 | |
6066 | 375 if (event->state & GDK_CONTROL_MASK) |
376 switch (event->keyval) { | |
8317 | 377 case 'a': |
378 return TRUE; | |
379 break; | |
380 | |
381 case GDK_Home: | |
382 return TRUE; | |
383 break; | |
384 | |
385 case GDK_End: | |
386 return TRUE; | |
387 break; | |
388 | |
389 case 'b': /* ctrl-b is GDK_Left, which moves backwards. */ | |
390 case 'B': | |
8420 | 391 if (imhtml->format_functions & GTK_IMHTML_BOLD) { |
8456 | 392 if(imhtml->html_shortcuts) { |
393 gtk_imhtml_toggle_bold(imhtml); | |
8466 | 394 return TRUE; |
8456 | 395 } |
8420 | 396 } |
8466 | 397 return FALSE; |
8317 | 398 break; |
399 | |
400 case 'f': | |
401 case 'F': | |
402 /*set_toggle(gtkconv->toolbar.font, | |
403 !gtk_toggle_button_get_active( | |
404 GTK_TOGGLE_BUTTON(gtkconv->toolbar.font)));*/ | |
405 | |
406 return TRUE; | |
407 break; | |
408 | |
409 case 'i': | |
410 case 'I': | |
8481 | 411 if (imhtml->format_functions & GTK_IMHTML_ITALIC) { |
8466 | 412 if(imhtml->html_shortcuts) { |
8456 | 413 gtk_imhtml_toggle_italic(imhtml); |
8466 | 414 return TRUE; |
415 } | |
8481 | 416 } |
8466 | 417 return FALSE; |
8317 | 418 break; |
419 | |
420 case 'u': /* ctrl-u is GDK_Clear, which clears the line. */ | |
421 case 'U': | |
8481 | 422 if (imhtml->format_functions & GTK_IMHTML_UNDERLINE) { |
8466 | 423 if(imhtml->html_shortcuts) { |
8456 | 424 gtk_imhtml_toggle_underline(imhtml); |
8466 | 425 return TRUE; |
426 } | |
8481 | 427 } |
8466 | 428 return FALSE; |
8317 | 429 break; |
430 | |
431 case '-': | |
8420 | 432 if (imhtml->format_functions & GTK_IMHTML_SHRINK) |
433 gtk_imhtml_font_shrink(imhtml); | |
8317 | 434 return TRUE; |
435 break; | |
436 | |
437 case '=': | |
438 case '+': | |
8420 | 439 if (imhtml->format_functions & GTK_IMHTML_GROW) |
440 gtk_imhtml_font_grow(imhtml); | |
8317 | 441 return TRUE; |
442 break; | |
443 | |
444 case '1': strcpy(buf, ":-)"); break; | |
445 case '2': strcpy(buf, ":-("); break; | |
446 case '3': strcpy(buf, ";-)"); break; | |
447 case '4': strcpy(buf, ":-P"); break; | |
448 case '5': strcpy(buf, "=-O"); break; | |
449 case '6': strcpy(buf, ":-*"); break; | |
450 case '7': strcpy(buf, ">:o"); break; | |
451 case '8': strcpy(buf, "8-)"); break; | |
452 case '!': strcpy(buf, ":-$"); break; | |
453 case '@': strcpy(buf, ":-!"); break; | |
454 case '#': strcpy(buf, ":-["); break; | |
455 case '$': strcpy(buf, "O:-)"); break; | |
456 case '%': strcpy(buf, ":-/"); break; | |
457 case '^': strcpy(buf, ":'("); break; | |
458 case '&': strcpy(buf, ":-X"); break; | |
459 case '*': strcpy(buf, ":-D"); break; | |
6066 | 460 } |
8456 | 461 if (*buf && imhtml->smiley_shortcuts) { |
462 gtk_imhtml_insert_smiley(imhtml, imhtml->protocol_name, buf); | |
8317 | 463 return TRUE; |
464 } | |
6066 | 465 return FALSE; |
466 } | |
467 | |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
468 #if GTK_CHECK_VERSION(2,2,0) |
8061 | 469 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { |
470 GtkTextIter start, end; | |
471 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
472 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
473 char *text; | |
474 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); | |
475 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
476 | |
477 | |
478 if (info == TARGET_HTML) { | |
8149 | 479 int len; |
8148 | 480 char *selection; |
8061 | 481 GString *str = g_string_new(NULL); |
482 text = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
483 | |
484 /* Mozilla asks that we start our text/html with the Unicode byte order mark */ | |
485 str = g_string_append_unichar(str, 0xfeff); | |
486 str = g_string_append(str, text); | |
487 str = g_string_append_unichar(str, 0x0000); | |
8148 | 488 selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL); |
8061 | 489 gtk_selection_data_set (selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len); |
490 g_string_free(str, TRUE); | |
491 g_free(selection); | |
492 } else { | |
493 text = gtk_text_buffer_get_text(imhtml->text_buffer, &start, &end, FALSE); | |
494 gtk_selection_data_set_text(selection_data, text, strlen(text)); | |
495 } | |
496 g_free(text); | |
497 } | |
498 | |
499 static void gtk_imhtml_primary_clipboard_clear(GtkClipboard *clipboard, GtkIMHtml *imhtml) | |
7749 | 500 { |
8061 | 501 GtkTextIter insert; |
502 GtkTextIter selection_bound; | |
503 | |
504 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &insert, | |
505 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert")); | |
506 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &selection_bound, | |
507 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound")); | |
508 | |
509 if (!gtk_text_iter_equal (&insert, &selection_bound)) | |
510 gtk_text_buffer_move_mark (imhtml->text_buffer, | |
511 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"), | |
512 &insert); | |
7749 | 513 } |
7742 | 514 |
7749 | 515 static void copy_clipboard_cb(GtkIMHtml *imhtml, GtkClipboard *clipboard) |
516 { | |
8061 | 517 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), |
518 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
519 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
520 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); | |
7346 | 521 |
8061 | 522 g_signal_stop_emission_by_name(imhtml, "copy-clipboard"); |
523 } | |
524 | |
525 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) | |
526 { | |
527 char *text; | |
528 guint16 c; | |
529 GtkIMHtml *imhtml = data; | |
7809 | 530 |
8123 | 531 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml))) |
8105 | 532 return; |
533 | |
8061 | 534 if (selection_data->length < 0) { |
535 text = gtk_clipboard_wait_for_text(clipboard); | |
8128
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
536 |
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
537 if (text == NULL) |
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
538 return; |
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
539 |
8061 | 540 } else { |
541 text = g_malloc((selection_data->format / 8) * selection_data->length); | |
542 memcpy(text, selection_data->data, selection_data->length * (selection_data->format / 8)); | |
7766 | 543 } |
8061 | 544 |
545 memcpy (&c, text, 2); | |
546 if (c == 0xfeff) { | |
547 /* This is UCS2 */ | |
548 char *utf8 = g_convert(text+2, (selection_data->length * (selection_data->format / 8)) - 2, "UTF-8", "UCS-2", NULL, NULL, NULL); | |
549 g_free(text); | |
550 text = utf8; | |
551 } | |
552 gtk_imhtml_close_tags(imhtml); | |
553 gtk_imhtml_append_text_with_images(imhtml, text, GTK_IMHTML_NO_NEWLINE, NULL); | |
554 } | |
555 | |
556 | |
557 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah) | |
558 { | |
559 | |
560 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); | |
561 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), | |
562 paste_received_cb, imhtml); | |
563 g_signal_stop_emission_by_name(imhtml, "paste-clipboard"); | |
7766 | 564 } |
565 | |
7346 | 566 static gboolean button_release_cb(GtkIMHtml *imhtml, GdkEventButton event, gpointer the_foibles_of_man) |
567 { | |
8061 | 568 GtkClipboard *clipboard; |
569 if (event.button == 1) { | |
570 if ((clipboard = gtk_widget_get_clipboard (GTK_WIDGET (imhtml), | |
571 GDK_SELECTION_PRIMARY))) | |
572 gtk_text_buffer_remove_selection_clipboard (imhtml->text_buffer, clipboard); | |
573 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY), | |
574 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
575 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
576 (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml)); | |
577 } | |
7346 | 578 return FALSE; |
579 } | |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
580 #endif |
5967 | 581 |
4263 | 582 |
4032 | 583 static GtkTextViewClass *parent_class = NULL; |
584 | |
585 static void | |
586 gtk_imhtml_finalize (GObject *object) | |
587 { | |
588 GtkIMHtml *imhtml = GTK_IMHTML(object); | |
4895 | 589 GList *scalables; |
8061 | 590 |
4138 | 591 g_hash_table_destroy(imhtml->smiley_data); |
4032 | 592 gtk_smiley_tree_destroy(imhtml->default_smilies); |
4138 | 593 gdk_cursor_unref(imhtml->hand_cursor); |
594 gdk_cursor_unref(imhtml->arrow_cursor); | |
8061 | 595 gdk_cursor_unref(imhtml->text_cursor); |
8456 | 596 |
4735 | 597 if(imhtml->tip_window){ |
598 gtk_widget_destroy(imhtml->tip_window); | |
599 } | |
600 if(imhtml->tip_timer) | |
601 gtk_timeout_remove(imhtml->tip_timer); | |
602 | |
4895 | 603 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) { |
604 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); | |
605 scale->free(scale); | |
606 } | |
7991 | 607 |
4895 | 608 g_list_free(imhtml->scalables); |
4032 | 609 G_OBJECT_CLASS(parent_class)->finalize (object); |
610 } | |
1428 | 611 |
3922 | 612 /* Boring GTK stuff */ |
8519 | 613 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass) |
1428 | 614 { |
3922 | 615 GtkObjectClass *object_class; |
4032 | 616 GObjectClass *gobject_class; |
8519 | 617 object_class = (GtkObjectClass*) klass; |
618 gobject_class = (GObjectClass*) klass; | |
4032 | 619 parent_class = gtk_type_class(GTK_TYPE_TEXT_VIEW); |
4417 | 620 signals[URL_CLICKED] = g_signal_new("url_clicked", |
621 G_TYPE_FROM_CLASS(gobject_class), | |
622 G_SIGNAL_RUN_FIRST, | |
623 G_STRUCT_OFFSET(GtkIMHtmlClass, url_clicked), | |
624 NULL, | |
625 0, | |
626 g_cclosure_marshal_VOID__POINTER, | |
627 G_TYPE_NONE, 1, | |
628 G_TYPE_POINTER); | |
8506 | 629 signals[BUTTONS_UPDATE] = g_signal_new("format_buttons_update", |
8420 | 630 G_TYPE_FROM_CLASS(gobject_class), |
631 G_SIGNAL_RUN_FIRST, | |
632 G_STRUCT_OFFSET(GtkIMHtmlClass, buttons_update), | |
633 NULL, | |
634 0, | |
635 g_cclosure_marshal_VOID__POINTER, | |
636 G_TYPE_NONE, 1, | |
637 G_TYPE_INT); | |
638 signals[TOGGLE_FORMAT] = g_signal_new("format_function_toggle", | |
639 G_TYPE_FROM_CLASS(gobject_class), | |
640 G_SIGNAL_RUN_FIRST, | |
641 G_STRUCT_OFFSET(GtkIMHtmlClass, toggle_format), | |
642 NULL, | |
643 0, | |
644 g_cclosure_marshal_VOID__POINTER, | |
8427 | 645 G_TYPE_NONE, 1, |
8420 | 646 G_TYPE_INT); |
8427 | 647 signals[CLEAR_FORMAT] = g_signal_new("format_function_clear", |
648 G_TYPE_FROM_CLASS(gobject_class), | |
649 G_SIGNAL_RUN_FIRST, | |
650 G_STRUCT_OFFSET(GtkIMHtmlClass, clear_format), | |
651 NULL, | |
652 0, | |
8481 | 653 g_cclosure_marshal_VOID__VOID, |
654 G_TYPE_NONE, 0); | |
8506 | 655 signals[UPDATE_FORMAT] = g_signal_new("format_function_update", |
656 G_TYPE_FROM_CLASS(gobject_class), | |
657 G_SIGNAL_RUN_FIRST, | |
658 G_STRUCT_OFFSET(GtkIMHtmlClass, update_format), | |
659 NULL, | |
660 0, | |
661 g_cclosure_marshal_VOID__VOID, | |
662 G_TYPE_NONE, 0); | |
4032 | 663 gobject_class->finalize = gtk_imhtml_finalize; |
1428 | 664 } |
665 | |
3922 | 666 static void gtk_imhtml_init (GtkIMHtml *imhtml) |
1428 | 667 { |
3922 | 668 GtkTextIter iter; |
669 imhtml->text_buffer = gtk_text_buffer_new(NULL); | |
670 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); | |
671 imhtml->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); | |
672 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); | |
5105 | 673 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); |
3922 | 674 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); |
8061 | 675 /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/ |
3922 | 676 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ |
8061 | 677 |
3922 | 678 /* These tags will be used often and can be reused--we create them on init and then apply them by name |
8061 | 679 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ |
3922 | 680 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); |
681 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); | |
682 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); | |
683 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); | |
684 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); | |
685 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); | |
686 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); | |
7295 | 687 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); |
8061 | 688 gtk_text_buffer_create_tag(imhtml->text_buffer, "LINK", "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
3922 | 689 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
690 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | |
691 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | |
8061 | 692 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); |
2993 | 693 |
4253 | 694 imhtml->show_smileys = TRUE; |
6124 | 695 imhtml->show_comments = TRUE; |
4253 | 696 |
4892 | 697 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 698 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4032 | 699 imhtml->default_smilies = gtk_smiley_tree_new(); |
4735 | 700 |
4944 | 701 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); |
4735 | 702 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); |
4944 | 703 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); |
6066 | 704 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); |
8061 | 705 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); |
8091 | 706 |
707 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0, | |
708 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry), | |
709 GDK_ACTION_COPY); | |
710 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); | |
711 | |
8427 | 712 #if 0 /* Remove buggy copy-and-paste for 0.76 */ |
7404
d889a99e0eb1
[gaim-migrate @ 8000]
Christian Hammond <chipx86@chipx86.com>
parents:
7386
diff
changeset
|
713 #if GTK_CHECK_VERSION(2,2,0) |
7353 | 714 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); |
8061 | 715 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); |
7346 | 716 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
|
717 #endif |
8427 | 718 #endif |
4944 | 719 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); |
4735 | 720 |
721 imhtml->tip = NULL; | |
722 imhtml->tip_timer = 0; | |
723 imhtml->tip_window = NULL; | |
4895 | 724 |
8061 | 725 imhtml->edit.bold = NULL; |
726 imhtml->edit.italic = NULL; | |
727 imhtml->edit.underline = NULL; | |
728 imhtml->edit.forecolor = NULL; | |
729 imhtml->edit.backcolor = NULL; | |
730 imhtml->edit.fontface = NULL; | |
731 imhtml->edit.sizespan = NULL; | |
732 imhtml->edit.fontsize = 3; | |
733 | |
734 imhtml->format_spans = NULL; | |
735 | |
4895 | 736 imhtml->scalables = NULL; |
8061 | 737 |
738 gtk_imhtml_set_editable(imhtml, FALSE); | |
2993 | 739 } |
740 | |
3922 | 741 GtkWidget *gtk_imhtml_new(void *a, void *b) |
1428 | 742 { |
4635 | 743 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); |
1428 | 744 } |
745 | |
4635 | 746 GType gtk_imhtml_get_type() |
1428 | 747 { |
4635 | 748 static GType imhtml_type = 0; |
1428 | 749 |
750 if (!imhtml_type) { | |
4635 | 751 static const GTypeInfo imhtml_info = { |
752 sizeof(GtkIMHtmlClass), | |
753 NULL, | |
754 NULL, | |
755 (GClassInitFunc) gtk_imhtml_class_init, | |
756 NULL, | |
757 NULL, | |
1428 | 758 sizeof (GtkIMHtml), |
4635 | 759 0, |
760 (GInstanceInitFunc) gtk_imhtml_init | |
1428 | 761 }; |
4635 | 762 |
763 imhtml_type = g_type_register_static(gtk_text_view_get_type(), | |
764 "GtkIMHtml", &imhtml_info, 0); | |
1428 | 765 } |
766 | |
767 return imhtml_type; | |
768 } | |
769 | |
4417 | 770 struct url_data { |
771 GObject *object; | |
772 gchar *url; | |
773 }; | |
774 | |
775 static void url_open(GtkWidget *w, struct url_data *data) { | |
776 if(!data) return; | |
8061 | 777 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); |
7988 | 778 |
4417 | 779 g_object_unref(data->object); |
780 g_free(data->url); | |
781 g_free(data); | |
782 } | |
5582 | 783 |
4417 | 784 static void url_copy(GtkWidget *w, gchar *url) { |
785 GtkClipboard *clipboard; | |
786 | |
5293
ead927e2543f
[gaim-migrate @ 5665]
Christian Hammond <chipx86@chipx86.com>
parents:
5282
diff
changeset
|
787 clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
4417 | 788 gtk_clipboard_set_text(clipboard, url, -1); |
5582 | 789 |
790 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | |
791 gtk_clipboard_set_text(clipboard, url, -1); | |
4417 | 792 } |
793 | |
794 /* The callback for an event on a link tag. */ | |
5091 | 795 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, char *url) { |
4417 | 796 GdkEventButton *event_button = (GdkEventButton *) event; |
8061 | 797 if (GTK_IMHTML(imhtml)->editable) |
798 return FALSE; | |
3922 | 799 if (event->type == GDK_BUTTON_RELEASE) { |
8061 | 800 if (event_button->button == 1) { |
4417 | 801 GtkTextIter start, end; |
802 /* we shouldn't open a URL if the user has selected something: */ | |
803 gtk_text_buffer_get_selection_bounds( | |
804 gtk_text_iter_get_buffer(arg2), &start, &end); | |
805 if(gtk_text_iter_get_offset(&start) != | |
806 gtk_text_iter_get_offset(&end)) | |
807 return FALSE; | |
808 | |
809 /* A link was clicked--we emit the "url_clicked" signal | |
810 * with the URL as the argument */ | |
5091 | 811 g_signal_emit(imhtml, signals[URL_CLICKED], 0, url); |
4417 | 812 return FALSE; |
813 } else if(event_button->button == 3) { | |
4745 | 814 GtkWidget *img, *item, *menu; |
4417 | 815 struct url_data *tempdata = g_new(struct url_data, 1); |
5091 | 816 tempdata->object = g_object_ref(imhtml); |
4417 | 817 tempdata->url = g_strdup(url); |
4745 | 818 |
5091 | 819 /* Don't want the tooltip around if user right-clicked on link */ |
820 if (GTK_IMHTML(imhtml)->tip_window) { | |
821 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
822 GTK_IMHTML(imhtml)->tip_window = NULL; | |
823 } | |
824 if (GTK_IMHTML(imhtml)->tip_timer) { | |
825 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
826 GTK_IMHTML(imhtml)->tip_timer = 0; | |
827 } | |
8061 | 828 if (GTK_IMHTML(imhtml)->editable) |
829 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); | |
830 else | |
831 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
4417 | 832 menu = gtk_menu_new(); |
4745 | 833 |
4417 | 834 /* buttons and such */ |
835 | |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
836 if (!strncmp(url, "mailto:", 7)) |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
837 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
838 /* Copy E-Mail Address */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
839 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
840 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
841 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
842 _("_Copy E-Mail Address")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
843 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
|
844 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
845 G_CALLBACK(url_copy), url + 7); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
846 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
847 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
848 else |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
849 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
850 /* Copy Link Location */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
851 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
852 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
853 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
854 _("_Copy Link Location")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
855 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
|
856 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
857 G_CALLBACK(url_copy), url); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
858 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
859 |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
860 /* Open Link in Browser */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
861 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
862 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
863 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
864 _("_Open Link in Browser")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
865 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
|
866 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
867 G_CALLBACK(url_open), tempdata); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
868 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
869 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
870 |
4756 | 871 |
4417 | 872 gtk_widget_show_all(menu); |
4756 | 873 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
874 event_button->button, event_button->time); | |
4745 | 875 |
4417 | 876 return TRUE; |
877 } | |
1428 | 878 } |
4417 | 879 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) |
880 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
881 be caught by the regular GtkTextView menu */ | |
882 else | |
883 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1428 | 884 } |
885 | |
8091 | 886 static void |
887 gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, | |
888 GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml) | |
889 { | |
890 if(gtk_imhtml_get_editable(imhtml) && sd->data){ | |
891 gchar **links; | |
892 gchar *link; | |
893 | |
894 gaim_str_strip_cr(sd->data); | |
895 | |
896 links = g_strsplit(sd->data, "\n", 0); | |
897 while((link = *links++) != NULL){ | |
898 if(gaim_str_has_prefix(link, "http://") || | |
899 gaim_str_has_prefix(link, "https://") || | |
900 gaim_str_has_prefix(link, "ftp://")){ | |
901 gtk_imhtml_insert_link(imhtml, link, link); | |
902 } else if (link=='\0') { | |
8177 | 903 /* Ignore blank lines */ |
8091 | 904 } else { |
8177 | 905 /* Special reasons, aka images being put in via other tag, etc. */ |
8091 | 906 } |
907 } | |
908 | |
909 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); | |
910 } else { | |
911 gtk_drag_finish(dc, FALSE, FALSE, t); | |
912 } | |
913 } | |
914 | |
4298 | 915 /* this isn't used yet |
4032 | 916 static void |
4263 | 917 gtk_smiley_tree_remove (GtkSmileyTree *tree, |
918 GtkIMHtmlSmiley *smiley) | |
4032 | 919 { |
920 GtkSmileyTree *t = tree; | |
4263 | 921 const gchar *x = smiley->smile; |
4032 | 922 gint len = 0; |
923 | |
924 while (*x) { | |
925 gchar *pos; | |
926 | |
927 if (!t->values) | |
928 return; | |
929 | |
930 pos = strchr (t->values->str, *x); | |
931 if (pos) | |
932 t = t->children [(int) pos - (int) t->values->str]; | |
933 else | |
934 return; | |
935 | |
936 x++; len++; | |
937 } | |
938 | |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
939 if (t->image) { |
4032 | 940 t->image = NULL; |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
941 } |
4032 | 942 } |
4298 | 943 */ |
944 | |
4032 | 945 |
946 static gint | |
947 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
948 const gchar *text) | |
949 { | |
950 GtkSmileyTree *t = tree; | |
951 const gchar *x = text; | |
952 gint len = 0; | |
8505 | 953 gchar *amp; |
954 gint alen; | |
4032 | 955 |
956 while (*x) { | |
957 gchar *pos; | |
958 | |
959 if (!t->values) | |
960 break; | |
961 | |
8505 | 962 if(*x == '&' && gtk_imhtml_is_amp_escape(x, &, &alen)) { |
963 len += alen - strlen(amp); | |
964 x += alen - strlen(amp); | |
965 pos = strchr (t->values->str, *amp); | |
966 } | |
967 else | |
968 pos = strchr (t->values->str, *x); | |
969 | |
4032 | 970 if (pos) |
7371 | 971 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 972 else |
973 break; | |
974 | |
975 x++; len++; | |
976 } | |
977 | |
978 if (t->image) | |
979 return len; | |
980 | |
981 return 0; | |
982 } | |
983 | |
984 void | |
4263 | 985 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
986 gchar *sml, | |
987 GtkIMHtmlSmiley *smiley) | |
4032 | 988 { |
989 GtkSmileyTree *tree; | |
990 g_return_if_fail (imhtml != NULL); | |
991 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
7371 | 992 |
4032 | 993 if (sml == NULL) |
994 tree = imhtml->default_smilies; | |
995 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
996 } else { | |
997 tree = gtk_smiley_tree_new(); | |
4892 | 998 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 999 } |
1000 | |
4263 | 1001 gtk_smiley_tree_insert (tree, smiley); |
4032 | 1002 } |
1003 | |
1004 static gboolean | |
1005 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
1006 GSList *fonts, | |
1007 const gchar *text, | |
1008 gint *len) | |
1009 { | |
1010 GtkSmileyTree *tree; | |
5967 | 1011 GtkIMHtmlFontDetail *font; |
4032 | 1012 char *sml = NULL; |
1013 | |
1014 if (fonts) { | |
1015 font = fonts->data; | |
1016 sml = font->sml; | |
1017 } | |
1018 | |
1019 if (sml == NULL) | |
1020 tree = imhtml->default_smilies; | |
1021 else { | |
1022 tree = g_hash_table_lookup(imhtml->smiley_data, sml); | |
1023 } | |
1024 if (tree == NULL) | |
1025 return FALSE; | |
7371 | 1026 |
8505 | 1027 *len = gtk_smiley_tree_lookup (tree, text); |
4032 | 1028 return (*len > 0); |
1029 } | |
1030 | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1031 GdkPixbufAnimation * |
4032 | 1032 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
1033 const gchar *sml, | |
1034 const gchar *text) | |
1035 { | |
1036 GtkSmileyTree *t; | |
1037 const gchar *x = text; | |
1038 if (sml == NULL) | |
1039 t = imhtml->default_smilies; | |
7371 | 1040 else |
4032 | 1041 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
7371 | 1042 |
4032 | 1043 |
1044 if (t == NULL) | |
1045 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1046 | |
1047 while (*x) { | |
1048 gchar *pos; | |
1049 | |
1050 if (!t->values) { | |
1051 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1052 } | |
7371 | 1053 |
4032 | 1054 pos = strchr (t->values->str, *x); |
1055 if (pos) { | |
7371 | 1056 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1057 } else { |
1058 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1059 } | |
1060 x++; | |
1061 } | |
1062 | |
4263 | 1063 if (!t->image->icon) |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1064 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
4263 | 1065 |
1066 return t->image->icon; | |
4032 | 1067 } |
4793 | 1068 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 1069 *tag = g_strndup (string, strlen (x)); \ |
1070 *len = strlen (x) + 1; \ | |
1071 return TRUE; \ | |
1072 } \ | |
1073 (*type)++ | |
1428 | 1074 |
4793 | 1075 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 1076 const gchar *c = string + strlen (x " "); \ |
1077 gchar e = '"'; \ | |
1078 gboolean quote = FALSE; \ | |
1079 while (*c) { \ | |
1080 if (*c == '"' || *c == '\'') { \ | |
1081 if (quote && (*c == e)) \ | |
1082 quote = !quote; \ | |
1083 else if (!quote) { \ | |
1084 quote = !quote; \ | |
1085 e = *c; \ | |
1086 } \ | |
1087 } else if (!quote && (*c == '>')) \ | |
1088 break; \ | |
1089 c++; \ | |
1090 } \ | |
1091 if (*c) { \ | |
1092 *tag = g_strndup (string, c - string); \ | |
1093 *len = c - string + 1; \ | |
1094 return TRUE; \ | |
1095 } \ | |
1096 } \ | |
1097 (*type)++ | |
1428 | 1098 |
1099 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1100 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1101 gtk_imhtml_is_amp_escape (const gchar *string, |
7280 | 1102 gchar **replace, |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1103 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1104 { |
7287 | 1105 static char buf[7]; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1106 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1107 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1108 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1109 |
4793 | 1110 if (!g_ascii_strncasecmp (string, "&", 5)) { |
7280 | 1111 *replace = "&"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1112 *length = 5; |
4793 | 1113 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
7280 | 1114 *replace = "<"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1115 *length = 4; |
4793 | 1116 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
7280 | 1117 *replace = ">"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1118 *length = 4; |
4793 | 1119 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
7280 | 1120 *replace = " "; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1121 *length = 6; |
4793 | 1122 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
7280 | 1123 *replace = "©"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1124 *length = 6; |
4793 | 1125 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
7280 | 1126 *replace = "\""; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1127 *length = 6; |
4793 | 1128 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
7280 | 1129 *replace = "®"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1130 *length = 5; |
5093 | 1131 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
7280 | 1132 *replace = "\'"; |
5093 | 1133 *length = 6; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1134 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
1135 guint pound = 0; |
3004 | 1136 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
7287 | 1137 int buflen; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1138 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1139 return FALSE; |
7287 | 1140 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
1141 buf[buflen] = '\0'; | |
7280 | 1142 *replace = buf; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1143 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1144 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1145 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1146 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1147 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1148 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1149 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1150 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1151 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1152 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1153 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1154 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1155 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1156 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1157 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1158 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1159 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1160 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1161 { |
8061 | 1162 char *close; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1163 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1164 |
8118 | 1165 |
8061 | 1166 if (!(close = strchr (string, '>'))) |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1167 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1168 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1169 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1170 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1171 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1172 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1173 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1174 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1175 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1176 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1177 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1178 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1179 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1180 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1181 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1182 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1183 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1184 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1185 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1186 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1187 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1188 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1189 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1190 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1191 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1192 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1193 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1194 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1195 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1196 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1197 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1198 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1199 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1200 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1201 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1202 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1203 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1204 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1205 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1206 VALID_TAG ("HEAD"); |
2993 | 1207 VALID_TAG ("/HEAD"); |
1208 VALID_TAG ("BINARY"); | |
1209 VALID_TAG ("/BINARY"); | |
5093 | 1210 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1211 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1212 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1213 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1214 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1215 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1216 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1217 VALID_OPT_TAG ("H3"); |
5093 | 1218 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1219 |
5101 | 1220 VALID_TAG ("CITE"); |
1221 VALID_TAG ("/CITE"); | |
1222 VALID_TAG ("EM"); | |
1223 VALID_TAG ("/EM"); | |
1224 VALID_TAG ("STRONG"); | |
1225 VALID_TAG ("/STRONG"); | |
1226 | |
5104 | 1227 VALID_OPT_TAG ("SPAN"); |
1228 VALID_TAG ("/SPAN"); | |
5174 | 1229 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
6982 | 1230 VALID_TAG ("IMG"); |
8026 | 1231 VALID_TAG("SPAN"); |
8061 | 1232 VALID_OPT_TAG("BR"); |
7988 | 1233 |
4793 | 1234 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
1235 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1236 if (e) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1237 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1238 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1239 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1240 } |
8118 | 1241 } |
1242 | |
8061 | 1243 *type = -1; |
1244 *len = close - string + 1; | |
1245 *tag = g_strndup(string, *len - 1); | |
1246 return TRUE; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1247 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1248 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1249 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1250 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1251 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1252 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1253 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1254 gchar *e, *a; |
5177 | 1255 gchar *val; |
1256 gint len; | |
7280 | 1257 gchar *c; |
5177 | 1258 GString *ret; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1259 |
4793 | 1260 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1261 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1262 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1263 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1264 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1265 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1266 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1267 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1268 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1269 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1270 |
4793 | 1271 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1272 t += strlen (opt); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1273 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1274 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1275 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1276 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1277 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1278 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1279 while (*e && (*e != *(t - 1))) e++; |
2993 | 1280 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1281 return NULL; |
5177 | 1282 } else |
1283 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1284 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1285 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1286 while (*e && !isspace ((gint) *e)) e++; |
5177 | 1287 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1288 } |
5177 | 1289 |
1290 ret = g_string_new(""); | |
1291 e = val; | |
1292 while(*e) { | |
1293 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
7280 | 1294 ret = g_string_append(ret, c); |
5177 | 1295 e += len; |
1296 } else { | |
1297 ret = g_string_append_c(ret, *e); | |
1298 e++; | |
1299 } | |
1300 } | |
1301 | |
1302 g_free(val); | |
1303 val = ret->str; | |
1304 g_string_free(ret, FALSE); | |
1305 return val; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1306 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1307 |
8118 | 1308 /* Inline CSS Support - Douglas Thrift */ |
1309 static gchar* | |
1310 gtk_imhtml_get_css_opt (gchar *style, | |
1311 const gchar *opt) | |
1312 { | |
1313 gchar *t = style; | |
1314 gchar *e, *a; | |
1315 gchar *val; | |
1316 gint len; | |
1317 gchar *c; | |
1318 GString *ret; | |
1319 | |
1320 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
8177 | 1321 /* gboolean quote = FALSE; */ |
8118 | 1322 if (*t == '\0') break; |
1323 while (*t && !((*t == ' ') /*&& !quote*/)) { | |
1324 /* if (*t == '\"') | |
8177 | 1325 quote = ! quote; */ |
8118 | 1326 t++; |
1327 } | |
1328 while (*t && (*t == ' ')) t++; | |
1329 } | |
1330 | |
1331 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
1332 t += strlen (opt); | |
1333 } else { | |
1334 return NULL; | |
1335 } | |
1336 | |
1337 /* if ((*t == '\"') || (*t == '\'')) { | |
1338 e = a = ++t; | |
1339 while (*e && (*e != *(t - 1))) e++; | |
1340 if (*e == '\0') { | |
1341 return NULL; | |
1342 } else | |
1343 val = g_strndup(a, e - a); | |
1344 } else { | |
1345 e = a = t; | |
1346 while (*e && !isspace ((gint) *e)) e++; | |
1347 val = g_strndup(a, e - a); | |
1348 }*/ | |
1349 | |
1350 e = a = t; | |
1351 while (*e && *e != ';') e++; | |
1352 val = g_strndup(a, e - a); | |
1353 | |
1354 ret = g_string_new(""); | |
1355 e = val; | |
1356 while(*e) { | |
1357 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
1358 ret = g_string_append(ret, c); | |
1359 e += len; | |
1360 } else { | |
1361 ret = g_string_append_c(ret, *e); | |
1362 e++; | |
1363 } | |
1364 } | |
1365 | |
1366 g_free(val); | |
1367 val = ret->str; | |
1368 g_string_free(ret, FALSE); | |
1369 return val; | |
1370 } | |
3922 | 1371 |
8334 | 1372 static const char *accepted_protocols[] = { |
1373 "http://", | |
1374 "https://", | |
1375 "ftp://" | |
1376 }; | |
1377 | |
1378 static const int accepted_protocols_size = 3; | |
1379 | |
1380 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so | |
1381 the caller knows how long the protocol string is. */ | |
1382 int gtk_imhtml_is_protocol(const char *text) | |
1383 { | |
1384 gint i; | |
1385 | |
1386 for(i=0; i<accepted_protocols_size; i++){ | |
1387 if( strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0 ){ | |
1388 return strlen(accepted_protocols[i]); | |
1389 } | |
1390 } | |
1391 return 0; | |
1392 } | |
1393 | |
6982 | 1394 GString* gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, |
1395 const gchar *text, | |
1396 GtkIMHtmlOptions options, | |
1397 GSList *images) | |
1428 | 1398 { |
8061 | 1399 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
1400 GtkTextIter insert; | |
1401 GdkRectangle rect; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1402 gint pos = 0; |
3922 | 1403 GString *str = NULL; |
8061 | 1404 GtkTextIter iter; |
1405 GtkTextMark *mark; | |
3922 | 1406 gchar *ws; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1407 gchar *tag; |
3922 | 1408 gchar *url = NULL; |
1409 gchar *bg = NULL; | |
6982 | 1410 gint len; |
4032 | 1411 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1412 gint type; |
3922 | 1413 const gchar *c; |
7280 | 1414 gchar *amp; |
8334 | 1415 gint len_protocol; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1416 |
1428 | 1417 guint bold = 0, |
1418 italics = 0, | |
1419 underline = 0, | |
1420 strike = 0, | |
1421 sub = 0, | |
1422 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1423 title = 0, |
8061 | 1424 pre = 0; |
1428 | 1425 |
3922 | 1426 GSList *fonts = NULL; |
8506 | 1427 GObject *object; |
8061 | 1428 GtkIMHtmlScalable *scalable = NULL; |
4612 | 1429 int y, height; |
1430 | |
1428 | 1431 g_return_val_if_fail (imhtml != NULL, NULL); |
1432 g_return_val_if_fail (GTK_IS_IMHTML (imhtml), NULL); | |
1433 g_return_val_if_fail (text != NULL, NULL); | |
3922 | 1434 c = text; |
6982 | 1435 len = strlen(text); |
3922 | 1436 ws = g_malloc(len + 1); |
1437 ws[0] = 0; | |
1428 | 1438 |
1439 if (options & GTK_IMHTML_RETURN_LOG) | |
3922 | 1440 str = g_string_new(""); |
1428 | 1441 |
8061 | 1442 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &insert, ins); |
1443 | |
3922 | 1444 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); |
1445 mark = gtk_text_buffer_create_mark (imhtml->text_buffer, NULL, &iter, /* right grav */ FALSE); | |
4612 | 1446 |
8061 | 1447 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
4612 | 1448 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); |
1449 | |
8061 | 1450 #if GTK_CHECK_VERSION(2,2,0) |
1451 gtk_imhtml_primary_clipboard_clear(NULL, imhtml); | |
1452 #endif | |
1453 gtk_text_buffer_move_mark (imhtml->text_buffer, | |
1454 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"), | |
1455 &iter); | |
1456 | |
1457 if(((y + height) - (rect.y + rect.height)) > height | |
4612 | 1458 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ |
1459 options |= GTK_IMHTML_NO_SCROLL; | |
1460 } | |
1461 | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1462 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1463 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1464 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1465 pos++; |
8061 | 1466 ws[wpos] = '\0'; |
1467 switch (type) | |
3922 | 1468 { |
1469 case 1: /* B */ | |
1470 case 2: /* BOLD */ | |
5101 | 1471 case 54: /* STRONG */ |
8061 | 1472 if (url) |
1473 gtk_imhtml_insert_link(imhtml, url, ws); | |
1474 else | |
1475 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1476 if (bold == 0) | |
1477 gtk_imhtml_toggle_bold(imhtml); | |
3922 | 1478 bold++; |
8061 | 1479 ws[0] = '\0'; wpos = 0; |
3922 | 1480 break; |
1481 case 3: /* /B */ | |
1482 case 4: /* /BOLD */ | |
5101 | 1483 case 55: /* /STRONG */ |
8061 | 1484 if (url) |
1485 gtk_imhtml_insert_link(imhtml, url, ws); | |
1486 else | |
1487 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1488 ws[0] = '\0'; wpos = 0; | |
1489 | |
3922 | 1490 if (bold) |
1491 bold--; | |
8061 | 1492 if (bold == 0) |
1493 gtk_imhtml_toggle_bold(imhtml); | |
3922 | 1494 break; |
1495 case 5: /* I */ | |
1496 case 6: /* ITALIC */ | |
5101 | 1497 case 52: /* EM */ |
8061 | 1498 if (url) |
1499 gtk_imhtml_insert_link(imhtml, url, ws); | |
1500 else | |
1501 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1502 ws[0] = '\0'; wpos = 0; | |
1503 if (italics == 0) | |
1504 gtk_imhtml_toggle_italic(imhtml); | |
3922 | 1505 italics++; |
1506 break; | |
1507 case 7: /* /I */ | |
1508 case 8: /* /ITALIC */ | |
5101 | 1509 case 53: /* /EM */ |
8061 | 1510 if (url) |
1511 gtk_imhtml_insert_link(imhtml, url, ws); | |
1512 else | |
1513 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1514 ws[0] = '\0'; wpos = 0; | |
3922 | 1515 if (italics) |
1516 italics--; | |
8061 | 1517 if (italics == 0) |
1518 gtk_imhtml_toggle_italic(imhtml); | |
3922 | 1519 break; |
1520 case 9: /* U */ | |
1521 case 10: /* UNDERLINE */ | |
8061 | 1522 if (url) |
1523 gtk_imhtml_insert_link(imhtml, url, ws); | |
1524 else | |
1525 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1526 ws[0] = '\0'; wpos = 0; | |
1527 if (underline == 0) | |
1528 gtk_imhtml_toggle_underline(imhtml); | |
3922 | 1529 underline++; |
1530 break; | |
1531 case 11: /* /U */ | |
1532 case 12: /* /UNDERLINE */ | |
8061 | 1533 if (url) |
1534 gtk_imhtml_insert_link(imhtml, url, ws); | |
1535 else | |
1536 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1537 ws[0] = '\0'; wpos = 0; | |
3922 | 1538 if (underline) |
1539 underline--; | |
8061 | 1540 if (underline == 0) |
1541 gtk_imhtml_toggle_underline(imhtml); | |
3922 | 1542 break; |
1543 case 13: /* S */ | |
1544 case 14: /* STRIKE */ | |
8177 | 1545 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1546 strike++; |
1547 break; | |
1548 case 15: /* /S */ | |
1549 case 16: /* /STRIKE */ | |
8177 | 1550 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1551 if (strike) |
1552 strike--; | |
1553 break; | |
1554 case 17: /* SUB */ | |
8177 | 1555 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1556 sub++; |
1557 break; | |
1558 case 18: /* /SUB */ | |
8177 | 1559 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1560 if (sub) |
1561 sub--; | |
1562 break; | |
1563 case 19: /* SUP */ | |
8177 | 1564 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1565 sup++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1566 break; |
3922 | 1567 case 20: /* /SUP */ |
8177 | 1568 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1569 if (sup) |
1570 sup--; | |
1571 break; | |
1572 case 21: /* PRE */ | |
8177 | 1573 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1574 pre++; |
1575 break; | |
1576 case 22: /* /PRE */ | |
8177 | 1577 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1578 if (pre) |
1579 pre--; | |
1580 break; | |
1581 case 23: /* TITLE */ | |
8177 | 1582 /* NEW_BIT (NEW_TEXT_BIT); */ |
3922 | 1583 title++; |
1584 break; | |
1585 case 24: /* /TITLE */ | |
1586 if (title) { | |
1587 if (options & GTK_IMHTML_NO_TITLE) { | |
1588 wpos = 0; | |
1589 ws [wpos] = '\0'; | |
1590 } | |
1591 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1592 } |
3922 | 1593 break; |
1594 case 25: /* BR */ | |
5174 | 1595 case 58: /* BR/ */ |
8061 | 1596 case 61: /* BR (opt) */ |
3922 | 1597 ws[wpos] = '\n'; |
1598 wpos++; | |
8177 | 1599 /* NEW_BIT (NEW_TEXT_BIT); */ |
6982 | 1600 break; |
3922 | 1601 case 26: /* HR */ |
1602 case 42: /* HR (opt) */ | |
1603 ws[wpos++] = '\n'; | |
8061 | 1604 if (url) |
1605 gtk_imhtml_insert_link(imhtml, url, ws); | |
1606 else | |
1607 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
5967 | 1608 scalable = gtk_imhtml_hr_new(); |
8061 | 1609 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
1610 scalable->add_to(scalable, imhtml, &iter); | |
1611 scalable->scale(scalable, rect.width, rect.height); | |
1612 imhtml->scalables = g_list_append(imhtml->scalables, scalable); | |
1613 ws[0] = '\0'; wpos = 0; | |
7942 | 1614 ws[wpos++] = '\n'; |
8061 | 1615 |
3922 | 1616 break; |
1617 case 27: /* /FONT */ | |
1618 if (fonts) { | |
5967 | 1619 GtkIMHtmlFontDetail *font = fonts->data; |
8061 | 1620 if (url) |
1621 gtk_imhtml_insert_link(imhtml, url, ws); | |
1622 else | |
1623 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1624 ws[0] = '\0'; wpos = 0; | |
8177 | 1625 /* NEW_BIT (NEW_TEXT_BIT); */ |
8309 | 1626 |
8061 | 1627 if (font->face) { |
1628 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
3922 | 1629 g_free (font->face); |
8061 | 1630 } |
1631 if (font->fore) { | |
1632 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
3922 | 1633 g_free (font->fore); |
8061 | 1634 } |
1635 if (font->back) { | |
1636 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
3922 | 1637 g_free (font->back); |
8061 | 1638 } |
4032 | 1639 if (font->sml) |
1640 g_free (font->sml); | |
3922 | 1641 g_free (font); |
8309 | 1642 |
1643 if (font->size != 3) | |
1644 gtk_imhtml_font_set_size(imhtml, 3); | |
1645 | |
1646 fonts = fonts->next; | |
1647 if (fonts) { | |
1648 GtkIMHtmlFontDetail *font = fonts->data; | |
1649 | |
1650 if (font->face) | |
1651 gtk_imhtml_toggle_fontface(imhtml, font->face); | |
1652 if (font->fore) | |
1653 gtk_imhtml_toggle_forecolor(imhtml, font->fore); | |
1654 if (font->back) | |
1655 gtk_imhtml_toggle_backcolor(imhtml, font->back); | |
1656 if (font->size != 3) | |
1657 gtk_imhtml_font_set_size(imhtml, font->size); | |
1658 } | |
3922 | 1659 } |
8309 | 1660 break; |
3922 | 1661 case 28: /* /A */ |
1662 if (url) { | |
8061 | 1663 gtk_imhtml_insert_link(imhtml, url, ws); |
3922 | 1664 g_free(url); |
8061 | 1665 ws[0] = '\0'; wpos = 0; |
3922 | 1666 url = NULL; |
8061 | 1667 ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
1668 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2993 | 1669 } |
8061 | 1670 break; |
8118 | 1671 |
3922 | 1672 case 29: /* P */ |
1673 case 30: /* /P */ | |
1674 case 31: /* H3 */ | |
1675 case 32: /* /H3 */ | |
1676 case 33: /* HTML */ | |
1677 case 34: /* /HTML */ | |
1678 case 35: /* BODY */ | |
1679 case 36: /* /BODY */ | |
1680 case 37: /* FONT */ | |
1681 case 38: /* HEAD */ | |
1682 case 39: /* /HEAD */ | |
6982 | 1683 case 40: /* BINARY */ |
1684 case 41: /* /BINARY */ | |
3922 | 1685 break; |
1686 case 43: /* FONT (opt) */ | |
1687 { | |
4032 | 1688 gchar *color, *back, *face, *size, *sml; |
5967 | 1689 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 1690 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
1691 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
1692 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
1693 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 1694 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
1695 if (!(color || back || face || size || sml)) | |
3922 | 1696 break; |
8061 | 1697 |
1698 if (url) | |
1699 gtk_imhtml_insert_link(imhtml, url, ws); | |
1700 else | |
1701 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1702 ws[0] = '\0'; wpos = 0; | |
1703 | |
5967 | 1704 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 1705 if (fonts) |
1706 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1707 |
8309 | 1708 if (color && !(options & GTK_IMHTML_NO_COLOURS)) { |
3922 | 1709 font->fore = color; |
8061 | 1710 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8309 | 1711 } |
1712 //else if (oldfont && oldfont->fore) | |
1713 // font->fore = g_strdup(oldfont->fore); | |
1714 | |
1715 if (back && !(options & GTK_IMHTML_NO_COLOURS)) { | |
3922 | 1716 font->back = back; |
8061 | 1717 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8309 | 1718 } |
1719 //else if (oldfont && oldfont->back) | |
1720 // font->back = g_strdup(oldfont->back); | |
1721 | |
1722 if (face && !(options & GTK_IMHTML_NO_FONTS)) { | |
3922 | 1723 font->face = face; |
8061 | 1724 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8309 | 1725 } |
1726 //else if (oldfont && oldfont->face) | |
1727 // font->face = g_strdup(oldfont->face); | |
4032 | 1728 |
1729 if (sml) | |
1730 font->sml = sml; | |
1731 else if (oldfont && oldfont->sml) | |
1732 font->sml = g_strdup(oldfont->sml); | |
1733 | |
3922 | 1734 if (size && !(options & GTK_IMHTML_NO_SIZES)) { |
1735 if (*size == '+') { | |
1736 sscanf (size + 1, "%hd", &font->size); | |
1737 font->size += 3; | |
1738 } else if (*size == '-') { | |
1739 sscanf (size + 1, "%hd", &font->size); | |
1740 font->size = MAX (0, 3 - font->size); | |
1741 } else if (isdigit (*size)) { | |
1742 sscanf (size, "%hd", &font->size); | |
8061 | 1743 } |
6042 | 1744 if (font->size > 100) |
1745 font->size = 100; | |
3922 | 1746 } else if (oldfont) |
1747 font->size = oldfont->size; | |
8309 | 1748 else |
1749 font->size = 3; | |
1750 gtk_imhtml_font_set_size(imhtml, font->size); | |
3922 | 1751 g_free(size); |
1752 fonts = g_slist_prepend (fonts, font); | |
1753 } | |
1754 break; | |
1755 case 44: /* BODY (opt) */ | |
1756 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
1757 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
1758 if (bgcolor) { | |
8061 | 1759 if (url) |
1760 gtk_imhtml_insert_link(imhtml, url, ws); | |
1761 else | |
1762 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1763 ws[0] = '\0'; wpos = 0; | |
8177 | 1764 /* NEW_BIT(NEW_TEXT_BIT); */ |
3922 | 1765 if (bg) |
1766 g_free(bg); | |
1767 bg = bgcolor; | |
8061 | 1768 gtk_imhtml_toggle_backcolor(imhtml, bg); |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
1769 } |
1428 | 1770 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1771 break; |
3922 | 1772 case 45: /* A (opt) */ |
1773 { | |
1774 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
1775 if (href) { | |
8061 | 1776 if (url) { |
1777 gtk_imhtml_insert_link(imhtml, url, ws); | |
1778 g_free(url); | |
1779 } else | |
1780 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1781 ws[0] = '\0'; wpos = 0; | |
3922 | 1782 url = href; |
1783 } | |
2993 | 1784 } |
3922 | 1785 break; |
4895 | 1786 case 46: /* IMG (opt) */ |
6982 | 1787 case 59: /* IMG */ |
4895 | 1788 { |
6982 | 1789 GdkPixbuf *img = NULL; |
1790 const gchar *filename = NULL; | |
4895 | 1791 |
6982 | 1792 if (images && images->data) { |
1793 img = images->data; | |
1794 images = images->next; | |
1795 filename = g_object_get_data(G_OBJECT(img), "filename"); | |
1796 g_object_ref(G_OBJECT(img)); | |
1797 } else { | |
1798 img = gtk_widget_render_icon(GTK_WIDGET(imhtml), | |
1799 GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON, | |
1800 "gtkimhtml-missing-image"); | |
1801 } | |
4895 | 1802 |
6982 | 1803 scalable = gtk_imhtml_image_new(img, filename); |
8177 | 1804 /* NEW_BIT(NEW_SCALABLE_BIT); */ |
6982 | 1805 g_object_unref(G_OBJECT(img)); |
4895 | 1806 } |
3922 | 1807 case 47: /* P (opt) */ |
1808 case 48: /* H3 (opt) */ | |
5093 | 1809 case 49: /* HTML (opt) */ |
5101 | 1810 case 50: /* CITE */ |
1811 case 51: /* /CITE */ | |
8026 | 1812 case 56: /* SPAN (opt) */ |
8118 | 1813 /* Inline CSS Support - Douglas Thrift |
1814 * | |
1815 * color | |
1816 * font-family | |
1817 * font-size | |
1818 */ | |
1819 { | |
1820 gchar *style, *color, *family, *size; | |
1821 GtkIMHtmlFontDetail *font, *oldfont = NULL; | |
1822 style = gtk_imhtml_get_html_opt (tag, "style="); | |
1823 | |
1824 if (!style) break; | |
1825 | |
1826 color = gtk_imhtml_get_css_opt (style, "color: "); | |
1827 family = gtk_imhtml_get_css_opt (style, | |
1828 "font-family: "); | |
1829 size = gtk_imhtml_get_css_opt (style, "font-size: "); | |
1830 | |
8120 | 1831 if (!(color || family || size)) { |
1832 g_free(style); | |
1833 break; | |
1834 } | |
8118 | 1835 |
1836 if (url) | |
1837 gtk_imhtml_insert_link(imhtml, url, ws); | |
1838 else | |
1839 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1840 ws[0] = '\0'; wpos = 0; | |
8177 | 1841 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 1842 |
1843 font = g_new0 (GtkIMHtmlFontDetail, 1); | |
1844 if (fonts) | |
1845 oldfont = fonts->data; | |
1846 | |
1847 if (color && !(options & GTK_IMHTML_NO_COLOURS)) | |
1848 font->fore = color; | |
1849 else if (oldfont && oldfont->fore) | |
1850 font->fore = g_strdup(oldfont->fore); | |
1851 | |
1852 if (oldfont && oldfont->back) | |
1853 font->back = g_strdup(oldfont->back); | |
1854 | |
1855 if (family && !(options & GTK_IMHTML_NO_FONTS)) | |
1856 font->face = family; | |
1857 else if (oldfont && oldfont->face) | |
1858 font->face = g_strdup(oldfont->face); | |
1859 if (font->face && (atoi(font->face) > 100)) { | |
1860 g_free(font->face); | |
1861 font->face = g_strdup("100"); | |
1862 } | |
1863 | |
1864 if (oldfont && oldfont->sml) | |
1865 font->sml = g_strdup(oldfont->sml); | |
1866 | |
1867 if (size && !(options & GTK_IMHTML_NO_SIZES)) { | |
1868 if (g_ascii_strcasecmp(size, "smaller") == 0) | |
1869 { | |
1870 font->size = 2; | |
1871 } | |
1872 else if (g_ascii_strcasecmp(size, "larger") == 0) | |
1873 { | |
1874 font->size = 4; | |
1875 } | |
1876 else | |
1877 { | |
1878 font->size = 3; | |
1879 } | |
1880 } else if (oldfont) | |
1881 font->size = oldfont->size; | |
1882 | |
1883 g_free(style); | |
1884 g_free(size); | |
1885 fonts = g_slist_prepend (fonts, font); | |
1886 } | |
1887 break; | |
5104 | 1888 case 57: /* /SPAN */ |
8118 | 1889 /* Inline CSS Support - Douglas Thrift */ |
1890 if (fonts) { | |
1891 GtkIMHtmlFontDetail *font = fonts->data; | |
1892 if (url) | |
1893 gtk_imhtml_insert_link(imhtml, url, ws); | |
1894 else | |
1895 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1896 ws[0] = '\0'; wpos = 0; | |
8177 | 1897 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 1898 fonts = g_slist_remove (fonts, font); |
1899 if (font->face) | |
1900 g_free (font->face); | |
1901 if (font->fore) | |
1902 g_free (font->fore); | |
1903 if (font->back) | |
1904 g_free (font->back); | |
1905 if (font->sml) | |
1906 g_free (font->sml); | |
1907 g_free (font); | |
1908 } | |
1909 break; | |
8026 | 1910 case 60: /* SPAN */ |
2993 | 1911 break; |
8061 | 1912 case 62: /* comment */ |
8177 | 1913 /* NEW_BIT (NEW_TEXT_BIT); */ |
8317 | 1914 ws[wpos] = '\0'; |
1915 if (url) | |
1916 gtk_imhtml_insert_link(imhtml, url, ws); | |
1917 else | |
1918 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
6124 | 1919 if (imhtml->show_comments) |
1920 wpos = g_snprintf (ws, len, "%s", tag); | |
8177 | 1921 /* NEW_BIT (NEW_COMMENT_BIT); */ |
3922 | 1922 break; |
1923 default: | |
6882 | 1924 break; |
2993 | 1925 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1926 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1927 pos += tlen; |
4138 | 1928 if(tag) |
1929 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
8473 | 1930 } else if (imhtml->show_smileys && (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen))) { |
1931 GtkIMHtmlFontDetail *fd; | |
1932 | |
1933 gchar *sml = NULL; | |
1934 if (fonts) { | |
1935 fd = fonts->data; | |
1936 sml = fd->sml; | |
1937 } | |
1938 if (url) | |
1939 gtk_imhtml_insert_link(imhtml, url, ws); | |
1940 else { | |
1941 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1942 } | |
8505 | 1943 wpos = g_snprintf (ws, smilelen + 1, "%s", c); |
8473 | 1944 |
1945 gtk_imhtml_insert_smiley(imhtml, sml, ws); | |
1946 | |
1947 ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
1948 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
1949 | |
8505 | 1950 c += smilelen; |
1951 pos += smilelen; | |
8473 | 1952 wpos = 0; |
1953 ws[0] = 0; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1954 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
7280 | 1955 while(*amp) { |
1956 ws [wpos++] = *amp++; | |
1957 } | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1958 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1959 pos += tlen; |
1428 | 1960 } else if (*c == '\n') { |
1961 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 1962 ws[wpos] = '\n'; |
1963 wpos++; | |
8061 | 1964 if (url) |
1965 gtk_imhtml_insert_link(imhtml, url, ws); | |
1966 else | |
1967 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1968 ws[0] = '\0'; | |
1969 wpos = 0; | |
8177 | 1970 /* NEW_BIT (NEW_TEXT_BIT); */ |
1428 | 1971 } |
1972 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1973 pos++; |
8334 | 1974 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ |
1975 while(len_protocol--){ | |
1976 /* Skip the next len_protocol characters, but make sure they're | |
1977 copied into the ws array. | |
1978 */ | |
1979 ws [wpos++] = *c++; | |
1980 pos++; | |
1981 } | |
8061 | 1982 } else if (*c) { |
1428 | 1983 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1984 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1985 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1986 break; |
1428 | 1987 } |
1988 } | |
8061 | 1989 if (url) |
1990 gtk_imhtml_insert_link(imhtml, url, ws); | |
1991 else | |
1992 gtk_text_buffer_insert(imhtml->text_buffer, &iter, ws, wpos); | |
1993 ws[0] = '\0'; wpos = 0; | |
1994 | |
8177 | 1995 /* NEW_BIT(NEW_TEXT_BIT); */ |
1428 | 1996 if (url) { |
1997 g_free (url); | |
3922 | 1998 if (str) |
1999 str = g_string_append (str, "</A>"); | |
1428 | 2000 } |
8061 | 2001 |
4032 | 2002 while (fonts) { |
5967 | 2003 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 2004 fonts = g_slist_remove (fonts, font); |
2005 if (font->face) | |
2006 g_free (font->face); | |
2007 if (font->fore) | |
2008 g_free (font->fore); | |
2009 if (font->back) | |
2010 g_free (font->back); | |
2011 if (font->sml) | |
2012 g_free (font->sml); | |
2013 g_free (font); | |
2014 if (str) | |
2015 str = g_string_append (str, "</FONT>"); | |
2016 } | |
2017 | |
3922 | 2018 if (str) { |
1428 | 2019 while (bold) { |
3922 | 2020 str = g_string_append (str, "</B>"); |
1428 | 2021 bold--; |
2022 } | |
2023 while (italics) { | |
3922 | 2024 str = g_string_append (str, "</I>"); |
1428 | 2025 italics--; |
2026 } | |
2027 while (underline) { | |
3922 | 2028 str = g_string_append (str, "</U>"); |
1428 | 2029 underline--; |
2030 } | |
2031 while (strike) { | |
3922 | 2032 str = g_string_append (str, "</S>"); |
1428 | 2033 strike--; |
2034 } | |
2035 while (sub) { | |
3922 | 2036 str = g_string_append (str, "</SUB>"); |
1428 | 2037 sub--; |
2038 } | |
2039 while (sup) { | |
3922 | 2040 str = g_string_append (str, "</SUP>"); |
1428 | 2041 sup--; |
2042 } | |
2043 while (title) { | |
3922 | 2044 str = g_string_append (str, "</TITLE>"); |
1428 | 2045 title--; |
2046 } | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2047 while (pre) { |
3922 | 2048 str = g_string_append (str, "</PRE>"); |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2049 pre--; |
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2050 } |
1428 | 2051 } |
4032 | 2052 g_free (ws); |
4630 | 2053 if(bg) |
2054 g_free(bg); | |
8506 | 2055 /* this shouldn't be necessary if we want to be able to continue |
2056 * using the format if it was unclosed. But seeing as removing this | |
2057 * line does not help the ctrl-up/down from enabling open tags, I'm | |
2058 * leaving it up to sean, or unless I find some time to look into it | |
2059 * more -Gary */ | |
2060 gtk_imhtml_close_tags(imhtml); | |
4032 | 2061 if (!(options & GTK_IMHTML_NO_SCROLL)) |
2062 gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (imhtml), mark, | |
2063 0, TRUE, 0.0, 1.0); | |
3922 | 2064 gtk_text_buffer_delete_mark (imhtml->text_buffer, mark); |
8061 | 2065 gtk_text_buffer_move_mark (imhtml->text_buffer, |
2066 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert"), | |
2067 &iter); | |
8506 | 2068 |
2069 object = g_object_ref(G_OBJECT(imhtml)); | |
2070 g_signal_emit(object, signals[UPDATE_FORMAT], 0); | |
2071 g_object_unref(object); | |
2072 | |
3922 | 2073 return str; |
2074 } | |
2075 | |
4892 | 2076 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
2077 { | |
4288 | 2078 g_hash_table_destroy(imhtml->smiley_data); |
2079 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 2080 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 2081 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 2082 imhtml->default_smilies = gtk_smiley_tree_new(); |
2083 } | |
8481 | 2084 |
3922 | 2085 void gtk_imhtml_show_smileys (GtkIMHtml *imhtml, |
4253 | 2086 gboolean show) |
2087 { | |
2088 imhtml->show_smileys = show; | |
2089 } | |
3922 | 2090 |
2091 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, | |
4253 | 2092 gboolean show) |
2093 { | |
6124 | 2094 imhtml->show_comments = show; |
4253 | 2095 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2096 |
8456 | 2097 void gtk_imhtml_html_shortcuts (GtkIMHtml *imhtml, |
2098 gboolean allow) | |
2099 { | |
2100 imhtml->html_shortcuts = allow; | |
2101 } | |
2102 | |
2103 void gtk_imhtml_smiley_shortcuts (GtkIMHtml *imhtml, | |
2104 gboolean allow) | |
2105 { | |
2106 imhtml->smiley_shortcuts = allow; | |
2107 } | |
2108 | |
2109 void | |
2110 gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, gchar *protocol_name) { | |
2111 imhtml->protocol_name = protocol_name; | |
2112 } | |
2113 | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2114 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2115 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2116 { |
7991 | 2117 GList *del; |
3922 | 2118 GtkTextIter start, end; |
8427 | 2119 GObject *object = g_object_ref(G_OBJECT(imhtml)); |
7991 | 2120 |
3922 | 2121 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2122 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2123 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
7991 | 2124 |
8061 | 2125 for(del = imhtml->format_spans; del; del = del->next) { |
2126 GtkIMHtmlFormatSpan *span = del->data; | |
2127 if (span->start_tag) | |
2128 g_free(span->start_tag); | |
2129 if (span->end_tag) | |
2130 g_free(span->end_tag); | |
2131 g_free(span); | |
2132 } | |
2133 g_list_free(imhtml->format_spans); | |
2134 imhtml->format_spans = NULL; | |
2135 | |
7991 | 2136 for(del = imhtml->scalables; del; del = del->next) { |
2137 GtkIMHtmlScalable *scale = del->data; | |
2138 scale->free(scale); | |
2139 } | |
2140 g_list_free(imhtml->scalables); | |
2141 imhtml->scalables = NULL; | |
8061 | 2142 |
2143 imhtml->edit.bold = NULL; | |
2144 imhtml->edit.italic = NULL; | |
2145 imhtml->edit.underline = NULL; | |
2146 imhtml->edit.fontface = NULL; | |
2147 imhtml->edit.forecolor = NULL; | |
2148 imhtml->edit.backcolor = NULL; | |
2149 imhtml->edit.sizespan = NULL; | |
2150 imhtml->edit.fontsize = 3; | |
8481 | 2151 |
8427 | 2152 g_signal_emit(object, signals[CLEAR_FORMAT], 0); |
2153 g_object_unref(object); | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2154 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
2155 |
4046 | 2156 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
2157 { | |
5282 | 2158 GdkRectangle rect; |
2159 GtkTextIter iter; | |
4046 | 2160 |
5282 | 2161 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
2162 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2163 rect.y - rect.height); | |
2164 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
8061 | 2165 |
4046 | 2166 } |
5282 | 2167 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
2168 { | |
2169 GdkRectangle rect; | |
2170 GtkTextIter iter; | |
2171 | |
2172 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
2173 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2174 rect.y + rect.height); | |
2175 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
2176 } | |
4735 | 2177 |
5967 | 2178 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
6982 | 2179 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename) |
4735 | 2180 { |
5967 | 2181 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 2182 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 2183 |
5967 | 2184 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
2185 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
2186 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 2187 |
2188 im_image->pixbuf = img; | |
5012 | 2189 im_image->image = image; |
4895 | 2190 im_image->width = gdk_pixbuf_get_width(img); |
2191 im_image->height = gdk_pixbuf_get_height(img); | |
2192 im_image->mark = NULL; | |
6982 | 2193 im_image->filename = filename ? g_strdup(filename) : NULL; |
4895 | 2194 |
5046 | 2195 g_object_ref(img); |
4895 | 2196 return GTK_IMHTML_SCALABLE(im_image); |
2197 } | |
2198 | |
5967 | 2199 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 2200 { |
5967 | 2201 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 2202 |
2203 if(image->width > width || image->height > height){ | |
2204 GdkPixbuf *new_image = NULL; | |
2205 float factor; | |
2206 int new_width = image->width, new_height = image->height; | |
2207 | |
2208 if(image->width > width){ | |
2209 factor = (float)(width)/image->width; | |
2210 new_width = width; | |
2211 new_height = image->height * factor; | |
2212 } | |
2213 if(new_height > height){ | |
2214 factor = (float)(height)/new_height; | |
2215 new_height = height; | |
2216 new_width = new_width * factor; | |
2217 } | |
2218 | |
5046 | 2219 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 2220 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 2221 g_object_unref(G_OBJECT(new_image)); |
2222 } | |
2223 } | |
2224 | |
5012 | 2225 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) |
2226 { | |
2227 const gchar *filename = gtk_file_selection_get_filename(sel); | |
5967 | 2228 gchar *dirname; |
2229 GtkIMHtmlImage *image = g_object_get_data(G_OBJECT(sel), "GtkIMHtmlImage"); | |
5012 | 2230 gchar *type = NULL; |
5019 | 2231 GError *error = NULL; |
5015 | 2232 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 2233 GSList *formats = gdk_pixbuf_get_formats(); |
6162 | 2234 #else |
2235 char *basename = g_path_get_basename(filename); | |
2236 char *ext = strrchr(basename, '.'); | |
5959 | 2237 #endif |
5012 | 2238 |
5967 | 2239 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { |
2240 /* append a / if needed */ | |
2241 if (filename[strlen(filename) - 1] != '/') { | |
2242 dirname = g_strconcat(filename, "/", NULL); | |
2243 } else { | |
2244 dirname = g_strdup(filename); | |
2245 } | |
2246 gtk_file_selection_set_filename(sel, dirname); | |
2247 g_free(dirname); | |
5959 | 2248 return; |
5967 | 2249 } |
5959 | 2250 |
2251 #if GTK_CHECK_VERSION(2,2,0) | |
5012 | 2252 while(formats){ |
2253 GdkPixbufFormat *format = formats->data; | |
2254 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
2255 gpointer p = extensions; | |
2256 | |
2257 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
2258 gchar *fmt_ext = extensions[0]; | |
2259 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
2260 | |
2261 if(!strcmp(fmt_ext, file_ext)){ | |
2262 type = gdk_pixbuf_format_get_name(format); | |
2263 break; | |
2264 } | |
2265 | |
2266 extensions++; | |
2267 } | |
2268 | |
2269 g_strfreev(p); | |
2270 | |
2271 if(type) | |
2272 break; | |
2273 | |
2274 formats = formats->next; | |
2275 } | |
2276 | |
5020 | 2277 g_slist_free(formats); |
2278 #else | |
2279 /* this is really ugly code, but I think it will work */ | |
2280 if(ext) { | |
2281 ext++; | |
2282 if(!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) | |
2283 type = g_strdup("jpeg"); | |
2284 else if(!g_ascii_strcasecmp(ext, "png")) | |
2285 type = g_strdup("png"); | |
2286 } | |
2287 | |
2288 g_free(basename); | |
2289 #endif | |
2290 | |
5012 | 2291 /* If I can't find a valid type, I will just tell the user about it and then assume |
2292 it's a png */ | |
2293 if(!type){ | |
2294 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
5967 | 2295 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
5012 | 2296 type = g_strdup("png"); |
2297 } | |
2298 | |
5046 | 2299 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 2300 |
2301 if(error){ | |
2302 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
2303 _("Error saving image: %s"), error->message); | |
2304 g_error_free(error); | |
2305 } | |
2306 | |
2307 g_free(type); | |
2308 } | |
2309 | |
5967 | 2310 static void gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) |
5012 | 2311 { |
5967 | 2312 GtkWidget *sel = gtk_file_selection_new(_("Save Image")); |
5012 | 2313 |
6982 | 2314 if (image->filename) |
2315 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); | |
5967 | 2316 g_object_set_data(G_OBJECT(sel), "GtkIMHtmlImage", image); |
5012 | 2317 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
2318 G_CALLBACK(write_img_to_file), sel); | |
2319 | |
2320 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | |
2321 G_CALLBACK(gtk_widget_destroy), sel); | |
2322 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", | |
8061 | 2323 G_CALLBACK(gtk_widget_destroy), sel); |
5012 | 2324 |
2325 gtk_widget_show(sel); | |
2326 } | |
2327 | |
5967 | 2328 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 2329 { |
2330 GdkEventButton *event_button = (GdkEventButton *) event; | |
2331 | |
2332 if (event->type == GDK_BUTTON_RELEASE) { | |
2333 if(event_button->button == 3) { | |
2334 GtkWidget *img, *item, *menu; | |
2335 gchar *text = g_strdup_printf(_("_Save Image...")); | |
2336 menu = gtk_menu_new(); | |
2337 | |
2338 /* buttons and such */ | |
2339 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
2340 item = gtk_image_menu_item_new_with_mnemonic(text); | |
2341 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 2342 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 2343 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
2344 | |
2345 gtk_widget_show_all(menu); | |
2346 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
2347 event_button->button, event_button->time); | |
2348 | |
2349 g_free(text); | |
2350 return TRUE; | |
2351 } | |
2352 } | |
2353 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
2354 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
2355 be caught by the regular GtkTextView menu */ | |
2356 else | |
2357 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
2358 | |
2359 } | |
5967 | 2360 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
2361 { | |
2362 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2363 | |
2364 g_object_unref(image->pixbuf); | |
6982 | 2365 if (image->filename) |
2366 g_free(image->filename); | |
5967 | 2367 g_free(scale); |
2368 } | |
2369 | |
2370 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2371 { | |
2372 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2373 GtkWidget *box = gtk_event_box_new(); | |
2374 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
2375 | |
2376 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
2377 | |
2378 gtk_widget_show(GTK_WIDGET(image->image)); | |
2379 gtk_widget_show(box); | |
2380 | |
2381 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); | |
2382 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
2383 } | |
2384 | |
2385 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
2386 { | |
2387 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
2388 | |
2389 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
2390 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
2391 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
2392 | |
2393 hr->sep = gtk_hseparator_new(); | |
2394 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
2395 gtk_widget_show(hr->sep); | |
2396 | |
2397 return GTK_IMHTML_SCALABLE(hr); | |
2398 } | |
2399 | |
2400 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
2401 { | |
2402 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width, 2); | |
2403 } | |
2404 | |
2405 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2406 { | |
2407 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
2408 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
8061 | 2409 g_object_set_data(G_OBJECT(anchor), "text_tag", "<hr>"); |
5967 | 2410 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); |
2411 } | |
2412 | |
2413 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
2414 { | |
2415 g_free(scale); | |
2416 } | |
7295 | 2417 |
2418 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
2419 { | |
2420 GtkTextIter iter, start, end; | |
2421 gboolean new_search = TRUE; | |
2422 | |
2423 g_return_val_if_fail(imhtml != NULL, FALSE); | |
2424 g_return_val_if_fail(text != NULL, FALSE); | |
8061 | 2425 |
7295 | 2426 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) |
2427 new_search = FALSE; | |
8061 | 2428 |
7295 | 2429 if (new_search) { |
2430 gtk_imhtml_search_clear(imhtml); | |
2431 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
2432 } else { | |
2433 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
8061 | 2434 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); |
7295 | 2435 } |
2436 imhtml->search_string = g_strdup(text); | |
2437 | |
7358 | 2438 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
2439 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 2440 &start, &end, NULL)) { |
2441 | |
2442 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
2443 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
2444 if (new_search) { | |
2445 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
8061 | 2446 do |
7295 | 2447 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); |
8061 | 2448 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
2449 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
7358 | 2450 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, |
7295 | 2451 &start, &end, NULL)); |
2452 } | |
2453 return TRUE; | |
2454 } | |
8061 | 2455 |
2456 gtk_imhtml_search_clear(imhtml); | |
2457 | |
7295 | 2458 return FALSE; |
2459 } | |
2460 | |
2461 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
2462 { | |
2463 GtkTextIter start, end; | |
8061 | 2464 |
7295 | 2465 g_return_if_fail(imhtml != NULL); |
8061 | 2466 |
7295 | 2467 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2468 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2469 | |
2470 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
2471 if (imhtml->search_string) | |
2472 g_free(imhtml->search_string); | |
2473 imhtml->search_string = NULL; | |
2474 } | |
8061 | 2475 |
2476 /* Editable stuff */ | |
2477 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
2478 { | |
2479 GtkIMHtmlFormatSpan *span = NULL; | |
2480 GtkTextIter end; | |
2481 | |
2482 gtk_text_iter_forward_chars(iter, len); | |
2483 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2484 gtk_text_iter_forward_char(&end); | |
2485 | |
2486 if (!gtk_text_iter_equal(&end, iter)) | |
2487 return; | |
2488 | |
2489 | |
2490 if ((span = imhtml->edit.bold)) { | |
2491 GtkTextIter bold; | |
2492 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &bold, span->start); | |
2493 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &bold, iter); | |
2494 } | |
2495 | |
2496 if ((span = imhtml->edit.italic)) { | |
2497 GtkTextIter italic; | |
2498 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &italic, span->start); | |
2499 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &italic, | |
2500 iter); | |
2501 } | |
2502 | |
2503 if ((span = imhtml->edit.underline)) { | |
2504 GtkTextIter underline; | |
2505 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &underline, span->start); | |
2506 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &underline, | |
2507 iter); | |
2508 } | |
2509 | |
2510 if ((span = imhtml->edit.forecolor)) { | |
2511 GtkTextIter fore; | |
2512 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &fore, span->start); | |
2513 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &fore, iter); | |
2514 } | |
2515 | |
2516 if ((span = imhtml->edit.backcolor)) { | |
2517 GtkTextIter back; | |
2518 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &back, span->start); | |
2519 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &back, iter); | |
2520 } | |
2521 | |
2522 if ((span = imhtml->edit.fontface)) { | |
2523 GtkTextIter face; | |
2524 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &face, span->start); | |
2525 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &face, iter); | |
2526 } | |
2527 | |
2528 if ((span = imhtml->edit.sizespan)) { | |
2529 GtkTextIter size; | |
2530 /* We create the tags here so that one can grow font or shrink font several times | |
2531 * in a row without creating unnecessary tags */ | |
2532 if (span->tag == NULL) { | |
2533 span->tag = gtk_text_buffer_create_tag | |
8309 | 2534 (imhtml->text_buffer, NULL, "scale", (double)_point_sizes [imhtml->edit.fontsize-1], NULL); |
8061 | 2535 span->start_tag = g_strdup_printf("<font size=\"%d\">", imhtml->edit.fontsize); |
2536 span->end_tag = g_strdup("</font>"); | |
2537 } | |
2538 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &size, span->start); | |
2539 gtk_text_buffer_apply_tag(imhtml->text_buffer, span->tag, &size, iter); | |
2540 } | |
2541 } | |
2542 | |
2543 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
2544 { | |
2545 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
8177 | 2546 /* |
2547 * We need a visible caret for accessibility, so mouseless | |
2548 * people can highlight stuff. | |
2549 */ | |
2550 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ | |
8061 | 2551 imhtml->editable = editable; |
8420 | 2552 imhtml->format_functions = !editable ? 0 : -1; |
2553 } | |
2554 | |
2555 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) | |
2556 { | |
2557 GObject *object = g_object_ref(G_OBJECT(imhtml)); | |
2558 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); | |
2559 imhtml->format_functions = buttons; | |
2560 g_object_unref(object); | |
8061 | 2561 } |
2562 | |
8516 | 2563 static gboolean |
2564 gtk_imhtml_has_open_tags(GtkIMHtml *imhtml) { | |
2565 if(imhtml->edit.bold && imhtml->edit.bold->end == NULL) | |
2566 return TRUE; | |
2567 | |
2568 if(imhtml->edit.italic && imhtml->edit.italic->end == NULL) | |
2569 return TRUE; | |
2570 | |
2571 if(imhtml->edit.underline && imhtml->edit.underline->end == NULL) | |
2572 return TRUE; | |
2573 | |
2574 if(imhtml->edit.forecolor && imhtml->edit.forecolor->end == NULL) | |
2575 return TRUE; | |
2576 | |
2577 if(imhtml->edit.backcolor && imhtml->edit.backcolor->end == NULL) | |
2578 return TRUE; | |
2579 | |
2580 if(imhtml->edit.fontface && imhtml->edit.fontface->end == NULL) | |
2581 return TRUE; | |
2582 | |
2583 if(imhtml->edit.sizespan && imhtml->edit.sizespan->end == NULL) | |
2584 return TRUE; | |
2585 | |
2586 return FALSE; | |
2587 } | |
2588 | |
2589 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, | |
2590 gboolean *italic, gboolean *underline) | |
8481 | 2591 { |
2592 GtkTextMark *ins_mark; | |
8516 | 2593 GtkTextIter ins_iter; |
8481 | 2594 GSList *tags; |
8516 | 2595 |
8481 | 2596 ins_mark = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2597 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins_iter, ins_mark); | |
8516 | 2598 |
2599 if(gtk_imhtml_has_open_tags(imhtml)) { | |
2600 GtkTextIter end_iter; | |
2601 gint position, length; | |
2602 | |
2603 position = gtk_text_iter_get_offset(&ins_iter); | |
2604 | |
2605 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end_iter); | |
2606 length = gtk_text_iter_get_offset(&end_iter); | |
2607 | |
2608 if(position == length) | |
2609 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins_iter, | |
2610 length - 1); | |
8481 | 2611 } |
8516 | 2612 |
2613 for(tags = gtk_text_iter_get_tags(&ins_iter); | |
8481 | 2614 tags != NULL; tags = tags->next) |
2615 { | |
2616 GtkTextTag *tag = GTK_TEXT_TAG(tags->data); | |
2617 if(tag->name) { | |
2618 if(g_ascii_strcasecmp(tag->name, "BOLD") == 0) | |
2619 (*bold) = TRUE; | |
2620 if(g_ascii_strcasecmp(tag->name, "ITALICS") == 0) | |
2621 (*italic) = TRUE; | |
2622 if(g_ascii_strcasecmp(tag->name, "UNDERLINE") == 0) | |
2623 (*underline) = TRUE; | |
2624 } | |
2625 } | |
2626 } | |
2627 | |
8061 | 2628 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) |
2629 { | |
2630 return imhtml->editable; | |
2631 } | |
2632 | |
2633 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) | |
2634 { | |
2635 GtkIMHtmlFormatSpan *span; | |
8481 | 2636 GObject *object; |
8061 | 2637 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2638 GtkTextIter iter; | |
8481 | 2639 |
8061 | 2640 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); |
8481 | 2641 |
8061 | 2642 if (!imhtml->edit.bold) { |
8481 | 2643 span = g_new0(GtkIMHtmlFormatSpan, 1); |
8061 | 2644 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2645 span->start_tag = g_strdup("<b>"); | |
2646 span->end = NULL; | |
2647 span->end_tag = g_strdup("</b>"); | |
2648 span->buffer = imhtml->text_buffer; | |
8481 | 2649 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "BOLD"); |
8061 | 2650 imhtml->edit.bold = span; |
2651 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2652 } else { | |
8428 | 2653 GtkTextIter start; |
8061 | 2654 span = imhtml->edit.bold; |
2655 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
8428 | 2656 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, span->start); |
2657 if (gtk_text_iter_equal(&start, &iter)) { /* Format turned off before any text was entered, so remove the tag */ | |
2658 imhtml->format_spans = g_list_remove(imhtml->format_spans, span); | |
2659 if (span->start_tag) | |
2660 g_free(span->start_tag); | |
2661 if (span->end_tag) | |
2662 g_free(span->end_tag); | |
2663 g_free(span); | |
2664 } | |
8061 | 2665 imhtml->edit.bold = NULL; |
2666 } | |
8481 | 2667 |
2668 object = g_object_ref(G_OBJECT(imhtml)); | |
2669 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BOLD); | |
2670 g_object_unref(object); | |
2671 | |
2672 return (imhtml->edit.bold != NULL); | |
8061 | 2673 } |
2674 | |
2675 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
2676 { | |
2677 GtkIMHtmlFormatSpan *span; | |
8481 | 2678 GObject *object; |
8061 | 2679 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2680 GtkTextIter iter; | |
8481 | 2681 |
8061 | 2682 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); |
8481 | 2683 |
8061 | 2684 if (!imhtml->edit.italic) { |
8481 | 2685 span = g_new0(GtkIMHtmlFormatSpan, 1); |
8061 | 2686 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2687 span->start_tag = g_strdup("<i>"); | |
2688 span->end = NULL; | |
2689 span->end_tag = g_strdup("</i>"); | |
2690 span->buffer = imhtml->text_buffer; | |
2691 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "ITALIC"); | |
2692 imhtml->edit.italic = span; | |
2693 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2694 } else { | |
8428 | 2695 GtkTextIter start; |
8061 | 2696 span = imhtml->edit.italic; |
2697 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
8428 | 2698 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, span->start); |
2699 if (gtk_text_iter_equal(&start, &iter)) { /* Format turned off before any text was entered, so remove the tag */ | |
2700 imhtml->format_spans = g_list_remove(imhtml->format_spans, span); | |
2701 if (span->start_tag) | |
2702 g_free(span->start_tag); | |
2703 if (span->end_tag) | |
2704 g_free(span->end_tag); | |
2705 g_free(span); | |
2706 } | |
8061 | 2707 imhtml->edit.italic = NULL; |
2708 } | |
8481 | 2709 |
2710 object = g_object_ref(G_OBJECT(imhtml)); | |
2711 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_ITALIC); | |
2712 g_object_unref(object); | |
2713 | |
8061 | 2714 return imhtml->edit.italic != NULL; |
2715 } | |
2716 | |
2717 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) | |
2718 { | |
2719 GtkIMHtmlFormatSpan *span; | |
8481 | 2720 GObject *object; |
8061 | 2721 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); |
2722 GtkTextIter iter; | |
8481 | 2723 |
8061 | 2724 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); |
8481 | 2725 |
8061 | 2726 if (!imhtml->edit.underline) { |
8481 | 2727 span = g_new0(GtkIMHtmlFormatSpan, 1); |
8061 | 2728 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2729 span->start_tag = g_strdup("<u>"); | |
2730 span->end = NULL; | |
2731 span->end_tag = g_strdup("</u>"); | |
2732 span->buffer = imhtml->text_buffer; | |
2733 span->tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "UNDERLINE"); | |
2734 imhtml->edit.underline = span; | |
2735 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2736 } else { | |
8428 | 2737 GtkTextIter start; |
8061 | 2738 span = imhtml->edit.underline; |
2739 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
8428 | 2740 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, span->start); |
2741 if (gtk_text_iter_equal(&start, &iter)) { /* Format turned off before any text was entered, so remove the tag */ | |
2742 imhtml->format_spans = g_list_remove(imhtml->format_spans, span); | |
2743 if (span->start_tag) | |
2744 g_free(span->start_tag); | |
2745 if (span->end_tag) | |
2746 g_free(span->end_tag); | |
2747 g_free(span); | |
2748 } | |
8061 | 2749 imhtml->edit.underline = NULL; |
2750 } | |
8481 | 2751 |
2752 object = g_object_ref(G_OBJECT(imhtml)); | |
2753 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_UNDERLINE); | |
2754 g_object_unref(object); | |
2755 | |
8061 | 2756 return imhtml->edit.underline != NULL; |
2757 } | |
2758 | |
2759 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) | |
2760 { | |
2761 GtkIMHtmlFormatSpan *span; | |
2762 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2763 GtkTextIter iter; | |
2764 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2765 | |
2766 imhtml->edit.fontsize = size; | |
2767 | |
2768 if (imhtml->edit.sizespan) { | |
2769 GtkTextIter iter2; | |
2770 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); | |
2771 if (gtk_text_iter_equal(&iter2, &iter)) | |
2772 return; | |
2773 span = imhtml->edit.sizespan; | |
2774 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2775 } | |
2776 if (size != -1) { | |
8250 | 2777 span = g_malloc0(sizeof(GtkIMHtmlFormatSpan)); |
8061 | 2778 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2779 span->end = NULL; | |
2780 span->buffer = imhtml->text_buffer; | |
2781 span->tag = NULL; | |
2782 imhtml->edit.sizespan = span; | |
2783 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2784 } | |
2785 } | |
2786 | |
2787 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) | |
2788 { | |
2789 GtkIMHtmlFormatSpan *span; | |
2790 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2791 GtkTextIter iter; | |
2792 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2793 if (imhtml->edit.fontsize == 1) | |
2794 return; | |
2795 | |
2796 imhtml->edit.fontsize--; | |
2797 | |
2798 if (imhtml->edit.sizespan) { | |
2799 GtkTextIter iter2; | |
2800 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); | |
2801 if (gtk_text_iter_equal(&iter2, &iter)) | |
2802 return; | |
2803 span = imhtml->edit.sizespan; | |
2804 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2805 } | |
2806 | |
8250 | 2807 span = g_malloc0(sizeof(GtkIMHtmlFormatSpan)); |
8061 | 2808 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2809 span->end = NULL; | |
2810 span->buffer = imhtml->text_buffer; | |
2811 span->tag = NULL; | |
2812 imhtml->edit.sizespan = span; | |
2813 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2814 } | |
2815 | |
2816 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) | |
2817 { | |
2818 GtkIMHtmlFormatSpan *span; | |
2819 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2820 GtkTextIter iter; | |
2821 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
2822 if (imhtml->edit.fontsize == MAX_FONT_SIZE) | |
2823 return; | |
2824 | |
2825 imhtml->edit.fontsize++; | |
2826 if (imhtml->edit.sizespan) { | |
2827 GtkTextIter iter2; | |
2828 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter2, imhtml->edit.sizespan->start); | |
2829 if (gtk_text_iter_equal(&iter2, &iter)) | |
2830 return; | |
2831 span = imhtml->edit.sizespan; | |
2832 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2833 } | |
2834 | |
8250 | 2835 span = g_malloc0(sizeof(GtkIMHtmlFormatSpan)); |
8061 | 2836 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); |
2837 span->end = NULL; | |
2838 span->tag = NULL; | |
2839 span->buffer = imhtml->text_buffer; | |
2840 imhtml->edit.sizespan = span; | |
2841 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2842 } | |
2843 | |
2844 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) | |
2845 { | |
2846 GtkIMHtmlFormatSpan *span; | |
2847 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2848 GtkTextIter iter; | |
2849 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
8429 | 2850 if (color) { |
8061 | 2851 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); |
2852 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2853 span->start_tag = g_strdup_printf("<font color=\"%s\">", color); | |
2854 span->end = NULL; | |
2855 span->end_tag = g_strdup("</font>"); | |
2856 span->buffer = imhtml->text_buffer; | |
2857 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "foreground", color, NULL); | |
2858 imhtml->edit.forecolor = span; | |
2859 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2860 } else { | |
2861 span = imhtml->edit.forecolor; | |
2862 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2863 imhtml->edit.forecolor = NULL; | |
2864 } | |
2865 | |
2866 | |
2867 return imhtml->edit.forecolor != NULL; | |
2868 } | |
2869 | |
2870 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
2871 { | |
2872 GtkIMHtmlFormatSpan *span; | |
2873 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2874 GtkTextIter iter; | |
2875 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
8429 | 2876 if (color) { |
8061 | 2877 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); |
2878 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2879 span->start_tag = g_strdup_printf("<font back=\"%s\">", color); | |
2880 span->end = NULL; | |
2881 span->end_tag = g_strdup("</font>"); | |
2882 span->buffer = imhtml->text_buffer; | |
2883 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "background", color, NULL); | |
2884 imhtml->edit.backcolor = span; | |
2885 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2886 } else { | |
2887 span = imhtml->edit.backcolor; | |
2888 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2889 imhtml->edit.backcolor = NULL; | |
2890 } | |
2891 return imhtml->edit.backcolor != NULL; | |
2892 } | |
2893 | |
2894 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) | |
2895 { | |
2896 GtkIMHtmlFormatSpan *span; | |
2897 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2898 GtkTextIter iter; | |
2899 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); | |
8429 | 2900 if (face) { |
8061 | 2901 span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); |
2902 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2903 span->start_tag = g_strdup_printf("<font face=\"%s\">", face); | |
2904 span->end = NULL; | |
2905 span->end_tag = g_strdup("</font>"); | |
2906 span->buffer = imhtml->text_buffer; | |
2907 span->tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, "family", face, NULL); | |
2908 imhtml->edit.fontface = span; | |
2909 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2910 } else { | |
2911 span = imhtml->edit.fontface; | |
2912 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2913 imhtml->edit.fontface = NULL; | |
2914 } | |
2915 return imhtml->edit.fontface != NULL; | |
2916 } | |
2917 | |
2918 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, const char *url, const char *text) | |
2919 { | |
2920 GtkIMHtmlFormatSpan *span = g_malloc(sizeof(GtkIMHtmlFormatSpan)); | |
2921 GtkTextMark *mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2922 GtkTextIter iter; | |
2923 GtkTextTag *tag, *linktag; | |
2924 | |
2925 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, NULL, NULL); | |
2926 g_object_set_data(G_OBJECT(tag), "link_url", g_strdup(url)); | |
2927 | |
2928 linktag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), "LINK"); | |
2929 | |
2930 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
2931 span->start = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2932 span->buffer = imhtml->text_buffer; | |
2933 span->start_tag = g_strdup_printf("<a href=\"%s\">", url); | |
2934 span->end_tag = g_strdup("</a>"); | |
2935 g_signal_connect(G_OBJECT(tag), "event", G_CALLBACK(tag_event), g_strdup(url)); | |
2936 | |
2937 gtk_text_buffer_insert_with_tags(imhtml->text_buffer, &iter, text, strlen(text), linktag, tag, NULL); | |
2938 span->end = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, TRUE); | |
2939 imhtml->format_spans = g_list_append(imhtml->format_spans, span); | |
2940 } | |
2941 | |
2942 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) | |
2943 { | |
2944 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
2945 GtkTextIter iter; | |
2946 GdkPixbuf *pixbuf = NULL; | |
2947 GdkPixbufAnimation *annipixbuf = NULL; | |
2948 GtkWidget *icon = NULL; | |
2949 GtkTextChildAnchor *anchor; | |
8505 | 2950 char *unescaped = gaim_unescape_html(smiley); |
8061 | 2951 |
8515 | 2952 if (!imhtml->show_smileys) { |
2953 gtk_text_buffer_insert_at_cursor(imhtml->text_buffer, smiley, strlen(smiley)); | |
2954 return; | |
2955 } | |
2956 | |
8061 | 2957 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, ins); |
2958 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, &iter); | |
8505 | 2959 g_object_set_data(G_OBJECT(anchor), "text_tag", unescaped); |
2960 | |
2961 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); | |
8061 | 2962 if(annipixbuf) { |
2963 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
2964 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
2965 if(pixbuf) | |
2966 icon = gtk_image_new_from_pixbuf(pixbuf); | |
2967 } else { | |
2968 icon = gtk_image_new_from_animation(annipixbuf); | |
2969 } | |
2970 } | |
2971 | |
2972 if (icon) { | |
2973 gtk_widget_show(icon); | |
2974 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
2975 } | |
2976 } | |
2977 | |
2978 int span_compare_begin(const GtkIMHtmlFormatSpan *a, const GtkIMHtmlFormatSpan *b, GtkTextBuffer *buffer) | |
2979 { | |
2980 GtkTextIter ia, ib; | |
2981 gtk_text_buffer_get_iter_at_mark(buffer, &ia, a->start); | |
2982 gtk_text_buffer_get_iter_at_mark(buffer, &ib, b->start); | |
2983 return gtk_text_iter_compare(&ia, &ib); | |
2984 } | |
2985 | |
2986 int span_compare_end(GtkIMHtmlFormatSpan *a, GtkIMHtmlFormatSpan *b) | |
2987 { | |
2988 GtkTextIter ia, ib; | |
2989 gtk_text_buffer_get_iter_at_mark(a->buffer, &ia, a->start); | |
2990 gtk_text_buffer_get_iter_at_mark(b->buffer, &ib, b->start); | |
2991 /* The -1 here makes it so that if I have two spans that close at the same point, the | |
2992 * span added second will be closed first, as in <b><i>Hello</i></b>. Without this, | |
2993 * it would be <b><i>Hello</b></i> */ | |
2994 return gtk_text_iter_compare(&ia, &ib) - 1; | |
2995 } | |
2996 | |
2997 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
2998 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
2999 * check the list of formatted strings, sorted by the position of the starting tags and apply them as | |
3000 * needed. After applying the start tags, add the end tags to the "closers" list, which is sorted by | |
3001 * location of ending tags. These get applied in a similar fashion. Finally, replace <, >, &, and " | |
3002 * with their HTML equivilent. */ | |
3003 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) | |
3004 { | |
3005 gunichar c; | |
3006 GtkIMHtmlFormatSpan *sspan = NULL, *espan = NULL; | |
3007 GtkTextIter iter, siter, eiter; | |
3008 GList *starters = imhtml->format_spans; | |
3009 GList *closers = NULL; | |
3010 GString *str = g_string_new(""); | |
8481 | 3011 |
8061 | 3012 g_list_sort_with_data(starters, (GCompareDataFunc)span_compare_begin, imhtml->text_buffer); |
3013 | |
3014 gtk_text_iter_order(start, end); | |
3015 iter = *start; | |
3016 | |
3017 | |
3018 /* Initialize these to the end iter */ | |
3019 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); | |
3020 eiter = siter; | |
3021 | |
8429 | 3022 if (starters) { |
8061 | 3023 while (starters) { |
3024 GtkTextIter tagend; | |
3025 sspan = (GtkIMHtmlFormatSpan*)starters->data; | |
3026 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); | |
3027 if (gtk_text_iter_compare(&siter, start) > 0) | |
3028 break; | |
3029 if (sspan->end) | |
3030 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &tagend, sspan->end); | |
3031 if (sspan->end == NULL || gtk_text_iter_compare(&tagend, start) > 0) { | |
3032 str = g_string_append(str, sspan->start_tag); | |
3033 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end); | |
3034 espan = (GtkIMHtmlFormatSpan*)closers->data; | |
8365 | 3035 /* |
3036 * When sending an IM, the following line causes the following warning: | |
3037 * Gtk: file gtktextbuffer.c: line 1794 | |
3038 * (gtk_text_buffer_get_iter_at_mark): assertion `GTK_IS_TEXT_MARK (mark)' failed | |
3039 * | |
3040 * The callback path thingy to get here is: | |
3041 * gtkconv.c, send(), "buf = gtk_imhtml_get_markup(GTK_IMHTML(gtkconv->entry));" | |
3042 * gtkimhtml.c, gtk_imthml_get_markup(), "return gtk_imhtml_get_markup_range(imhtml, &start, &end);" | |
3043 * | |
3044 * I don't really know anything about gtkimhtml, but it almost seems like | |
3045 * the line above this comments expects to find a closing html tag, but | |
3046 * can't, for some reason. The warning depends on how much HTML I send | |
3047 * in my message, kind of. | |
3048 */ | |
8481 | 3049 /* comment this out until myself or someone else finishes |
3050 * it. This is supposed to apply a tag to selected text, | |
3051 * i believe... | |
8061 | 3052 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); |
8481 | 3053 */ |
8061 | 3054 } |
3055 sspan = (GtkIMHtmlFormatSpan*)starters->data; | |
3056 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); | |
3057 starters = starters->next; | |
3058 } | |
3059 if (!starters) { | |
3060 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); | |
3061 sspan = NULL; | |
3062 } | |
3063 } | |
3064 | |
3065 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { | |
3066 if (c == 0xFFFC) { | |
3067 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
3068 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); | |
3069 str = g_string_append(str, text); | |
3070 } else { | |
3071 while (gtk_text_iter_equal(&eiter, &iter)) { | |
3072 /* This is where we shall insert the ending tag of | |
3073 * this format span */ | |
3074 str = g_string_append(str, espan->end_tag); | |
3075 closers = g_list_remove(closers, espan); | |
3076 if (!closers) { | |
3077 espan = NULL; | |
3078 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &eiter); | |
3079 } else { | |
3080 espan = (GtkIMHtmlFormatSpan*)closers->data; | |
8429 | 3081 if (espan->end) |
3082 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); | |
3083 else | |
3084 gtk_text_iter_forward_to_end(&eiter); | |
8061 | 3085 } |
3086 } | |
3087 while (gtk_text_iter_equal(&siter, &iter)) { | |
3088 /* This is where we shall insert the starting tag of | |
3089 * this format span */ | |
3090 str = g_string_append(str, sspan->start_tag); | |
3091 if (sspan->end) { | |
3092 closers = g_list_insert_sorted(closers, sspan, (GCompareFunc)span_compare_end); | |
3093 espan = (GtkIMHtmlFormatSpan*)closers->data; | |
3094 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &eiter, espan->end); | |
3095 | |
3096 } | |
3097 starters = starters->next; | |
3098 if (starters) { | |
3099 sspan = (GtkIMHtmlFormatSpan*)starters->data; | |
3100 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &siter, sspan->start); | |
3101 } else { | |
3102 sspan = NULL; | |
3103 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &siter); | |
3104 } | |
3105 | |
3106 } | |
3107 | |
3108 if (c == '<') | |
3109 str = g_string_append(str, "<"); | |
3110 else if (c == '>') | |
3111 str = g_string_append(str, ">"); | |
3112 else if (c == '&') | |
3113 str = g_string_append(str, "&"); | |
3114 else if (c == '"') | |
3115 str = g_string_append(str, """); | |
3116 else if (c == '\n') | |
3117 str = g_string_append(str, "<br>"); | |
3118 else | |
3119 str = g_string_append_unichar(str, c); | |
3120 } | |
3121 gtk_text_iter_forward_char(&iter); | |
3122 } | |
3123 while (closers) { | |
3124 GtkIMHtmlFormatSpan *span = (GtkIMHtmlFormatSpan*)closers->data; | |
3125 str = g_string_append(str, span->end_tag); | |
3126 closers = g_list_remove(closers, span); | |
3127 | |
3128 } | |
3129 return g_string_free(str, FALSE); | |
3130 } | |
3131 | |
3132 void gtk_imhtml_close_tags(GtkIMHtml *imhtml) | |
3133 { | |
3134 | |
3135 if (imhtml->edit.bold) | |
3136 gtk_imhtml_toggle_bold(imhtml); | |
3137 | |
3138 if (imhtml->edit.italic) | |
3139 gtk_imhtml_toggle_italic(imhtml); | |
3140 | |
3141 if (imhtml->edit.underline) | |
3142 gtk_imhtml_toggle_underline(imhtml); | |
3143 | |
3144 if (imhtml->edit.forecolor) | |
3145 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
3146 | |
3147 if (imhtml->edit.backcolor) | |
3148 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
3149 | |
3150 if (imhtml->edit.fontface) | |
3151 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
3152 | |
3153 if (imhtml->edit.sizespan) | |
3154 gtk_imhtml_font_set_size(imhtml, -1); | |
3155 | |
3156 } | |
3157 | |
3158 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
3159 { | |
3160 GtkTextIter start, end; | |
3161 | |
3162 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
3163 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3164 return gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
3165 } | |
3166 | |
3167 char *gtk_imhtml_get_text(GtkIMHtml *imhtml) | |
3168 { | |
8519 | 3169 GString *str = g_string_new(""); |
3170 GtkTextIter iter, end; | |
3171 gunichar c; | |
3172 | |
3173 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
3174 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3175 | |
3176 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { | |
3177 if (c == 0xFFFC) { | |
3178 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
3179 char *text = g_object_get_data(G_OBJECT(anchor), "text_tag"); | |
3180 str = g_string_append(str, text); | |
3181 } else { | |
3182 g_string_append_unichar(str, c); | |
3183 } | |
3184 gtk_text_iter_forward_char(&iter); | |
3185 } | |
3186 | |
3187 return g_string_free(str, FALSE); | |
8061 | 3188 } |