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