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