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