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