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