Mercurial > pidgin
annotate src/gtkimhtml.c @ 8907:00138e366ef8
[gaim-migrate @ 9677]
" Fixes a few warnings on 64bit machines. Also fixes
yahoo auth on 64bit machines which would have taken me
awhile if marv didn't point me in the right direction.
I've applied to my local 32bit copy and everything
seems to be working fine." --Gary Kramlich
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Sat, 08 May 2004 23:34:30 +0000 |
parents | 6c98b883580a |
children | 87e171358001 |
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 |
8526 | 27 #include "debug.h" |
8091 | 28 #include "util.h" |
1428 | 29 #include "gtkimhtml.h" |
7358 | 30 #include "gtksourceiter.h" |
1428 | 31 #include <gtk/gtk.h> |
4895 | 32 #include <glib/gerror.h> |
4046 | 33 #include <gdk/gdkkeysyms.h> |
1428 | 34 #include <string.h> |
35 #include <ctype.h> | |
36 #include <stdio.h> | |
4629 | 37 #include <stdlib.h> |
1428 | 38 #include <math.h> |
2541
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
39 #ifdef HAVE_LANGINFO_CODESET |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
40 #include <langinfo.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
41 #include <locale.h> |
8229710b343b
[gaim-migrate @ 2554]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2365
diff
changeset
|
42 #endif |
8692 | 43 #ifdef _WIN32 |
44 #include <windows.h> | |
45 #endif | |
1428 | 46 |
4417 | 47 #ifdef ENABLE_NLS |
48 # include <libintl.h> | |
49 # define _(x) gettext(x) | |
50 # ifdef gettext_noop | |
51 # define N_(String) gettext_noop (String) | |
52 # else | |
53 # define N_(String) (String) | |
54 # endif | |
55 #else | |
56 # define N_(String) (String) | |
57 # define _(x) (x) | |
58 #endif | |
59 | |
4735 | 60 #include <pango/pango-font.h> |
61 | |
5105 | 62 /* GTK+ < 2.2.2 hack, see ui.h for details. */ |
63 #ifndef GTK_WRAP_WORD_CHAR | |
64 #define GTK_WRAP_WORD_CHAR GTK_WRAP_WORD | |
65 #endif | |
66 | |
4735 | 67 #define TOOLTIP_TIMEOUT 500 |
68 | |
8786 | 69 /* GTK+ 2.0 hack */ |
70 #if (!GTK_CHECK_VERSION(2,2,0)) | |
71 #define gtk_widget_get_clipboard(x, y) gtk_clipboard_get(y) | |
72 #endif | |
73 | |
8677 | 74 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); |
8061 | 75 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml); |
8505 | 76 static gboolean gtk_imhtml_is_amp_escape (const gchar *string, gchar **replace, gint *length); |
8698 | 77 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter); |
8091 | 78 static void gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml); |
8677 | 79 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml); |
8061 | 80 |
3922 | 81 /* POINT_SIZE converts from AIM font sizes to point sizes. It probably should be redone in such a |
82 * way that it base the sizes off the default font size rather than using arbitrary font sizes. */ | |
83 #define MAX_FONT_SIZE 7 | |
5367 | 84 #define POINT_SIZE(x) (options & GTK_IMHTML_USE_POINTSIZE ? x : _point_sizes [MIN ((x), MAX_FONT_SIZE) - 1]) |
8380 | 85 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
|
86 |
8498 | 87 enum { |
8677 | 88 TARGET_HTML, |
8061 | 89 TARGET_UTF8_STRING, |
90 TARGET_COMPOUND_TEXT, | |
91 TARGET_STRING, | |
92 TARGET_TEXT | |
93 }; | |
94 | |
8091 | 95 enum { |
96 DRAG_URL | |
97 }; | |
98 | |
8420 | 99 enum { |
100 URL_CLICKED, | |
101 BUTTONS_UPDATE, | |
102 TOGGLE_FORMAT, | |
8427 | 103 CLEAR_FORMAT, |
8506 | 104 UPDATE_FORMAT, |
8420 | 105 LAST_SIGNAL |
106 }; | |
107 static guint signals [LAST_SIGNAL] = { 0 }; | |
108 | |
8061 | 109 GtkTargetEntry selection_targets[] = { |
8566 | 110 { "text/html", 0, TARGET_HTML }, |
8061 | 111 { "UTF8_STRING", 0, TARGET_UTF8_STRING }, |
112 { "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT }, | |
113 { "STRING", 0, TARGET_STRING }, | |
114 { "TEXT", 0, TARGET_TEXT}}; | |
115 | |
8091 | 116 GtkTargetEntry link_drag_drop_targets[] = { |
117 {"x-url/ftp", 0, DRAG_URL}, | |
118 {"x-url/http", 0, DRAG_URL}, | |
119 {"text/uri-list", 0, DRAG_URL}, | |
120 {"_NETSCAPE_URL", 0, DRAG_URL}}; | |
121 | |
8692 | 122 #ifdef _WIN32 |
123 /* Win32 clipboard format value, and functions to convert back and | |
124 * forth between HTML and the clipboard format. | |
125 */ | |
126 static UINT win_html_fmt; | |
127 | |
128 static gchar * | |
129 clipboard_win32_to_html(char *clipboard) { | |
8693 | 130 const char *begin, *end; |
8692 | 131 gchar *html; |
132 | |
8693 | 133 begin = strstr(clipboard, "<!--StartFragment"); |
134 while(*begin++ != '>'); | |
8692 | 135 end = strstr(clipboard, "<!--EndFragment"); |
136 html = g_strstrip(g_strndup(begin, (end ? (end - begin) : strlen(begin)))); | |
8707 | 137 return html; |
8692 | 138 } |
139 | |
140 static gchar * | |
141 clipboard_html_to_win32(char *html) { | |
8693 | 142 int length; |
8692 | 143 gchar *ret; |
144 GString *clipboard; | |
145 | |
8693 | 146 if (html == NULL) |
147 return NULL; | |
8692 | 148 |
149 length = strlen(html); | |
150 clipboard = g_string_new ("Version:0.9\r\n"); | |
151 g_string_append(clipboard, "StartHTML:0000000105\r\n"); | |
152 g_string_append(clipboard, g_strdup_printf("EndHTML:%010d\r\n", 143 + length)); | |
153 g_string_append(clipboard, "StartFragment:0000000105\r\n"); | |
154 g_string_append(clipboard, g_strdup_printf("EndFragment:%010d\r\n", 143 + length)); | |
155 g_string_append(clipboard, "<!--StartFragment-->"); | |
156 g_string_append(clipboard, html); | |
157 g_string_append(clipboard, "<!--EndFragment-->"); | |
158 ret = clipboard->str; | |
159 g_string_free(clipboard, FALSE); | |
160 return ret; | |
161 } | |
162 #endif | |
163 | |
4032 | 164 static GtkSmileyTree* |
165 gtk_smiley_tree_new () | |
166 { | |
167 return g_new0 (GtkSmileyTree, 1); | |
168 } | |
169 | |
170 static void | |
171 gtk_smiley_tree_insert (GtkSmileyTree *tree, | |
4263 | 172 GtkIMHtmlSmiley *smiley) |
4032 | 173 { |
174 GtkSmileyTree *t = tree; | |
4263 | 175 const gchar *x = smiley->smile; |
4032 | 176 |
177 if (!strlen (x)) | |
178 return; | |
179 | |
180 while (*x) { | |
181 gchar *pos; | |
182 gint index; | |
183 | |
184 if (!t->values) | |
185 t->values = g_string_new (""); | |
186 | |
187 pos = strchr (t->values->str, *x); | |
188 if (!pos) { | |
189 t->values = g_string_append_c (t->values, *x); | |
190 index = t->values->len - 1; | |
191 t->children = g_realloc (t->children, t->values->len * sizeof (GtkSmileyTree *)); | |
192 t->children [index] = g_new0 (GtkSmileyTree, 1); | |
193 } else | |
7386 | 194 index = GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str); |
8061 | 195 |
4032 | 196 t = t->children [index]; |
8061 | 197 |
4032 | 198 x++; |
199 } | |
8061 | 200 |
4263 | 201 t->image = smiley; |
4032 | 202 } |
4041 | 203 |
4263 | 204 |
4264 | 205 void gtk_smiley_tree_destroy (GtkSmileyTree *tree) |
4032 | 206 { |
207 GSList *list = g_slist_append (NULL, tree); | |
208 | |
209 while (list) { | |
210 GtkSmileyTree *t = list->data; | |
211 gint i; | |
212 list = g_slist_remove(list, t); | |
7384 | 213 if (t && t->values) { |
4032 | 214 for (i = 0; i < t->values->len; i++) |
215 list = g_slist_append (list, t->children [i]); | |
216 g_string_free (t->values, TRUE); | |
217 g_free (t->children); | |
218 } | |
219 g_free (t); | |
220 } | |
221 } | |
222 | |
5967 | 223 static gboolean gtk_size_allocate_cb(GtkIMHtml *widget, GtkAllocation *alloc, gpointer user_data) |
224 { | |
225 GdkRectangle rect; | |
8726 | 226 int xminus; |
5967 | 227 |
228 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(widget), &rect); | |
229 if(widget->old_rect.width != rect.width || widget->old_rect.height != rect.height){ | |
230 GList *iter = GTK_IMHTML(widget)->scalables; | |
231 | |
8726 | 232 xminus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(widget)) + |
233 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(widget)); | |
234 | |
5967 | 235 while(iter){ |
236 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(iter->data); | |
8726 | 237 scale->scale(scale, rect.width - xminus, rect.height); |
5967 | 238 |
239 iter = iter->next; | |
240 } | |
241 } | |
242 | |
243 widget->old_rect = rect; | |
244 return FALSE; | |
245 } | |
246 | |
247 static gint | |
248 gtk_imhtml_tip_paint (GtkIMHtml *imhtml) | |
249 { | |
250 PangoLayout *layout; | |
251 | |
252 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
253 | |
254 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
255 | |
8061 | 256 gtk_paint_flat_box (imhtml->tip_window->style, imhtml->tip_window->window, |
5967 | 257 GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, imhtml->tip_window, |
258 "tooltip", 0, 0, -1, -1); | |
259 | |
260 gtk_paint_layout (imhtml->tip_window->style, imhtml->tip_window->window, GTK_STATE_NORMAL, | |
261 FALSE, NULL, imhtml->tip_window, NULL, 4, 4, layout); | |
262 | |
263 g_object_unref(layout); | |
264 return FALSE; | |
265 } | |
266 | |
267 static gint | |
268 gtk_imhtml_tip (gpointer data) | |
269 { | |
270 GtkIMHtml *imhtml = data; | |
8526 | 271 PangoFontMetrics *font_metrics; |
5967 | 272 PangoLayout *layout; |
8526 | 273 PangoFont *font; |
5967 | 274 |
275 gint gap, x, y, h, w, scr_w, baseline_skip; | |
276 | |
277 g_return_val_if_fail(GTK_IS_IMHTML(imhtml), FALSE); | |
278 | |
279 if (!imhtml->tip || !GTK_WIDGET_DRAWABLE (GTK_WIDGET(imhtml))) { | |
280 imhtml->tip_timer = 0; | |
281 return FALSE; | |
282 } | |
8061 | 283 |
5967 | 284 if (imhtml->tip_window){ |
285 gtk_widget_destroy (imhtml->tip_window); | |
286 imhtml->tip_window = NULL; | |
287 } | |
288 | |
289 imhtml->tip_timer = 0; | |
290 imhtml->tip_window = gtk_window_new (GTK_WINDOW_POPUP); | |
291 gtk_widget_set_app_paintable (imhtml->tip_window, TRUE); | |
292 gtk_window_set_resizable (GTK_WINDOW (imhtml->tip_window), FALSE); | |
293 gtk_widget_set_name (imhtml->tip_window, "gtk-tooltips"); | |
294 g_signal_connect_swapped (G_OBJECT (imhtml->tip_window), "expose_event", | |
295 G_CALLBACK (gtk_imhtml_tip_paint), imhtml); | |
296 | |
297 gtk_widget_ensure_style (imhtml->tip_window); | |
298 layout = gtk_widget_create_pango_layout(imhtml->tip_window, imhtml->tip); | |
8526 | 299 font = pango_context_load_font(pango_layout_get_context(layout), |
300 imhtml->tip_window->style->font_desc); | |
301 | |
302 if (font == NULL) { | |
303 char *tmp = pango_font_description_to_string( | |
304 imhtml->tip_window->style->font_desc); | |
305 | |
306 gaim_debug(GAIM_DEBUG_ERROR, "gtk_imhtml_tip", | |
307 "pango_context_load_font() couldn't load font: '%s'\n", | |
308 tmp); | |
309 g_free(tmp); | |
310 | |
311 return FALSE; | |
312 | |
313 } | |
314 | |
315 font_metrics = pango_font_get_metrics(font, NULL); | |
8309 | 316 |
5967 | 317 |
318 pango_layout_get_pixel_size(layout, &scr_w, NULL); | |
8526 | 319 gap = PANGO_PIXELS((pango_font_metrics_get_ascent(font_metrics) + |
320 pango_font_metrics_get_descent(font_metrics))/ 4); | |
5967 | 321 |
322 if (gap < 2) | |
323 gap = 2; | |
8526 | 324 baseline_skip = PANGO_PIXELS(pango_font_metrics_get_ascent(font_metrics) + |
325 pango_font_metrics_get_descent(font_metrics)); | |
5967 | 326 w = 8 + scr_w; |
327 h = 8 + baseline_skip; | |
328 | |
329 gdk_window_get_pointer (NULL, &x, &y, NULL); | |
330 if (GTK_WIDGET_NO_WINDOW (GTK_WIDGET(imhtml))) | |
331 y += GTK_WIDGET(imhtml)->allocation.y; | |
332 | |
333 scr_w = gdk_screen_width(); | |
334 | |
335 x -= ((w >> 1) + 4); | |
336 | |
337 if ((x + w) > scr_w) | |
338 x -= (x + w) - scr_w; | |
339 else if (x < 0) | |
340 x = 0; | |
341 | |
8526 | 342 y = y + PANGO_PIXELS(pango_font_metrics_get_ascent(font_metrics) + |
343 pango_font_metrics_get_descent(font_metrics)); | |
5967 | 344 |
345 gtk_widget_set_size_request (imhtml->tip_window, w, h); | |
346 gtk_widget_show (imhtml->tip_window); | |
347 gtk_window_move (GTK_WINDOW(imhtml->tip_window), x, y); | |
348 | |
8526 | 349 pango_font_metrics_unref(font_metrics); |
5967 | 350 g_object_unref(layout); |
351 | |
352 return FALSE; | |
353 } | |
354 | |
355 gboolean gtk_motion_event_notify(GtkWidget *imhtml, GdkEventMotion *event, gpointer data) | |
8061 | 356 { |
5967 | 357 GtkTextIter iter; |
358 GdkWindow *win = event->window; | |
359 int x, y; | |
360 char *tip = NULL; | |
361 GSList *tags = NULL, *templist = NULL; | |
362 gdk_window_get_pointer(GTK_WIDGET(imhtml)->window, NULL, NULL, NULL); | |
363 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), GTK_TEXT_WINDOW_WIDGET, | |
364 event->x, event->y, &x, &y); | |
365 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
366 tags = gtk_text_iter_get_tags(&iter); | |
367 | |
368 templist = tags; | |
369 while (templist) { | |
370 GtkTextTag *tag = templist->data; | |
371 tip = g_object_get_data(G_OBJECT(tag), "link_url"); | |
372 if (tip) | |
373 break; | |
374 templist = templist->next; | |
375 } | |
8061 | 376 |
5967 | 377 if (GTK_IMHTML(imhtml)->tip) { |
378 if ((tip == GTK_IMHTML(imhtml)->tip)) { | |
379 return FALSE; | |
380 } | |
381 /* We've left the cell. Remove the timeout and create a new one below */ | |
382 if (GTK_IMHTML(imhtml)->tip_window) { | |
383 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
384 GTK_IMHTML(imhtml)->tip_window = NULL; | |
385 } | |
8061 | 386 if (GTK_IMHTML(imhtml)->editable) |
387 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->text_cursor); | |
388 else | |
389 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 390 if (GTK_IMHTML(imhtml)->tip_timer) |
391 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
392 GTK_IMHTML(imhtml)->tip_timer = 0; | |
393 } | |
8061 | 394 |
5967 | 395 if(tip){ |
8061 | 396 if (!GTK_IMHTML(imhtml)->editable) |
397 gdk_window_set_cursor(win, GTK_IMHTML(imhtml)->hand_cursor); | |
398 GTK_IMHTML(imhtml)->tip_timer = g_timeout_add (TOOLTIP_TIMEOUT, | |
5967 | 399 gtk_imhtml_tip, imhtml); |
400 } | |
8061 | 401 |
5967 | 402 GTK_IMHTML(imhtml)->tip = tip; |
403 g_slist_free(tags); | |
404 return FALSE; | |
405 } | |
406 | |
407 gboolean gtk_leave_event_notify(GtkWidget *imhtml, GdkEventCrossing *event, gpointer data) | |
408 { | |
409 /* when leaving the widget, clear any current & pending tooltips and restore the cursor */ | |
410 if (GTK_IMHTML(imhtml)->tip_window) { | |
411 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
412 GTK_IMHTML(imhtml)->tip_window = NULL; | |
413 } | |
414 if (GTK_IMHTML(imhtml)->tip_timer) { | |
415 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
416 GTK_IMHTML(imhtml)->tip_timer = 0; | |
417 } | |
8061 | 418 if (GTK_IMHTML(imhtml)->editable) |
419 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->text_cursor); | |
420 else | |
421 gdk_window_set_cursor(event->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
5967 | 422 |
8568 | 423 /* propagate the event normally */ |
5967 | 424 return FALSE; |
425 } | |
426 | |
6066 | 427 /* |
428 * XXX - This should be removed eventually. | |
429 * | |
8061 | 430 * This function exists to work around a gross bug in GtkTextView. |
431 * Basically, we short circuit ctrl+a and ctrl+end because they make | |
6066 | 432 * el program go boom. |
433 * | |
8061 | 434 * It's supposed to be fixed in gtk2.2. You can view the bug report at |
6066 | 435 * http://bugzilla.gnome.org/show_bug.cgi?id=107939 |
436 */ | |
8317 | 437 |
438 /* | |
439 * I'm adding some keyboard shortcuts too. | |
440 */ | |
441 | |
442 gboolean gtk_key_pressed_cb(GtkIMHtml *imhtml, GdkEventKey *event, gpointer data) | |
8677 | 443 { |
8317 | 444 char buf[7]; |
445 buf[0] = '\0'; | |
446 | |
6066 | 447 if (event->state & GDK_CONTROL_MASK) |
448 switch (event->keyval) { | |
8539 | 449 #if (!GTK_CHECK_VERSION(2,2,0)) |
8317 | 450 case 'a': |
451 return TRUE; | |
452 break; | |
8677 | 453 |
8317 | 454 case GDK_Home: |
455 return TRUE; | |
456 break; | |
457 | |
458 case GDK_End: | |
459 return TRUE; | |
460 break; | |
8758 | 461 #endif /* !(Gtk+ >= 2.2.0) */ |
8317 | 462 |
463 case 'b': /* ctrl-b is GDK_Left, which moves backwards. */ | |
464 case 'B': | |
8420 | 465 if (imhtml->format_functions & GTK_IMHTML_BOLD) { |
8456 | 466 if(imhtml->html_shortcuts) { |
467 gtk_imhtml_toggle_bold(imhtml); | |
8466 | 468 return TRUE; |
8456 | 469 } |
8420 | 470 } |
8466 | 471 return FALSE; |
8317 | 472 break; |
8654 | 473 |
474 #ifdef LAY_OFF_MY_FRIGGIN_KEYBINDINGS | |
8317 | 475 case 'f': |
476 case 'F': | |
477 /*set_toggle(gtkconv->toolbar.font, | |
478 !gtk_toggle_button_get_active( | |
479 GTK_TOGGLE_BUTTON(gtkconv->toolbar.font)));*/ | |
480 | |
481 return TRUE; | |
482 break; | |
8654 | 483 #endif /* this doesn't even DO anything */ |
8317 | 484 |
485 case 'i': | |
486 case 'I': | |
8481 | 487 if (imhtml->format_functions & GTK_IMHTML_ITALIC) { |
8466 | 488 if(imhtml->html_shortcuts) { |
8456 | 489 gtk_imhtml_toggle_italic(imhtml); |
8466 | 490 return TRUE; |
491 } | |
8481 | 492 } |
8466 | 493 return FALSE; |
8317 | 494 break; |
495 | |
496 case 'u': /* ctrl-u is GDK_Clear, which clears the line. */ | |
497 case 'U': | |
8481 | 498 if (imhtml->format_functions & GTK_IMHTML_UNDERLINE) { |
8466 | 499 if(imhtml->html_shortcuts) { |
8456 | 500 gtk_imhtml_toggle_underline(imhtml); |
8466 | 501 return TRUE; |
502 } | |
8481 | 503 } |
8466 | 504 return FALSE; |
8317 | 505 break; |
506 | |
507 case '-': | |
8420 | 508 if (imhtml->format_functions & GTK_IMHTML_SHRINK) |
509 gtk_imhtml_font_shrink(imhtml); | |
8317 | 510 return TRUE; |
511 break; | |
512 | |
513 case '=': | |
514 case '+': | |
8420 | 515 if (imhtml->format_functions & GTK_IMHTML_GROW) |
516 gtk_imhtml_font_grow(imhtml); | |
8317 | 517 return TRUE; |
518 break; | |
8677 | 519 |
8317 | 520 case '1': strcpy(buf, ":-)"); break; |
521 case '2': strcpy(buf, ":-("); break; | |
522 case '3': strcpy(buf, ";-)"); break; | |
523 case '4': strcpy(buf, ":-P"); break; | |
524 case '5': strcpy(buf, "=-O"); break; | |
525 case '6': strcpy(buf, ":-*"); break; | |
526 case '7': strcpy(buf, ">:o"); break; | |
527 case '8': strcpy(buf, "8-)"); break; | |
528 case '!': strcpy(buf, ":-$"); break; | |
529 case '@': strcpy(buf, ":-!"); break; | |
530 case '#': strcpy(buf, ":-["); break; | |
531 case '$': strcpy(buf, "O:-)"); break; | |
532 case '%': strcpy(buf, ":-/"); break; | |
533 case '^': strcpy(buf, ":'("); break; | |
534 case '&': strcpy(buf, ":-X"); break; | |
535 case '*': strcpy(buf, ":-D"); break; | |
6066 | 536 } |
8456 | 537 if (*buf && imhtml->smiley_shortcuts) { |
538 gtk_imhtml_insert_smiley(imhtml, imhtml->protocol_name, buf); | |
8317 | 539 return TRUE; |
8677 | 540 } |
6066 | 541 return FALSE; |
542 } | |
543 | |
8061 | 544 static void gtk_imhtml_clipboard_get(GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, GtkIMHtml *imhtml) { |
8681 | 545 char *text; |
8782
5a2b5e4abf3a
[gaim-migrate @ 9544]
Christian Hammond <chipx86@chipx86.com>
parents:
8758
diff
changeset
|
546 gboolean primary; |
8061 | 547 GtkTextIter start, end; |
548 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
549 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
8681 | 550 |
8061 | 551 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); |
552 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
8782
5a2b5e4abf3a
[gaim-migrate @ 9544]
Christian Hammond <chipx86@chipx86.com>
parents:
8758
diff
changeset
|
553 primary = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY) == clipboard; |
8061 | 554 |
555 if (info == TARGET_HTML) { | |
8907 | 556 gsize len; |
8148 | 557 char *selection; |
8061 | 558 GString *str = g_string_new(NULL); |
8681 | 559 if (primary) { |
560 text = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
561 } else | |
562 text = imhtml->clipboard_html_string; | |
8061 | 563 |
564 /* Mozilla asks that we start our text/html with the Unicode byte order mark */ | |
565 str = g_string_append_unichar(str, 0xfeff); | |
566 str = g_string_append(str, text); | |
567 str = g_string_append_unichar(str, 0x0000); | |
8148 | 568 selection = g_convert(str->str, str->len, "UCS-2", "UTF-8", NULL, &len, NULL); |
8719 | 569 gtk_selection_data_set(selection_data, gdk_atom_intern("text/html", FALSE), 16, selection, len); |
8061 | 570 g_string_free(str, TRUE); |
571 g_free(selection); | |
572 } else { | |
8681 | 573 if (primary) { |
574 text = gtk_imhtml_get_text(imhtml, &start, &end); | |
575 } else | |
576 text = imhtml->clipboard_text_string; | |
8061 | 577 gtk_selection_data_set_text(selection_data, text, strlen(text)); |
578 } | |
8681 | 579 if (primary) /* This was allocated here */ |
580 g_free(text); | |
581 } | |
8061 | 582 |
583 static void gtk_imhtml_primary_clipboard_clear(GtkClipboard *clipboard, GtkIMHtml *imhtml) | |
7749 | 584 { |
8061 | 585 GtkTextIter insert; |
586 GtkTextIter selection_bound; | |
587 | |
588 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &insert, | |
589 gtk_text_buffer_get_mark (imhtml->text_buffer, "insert")); | |
590 gtk_text_buffer_get_iter_at_mark (imhtml->text_buffer, &selection_bound, | |
591 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound")); | |
592 | |
593 if (!gtk_text_iter_equal (&insert, &selection_bound)) | |
594 gtk_text_buffer_move_mark (imhtml->text_buffer, | |
595 gtk_text_buffer_get_mark (imhtml->text_buffer, "selection_bound"), | |
596 &insert); | |
7749 | 597 } |
7742 | 598 |
8677 | 599 static void copy_clipboard_cb(GtkIMHtml *imhtml, gpointer unused) |
7749 | 600 { |
8681 | 601 GtkTextIter start, end; |
602 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
603 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
604 | |
605 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); | |
606 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
607 | |
8061 | 608 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), |
609 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
610 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
611 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); | |
7346 | 612 |
8681 | 613 if (imhtml->clipboard_html_string) { |
614 g_free(imhtml->clipboard_html_string); | |
615 g_free(imhtml->clipboard_text_string); | |
616 } | |
617 | |
618 imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
619 imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end); | |
620 | |
8692 | 621 #ifdef _WIN32 |
622 /* We're going to still copy plain text, but let's toss the "HTML Format" | |
623 we need into the windows clipboard now as well. */ | |
624 HGLOBAL hdata; | |
625 gchar *clipboard = clipboard_html_to_win32(imhtml->clipboard_html_string); | |
626 gchar *buffer; | |
627 gint length = strlen(clipboard); | |
628 if(clipboard != NULL) { | |
8693 | 629 OpenClipboard(NULL); |
8692 | 630 hdata = GlobalAlloc(GMEM_MOVEABLE, length); |
631 buffer = GlobalLock(hdata); | |
632 memcpy(buffer, clipboard, length); | |
633 GlobalUnlock(hdata); | |
634 SetClipboardData(win_html_fmt, hdata); | |
635 CloseClipboard(); | |
8693 | 636 g_free(clipboard); |
8692 | 637 } |
638 #endif | |
639 | |
8061 | 640 g_signal_stop_emission_by_name(imhtml, "copy-clipboard"); |
641 } | |
642 | |
8698 | 643 static void cut_clipboard_cb(GtkIMHtml *imhtml, gpointer unused) |
644 { | |
645 GtkTextIter start, end; | |
646 GtkTextMark *sel = gtk_text_buffer_get_selection_bound(imhtml->text_buffer); | |
647 GtkTextMark *ins = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
648 | |
649 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &start, sel); | |
650 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &end, ins); | |
651 | |
652 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD), | |
653 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
654 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
655 (GtkClipboardClearFunc)NULL, G_OBJECT(imhtml)); | |
656 | |
657 if (imhtml->clipboard_html_string) { | |
658 g_free(imhtml->clipboard_html_string); | |
659 g_free(imhtml->clipboard_text_string); | |
660 } | |
661 | |
662 imhtml->clipboard_html_string = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
663 imhtml->clipboard_text_string = gtk_imhtml_get_text(imhtml, &start, &end); | |
664 | |
665 #ifdef _WIN32 | |
666 /* We're going to still copy plain text, but let's toss the "HTML Format" | |
667 we need into the windows clipboard now as well. */ | |
668 HGLOBAL hdata; | |
669 gchar *clipboard = clipboard_html_to_win32(imhtml->clipboard_html_string); | |
670 gchar *buffer; | |
671 gint length = strlen(clipboard); | |
672 if(clipboard != NULL) { | |
673 OpenClipboard(NULL); | |
674 hdata = GlobalAlloc(GMEM_MOVEABLE, length); | |
675 buffer = GlobalLock(hdata); | |
676 memcpy(buffer, clipboard, length); | |
677 GlobalUnlock(hdata); | |
678 SetClipboardData(win_html_fmt, hdata); | |
679 CloseClipboard(); | |
680 g_free(clipboard); | |
681 } | |
682 #endif | |
683 | |
684 if (imhtml->editable) | |
685 gtk_text_buffer_delete_selection(imhtml->text_buffer, FALSE, FALSE); | |
686 g_signal_stop_emission_by_name(imhtml, "cut-clipboard"); | |
687 } | |
688 | |
8061 | 689 static void paste_received_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, gpointer data) |
690 { | |
691 char *text; | |
692 GtkIMHtml *imhtml = data; | |
8677 | 693 GtkTextIter iter; |
8698 | 694 GtkIMHtmlOptions flags = GTK_IMHTML_NO_NEWLINE; |
695 gboolean plaintext = FALSE; | |
7809 | 696 |
8123 | 697 if (!gtk_text_view_get_editable(GTK_TEXT_VIEW(imhtml))) |
8105 | 698 return; |
699 | |
8692 | 700 #ifdef _WIN32 |
701 /* If we're on windows, let's see if we can get data from the HTML Format | |
702 clipboard before we try to paste from the GTK buffer */ | |
703 HGLOBAL hdata; | |
704 DWORD err; | |
705 char *buffer; | |
706 if (IsClipboardFormatAvailable(win_html_fmt)) { | |
8693 | 707 OpenClipboard(NULL); |
8692 | 708 hdata = GetClipboardData(win_html_fmt); |
709 if (hdata == NULL) { | |
710 err = GetLastError(); | |
711 gaim_debug_info("html clipboard", "error number %u! See http://msdn.microsoft.com/library/en-us/debug/base/system_error_codes.asp\n", err); | |
712 CloseClipboard(); | |
713 return; | |
714 } | |
715 buffer = GlobalLock(hdata); | |
716 if (buffer == NULL) { | |
8693 | 717 err = GetLastError(); |
8692 | 718 gaim_debug_info("html clipboard", "error number %u! See http://msdn.microsoft.com/library/en-us/debug/base/system_error_codes.asp\n", err); |
719 CloseClipboard(); | |
720 return; | |
721 } | |
722 text = clipboard_win32_to_html(buffer); | |
723 GlobalUnlock(hdata); | |
724 CloseClipboard(); | |
725 } else | |
726 #endif | |
8061 | 727 if (selection_data->length < 0) { |
8698 | 728 char *tmp; |
8061 | 729 text = gtk_clipboard_wait_for_text(clipboard); |
8698 | 730 flags = 0; |
731 plaintext = TRUE; | |
8128
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
732 |
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
733 if (text == NULL) |
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
734 return; |
9aafd344230d
[gaim-migrate @ 8833]
Christian Hammond <chipx86@chipx86.com>
parents:
8123
diff
changeset
|
735 |
8698 | 736 tmp = gaim_escape_html(text); |
737 g_free(text); | |
738 text = tmp; | |
8061 | 739 } else { |
8719 | 740 #if 0 |
741 /* Here's some debug code, for figuring out what sent to us over the clipboard. */ | |
742 { | |
743 int i; | |
744 | |
745 gaim_debug_misc("gtkimhtml", "In paste_received_cb():\n\tformat = %d, length = %d\n\t", | |
746 selection_data->format, selection_data->length); | |
747 | |
748 for (i = 0; i < (/*(selection_data->format / 8) **/ selection_data->length); i++) { | |
749 if ((i % 70) == 0) | |
750 printf("\n\t"); | |
751 if (selection_data->data[i] == '\0') | |
752 printf("."); | |
753 else | |
754 printf("%c", selection_data->data[i]); | |
755 } | |
756 printf("\n"); | |
757 } | |
758 #endif | |
759 text = g_malloc(selection_data->length); | |
760 memcpy(text, selection_data->data, selection_data->length); | |
7766 | 761 } |
8061 | 762 |
8869 | 763 if (selection_data->length >= 2 && |
764 (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe)) { | |
765 /* This is UCS-2 */ | |
766 char *utf8 = g_convert(text, selection_data->length, "UTF-8", "UCS-2", NULL, NULL, NULL); | |
8061 | 767 g_free(text); |
768 text = utf8; | |
8698 | 769 if (!text) { |
8869 | 770 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in paste_received_cb\n"); |
8698 | 771 return; |
772 } | |
8061 | 773 } |
8698 | 774 |
775 if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
776 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in paste_received_cb\n"); | |
777 g_free(text); | |
778 return; | |
779 } | |
780 | |
8677 | 781 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, gtk_text_buffer_get_insert(imhtml->text_buffer)); |
8698 | 782 if (!imhtml->wbfo && !plaintext) |
783 gtk_imhtml_close_tags(imhtml, &iter); | |
784 gtk_imhtml_insert_html_at_iter(imhtml, text, flags, &iter); | |
8677 | 785 gtk_text_buffer_move_mark_by_name(imhtml->text_buffer, "insert", &iter); |
8698 | 786 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), gtk_text_buffer_get_insert(imhtml->text_buffer), |
787 0, FALSE, 0.0, 0.0); | |
8681 | 788 g_free(text); |
8061 | 789 } |
790 | |
791 static void paste_clipboard_cb(GtkIMHtml *imhtml, gpointer blah) | |
792 { | |
793 | |
794 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_CLIPBOARD); | |
795 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), | |
796 paste_received_cb, imhtml); | |
797 g_signal_stop_emission_by_name(imhtml, "paste-clipboard"); | |
7766 | 798 } |
799 | |
8677 | 800 static void imhtml_realized_remove_primary(GtkIMHtml *imhtml, gpointer unused) |
801 { | |
802 gtk_text_buffer_remove_selection_clipboard(GTK_IMHTML(imhtml)->text_buffer, | |
803 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY)); | |
804 | |
805 } | |
806 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
807 static void imhtml_destroy_add_primary(GtkIMHtml *imhtml, gpointer unused) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
808 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
809 gtk_text_buffer_add_selection_clipboard(GTK_IMHTML(imhtml)->text_buffer, |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
810 gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
811 } |
8677 | 812 |
813 static void mark_set_so_update_selection_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, GtkIMHtml *imhtml) | |
814 { | |
815 if (gtk_text_buffer_get_selection_bounds(buffer, NULL, NULL)) { | |
816 gtk_clipboard_set_with_owner(gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY), | |
817 selection_targets, sizeof(selection_targets) / sizeof(GtkTargetEntry), | |
818 (GtkClipboardGetFunc)gtk_imhtml_clipboard_get, | |
819 (GtkClipboardClearFunc)gtk_imhtml_primary_clipboard_clear, G_OBJECT(imhtml)); | |
820 } | |
821 } | |
822 | |
823 /* does this go in the #ifdef too? I need to keep track of which functions are 2.2 only */ | |
824 /* adapted from gtktextview.c */ | |
825 static gboolean gtk_imhtml_button_press_event(GtkIMHtml *imhtml, GdkEventButton *event, gpointer unused) | |
7346 | 826 { |
8677 | 827 if (event->button == 2) { |
828 int x, y; | |
829 GtkTextIter iter; | |
830 GtkClipboard *clipboard = gtk_widget_get_clipboard(GTK_WIDGET(imhtml), GDK_SELECTION_PRIMARY); | |
831 | |
832 if (!imhtml->editable) | |
833 return FALSE; | |
834 | |
835 gtk_text_view_window_to_buffer_coords(GTK_TEXT_VIEW(imhtml), | |
836 GTK_TEXT_WINDOW_TEXT, | |
837 event->x, | |
838 event->y, | |
839 &x, | |
840 &y); | |
841 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, x, y); | |
842 gtk_text_buffer_place_cursor(imhtml->text_buffer, &iter); | |
843 | |
844 gtk_clipboard_request_contents(clipboard, gdk_atom_intern("text/html", FALSE), | |
845 paste_received_cb, imhtml); | |
846 | |
847 return TRUE; | |
848 } | |
849 | |
7346 | 850 return FALSE; |
851 } | |
4263 | 852 |
4032 | 853 static GtkTextViewClass *parent_class = NULL; |
854 | |
855 static void | |
856 gtk_imhtml_finalize (GObject *object) | |
857 { | |
858 GtkIMHtml *imhtml = GTK_IMHTML(object); | |
4895 | 859 GList *scalables; |
8061 | 860 |
4138 | 861 g_hash_table_destroy(imhtml->smiley_data); |
4032 | 862 gtk_smiley_tree_destroy(imhtml->default_smilies); |
4138 | 863 gdk_cursor_unref(imhtml->hand_cursor); |
864 gdk_cursor_unref(imhtml->arrow_cursor); | |
8061 | 865 gdk_cursor_unref(imhtml->text_cursor); |
8677 | 866 |
4735 | 867 if(imhtml->tip_window){ |
868 gtk_widget_destroy(imhtml->tip_window); | |
869 } | |
870 if(imhtml->tip_timer) | |
871 gtk_timeout_remove(imhtml->tip_timer); | |
872 | |
4895 | 873 for(scalables = imhtml->scalables; scalables; scalables = scalables->next) { |
874 GtkIMHtmlScalable *scale = GTK_IMHTML_SCALABLE(scalables->data); | |
875 scale->free(scale); | |
876 } | |
7991 | 877 |
8681 | 878 if (imhtml->clipboard_text_string) { |
879 g_free(imhtml->clipboard_text_string); | |
880 g_free(imhtml->clipboard_html_string); | |
881 } | |
882 | |
4895 | 883 g_list_free(imhtml->scalables); |
4032 | 884 G_OBJECT_CLASS(parent_class)->finalize (object); |
885 } | |
1428 | 886 |
3922 | 887 /* Boring GTK stuff */ |
8519 | 888 static void gtk_imhtml_class_init (GtkIMHtmlClass *klass) |
1428 | 889 { |
3922 | 890 GtkObjectClass *object_class; |
4032 | 891 GObjectClass *gobject_class; |
8519 | 892 object_class = (GtkObjectClass*) klass; |
893 gobject_class = (GObjectClass*) klass; | |
4032 | 894 parent_class = gtk_type_class(GTK_TYPE_TEXT_VIEW); |
4417 | 895 signals[URL_CLICKED] = g_signal_new("url_clicked", |
896 G_TYPE_FROM_CLASS(gobject_class), | |
897 G_SIGNAL_RUN_FIRST, | |
898 G_STRUCT_OFFSET(GtkIMHtmlClass, url_clicked), | |
899 NULL, | |
900 0, | |
901 g_cclosure_marshal_VOID__POINTER, | |
902 G_TYPE_NONE, 1, | |
903 G_TYPE_POINTER); | |
8506 | 904 signals[BUTTONS_UPDATE] = g_signal_new("format_buttons_update", |
8420 | 905 G_TYPE_FROM_CLASS(gobject_class), |
906 G_SIGNAL_RUN_FIRST, | |
907 G_STRUCT_OFFSET(GtkIMHtmlClass, buttons_update), | |
908 NULL, | |
909 0, | |
910 g_cclosure_marshal_VOID__POINTER, | |
911 G_TYPE_NONE, 1, | |
912 G_TYPE_INT); | |
913 signals[TOGGLE_FORMAT] = g_signal_new("format_function_toggle", | |
914 G_TYPE_FROM_CLASS(gobject_class), | |
915 G_SIGNAL_RUN_FIRST, | |
916 G_STRUCT_OFFSET(GtkIMHtmlClass, toggle_format), | |
917 NULL, | |
918 0, | |
919 g_cclosure_marshal_VOID__POINTER, | |
8427 | 920 G_TYPE_NONE, 1, |
8420 | 921 G_TYPE_INT); |
8427 | 922 signals[CLEAR_FORMAT] = g_signal_new("format_function_clear", |
923 G_TYPE_FROM_CLASS(gobject_class), | |
924 G_SIGNAL_RUN_FIRST, | |
925 G_STRUCT_OFFSET(GtkIMHtmlClass, clear_format), | |
926 NULL, | |
927 0, | |
8481 | 928 g_cclosure_marshal_VOID__VOID, |
929 G_TYPE_NONE, 0); | |
8506 | 930 signals[UPDATE_FORMAT] = g_signal_new("format_function_update", |
931 G_TYPE_FROM_CLASS(gobject_class), | |
932 G_SIGNAL_RUN_FIRST, | |
933 G_STRUCT_OFFSET(GtkIMHtmlClass, update_format), | |
934 NULL, | |
935 0, | |
936 g_cclosure_marshal_VOID__VOID, | |
937 G_TYPE_NONE, 0); | |
4032 | 938 gobject_class->finalize = gtk_imhtml_finalize; |
1428 | 939 } |
940 | |
3922 | 941 static void gtk_imhtml_init (GtkIMHtml *imhtml) |
1428 | 942 { |
3922 | 943 GtkTextIter iter; |
944 imhtml->text_buffer = gtk_text_buffer_new(NULL); | |
945 gtk_text_buffer_get_end_iter (imhtml->text_buffer, &iter); | |
8677 | 946 imhtml->scrollpoint = gtk_text_buffer_create_mark(imhtml->text_buffer, NULL, &iter, FALSE); |
3922 | 947 gtk_text_view_set_buffer(GTK_TEXT_VIEW(imhtml), imhtml->text_buffer); |
5105 | 948 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(imhtml), GTK_WRAP_WORD_CHAR); |
3922 | 949 gtk_text_view_set_pixels_below_lines(GTK_TEXT_VIEW(imhtml), 5); |
8677 | 950 gtk_text_view_set_left_margin(GTK_TEXT_VIEW(imhtml), 2); |
951 gtk_text_view_set_right_margin(GTK_TEXT_VIEW(imhtml), 2); | |
8061 | 952 /*gtk_text_view_set_indent(GTK_TEXT_VIEW(imhtml), -15);*/ |
3922 | 953 /*gtk_text_view_set_justification(GTK_TEXT_VIEW(imhtml), GTK_JUSTIFY_FILL);*/ |
8061 | 954 |
3922 | 955 /* These tags will be used often and can be reused--we create them on init and then apply them by name |
8061 | 956 * other tags (color, size, face, etc.) will have to be created and applied dynamically */ |
3922 | 957 gtk_text_buffer_create_tag(imhtml->text_buffer, "BOLD", "weight", PANGO_WEIGHT_BOLD, NULL); |
958 gtk_text_buffer_create_tag(imhtml->text_buffer, "ITALICS", "style", PANGO_STYLE_ITALIC, NULL); | |
959 gtk_text_buffer_create_tag(imhtml->text_buffer, "UNDERLINE", "underline", PANGO_UNDERLINE_SINGLE, NULL); | |
960 gtk_text_buffer_create_tag(imhtml->text_buffer, "STRIKE", "strikethrough", TRUE, NULL); | |
961 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUB", "rise", -5000, NULL); | |
962 gtk_text_buffer_create_tag(imhtml->text_buffer, "SUP", "rise", 5000, NULL); | |
963 gtk_text_buffer_create_tag(imhtml->text_buffer, "PRE", "family", "Monospace", NULL); | |
7295 | 964 gtk_text_buffer_create_tag(imhtml->text_buffer, "search", "background", "#22ff00", "weight", "bold", NULL); |
8677 | 965 |
3922 | 966 /* When hovering over a link, we show the hand cursor--elsewhere we show the plain ol' pointer cursor */ |
967 imhtml->hand_cursor = gdk_cursor_new (GDK_HAND2); | |
968 imhtml->arrow_cursor = gdk_cursor_new (GDK_LEFT_PTR); | |
8061 | 969 imhtml->text_cursor = gdk_cursor_new (GDK_XTERM); |
2993 | 970 |
6124 | 971 imhtml->show_comments = TRUE; |
4253 | 972 |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
973 imhtml->zoom = 1.0; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
974 imhtml->original_fsize = 0; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
975 |
4892 | 976 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 977 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4032 | 978 imhtml->default_smilies = gtk_smiley_tree_new(); |
4735 | 979 |
4944 | 980 g_signal_connect(G_OBJECT(imhtml), "size-allocate", G_CALLBACK(gtk_size_allocate_cb), NULL); |
4735 | 981 g_signal_connect(G_OBJECT(imhtml), "motion-notify-event", G_CALLBACK(gtk_motion_event_notify), NULL); |
4944 | 982 g_signal_connect(G_OBJECT(imhtml), "leave-notify-event", G_CALLBACK(gtk_leave_event_notify), NULL); |
6066 | 983 g_signal_connect(G_OBJECT(imhtml), "key_press_event", G_CALLBACK(gtk_key_pressed_cb), NULL); |
8677 | 984 g_signal_connect(G_OBJECT(imhtml), "button_press_event", G_CALLBACK(gtk_imhtml_button_press_event), NULL); |
985 g_signal_connect(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(preinsert_cb), imhtml); | |
8061 | 986 g_signal_connect_after(G_OBJECT(imhtml->text_buffer), "insert-text", G_CALLBACK(insert_cb), imhtml); |
8091 | 987 |
988 gtk_drag_dest_set(GTK_WIDGET(imhtml), 0, | |
989 link_drag_drop_targets, sizeof(link_drag_drop_targets) / sizeof(GtkTargetEntry), | |
990 GDK_ACTION_COPY); | |
991 g_signal_connect(G_OBJECT(imhtml), "drag_data_received", G_CALLBACK(gtk_imhtml_link_drag_rcv_cb), imhtml); | |
992 | |
7353 | 993 g_signal_connect(G_OBJECT(imhtml), "copy-clipboard", G_CALLBACK(copy_clipboard_cb), NULL); |
8698 | 994 g_signal_connect(G_OBJECT(imhtml), "cut-clipboard", G_CALLBACK(cut_clipboard_cb), NULL); |
8061 | 995 g_signal_connect(G_OBJECT(imhtml), "paste-clipboard", G_CALLBACK(paste_clipboard_cb), NULL); |
8677 | 996 //g_signal_connect_after(G_OBJECT(imhtml), "button-release-event", G_CALLBACK(button_release_cb), imhtml); |
997 g_signal_connect_after(G_OBJECT(imhtml), "realize", G_CALLBACK(imhtml_realized_remove_primary), NULL); | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
998 g_signal_connect(G_OBJECT(imhtml), "unrealize", G_CALLBACK(imhtml_destroy_add_primary), NULL); |
8677 | 999 |
1000 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
1001 G_CALLBACK(mark_set_so_update_selection_cb), imhtml); | |
1002 | |
4944 | 1003 gtk_widget_add_events(GTK_WIDGET(imhtml), GDK_LEAVE_NOTIFY_MASK); |
4735 | 1004 |
8681 | 1005 imhtml->clipboard_text_string = NULL; |
1006 imhtml->clipboard_html_string = NULL; | |
1007 | |
4735 | 1008 imhtml->tip = NULL; |
1009 imhtml->tip_timer = 0; | |
1010 imhtml->tip_window = NULL; | |
4895 | 1011 |
8677 | 1012 imhtml->edit.bold = FALSE; |
1013 imhtml->edit.italic = FALSE; | |
1014 imhtml->edit.underline = FALSE; | |
8061 | 1015 imhtml->edit.forecolor = NULL; |
1016 imhtml->edit.backcolor = NULL; | |
1017 imhtml->edit.fontface = NULL; | |
8677 | 1018 imhtml->edit.fontsize = 0; |
1019 imhtml->edit.link = NULL; | |
1020 | |
8061 | 1021 |
4895 | 1022 imhtml->scalables = NULL; |
8061 | 1023 |
1024 gtk_imhtml_set_editable(imhtml, FALSE); | |
8692 | 1025 |
1026 #ifdef _WIN32 | |
1027 /* Register HTML Format as desired clipboard format */ | |
1028 win_html_fmt = RegisterClipboardFormat("HTML Format"); | |
1029 #endif | |
2993 | 1030 } |
1031 | |
3922 | 1032 GtkWidget *gtk_imhtml_new(void *a, void *b) |
1428 | 1033 { |
4635 | 1034 return GTK_WIDGET(g_object_new(gtk_imhtml_get_type(), NULL)); |
1428 | 1035 } |
1036 | |
4635 | 1037 GType gtk_imhtml_get_type() |
1428 | 1038 { |
4635 | 1039 static GType imhtml_type = 0; |
1428 | 1040 |
1041 if (!imhtml_type) { | |
4635 | 1042 static const GTypeInfo imhtml_info = { |
1043 sizeof(GtkIMHtmlClass), | |
1044 NULL, | |
1045 NULL, | |
1046 (GClassInitFunc) gtk_imhtml_class_init, | |
1047 NULL, | |
1048 NULL, | |
1428 | 1049 sizeof (GtkIMHtml), |
4635 | 1050 0, |
1051 (GInstanceInitFunc) gtk_imhtml_init | |
1428 | 1052 }; |
4635 | 1053 |
1054 imhtml_type = g_type_register_static(gtk_text_view_get_type(), | |
1055 "GtkIMHtml", &imhtml_info, 0); | |
1428 | 1056 } |
1057 | |
1058 return imhtml_type; | |
1059 } | |
1060 | |
4417 | 1061 struct url_data { |
1062 GObject *object; | |
1063 gchar *url; | |
1064 }; | |
1065 | |
8677 | 1066 static void url_data_destroy(gpointer mydata) |
1067 { | |
1068 struct url_data *data = mydata; | |
1069 g_object_unref(data->object); | |
1070 g_free(data->url); | |
1071 g_free(data); | |
1072 } | |
1073 | |
4417 | 1074 static void url_open(GtkWidget *w, struct url_data *data) { |
1075 if(!data) return; | |
8061 | 1076 g_signal_emit(data->object, signals[URL_CLICKED], 0, data->url); |
7988 | 1077 |
4417 | 1078 } |
5582 | 1079 |
4417 | 1080 static void url_copy(GtkWidget *w, gchar *url) { |
1081 GtkClipboard *clipboard; | |
1082 | |
5293
ead927e2543f
[gaim-migrate @ 5665]
Christian Hammond <chipx86@chipx86.com>
parents:
5282
diff
changeset
|
1083 clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
4417 | 1084 gtk_clipboard_set_text(clipboard, url, -1); |
5582 | 1085 |
1086 clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | |
1087 gtk_clipboard_set_text(clipboard, url, -1); | |
4417 | 1088 } |
1089 | |
1090 /* The callback for an event on a link tag. */ | |
8677 | 1091 gboolean tag_event(GtkTextTag *tag, GObject *imhtml, GdkEvent *event, GtkTextIter *arg2, gpointer unused) { |
4417 | 1092 GdkEventButton *event_button = (GdkEventButton *) event; |
8061 | 1093 if (GTK_IMHTML(imhtml)->editable) |
1094 return FALSE; | |
3922 | 1095 if (event->type == GDK_BUTTON_RELEASE) { |
8061 | 1096 if (event_button->button == 1) { |
4417 | 1097 GtkTextIter start, end; |
1098 /* we shouldn't open a URL if the user has selected something: */ | |
8677 | 1099 if (gtk_text_buffer_get_selection_bounds( |
1100 gtk_text_iter_get_buffer(arg2), &start, &end)) | |
4417 | 1101 return FALSE; |
1102 | |
1103 /* A link was clicked--we emit the "url_clicked" signal | |
1104 * with the URL as the argument */ | |
8677 | 1105 g_object_ref(G_OBJECT(tag)); |
1106 g_signal_emit(imhtml, signals[URL_CLICKED], 0, g_object_get_data(G_OBJECT(tag), "link_url")); | |
1107 g_object_unref(G_OBJECT(tag)); | |
4417 | 1108 return FALSE; |
1109 } else if(event_button->button == 3) { | |
4745 | 1110 GtkWidget *img, *item, *menu; |
4417 | 1111 struct url_data *tempdata = g_new(struct url_data, 1); |
5091 | 1112 tempdata->object = g_object_ref(imhtml); |
8677 | 1113 tempdata->url = g_strdup(g_object_get_data(G_OBJECT(tag), "link_url")); |
4745 | 1114 |
5091 | 1115 /* Don't want the tooltip around if user right-clicked on link */ |
1116 if (GTK_IMHTML(imhtml)->tip_window) { | |
1117 gtk_widget_destroy(GTK_IMHTML(imhtml)->tip_window); | |
1118 GTK_IMHTML(imhtml)->tip_window = NULL; | |
1119 } | |
1120 if (GTK_IMHTML(imhtml)->tip_timer) { | |
1121 g_source_remove(GTK_IMHTML(imhtml)->tip_timer); | |
1122 GTK_IMHTML(imhtml)->tip_timer = 0; | |
1123 } | |
8061 | 1124 if (GTK_IMHTML(imhtml)->editable) |
1125 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->text_cursor); | |
1126 else | |
1127 gdk_window_set_cursor(event_button->window, GTK_IMHTML(imhtml)->arrow_cursor); | |
4417 | 1128 menu = gtk_menu_new(); |
8677 | 1129 g_object_set_data_full(G_OBJECT(menu), "x-imhtml-url-data", tempdata, url_data_destroy); |
4745 | 1130 |
4417 | 1131 /* buttons and such */ |
1132 | |
8677 | 1133 if (!strncmp(tempdata->url, "mailto:", 7)) |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1134 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1135 /* Copy E-Mail Address */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1136 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1137 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1138 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1139 _("_Copy E-Mail Address")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1140 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
|
1141 g_signal_connect(G_OBJECT(item), "activate", |
8677 | 1142 G_CALLBACK(url_copy), tempdata->url + 7); |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1143 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1144 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1145 else |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1146 { |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1147 /* Copy Link Location */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1148 img = gtk_image_new_from_stock(GTK_STOCK_COPY, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1149 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1150 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1151 _("_Copy Link Location")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1152 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
|
1153 g_signal_connect(G_OBJECT(item), "activate", |
8677 | 1154 G_CALLBACK(url_copy), tempdata->url); |
7140
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1155 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1156 |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1157 /* Open Link in Browser */ |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1158 img = gtk_image_new_from_stock(GTK_STOCK_JUMP_TO, |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1159 GTK_ICON_SIZE_MENU); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1160 item = gtk_image_menu_item_new_with_mnemonic( |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1161 _("_Open Link in Browser")); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1162 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
|
1163 g_signal_connect(G_OBJECT(item), "activate", |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1164 G_CALLBACK(url_open), tempdata); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1165 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1166 } |
48cc5d5d5a6c
[gaim-migrate @ 7707]
Christian Hammond <chipx86@chipx86.com>
parents:
6982
diff
changeset
|
1167 |
4756 | 1168 |
4417 | 1169 gtk_widget_show_all(menu); |
4756 | 1170 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, |
1171 event_button->button, event_button->time); | |
4745 | 1172 |
4417 | 1173 return TRUE; |
1174 } | |
1428 | 1175 } |
4417 | 1176 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) |
1177 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
1178 be caught by the regular GtkTextView menu */ | |
1179 else | |
1180 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
1428 | 1181 } |
1182 | |
8091 | 1183 static void |
1184 gtk_imhtml_link_drag_rcv_cb(GtkWidget *widget, GdkDragContext *dc, guint x, guint y, | |
1185 GtkSelectionData *sd, guint info, guint t, GtkIMHtml *imhtml) | |
1186 { | |
1187 if(gtk_imhtml_get_editable(imhtml) && sd->data){ | |
1188 gchar **links; | |
1189 gchar *link; | |
1190 | |
1191 gaim_str_strip_cr(sd->data); | |
1192 | |
1193 links = g_strsplit(sd->data, "\n", 0); | |
1194 while((link = *links++) != NULL){ | |
1195 if(gaim_str_has_prefix(link, "http://") || | |
1196 gaim_str_has_prefix(link, "https://") || | |
1197 gaim_str_has_prefix(link, "ftp://")){ | |
8677 | 1198 gtk_imhtml_insert_link(imhtml, gtk_text_buffer_get_insert(imhtml->text_buffer), link, link); |
8091 | 1199 } else if (link=='\0') { |
8177 | 1200 /* Ignore blank lines */ |
8091 | 1201 } else { |
8177 | 1202 /* Special reasons, aka images being put in via other tag, etc. */ |
8091 | 1203 } |
1204 } | |
1205 | |
1206 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); | |
1207 } else { | |
1208 gtk_drag_finish(dc, FALSE, FALSE, t); | |
1209 } | |
1210 } | |
1211 | |
4298 | 1212 /* this isn't used yet |
4032 | 1213 static void |
4263 | 1214 gtk_smiley_tree_remove (GtkSmileyTree *tree, |
1215 GtkIMHtmlSmiley *smiley) | |
4032 | 1216 { |
1217 GtkSmileyTree *t = tree; | |
4263 | 1218 const gchar *x = smiley->smile; |
4032 | 1219 gint len = 0; |
1220 | |
1221 while (*x) { | |
1222 gchar *pos; | |
1223 | |
1224 if (!t->values) | |
1225 return; | |
1226 | |
1227 pos = strchr (t->values->str, *x); | |
1228 if (pos) | |
1229 t = t->children [(int) pos - (int) t->values->str]; | |
1230 else | |
1231 return; | |
1232 | |
1233 x++; len++; | |
1234 } | |
1235 | |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1236 if (t->image) { |
4032 | 1237 t->image = NULL; |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1238 } |
4032 | 1239 } |
4298 | 1240 */ |
1241 | |
4032 | 1242 |
1243 static gint | |
1244 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
1245 const gchar *text) | |
1246 { | |
1247 GtkSmileyTree *t = tree; | |
1248 const gchar *x = text; | |
1249 gint len = 0; | |
8505 | 1250 gchar *amp; |
1251 gint alen; | |
4032 | 1252 |
1253 while (*x) { | |
1254 gchar *pos; | |
1255 | |
1256 if (!t->values) | |
1257 break; | |
1258 | |
8505 | 1259 if(*x == '&' && gtk_imhtml_is_amp_escape(x, &, &alen)) { |
1260 len += alen - strlen(amp); | |
1261 x += alen - strlen(amp); | |
1262 pos = strchr (t->values->str, *amp); | |
1263 } | |
1264 else | |
1265 pos = strchr (t->values->str, *x); | |
1266 | |
4032 | 1267 if (pos) |
7371 | 1268 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1269 else |
1270 break; | |
1271 | |
1272 x++; len++; | |
1273 } | |
1274 | |
1275 if (t->image) | |
1276 return len; | |
1277 | |
1278 return 0; | |
1279 } | |
1280 | |
1281 void | |
4263 | 1282 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
1283 gchar *sml, | |
1284 GtkIMHtmlSmiley *smiley) | |
4032 | 1285 { |
1286 GtkSmileyTree *tree; | |
1287 g_return_if_fail (imhtml != NULL); | |
1288 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
7371 | 1289 |
4032 | 1290 if (sml == NULL) |
1291 tree = imhtml->default_smilies; | |
1292 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
1293 } else { | |
1294 tree = gtk_smiley_tree_new(); | |
4892 | 1295 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 1296 } |
1297 | |
4263 | 1298 gtk_smiley_tree_insert (tree, smiley); |
4032 | 1299 } |
1300 | |
1301 static gboolean | |
1302 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
1303 GSList *fonts, | |
1304 const gchar *text, | |
1305 gint *len) | |
1306 { | |
1307 GtkSmileyTree *tree; | |
5967 | 1308 GtkIMHtmlFontDetail *font; |
4032 | 1309 char *sml = NULL; |
1310 | |
1311 if (fonts) { | |
1312 font = fonts->data; | |
1313 sml = font->sml; | |
1314 } | |
1315 | |
1316 if (sml == NULL) | |
1317 tree = imhtml->default_smilies; | |
1318 else { | |
1319 tree = g_hash_table_lookup(imhtml->smiley_data, sml); | |
1320 } | |
1321 if (tree == NULL) | |
1322 return FALSE; | |
7371 | 1323 |
8505 | 1324 *len = gtk_smiley_tree_lookup (tree, text); |
4032 | 1325 return (*len > 0); |
1326 } | |
1327 | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1328 GdkPixbufAnimation * |
4032 | 1329 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
1330 const gchar *sml, | |
1331 const gchar *text) | |
1332 { | |
1333 GtkSmileyTree *t; | |
1334 const gchar *x = text; | |
1335 if (sml == NULL) | |
1336 t = imhtml->default_smilies; | |
7371 | 1337 else |
4032 | 1338 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
7371 | 1339 |
4032 | 1340 |
1341 if (t == NULL) | |
1342 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1343 | |
1344 while (*x) { | |
1345 gchar *pos; | |
1346 | |
1347 if (!t->values) { | |
1348 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1349 } | |
7371 | 1350 |
4032 | 1351 pos = strchr (t->values->str, *x); |
1352 if (pos) { | |
7371 | 1353 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1354 } else { |
1355 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1356 } | |
1357 x++; | |
1358 } | |
1359 | |
8890 | 1360 if (!t->image->file) |
1361 return NULL; | |
1362 | |
4263 | 1363 if (!t->image->icon) |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1364 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
4263 | 1365 |
1366 return t->image->icon; | |
4032 | 1367 } |
8890 | 1368 |
4793 | 1369 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 1370 *tag = g_strndup (string, strlen (x)); \ |
1371 *len = strlen (x) + 1; \ | |
1372 return TRUE; \ | |
1373 } \ | |
1374 (*type)++ | |
1428 | 1375 |
4793 | 1376 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 1377 const gchar *c = string + strlen (x " "); \ |
1378 gchar e = '"'; \ | |
1379 gboolean quote = FALSE; \ | |
1380 while (*c) { \ | |
1381 if (*c == '"' || *c == '\'') { \ | |
1382 if (quote && (*c == e)) \ | |
1383 quote = !quote; \ | |
1384 else if (!quote) { \ | |
1385 quote = !quote; \ | |
1386 e = *c; \ | |
1387 } \ | |
1388 } else if (!quote && (*c == '>')) \ | |
1389 break; \ | |
1390 c++; \ | |
1391 } \ | |
1392 if (*c) { \ | |
1393 *tag = g_strndup (string, c - string); \ | |
1394 *len = c - string + 1; \ | |
1395 return TRUE; \ | |
1396 } \ | |
1397 } \ | |
1398 (*type)++ | |
1428 | 1399 |
1400 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1401 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1402 gtk_imhtml_is_amp_escape (const gchar *string, |
7280 | 1403 gchar **replace, |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1404 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1405 { |
7287 | 1406 static char buf[7]; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1407 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1408 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1409 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1410 |
4793 | 1411 if (!g_ascii_strncasecmp (string, "&", 5)) { |
7280 | 1412 *replace = "&"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1413 *length = 5; |
4793 | 1414 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
7280 | 1415 *replace = "<"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1416 *length = 4; |
4793 | 1417 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
7280 | 1418 *replace = ">"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1419 *length = 4; |
4793 | 1420 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
7280 | 1421 *replace = " "; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1422 *length = 6; |
4793 | 1423 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
7280 | 1424 *replace = "©"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1425 *length = 6; |
4793 | 1426 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
7280 | 1427 *replace = "\""; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1428 *length = 6; |
4793 | 1429 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
7280 | 1430 *replace = "®"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1431 *length = 5; |
5093 | 1432 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
7280 | 1433 *replace = "\'"; |
5093 | 1434 *length = 6; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1435 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
1436 guint pound = 0; |
3004 | 1437 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
7287 | 1438 int buflen; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1439 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1440 return FALSE; |
7287 | 1441 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
1442 buf[buflen] = '\0'; | |
7280 | 1443 *replace = buf; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1444 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1445 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1446 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1447 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1448 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1449 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1450 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1451 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1452 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1453 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1454 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1455 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1456 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1457 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1458 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1459 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1460 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1461 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1462 { |
8061 | 1463 char *close; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1464 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1465 |
8118 | 1466 |
8061 | 1467 if (!(close = strchr (string, '>'))) |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1468 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1469 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1470 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1471 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1472 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1473 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1474 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1475 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1476 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1477 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1478 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1479 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1480 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1481 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1482 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1483 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1484 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1485 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1486 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1487 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1488 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1489 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1490 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1491 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1492 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1493 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1494 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1495 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1496 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1497 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1498 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1499 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1500 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1501 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1502 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1503 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1504 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1505 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1506 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1507 VALID_TAG ("HEAD"); |
2993 | 1508 VALID_TAG ("/HEAD"); |
1509 VALID_TAG ("BINARY"); | |
1510 VALID_TAG ("/BINARY"); | |
5093 | 1511 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1512 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1513 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1514 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1515 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1516 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1517 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1518 VALID_OPT_TAG ("H3"); |
5093 | 1519 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1520 |
5101 | 1521 VALID_TAG ("CITE"); |
1522 VALID_TAG ("/CITE"); | |
1523 VALID_TAG ("EM"); | |
1524 VALID_TAG ("/EM"); | |
1525 VALID_TAG ("STRONG"); | |
1526 VALID_TAG ("/STRONG"); | |
1527 | |
5104 | 1528 VALID_OPT_TAG ("SPAN"); |
1529 VALID_TAG ("/SPAN"); | |
5174 | 1530 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
6982 | 1531 VALID_TAG ("IMG"); |
8026 | 1532 VALID_TAG("SPAN"); |
8061 | 1533 VALID_OPT_TAG("BR"); |
7988 | 1534 |
4793 | 1535 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
1536 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1537 if (e) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1538 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1539 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1540 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1541 } |
8118 | 1542 } |
1543 | |
8061 | 1544 *type = -1; |
1545 *len = close - string + 1; | |
1546 *tag = g_strndup(string, *len - 1); | |
1547 return TRUE; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1548 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1549 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1550 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1551 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1552 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1553 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1554 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1555 gchar *e, *a; |
5177 | 1556 gchar *val; |
1557 gint len; | |
7280 | 1558 gchar *c; |
5177 | 1559 GString *ret; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1560 |
4793 | 1561 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1562 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1563 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1564 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1565 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1566 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1567 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1568 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1569 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1570 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1571 |
4793 | 1572 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1573 t += strlen (opt); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1574 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1575 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1576 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1577 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1578 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1579 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1580 while (*e && (*e != *(t - 1))) e++; |
2993 | 1581 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1582 return NULL; |
5177 | 1583 } else |
1584 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1585 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1586 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1587 while (*e && !isspace ((gint) *e)) e++; |
5177 | 1588 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1589 } |
5177 | 1590 |
1591 ret = g_string_new(""); | |
1592 e = val; | |
1593 while(*e) { | |
1594 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
7280 | 1595 ret = g_string_append(ret, c); |
5177 | 1596 e += len; |
1597 } else { | |
1598 ret = g_string_append_c(ret, *e); | |
1599 e++; | |
1600 } | |
1601 } | |
1602 | |
1603 g_free(val); | |
8568 | 1604 |
1605 return g_string_free(ret, FALSE); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1606 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1607 |
8118 | 1608 /* Inline CSS Support - Douglas Thrift */ |
1609 static gchar* | |
1610 gtk_imhtml_get_css_opt (gchar *style, | |
1611 const gchar *opt) | |
1612 { | |
1613 gchar *t = style; | |
1614 gchar *e, *a; | |
1615 gchar *val; | |
1616 gint len; | |
1617 gchar *c; | |
1618 GString *ret; | |
1619 | |
1620 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
8177 | 1621 /* gboolean quote = FALSE; */ |
8118 | 1622 if (*t == '\0') break; |
1623 while (*t && !((*t == ' ') /*&& !quote*/)) { | |
1624 /* if (*t == '\"') | |
8177 | 1625 quote = ! quote; */ |
8118 | 1626 t++; |
1627 } | |
1628 while (*t && (*t == ' ')) t++; | |
1629 } | |
1630 | |
1631 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
1632 t += strlen (opt); | |
1633 } else { | |
1634 return NULL; | |
1635 } | |
1636 | |
1637 /* if ((*t == '\"') || (*t == '\'')) { | |
1638 e = a = ++t; | |
1639 while (*e && (*e != *(t - 1))) e++; | |
1640 if (*e == '\0') { | |
1641 return NULL; | |
1642 } else | |
1643 val = g_strndup(a, e - a); | |
1644 } else { | |
1645 e = a = t; | |
1646 while (*e && !isspace ((gint) *e)) e++; | |
1647 val = g_strndup(a, e - a); | |
1648 }*/ | |
1649 | |
1650 e = a = t; | |
1651 while (*e && *e != ';') e++; | |
1652 val = g_strndup(a, e - a); | |
1653 | |
1654 ret = g_string_new(""); | |
1655 e = val; | |
1656 while(*e) { | |
1657 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
1658 ret = g_string_append(ret, c); | |
1659 e += len; | |
1660 } else { | |
1661 ret = g_string_append_c(ret, *e); | |
1662 e++; | |
1663 } | |
1664 } | |
1665 | |
1666 g_free(val); | |
1667 val = ret->str; | |
1668 g_string_free(ret, FALSE); | |
1669 return val; | |
1670 } | |
3922 | 1671 |
8334 | 1672 static const char *accepted_protocols[] = { |
1673 "http://", | |
1674 "https://", | |
1675 "ftp://" | |
1676 }; | |
1677 | |
1678 static const int accepted_protocols_size = 3; | |
1679 | |
1680 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so | |
1681 the caller knows how long the protocol string is. */ | |
1682 int gtk_imhtml_is_protocol(const char *text) | |
1683 { | |
1684 gint i; | |
1685 | |
1686 for(i=0; i<accepted_protocols_size; i++){ | |
1687 if( strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0 ){ | |
1688 return strlen(accepted_protocols[i]); | |
1689 } | |
1690 } | |
1691 return 0; | |
1692 } | |
1693 | |
8677 | 1694 /* |
1695 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming | |
1696 | |
1697 | |
1698 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :) | |
1699 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/> | |
1700 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz | |
1701 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add | |
1702 [20:00] <marv> Robot101: so how does the image get passed to serv_got_im() and serv_send_im()? just as the <img id="#" and then the prpl looks it up from the store? | |
1703 [20:00] <KingAnt> marv: Right | |
1704 [20:00] <marv> alright | |
1705 | |
1706 Here's my plan with IMImages. make gtk_imhtml_[append|insert]_text_with_images instead just | |
1707 gtkimhtml_[append|insert]_text (hrm maybe it should be called html instead of text), add a | |
1708 function for gaim to register for look up images, i.e. gtk_imhtml_set_get_img_fnc, so that | |
1709 images can be looked up like that, instead of passing a GSList of them. | |
1710 */ | |
1711 | |
1712 void gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, | |
1713 const gchar *text, | |
1714 GtkIMHtmlOptions options, | |
1715 GSList *unused) | |
1428 | 1716 { |
8677 | 1717 GtkTextIter iter, ins, sel; |
1718 GdkRectangle rect; | |
1719 int y, height, ins_offset = 0, sel_offset = 0; | |
1720 gboolean fixins = FALSE, fixsel = FALSE; | |
1721 | |
1722 g_return_if_fail (imhtml != NULL); | |
1723 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1724 g_return_if_fail (text != NULL); | |
1725 | |
1726 | |
1727 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1728 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, gtk_text_buffer_get_insert(imhtml->text_buffer)); | |
1729 if (gtk_text_iter_equal(&iter, &ins) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1730 fixins = TRUE; | |
1731 ins_offset = gtk_text_iter_get_offset(&ins); | |
1732 } | |
1733 | |
1734 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &sel, gtk_text_buffer_get_selection_bound(imhtml->text_buffer)); | |
1735 if (gtk_text_iter_equal(&iter, &sel) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1736 fixsel = TRUE; | |
1737 sel_offset = gtk_text_iter_get_offset(&sel); | |
1738 } | |
1739 | |
1740 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1741 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
1742 | |
1743 | |
1744 if(((y + height) - (rect.y + rect.height)) > height | |
1745 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
1746 options |= GTK_IMHTML_NO_SCROLL; | |
1747 } | |
1748 | |
1749 gtk_imhtml_insert_html_at_iter(imhtml, text, options, &iter); | |
1750 | |
1751 if (fixins) { | |
1752 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins, ins_offset); | |
1753 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_insert(imhtml->text_buffer), &ins); | |
1754 } | |
1755 | |
1756 if (fixsel) { | |
1757 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &sel, sel_offset); | |
1758 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_selection_bound(imhtml->text_buffer), &sel); | |
1759 } | |
1760 | |
1761 if (!(options & GTK_IMHTML_NO_SCROLL)) { | |
8729 | 1762 gtk_imhtml_scroll_to_end(imhtml); |
8677 | 1763 } |
1764 } | |
1765 | |
8729 | 1766 void gtk_imhtml_scroll_to_end(GtkIMHtml *imhtml) |
1767 { | |
1768 GtkTextIter iter; | |
1769 /* If this seems backwards at first glance, well it's not. | |
1770 * It means scroll such that the mark is closest to the top, | |
1771 * and closest to the right as possible. Remember kids, you have | |
1772 * to scroll left to move a given spot closest to the right, | |
1773 * and scroll down to move a spot closest to the top. | |
1774 */ | |
1775 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1776 gtk_text_iter_set_line_offset(&iter, 0); | |
1777 gtk_text_buffer_move_mark(imhtml->text_buffer, imhtml->scrollpoint, &iter); | |
1778 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), imhtml->scrollpoint, | |
1779 0, TRUE, 1.0, 0.0); | |
1780 } | |
1781 | |
8677 | 1782 void gtk_imhtml_insert_html_at_iter(GtkIMHtml *imhtml, |
1783 const gchar *text, | |
1784 GtkIMHtmlOptions options, | |
1785 GtkTextIter *iter) | |
1786 { | |
8061 | 1787 GdkRectangle rect; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1788 gint pos = 0; |
3922 | 1789 gchar *ws; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1790 gchar *tag; |
3922 | 1791 gchar *bg = NULL; |
6982 | 1792 gint len; |
4032 | 1793 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1794 gint type; |
3922 | 1795 const gchar *c; |
7280 | 1796 gchar *amp; |
8334 | 1797 gint len_protocol; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1798 |
1428 | 1799 guint bold = 0, |
1800 italics = 0, | |
1801 underline = 0, | |
1802 strike = 0, | |
1803 sub = 0, | |
1804 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
1805 title = 0, |
8061 | 1806 pre = 0; |
1428 | 1807 |
3922 | 1808 GSList *fonts = NULL; |
8506 | 1809 GObject *object; |
8061 | 1810 GtkIMHtmlScalable *scalable = NULL; |
8677 | 1811 |
1812 g_return_if_fail (imhtml != NULL); | |
1813 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1814 g_return_if_fail (text != NULL); | |
3922 | 1815 c = text; |
6982 | 1816 len = strlen(text); |
3922 | 1817 ws = g_malloc(len + 1); |
1818 ws[0] = 0; | |
1428 | 1819 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1820 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1821 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1822 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1823 pos++; |
8061 | 1824 ws[wpos] = '\0'; |
1825 switch (type) | |
3922 | 1826 { |
1827 case 1: /* B */ | |
1828 case 2: /* BOLD */ | |
5101 | 1829 case 54: /* STRONG */ |
8677 | 1830 |
1831 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
1832 | |
1833 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD)) | |
8061 | 1834 gtk_imhtml_toggle_bold(imhtml); |
3922 | 1835 bold++; |
8061 | 1836 ws[0] = '\0'; wpos = 0; |
3922 | 1837 break; |
1838 case 3: /* /B */ | |
1839 case 4: /* /BOLD */ | |
5101 | 1840 case 55: /* /STRONG */ |
8677 | 1841 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 1842 ws[0] = '\0'; wpos = 0; |
1843 | |
3922 | 1844 if (bold) |
1845 bold--; | |
8677 | 1846 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD) && !imhtml->wbfo) |
8061 | 1847 gtk_imhtml_toggle_bold(imhtml); |
3922 | 1848 break; |
1849 case 5: /* I */ | |
1850 case 6: /* ITALIC */ | |
5101 | 1851 case 52: /* EM */ |
8677 | 1852 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 1853 ws[0] = '\0'; wpos = 0; |
8677 | 1854 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC)) |
8061 | 1855 gtk_imhtml_toggle_italic(imhtml); |
3922 | 1856 italics++; |
1857 break; | |
1858 case 7: /* /I */ | |
1859 case 8: /* /ITALIC */ | |
5101 | 1860 case 53: /* /EM */ |
8677 | 1861 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 1862 ws[0] = '\0'; wpos = 0; |
3922 | 1863 if (italics) |
1864 italics--; | |
8677 | 1865 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC) && !imhtml->wbfo) |
8061 | 1866 gtk_imhtml_toggle_italic(imhtml); |
3922 | 1867 break; |
1868 case 9: /* U */ | |
1869 case 10: /* UNDERLINE */ | |
8677 | 1870 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 1871 ws[0] = '\0'; wpos = 0; |
8677 | 1872 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
8061 | 1873 gtk_imhtml_toggle_underline(imhtml); |
3922 | 1874 underline++; |
1875 break; | |
1876 case 11: /* /U */ | |
1877 case 12: /* /UNDERLINE */ | |
8677 | 1878 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 1879 ws[0] = '\0'; wpos = 0; |
3922 | 1880 if (underline) |
1881 underline--; | |
8677 | 1882 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE) && !imhtml->wbfo) |
8061 | 1883 gtk_imhtml_toggle_underline(imhtml); |
3922 | 1884 break; |
1885 case 13: /* S */ | |
1886 case 14: /* STRIKE */ | |
8677 | 1887 /* FIXME: reimplement this */ |
3922 | 1888 strike++; |
1889 break; | |
1890 case 15: /* /S */ | |
1891 case 16: /* /STRIKE */ | |
8677 | 1892 /* FIXME: reimplement this */ |
3922 | 1893 if (strike) |
1894 strike--; | |
1895 break; | |
1896 case 17: /* SUB */ | |
8677 | 1897 /* FIXME: reimpliment this */ |
3922 | 1898 sub++; |
1899 break; | |
1900 case 18: /* /SUB */ | |
8677 | 1901 /* FIXME: reimpliment this */ |
3922 | 1902 if (sub) |
1903 sub--; | |
1904 break; | |
1905 case 19: /* SUP */ | |
8677 | 1906 /* FIXME: reimplement this */ |
3922 | 1907 sup++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1908 break; |
3922 | 1909 case 20: /* /SUP */ |
8677 | 1910 /* FIXME: reimplement this */ |
3922 | 1911 if (sup) |
1912 sup--; | |
1913 break; | |
1914 case 21: /* PRE */ | |
8677 | 1915 /* FIXME: reimplement this */ |
3922 | 1916 pre++; |
1917 break; | |
1918 case 22: /* /PRE */ | |
8677 | 1919 /* FIXME: reimplement this */ |
3922 | 1920 if (pre) |
1921 pre--; | |
1922 break; | |
1923 case 23: /* TITLE */ | |
8677 | 1924 /* FIXME: what was this supposed to do anyway? */ |
3922 | 1925 title++; |
1926 break; | |
1927 case 24: /* /TITLE */ | |
8677 | 1928 /* FIXME: make this undo whatever 23 was supposed to do */ |
3922 | 1929 if (title) { |
1930 if (options & GTK_IMHTML_NO_TITLE) { | |
1931 wpos = 0; | |
1932 ws [wpos] = '\0'; | |
1933 } | |
1934 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1935 } |
3922 | 1936 break; |
1937 case 25: /* BR */ | |
5174 | 1938 case 58: /* BR/ */ |
8061 | 1939 case 61: /* BR (opt) */ |
3922 | 1940 ws[wpos] = '\n'; |
1941 wpos++; | |
6982 | 1942 break; |
3922 | 1943 case 26: /* HR */ |
1944 case 42: /* HR (opt) */ | |
8726 | 1945 { |
1946 int minus; | |
1947 | |
3922 | 1948 ws[wpos++] = '\n'; |
8677 | 1949 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
1950 | |
5967 | 1951 scalable = gtk_imhtml_hr_new(); |
8061 | 1952 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
8677 | 1953 scalable->add_to(scalable, imhtml, iter); |
8726 | 1954 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + |
1955 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
1956 scalable->scale(scalable, rect.width - minus, rect.height); | |
8061 | 1957 imhtml->scalables = g_list_append(imhtml->scalables, scalable); |
1958 ws[0] = '\0'; wpos = 0; | |
7942 | 1959 ws[wpos++] = '\n'; |
8061 | 1960 |
3922 | 1961 break; |
8726 | 1962 } |
3922 | 1963 case 27: /* /FONT */ |
8677 | 1964 if (fonts && !imhtml->wbfo) { |
5967 | 1965 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 1966 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 1967 ws[0] = '\0'; wpos = 0; |
8177 | 1968 /* NEW_BIT (NEW_TEXT_BIT); */ |
8677 | 1969 |
8698 | 1970 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) { |
8061 | 1971 gtk_imhtml_toggle_fontface(imhtml, NULL); |
3922 | 1972 g_free (font->face); |
8061 | 1973 } |
8698 | 1974 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
8061 | 1975 gtk_imhtml_toggle_forecolor(imhtml, NULL); |
3922 | 1976 g_free (font->fore); |
8061 | 1977 } |
8698 | 1978 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
8061 | 1979 gtk_imhtml_toggle_backcolor(imhtml, NULL); |
3922 | 1980 g_free (font->back); |
8061 | 1981 } |
4032 | 1982 if (font->sml) |
1983 g_free (font->sml); | |
3922 | 1984 g_free (font); |
8309 | 1985 |
8698 | 1986 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 1987 gtk_imhtml_font_set_size(imhtml, 3); |
1988 | |
1989 fonts = fonts->next; | |
1990 if (fonts) { | |
1991 GtkIMHtmlFontDetail *font = fonts->data; | |
8677 | 1992 |
8698 | 1993 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8309 | 1994 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8698 | 1995 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8309 | 1996 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8698 | 1997 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
8309 | 1998 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8698 | 1999 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2000 gtk_imhtml_font_set_size(imhtml, font->size); |
2001 } | |
3922 | 2002 } |
8309 | 2003 break; |
3922 | 2004 case 28: /* /A */ |
8677 | 2005 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2006 gtk_imhtml_toggle_link(imhtml, NULL); | |
2007 ws[0] = '\0'; wpos = 0; | |
8061 | 2008 break; |
8118 | 2009 |
3922 | 2010 case 29: /* P */ |
2011 case 30: /* /P */ | |
2012 case 31: /* H3 */ | |
2013 case 32: /* /H3 */ | |
2014 case 33: /* HTML */ | |
2015 case 34: /* /HTML */ | |
2016 case 35: /* BODY */ | |
2017 case 36: /* /BODY */ | |
2018 case 37: /* FONT */ | |
2019 case 38: /* HEAD */ | |
2020 case 39: /* /HEAD */ | |
6982 | 2021 case 40: /* BINARY */ |
2022 case 41: /* /BINARY */ | |
3922 | 2023 break; |
2024 case 43: /* FONT (opt) */ | |
2025 { | |
4032 | 2026 gchar *color, *back, *face, *size, *sml; |
5967 | 2027 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 2028 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
2029 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
2030 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
2031 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 2032 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
2033 if (!(color || back || face || size || sml)) | |
3922 | 2034 break; |
8061 | 2035 |
8677 | 2036 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2037 ws[0] = '\0'; wpos = 0; |
2038 | |
5967 | 2039 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 2040 if (fonts) |
2041 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2042 |
8677 | 2043 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
3922 | 2044 font->fore = color; |
8061 | 2045 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8677 | 2046 } |
8309 | 2047 //else if (oldfont && oldfont->fore) |
2048 // font->fore = g_strdup(oldfont->fore); | |
8677 | 2049 |
2050 if (back && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { | |
3922 | 2051 font->back = back; |
8061 | 2052 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8309 | 2053 } |
2054 //else if (oldfont && oldfont->back) | |
2055 // font->back = g_strdup(oldfont->back); | |
8677 | 2056 |
2057 if (face && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) { | |
3922 | 2058 font->face = face; |
8061 | 2059 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8309 | 2060 } |
2061 //else if (oldfont && oldfont->face) | |
2062 // font->face = g_strdup(oldfont->face); | |
4032 | 2063 |
2064 if (sml) | |
2065 font->sml = sml; | |
2066 else if (oldfont && oldfont->sml) | |
2067 font->sml = g_strdup(oldfont->sml); | |
2068 | |
8677 | 2069 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) { |
3922 | 2070 if (*size == '+') { |
2071 sscanf (size + 1, "%hd", &font->size); | |
2072 font->size += 3; | |
2073 } else if (*size == '-') { | |
2074 sscanf (size + 1, "%hd", &font->size); | |
2075 font->size = MAX (0, 3 - font->size); | |
2076 } else if (isdigit (*size)) { | |
2077 sscanf (size, "%hd", &font->size); | |
8061 | 2078 } |
6042 | 2079 if (font->size > 100) |
2080 font->size = 100; | |
3922 | 2081 } else if (oldfont) |
2082 font->size = oldfont->size; | |
8309 | 2083 else |
2084 font->size = 3; | |
8698 | 2085 if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
2086 gtk_imhtml_font_set_size(imhtml, font->size); | |
3922 | 2087 g_free(size); |
2088 fonts = g_slist_prepend (fonts, font); | |
2089 } | |
2090 break; | |
2091 case 44: /* BODY (opt) */ | |
2092 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
2093 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
8677 | 2094 if (bgcolor && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
2095 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2096 ws[0] = '\0'; wpos = 0; |
8177 | 2097 /* NEW_BIT(NEW_TEXT_BIT); */ |
3922 | 2098 if (bg) |
2099 g_free(bg); | |
2100 bg = bgcolor; | |
8061 | 2101 gtk_imhtml_toggle_backcolor(imhtml, bg); |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
2102 } |
1428 | 2103 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2104 break; |
3922 | 2105 case 45: /* A (opt) */ |
2106 { | |
2107 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
8677 | 2108 if (href && (imhtml->format_functions & GTK_IMHTML_LINK)) { |
2109 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2110 ws[0] = '\0'; wpos = 0; |
8677 | 2111 gtk_imhtml_toggle_link(imhtml, href); |
3922 | 2112 } |
2993 | 2113 } |
3922 | 2114 break; |
4895 | 2115 case 46: /* IMG (opt) */ |
6982 | 2116 case 59: /* IMG */ |
4895 | 2117 { |
8677 | 2118 #if 0 |
2119 /* disabling this for now, it's easy to add it back... */ | |
6982 | 2120 GdkPixbuf *img = NULL; |
2121 const gchar *filename = NULL; | |
4895 | 2122 |
8677 | 2123 if (!(imhtml->format_functions & GTK_IMHTML_IMAGE)) |
2124 break; | |
2125 | |
6982 | 2126 if (images && images->data) { |
2127 img = images->data; | |
2128 images = images->next; | |
2129 filename = g_object_get_data(G_OBJECT(img), "filename"); | |
2130 g_object_ref(G_OBJECT(img)); | |
2131 } else { | |
2132 img = gtk_widget_render_icon(GTK_WIDGET(imhtml), | |
2133 GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_BUTTON, | |
2134 "gtkimhtml-missing-image"); | |
2135 } | |
4895 | 2136 |
6982 | 2137 scalable = gtk_imhtml_image_new(img, filename); |
8177 | 2138 /* NEW_BIT(NEW_SCALABLE_BIT); */ |
8677 | 2139 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
2140 scalable->add_to(scalable, imhtml, iter); | |
2141 scalable->scale(scalable, rect.width, rect.height); | |
2142 imhtml->scalables = g_list_append(imhtml->scalables, scalable); | |
2143 | |
6982 | 2144 g_object_unref(G_OBJECT(img)); |
8677 | 2145 #endif |
4895 | 2146 } |
3922 | 2147 case 47: /* P (opt) */ |
2148 case 48: /* H3 (opt) */ | |
5093 | 2149 case 49: /* HTML (opt) */ |
5101 | 2150 case 50: /* CITE */ |
2151 case 51: /* /CITE */ | |
8026 | 2152 case 56: /* SPAN (opt) */ |
8118 | 2153 /* Inline CSS Support - Douglas Thrift |
2154 * | |
2155 * color | |
8686 | 2156 * background |
8118 | 2157 * font-family |
2158 * font-size | |
8686 | 2159 * text-decoration: underline |
8118 | 2160 */ |
2161 { | |
8686 | 2162 gchar *style, *color, *background, *family, *size; |
2163 gchar *textdec; | |
8118 | 2164 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
2165 style = gtk_imhtml_get_html_opt (tag, "style="); | |
2166 | |
2167 if (!style) break; | |
2168 | |
2169 color = gtk_imhtml_get_css_opt (style, "color: "); | |
8686 | 2170 background = gtk_imhtml_get_css_opt (style, "background: "); |
8118 | 2171 family = gtk_imhtml_get_css_opt (style, |
2172 "font-family: "); | |
2173 size = gtk_imhtml_get_css_opt (style, "font-size: "); | |
8686 | 2174 textdec = gtk_imhtml_get_css_opt (style, "text-decoration: "); |
2175 | |
2176 if (!(color || family || size || background || textdec)) { | |
8120 | 2177 g_free(style); |
2178 break; | |
2179 } | |
8118 | 2180 |
8677 | 2181 |
2182 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8118 | 2183 ws[0] = '\0'; wpos = 0; |
8177 | 2184 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2185 |
2186 font = g_new0 (GtkIMHtmlFontDetail, 1); | |
2187 if (fonts) | |
2188 oldfont = fonts->data; | |
2189 | |
8677 | 2190 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8686 | 2191 { |
8118 | 2192 font->fore = color; |
8686 | 2193 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
2194 } | |
8118 | 2195 else if (oldfont && oldfont->fore) |
2196 font->fore = g_strdup(oldfont->fore); | |
2197 | |
8686 | 2198 if (background && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
2199 { | |
2200 font->back = background; | |
2201 gtk_imhtml_toggle_backcolor(imhtml, font->back); | |
2202 } | |
2203 else if (oldfont && oldfont->back) | |
8118 | 2204 font->back = g_strdup(oldfont->back); |
2205 | |
8677 | 2206 if (family && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8686 | 2207 { |
8118 | 2208 font->face = family; |
8686 | 2209 gtk_imhtml_toggle_fontface(imhtml, font->face); |
2210 } | |
8118 | 2211 else if (oldfont && oldfont->face) |
2212 font->face = g_strdup(oldfont->face); | |
2213 if (font->face && (atoi(font->face) > 100)) { | |
8677 | 2214 /* WTF is this? */ |
8118 | 2215 g_free(font->face); |
2216 font->face = g_strdup("100"); | |
2217 } | |
2218 | |
2219 if (oldfont && oldfont->sml) | |
2220 font->sml = g_strdup(oldfont->sml); | |
2221 | |
8677 | 2222 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_SHRINK|GTK_IMHTML_GROW))) { |
8686 | 2223 if (g_ascii_strcasecmp(size, "xx-small") == 0) |
2224 font->size = 1; | |
2225 else if (g_ascii_strcasecmp(size, "smaller") == 0 | |
2226 || g_ascii_strcasecmp(size, "x-small") == 0) | |
8118 | 2227 font->size = 2; |
8686 | 2228 else if (g_ascii_strcasecmp(size, "larger") == 0 |
2229 || g_ascii_strcasecmp(size, "medium") == 0) | |
8118 | 2230 font->size = 4; |
8686 | 2231 else if (g_ascii_strcasecmp(size, "large") == 0) |
2232 font->size = 5; | |
2233 else if (g_ascii_strcasecmp(size, "x-large") == 0) | |
2234 font->size = 6; | |
2235 else if (g_ascii_strcasecmp(size, "xx-large") == 0) | |
2236 font->size = 7; | |
8118 | 2237 else |
2238 font->size = 3; | |
8686 | 2239 gtk_imhtml_font_set_size(imhtml, font->size); |
2240 } | |
2241 else if (oldfont) | |
2242 { | |
2243 font->size = oldfont->size; | |
2244 } | |
2245 | |
2246 if (oldfont) | |
2247 { | |
2248 font->underline = oldfont->underline; | |
2249 } | |
2250 if (textdec && font->underline != 1 | |
8858 | 2251 && size |
8686 | 2252 && g_ascii_strcasecmp(size, "underline") == 0 |
2253 && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) | |
2254 { | |
2255 gtk_imhtml_toggle_underline(imhtml); | |
2256 font->underline = 1; | |
2257 } | |
8118 | 2258 |
2259 g_free(style); | |
2260 g_free(size); | |
2261 fonts = g_slist_prepend (fonts, font); | |
2262 } | |
2263 break; | |
5104 | 2264 case 57: /* /SPAN */ |
8118 | 2265 /* Inline CSS Support - Douglas Thrift */ |
8677 | 2266 if (fonts && !imhtml->wbfo) { |
8686 | 2267 GtkIMHtmlFontDetail *oldfont = NULL; |
8118 | 2268 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2269 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8118 | 2270 ws[0] = '\0'; wpos = 0; |
8177 | 2271 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2272 fonts = g_slist_remove (fonts, font); |
8692 | 2273 if (fonts) |
2274 oldfont = fonts->data; | |
2275 | |
2276 if (!oldfont) { | |
2277 gtk_imhtml_font_set_size(imhtml, 3); | |
2278 if (font->underline) | |
2279 gtk_imhtml_toggle_underline(imhtml); | |
2280 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
2281 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
2282 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
8686 | 2283 } |
8692 | 2284 else |
8686 | 2285 { |
8692 | 2286 |
2287 if (font->size != oldfont->size) | |
2288 gtk_imhtml_font_set_size(imhtml, oldfont->size); | |
2289 | |
2290 if (font->underline != oldfont->underline) | |
2291 gtk_imhtml_toggle_underline(imhtml); | |
2292 | |
2293 if (!oldfont->face || strcmp(font->face, oldfont->face) != 0) | |
2294 gtk_imhtml_toggle_fontface(imhtml, oldfont->face); | |
2295 | |
2296 if (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0) | |
2297 gtk_imhtml_toggle_forecolor(imhtml, oldfont->fore); | |
2298 | |
2299 if (!oldfont->back || strcmp(font->back, oldfont->back) != 0) | |
2300 gtk_imhtml_toggle_backcolor(imhtml, oldfont->back); | |
8686 | 2301 } |
8692 | 2302 |
2303 g_free (font->face); | |
2304 g_free (font->fore); | |
2305 g_free (font->back); | |
2306 g_free (font->sml); | |
2307 | |
8118 | 2308 g_free (font); |
2309 } | |
2310 break; | |
8026 | 2311 case 60: /* SPAN */ |
2993 | 2312 break; |
8061 | 2313 case 62: /* comment */ |
8177 | 2314 /* NEW_BIT (NEW_TEXT_BIT); */ |
8317 | 2315 ws[wpos] = '\0'; |
8677 | 2316 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2317 | |
6124 | 2318 if (imhtml->show_comments) |
2319 wpos = g_snprintf (ws, len, "%s", tag); | |
8177 | 2320 /* NEW_BIT (NEW_COMMENT_BIT); */ |
3922 | 2321 break; |
2322 default: | |
6882 | 2323 break; |
2993 | 2324 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2325 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2326 pos += tlen; |
4138 | 2327 if(tag) |
2328 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
8881 | 2329 } else if (gtk_imhtml_is_smiley (imhtml, fonts, c, &smilelen) || gtk_imhtml_is_smiley(imhtml, NULL, c, &smilelen)) { |
8473 | 2330 GtkIMHtmlFontDetail *fd; |
2331 | |
2332 gchar *sml = NULL; | |
2333 if (fonts) { | |
2334 fd = fonts->data; | |
2335 sml = fd->sml; | |
2336 } | |
8677 | 2337 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8505 | 2338 wpos = g_snprintf (ws, smilelen + 1, "%s", c); |
8473 | 2339 |
8677 | 2340 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, ws, iter); |
8473 | 2341 |
8505 | 2342 c += smilelen; |
2343 pos += smilelen; | |
8473 | 2344 wpos = 0; |
2345 ws[0] = 0; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2346 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
7280 | 2347 while(*amp) { |
2348 ws [wpos++] = *amp++; | |
2349 } | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2350 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2351 pos += tlen; |
1428 | 2352 } else if (*c == '\n') { |
2353 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 2354 ws[wpos] = '\n'; |
2355 wpos++; | |
8677 | 2356 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2357 ws[0] = '\0'; |
2358 wpos = 0; | |
8177 | 2359 /* NEW_BIT (NEW_TEXT_BIT); */ |
1428 | 2360 } |
2361 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2362 pos++; |
8334 | 2363 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ |
2364 while(len_protocol--){ | |
8677 | 2365 /* Skip the next len_protocol characters, but make sure they're |
8334 | 2366 copied into the ws array. |
2367 */ | |
2368 ws [wpos++] = *c++; | |
2369 pos++; | |
2370 } | |
8061 | 2371 } else if (*c) { |
1428 | 2372 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2373 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2374 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2375 break; |
1428 | 2376 } |
2377 } | |
8677 | 2378 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2379 ws[0] = '\0'; wpos = 0; |
2380 | |
8177 | 2381 /* NEW_BIT(NEW_TEXT_BIT); */ |
8061 | 2382 |
4032 | 2383 while (fonts) { |
5967 | 2384 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 2385 fonts = g_slist_remove (fonts, font); |
2386 if (font->face) | |
2387 g_free (font->face); | |
2388 if (font->fore) | |
2389 g_free (font->fore); | |
2390 if (font->back) | |
2391 g_free (font->back); | |
2392 if (font->sml) | |
2393 g_free (font->sml); | |
2394 g_free (font); | |
8677 | 2395 //if (str) |
2396 // str = g_string_append (str, "</FONT>"); | |
4032 | 2397 } |
8677 | 2398 #if 0 |
3922 | 2399 if (str) { |
1428 | 2400 while (bold) { |
8677 | 2401 // str = g_string_append (str, "</B>"); |
1428 | 2402 bold--; |
2403 } | |
2404 while (italics) { | |
8677 | 2405 // str = g_string_append (str, "</I>"); |
1428 | 2406 italics--; |
2407 } | |
2408 while (underline) { | |
8677 | 2409 //str = g_string_append (str, "</U>"); |
1428 | 2410 underline--; |
2411 } | |
2412 while (strike) { | |
8677 | 2413 //str = g_string_append (str, "</S>"); |
1428 | 2414 strike--; |
2415 } | |
2416 while (sub) { | |
8677 | 2417 //str = g_string_append (str, "</SUB>"); |
1428 | 2418 sub--; |
2419 } | |
2420 while (sup) { | |
8677 | 2421 //str = g_string_append (str, "</SUP>"); |
1428 | 2422 sup--; |
2423 } | |
2424 while (title) { | |
8677 | 2425 //str = g_string_append (str, "</TITLE>"); |
1428 | 2426 title--; |
2427 } | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2428 while (pre) { |
8677 | 2429 //str = g_string_append (str, "</PRE>"); |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2430 pre--; |
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2431 } |
1428 | 2432 } |
8677 | 2433 #endif |
4032 | 2434 g_free (ws); |
4630 | 2435 if(bg) |
2436 g_free(bg); | |
8677 | 2437 |
2438 if (!imhtml->wbfo) | |
8698 | 2439 gtk_imhtml_close_tags(imhtml, iter); |
8506 | 2440 |
2441 object = g_object_ref(G_OBJECT(imhtml)); | |
2442 g_signal_emit(object, signals[UPDATE_FORMAT], 0); | |
2443 g_object_unref(object); | |
2444 | |
3922 | 2445 } |
2446 | |
4892 | 2447 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
2448 { | |
4288 | 2449 g_hash_table_destroy(imhtml->smiley_data); |
2450 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 2451 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 2452 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 2453 imhtml->default_smilies = gtk_smiley_tree_new(); |
2454 } | |
8481 | 2455 |
3922 | 2456 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, |
4253 | 2457 gboolean show) |
2458 { | |
6124 | 2459 imhtml->show_comments = show; |
4253 | 2460 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2461 |
8456 | 2462 void gtk_imhtml_html_shortcuts (GtkIMHtml *imhtml, |
2463 gboolean allow) | |
2464 { | |
2465 imhtml->html_shortcuts = allow; | |
2466 } | |
2467 | |
2468 void gtk_imhtml_smiley_shortcuts (GtkIMHtml *imhtml, | |
2469 gboolean allow) | |
2470 { | |
2471 imhtml->smiley_shortcuts = allow; | |
2472 } | |
2473 | |
2474 void | |
2475 gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, gchar *protocol_name) { | |
2476 imhtml->protocol_name = protocol_name; | |
2477 } | |
2478 | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2479 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2480 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2481 { |
7991 | 2482 GList *del; |
3922 | 2483 GtkTextIter start, end; |
8427 | 2484 GObject *object = g_object_ref(G_OBJECT(imhtml)); |
7991 | 2485 |
3922 | 2486 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2487 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2488 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
7991 | 2489 |
2490 for(del = imhtml->scalables; del; del = del->next) { | |
2491 GtkIMHtmlScalable *scale = del->data; | |
2492 scale->free(scale); | |
2493 } | |
2494 g_list_free(imhtml->scalables); | |
2495 imhtml->scalables = NULL; | |
8061 | 2496 |
8719 | 2497 gtk_imhtml_close_tags(imhtml, &start); |
8481 | 2498 |
8427 | 2499 g_signal_emit(object, signals[CLEAR_FORMAT], 0); |
2500 g_object_unref(object); | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2501 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
2502 |
4046 | 2503 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
2504 { | |
5282 | 2505 GdkRectangle rect; |
2506 GtkTextIter iter; | |
4046 | 2507 |
5282 | 2508 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
2509 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2510 rect.y - rect.height); | |
2511 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
8061 | 2512 |
4046 | 2513 } |
5282 | 2514 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
2515 { | |
2516 GdkRectangle rect; | |
2517 GtkTextIter iter; | |
2518 | |
2519 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
2520 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2521 rect.y + rect.height); | |
2522 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
2523 } | |
4735 | 2524 |
5967 | 2525 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
6982 | 2526 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename) |
4735 | 2527 { |
5967 | 2528 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 2529 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 2530 |
5967 | 2531 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
2532 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
2533 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 2534 |
2535 im_image->pixbuf = img; | |
5012 | 2536 im_image->image = image; |
4895 | 2537 im_image->width = gdk_pixbuf_get_width(img); |
2538 im_image->height = gdk_pixbuf_get_height(img); | |
2539 im_image->mark = NULL; | |
6982 | 2540 im_image->filename = filename ? g_strdup(filename) : NULL; |
4895 | 2541 |
5046 | 2542 g_object_ref(img); |
4895 | 2543 return GTK_IMHTML_SCALABLE(im_image); |
2544 } | |
2545 | |
5967 | 2546 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 2547 { |
5967 | 2548 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 2549 |
2550 if(image->width > width || image->height > height){ | |
2551 GdkPixbuf *new_image = NULL; | |
2552 float factor; | |
2553 int new_width = image->width, new_height = image->height; | |
2554 | |
8588 | 2555 if(image->width > (width - 2)){ |
4895 | 2556 factor = (float)(width)/image->width; |
2557 new_width = width; | |
2558 new_height = image->height * factor; | |
2559 } | |
8588 | 2560 if(new_height >= (height - 2)){ |
4895 | 2561 factor = (float)(height)/new_height; |
2562 new_height = height; | |
2563 new_width = new_width * factor; | |
2564 } | |
2565 | |
5046 | 2566 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 2567 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 2568 g_object_unref(G_OBJECT(new_image)); |
2569 } | |
2570 } | |
2571 | |
5012 | 2572 static void write_img_to_file(GtkWidget *w, GtkFileSelection *sel) |
2573 { | |
2574 const gchar *filename = gtk_file_selection_get_filename(sel); | |
5967 | 2575 gchar *dirname; |
2576 GtkIMHtmlImage *image = g_object_get_data(G_OBJECT(sel), "GtkIMHtmlImage"); | |
5012 | 2577 gchar *type = NULL; |
5019 | 2578 GError *error = NULL; |
5015 | 2579 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 2580 GSList *formats = gdk_pixbuf_get_formats(); |
6162 | 2581 #else |
2582 char *basename = g_path_get_basename(filename); | |
2583 char *ext = strrchr(basename, '.'); | |
5959 | 2584 #endif |
5012 | 2585 |
5967 | 2586 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { |
2587 /* append a / if needed */ | |
2588 if (filename[strlen(filename) - 1] != '/') { | |
2589 dirname = g_strconcat(filename, "/", NULL); | |
2590 } else { | |
2591 dirname = g_strdup(filename); | |
2592 } | |
2593 gtk_file_selection_set_filename(sel, dirname); | |
2594 g_free(dirname); | |
5959 | 2595 return; |
5967 | 2596 } |
5959 | 2597 |
2598 #if GTK_CHECK_VERSION(2,2,0) | |
5012 | 2599 while(formats){ |
2600 GdkPixbufFormat *format = formats->data; | |
2601 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
2602 gpointer p = extensions; | |
2603 | |
2604 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
2605 gchar *fmt_ext = extensions[0]; | |
2606 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
2607 | |
2608 if(!strcmp(fmt_ext, file_ext)){ | |
2609 type = gdk_pixbuf_format_get_name(format); | |
2610 break; | |
2611 } | |
2612 | |
2613 extensions++; | |
2614 } | |
2615 | |
2616 g_strfreev(p); | |
2617 | |
2618 if(type) | |
2619 break; | |
2620 | |
2621 formats = formats->next; | |
2622 } | |
2623 | |
5020 | 2624 g_slist_free(formats); |
2625 #else | |
2626 /* this is really ugly code, but I think it will work */ | |
2627 if(ext) { | |
2628 ext++; | |
2629 if(!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) | |
2630 type = g_strdup("jpeg"); | |
2631 else if(!g_ascii_strcasecmp(ext, "png")) | |
2632 type = g_strdup("png"); | |
2633 } | |
2634 | |
2635 g_free(basename); | |
2636 #endif | |
2637 | |
5012 | 2638 /* If I can't find a valid type, I will just tell the user about it and then assume |
2639 it's a png */ | |
2640 if(!type){ | |
2641 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
5967 | 2642 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
5012 | 2643 type = g_strdup("png"); |
2644 } | |
2645 | |
5046 | 2646 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 2647 |
2648 if(error){ | |
2649 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, | |
2650 _("Error saving image: %s"), error->message); | |
2651 g_error_free(error); | |
2652 } | |
2653 | |
2654 g_free(type); | |
2655 } | |
2656 | |
5967 | 2657 static void gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) |
5012 | 2658 { |
5967 | 2659 GtkWidget *sel = gtk_file_selection_new(_("Save Image")); |
5012 | 2660 |
6982 | 2661 if (image->filename) |
2662 gtk_file_selection_set_filename(GTK_FILE_SELECTION(sel), image->filename); | |
5967 | 2663 g_object_set_data(G_OBJECT(sel), "GtkIMHtmlImage", image); |
5012 | 2664 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", |
2665 G_CALLBACK(write_img_to_file), sel); | |
2666 | |
2667 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->ok_button), "clicked", | |
2668 G_CALLBACK(gtk_widget_destroy), sel); | |
2669 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(sel)->cancel_button), "clicked", | |
8061 | 2670 G_CALLBACK(gtk_widget_destroy), sel); |
5012 | 2671 |
2672 gtk_widget_show(sel); | |
2673 } | |
2674 | |
5967 | 2675 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 2676 { |
2677 GdkEventButton *event_button = (GdkEventButton *) event; | |
2678 | |
2679 if (event->type == GDK_BUTTON_RELEASE) { | |
2680 if(event_button->button == 3) { | |
2681 GtkWidget *img, *item, *menu; | |
2682 gchar *text = g_strdup_printf(_("_Save Image...")); | |
2683 menu = gtk_menu_new(); | |
2684 | |
2685 /* buttons and such */ | |
2686 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
2687 item = gtk_image_menu_item_new_with_mnemonic(text); | |
2688 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 2689 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 2690 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
2691 | |
2692 gtk_widget_show_all(menu); | |
2693 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
2694 event_button->button, event_button->time); | |
2695 | |
2696 g_free(text); | |
2697 return TRUE; | |
2698 } | |
2699 } | |
2700 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
2701 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
2702 be caught by the regular GtkTextView menu */ | |
2703 else | |
2704 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
2705 | |
2706 } | |
5967 | 2707 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
2708 { | |
2709 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2710 | |
2711 g_object_unref(image->pixbuf); | |
6982 | 2712 if (image->filename) |
2713 g_free(image->filename); | |
5967 | 2714 g_free(scale); |
2715 } | |
2716 | |
2717 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2718 { | |
2719 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2720 GtkWidget *box = gtk_event_box_new(); | |
2721 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
2722 | |
2723 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
2724 | |
2725 gtk_widget_show(GTK_WIDGET(image->image)); | |
2726 gtk_widget_show(box); | |
2727 | |
2728 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); | |
2729 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
2730 } | |
2731 | |
2732 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
2733 { | |
2734 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
2735 | |
2736 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
2737 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
2738 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
2739 | |
2740 hr->sep = gtk_hseparator_new(); | |
2741 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
2742 gtk_widget_show(hr->sep); | |
2743 | |
2744 return GTK_IMHTML_SCALABLE(hr); | |
2745 } | |
2746 | |
2747 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
2748 { | |
8588 | 2749 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width - 2, 2); |
5967 | 2750 } |
2751 | |
2752 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2753 { | |
2754 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
2755 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
8698 | 2756 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>"); |
2757 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n"); | |
5967 | 2758 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); |
2759 } | |
2760 | |
2761 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
2762 { | |
2763 g_free(scale); | |
2764 } | |
7295 | 2765 |
2766 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
2767 { | |
2768 GtkTextIter iter, start, end; | |
2769 gboolean new_search = TRUE; | |
2770 | |
2771 g_return_val_if_fail(imhtml != NULL, FALSE); | |
2772 g_return_val_if_fail(text != NULL, FALSE); | |
8061 | 2773 |
7295 | 2774 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) |
2775 new_search = FALSE; | |
8061 | 2776 |
7295 | 2777 if (new_search) { |
2778 gtk_imhtml_search_clear(imhtml); | |
2779 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
2780 } else { | |
2781 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
8061 | 2782 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); |
7295 | 2783 } |
2784 imhtml->search_string = g_strdup(text); | |
2785 | |
7358 | 2786 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
2787 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 2788 &start, &end, NULL)) { |
2789 | |
2790 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
2791 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
2792 if (new_search) { | |
2793 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
8061 | 2794 do |
7295 | 2795 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); |
8061 | 2796 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
2797 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
7358 | 2798 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, |
7295 | 2799 &start, &end, NULL)); |
2800 } | |
2801 return TRUE; | |
2802 } | |
8061 | 2803 |
2804 gtk_imhtml_search_clear(imhtml); | |
2805 | |
7295 | 2806 return FALSE; |
2807 } | |
2808 | |
2809 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
2810 { | |
2811 GtkTextIter start, end; | |
8061 | 2812 |
7295 | 2813 g_return_if_fail(imhtml != NULL); |
8061 | 2814 |
7295 | 2815 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2816 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2817 | |
2818 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
2819 if (imhtml->search_string) | |
2820 g_free(imhtml->search_string); | |
2821 imhtml->search_string = NULL; | |
2822 } | |
8061 | 2823 |
8677 | 2824 static GtkTextTag *find_font_forecolor_tag(GtkIMHtml *imhtml, gchar *color) |
2825 { | |
2826 gchar str[18]; | |
2827 GtkTextTag *tag; | |
2828 | |
2829 g_snprintf(str, sizeof(str), "FORECOLOR %s", color); | |
2830 | |
2831 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2832 if (!tag) | |
2833 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", color, NULL); | |
2834 | |
2835 return tag; | |
2836 } | |
2837 | |
2838 static GtkTextTag *find_font_backcolor_tag(GtkIMHtml *imhtml, gchar *color) | |
2839 { | |
2840 gchar str[18]; | |
2841 GtkTextTag *tag; | |
2842 | |
2843 g_snprintf(str, sizeof(str), "BACKCOLOR %s", color); | |
2844 | |
2845 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2846 if (!tag) | |
2847 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "background", color, NULL); | |
2848 | |
2849 return tag; | |
2850 } | |
2851 | |
2852 static GtkTextTag *find_font_face_tag(GtkIMHtml *imhtml, gchar *face) | |
8061 | 2853 { |
8677 | 2854 gchar str[256]; |
2855 GtkTextTag *tag; | |
2856 | |
2857 g_snprintf(str, sizeof(str), "FONT FACE %s", face); | |
2858 str[255] = '\0'; | |
2859 | |
2860 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2861 if (!tag) | |
2862 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "family", face, NULL); | |
2863 | |
2864 return tag; | |
2865 } | |
2866 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2867 static void _init_original_fsize(GtkIMHtml *imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2868 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2869 GtkTextAttributes *attr; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2870 attr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2871 imhtml->original_fsize = pango_font_description_get_size(attr->font); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2872 gtk_text_attributes_unref(attr); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2873 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2874 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2875 static void _recalculate_font_sizes(GtkTextTag *tag, gpointer imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2876 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2877 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2878 int size; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2879 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2880 size = strtol(tag->name + 10, NULL, 10); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2881 g_object_set(G_OBJECT(tag), "size", |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2882 (gint) (GTK_IMHTML(imhtml)->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2883 ((double) _point_sizes[size-1] * GTK_IMHTML(imhtml)->zoom)), NULL); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2884 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2885 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2886 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2887 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2888 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2889 void gtk_imhtml_font_zoom(GtkIMHtml *imhtml, double zoom) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2890 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2891 GtkRcStyle *s; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2892 PangoFontDescription *font_desc = pango_font_description_new(); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2893 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2894 imhtml->zoom = zoom; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2895 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2896 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2897 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2898 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2899 gtk_text_tag_table_foreach(gtk_text_buffer_get_tag_table(imhtml->text_buffer), |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2900 _recalculate_font_sizes, imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2901 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2902 pango_font_description_set_size(font_desc, (gint)((double) imhtml->original_fsize * zoom)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2903 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2904 s = gtk_widget_get_modifier_style(GTK_WIDGET(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2905 s->font_desc = font_desc; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2906 gtk_widget_modify_style(GTK_WIDGET(imhtml), s); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2907 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2908 |
8677 | 2909 static GtkTextTag *find_font_size_tag(GtkIMHtml *imhtml, int size) |
2910 { | |
2911 gchar str[24]; | |
2912 GtkTextTag *tag; | |
2913 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2914 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2915 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2916 |
8677 | 2917 g_snprintf(str, sizeof(str), "FONT SIZE %d", size); |
2918 str[23] = '\0'; | |
2919 | |
2920 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
2921 if (!tag) { | |
2922 /* For reasons I don't understand, setting "scale" here scaled based on some default | |
2923 * size other than my theme's default size. Our size 4 was actually smaller than | |
2924 * our size 3 for me. So this works around that oddity. | |
2925 */ | |
2926 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "size", | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2927 (gint) (imhtml->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
2928 ((double) _point_sizes[size-1] * imhtml->zoom)), NULL); |
8061 | 2929 } |
2930 | |
8677 | 2931 return tag; |
2932 } | |
2933 | |
2934 static void remove_tag_by_prefix(GtkIMHtml *imhtml, const GtkTextIter *i, const GtkTextIter *e, | |
2935 const char *prefix, guint len, gboolean homo) | |
2936 { | |
2937 GSList *tags, *l; | |
2938 GtkTextIter iter; | |
2939 | |
2940 tags = gtk_text_iter_get_tags(i); | |
2941 | |
2942 for (l = tags; l; l = l->next) { | |
2943 GtkTextTag *tag = l->data; | |
2944 | |
2945 if (tag->name && !strncmp(tag->name, prefix, len)) | |
2946 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, i, e); | |
8061 | 2947 } |
2948 | |
8677 | 2949 g_slist_free(tags); |
2950 | |
2951 if (homo) | |
2952 return; | |
2953 | |
2954 iter = *i; | |
2955 | |
2956 while (gtk_text_iter_forward_char(&iter) && !gtk_text_iter_equal(&iter, e)) { | |
2957 if (gtk_text_iter_begins_tag(&iter, NULL)) { | |
2958 tags = gtk_text_iter_get_toggled_tags(&iter, TRUE); | |
2959 | |
2960 for (l = tags; l; l = l->next) { | |
2961 GtkTextTag *tag = l->data; | |
2962 | |
2963 if (tag->name && !strncmp(tag->name, prefix, len)) | |
2964 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e); | |
2965 } | |
2966 | |
2967 g_slist_free(tags); | |
2968 } | |
8061 | 2969 } |
8677 | 2970 } |
2971 | |
2972 static void remove_font_size(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
2973 { | |
2974 remove_tag_by_prefix(imhtml, i, e, "FONT SIZE ", 10, homo); | |
2975 } | |
2976 | |
2977 static void remove_font_face(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
2978 { | |
2979 remove_tag_by_prefix(imhtml, i, e, "FONT FACE ", 10, homo); | |
2980 } | |
2981 | |
2982 static void remove_font_forecolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
2983 { | |
2984 remove_tag_by_prefix(imhtml, i, e, "FORECOLOR ", 10, homo); | |
2985 } | |
2986 | |
2987 static void remove_font_backcolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
2988 { | |
2989 remove_tag_by_prefix(imhtml, i, e, "BACKCOLOR ", 10, homo); | |
2990 } | |
2991 | |
2992 static void remove_font_link(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
2993 { | |
2994 remove_tag_by_prefix(imhtml, i, e, "LINK ", 5, homo); | |
2995 } | |
2996 | |
2997 /* Editable stuff */ | |
2998 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
2999 { | |
3000 imhtml->insert_offset = gtk_text_iter_get_offset(iter); | |
3001 } | |
3002 | |
3003 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *end, gchar *text, gint len, GtkIMHtml *imhtml) | |
3004 { | |
3005 GtkTextIter start; | |
3006 | |
3007 if (!len) | |
3008 return; | |
3009 | |
3010 start = *end; | |
3011 gtk_text_iter_set_offset(&start, imhtml->insert_offset); | |
3012 | |
3013 if (imhtml->edit.bold) | |
3014 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, end); | |
3015 else | |
3016 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, end); | |
3017 | |
3018 if (imhtml->edit.italic) | |
3019 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end); | |
3020 else | |
3021 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, end); | |
3022 | |
3023 if (imhtml->edit.underline) | |
3024 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end); | |
3025 else | |
3026 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, end); | |
3027 | |
3028 if (imhtml->edit.forecolor) { | |
3029 remove_font_forecolor(imhtml, &start, end, TRUE); | |
3030 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3031 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3032 &start, end); | |
8061 | 3033 } |
3034 | |
8677 | 3035 if (imhtml->edit.backcolor) { |
3036 remove_font_backcolor(imhtml, &start, end, TRUE); | |
3037 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3038 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), | |
3039 &start, end); | |
3040 } | |
3041 | |
3042 if (imhtml->edit.fontface) { | |
3043 remove_font_face(imhtml, &start, end, TRUE); | |
3044 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3045 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3046 &start, end); | |
8061 | 3047 } |
8677 | 3048 |
3049 if (imhtml->edit.fontsize) { | |
3050 remove_font_size(imhtml, &start, end, TRUE); | |
3051 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3052 find_font_size_tag(imhtml, imhtml->edit.fontsize), | |
3053 &start, end); | |
3054 } | |
3055 | |
3056 if (imhtml->edit.link) { | |
3057 remove_font_link(imhtml, &start, end, TRUE); | |
3058 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3059 imhtml->edit.link, | |
3060 &start, end); | |
3061 } | |
3062 | |
8061 | 3063 } |
3064 | |
3065 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
3066 { | |
3067 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
8177 | 3068 /* |
3069 * We need a visible caret for accessibility, so mouseless | |
3070 * people can highlight stuff. | |
3071 */ | |
3072 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ | |
8061 | 3073 imhtml->editable = editable; |
8677 | 3074 imhtml->format_functions = GTK_IMHTML_ALL; |
3075 | |
3076 if (editable) | |
3077 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
3078 G_CALLBACK(mark_set_cb), imhtml); | |
3079 } | |
3080 | |
3081 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo) | |
3082 { | |
3083 g_return_if_fail(imhtml != NULL); | |
3084 | |
3085 imhtml->wbfo = wbfo; | |
8420 | 3086 } |
3087 | |
3088 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) | |
3089 { | |
3090 GObject *object = g_object_ref(G_OBJECT(imhtml)); | |
8677 | 3091 imhtml->format_functions = buttons; |
8420 | 3092 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); |
3093 g_object_unref(object); | |
8061 | 3094 } |
3095 | |
8788 | 3096 GtkIMHtmlButtons gtk_imhtml_get_format_functions(GtkIMHtml *imhtml) |
3097 { | |
3098 return imhtml->format_functions; | |
3099 } | |
8516 | 3100 |
3101 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, | |
3102 gboolean *italic, gboolean *underline) | |
8481 | 3103 { |
8677 | 3104 if (imhtml->edit.bold) |
3105 (*bold) = TRUE; | |
3106 if (imhtml->edit.italic) | |
3107 (*italic) = TRUE; | |
3108 if (imhtml->edit.underline) | |
3109 (*underline) = TRUE; | |
8481 | 3110 } |
3111 | |
8061 | 3112 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) |
3113 { | |
3114 return imhtml->editable; | |
3115 } | |
3116 | |
8677 | 3117 /* |
3118 * I had this crazy idea about changing the text cursor color to reflex the foreground color | |
3119 * of the text about to be entered. This is the place you'd do it, along with the place where | |
3120 * we actually set a new foreground color. | |
3121 * I may not do this, because people will bitch about Gaim overriding their gtk theme's cursor | |
3122 * colors. | |
3123 * | |
3124 * Just in case I do do this, I asked about what to set the secondary text cursor to. | |
3125 * | |
8719 | 3126 * (12:45:27) ?? ???: secondary_cursor_color = (rgb(background) + rgb(primary_cursor_color) ) / 2 |
3127 * (12:45:55) ?? ???: understand? | |
8677 | 3128 * (12:46:14) Tim: yeah. i didn't know there was an exact formula |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8729
diff
changeset
|
3129 * (12:46:56) ?? ???: u might need to extract separate each color from RGB |
8677 | 3130 */ |
3131 | |
3132 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, | |
3133 GtkIMHtml *imhtml) | |
3134 { | |
3135 GSList *tags, *l; | |
3136 GtkTextIter iter; | |
3137 | |
3138 if (mark != gtk_text_buffer_get_insert(buffer)) | |
3139 return; | |
3140 | |
3141 if (!gtk_text_buffer_get_char_count(buffer)) | |
3142 return; | |
3143 | |
3144 imhtml->edit.bold = imhtml->edit.italic = imhtml->edit.underline = FALSE; | |
3145 if (imhtml->edit.forecolor) | |
3146 g_free(imhtml->edit.forecolor); | |
3147 imhtml->edit.forecolor = NULL; | |
3148 if (imhtml->edit.backcolor) | |
3149 g_free(imhtml->edit.backcolor); | |
3150 imhtml->edit.backcolor = NULL; | |
3151 if (imhtml->edit.fontface) | |
3152 g_free(imhtml->edit.fontface); | |
3153 imhtml->edit.fontface = NULL; | |
3154 imhtml->edit.fontsize = 0; | |
3155 imhtml->edit.link = NULL; | |
3156 | |
3157 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3158 | |
3159 | |
3160 if (gtk_text_iter_is_end(&iter)) | |
3161 tags = gtk_text_iter_get_toggled_tags(&iter, FALSE); | |
3162 else | |
3163 tags = gtk_text_iter_get_tags(&iter); | |
3164 | |
3165 for (l = tags; l != NULL; l = l->next) { | |
3166 GtkTextTag *tag = GTK_TEXT_TAG(l->data); | |
3167 | |
3168 if (tag->name) { | |
3169 if (strcmp(tag->name, "BOLD") == 0) | |
3170 imhtml->edit.bold = TRUE; | |
3171 if (strcmp(tag->name, "ITALICS") == 0) | |
3172 imhtml->edit.italic = TRUE; | |
3173 if (strcmp(tag->name, "UNDERLINE") == 0) | |
3174 imhtml->edit.underline = TRUE; | |
3175 if (strncmp(tag->name, "FORECOLOR ", 10) == 0) | |
3176 imhtml->edit.forecolor = g_strdup(&(tag->name)[10]); | |
3177 if (strncmp(tag->name, "BACKCOLOR ", 10) == 0) | |
3178 imhtml->edit.backcolor = g_strdup(&(tag->name)[10]); | |
3179 if (strncmp(tag->name, "FONT FACE ", 10) == 0) | |
3180 imhtml->edit.fontface = g_strdup(&(tag->name)[10]); | |
3181 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) | |
3182 imhtml->edit.fontsize = strtol(&(tag->name)[10], NULL, 10); | |
8719 | 3183 if ((strncmp(tag->name, "LINK ", 5) == 0) && !gtk_text_iter_is_end(&iter)) |
8677 | 3184 imhtml->edit.link = tag; |
3185 } | |
3186 } | |
3187 | |
3188 g_slist_free(tags); | |
3189 } | |
3190 | |
8061 | 3191 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) |
3192 { | |
8481 | 3193 GObject *object; |
8677 | 3194 GtkTextIter start, end; |
3195 | |
3196 imhtml->edit.bold = !imhtml->edit.bold; | |
3197 | |
3198 if (imhtml->wbfo) { | |
3199 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3200 if (imhtml->edit.bold) | |
3201 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3202 else | |
3203 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3204 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3205 if (imhtml->edit.bold) | |
3206 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3207 else | |
3208 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3209 | |
8061 | 3210 } |
8481 | 3211 object = g_object_ref(G_OBJECT(imhtml)); |
3212 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_BOLD); | |
3213 g_object_unref(object); | |
3214 | |
8677 | 3215 return (imhtml->edit.bold != FALSE); |
8061 | 3216 } |
3217 | |
3218 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
3219 { | |
8481 | 3220 GObject *object; |
8677 | 3221 GtkTextIter start, end; |
3222 | |
3223 imhtml->edit.italic = !imhtml->edit.italic; | |
3224 | |
3225 if (imhtml->wbfo) { | |
3226 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3227 if (imhtml->edit.italic) | |
3228 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3229 else | |
3230 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3231 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3232 if (imhtml->edit.italic) | |
3233 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3234 else | |
3235 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
8061 | 3236 } |
8481 | 3237 object = g_object_ref(G_OBJECT(imhtml)); |
3238 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_ITALIC); | |
3239 g_object_unref(object); | |
3240 | |
8677 | 3241 return imhtml->edit.italic != FALSE; |
8061 | 3242 } |
3243 | |
3244 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) | |
3245 { | |
8481 | 3246 GObject *object; |
8677 | 3247 GtkTextIter start, end; |
3248 | |
3249 imhtml->edit.underline = !imhtml->edit.underline; | |
3250 | |
3251 if (imhtml->wbfo) { | |
3252 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3253 if (imhtml->edit.underline) | |
3254 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3255 else | |
3256 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3257 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3258 if (imhtml->edit.underline) | |
3259 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3260 else | |
3261 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
8061 | 3262 } |
8481 | 3263 object = g_object_ref(G_OBJECT(imhtml)); |
3264 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_UNDERLINE); | |
3265 g_object_unref(object); | |
3266 | |
8677 | 3267 return imhtml->edit.underline != FALSE; |
8061 | 3268 } |
3269 | |
3270 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) | |
3271 { | |
8677 | 3272 GtkTextIter start, end; |
8061 | 3273 |
3274 imhtml->edit.fontsize = size; | |
3275 | |
8677 | 3276 |
3277 if (imhtml->wbfo) { | |
3278 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3279 remove_font_size(imhtml, &start, &end, TRUE); | |
3280 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3281 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3282 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3283 remove_font_size(imhtml, &start, &end, FALSE); | |
3284 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3285 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3286 } |
8677 | 3287 |
8061 | 3288 } |
3289 | |
3290 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) | |
3291 { | |
8677 | 3292 GtkTextIter start, end; |
3293 | |
8061 | 3294 if (imhtml->edit.fontsize == 1) |
3295 return; | |
3296 | |
8677 | 3297 if (!imhtml->edit.fontsize) |
3298 imhtml->edit.fontsize = 2; | |
3299 else | |
3300 imhtml->edit.fontsize--; | |
3301 | |
3302 if (imhtml->wbfo) { | |
3303 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3304 remove_font_size(imhtml, &start, &end, TRUE); | |
3305 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3306 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3307 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3308 remove_font_size(imhtml, &start, &end, FALSE); | |
3309 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3310 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3311 } |
3312 } | |
3313 | |
3314 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) | |
3315 { | |
8677 | 3316 GtkTextIter start, end; |
3317 | |
8061 | 3318 if (imhtml->edit.fontsize == MAX_FONT_SIZE) |
3319 return; | |
3320 | |
8677 | 3321 if (!imhtml->edit.fontsize) |
3322 imhtml->edit.fontsize = 4; | |
3323 else | |
3324 imhtml->edit.fontsize++; | |
3325 | |
3326 if (imhtml->wbfo) { | |
3327 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3328 remove_font_size(imhtml, &start, &end, TRUE); | |
3329 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3330 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3331 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3332 remove_font_size(imhtml, &start, &end, FALSE); | |
3333 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3334 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3335 } |
3336 } | |
3337 | |
3338 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) | |
3339 { | |
8677 | 3340 GtkTextIter start, end; |
3341 | |
3342 if (imhtml->edit.forecolor != NULL) | |
3343 g_free(imhtml->edit.forecolor); | |
3344 | |
8429 | 3345 if (color) { |
8677 | 3346 imhtml->edit.forecolor = g_strdup(color); |
3347 if (imhtml->wbfo) { | |
3348 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3349 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3350 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3351 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), &start, &end); | |
3352 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3353 remove_font_forecolor(imhtml, &start, &end, FALSE); | |
3354 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3355 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3356 &start, &end); | |
3357 } | |
8061 | 3358 } else { |
3359 imhtml->edit.forecolor = NULL; | |
3360 } | |
3361 | |
3362 return imhtml->edit.forecolor != NULL; | |
3363 } | |
3364 | |
3365 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
3366 { | |
8677 | 3367 GtkTextIter start, end; |
3368 | |
3369 if (imhtml->edit.backcolor != NULL) | |
3370 g_free(imhtml->edit.backcolor); | |
3371 | |
8429 | 3372 if (color) { |
8677 | 3373 imhtml->edit.backcolor = g_strdup(color); |
3374 | |
3375 if (imhtml->wbfo) { | |
3376 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3377 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3378 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3379 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), &start, &end); | |
3380 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3381 remove_font_backcolor(imhtml, &start, &end, FALSE); | |
3382 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3383 find_font_backcolor_tag(imhtml, | |
3384 imhtml->edit.backcolor), &start, &end); | |
3385 } | |
8061 | 3386 } else { |
3387 imhtml->edit.backcolor = NULL; | |
3388 } | |
8677 | 3389 |
8061 | 3390 return imhtml->edit.backcolor != NULL; |
3391 } | |
3392 | |
3393 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) | |
3394 { | |
8677 | 3395 GtkTextIter start, end; |
3396 | |
3397 if (imhtml->edit.fontface != NULL) | |
3398 g_free(imhtml->edit.fontface); | |
3399 | |
8429 | 3400 if (face) { |
8677 | 3401 imhtml->edit.fontface = g_strdup(face); |
3402 | |
3403 if (imhtml->wbfo) { | |
3404 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3405 remove_font_face(imhtml, &start, &end, TRUE); | |
3406 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3407 find_font_face_tag(imhtml, imhtml->edit.fontface), &start, &end); | |
3408 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3409 remove_font_face(imhtml, &start, &end, FALSE); | |
3410 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3411 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3412 &start, &end); | |
3413 } | |
8061 | 3414 } else { |
3415 imhtml->edit.fontface = NULL; | |
3416 } | |
8677 | 3417 |
8061 | 3418 return imhtml->edit.fontface != NULL; |
3419 } | |
3420 | |
8677 | 3421 void gtk_imhtml_toggle_link(GtkIMHtml *imhtml, const char *url) |
8061 | 3422 { |
8677 | 3423 GtkTextIter start, end; |
3424 GtkTextTag *linktag; | |
3425 static guint linkno = 0; | |
3426 gchar str[48]; | |
3427 | |
3428 imhtml->edit.link = NULL; | |
3429 | |
3430 | |
3431 | |
3432 if (url) { | |
3433 g_snprintf(str, sizeof(str), "LINK %d", linkno++); | |
3434 str[47] = '\0'; | |
3435 | |
3436 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); | |
3437 g_object_set_data_full(G_OBJECT(linktag), "link_url", g_strdup(url), g_free); | |
3438 g_signal_connect(G_OBJECT(linktag), "event", G_CALLBACK(tag_event), NULL); | |
3439 | |
3440 if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3441 remove_font_link(imhtml, &start, &end, FALSE); | |
3442 gtk_text_buffer_apply_tag(imhtml->text_buffer, linktag, &start, &end); | |
3443 } | |
3444 } | |
3445 } | |
3446 | |
3447 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text) | |
3448 { | |
8061 | 3449 GtkTextIter iter; |
8677 | 3450 |
3451 gtk_imhtml_toggle_link(imhtml, url); | |
8061 | 3452 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); |
8677 | 3453 gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1); |
3454 gtk_imhtml_toggle_link(imhtml, NULL); | |
8061 | 3455 } |
3456 | |
3457 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) | |
3458 { | |
8677 | 3459 GtkTextMark *mark; |
8061 | 3460 GtkTextIter iter; |
8677 | 3461 |
3462 mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
3463 | |
3464 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3465 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, smiley, &iter); | |
3466 } | |
3467 | |
3468 void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter) | |
3469 { | |
8061 | 3470 GdkPixbuf *pixbuf = NULL; |
3471 GdkPixbufAnimation *annipixbuf = NULL; | |
3472 GtkWidget *icon = NULL; | |
3473 GtkTextChildAnchor *anchor; | |
8505 | 3474 char *unescaped = gaim_unescape_html(smiley); |
8061 | 3475 |
8505 | 3476 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); |
8061 | 3477 if(annipixbuf) { |
3478 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
3479 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
3480 if(pixbuf) | |
3481 icon = gtk_image_new_from_pixbuf(pixbuf); | |
3482 } else { | |
3483 icon = gtk_image_new_from_animation(annipixbuf); | |
3484 } | |
3485 } | |
3486 | |
3487 if (icon) { | |
8890 | 3488 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
3489 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", g_strdup(unescaped), g_free); | |
3490 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); | |
3491 | |
8061 | 3492 gtk_widget_show(icon); |
3493 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
8890 | 3494 } else { |
3495 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, -1); | |
8061 | 3496 } |
8890 | 3497 |
3498 g_free(unescaped); | |
8061 | 3499 } |
3500 | |
8677 | 3501 static const gchar *tag_to_html_start(GtkTextTag *tag) |
8061 | 3502 { |
8677 | 3503 const gchar *name; |
3504 static gchar buf[1024]; | |
3505 | |
3506 name = tag->name; | |
3507 g_return_val_if_fail(name != NULL, ""); | |
3508 | |
3509 if (strcmp(name, "BOLD") == 0) { | |
3510 return "<b>"; | |
3511 } else if (strcmp(name, "ITALICS") == 0) { | |
3512 return "<i>"; | |
3513 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3514 return "<u>"; | |
3515 } else if (strncmp(name, "LINK ", 5) == 0) { | |
3516 char *tmp = g_object_get_data(G_OBJECT(tag), "link_url"); | |
3517 if (tmp) { | |
3518 g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp); | |
3519 buf[sizeof(buf)-1] = '\0'; | |
3520 return buf; | |
3521 } else { | |
3522 return ""; | |
3523 } | |
3524 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3525 g_snprintf(buf, sizeof(buf), "<font color=\"%s\">", &name[10]); | |
3526 return buf; | |
3527 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3528 g_snprintf(buf, sizeof(buf), "<font back=\"%s\">", &name[10]); | |
3529 return buf; | |
3530 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3531 g_snprintf(buf, sizeof(buf), "<font face=\"%s\">", &name[10]); | |
3532 return buf; | |
3533 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3534 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); | |
3535 return buf; | |
3536 } else { | |
3537 return ""; | |
3538 } | |
8061 | 3539 } |
3540 | |
8677 | 3541 static const gchar *tag_to_html_end(GtkTextTag *tag) |
8061 | 3542 { |
8677 | 3543 const gchar *name; |
3544 | |
3545 name = tag->name; | |
3546 g_return_val_if_fail(name != NULL, ""); | |
3547 | |
3548 if (strcmp(name, "BOLD") == 0) { | |
3549 return "</b>"; | |
3550 } else if (strcmp(name, "ITALICS") == 0) { | |
3551 return "</i>"; | |
3552 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3553 return "</u>"; | |
3554 } else if (strncmp(name, "LINK ", 5) == 0) { | |
3555 return "</a>"; | |
3556 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3557 return "</font>"; | |
3558 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3559 return "</font>"; | |
3560 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3561 return "</font>"; | |
3562 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3563 return "</font>"; | |
3564 } else { | |
3565 return ""; | |
3566 } | |
3567 } | |
3568 | |
3569 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) | |
3570 { | |
3571 return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && | |
3572 !gtk_text_iter_has_tag(niter, GTK_TEXT_TAG(tag))) || | |
3573 gtk_text_iter_is_end(niter)); | |
8061 | 3574 } |
3575 | |
3576 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
3577 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
8677 | 3578 * check for tags that are toggled on, insert their html form, and push them on the queue. Then insert |
3579 * the actual text. Then check for tags that are toggled off and insert them, after checking the queue. | |
8735
92cbf9713795
[gaim-migrate @ 9490]
Christian Hammond <chipx86@chipx86.com>
parents:
8729
diff
changeset
|
3580 * Finally, replace <, >, &, and " with their HTML equivalent. |
8677 | 3581 */ |
8061 | 3582 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) |
3583 { | |
3584 gunichar c; | |
8677 | 3585 GtkTextIter iter, nextiter; |
8061 | 3586 GString *str = g_string_new(""); |
8677 | 3587 GSList *tags, *sl; |
3588 GQueue *q, *r; | |
3589 GtkTextTag *tag; | |
3590 | |
3591 q = g_queue_new(); | |
3592 r = g_queue_new(); | |
3593 | |
8061 | 3594 |
3595 gtk_text_iter_order(start, end); | |
8677 | 3596 nextiter = iter = *start; |
3597 gtk_text_iter_forward_char(&nextiter); | |
3598 | |
3599 /* First add the tags that are already in progress */ | |
3600 tags = gtk_text_iter_get_tags(start); | |
3601 | |
3602 for (sl = tags; sl; sl = sl->next) { | |
3603 tag = sl->data; | |
3604 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { | |
3605 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tag))); | |
3606 g_queue_push_tail(q, tag); | |
8061 | 3607 } |
3608 } | |
8677 | 3609 g_slist_free(tags); |
8061 | 3610 |
3611 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { | |
8677 | 3612 |
3613 tags = gtk_text_iter_get_tags(&iter); | |
3614 | |
3615 for (sl = tags; sl; sl = sl->next) { | |
3616 tag = sl->data; | |
3617 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { | |
3618 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tag))); | |
3619 g_queue_push_tail(q, tag); | |
3620 } | |
3621 } | |
3622 | |
3623 | |
8061 | 3624 if (c == 0xFFFC) { |
3625 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
8698 | 3626 char *text = NULL; |
3627 if (anchor) | |
3628 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext"); | |
3629 if (text) | |
3630 str = g_string_append(str, text); | |
8677 | 3631 } else if (c == '<') { |
3632 str = g_string_append(str, "<"); | |
3633 } else if (c == '>') { | |
3634 str = g_string_append(str, ">"); | |
3635 } else if (c == '&') { | |
3636 str = g_string_append(str, "&"); | |
3637 } else if (c == '"') { | |
3638 str = g_string_append(str, """); | |
3639 } else if (c == '\n') { | |
3640 str = g_string_append(str, "<br>"); | |
8061 | 3641 } else { |
8677 | 3642 str = g_string_append_unichar(str, c); |
3643 } | |
3644 | |
3645 tags = g_slist_reverse(tags); | |
3646 for (sl = tags; sl; sl = sl->next) { | |
3647 tag = sl->data; | |
3648 if (tag_ends_here(tag, &iter, &nextiter)) { | |
3649 | |
3650 GtkTextTag *tmp; | |
3651 | |
3652 while ((tmp = g_queue_pop_tail(q)) != tag) { | |
3653 if (tmp == NULL) | |
3654 break; | |
3655 | |
3656 if (!tag_ends_here(tmp, &iter, &nextiter)) | |
3657 g_queue_push_tail(r, tmp); | |
3658 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); | |
3659 } | |
3660 | |
3661 if (tmp == NULL) | |
3662 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); | |
3663 else | |
3664 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
3665 | |
3666 while ((tmp = g_queue_pop_head(r))) { | |
3667 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); | |
3668 g_queue_push_tail(q, tmp); | |
8061 | 3669 } |
3670 } | |
3671 } | |
8677 | 3672 |
3673 g_slist_free(tags); | |
8061 | 3674 gtk_text_iter_forward_char(&iter); |
8677 | 3675 gtk_text_iter_forward_char(&nextiter); |
8061 | 3676 } |
8677 | 3677 |
3678 while ((tag = g_queue_pop_tail(q))) | |
3679 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
3680 | |
3681 g_queue_free(q); | |
3682 g_queue_free(r); | |
8061 | 3683 return g_string_free(str, FALSE); |
3684 } | |
3685 | |
8698 | 3686 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter) |
8061 | 3687 { |
3688 if (imhtml->edit.bold) | |
3689 gtk_imhtml_toggle_bold(imhtml); | |
3690 | |
3691 if (imhtml->edit.italic) | |
3692 gtk_imhtml_toggle_italic(imhtml); | |
3693 | |
3694 if (imhtml->edit.underline) | |
3695 gtk_imhtml_toggle_underline(imhtml); | |
3696 | |
3697 if (imhtml->edit.forecolor) | |
3698 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
3699 | |
3700 if (imhtml->edit.backcolor) | |
3701 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
3702 | |
3703 if (imhtml->edit.fontface) | |
3704 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
3705 | |
8677 | 3706 imhtml->edit.fontsize = 0; |
3707 | |
8719 | 3708 if (imhtml->edit.link) |
3709 gtk_imhtml_toggle_link(imhtml, NULL); | |
3710 | |
8698 | 3711 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter); |
8061 | 3712 |
3713 } | |
3714 | |
3715 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
3716 { | |
3717 GtkTextIter start, end; | |
3718 | |
3719 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
3720 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3721 return gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
3722 } | |
3723 | |
8677 | 3724 char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml) |
3725 { | |
3726 int i, j, lines; | |
3727 GtkTextIter start, end; | |
3728 char **ret; | |
3729 | |
3730 lines = gtk_text_buffer_get_line_count(imhtml->text_buffer); | |
3731 ret = g_new0(char *, lines + 1); | |
3732 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
3733 end = start; | |
3734 gtk_text_iter_forward_to_line_end(&end); | |
3735 | |
3736 for (i = 0, j = 0; i < lines; i++) { | |
3737 ret[j] = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
3738 if (ret[j] != NULL) | |
3739 j++; | |
3740 gtk_text_iter_forward_line(&start); | |
3741 end = start; | |
3742 gtk_text_iter_forward_to_line_end(&end); | |
3743 } | |
3744 | |
3745 return ret; | |
3746 } | |
3747 | |
3748 char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop) | |
8061 | 3749 { |
8519 | 3750 GString *str = g_string_new(""); |
3751 GtkTextIter iter, end; | |
3752 gunichar c; | |
3753 | |
8677 | 3754 if (start == NULL) |
3755 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
3756 else | |
3757 iter = *start; | |
3758 | |
3759 if (stop == NULL) | |
3760 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3761 else | |
3762 end = *stop; | |
3763 | |
3764 gtk_text_iter_order(&iter, &end); | |
8519 | 3765 |
3766 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { | |
3767 if (c == 0xFFFC) { | |
8677 | 3768 GtkTextChildAnchor* anchor; |
3769 char *text = NULL; | |
3770 | |
3771 anchor = gtk_text_iter_get_child_anchor(&iter); | |
3772 if (anchor) | |
8698 | 3773 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext"); |
8677 | 3774 if (text) |
3775 str = g_string_append(str, text); | |
8519 | 3776 } else { |
3777 g_string_append_unichar(str, c); | |
3778 } | |
3779 gtk_text_iter_forward_char(&iter); | |
3780 } | |
3781 | |
3782 return g_string_free(str, FALSE); | |
8061 | 3783 } |