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