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