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