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