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