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