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