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