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