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