Mercurial > pidgin.yaz
annotate src/gtkimhtml.c @ 10274:3016b1b32339
[gaim-migrate @ 11424]
Don't allow sending oversized messages on MSN - they wouldn't get there, and
the switchboard server would disconnect us. Also fix up the oversized message
truncation which should have been truncating the messages anyway.
Add support for sending strikethrough on MSN (not that anyone can actually
enter strikethrough tags yet)
And a slight change to the building of chat user status icons.
committer: Tailor Script <tailor@pidgin.im>
author | Stu Tomlinson <stu@nosnilmot.com> |
---|---|
date | Sat, 27 Nov 2004 19:39:25 +0000 |
parents | e450f24d1fe1 |
children | ec140184437b |
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 |
10184 | 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; |
10184 | 1012 |
4032 | 1013 gobject_class->finalize = gtk_imhtml_finalize; |
10184 | 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 | |
8091 | 1335 if(gtk_imhtml_get_editable(imhtml) && sd->data){ |
9300 | 1336 switch (info) { |
10145 | 1337 case GTK_IMHTML_DRAG_URL: |
9300 | 1338 gaim_str_strip_cr(sd->data); |
1339 | |
1340 links = g_strsplit(sd->data, "\n", 0); | |
1341 while((link = *links++) != NULL){ | |
1342 if(gaim_str_has_prefix(link, "http://") || | |
1343 gaim_str_has_prefix(link, "https://") || | |
1344 gaim_str_has_prefix(link, "ftp://")){ | |
1345 gtk_imhtml_insert_link(imhtml, mark, link, link); | |
1346 } else if (link=='\0') { | |
1347 /* Ignore blank lines */ | |
1348 } else { | |
1349 /* Special reasons, aka images being put in via other tag, etc. */ | |
1350 } | |
8091 | 1351 } |
9300 | 1352 break; |
10145 | 1353 case GTK_IMHTML_DRAG_HTML: |
10243 | 1354 { |
1355 char *utf8 = NULL; | |
1356 /* Ewww. This is all because mozilla thinks that text/html is 'for internal use only.' | |
1357 * as explained by this comment in gtkhtml: | |
1358 * | |
1359 * FIXME This hack decides the charset of the selection. It seems that | |
1360 * mozilla/netscape alway use ucs2 for text/html | |
1361 * and openoffice.org seems to always use utf8 so we try to validate | |
1362 * the string as utf8 and if that fails we assume it is ucs2 | |
1363 * | |
1364 * See also the comment on text/html here: | |
1365 * http://mail.gnome.org/archives/gtk-devel-list/2001-September/msg00114.html | |
1366 */ | |
1367 if (sd->length >= 2 && !g_utf8_validate(text, sd->length - 1, NULL)) { | |
1368 utf8 = g_convert(text, sd->length, "UTF-8", "UCS-2", NULL, NULL, NULL); | |
1369 | |
1370 if (!utf8) { | |
9300 | 1371 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n"); |
1372 return; | |
1373 } | |
10243 | 1374 |
1375 if (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe || TRUE) { | |
1376 char *tmp; | |
1377 tmp = g_utf8_next_char(utf8); | |
1378 memmove(utf8, tmp, strlen(tmp) + 1); | |
1379 } | |
1380 } else if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
9300 | 1381 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); |
1382 return; | |
1383 } | |
10243 | 1384 |
1385 gtk_imhtml_insert_html_at_iter(imhtml, utf8 ? utf8 : text, 0, &iter); | |
1386 g_free(utf8); | |
9300 | 1387 break; |
10243 | 1388 } |
10145 | 1389 case GTK_IMHTML_DRAG_TEXT: |
1390 if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
1391 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); | |
1392 return; | |
1393 } else { | |
1394 char *tmp = gaim_escape_html(text); | |
1395 gtk_imhtml_insert_html_at_iter(imhtml, tmp, 0, &iter); | |
1396 g_free(tmp); | |
1397 } | |
1398 break; | |
9300 | 1399 default: |
10145 | 1400 gtk_drag_finish(dc, FALSE, FALSE, t); |
1401 return; | |
8091 | 1402 } |
1403 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); | |
1404 } else { | |
1405 gtk_drag_finish(dc, FALSE, FALSE, t); | |
1406 } | |
1407 } | |
1408 | |
4298 | 1409 /* this isn't used yet |
9300 | 1410 static void gtk_smiley_tree_remove (GtkSmileyTree *tree, |
4263 | 1411 GtkIMHtmlSmiley *smiley) |
4032 | 1412 { |
1413 GtkSmileyTree *t = tree; | |
4263 | 1414 const gchar *x = smiley->smile; |
4032 | 1415 gint len = 0; |
1416 | |
1417 while (*x) { | |
1418 gchar *pos; | |
1419 | |
1420 if (!t->values) | |
1421 return; | |
1422 | |
1423 pos = strchr (t->values->str, *x); | |
1424 if (pos) | |
1425 t = t->children [(int) pos - (int) t->values->str]; | |
1426 else | |
1427 return; | |
1428 | |
1429 x++; len++; | |
1430 } | |
1431 | |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1432 if (t->image) { |
4032 | 1433 t->image = NULL; |
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1434 } |
4032 | 1435 } |
4298 | 1436 */ |
1437 | |
4032 | 1438 |
1439 static gint | |
1440 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
1441 const gchar *text) | |
1442 { | |
1443 GtkSmileyTree *t = tree; | |
1444 const gchar *x = text; | |
1445 gint len = 0; | |
8505 | 1446 gchar *amp; |
1447 gint alen; | |
4032 | 1448 |
1449 while (*x) { | |
1450 gchar *pos; | |
1451 | |
1452 if (!t->values) | |
1453 break; | |
1454 | |
8505 | 1455 if(*x == '&' && gtk_imhtml_is_amp_escape(x, &, &alen)) { |
1456 len += alen - strlen(amp); | |
1457 x += alen - strlen(amp); | |
1458 pos = strchr (t->values->str, *amp); | |
1459 } | |
9636 | 1460 else if (*x == '<') /* Because we're all WYSIWYG now, a '<' |
1461 * char should only appear as the start of a tag. Perhaps a safer (but costlier) | |
1462 * check would be to call gtk_imhtml_is_tag on it */ | |
1463 return 0; | |
8505 | 1464 else |
1465 pos = strchr (t->values->str, *x); | |
1466 | |
4032 | 1467 if (pos) |
7371 | 1468 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1469 else |
1470 break; | |
1471 | |
1472 x++; len++; | |
1473 } | |
1474 | |
1475 if (t->image) | |
1476 return len; | |
1477 | |
1478 return 0; | |
1479 } | |
1480 | |
1481 void | |
4263 | 1482 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
1483 gchar *sml, | |
1484 GtkIMHtmlSmiley *smiley) | |
4032 | 1485 { |
1486 GtkSmileyTree *tree; | |
1487 g_return_if_fail (imhtml != NULL); | |
1488 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
7371 | 1489 |
4032 | 1490 if (sml == NULL) |
1491 tree = imhtml->default_smilies; | |
1492 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
1493 } else { | |
1494 tree = gtk_smiley_tree_new(); | |
4892 | 1495 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
4032 | 1496 } |
1497 | |
4263 | 1498 gtk_smiley_tree_insert (tree, smiley); |
4032 | 1499 } |
1500 | |
1501 static gboolean | |
1502 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
1503 GSList *fonts, | |
1504 const gchar *text, | |
1505 gint *len) | |
1506 { | |
1507 GtkSmileyTree *tree; | |
5967 | 1508 GtkIMHtmlFontDetail *font; |
4032 | 1509 char *sml = NULL; |
1510 | |
1511 if (fonts) { | |
1512 font = fonts->data; | |
1513 sml = font->sml; | |
1514 } | |
1515 | |
9029 | 1516 if (!sml) |
1517 sml = imhtml->protocol_name; | |
1518 | |
1519 if (!sml || !(tree = g_hash_table_lookup(imhtml->smiley_data, sml))) | |
4032 | 1520 tree = imhtml->default_smilies; |
9029 | 1521 |
4032 | 1522 if (tree == NULL) |
1523 return FALSE; | |
7371 | 1524 |
8505 | 1525 *len = gtk_smiley_tree_lookup (tree, text); |
4032 | 1526 return (*len > 0); |
1527 } | |
1528 | |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1529 GdkPixbufAnimation * |
4032 | 1530 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
1531 const gchar *sml, | |
1532 const gchar *text) | |
1533 { | |
1534 GtkSmileyTree *t; | |
1535 const gchar *x = text; | |
1536 if (sml == NULL) | |
1537 t = imhtml->default_smilies; | |
7371 | 1538 else |
4032 | 1539 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
7371 | 1540 |
4032 | 1541 |
1542 if (t == NULL) | |
1543 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1544 | |
1545 while (*x) { | |
1546 gchar *pos; | |
1547 | |
1548 if (!t->values) { | |
1549 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1550 } | |
7371 | 1551 |
4032 | 1552 pos = strchr (t->values->str, *x); |
1553 if (pos) { | |
7371 | 1554 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
4032 | 1555 } else { |
1556 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
1557 } | |
1558 x++; | |
1559 } | |
1560 | |
8890 | 1561 if (!t->image->file) |
1562 return NULL; | |
1563 | |
4263 | 1564 if (!t->image->icon) |
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1565 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
4263 | 1566 |
1567 return t->image->icon; | |
4032 | 1568 } |
8890 | 1569 |
4793 | 1570 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
3922 | 1571 *tag = g_strndup (string, strlen (x)); \ |
1572 *len = strlen (x) + 1; \ | |
1573 return TRUE; \ | |
1574 } \ | |
1575 (*type)++ | |
1428 | 1576 |
4793 | 1577 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
3922 | 1578 const gchar *c = string + strlen (x " "); \ |
1579 gchar e = '"'; \ | |
1580 gboolean quote = FALSE; \ | |
1581 while (*c) { \ | |
1582 if (*c == '"' || *c == '\'') { \ | |
1583 if (quote && (*c == e)) \ | |
1584 quote = !quote; \ | |
1585 else if (!quote) { \ | |
1586 quote = !quote; \ | |
1587 e = *c; \ | |
1588 } \ | |
1589 } else if (!quote && (*c == '>')) \ | |
1590 break; \ | |
1591 c++; \ | |
1592 } \ | |
1593 if (*c) { \ | |
1594 *tag = g_strndup (string, c - string); \ | |
1595 *len = c - string + 1; \ | |
1596 return TRUE; \ | |
1597 } \ | |
1598 } \ | |
1599 (*type)++ | |
1428 | 1600 |
1601 | |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1602 static gboolean |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1603 gtk_imhtml_is_amp_escape (const gchar *string, |
7280 | 1604 gchar **replace, |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1605 gint *length) |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1606 { |
7287 | 1607 static char buf[7]; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1608 g_return_val_if_fail (string != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1609 g_return_val_if_fail (replace != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1610 g_return_val_if_fail (length != NULL, FALSE); |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1611 |
4793 | 1612 if (!g_ascii_strncasecmp (string, "&", 5)) { |
7280 | 1613 *replace = "&"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1614 *length = 5; |
4793 | 1615 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
7280 | 1616 *replace = "<"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1617 *length = 4; |
4793 | 1618 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
7280 | 1619 *replace = ">"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1620 *length = 4; |
4793 | 1621 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
7280 | 1622 *replace = " "; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1623 *length = 6; |
4793 | 1624 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
7280 | 1625 *replace = "©"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1626 *length = 6; |
4793 | 1627 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
7280 | 1628 *replace = "\""; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1629 *length = 6; |
4793 | 1630 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
7280 | 1631 *replace = "®"; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1632 *length = 5; |
5093 | 1633 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
7280 | 1634 *replace = "\'"; |
5093 | 1635 *length = 6; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1636 } else if (*(string + 1) == '#') { |
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
1637 guint pound = 0; |
3004 | 1638 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
7287 | 1639 int buflen; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1640 if (*(string + 3 + (gint)log10 (pound)) != ';') |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1641 return FALSE; |
7287 | 1642 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
1643 buf[buflen] = '\0'; | |
7280 | 1644 *replace = buf; |
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1645 *length = 2; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1646 while (isdigit ((gint) string [*length])) (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1647 if (string [*length] == ';') (*length)++; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1648 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1649 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1650 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1651 } else { |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1652 return FALSE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1653 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1654 |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1655 return TRUE; |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1656 } |
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1657 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1658 static gboolean |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1659 gtk_imhtml_is_tag (const gchar *string, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1660 gchar **tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1661 gint *len, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1662 gint *type) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1663 { |
8061 | 1664 char *close; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1665 *type = 1; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1666 |
8118 | 1667 |
8061 | 1668 if (!(close = strchr (string, '>'))) |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1669 return FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1670 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1671 VALID_TAG ("B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1672 VALID_TAG ("BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1673 VALID_TAG ("/B"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1674 VALID_TAG ("/BOLD"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1675 VALID_TAG ("I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1676 VALID_TAG ("ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1677 VALID_TAG ("/I"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1678 VALID_TAG ("/ITALIC"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1679 VALID_TAG ("U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1680 VALID_TAG ("UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1681 VALID_TAG ("/U"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1682 VALID_TAG ("/UNDERLINE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1683 VALID_TAG ("S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1684 VALID_TAG ("STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1685 VALID_TAG ("/S"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1686 VALID_TAG ("/STRIKE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1687 VALID_TAG ("SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1688 VALID_TAG ("/SUB"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1689 VALID_TAG ("SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1690 VALID_TAG ("/SUP"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1691 VALID_TAG ("PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1692 VALID_TAG ("/PRE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1693 VALID_TAG ("TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1694 VALID_TAG ("/TITLE"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1695 VALID_TAG ("BR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1696 VALID_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1697 VALID_TAG ("/FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1698 VALID_TAG ("/A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1699 VALID_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1700 VALID_TAG ("/P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1701 VALID_TAG ("H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1702 VALID_TAG ("/H3"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1703 VALID_TAG ("HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1704 VALID_TAG ("/HTML"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1705 VALID_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1706 VALID_TAG ("/BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1707 VALID_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1708 VALID_TAG ("HEAD"); |
2993 | 1709 VALID_TAG ("/HEAD"); |
1710 VALID_TAG ("BINARY"); | |
1711 VALID_TAG ("/BINARY"); | |
5093 | 1712 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1713 VALID_OPT_TAG ("HR"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1714 VALID_OPT_TAG ("FONT"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1715 VALID_OPT_TAG ("BODY"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1716 VALID_OPT_TAG ("A"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1717 VALID_OPT_TAG ("IMG"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1718 VALID_OPT_TAG ("P"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1719 VALID_OPT_TAG ("H3"); |
5093 | 1720 VALID_OPT_TAG ("HTML"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1721 |
5101 | 1722 VALID_TAG ("CITE"); |
1723 VALID_TAG ("/CITE"); | |
1724 VALID_TAG ("EM"); | |
1725 VALID_TAG ("/EM"); | |
1726 VALID_TAG ("STRONG"); | |
1727 VALID_TAG ("/STRONG"); | |
1728 | |
5104 | 1729 VALID_OPT_TAG ("SPAN"); |
1730 VALID_TAG ("/SPAN"); | |
5174 | 1731 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
6982 | 1732 VALID_TAG ("IMG"); |
8026 | 1733 VALID_TAG("SPAN"); |
8061 | 1734 VALID_OPT_TAG("BR"); |
7988 | 1735 |
4793 | 1736 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
1737 gchar *e = strstr (string + strlen("!--"), "-->"); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1738 if (e) { |
9726 | 1739 /* |
1740 * If we uncomment the following line then HTML comments will be | |
1741 * hidden. This is good because it means when a WinAIM users pastes | |
1742 * part of a conversation to you, the screen names won't be | |
1743 * duplicated (because WinAIM pastes an HTML comment containing the | |
1744 * screen name, for some reason). | |
1745 * | |
1746 * However, uncommenting this is bad because we use HTML comment | |
1747 * tags to print timestamps to conversations (at least, I think...) | |
1748 * | |
1749 * KingAnt thinks it would be best to display timestamps using | |
1750 * something other than comment tags. | |
1751 */ | |
1752 /* *type = -1; */ | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1753 *len = e - string + strlen ("-->"); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1754 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1755 return TRUE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1756 } |
8118 | 1757 } |
1758 | |
8061 | 1759 *type = -1; |
1760 *len = close - string + 1; | |
1761 *tag = g_strndup(string, *len - 1); | |
1762 return TRUE; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1763 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1764 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1765 static gchar* |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1766 gtk_imhtml_get_html_opt (gchar *tag, |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1767 const gchar *opt) |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1768 { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1769 gchar *t = tag; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1770 gchar *e, *a; |
5177 | 1771 gchar *val; |
1772 gint len; | |
7280 | 1773 gchar *c; |
5177 | 1774 GString *ret; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1775 |
4793 | 1776 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1777 gboolean quote = FALSE; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1778 if (*t == '\0') break; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1779 while (*t && !((*t == ' ') && !quote)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1780 if (*t == '\"') |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1781 quote = ! quote; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1782 t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1783 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1784 while (*t && (*t == ' ')) t++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1785 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1786 |
4793 | 1787 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1788 t += strlen (opt); |
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 return NULL; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1791 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1792 |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1793 if ((*t == '\"') || (*t == '\'')) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1794 e = a = ++t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1795 while (*e && (*e != *(t - 1))) e++; |
2993 | 1796 if (*e == '\0') { |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1797 return NULL; |
5177 | 1798 } else |
1799 val = g_strndup(a, e - a); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1800 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1801 e = a = t; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1802 while (*e && !isspace ((gint) *e)) e++; |
5177 | 1803 val = g_strndup(a, e - a); |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1804 } |
5177 | 1805 |
1806 ret = g_string_new(""); | |
1807 e = val; | |
1808 while(*e) { | |
1809 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
7280 | 1810 ret = g_string_append(ret, c); |
5177 | 1811 e += len; |
1812 } else { | |
1813 ret = g_string_append_c(ret, *e); | |
1814 e++; | |
1815 } | |
1816 } | |
1817 | |
1818 g_free(val); | |
8568 | 1819 |
1820 return g_string_free(ret, FALSE); | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1821 } |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1822 |
8118 | 1823 /* Inline CSS Support - Douglas Thrift */ |
1824 static gchar* | |
1825 gtk_imhtml_get_css_opt (gchar *style, | |
1826 const gchar *opt) | |
1827 { | |
1828 gchar *t = style; | |
1829 gchar *e, *a; | |
1830 gchar *val; | |
1831 gint len; | |
1832 gchar *c; | |
1833 GString *ret; | |
1834 | |
1835 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
8177 | 1836 /* gboolean quote = FALSE; */ |
8118 | 1837 if (*t == '\0') break; |
1838 while (*t && !((*t == ' ') /*&& !quote*/)) { | |
1839 /* if (*t == '\"') | |
8177 | 1840 quote = ! quote; */ |
8118 | 1841 t++; |
1842 } | |
1843 while (*t && (*t == ' ')) t++; | |
1844 } | |
1845 | |
1846 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
1847 t += strlen (opt); | |
1848 } else { | |
1849 return NULL; | |
1850 } | |
1851 | |
1852 /* if ((*t == '\"') || (*t == '\'')) { | |
1853 e = a = ++t; | |
1854 while (*e && (*e != *(t - 1))) e++; | |
1855 if (*e == '\0') { | |
1856 return NULL; | |
1857 } else | |
1858 val = g_strndup(a, e - a); | |
1859 } else { | |
1860 e = a = t; | |
1861 while (*e && !isspace ((gint) *e)) e++; | |
1862 val = g_strndup(a, e - a); | |
1863 }*/ | |
1864 | |
1865 e = a = t; | |
1866 while (*e && *e != ';') e++; | |
1867 val = g_strndup(a, e - a); | |
1868 | |
1869 ret = g_string_new(""); | |
1870 e = val; | |
1871 while(*e) { | |
1872 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
1873 ret = g_string_append(ret, c); | |
1874 e += len; | |
1875 } else { | |
1876 ret = g_string_append_c(ret, *e); | |
1877 e++; | |
1878 } | |
1879 } | |
1880 | |
1881 g_free(val); | |
1882 val = ret->str; | |
1883 g_string_free(ret, FALSE); | |
1884 return val; | |
1885 } | |
3922 | 1886 |
8334 | 1887 static const char *accepted_protocols[] = { |
1888 "http://", | |
1889 "https://", | |
1890 "ftp://" | |
1891 }; | |
1892 | |
1893 static const int accepted_protocols_size = 3; | |
1894 | |
1895 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so | |
1896 the caller knows how long the protocol string is. */ | |
1897 int gtk_imhtml_is_protocol(const char *text) | |
1898 { | |
1899 gint i; | |
1900 | |
1901 for(i=0; i<accepted_protocols_size; i++){ | |
1902 if( strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0 ){ | |
1903 return strlen(accepted_protocols[i]); | |
1904 } | |
1905 } | |
1906 return 0; | |
1907 } | |
1908 | |
8677 | 1909 /* |
1910 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming | |
1911 | |
1912 | |
1913 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :) | |
1914 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/> | |
1915 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz | |
1916 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add | |
1917 [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? | |
1918 [20:00] <KingAnt> marv: Right | |
1919 [20:00] <marv> alright | |
1920 | |
1921 Here's my plan with IMImages. make gtk_imhtml_[append|insert]_text_with_images instead just | |
1922 gtkimhtml_[append|insert]_text (hrm maybe it should be called html instead of text), add a | |
1923 function for gaim to register for look up images, i.e. gtk_imhtml_set_get_img_fnc, so that | |
1924 images can be looked up like that, instead of passing a GSList of them. | |
1925 */ | |
1926 | |
1927 void gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, | |
1928 const gchar *text, | |
1929 GtkIMHtmlOptions options, | |
1930 GSList *unused) | |
1428 | 1931 { |
8677 | 1932 GtkTextIter iter, ins, sel; |
1933 GdkRectangle rect; | |
1934 int y, height, ins_offset = 0, sel_offset = 0; | |
1935 gboolean fixins = FALSE, fixsel = FALSE; | |
1936 | |
1937 g_return_if_fail (imhtml != NULL); | |
1938 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
1939 g_return_if_fail (text != NULL); | |
1940 | |
1941 | |
1942 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1943 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, gtk_text_buffer_get_insert(imhtml->text_buffer)); | |
1944 if (gtk_text_iter_equal(&iter, &ins) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1945 fixins = TRUE; | |
1946 ins_offset = gtk_text_iter_get_offset(&ins); | |
1947 } | |
1948 | |
1949 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &sel, gtk_text_buffer_get_selection_bound(imhtml->text_buffer)); | |
1950 if (gtk_text_iter_equal(&iter, &sel) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
1951 fixsel = TRUE; | |
1952 sel_offset = gtk_text_iter_get_offset(&sel); | |
1953 } | |
1954 | |
1955 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
1956 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
1957 | |
1958 | |
1959 if(((y + height) - (rect.y + rect.height)) > height | |
1960 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
1961 options |= GTK_IMHTML_NO_SCROLL; | |
1962 } | |
1963 | |
1964 gtk_imhtml_insert_html_at_iter(imhtml, text, options, &iter); | |
1965 | |
1966 if (fixins) { | |
1967 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins, ins_offset); | |
1968 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_insert(imhtml->text_buffer), &ins); | |
1969 } | |
1970 | |
1971 if (fixsel) { | |
1972 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &sel, sel_offset); | |
1973 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_selection_bound(imhtml->text_buffer), &sel); | |
1974 } | |
1975 | |
1976 if (!(options & GTK_IMHTML_NO_SCROLL)) { | |
8729 | 1977 gtk_imhtml_scroll_to_end(imhtml); |
8677 | 1978 } |
1979 } | |
1980 | |
8729 | 1981 void gtk_imhtml_scroll_to_end(GtkIMHtml *imhtml) |
1982 { | |
1983 GtkTextIter iter; | |
1984 /* If this seems backwards at first glance, well it's not. | |
1985 * It means scroll such that the mark is closest to the top, | |
1986 * and closest to the right as possible. Remember kids, you have | |
1987 * to scroll left to move a given spot closest to the right, | |
1988 * and scroll down to move a spot closest to the top. | |
1989 */ | |
1990 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
1991 gtk_text_iter_set_line_offset(&iter, 0); | |
1992 gtk_text_buffer_move_mark(imhtml->text_buffer, imhtml->scrollpoint, &iter); | |
1993 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), imhtml->scrollpoint, | |
1994 0, TRUE, 1.0, 0.0); | |
1995 } | |
1996 | |
8677 | 1997 void gtk_imhtml_insert_html_at_iter(GtkIMHtml *imhtml, |
1998 const gchar *text, | |
1999 GtkIMHtmlOptions options, | |
2000 GtkTextIter *iter) | |
2001 { | |
8061 | 2002 GdkRectangle rect; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2003 gint pos = 0; |
3922 | 2004 gchar *ws; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2005 gchar *tag; |
3922 | 2006 gchar *bg = NULL; |
6982 | 2007 gint len; |
4032 | 2008 gint tlen, smilelen, wpos=0; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2009 gint type; |
3922 | 2010 const gchar *c; |
7280 | 2011 gchar *amp; |
8334 | 2012 gint len_protocol; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2013 |
1428 | 2014 guint bold = 0, |
2015 italics = 0, | |
2016 underline = 0, | |
2017 strike = 0, | |
2018 sub = 0, | |
2019 sup = 0, | |
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2020 title = 0, |
8061 | 2021 pre = 0; |
1428 | 2022 |
10217 | 2023 gboolean br = FALSE; |
2024 | |
3922 | 2025 GSList *fonts = NULL; |
8506 | 2026 GObject *object; |
8061 | 2027 GtkIMHtmlScalable *scalable = NULL; |
8677 | 2028 |
2029 g_return_if_fail (imhtml != NULL); | |
2030 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
2031 g_return_if_fail (text != NULL); | |
3922 | 2032 c = text; |
6982 | 2033 len = strlen(text); |
3922 | 2034 ws = g_malloc(len + 1); |
2035 ws[0] = 0; | |
1428 | 2036 |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2037 while (pos < len) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2038 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2039 c++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2040 pos++; |
8061 | 2041 ws[wpos] = '\0'; |
10217 | 2042 br = FALSE; |
8061 | 2043 switch (type) |
3922 | 2044 { |
2045 case 1: /* B */ | |
2046 case 2: /* BOLD */ | |
5101 | 2047 case 54: /* STRONG */ |
8677 | 2048 |
2049 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2050 | |
2051 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD)) | |
8061 | 2052 gtk_imhtml_toggle_bold(imhtml); |
3922 | 2053 bold++; |
8061 | 2054 ws[0] = '\0'; wpos = 0; |
3922 | 2055 break; |
2056 case 3: /* /B */ | |
2057 case 4: /* /BOLD */ | |
5101 | 2058 case 55: /* /STRONG */ |
8677 | 2059 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2060 ws[0] = '\0'; wpos = 0; |
2061 | |
3922 | 2062 if (bold) |
2063 bold--; | |
8677 | 2064 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD) && !imhtml->wbfo) |
8061 | 2065 gtk_imhtml_toggle_bold(imhtml); |
3922 | 2066 break; |
2067 case 5: /* I */ | |
2068 case 6: /* ITALIC */ | |
5101 | 2069 case 52: /* EM */ |
8677 | 2070 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2071 ws[0] = '\0'; wpos = 0; |
8677 | 2072 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC)) |
8061 | 2073 gtk_imhtml_toggle_italic(imhtml); |
3922 | 2074 italics++; |
2075 break; | |
2076 case 7: /* /I */ | |
2077 case 8: /* /ITALIC */ | |
5101 | 2078 case 53: /* /EM */ |
8677 | 2079 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2080 ws[0] = '\0'; wpos = 0; |
3922 | 2081 if (italics) |
2082 italics--; | |
8677 | 2083 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC) && !imhtml->wbfo) |
8061 | 2084 gtk_imhtml_toggle_italic(imhtml); |
3922 | 2085 break; |
2086 case 9: /* U */ | |
2087 case 10: /* UNDERLINE */ | |
8677 | 2088 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2089 ws[0] = '\0'; wpos = 0; |
8677 | 2090 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
8061 | 2091 gtk_imhtml_toggle_underline(imhtml); |
3922 | 2092 underline++; |
2093 break; | |
2094 case 11: /* /U */ | |
2095 case 12: /* /UNDERLINE */ | |
8677 | 2096 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2097 ws[0] = '\0'; wpos = 0; |
3922 | 2098 if (underline) |
2099 underline--; | |
8677 | 2100 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE) && !imhtml->wbfo) |
8061 | 2101 gtk_imhtml_toggle_underline(imhtml); |
3922 | 2102 break; |
2103 case 13: /* S */ | |
2104 case 14: /* STRIKE */ | |
9924 | 2105 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2106 ws[0] = '\0'; wpos = 0; | |
2107 if ((strike == 0) && (imhtml->format_functions & GTK_IMHTML_STRIKE)) | |
2108 gtk_imhtml_toggle_strike(imhtml); | |
3922 | 2109 strike++; |
2110 break; | |
2111 case 15: /* /S */ | |
2112 case 16: /* /STRIKE */ | |
9924 | 2113 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2114 ws[0] = '\0'; wpos = 0; | |
3922 | 2115 if (strike) |
2116 strike--; | |
9924 | 2117 if ((strike == 0) && (imhtml->format_functions & GTK_IMHTML_STRIKE) && !imhtml->wbfo) |
2118 gtk_imhtml_toggle_strike(imhtml); | |
3922 | 2119 break; |
2120 case 17: /* SUB */ | |
8677 | 2121 /* FIXME: reimpliment this */ |
3922 | 2122 sub++; |
2123 break; | |
2124 case 18: /* /SUB */ | |
8677 | 2125 /* FIXME: reimpliment this */ |
3922 | 2126 if (sub) |
2127 sub--; | |
2128 break; | |
2129 case 19: /* SUP */ | |
8677 | 2130 /* FIXME: reimplement this */ |
3922 | 2131 sup++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2132 break; |
3922 | 2133 case 20: /* /SUP */ |
8677 | 2134 /* FIXME: reimplement this */ |
3922 | 2135 if (sup) |
2136 sup--; | |
2137 break; | |
2138 case 21: /* PRE */ | |
8677 | 2139 /* FIXME: reimplement this */ |
3922 | 2140 pre++; |
2141 break; | |
2142 case 22: /* /PRE */ | |
8677 | 2143 /* FIXME: reimplement this */ |
3922 | 2144 if (pre) |
2145 pre--; | |
2146 break; | |
2147 case 23: /* TITLE */ | |
8677 | 2148 /* FIXME: what was this supposed to do anyway? */ |
3922 | 2149 title++; |
2150 break; | |
2151 case 24: /* /TITLE */ | |
8677 | 2152 /* FIXME: make this undo whatever 23 was supposed to do */ |
3922 | 2153 if (title) { |
2154 if (options & GTK_IMHTML_NO_TITLE) { | |
2155 wpos = 0; | |
2156 ws [wpos] = '\0'; | |
2157 } | |
2158 title--; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2159 } |
3922 | 2160 break; |
2161 case 25: /* BR */ | |
5174 | 2162 case 58: /* BR/ */ |
8061 | 2163 case 61: /* BR (opt) */ |
3922 | 2164 ws[wpos] = '\n'; |
2165 wpos++; | |
10217 | 2166 br = TRUE; |
6982 | 2167 break; |
3922 | 2168 case 26: /* HR */ |
2169 case 42: /* HR (opt) */ | |
8726 | 2170 { |
2171 int minus; | |
2172 | |
3922 | 2173 ws[wpos++] = '\n'; |
8677 | 2174 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2175 | |
5967 | 2176 scalable = gtk_imhtml_hr_new(); |
8061 | 2177 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
8677 | 2178 scalable->add_to(scalable, imhtml, iter); |
8726 | 2179 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + |
2180 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
2181 scalable->scale(scalable, rect.width - minus, rect.height); | |
8061 | 2182 imhtml->scalables = g_list_append(imhtml->scalables, scalable); |
2183 ws[0] = '\0'; wpos = 0; | |
7942 | 2184 ws[wpos++] = '\n'; |
8061 | 2185 |
3922 | 2186 break; |
8726 | 2187 } |
3922 | 2188 case 27: /* /FONT */ |
8677 | 2189 if (fonts && !imhtml->wbfo) { |
5967 | 2190 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2191 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2192 ws[0] = '\0'; wpos = 0; |
8177 | 2193 /* NEW_BIT (NEW_TEXT_BIT); */ |
8677 | 2194 |
8698 | 2195 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) { |
8061 | 2196 gtk_imhtml_toggle_fontface(imhtml, NULL); |
3922 | 2197 g_free (font->face); |
8061 | 2198 } |
8698 | 2199 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
8061 | 2200 gtk_imhtml_toggle_forecolor(imhtml, NULL); |
3922 | 2201 g_free (font->fore); |
8061 | 2202 } |
8698 | 2203 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
8061 | 2204 gtk_imhtml_toggle_backcolor(imhtml, NULL); |
3922 | 2205 g_free (font->back); |
8061 | 2206 } |
4032 | 2207 if (font->sml) |
2208 g_free (font->sml); | |
8309 | 2209 |
8698 | 2210 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2211 gtk_imhtml_font_set_size(imhtml, 3); |
2212 | |
9245 | 2213 g_free(font); |
2214 | |
8309 | 2215 fonts = fonts->next; |
2216 if (fonts) { | |
2217 GtkIMHtmlFontDetail *font = fonts->data; | |
8677 | 2218 |
8698 | 2219 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8309 | 2220 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8698 | 2221 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8309 | 2222 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8698 | 2223 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
8309 | 2224 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8698 | 2225 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
8309 | 2226 gtk_imhtml_font_set_size(imhtml, font->size); |
2227 } | |
3922 | 2228 } |
8309 | 2229 break; |
3922 | 2230 case 28: /* /A */ |
8677 | 2231 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2232 gtk_imhtml_toggle_link(imhtml, NULL); | |
2233 ws[0] = '\0'; wpos = 0; | |
8061 | 2234 break; |
8118 | 2235 |
3922 | 2236 case 29: /* P */ |
2237 case 30: /* /P */ | |
2238 case 31: /* H3 */ | |
2239 case 32: /* /H3 */ | |
2240 case 33: /* HTML */ | |
2241 case 34: /* /HTML */ | |
2242 case 35: /* BODY */ | |
2243 case 36: /* /BODY */ | |
2244 case 37: /* FONT */ | |
2245 case 38: /* HEAD */ | |
2246 case 39: /* /HEAD */ | |
6982 | 2247 case 40: /* BINARY */ |
2248 case 41: /* /BINARY */ | |
3922 | 2249 break; |
2250 case 43: /* FONT (opt) */ | |
2251 { | |
4032 | 2252 gchar *color, *back, *face, *size, *sml; |
5967 | 2253 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
3922 | 2254 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
2255 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
2256 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
2257 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
4032 | 2258 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
2259 if (!(color || back || face || size || sml)) | |
3922 | 2260 break; |
8061 | 2261 |
8677 | 2262 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2263 ws[0] = '\0'; wpos = 0; |
2264 | |
5967 | 2265 font = g_new0 (GtkIMHtmlFontDetail, 1); |
3922 | 2266 if (fonts) |
2267 oldfont = fonts->data; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2268 |
8677 | 2269 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
3922 | 2270 font->fore = color; |
8061 | 2271 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
8677 | 2272 } |
8309 | 2273 //else if (oldfont && oldfont->fore) |
2274 // font->fore = g_strdup(oldfont->fore); | |
8677 | 2275 |
2276 if (back && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { | |
3922 | 2277 font->back = back; |
8061 | 2278 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
8309 | 2279 } |
2280 //else if (oldfont && oldfont->back) | |
2281 // font->back = g_strdup(oldfont->back); | |
8677 | 2282 |
2283 if (face && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) { | |
3922 | 2284 font->face = face; |
8061 | 2285 gtk_imhtml_toggle_fontface(imhtml, font->face); |
8309 | 2286 } |
2287 //else if (oldfont && oldfont->face) | |
2288 // font->face = g_strdup(oldfont->face); | |
4032 | 2289 |
2290 if (sml) | |
2291 font->sml = sml; | |
2292 else if (oldfont && oldfont->sml) | |
2293 font->sml = g_strdup(oldfont->sml); | |
2294 | |
8677 | 2295 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) { |
3922 | 2296 if (*size == '+') { |
2297 sscanf (size + 1, "%hd", &font->size); | |
2298 font->size += 3; | |
2299 } else if (*size == '-') { | |
2300 sscanf (size + 1, "%hd", &font->size); | |
2301 font->size = MAX (0, 3 - font->size); | |
2302 } else if (isdigit (*size)) { | |
2303 sscanf (size, "%hd", &font->size); | |
8061 | 2304 } |
6042 | 2305 if (font->size > 100) |
2306 font->size = 100; | |
3922 | 2307 } else if (oldfont) |
2308 font->size = oldfont->size; | |
8309 | 2309 else |
2310 font->size = 3; | |
8698 | 2311 if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
2312 gtk_imhtml_font_set_size(imhtml, font->size); | |
3922 | 2313 g_free(size); |
2314 fonts = g_slist_prepend (fonts, font); | |
2315 } | |
2316 break; | |
2317 case 44: /* BODY (opt) */ | |
2318 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
2319 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
8677 | 2320 if (bgcolor && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
2321 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2322 ws[0] = '\0'; wpos = 0; |
8177 | 2323 /* NEW_BIT(NEW_TEXT_BIT); */ |
3922 | 2324 if (bg) |
2325 g_free(bg); | |
2326 bg = bgcolor; | |
8061 | 2327 gtk_imhtml_toggle_backcolor(imhtml, bg); |
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
2328 } |
1428 | 2329 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2330 break; |
3922 | 2331 case 45: /* A (opt) */ |
2332 { | |
2333 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
8677 | 2334 if (href && (imhtml->format_functions & GTK_IMHTML_LINK)) { |
2335 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8061 | 2336 ws[0] = '\0'; wpos = 0; |
8677 | 2337 gtk_imhtml_toggle_link(imhtml, href); |
3922 | 2338 } |
2993 | 2339 } |
3922 | 2340 break; |
4895 | 2341 case 46: /* IMG (opt) */ |
6982 | 2342 case 59: /* IMG */ |
4895 | 2343 { |
8962 | 2344 const char *id; |
2345 | |
2346 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2347 ws[0] = '\0'; wpos = 0; | |
4895 | 2348 |
8677 | 2349 if (!(imhtml->format_functions & GTK_IMHTML_IMAGE)) |
2350 break; | |
2351 | |
8962 | 2352 id = gtk_imhtml_get_html_opt(tag, "ID="); |
9186 | 2353 if (!id) |
2354 break; | |
8962 | 2355 gtk_imhtml_insert_image_at_iter(imhtml, atoi(id), iter); |
2356 break; | |
4895 | 2357 } |
3922 | 2358 case 47: /* P (opt) */ |
2359 case 48: /* H3 (opt) */ | |
5093 | 2360 case 49: /* HTML (opt) */ |
5101 | 2361 case 50: /* CITE */ |
2362 case 51: /* /CITE */ | |
8026 | 2363 case 56: /* SPAN (opt) */ |
8118 | 2364 /* Inline CSS Support - Douglas Thrift |
2365 * | |
2366 * color | |
8686 | 2367 * background |
8118 | 2368 * font-family |
2369 * font-size | |
8686 | 2370 * text-decoration: underline |
8118 | 2371 */ |
2372 { | |
8686 | 2373 gchar *style, *color, *background, *family, *size; |
2374 gchar *textdec; | |
8118 | 2375 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
2376 style = gtk_imhtml_get_html_opt (tag, "style="); | |
2377 | |
2378 if (!style) break; | |
2379 | |
2380 color = gtk_imhtml_get_css_opt (style, "color: "); | |
8686 | 2381 background = gtk_imhtml_get_css_opt (style, "background: "); |
8118 | 2382 family = gtk_imhtml_get_css_opt (style, |
2383 "font-family: "); | |
2384 size = gtk_imhtml_get_css_opt (style, "font-size: "); | |
8686 | 2385 textdec = gtk_imhtml_get_css_opt (style, "text-decoration: "); |
2386 | |
2387 if (!(color || family || size || background || textdec)) { | |
8120 | 2388 g_free(style); |
2389 break; | |
2390 } | |
8118 | 2391 |
8677 | 2392 |
2393 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
8118 | 2394 ws[0] = '\0'; wpos = 0; |
8177 | 2395 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2396 |
2397 font = g_new0 (GtkIMHtmlFontDetail, 1); | |
2398 if (fonts) | |
2399 oldfont = fonts->data; | |
2400 | |
8677 | 2401 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
8686 | 2402 { |
8118 | 2403 font->fore = color; |
8686 | 2404 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
2405 } | |
8118 | 2406 else if (oldfont && oldfont->fore) |
2407 font->fore = g_strdup(oldfont->fore); | |
2408 | |
8686 | 2409 if (background && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
2410 { | |
2411 font->back = background; | |
2412 gtk_imhtml_toggle_backcolor(imhtml, font->back); | |
2413 } | |
2414 else if (oldfont && oldfont->back) | |
8118 | 2415 font->back = g_strdup(oldfont->back); |
2416 | |
8677 | 2417 if (family && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) |
8686 | 2418 { |
8118 | 2419 font->face = family; |
8686 | 2420 gtk_imhtml_toggle_fontface(imhtml, font->face); |
2421 } | |
8118 | 2422 else if (oldfont && oldfont->face) |
2423 font->face = g_strdup(oldfont->face); | |
2424 if (font->face && (atoi(font->face) > 100)) { | |
8677 | 2425 /* WTF is this? */ |
9696 | 2426 /* Maybe it sets a max size on the font face? I seem to |
2427 * remember bad things happening if the font size was | |
2428 * 2 billion */ | |
8118 | 2429 g_free(font->face); |
2430 font->face = g_strdup("100"); | |
2431 } | |
2432 | |
2433 if (oldfont && oldfont->sml) | |
2434 font->sml = g_strdup(oldfont->sml); | |
2435 | |
8677 | 2436 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_SHRINK|GTK_IMHTML_GROW))) { |
8686 | 2437 if (g_ascii_strcasecmp(size, "xx-small") == 0) |
2438 font->size = 1; | |
2439 else if (g_ascii_strcasecmp(size, "smaller") == 0 | |
2440 || g_ascii_strcasecmp(size, "x-small") == 0) | |
8118 | 2441 font->size = 2; |
8686 | 2442 else if (g_ascii_strcasecmp(size, "larger") == 0 |
2443 || g_ascii_strcasecmp(size, "medium") == 0) | |
8118 | 2444 font->size = 4; |
8686 | 2445 else if (g_ascii_strcasecmp(size, "large") == 0) |
2446 font->size = 5; | |
2447 else if (g_ascii_strcasecmp(size, "x-large") == 0) | |
2448 font->size = 6; | |
2449 else if (g_ascii_strcasecmp(size, "xx-large") == 0) | |
2450 font->size = 7; | |
8118 | 2451 else |
2452 font->size = 3; | |
8686 | 2453 gtk_imhtml_font_set_size(imhtml, font->size); |
2454 } | |
2455 else if (oldfont) | |
2456 { | |
2457 font->size = oldfont->size; | |
2458 } | |
2459 | |
2460 if (oldfont) | |
2461 { | |
2462 font->underline = oldfont->underline; | |
2463 } | |
2464 if (textdec && font->underline != 1 | |
9025 | 2465 && g_ascii_strcasecmp(textdec, "underline") == 0 |
8686 | 2466 && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
2467 { | |
2468 gtk_imhtml_toggle_underline(imhtml); | |
2469 font->underline = 1; | |
2470 } | |
8118 | 2471 |
2472 g_free(style); | |
2473 g_free(size); | |
2474 fonts = g_slist_prepend (fonts, font); | |
2475 } | |
2476 break; | |
5104 | 2477 case 57: /* /SPAN */ |
8118 | 2478 /* Inline CSS Support - Douglas Thrift */ |
8677 | 2479 if (fonts && !imhtml->wbfo) { |
8686 | 2480 GtkIMHtmlFontDetail *oldfont = NULL; |
8118 | 2481 GtkIMHtmlFontDetail *font = fonts->data; |
8677 | 2482 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8118 | 2483 ws[0] = '\0'; wpos = 0; |
8177 | 2484 /* NEW_BIT (NEW_TEXT_BIT); */ |
8118 | 2485 fonts = g_slist_remove (fonts, font); |
8692 | 2486 if (fonts) |
2487 oldfont = fonts->data; | |
2488 | |
2489 if (!oldfont) { | |
2490 gtk_imhtml_font_set_size(imhtml, 3); | |
2491 if (font->underline) | |
2492 gtk_imhtml_toggle_underline(imhtml); | |
2493 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
2494 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
2495 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
8686 | 2496 } |
8692 | 2497 else |
8686 | 2498 { |
8692 | 2499 |
2500 if (font->size != oldfont->size) | |
2501 gtk_imhtml_font_set_size(imhtml, oldfont->size); | |
2502 | |
2503 if (font->underline != oldfont->underline) | |
2504 gtk_imhtml_toggle_underline(imhtml); | |
2505 | |
9286 | 2506 if (font->face && (!oldfont->face || strcmp(font->face, oldfont->face) != 0)) |
8692 | 2507 gtk_imhtml_toggle_fontface(imhtml, oldfont->face); |
2508 | |
9286 | 2509 if (font->fore && (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0)) |
8692 | 2510 gtk_imhtml_toggle_forecolor(imhtml, oldfont->fore); |
2511 | |
9286 | 2512 if (font->back && (!oldfont->back || strcmp(font->back, oldfont->back) != 0)) |
8692 | 2513 gtk_imhtml_toggle_backcolor(imhtml, oldfont->back); |
8686 | 2514 } |
8692 | 2515 |
2516 g_free (font->face); | |
2517 g_free (font->fore); | |
2518 g_free (font->back); | |
2519 g_free (font->sml); | |
2520 | |
8118 | 2521 g_free (font); |
2522 } | |
2523 break; | |
8026 | 2524 case 60: /* SPAN */ |
2993 | 2525 break; |
8061 | 2526 case 62: /* comment */ |
8177 | 2527 /* NEW_BIT (NEW_TEXT_BIT); */ |
8317 | 2528 ws[wpos] = '\0'; |
9465 | 2529 |
8677 | 2530 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
2531 | |
9465 | 2532 if (imhtml->show_comments && !(options & GTK_IMHTML_NO_COMMENTS)) |
6124 | 2533 wpos = g_snprintf (ws, len, "%s", tag); |
8177 | 2534 /* NEW_BIT (NEW_COMMENT_BIT); */ |
3922 | 2535 break; |
2536 default: | |
6882 | 2537 break; |
2993 | 2538 } |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2539 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2540 pos += tlen; |
4138 | 2541 if(tag) |
2542 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
9029 | 2543 } else if (gtk_imhtml_is_smiley(imhtml, fonts, c, &smilelen)) { |
8473 | 2544 GtkIMHtmlFontDetail *fd; |
2545 | |
2546 gchar *sml = NULL; | |
2547 if (fonts) { | |
2548 fd = fonts->data; | |
2549 sml = fd->sml; | |
2550 } | |
9029 | 2551 if (!sml) |
2552 sml = imhtml->protocol_name; | |
2553 | |
8677 | 2554 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8505 | 2555 wpos = g_snprintf (ws, smilelen + 1, "%s", c); |
8473 | 2556 |
8677 | 2557 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, ws, iter); |
8473 | 2558 |
8505 | 2559 c += smilelen; |
2560 pos += smilelen; | |
8473 | 2561 wpos = 0; |
2562 ws[0] = 0; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2563 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
7280 | 2564 while(*amp) { |
2565 ws [wpos++] = *amp++; | |
2566 } | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2567 c += tlen; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2568 pos += tlen; |
1428 | 2569 } else if (*c == '\n') { |
2570 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
3922 | 2571 ws[wpos] = '\n'; |
2572 wpos++; | |
8677 | 2573 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2574 ws[0] = '\0'; |
2575 wpos = 0; | |
8177 | 2576 /* NEW_BIT (NEW_TEXT_BIT); */ |
10217 | 2577 } else if (!br) { /* Don't insert a space immediately after an HTML break */ |
9621 | 2578 /* A newline is defined by HTML as whitespace, which means we have to replace it with a word boundary. |
2579 * word breaks vary depending on the language used, so the correct thing to do is to use Pango to determine | |
2580 * what language this is, determine the proper word boundary to use, and insert that. I'm just going to insert | |
2581 * a space instead. What are the non-English speakers going to do? Complain in a language I'll understand? | |
2582 * Bu-wahaha! */ | |
2583 ws[wpos] = ' '; | |
2584 wpos++; | |
2585 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
2586 ws[0] = '\0'; | |
2587 wpos = 0; | |
1428 | 2588 } |
2589 c++; | |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2590 pos++; |
8334 | 2591 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ |
2592 while(len_protocol--){ | |
8677 | 2593 /* Skip the next len_protocol characters, but make sure they're |
8334 | 2594 copied into the ws array. |
2595 */ | |
2596 ws [wpos++] = *c++; | |
2597 pos++; | |
2598 } | |
8061 | 2599 } else if (*c) { |
1428 | 2600 ws [wpos++] = *c++; |
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2601 pos++; |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2602 } else { |
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2603 break; |
1428 | 2604 } |
2605 } | |
8677 | 2606 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
8061 | 2607 ws[0] = '\0'; wpos = 0; |
2608 | |
8177 | 2609 /* NEW_BIT(NEW_TEXT_BIT); */ |
8061 | 2610 |
4032 | 2611 while (fonts) { |
5967 | 2612 GtkIMHtmlFontDetail *font = fonts->data; |
4032 | 2613 fonts = g_slist_remove (fonts, font); |
2614 if (font->face) | |
2615 g_free (font->face); | |
2616 if (font->fore) | |
2617 g_free (font->fore); | |
2618 if (font->back) | |
2619 g_free (font->back); | |
2620 if (font->sml) | |
2621 g_free (font->sml); | |
2622 g_free (font); | |
2623 } | |
8932 | 2624 |
2625 g_free(ws); | |
2626 if (bg) | |
4630 | 2627 g_free(bg); |
8677 | 2628 |
2629 if (!imhtml->wbfo) | |
8698 | 2630 gtk_imhtml_close_tags(imhtml, iter); |
8506 | 2631 |
2632 object = g_object_ref(G_OBJECT(imhtml)); | |
2633 g_signal_emit(object, signals[UPDATE_FORMAT], 0); | |
2634 g_object_unref(object); | |
2635 | |
3922 | 2636 } |
2637 | |
4892 | 2638 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
2639 { | |
4288 | 2640 g_hash_table_destroy(imhtml->smiley_data); |
2641 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
4892 | 2642 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
4902 | 2643 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
4288 | 2644 imhtml->default_smilies = gtk_smiley_tree_new(); |
2645 } | |
8481 | 2646 |
3922 | 2647 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, |
4253 | 2648 gboolean show) |
2649 { | |
6124 | 2650 imhtml->show_comments = show; |
4253 | 2651 } |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2652 |
8962 | 2653 void |
9029 | 2654 gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, const gchar *protocol_name) { |
2655 if (imhtml->protocol_name) | |
2656 g_free(imhtml->protocol_name); | |
2657 imhtml->protocol_name = protocol_name ? g_strdup(protocol_name) : NULL; | |
8456 | 2658 } |
2659 | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2660 void |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2661 gtk_imhtml_clear (GtkIMHtml *imhtml) |
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2662 { |
7991 | 2663 GList *del; |
3922 | 2664 GtkTextIter start, end; |
8427 | 2665 GObject *object = g_object_ref(G_OBJECT(imhtml)); |
7991 | 2666 |
3922 | 2667 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
2668 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
2669 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
7991 | 2670 |
2671 for(del = imhtml->scalables; del; del = del->next) { | |
2672 GtkIMHtmlScalable *scale = del->data; | |
2673 scale->free(scale); | |
2674 } | |
2675 g_list_free(imhtml->scalables); | |
2676 imhtml->scalables = NULL; | |
8061 | 2677 |
8719 | 2678 gtk_imhtml_close_tags(imhtml, &start); |
8481 | 2679 |
8427 | 2680 g_signal_emit(object, signals[CLEAR_FORMAT], 0); |
2681 g_object_unref(object); | |
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2682 } |
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
2683 |
4046 | 2684 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
2685 { | |
5282 | 2686 GdkRectangle rect; |
2687 GtkTextIter iter; | |
4046 | 2688 |
5282 | 2689 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
2690 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2691 rect.y - rect.height); | |
2692 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
8061 | 2693 |
4046 | 2694 } |
5282 | 2695 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
2696 { | |
2697 GdkRectangle rect; | |
2698 GtkTextIter iter; | |
2699 | |
2700 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
2701 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
2702 rect.y + rect.height); | |
2703 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
2704 } | |
4735 | 2705 |
5967 | 2706 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
8962 | 2707 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id) |
4735 | 2708 { |
5967 | 2709 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
5012 | 2710 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
4895 | 2711 |
5967 | 2712 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
2713 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
2714 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
5046 | 2715 |
2716 im_image->pixbuf = img; | |
5012 | 2717 im_image->image = image; |
4895 | 2718 im_image->width = gdk_pixbuf_get_width(img); |
2719 im_image->height = gdk_pixbuf_get_height(img); | |
2720 im_image->mark = NULL; | |
6982 | 2721 im_image->filename = filename ? g_strdup(filename) : NULL; |
8962 | 2722 im_image->id = id; |
9573 | 2723 im_image->filesel = NULL; |
4895 | 2724 |
5046 | 2725 g_object_ref(img); |
4895 | 2726 return GTK_IMHTML_SCALABLE(im_image); |
2727 } | |
2728 | |
5967 | 2729 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
4895 | 2730 { |
5967 | 2731 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
4895 | 2732 |
2733 if(image->width > width || image->height > height){ | |
2734 GdkPixbuf *new_image = NULL; | |
2735 float factor; | |
2736 int new_width = image->width, new_height = image->height; | |
2737 | |
8588 | 2738 if(image->width > (width - 2)){ |
4895 | 2739 factor = (float)(width)/image->width; |
2740 new_width = width; | |
2741 new_height = image->height * factor; | |
2742 } | |
8588 | 2743 if(new_height >= (height - 2)){ |
4895 | 2744 factor = (float)(height)/new_height; |
2745 new_height = height; | |
2746 new_width = new_width * factor; | |
2747 } | |
2748 | |
5046 | 2749 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
5012 | 2750 gtk_image_set_from_pixbuf(image->image, new_image); |
4895 | 2751 g_object_unref(G_OBJECT(new_image)); |
2752 } | |
2753 } | |
2754 | |
9573 | 2755 static void |
2756 image_save_yes_cb(GtkIMHtmlImage *image, const char *filename) | |
5012 | 2757 { |
2758 gchar *type = NULL; | |
5019 | 2759 GError *error = NULL; |
5015 | 2760 #if GTK_CHECK_VERSION(2,2,0) |
5012 | 2761 GSList *formats = gdk_pixbuf_get_formats(); |
6162 | 2762 #else |
2763 char *basename = g_path_get_basename(filename); | |
2764 char *ext = strrchr(basename, '.'); | |
5959 | 2765 #endif |
5012 | 2766 |
9573 | 2767 gtk_widget_destroy(image->filesel); |
2768 image->filesel = NULL; | |
5959 | 2769 |
2770 #if GTK_CHECK_VERSION(2,2,0) | |
9573 | 2771 while (formats) { |
5012 | 2772 GdkPixbufFormat *format = formats->data; |
2773 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
2774 gpointer p = extensions; | |
2775 | |
2776 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
2777 gchar *fmt_ext = extensions[0]; | |
2778 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
2779 | |
2780 if(!strcmp(fmt_ext, file_ext)){ | |
2781 type = gdk_pixbuf_format_get_name(format); | |
2782 break; | |
2783 } | |
2784 | |
2785 extensions++; | |
2786 } | |
2787 | |
2788 g_strfreev(p); | |
2789 | |
9573 | 2790 if (type) |
5012 | 2791 break; |
2792 | |
2793 formats = formats->next; | |
2794 } | |
2795 | |
5020 | 2796 g_slist_free(formats); |
2797 #else | |
2798 /* this is really ugly code, but I think it will work */ | |
9573 | 2799 if (ext) { |
5020 | 2800 ext++; |
9573 | 2801 if (!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) |
5020 | 2802 type = g_strdup("jpeg"); |
9573 | 2803 else if (!g_ascii_strcasecmp(ext, "png")) |
5020 | 2804 type = g_strdup("png"); |
2805 } | |
2806 | |
2807 g_free(basename); | |
2808 #endif | |
2809 | |
5012 | 2810 /* If I can't find a valid type, I will just tell the user about it and then assume |
2811 it's a png */ | |
9573 | 2812 if (!type){ |
5012 | 2813 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
9717 | 2814 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
2815 type = g_strdup("png"); | |
5012 | 2816 } |
2817 | |
5046 | 2818 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
5012 | 2819 |
9573 | 2820 if (error){ |
5012 | 2821 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
2822 _("Error saving image: %s"), error->message); | |
2823 g_error_free(error); | |
2824 } | |
2825 | |
2826 g_free(type); | |
2827 } | |
2828 | |
9573 | 2829 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
2830 static void | |
2831 image_save_check_if_exists_cb(GtkWidget *widget, gint response, GtkIMHtmlImage *image) | |
2832 { | |
2833 gchar *filename; | |
2834 | |
2835 if (response != GTK_RESPONSE_ACCEPT) { | |
2836 gtk_widget_destroy(widget); | |
2837 image->filesel = NULL; | |
2838 return; | |
2839 } | |
2840 | |
2841 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); | |
2842 #else /* FILECHOOSER */ | |
2843 static void | |
2844 image_save_check_if_exists_cb(GtkWidget *button, GtkIMHtmlImage *image) | |
5012 | 2845 { |
9573 | 2846 gchar *filename; |
2847 | |
2848 filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(image->filesel))); | |
2849 | |
2850 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { | |
2851 gchar *dirname; | |
2852 /* append a / is needed */ | |
2853 if (filename[strlen(filename) - 1] != G_DIR_SEPARATOR) { | |
2854 dirname = g_strconcat(filename, G_DIR_SEPARATOR_S, NULL); | |
2855 } else { | |
2856 dirname = g_strdup(filename); | |
2857 } | |
9574 | 2858 gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), dirname); |
9573 | 2859 g_free(dirname); |
2860 g_free(filename); | |
2861 return; | |
2862 } | |
2863 #endif /* FILECHOOSER */ | |
2864 | |
2865 /* | |
2866 * XXX - We should probably prompt the user to determine if they really | |
2867 * want to overwrite the file or not. However, I don't feel like doing | |
2868 * that, so we're just always going to overwrite if the file exists. | |
2869 */ | |
2870 /* | |
2871 if (g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
2872 } else | |
2873 image_save_yes_cb(image, filename); | |
2874 */ | |
2875 | |
2876 image_save_yes_cb(image, filename); | |
2877 | |
2878 g_free(filename); | |
2879 } | |
2880 | |
2881 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ | |
2882 static void | |
2883 image_save_cancel_cb(GtkIMHtmlImage *image) | |
2884 { | |
2885 gtk_widget_destroy(image->filesel); | |
2886 image->filesel = NULL; | |
2887 } | |
2888 #endif /* FILECHOOSER */ | |
2889 | |
2890 static void | |
2891 gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) | |
2892 { | |
2893 if (image->filesel != NULL) { | |
2894 gtk_window_present(GTK_WINDOW(image->filesel)); | |
2895 return; | |
2896 } | |
2897 | |
2898 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ | |
2899 image->filesel = gtk_file_chooser_dialog_new(_("Save Image"), | |
2900 NULL, | |
2901 GTK_FILE_CHOOSER_ACTION_SAVE, | |
2902 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
2903 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, | |
2904 NULL); | |
2905 gtk_dialog_set_default_response(GTK_DIALOG(image->filesel), GTK_RESPONSE_ACCEPT); | |
2906 if (image->filename != NULL) | |
2907 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(image->filesel), image->filename); | |
2908 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(image->filesel)), "response", | |
2909 G_CALLBACK(image_save_check_if_exists_cb), image); | |
2910 #else /* FILECHOOSER */ | |
2911 image->filesel = gtk_file_selection_new(_("Save Image")); | |
2912 if (image->filename != NULL) | |
2913 gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), image->filename); | |
9574 | 2914 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)), "delete_event", |
2915 G_CALLBACK(image_save_cancel_cb), image); | |
2916 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->cancel_button), | |
2917 "clicked", G_CALLBACK(image_save_cancel_cb), image); | |
9573 | 2918 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->ok_button), "clicked", |
2919 G_CALLBACK(image_save_check_if_exists_cb), image); | |
2920 #endif /* FILECHOOSER */ | |
2921 | |
2922 gtk_widget_show(image->filesel); | |
5012 | 2923 } |
2924 | |
9815 | 2925 /* |
2926 * So, um, AIM Direct IM lets you send any file, not just images. You can | |
2927 * just insert a sound or a file or whatever in a conversation. It's | |
2928 * basically like file transfer, except there is an icon to open the file | |
2929 * embedded in the conversation. Someone should make the Gaim core handle | |
2930 * all of that. | |
2931 */ | |
5967 | 2932 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
5012 | 2933 { |
2934 GdkEventButton *event_button = (GdkEventButton *) event; | |
2935 | |
2936 if (event->type == GDK_BUTTON_RELEASE) { | |
2937 if(event_button->button == 3) { | |
2938 GtkWidget *img, *item, *menu; | |
2939 gchar *text = g_strdup_printf(_("_Save Image...")); | |
2940 menu = gtk_menu_new(); | |
2941 | |
2942 /* buttons and such */ | |
2943 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
2944 item = gtk_image_menu_item_new_with_mnemonic(text); | |
2945 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
5967 | 2946 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
5012 | 2947 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
2948 | |
2949 gtk_widget_show_all(menu); | |
2950 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
2951 event_button->button, event_button->time); | |
2952 | |
2953 g_free(text); | |
2954 return TRUE; | |
2955 } | |
2956 } | |
2957 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
2958 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
2959 be caught by the regular GtkTextView menu */ | |
2960 else | |
2961 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
2962 | |
2963 } | |
5967 | 2964 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
2965 { | |
2966 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2967 | |
2968 g_object_unref(image->pixbuf); | |
6982 | 2969 if (image->filename) |
2970 g_free(image->filename); | |
9573 | 2971 if (image->filesel) |
2972 gtk_widget_destroy(image->filesel); | |
5967 | 2973 g_free(scale); |
2974 } | |
2975 | |
2976 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
2977 { | |
2978 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
2979 GtkWidget *box = gtk_event_box_new(); | |
8962 | 2980 char *tag; |
5967 | 2981 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
2982 | |
2983 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
9229 | 2984 |
2985 if(!gtk_check_version(2, 4, 0)) | |
2986 g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL); | |
5967 | 2987 |
2988 gtk_widget_show(GTK_WIDGET(image->image)); | |
2989 gtk_widget_show(box); | |
2990 | |
8962 | 2991 tag = g_strdup_printf("<IMG ID=\"%d\">", image->id); |
2992 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", tag, g_free); | |
2993 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "[Image]"); | |
2994 | |
5967 | 2995 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); |
2996 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
2997 } | |
2998 | |
2999 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
3000 { | |
3001 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
3002 | |
3003 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
3004 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
3005 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
3006 | |
3007 hr->sep = gtk_hseparator_new(); | |
3008 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
3009 gtk_widget_show(hr->sep); | |
3010 | |
3011 return GTK_IMHTML_SCALABLE(hr); | |
3012 } | |
3013 | |
3014 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
3015 { | |
8588 | 3016 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width - 2, 2); |
5967 | 3017 } |
3018 | |
3019 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
3020 { | |
3021 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
3022 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
8698 | 3023 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>"); |
3024 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n"); | |
5967 | 3025 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); |
3026 } | |
3027 | |
3028 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
3029 { | |
3030 g_free(scale); | |
3031 } | |
7295 | 3032 |
3033 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
3034 { | |
3035 GtkTextIter iter, start, end; | |
3036 gboolean new_search = TRUE; | |
3037 | |
3038 g_return_val_if_fail(imhtml != NULL, FALSE); | |
3039 g_return_val_if_fail(text != NULL, FALSE); | |
8061 | 3040 |
7295 | 3041 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) |
3042 new_search = FALSE; | |
8061 | 3043 |
7295 | 3044 if (new_search) { |
3045 gtk_imhtml_search_clear(imhtml); | |
3046 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
3047 } else { | |
3048 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
8061 | 3049 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); |
7295 | 3050 } |
3051 imhtml->search_string = g_strdup(text); | |
3052 | |
7358 | 3053 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
3054 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
7295 | 3055 &start, &end, NULL)) { |
3056 | |
3057 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
3058 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
3059 if (new_search) { | |
3060 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
8061 | 3061 do |
7295 | 3062 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); |
8061 | 3063 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
3064 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
7358 | 3065 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, |
7295 | 3066 &start, &end, NULL)); |
3067 } | |
3068 return TRUE; | |
3069 } | |
8061 | 3070 |
3071 gtk_imhtml_search_clear(imhtml); | |
3072 | |
7295 | 3073 return FALSE; |
3074 } | |
3075 | |
3076 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
3077 { | |
3078 GtkTextIter start, end; | |
8061 | 3079 |
7295 | 3080 g_return_if_fail(imhtml != NULL); |
8061 | 3081 |
7295 | 3082 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
3083 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
3084 | |
3085 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
3086 if (imhtml->search_string) | |
3087 g_free(imhtml->search_string); | |
3088 imhtml->search_string = NULL; | |
3089 } | |
8061 | 3090 |
8677 | 3091 static GtkTextTag *find_font_forecolor_tag(GtkIMHtml *imhtml, gchar *color) |
3092 { | |
3093 gchar str[18]; | |
3094 GtkTextTag *tag; | |
3095 | |
3096 g_snprintf(str, sizeof(str), "FORECOLOR %s", color); | |
3097 | |
3098 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3099 if (!tag) | |
3100 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", color, NULL); | |
3101 | |
3102 return tag; | |
3103 } | |
3104 | |
3105 static GtkTextTag *find_font_backcolor_tag(GtkIMHtml *imhtml, gchar *color) | |
3106 { | |
3107 gchar str[18]; | |
3108 GtkTextTag *tag; | |
3109 | |
3110 g_snprintf(str, sizeof(str), "BACKCOLOR %s", color); | |
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, "background", color, NULL); | |
3115 | |
3116 return tag; | |
3117 } | |
3118 | |
3119 static GtkTextTag *find_font_face_tag(GtkIMHtml *imhtml, gchar *face) | |
8061 | 3120 { |
8677 | 3121 gchar str[256]; |
3122 GtkTextTag *tag; | |
3123 | |
3124 g_snprintf(str, sizeof(str), "FONT FACE %s", face); | |
3125 str[255] = '\0'; | |
3126 | |
3127 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3128 if (!tag) | |
3129 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "family", face, NULL); | |
3130 | |
3131 return tag; | |
3132 } | |
3133 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3134 static void _init_original_fsize(GtkIMHtml *imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3135 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3136 GtkTextAttributes *attr; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3137 attr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3138 imhtml->original_fsize = pango_font_description_get_size(attr->font); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3139 gtk_text_attributes_unref(attr); |
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 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3142 static void _recalculate_font_sizes(GtkTextTag *tag, gpointer imhtml) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3143 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3144 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3145 int size; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3146 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3147 size = strtol(tag->name + 10, NULL, 10); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3148 g_object_set(G_OBJECT(tag), "size", |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3149 (gint) (GTK_IMHTML(imhtml)->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3150 ((double) _point_sizes[size-1] * GTK_IMHTML(imhtml)->zoom)), NULL); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3151 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3152 |
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 } |
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 void gtk_imhtml_font_zoom(GtkIMHtml *imhtml, double zoom) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3157 { |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3158 GtkRcStyle *s; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3159 PangoFontDescription *font_desc = pango_font_description_new(); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3160 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3161 imhtml->zoom = zoom; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3162 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3163 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3164 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3165 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3166 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
|
3167 _recalculate_font_sizes, imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3168 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3169 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
|
3170 |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3171 s = gtk_widget_get_modifier_style(GTK_WIDGET(imhtml)); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3172 s->font_desc = font_desc; |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3173 gtk_widget_modify_style(GTK_WIDGET(imhtml), s); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3174 } |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3175 |
8677 | 3176 static GtkTextTag *find_font_size_tag(GtkIMHtml *imhtml, int size) |
3177 { | |
3178 gchar str[24]; | |
3179 GtkTextTag *tag; | |
3180 | |
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3181 if (!imhtml->original_fsize) |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3182 _init_original_fsize(imhtml); |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3183 |
8677 | 3184 g_snprintf(str, sizeof(str), "FONT SIZE %d", size); |
3185 str[23] = '\0'; | |
3186 | |
3187 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
3188 if (!tag) { | |
3189 /* For reasons I don't understand, setting "scale" here scaled based on some default | |
3190 * size other than my theme's default size. Our size 4 was actually smaller than | |
3191 * our size 3 for me. So this works around that oddity. | |
3192 */ | |
3193 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
|
3194 (gint) (imhtml->original_fsize * |
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3195 ((double) _point_sizes[size-1] * imhtml->zoom)), NULL); |
8061 | 3196 } |
3197 | |
8677 | 3198 return tag; |
3199 } | |
3200 | |
3201 static void remove_tag_by_prefix(GtkIMHtml *imhtml, const GtkTextIter *i, const GtkTextIter *e, | |
3202 const char *prefix, guint len, gboolean homo) | |
3203 { | |
3204 GSList *tags, *l; | |
3205 GtkTextIter iter; | |
3206 | |
3207 tags = gtk_text_iter_get_tags(i); | |
3208 | |
3209 for (l = tags; l; l = l->next) { | |
3210 GtkTextTag *tag = l->data; | |
3211 | |
3212 if (tag->name && !strncmp(tag->name, prefix, len)) | |
3213 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, i, e); | |
8061 | 3214 } |
3215 | |
8677 | 3216 g_slist_free(tags); |
3217 | |
3218 if (homo) | |
3219 return; | |
3220 | |
3221 iter = *i; | |
3222 | |
3223 while (gtk_text_iter_forward_char(&iter) && !gtk_text_iter_equal(&iter, e)) { | |
3224 if (gtk_text_iter_begins_tag(&iter, NULL)) { | |
3225 tags = gtk_text_iter_get_toggled_tags(&iter, TRUE); | |
3226 | |
3227 for (l = tags; l; l = l->next) { | |
3228 GtkTextTag *tag = l->data; | |
3229 | |
3230 if (tag->name && !strncmp(tag->name, prefix, len)) | |
3231 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e); | |
3232 } | |
3233 | |
3234 g_slist_free(tags); | |
3235 } | |
8061 | 3236 } |
8677 | 3237 } |
3238 | |
3239 static void remove_font_size(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3240 { | |
3241 remove_tag_by_prefix(imhtml, i, e, "FONT SIZE ", 10, homo); | |
3242 } | |
3243 | |
3244 static void remove_font_face(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3245 { | |
3246 remove_tag_by_prefix(imhtml, i, e, "FONT FACE ", 10, homo); | |
3247 } | |
3248 | |
3249 static void remove_font_forecolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3250 { | |
3251 remove_tag_by_prefix(imhtml, i, e, "FORECOLOR ", 10, homo); | |
3252 } | |
3253 | |
3254 static void remove_font_backcolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3255 { | |
3256 remove_tag_by_prefix(imhtml, i, e, "BACKCOLOR ", 10, homo); | |
3257 } | |
3258 | |
3259 static void remove_font_link(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
3260 { | |
3261 remove_tag_by_prefix(imhtml, i, e, "LINK ", 5, homo); | |
3262 } | |
3263 | |
3264 /* Editable stuff */ | |
3265 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
3266 { | |
3267 imhtml->insert_offset = gtk_text_iter_get_offset(iter); | |
3268 } | |
3269 | |
10169 | 3270 static void insert_ca_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextChildAnchor *arg2, gpointer user_data) |
3271 { | |
3272 GtkTextIter start; | |
3273 | |
3274 start = *arg1; | |
3275 gtk_text_iter_backward_char(&start); | |
3276 | |
3277 gtk_imhtml_apply_tags_on_insert(user_data, &start, arg1); | |
3278 } | |
3279 | |
8677 | 3280 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *end, gchar *text, gint len, GtkIMHtml *imhtml) |
3281 { | |
3282 GtkTextIter start; | |
3283 | |
3284 if (!len) | |
3285 return; | |
3286 | |
3287 start = *end; | |
3288 gtk_text_iter_set_offset(&start, imhtml->insert_offset); | |
3289 | |
10169 | 3290 gtk_imhtml_apply_tags_on_insert(imhtml, &start, end); |
3291 } | |
3292 | |
3293 static void gtk_imhtml_apply_tags_on_insert(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) | |
3294 { | |
8677 | 3295 if (imhtml->edit.bold) |
10169 | 3296 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", start, end); |
8677 | 3297 else |
10169 | 3298 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", start, end); |
8677 | 3299 |
3300 if (imhtml->edit.italic) | |
10169 | 3301 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", start, end); |
8677 | 3302 else |
10169 | 3303 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", start, end); |
8677 | 3304 |
3305 if (imhtml->edit.underline) | |
10169 | 3306 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", start, end); |
8677 | 3307 else |
10169 | 3308 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", start, end); |
8677 | 3309 |
9924 | 3310 if (imhtml->edit.strike) |
10169 | 3311 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", start, end); |
9924 | 3312 else |
10169 | 3313 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "STRIKE", start, end); |
9924 | 3314 |
8677 | 3315 if (imhtml->edit.forecolor) { |
10169 | 3316 remove_font_forecolor(imhtml, start, end, TRUE); |
8677 | 3317 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
3318 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
10169 | 3319 start, end); |
8061 | 3320 } |
3321 | |
8677 | 3322 if (imhtml->edit.backcolor) { |
10169 | 3323 remove_font_backcolor(imhtml, start, end, TRUE); |
8677 | 3324 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
3325 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), | |
10169 | 3326 start, end); |
8677 | 3327 } |
3328 | |
3329 if (imhtml->edit.fontface) { | |
10169 | 3330 remove_font_face(imhtml, start, end, TRUE); |
8677 | 3331 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
3332 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
10169 | 3333 start, end); |
8061 | 3334 } |
8677 | 3335 |
3336 if (imhtml->edit.fontsize) { | |
10169 | 3337 remove_font_size(imhtml, start, end, TRUE); |
8677 | 3338 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
3339 find_font_size_tag(imhtml, imhtml->edit.fontsize), | |
10169 | 3340 start, end); |
8677 | 3341 } |
3342 | |
3343 if (imhtml->edit.link) { | |
10169 | 3344 remove_font_link(imhtml, start, end, TRUE); |
8677 | 3345 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
3346 imhtml->edit.link, | |
10169 | 3347 start, end); |
8677 | 3348 } |
8061 | 3349 } |
3350 | |
3351 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
3352 { | |
3353 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
8177 | 3354 /* |
3355 * We need a visible caret for accessibility, so mouseless | |
3356 * people can highlight stuff. | |
3357 */ | |
3358 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ | |
8061 | 3359 imhtml->editable = editable; |
8677 | 3360 imhtml->format_functions = GTK_IMHTML_ALL; |
3361 | |
3362 if (editable) | |
3363 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
3364 G_CALLBACK(mark_set_cb), imhtml); | |
3365 } | |
3366 | |
3367 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo) | |
3368 { | |
3369 g_return_if_fail(imhtml != NULL); | |
3370 | |
3371 imhtml->wbfo = wbfo; | |
8420 | 3372 } |
3373 | |
3374 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) | |
3375 { | |
3376 GObject *object = g_object_ref(G_OBJECT(imhtml)); | |
8677 | 3377 imhtml->format_functions = buttons; |
8420 | 3378 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); |
3379 g_object_unref(object); | |
8061 | 3380 } |
3381 | |
8788 | 3382 GtkIMHtmlButtons gtk_imhtml_get_format_functions(GtkIMHtml *imhtml) |
3383 { | |
3384 return imhtml->format_functions; | |
3385 } | |
8516 | 3386 |
3387 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, | |
3388 gboolean *italic, gboolean *underline) | |
8481 | 3389 { |
8677 | 3390 if (imhtml->edit.bold) |
3391 (*bold) = TRUE; | |
3392 if (imhtml->edit.italic) | |
3393 (*italic) = TRUE; | |
3394 if (imhtml->edit.underline) | |
3395 (*underline) = TRUE; | |
8481 | 3396 } |
3397 | |
9025 | 3398 char * |
3399 gtk_imhtml_get_current_fontface(GtkIMHtml *imhtml) | |
3400 { | |
3401 if (imhtml->edit.fontface) | |
3402 return g_strdup(imhtml->edit.fontface); | |
3403 else | |
3404 return NULL; | |
3405 } | |
3406 | |
3407 char * | |
3408 gtk_imhtml_get_current_forecolor(GtkIMHtml *imhtml) | |
3409 { | |
3410 if (imhtml->edit.forecolor) | |
3411 return g_strdup(imhtml->edit.forecolor); | |
3412 else | |
3413 return NULL; | |
3414 } | |
3415 | |
3416 char * | |
3417 gtk_imhtml_get_current_backcolor(GtkIMHtml *imhtml) | |
3418 { | |
3419 if (imhtml->edit.backcolor) | |
3420 return g_strdup(imhtml->edit.backcolor); | |
3421 else | |
3422 return NULL; | |
3423 } | |
3424 | |
3425 gint | |
3426 gtk_imhtml_get_current_fontsize(GtkIMHtml *imhtml) | |
3427 { | |
3428 return imhtml->edit.fontsize; | |
3429 } | |
3430 | |
8061 | 3431 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) |
3432 { | |
3433 return imhtml->editable; | |
3434 } | |
3435 | |
8677 | 3436 /* |
3437 * I had this crazy idea about changing the text cursor color to reflex the foreground color | |
3438 * of the text about to be entered. This is the place you'd do it, along with the place where | |
3439 * we actually set a new foreground color. | |
3440 * I may not do this, because people will bitch about Gaim overriding their gtk theme's cursor | |
3441 * colors. | |
3442 * | |
3443 * Just in case I do do this, I asked about what to set the secondary text cursor to. | |
3444 * | |
8719 | 3445 * (12:45:27) ?? ???: secondary_cursor_color = (rgb(background) + rgb(primary_cursor_color) ) / 2 |
3446 * (12:45:55) ?? ???: understand? | |
8677 | 3447 * (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
|
3448 * (12:46:56) ?? ???: u might need to extract separate each color from RGB |
8677 | 3449 */ |
3450 | |
3451 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, | |
3452 GtkIMHtml *imhtml) | |
3453 { | |
3454 GSList *tags, *l; | |
3455 GtkTextIter iter; | |
3456 | |
3457 if (mark != gtk_text_buffer_get_insert(buffer)) | |
3458 return; | |
3459 | |
3460 if (!gtk_text_buffer_get_char_count(buffer)) | |
3461 return; | |
3462 | |
9924 | 3463 imhtml->edit.bold = imhtml->edit.italic = imhtml->edit.underline = imhtml->edit.strike = FALSE; |
8677 | 3464 if (imhtml->edit.forecolor) |
3465 g_free(imhtml->edit.forecolor); | |
3466 imhtml->edit.forecolor = NULL; | |
3467 if (imhtml->edit.backcolor) | |
3468 g_free(imhtml->edit.backcolor); | |
3469 imhtml->edit.backcolor = NULL; | |
3470 if (imhtml->edit.fontface) | |
3471 g_free(imhtml->edit.fontface); | |
3472 imhtml->edit.fontface = NULL; | |
3473 imhtml->edit.fontsize = 0; | |
3474 imhtml->edit.link = NULL; | |
3475 | |
3476 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3477 | |
3478 | |
3479 if (gtk_text_iter_is_end(&iter)) | |
3480 tags = gtk_text_iter_get_toggled_tags(&iter, FALSE); | |
3481 else | |
3482 tags = gtk_text_iter_get_tags(&iter); | |
3483 | |
3484 for (l = tags; l != NULL; l = l->next) { | |
3485 GtkTextTag *tag = GTK_TEXT_TAG(l->data); | |
3486 | |
3487 if (tag->name) { | |
3488 if (strcmp(tag->name, "BOLD") == 0) | |
3489 imhtml->edit.bold = TRUE; | |
3490 if (strcmp(tag->name, "ITALICS") == 0) | |
3491 imhtml->edit.italic = TRUE; | |
3492 if (strcmp(tag->name, "UNDERLINE") == 0) | |
3493 imhtml->edit.underline = TRUE; | |
9924 | 3494 if (strcmp(tag->name, "STRIKE") == 0) |
3495 imhtml->edit.strike = TRUE; | |
8677 | 3496 if (strncmp(tag->name, "FORECOLOR ", 10) == 0) |
3497 imhtml->edit.forecolor = g_strdup(&(tag->name)[10]); | |
3498 if (strncmp(tag->name, "BACKCOLOR ", 10) == 0) | |
3499 imhtml->edit.backcolor = g_strdup(&(tag->name)[10]); | |
3500 if (strncmp(tag->name, "FONT FACE ", 10) == 0) | |
3501 imhtml->edit.fontface = g_strdup(&(tag->name)[10]); | |
3502 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) | |
3503 imhtml->edit.fontsize = strtol(&(tag->name)[10], NULL, 10); | |
8719 | 3504 if ((strncmp(tag->name, "LINK ", 5) == 0) && !gtk_text_iter_is_end(&iter)) |
8677 | 3505 imhtml->edit.link = tag; |
3506 } | |
3507 } | |
3508 | |
3509 g_slist_free(tags); | |
3510 } | |
3511 | |
8061 | 3512 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) |
3513 { | |
8481 | 3514 GObject *object; |
8677 | 3515 GtkTextIter start, end; |
3516 | |
3517 imhtml->edit.bold = !imhtml->edit.bold; | |
3518 | |
3519 if (imhtml->wbfo) { | |
3520 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3521 if (imhtml->edit.bold) | |
3522 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3523 else | |
3524 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3525 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3526 if (imhtml->edit.bold) | |
3527 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3528 else | |
3529 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
3530 | |
8061 | 3531 } |
8481 | 3532 object = g_object_ref(G_OBJECT(imhtml)); |
3533 g_object_unref(object); | |
3534 | |
8677 | 3535 return (imhtml->edit.bold != FALSE); |
8061 | 3536 } |
3537 | |
3538 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
3539 { | |
8481 | 3540 GObject *object; |
8677 | 3541 GtkTextIter start, end; |
3542 | |
3543 imhtml->edit.italic = !imhtml->edit.italic; | |
3544 | |
3545 if (imhtml->wbfo) { | |
3546 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3547 if (imhtml->edit.italic) | |
3548 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3549 else | |
3550 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3551 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3552 if (imhtml->edit.italic) | |
3553 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
3554 else | |
3555 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
8061 | 3556 } |
8481 | 3557 object = g_object_ref(G_OBJECT(imhtml)); |
3558 g_object_unref(object); | |
3559 | |
8677 | 3560 return imhtml->edit.italic != FALSE; |
8061 | 3561 } |
3562 | |
3563 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) | |
3564 { | |
8481 | 3565 GObject *object; |
8677 | 3566 GtkTextIter start, end; |
3567 | |
3568 imhtml->edit.underline = !imhtml->edit.underline; | |
3569 | |
3570 if (imhtml->wbfo) { | |
3571 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3572 if (imhtml->edit.underline) | |
3573 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3574 else | |
3575 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3576 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3577 if (imhtml->edit.underline) | |
3578 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
3579 else | |
3580 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
8061 | 3581 } |
8481 | 3582 object = g_object_ref(G_OBJECT(imhtml)); |
3583 g_object_unref(object); | |
3584 | |
8677 | 3585 return imhtml->edit.underline != FALSE; |
8061 | 3586 } |
3587 | |
9924 | 3588 gboolean gtk_imhtml_toggle_strike(GtkIMHtml *imhtml) |
3589 { | |
3590 GObject *object; | |
3591 GtkTextIter start, end; | |
3592 | |
3593 imhtml->edit.strike = !imhtml->edit.strike; | |
3594 | |
3595 if (imhtml->wbfo) { | |
3596 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3597 if (imhtml->edit.strike) | |
3598 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
3599 else | |
3600 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
3601 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3602 if (imhtml->edit.strike) | |
3603 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
3604 else | |
3605 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
3606 } | |
3607 object = g_object_ref(G_OBJECT(imhtml)); | |
3608 g_object_unref(object); | |
3609 | |
3610 return imhtml->edit.strike != FALSE; | |
3611 } | |
3612 | |
8061 | 3613 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) |
3614 { | |
9025 | 3615 GObject *object; |
8677 | 3616 GtkTextIter start, end; |
9025 | 3617 GtkIMHtmlButtons b = 0; |
8061 | 3618 |
3619 imhtml->edit.fontsize = size; | |
3620 | |
8677 | 3621 |
3622 if (imhtml->wbfo) { | |
3623 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3624 remove_font_size(imhtml, &start, &end, TRUE); | |
3625 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3626 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3627 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3628 remove_font_size(imhtml, &start, &end, FALSE); | |
3629 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3630 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3631 } |
8677 | 3632 |
9025 | 3633 object = g_object_ref(G_OBJECT(imhtml)); |
3634 b |= GTK_IMHTML_SHRINK; | |
3635 b |= GTK_IMHTML_GROW; | |
3636 g_object_unref(object); | |
8061 | 3637 } |
3638 | |
3639 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) | |
3640 { | |
9025 | 3641 GObject *object; |
8677 | 3642 GtkTextIter start, end; |
3643 | |
8061 | 3644 if (imhtml->edit.fontsize == 1) |
3645 return; | |
3646 | |
8677 | 3647 if (!imhtml->edit.fontsize) |
3648 imhtml->edit.fontsize = 2; | |
3649 else | |
3650 imhtml->edit.fontsize--; | |
3651 | |
3652 if (imhtml->wbfo) { | |
3653 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3654 remove_font_size(imhtml, &start, &end, TRUE); | |
3655 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3656 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3657 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3658 remove_font_size(imhtml, &start, &end, FALSE); | |
3659 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3660 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3661 } |
9025 | 3662 object = g_object_ref(G_OBJECT(imhtml)); |
3663 g_object_unref(object); | |
8061 | 3664 } |
3665 | |
3666 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) | |
3667 { | |
9025 | 3668 GObject *object; |
8677 | 3669 GtkTextIter start, end; |
3670 | |
8061 | 3671 if (imhtml->edit.fontsize == MAX_FONT_SIZE) |
3672 return; | |
3673 | |
8677 | 3674 if (!imhtml->edit.fontsize) |
3675 imhtml->edit.fontsize = 4; | |
3676 else | |
3677 imhtml->edit.fontsize++; | |
3678 | |
3679 if (imhtml->wbfo) { | |
3680 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3681 remove_font_size(imhtml, &start, &end, TRUE); | |
3682 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3683 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
3684 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3685 remove_font_size(imhtml, &start, &end, FALSE); | |
3686 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3687 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
8061 | 3688 } |
9025 | 3689 object = g_object_ref(G_OBJECT(imhtml)); |
3690 g_object_unref(object); | |
8061 | 3691 } |
3692 | |
3693 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) | |
3694 { | |
9025 | 3695 GObject *object; |
8677 | 3696 GtkTextIter start, end; |
3697 | |
3698 if (imhtml->edit.forecolor != NULL) | |
3699 g_free(imhtml->edit.forecolor); | |
3700 | |
9025 | 3701 if (color && strcmp(color, "") != 0) { |
8677 | 3702 imhtml->edit.forecolor = g_strdup(color); |
3703 if (imhtml->wbfo) { | |
3704 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3705 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3706 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3707 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), &start, &end); | |
3708 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3709 remove_font_forecolor(imhtml, &start, &end, FALSE); | |
3710 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3711 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
3712 &start, &end); | |
3713 } | |
8061 | 3714 } else { |
3715 imhtml->edit.forecolor = NULL; | |
9025 | 3716 if (imhtml->wbfo) { |
3717 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3718 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
3719 } | |
8061 | 3720 } |
3721 | |
9025 | 3722 object = g_object_ref(G_OBJECT(imhtml)); |
3723 g_object_unref(object); | |
3724 | |
8061 | 3725 return imhtml->edit.forecolor != NULL; |
3726 } | |
3727 | |
3728 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
3729 { | |
9025 | 3730 GObject *object; |
8677 | 3731 GtkTextIter start, end; |
3732 | |
3733 if (imhtml->edit.backcolor != NULL) | |
3734 g_free(imhtml->edit.backcolor); | |
3735 | |
9025 | 3736 if (color && strcmp(color, "") != 0) { |
8677 | 3737 imhtml->edit.backcolor = g_strdup(color); |
3738 | |
3739 if (imhtml->wbfo) { | |
3740 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3741 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3742 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3743 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), &start, &end); | |
3744 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3745 remove_font_backcolor(imhtml, &start, &end, FALSE); | |
3746 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3747 find_font_backcolor_tag(imhtml, | |
3748 imhtml->edit.backcolor), &start, &end); | |
3749 } | |
8061 | 3750 } else { |
3751 imhtml->edit.backcolor = NULL; | |
9025 | 3752 if (imhtml->wbfo) { |
3753 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3754 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
3755 } | |
8061 | 3756 } |
8677 | 3757 |
9025 | 3758 object = g_object_ref(G_OBJECT(imhtml)); |
3759 g_object_unref(object); | |
3760 | |
8061 | 3761 return imhtml->edit.backcolor != NULL; |
3762 } | |
3763 | |
3764 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) | |
3765 { | |
9025 | 3766 GObject *object; |
8677 | 3767 GtkTextIter start, end; |
3768 | |
3769 if (imhtml->edit.fontface != NULL) | |
3770 g_free(imhtml->edit.fontface); | |
3771 | |
9025 | 3772 if (face && strcmp(face, "") != 0) { |
8677 | 3773 imhtml->edit.fontface = g_strdup(face); |
3774 | |
3775 if (imhtml->wbfo) { | |
3776 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3777 remove_font_face(imhtml, &start, &end, TRUE); | |
3778 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3779 find_font_face_tag(imhtml, imhtml->edit.fontface), &start, &end); | |
3780 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3781 remove_font_face(imhtml, &start, &end, FALSE); | |
3782 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
3783 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
3784 &start, &end); | |
3785 } | |
8061 | 3786 } else { |
3787 imhtml->edit.fontface = NULL; | |
9025 | 3788 if (imhtml->wbfo) { |
3789 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
3790 remove_font_face(imhtml, &start, &end, TRUE); | |
3791 } | |
8061 | 3792 } |
8677 | 3793 |
9025 | 3794 object = g_object_ref(G_OBJECT(imhtml)); |
3795 g_object_unref(object); | |
3796 | |
8061 | 3797 return imhtml->edit.fontface != NULL; |
3798 } | |
3799 | |
8677 | 3800 void gtk_imhtml_toggle_link(GtkIMHtml *imhtml, const char *url) |
8061 | 3801 { |
9025 | 3802 GObject *object; |
8677 | 3803 GtkTextIter start, end; |
3804 GtkTextTag *linktag; | |
3805 static guint linkno = 0; | |
3806 gchar str[48]; | |
9007 | 3807 GdkColor *color = NULL; |
8677 | 3808 |
3809 imhtml->edit.link = NULL; | |
3810 | |
3811 | |
3812 | |
3813 if (url) { | |
3814 g_snprintf(str, sizeof(str), "LINK %d", linkno++); | |
3815 str[47] = '\0'; | |
3816 | |
9007 | 3817 gtk_widget_style_get(GTK_WIDGET(imhtml), "hyperlink-color", &color, NULL); |
9008 | 3818 if (color) { |
9007 | 3819 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground-gdk", color, "underline", PANGO_UNDERLINE_SINGLE, NULL); |
9008 | 3820 gdk_color_free(color); |
3821 } else { | |
9007 | 3822 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
9008 | 3823 } |
8677 | 3824 g_object_set_data_full(G_OBJECT(linktag), "link_url", g_strdup(url), g_free); |
3825 g_signal_connect(G_OBJECT(linktag), "event", G_CALLBACK(tag_event), NULL); | |
3826 | |
3827 if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
3828 remove_font_link(imhtml, &start, &end, FALSE); | |
3829 gtk_text_buffer_apply_tag(imhtml->text_buffer, linktag, &start, &end); | |
3830 } | |
3831 } | |
9025 | 3832 |
3833 object = g_object_ref(G_OBJECT(imhtml)); | |
3834 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_LINK); | |
3835 g_object_unref(object); | |
8677 | 3836 } |
3837 | |
3838 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text) | |
3839 { | |
8061 | 3840 GtkTextIter iter; |
8677 | 3841 |
9599 | 3842 if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) |
3843 gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE); | |
3844 | |
8677 | 3845 gtk_imhtml_toggle_link(imhtml, url); |
8061 | 3846 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); |
8677 | 3847 gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1); |
3848 gtk_imhtml_toggle_link(imhtml, NULL); | |
8061 | 3849 } |
3850 | |
3851 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) | |
3852 { | |
8677 | 3853 GtkTextMark *mark; |
8061 | 3854 GtkTextIter iter; |
8677 | 3855 |
3856 mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
3857 | |
3858 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
3859 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, smiley, &iter); | |
3860 } | |
3861 | |
3862 void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter) | |
3863 { | |
8061 | 3864 GdkPixbuf *pixbuf = NULL; |
3865 GdkPixbufAnimation *annipixbuf = NULL; | |
3866 GtkWidget *icon = NULL; | |
3867 GtkTextChildAnchor *anchor; | |
8505 | 3868 char *unescaped = gaim_unescape_html(smiley); |
8061 | 3869 |
8505 | 3870 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); |
8061 | 3871 if(annipixbuf) { |
3872 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
3873 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
3874 if(pixbuf) | |
3875 icon = gtk_image_new_from_pixbuf(pixbuf); | |
3876 } else { | |
3877 icon = gtk_image_new_from_animation(annipixbuf); | |
3878 } | |
3879 } | |
3880 | |
3881 if (icon) { | |
8890 | 3882 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
3883 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", g_strdup(unescaped), g_free); | |
3884 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); | |
3885 | |
8061 | 3886 gtk_widget_show(icon); |
3887 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
8890 | 3888 } else { |
3889 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, -1); | |
8061 | 3890 } |
8890 | 3891 |
3892 g_free(unescaped); | |
8061 | 3893 } |
3894 | |
8962 | 3895 void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter) |
3896 { | |
3897 GdkPixbuf *pixbuf = NULL; | |
3898 const char *filename = NULL; | |
3899 gpointer image; | |
3900 GdkRectangle rect; | |
3901 GtkIMHtmlScalable *scalable = NULL; | |
3902 int minus; | |
3903 | |
3904 if (!imhtml->funcs || !imhtml->funcs->image_get || | |
3905 !imhtml->funcs->image_get_size || !imhtml->funcs->image_get_data || | |
3906 !imhtml->funcs->image_get_filename || !imhtml->funcs->image_ref || | |
3907 !imhtml->funcs->image_unref) | |
3908 return; | |
3909 | |
3910 image = imhtml->funcs->image_get(id); | |
3911 | |
3912 if (image) { | |
3913 gpointer data; | |
3914 size_t len; | |
3915 | |
3916 data = imhtml->funcs->image_get_data(image); | |
3917 len = imhtml->funcs->image_get_size(image); | |
3918 | |
3919 if (data && len) { | |
3920 GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); | |
3921 gdk_pixbuf_loader_write(loader, data, len, NULL); | |
3922 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); | |
9337 | 3923 if (pixbuf) |
3924 g_object_ref(G_OBJECT(pixbuf)); | |
8962 | 3925 gdk_pixbuf_loader_close(loader, NULL); |
9337 | 3926 g_object_unref(G_OBJECT(loader)); |
8962 | 3927 } |
3928 | |
3929 } | |
3930 | |
3931 if (pixbuf) { | |
3932 filename = imhtml->funcs->image_get_filename(image); | |
3933 imhtml->funcs->image_ref(id); | |
3934 imhtml->im_images = g_slist_prepend(imhtml->im_images, GINT_TO_POINTER(id)); | |
3935 } else { | |
3936 pixbuf = gtk_widget_render_icon(GTK_WIDGET(imhtml), GTK_STOCK_MISSING_IMAGE, | |
3937 GTK_ICON_SIZE_BUTTON, "gtkimhtml-missing-image"); | |
3938 } | |
3939 | |
3940 scalable = gtk_imhtml_image_new(pixbuf, filename, id); | |
3941 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
3942 scalable->add_to(scalable, imhtml, iter); | |
3943 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + | |
3944 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
3945 scalable->scale(scalable, rect.width - minus, rect.height); | |
3946 imhtml->scalables = g_list_append(imhtml->scalables, scalable); | |
3947 | |
3948 g_object_unref(G_OBJECT(pixbuf)); | |
3949 } | |
3950 | |
8677 | 3951 static const gchar *tag_to_html_start(GtkTextTag *tag) |
8061 | 3952 { |
8677 | 3953 const gchar *name; |
3954 static gchar buf[1024]; | |
3955 | |
3956 name = tag->name; | |
3957 g_return_val_if_fail(name != NULL, ""); | |
3958 | |
3959 if (strcmp(name, "BOLD") == 0) { | |
3960 return "<b>"; | |
3961 } else if (strcmp(name, "ITALICS") == 0) { | |
3962 return "<i>"; | |
3963 } else if (strcmp(name, "UNDERLINE") == 0) { | |
3964 return "<u>"; | |
9924 | 3965 } else if (strcmp(name, "STRIKE") == 0) { |
3966 return "<s>"; | |
8677 | 3967 } else if (strncmp(name, "LINK ", 5) == 0) { |
3968 char *tmp = g_object_get_data(G_OBJECT(tag), "link_url"); | |
3969 if (tmp) { | |
3970 g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp); | |
3971 buf[sizeof(buf)-1] = '\0'; | |
3972 return buf; | |
3973 } else { | |
3974 return ""; | |
3975 } | |
3976 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
3977 g_snprintf(buf, sizeof(buf), "<font color=\"%s\">", &name[10]); | |
3978 return buf; | |
3979 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
3980 g_snprintf(buf, sizeof(buf), "<font back=\"%s\">", &name[10]); | |
3981 return buf; | |
3982 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
3983 g_snprintf(buf, sizeof(buf), "<font face=\"%s\">", &name[10]); | |
3984 return buf; | |
3985 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
3986 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); | |
3987 return buf; | |
3988 } else { | |
3989 return ""; | |
3990 } | |
8061 | 3991 } |
3992 | |
8677 | 3993 static const gchar *tag_to_html_end(GtkTextTag *tag) |
8061 | 3994 { |
8677 | 3995 const gchar *name; |
3996 | |
3997 name = tag->name; | |
3998 g_return_val_if_fail(name != NULL, ""); | |
3999 | |
4000 if (strcmp(name, "BOLD") == 0) { | |
4001 return "</b>"; | |
4002 } else if (strcmp(name, "ITALICS") == 0) { | |
4003 return "</i>"; | |
4004 } else if (strcmp(name, "UNDERLINE") == 0) { | |
4005 return "</u>"; | |
9924 | 4006 } else if (strcmp(name, "STRIKE") == 0) { |
4007 return "</s>"; | |
8677 | 4008 } else if (strncmp(name, "LINK ", 5) == 0) { |
4009 return "</a>"; | |
4010 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
4011 return "</font>"; | |
4012 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
4013 return "</font>"; | |
4014 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
4015 return "</font>"; | |
4016 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
4017 return "</font>"; | |
4018 } else { | |
4019 return ""; | |
4020 } | |
4021 } | |
4022 | |
4023 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) | |
4024 { | |
4025 return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && | |
4026 !gtk_text_iter_has_tag(niter, GTK_TEXT_TAG(tag))) || | |
4027 gtk_text_iter_is_end(niter)); | |
8061 | 4028 } |
4029 | |
4030 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
4031 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
8677 | 4032 * check for tags that are toggled on, insert their html form, and push them on the queue. Then insert |
4033 * 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
|
4034 * Finally, replace <, >, &, and " with their HTML equivalent. |
8677 | 4035 */ |
8061 | 4036 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) |
4037 { | |
4038 gunichar c; | |
8677 | 4039 GtkTextIter iter, nextiter; |
8061 | 4040 GString *str = g_string_new(""); |
8677 | 4041 GSList *tags, *sl; |
4042 GQueue *q, *r; | |
4043 GtkTextTag *tag; | |
4044 | |
4045 q = g_queue_new(); | |
4046 r = g_queue_new(); | |
4047 | |
8061 | 4048 |
4049 gtk_text_iter_order(start, end); | |
8677 | 4050 nextiter = iter = *start; |
4051 gtk_text_iter_forward_char(&nextiter); | |
4052 | |
9071 | 4053 /* First add the tags that are already in progress (we don't care about non-printing tags)*/ |
8677 | 4054 tags = gtk_text_iter_get_tags(start); |
4055 | |
4056 for (sl = tags; sl; sl = sl->next) { | |
4057 tag = sl->data; | |
4058 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { | |
9071 | 4059 if (strlen(tag_to_html_end(tag)) > 0) |
4060 g_string_append(str, tag_to_html_start(tag)); | |
8677 | 4061 g_queue_push_tail(q, tag); |
8061 | 4062 } |
4063 } | |
8677 | 4064 g_slist_free(tags); |
8061 | 4065 |
4066 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { | |
8677 | 4067 |
4068 tags = gtk_text_iter_get_tags(&iter); | |
4069 | |
4070 for (sl = tags; sl; sl = sl->next) { | |
4071 tag = sl->data; | |
4072 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { | |
9071 | 4073 if (strlen(tag_to_html_end(tag)) > 0) |
4074 g_string_append(str, tag_to_html_start(tag)); | |
8677 | 4075 g_queue_push_tail(q, tag); |
4076 } | |
4077 } | |
4078 | |
4079 | |
8061 | 4080 if (c == 0xFFFC) { |
4081 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
9071 | 4082 if (anchor) { |
4083 char *text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext"); | |
4084 if (text) | |
4085 str = g_string_append(str, text); | |
4086 } | |
8677 | 4087 } else if (c == '<') { |
4088 str = g_string_append(str, "<"); | |
4089 } else if (c == '>') { | |
4090 str = g_string_append(str, ">"); | |
4091 } else if (c == '&') { | |
4092 str = g_string_append(str, "&"); | |
4093 } else if (c == '"') { | |
4094 str = g_string_append(str, """); | |
4095 } else if (c == '\n') { | |
4096 str = g_string_append(str, "<br>"); | |
8061 | 4097 } else { |
8677 | 4098 str = g_string_append_unichar(str, c); |
4099 } | |
4100 | |
4101 tags = g_slist_reverse(tags); | |
4102 for (sl = tags; sl; sl = sl->next) { | |
4103 tag = sl->data; | |
9071 | 4104 /** don't worry about non-printing tags ending */ |
4105 if (tag_ends_here(tag, &iter, &nextiter) && strlen(tag_to_html_end(tag)) > 0) { | |
8677 | 4106 |
4107 GtkTextTag *tmp; | |
4108 | |
4109 while ((tmp = g_queue_pop_tail(q)) != tag) { | |
4110 if (tmp == NULL) | |
4111 break; | |
4112 | |
9071 | 4113 if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0) |
8677 | 4114 g_queue_push_tail(r, tmp); |
4115 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); | |
4116 } | |
4117 | |
4118 if (tmp == NULL) | |
4119 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); | |
4120 else | |
4121 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
4122 | |
4123 while ((tmp = g_queue_pop_head(r))) { | |
4124 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); | |
4125 g_queue_push_tail(q, tmp); | |
8061 | 4126 } |
4127 } | |
4128 } | |
8677 | 4129 |
4130 g_slist_free(tags); | |
8061 | 4131 gtk_text_iter_forward_char(&iter); |
8677 | 4132 gtk_text_iter_forward_char(&nextiter); |
8061 | 4133 } |
8677 | 4134 |
4135 while ((tag = g_queue_pop_tail(q))) | |
4136 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
4137 | |
4138 g_queue_free(q); | |
4139 g_queue_free(r); | |
8061 | 4140 return g_string_free(str, FALSE); |
4141 } | |
4142 | |
8698 | 4143 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter) |
8061 | 4144 { |
4145 if (imhtml->edit.bold) | |
4146 gtk_imhtml_toggle_bold(imhtml); | |
4147 | |
4148 if (imhtml->edit.italic) | |
4149 gtk_imhtml_toggle_italic(imhtml); | |
4150 | |
4151 if (imhtml->edit.underline) | |
4152 gtk_imhtml_toggle_underline(imhtml); | |
4153 | |
9924 | 4154 if (imhtml->edit.strike) |
4155 gtk_imhtml_toggle_strike(imhtml); | |
4156 | |
8061 | 4157 if (imhtml->edit.forecolor) |
4158 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
4159 | |
4160 if (imhtml->edit.backcolor) | |
4161 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
4162 | |
4163 if (imhtml->edit.fontface) | |
4164 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
4165 | |
8677 | 4166 imhtml->edit.fontsize = 0; |
4167 | |
8719 | 4168 if (imhtml->edit.link) |
4169 gtk_imhtml_toggle_link(imhtml, NULL); | |
4170 | |
8698 | 4171 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter); |
8061 | 4172 |
4173 } | |
4174 | |
4175 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
4176 { | |
4177 GtkTextIter start, end; | |
4178 | |
4179 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
4180 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
4181 return gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
4182 } | |
4183 | |
8677 | 4184 char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml) |
4185 { | |
4186 int i, j, lines; | |
4187 GtkTextIter start, end; | |
4188 char **ret; | |
4189 | |
4190 lines = gtk_text_buffer_get_line_count(imhtml->text_buffer); | |
4191 ret = g_new0(char *, lines + 1); | |
4192 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
4193 end = start; | |
4194 gtk_text_iter_forward_to_line_end(&end); | |
4195 | |
4196 for (i = 0, j = 0; i < lines; i++) { | |
9612 | 4197 if (gtk_text_iter_get_char(&start) != '\n') { |
4198 ret[j] = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
4199 if (ret[j] != NULL) | |
4200 j++; | |
4201 } | |
4202 | |
8677 | 4203 gtk_text_iter_forward_line(&start); |
4204 end = start; | |
4205 gtk_text_iter_forward_to_line_end(&end); | |
4206 } | |
4207 | |
4208 return ret; | |
4209 } | |
4210 | |
4211 char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop) | |
8061 | 4212 { |
8519 | 4213 GString *str = g_string_new(""); |
4214 GtkTextIter iter, end; | |
4215 gunichar c; | |
4216 | |
8677 | 4217 if (start == NULL) |
4218 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
4219 else | |
4220 iter = *start; | |
4221 | |
4222 if (stop == NULL) | |
4223 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
4224 else | |
4225 end = *stop; | |
4226 | |
4227 gtk_text_iter_order(&iter, &end); | |
8519 | 4228 |
4229 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { | |
4230 if (c == 0xFFFC) { | |
8677 | 4231 GtkTextChildAnchor* anchor; |
4232 char *text = NULL; | |
4233 | |
4234 anchor = gtk_text_iter_get_child_anchor(&iter); | |
4235 if (anchor) | |
8698 | 4236 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext"); |
8677 | 4237 if (text) |
4238 str = g_string_append(str, text); | |
8519 | 4239 } else { |
4240 g_string_append_unichar(str, c); | |
4241 } | |
4242 gtk_text_iter_forward_char(&iter); | |
4243 } | |
4244 | |
4245 return g_string_free(str, FALSE); | |
8061 | 4246 } |
8962 | 4247 |
4248 void gtk_imhtml_set_funcs(GtkIMHtml *imhtml, GtkIMHtmlFuncs *f) | |
4249 { | |
4250 g_return_if_fail(imhtml != NULL); | |
4251 imhtml->funcs = f; | |
4252 } |