Mercurial > pidgin
annotate src/gtkimhtml.c @ 10345:2e01c503aa4f
[gaim-migrate @ 11556]
Patch 1078151 from Felipe Contreras to fix some more MSN bugs:
"User Dislpay messages, and other less used, did not set
an slpcall, so the callback that should not be called,
was called (in some very special cases)."
...
"Here it goes the real real one, as far as I can tell.
Cleaning + organizing + documentation + hard bug fix = big
patch." -- Felipe Contreras
I also fixed drag-and-drop to conversation window file transfers (which
I had broken when I fixed some other dnd thing), made the debug output
of the autoreconnect plugin more useful, and stopped the message
notification plugin notifying you for messages sent by ignored users.
committer: Tailor Script <tailor@pidgin.im>
| author | Stu Tomlinson <stu@nosnilmot.com> |
|---|---|
| date | Sat, 11 Dec 2004 20:01:58 +0000 |
| parents | ec140184437b |
| children | 0c020a10d5da |
| 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 } |
| 9300 | 1358 break; |
| 10145 | 1359 case GTK_IMHTML_DRAG_HTML: |
| 10243 | 1360 { |
| 1361 char *utf8 = NULL; | |
| 1362 /* Ewww. This is all because mozilla thinks that text/html is 'for internal use only.' | |
| 1363 * as explained by this comment in gtkhtml: | |
| 1364 * | |
| 1365 * FIXME This hack decides the charset of the selection. It seems that | |
| 1366 * mozilla/netscape alway use ucs2 for text/html | |
| 1367 * and openoffice.org seems to always use utf8 so we try to validate | |
| 1368 * the string as utf8 and if that fails we assume it is ucs2 | |
| 1369 * | |
| 1370 * See also the comment on text/html here: | |
| 1371 * http://mail.gnome.org/archives/gtk-devel-list/2001-September/msg00114.html | |
| 1372 */ | |
| 1373 if (sd->length >= 2 && !g_utf8_validate(text, sd->length - 1, NULL)) { | |
| 1374 utf8 = g_convert(text, sd->length, "UTF-8", "UCS-2", NULL, NULL, NULL); | |
| 1375 | |
| 1376 if (!utf8) { | |
| 9300 | 1377 gaim_debug_warning("gtkimhtml", "g_convert from UCS-2 failed in drag_rcv_cb\n"); |
| 1378 return; | |
| 1379 } | |
| 10243 | 1380 |
| 1381 if (*(guint16 *)text == 0xfeff || *(guint16 *)text == 0xfffe || TRUE) { | |
| 1382 char *tmp; | |
| 1383 tmp = g_utf8_next_char(utf8); | |
| 1384 memmove(utf8, tmp, strlen(tmp) + 1); | |
| 1385 } | |
| 1386 } else if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
| 9300 | 1387 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); |
| 1388 return; | |
| 1389 } | |
| 10243 | 1390 |
| 1391 gtk_imhtml_insert_html_at_iter(imhtml, utf8 ? utf8 : text, 0, &iter); | |
| 1392 g_free(utf8); | |
| 9300 | 1393 break; |
| 10243 | 1394 } |
| 10145 | 1395 case GTK_IMHTML_DRAG_TEXT: |
| 1396 if (!(*text) || !g_utf8_validate(text, -1, NULL)) { | |
| 1397 gaim_debug_warning("gtkimhtml", "empty string or invalid UTF-8 in drag_rcv_cb\n"); | |
| 1398 return; | |
| 1399 } else { | |
| 1400 char *tmp = gaim_escape_html(text); | |
| 1401 gtk_imhtml_insert_html_at_iter(imhtml, tmp, 0, &iter); | |
| 1402 g_free(tmp); | |
| 1403 } | |
| 1404 break; | |
| 9300 | 1405 default: |
| 10145 | 1406 gtk_drag_finish(dc, FALSE, FALSE, t); |
| 1407 return; | |
| 8091 | 1408 } |
| 1409 gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t); | |
| 1410 } else { | |
| 1411 gtk_drag_finish(dc, FALSE, FALSE, t); | |
| 1412 } | |
| 1413 } | |
| 1414 | |
| 4298 | 1415 /* this isn't used yet |
| 9300 | 1416 static void gtk_smiley_tree_remove (GtkSmileyTree *tree, |
| 4263 | 1417 GtkIMHtmlSmiley *smiley) |
| 4032 | 1418 { |
| 1419 GtkSmileyTree *t = tree; | |
| 4263 | 1420 const gchar *x = smiley->smile; |
| 4032 | 1421 gint len = 0; |
| 1422 | |
| 1423 while (*x) { | |
| 1424 gchar *pos; | |
| 1425 | |
| 1426 if (!t->values) | |
| 1427 return; | |
| 1428 | |
| 1429 pos = strchr (t->values->str, *x); | |
| 1430 if (pos) | |
| 1431 t = t->children [(int) pos - (int) t->values->str]; | |
| 1432 else | |
| 1433 return; | |
| 1434 | |
| 1435 x++; len++; | |
| 1436 } | |
| 1437 | |
|
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1438 if (t->image) { |
| 4032 | 1439 t->image = NULL; |
|
4141
ccec4fde84f4
[gaim-migrate @ 4359]
Christian Hammond <chipx86@chipx86.com>
parents:
4140
diff
changeset
|
1440 } |
| 4032 | 1441 } |
| 4298 | 1442 */ |
| 1443 | |
| 4032 | 1444 |
| 1445 static gint | |
| 1446 gtk_smiley_tree_lookup (GtkSmileyTree *tree, | |
| 1447 const gchar *text) | |
| 1448 { | |
| 1449 GtkSmileyTree *t = tree; | |
| 1450 const gchar *x = text; | |
| 1451 gint len = 0; | |
| 8505 | 1452 gchar *amp; |
| 1453 gint alen; | |
| 4032 | 1454 |
| 1455 while (*x) { | |
| 1456 gchar *pos; | |
| 1457 | |
| 1458 if (!t->values) | |
| 1459 break; | |
| 1460 | |
| 8505 | 1461 if(*x == '&' && gtk_imhtml_is_amp_escape(x, &, &alen)) { |
| 1462 len += alen - strlen(amp); | |
| 1463 x += alen - strlen(amp); | |
| 1464 pos = strchr (t->values->str, *amp); | |
| 1465 } | |
| 9636 | 1466 else if (*x == '<') /* Because we're all WYSIWYG now, a '<' |
| 1467 * char should only appear as the start of a tag. Perhaps a safer (but costlier) | |
| 1468 * check would be to call gtk_imhtml_is_tag on it */ | |
| 1469 return 0; | |
| 8505 | 1470 else |
| 1471 pos = strchr (t->values->str, *x); | |
| 1472 | |
| 4032 | 1473 if (pos) |
| 7371 | 1474 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
| 4032 | 1475 else |
| 1476 break; | |
| 1477 | |
| 1478 x++; len++; | |
| 1479 } | |
| 1480 | |
| 1481 if (t->image) | |
| 1482 return len; | |
| 1483 | |
| 1484 return 0; | |
| 1485 } | |
| 1486 | |
| 1487 void | |
| 4263 | 1488 gtk_imhtml_associate_smiley (GtkIMHtml *imhtml, |
| 1489 gchar *sml, | |
| 1490 GtkIMHtmlSmiley *smiley) | |
| 4032 | 1491 { |
| 1492 GtkSmileyTree *tree; | |
| 1493 g_return_if_fail (imhtml != NULL); | |
| 1494 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
| 7371 | 1495 |
| 4032 | 1496 if (sml == NULL) |
| 1497 tree = imhtml->default_smilies; | |
| 1498 else if ((tree = g_hash_table_lookup(imhtml->smiley_data, sml))) { | |
| 1499 } else { | |
| 1500 tree = gtk_smiley_tree_new(); | |
| 4892 | 1501 g_hash_table_insert(imhtml->smiley_data, g_strdup(sml), tree); |
| 4032 | 1502 } |
| 1503 | |
| 4263 | 1504 gtk_smiley_tree_insert (tree, smiley); |
| 4032 | 1505 } |
| 1506 | |
| 1507 static gboolean | |
| 1508 gtk_imhtml_is_smiley (GtkIMHtml *imhtml, | |
| 1509 GSList *fonts, | |
| 1510 const gchar *text, | |
| 1511 gint *len) | |
| 1512 { | |
| 1513 GtkSmileyTree *tree; | |
| 5967 | 1514 GtkIMHtmlFontDetail *font; |
| 4032 | 1515 char *sml = NULL; |
| 1516 | |
| 1517 if (fonts) { | |
| 1518 font = fonts->data; | |
| 1519 sml = font->sml; | |
| 1520 } | |
| 1521 | |
| 9029 | 1522 if (!sml) |
| 1523 sml = imhtml->protocol_name; | |
| 1524 | |
| 1525 if (!sml || !(tree = g_hash_table_lookup(imhtml->smiley_data, sml))) | |
| 4032 | 1526 tree = imhtml->default_smilies; |
| 9029 | 1527 |
| 4032 | 1528 if (tree == NULL) |
| 1529 return FALSE; | |
| 7371 | 1530 |
| 8505 | 1531 *len = gtk_smiley_tree_lookup (tree, text); |
| 4032 | 1532 return (*len > 0); |
| 1533 } | |
| 1534 | |
|
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1535 GdkPixbufAnimation * |
| 4032 | 1536 gtk_smiley_tree_image (GtkIMHtml *imhtml, |
| 1537 const gchar *sml, | |
| 1538 const gchar *text) | |
| 1539 { | |
| 1540 GtkSmileyTree *t; | |
| 1541 const gchar *x = text; | |
| 1542 if (sml == NULL) | |
| 1543 t = imhtml->default_smilies; | |
| 7371 | 1544 else |
| 4032 | 1545 t = g_hash_table_lookup(imhtml->smiley_data, sml); |
| 7371 | 1546 |
| 4032 | 1547 |
| 1548 if (t == NULL) | |
| 1549 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
| 1550 | |
| 1551 while (*x) { | |
| 1552 gchar *pos; | |
| 1553 | |
| 1554 if (!t->values) { | |
| 1555 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
| 1556 } | |
| 7371 | 1557 |
| 4032 | 1558 pos = strchr (t->values->str, *x); |
| 1559 if (pos) { | |
| 7371 | 1560 t = t->children [GPOINTER_TO_INT(pos) - GPOINTER_TO_INT(t->values->str)]; |
| 4032 | 1561 } else { |
| 1562 return sml ? gtk_smiley_tree_image(imhtml, NULL, text) : NULL; | |
| 1563 } | |
| 1564 x++; | |
| 1565 } | |
| 1566 | |
| 8890 | 1567 if (!t->image->file) |
| 1568 return NULL; | |
| 1569 | |
| 4263 | 1570 if (!t->image->icon) |
|
6814
782907a6ae65
[gaim-migrate @ 7354]
Christian Hammond <chipx86@chipx86.com>
parents:
6648
diff
changeset
|
1571 t->image->icon = gdk_pixbuf_animation_new_from_file(t->image->file, NULL); |
| 4263 | 1572 |
| 1573 return t->image->icon; | |
| 4032 | 1574 } |
| 8890 | 1575 |
| 4793 | 1576 #define VALID_TAG(x) if (!g_ascii_strncasecmp (string, x ">", strlen (x ">"))) { \ |
| 3922 | 1577 *tag = g_strndup (string, strlen (x)); \ |
| 1578 *len = strlen (x) + 1; \ | |
| 1579 return TRUE; \ | |
| 1580 } \ | |
| 1581 (*type)++ | |
| 1428 | 1582 |
| 4793 | 1583 #define VALID_OPT_TAG(x) if (!g_ascii_strncasecmp (string, x " ", strlen (x " "))) { \ |
| 3922 | 1584 const gchar *c = string + strlen (x " "); \ |
| 1585 gchar e = '"'; \ | |
| 1586 gboolean quote = FALSE; \ | |
| 1587 while (*c) { \ | |
| 1588 if (*c == '"' || *c == '\'') { \ | |
| 1589 if (quote && (*c == e)) \ | |
| 1590 quote = !quote; \ | |
| 1591 else if (!quote) { \ | |
| 1592 quote = !quote; \ | |
| 1593 e = *c; \ | |
| 1594 } \ | |
| 1595 } else if (!quote && (*c == '>')) \ | |
| 1596 break; \ | |
| 1597 c++; \ | |
| 1598 } \ | |
| 1599 if (*c) { \ | |
| 1600 *tag = g_strndup (string, c - string); \ | |
| 1601 *len = c - string + 1; \ | |
| 1602 return TRUE; \ | |
| 1603 } \ | |
| 1604 } \ | |
| 1605 (*type)++ | |
| 1428 | 1606 |
| 1607 | |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1608 static gboolean |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1609 gtk_imhtml_is_amp_escape (const gchar *string, |
| 7280 | 1610 gchar **replace, |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1611 gint *length) |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1612 { |
| 7287 | 1613 static char buf[7]; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1614 g_return_val_if_fail (string != NULL, FALSE); |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1615 g_return_val_if_fail (replace != NULL, FALSE); |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1616 g_return_val_if_fail (length != NULL, FALSE); |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1617 |
| 4793 | 1618 if (!g_ascii_strncasecmp (string, "&", 5)) { |
| 7280 | 1619 *replace = "&"; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1620 *length = 5; |
| 4793 | 1621 } else if (!g_ascii_strncasecmp (string, "<", 4)) { |
| 7280 | 1622 *replace = "<"; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1623 *length = 4; |
| 4793 | 1624 } else if (!g_ascii_strncasecmp (string, ">", 4)) { |
| 7280 | 1625 *replace = ">"; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1626 *length = 4; |
| 4793 | 1627 } else if (!g_ascii_strncasecmp (string, " ", 6)) { |
| 7280 | 1628 *replace = " "; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1629 *length = 6; |
| 4793 | 1630 } else if (!g_ascii_strncasecmp (string, "©", 6)) { |
| 7280 | 1631 *replace = "©"; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1632 *length = 6; |
| 4793 | 1633 } else if (!g_ascii_strncasecmp (string, """, 6)) { |
| 7280 | 1634 *replace = "\""; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1635 *length = 6; |
| 4793 | 1636 } else if (!g_ascii_strncasecmp (string, "®", 5)) { |
| 7280 | 1637 *replace = "®"; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1638 *length = 5; |
| 5093 | 1639 } else if (!g_ascii_strncasecmp (string, "'", 6)) { |
| 7280 | 1640 *replace = "\'"; |
| 5093 | 1641 *length = 6; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1642 } else if (*(string + 1) == '#') { |
|
2022
199ba82faacb
[gaim-migrate @ 2032]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2002
diff
changeset
|
1643 guint pound = 0; |
| 3004 | 1644 if ((sscanf (string, "&#%u;", £) == 1) && pound != 0) { |
| 7287 | 1645 int buflen; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1646 if (*(string + 3 + (gint)log10 (pound)) != ';') |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1647 return FALSE; |
| 7287 | 1648 buflen = g_unichar_to_utf8((gunichar)pound, buf); |
| 1649 buf[buflen] = '\0'; | |
| 7280 | 1650 *replace = buf; |
|
1472
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1651 *length = 2; |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1652 while (isdigit ((gint) string [*length])) (*length)++; |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1653 if (string [*length] == ';') (*length)++; |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1654 } else { |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1655 return FALSE; |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1656 } |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1657 } else { |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1658 return FALSE; |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1659 } |
|
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 return TRUE; |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1662 } |
|
be620a051d6d
[gaim-migrate @ 1482]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1463
diff
changeset
|
1663 |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1664 static gboolean |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1665 gtk_imhtml_is_tag (const gchar *string, |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1666 gchar **tag, |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1667 gint *len, |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1668 gint *type) |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1669 { |
| 8061 | 1670 char *close; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1671 *type = 1; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1672 |
| 8118 | 1673 |
| 8061 | 1674 if (!(close = strchr (string, '>'))) |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1675 return FALSE; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1676 |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1677 VALID_TAG ("B"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1678 VALID_TAG ("BOLD"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1679 VALID_TAG ("/B"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1680 VALID_TAG ("/BOLD"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1681 VALID_TAG ("I"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1682 VALID_TAG ("ITALIC"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1683 VALID_TAG ("/I"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1684 VALID_TAG ("/ITALIC"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1685 VALID_TAG ("U"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1686 VALID_TAG ("UNDERLINE"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1687 VALID_TAG ("/U"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1688 VALID_TAG ("/UNDERLINE"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1689 VALID_TAG ("S"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1690 VALID_TAG ("STRIKE"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1691 VALID_TAG ("/S"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1692 VALID_TAG ("/STRIKE"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1693 VALID_TAG ("SUB"); |
|
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 ("SUP"); |
|
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 ("PRE"); |
|
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 ("TITLE"); |
|
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 ("BR"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1702 VALID_TAG ("HR"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1703 VALID_TAG ("/FONT"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1704 VALID_TAG ("/A"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1705 VALID_TAG ("P"); |
|
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 ("H3"); |
|
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 ("HTML"); |
|
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 ("BODY"); |
|
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 ("FONT"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1714 VALID_TAG ("HEAD"); |
| 2993 | 1715 VALID_TAG ("/HEAD"); |
| 1716 VALID_TAG ("BINARY"); | |
| 1717 VALID_TAG ("/BINARY"); | |
| 5093 | 1718 |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1719 VALID_OPT_TAG ("HR"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1720 VALID_OPT_TAG ("FONT"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1721 VALID_OPT_TAG ("BODY"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1722 VALID_OPT_TAG ("A"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1723 VALID_OPT_TAG ("IMG"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1724 VALID_OPT_TAG ("P"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1725 VALID_OPT_TAG ("H3"); |
| 5093 | 1726 VALID_OPT_TAG ("HTML"); |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1727 |
| 5101 | 1728 VALID_TAG ("CITE"); |
| 1729 VALID_TAG ("/CITE"); | |
| 1730 VALID_TAG ("EM"); | |
| 1731 VALID_TAG ("/EM"); | |
| 1732 VALID_TAG ("STRONG"); | |
| 1733 VALID_TAG ("/STRONG"); | |
| 1734 | |
| 5104 | 1735 VALID_OPT_TAG ("SPAN"); |
| 1736 VALID_TAG ("/SPAN"); | |
| 5174 | 1737 VALID_TAG ("BR/"); /* hack until gtkimhtml handles things better */ |
| 6982 | 1738 VALID_TAG ("IMG"); |
| 8026 | 1739 VALID_TAG("SPAN"); |
| 8061 | 1740 VALID_OPT_TAG("BR"); |
| 7988 | 1741 |
| 4793 | 1742 if (!g_ascii_strncasecmp(string, "!--", strlen ("!--"))) { |
|
2954
f6c4f2187c08
[gaim-migrate @ 2967]
Christian Hammond <chipx86@chipx86.com>
parents:
2898
diff
changeset
|
1743 gchar *e = strstr (string + strlen("!--"), "-->"); |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1744 if (e) { |
| 9726 | 1745 /* |
| 1746 * If we uncomment the following line then HTML comments will be | |
| 1747 * hidden. This is good because it means when a WinAIM users pastes | |
| 1748 * part of a conversation to you, the screen names won't be | |
| 1749 * duplicated (because WinAIM pastes an HTML comment containing the | |
| 1750 * screen name, for some reason). | |
| 1751 * | |
| 1752 * However, uncommenting this is bad because we use HTML comment | |
| 1753 * tags to print timestamps to conversations (at least, I think...) | |
| 1754 * | |
| 1755 * KingAnt thinks it would be best to display timestamps using | |
| 1756 * something other than comment tags. | |
| 1757 */ | |
| 1758 /* *type = -1; */ | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1759 *len = e - string + strlen ("-->"); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1760 *tag = g_strndup (string + strlen ("!--"), *len - strlen ("!---->")); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1761 return TRUE; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1762 } |
| 8118 | 1763 } |
| 1764 | |
| 8061 | 1765 *type = -1; |
| 1766 *len = close - string + 1; | |
| 1767 *tag = g_strndup(string, *len - 1); | |
| 1768 return TRUE; | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1769 } |
|
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 static gchar* |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1772 gtk_imhtml_get_html_opt (gchar *tag, |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1773 const gchar *opt) |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1774 { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1775 gchar *t = tag; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1776 gchar *e, *a; |
| 5177 | 1777 gchar *val; |
| 1778 gint len; | |
| 7280 | 1779 gchar *c; |
| 5177 | 1780 GString *ret; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1781 |
| 4793 | 1782 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1783 gboolean quote = FALSE; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1784 if (*t == '\0') break; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1785 while (*t && !((*t == ' ') && !quote)) { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1786 if (*t == '\"') |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1787 quote = ! quote; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1788 t++; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1789 } |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1790 while (*t && (*t == ' ')) t++; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1791 } |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1792 |
| 4793 | 1793 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1794 t += strlen (opt); |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1795 } else { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1796 return NULL; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1797 } |
|
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 if ((*t == '\"') || (*t == '\'')) { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1800 e = a = ++t; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1801 while (*e && (*e != *(t - 1))) e++; |
| 2993 | 1802 if (*e == '\0') { |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1803 return NULL; |
| 5177 | 1804 } else |
| 1805 val = g_strndup(a, e - a); | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1806 } else { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1807 e = a = t; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1808 while (*e && !isspace ((gint) *e)) e++; |
| 5177 | 1809 val = g_strndup(a, e - a); |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1810 } |
| 5177 | 1811 |
| 1812 ret = g_string_new(""); | |
| 1813 e = val; | |
| 1814 while(*e) { | |
| 1815 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
| 7280 | 1816 ret = g_string_append(ret, c); |
| 5177 | 1817 e += len; |
| 1818 } else { | |
| 1819 ret = g_string_append_c(ret, *e); | |
| 1820 e++; | |
| 1821 } | |
| 1822 } | |
| 1823 | |
| 1824 g_free(val); | |
| 8568 | 1825 |
| 1826 return g_string_free(ret, FALSE); | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1827 } |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
1828 |
| 8118 | 1829 /* Inline CSS Support - Douglas Thrift */ |
| 1830 static gchar* | |
| 1831 gtk_imhtml_get_css_opt (gchar *style, | |
| 1832 const gchar *opt) | |
| 1833 { | |
| 1834 gchar *t = style; | |
| 1835 gchar *e, *a; | |
| 1836 gchar *val; | |
| 1837 gint len; | |
| 1838 gchar *c; | |
| 1839 GString *ret; | |
| 1840 | |
| 1841 while (g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
| 8177 | 1842 /* gboolean quote = FALSE; */ |
| 8118 | 1843 if (*t == '\0') break; |
| 1844 while (*t && !((*t == ' ') /*&& !quote*/)) { | |
| 1845 /* if (*t == '\"') | |
| 8177 | 1846 quote = ! quote; */ |
| 8118 | 1847 t++; |
| 1848 } | |
| 1849 while (*t && (*t == ' ')) t++; | |
| 1850 } | |
| 1851 | |
| 1852 if (!g_ascii_strncasecmp (t, opt, strlen (opt))) { | |
| 1853 t += strlen (opt); | |
| 1854 } else { | |
| 1855 return NULL; | |
| 1856 } | |
| 1857 | |
| 1858 /* if ((*t == '\"') || (*t == '\'')) { | |
| 1859 e = a = ++t; | |
| 1860 while (*e && (*e != *(t - 1))) e++; | |
| 1861 if (*e == '\0') { | |
| 1862 return NULL; | |
| 1863 } else | |
| 1864 val = g_strndup(a, e - a); | |
| 1865 } else { | |
| 1866 e = a = t; | |
| 1867 while (*e && !isspace ((gint) *e)) e++; | |
| 1868 val = g_strndup(a, e - a); | |
| 1869 }*/ | |
| 1870 | |
| 1871 e = a = t; | |
| 1872 while (*e && *e != ';') e++; | |
| 1873 val = g_strndup(a, e - a); | |
| 1874 | |
| 1875 ret = g_string_new(""); | |
| 1876 e = val; | |
| 1877 while(*e) { | |
| 1878 if(gtk_imhtml_is_amp_escape(e, &c, &len)) { | |
| 1879 ret = g_string_append(ret, c); | |
| 1880 e += len; | |
| 1881 } else { | |
| 1882 ret = g_string_append_c(ret, *e); | |
| 1883 e++; | |
| 1884 } | |
| 1885 } | |
| 1886 | |
| 1887 g_free(val); | |
| 1888 val = ret->str; | |
| 1889 g_string_free(ret, FALSE); | |
| 1890 return val; | |
| 1891 } | |
| 3922 | 1892 |
| 8334 | 1893 static const char *accepted_protocols[] = { |
| 1894 "http://", | |
| 1895 "https://", | |
| 1896 "ftp://" | |
| 1897 }; | |
| 1898 | |
| 1899 static const int accepted_protocols_size = 3; | |
| 1900 | |
| 1901 /* returns if the beginning of the text is a protocol. If it is the protocol, returns the length so | |
| 1902 the caller knows how long the protocol string is. */ | |
| 1903 int gtk_imhtml_is_protocol(const char *text) | |
| 1904 { | |
| 1905 gint i; | |
| 1906 | |
| 1907 for(i=0; i<accepted_protocols_size; i++){ | |
| 1908 if( strncasecmp(text, accepted_protocols[i], strlen(accepted_protocols[i])) == 0 ){ | |
| 1909 return strlen(accepted_protocols[i]); | |
| 1910 } | |
| 1911 } | |
| 1912 return 0; | |
| 1913 } | |
| 1914 | |
| 8677 | 1915 /* |
| 1916 <KingAnt> marv: The two IM image functions in oscar are gaim_odc_send_im and gaim_odc_incoming | |
| 1917 | |
| 1918 | |
| 1919 [19:58] <Robot101> marv: images go into the imgstore, a refcounted... well.. hash. :) | |
| 1920 [19:59] <KingAnt> marv: I think the image tag used by the core is something like <img id="#"/> | |
| 1921 [19:59] Ro0tSiEgE robert42 RobFlynn Robot101 ross22 roz | |
| 1922 [20:00] <KingAnt> marv: Where the ID is the what is returned when you add the image to the imgstore using gaim_imgstore_add | |
| 1923 [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? | |
| 1924 [20:00] <KingAnt> marv: Right | |
| 1925 [20:00] <marv> alright | |
| 1926 | |
| 1927 Here's my plan with IMImages. make gtk_imhtml_[append|insert]_text_with_images instead just | |
| 1928 gtkimhtml_[append|insert]_text (hrm maybe it should be called html instead of text), add a | |
| 1929 function for gaim to register for look up images, i.e. gtk_imhtml_set_get_img_fnc, so that | |
| 1930 images can be looked up like that, instead of passing a GSList of them. | |
| 1931 */ | |
| 1932 | |
| 1933 void gtk_imhtml_append_text_with_images (GtkIMHtml *imhtml, | |
| 1934 const gchar *text, | |
| 1935 GtkIMHtmlOptions options, | |
| 1936 GSList *unused) | |
| 1428 | 1937 { |
| 8677 | 1938 GtkTextIter iter, ins, sel; |
| 1939 GdkRectangle rect; | |
| 1940 int y, height, ins_offset = 0, sel_offset = 0; | |
| 1941 gboolean fixins = FALSE, fixsel = FALSE; | |
| 1942 | |
| 1943 g_return_if_fail (imhtml != NULL); | |
| 1944 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
| 1945 g_return_if_fail (text != NULL); | |
| 1946 | |
| 1947 | |
| 1948 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
| 1949 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, gtk_text_buffer_get_insert(imhtml->text_buffer)); | |
| 1950 if (gtk_text_iter_equal(&iter, &ins) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
| 1951 fixins = TRUE; | |
| 1952 ins_offset = gtk_text_iter_get_offset(&ins); | |
| 1953 } | |
| 1954 | |
| 1955 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &sel, gtk_text_buffer_get_selection_bound(imhtml->text_buffer)); | |
| 1956 if (gtk_text_iter_equal(&iter, &sel) && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) { | |
| 1957 fixsel = TRUE; | |
| 1958 sel_offset = gtk_text_iter_get_offset(&sel); | |
| 1959 } | |
| 1960 | |
| 1961 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
| 1962 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height); | |
| 1963 | |
| 1964 | |
| 1965 if(((y + height) - (rect.y + rect.height)) > height | |
| 1966 && gtk_text_buffer_get_char_count(imhtml->text_buffer)){ | |
| 1967 options |= GTK_IMHTML_NO_SCROLL; | |
| 1968 } | |
| 1969 | |
| 1970 gtk_imhtml_insert_html_at_iter(imhtml, text, options, &iter); | |
| 1971 | |
| 1972 if (fixins) { | |
| 1973 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ins, ins_offset); | |
| 1974 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_insert(imhtml->text_buffer), &ins); | |
| 1975 } | |
| 1976 | |
| 1977 if (fixsel) { | |
| 1978 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &sel, sel_offset); | |
| 1979 gtk_text_buffer_move_mark(imhtml->text_buffer, gtk_text_buffer_get_selection_bound(imhtml->text_buffer), &sel); | |
| 1980 } | |
| 1981 | |
| 1982 if (!(options & GTK_IMHTML_NO_SCROLL)) { | |
| 8729 | 1983 gtk_imhtml_scroll_to_end(imhtml); |
| 8677 | 1984 } |
| 1985 } | |
| 1986 | |
| 8729 | 1987 void gtk_imhtml_scroll_to_end(GtkIMHtml *imhtml) |
| 1988 { | |
| 1989 GtkTextIter iter; | |
| 1990 /* If this seems backwards at first glance, well it's not. | |
| 1991 * It means scroll such that the mark is closest to the top, | |
| 1992 * and closest to the right as possible. Remember kids, you have | |
| 1993 * to scroll left to move a given spot closest to the right, | |
| 1994 * and scroll down to move a spot closest to the top. | |
| 1995 */ | |
| 1996 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &iter); | |
| 1997 gtk_text_iter_set_line_offset(&iter, 0); | |
| 1998 gtk_text_buffer_move_mark(imhtml->text_buffer, imhtml->scrollpoint, &iter); | |
| 1999 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(imhtml), imhtml->scrollpoint, | |
| 2000 0, TRUE, 1.0, 0.0); | |
| 2001 } | |
| 2002 | |
| 8677 | 2003 void gtk_imhtml_insert_html_at_iter(GtkIMHtml *imhtml, |
| 2004 const gchar *text, | |
| 2005 GtkIMHtmlOptions options, | |
| 2006 GtkTextIter *iter) | |
| 2007 { | |
| 8061 | 2008 GdkRectangle rect; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2009 gint pos = 0; |
| 3922 | 2010 gchar *ws; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2011 gchar *tag; |
| 3922 | 2012 gchar *bg = NULL; |
| 6982 | 2013 gint len; |
| 4032 | 2014 gint tlen, smilelen, wpos=0; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2015 gint type; |
| 3922 | 2016 const gchar *c; |
| 7280 | 2017 gchar *amp; |
| 8334 | 2018 gint len_protocol; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2019 |
| 1428 | 2020 guint bold = 0, |
| 2021 italics = 0, | |
| 2022 underline = 0, | |
| 2023 strike = 0, | |
| 2024 sub = 0, | |
| 2025 sup = 0, | |
|
1691
d802b115800f
[gaim-migrate @ 1701]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1647
diff
changeset
|
2026 title = 0, |
| 8061 | 2027 pre = 0; |
| 1428 | 2028 |
| 10217 | 2029 gboolean br = FALSE; |
| 2030 | |
| 3922 | 2031 GSList *fonts = NULL; |
| 8506 | 2032 GObject *object; |
| 8061 | 2033 GtkIMHtmlScalable *scalable = NULL; |
| 8677 | 2034 |
| 2035 g_return_if_fail (imhtml != NULL); | |
| 2036 g_return_if_fail (GTK_IS_IMHTML (imhtml)); | |
| 2037 g_return_if_fail (text != NULL); | |
| 3922 | 2038 c = text; |
| 6982 | 2039 len = strlen(text); |
| 3922 | 2040 ws = g_malloc(len + 1); |
| 2041 ws[0] = 0; | |
| 1428 | 2042 |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2043 while (pos < len) { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2044 if (*c == '<' && gtk_imhtml_is_tag (c + 1, &tag, &tlen, &type)) { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2045 c++; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2046 pos++; |
| 8061 | 2047 ws[wpos] = '\0'; |
| 10217 | 2048 br = FALSE; |
| 8061 | 2049 switch (type) |
| 3922 | 2050 { |
| 2051 case 1: /* B */ | |
| 2052 case 2: /* BOLD */ | |
| 5101 | 2053 case 54: /* STRONG */ |
| 8677 | 2054 |
| 2055 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
| 2056 | |
| 2057 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD)) | |
| 8061 | 2058 gtk_imhtml_toggle_bold(imhtml); |
| 3922 | 2059 bold++; |
| 8061 | 2060 ws[0] = '\0'; wpos = 0; |
| 3922 | 2061 break; |
| 2062 case 3: /* /B */ | |
| 2063 case 4: /* /BOLD */ | |
| 5101 | 2064 case 55: /* /STRONG */ |
| 8677 | 2065 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2066 ws[0] = '\0'; wpos = 0; |
| 2067 | |
| 3922 | 2068 if (bold) |
| 2069 bold--; | |
| 8677 | 2070 if ((bold == 0) && (imhtml->format_functions & GTK_IMHTML_BOLD) && !imhtml->wbfo) |
| 8061 | 2071 gtk_imhtml_toggle_bold(imhtml); |
| 3922 | 2072 break; |
| 2073 case 5: /* I */ | |
| 2074 case 6: /* ITALIC */ | |
| 5101 | 2075 case 52: /* EM */ |
| 8677 | 2076 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2077 ws[0] = '\0'; wpos = 0; |
| 8677 | 2078 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC)) |
| 8061 | 2079 gtk_imhtml_toggle_italic(imhtml); |
| 3922 | 2080 italics++; |
| 2081 break; | |
| 2082 case 7: /* /I */ | |
| 2083 case 8: /* /ITALIC */ | |
| 5101 | 2084 case 53: /* /EM */ |
| 8677 | 2085 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2086 ws[0] = '\0'; wpos = 0; |
| 3922 | 2087 if (italics) |
| 2088 italics--; | |
| 8677 | 2089 if ((italics == 0) && (imhtml->format_functions & GTK_IMHTML_ITALIC) && !imhtml->wbfo) |
| 8061 | 2090 gtk_imhtml_toggle_italic(imhtml); |
| 3922 | 2091 break; |
| 2092 case 9: /* U */ | |
| 2093 case 10: /* UNDERLINE */ | |
| 8677 | 2094 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2095 ws[0] = '\0'; wpos = 0; |
| 8677 | 2096 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
| 8061 | 2097 gtk_imhtml_toggle_underline(imhtml); |
| 3922 | 2098 underline++; |
| 2099 break; | |
| 2100 case 11: /* /U */ | |
| 2101 case 12: /* /UNDERLINE */ | |
| 8677 | 2102 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2103 ws[0] = '\0'; wpos = 0; |
| 3922 | 2104 if (underline) |
| 2105 underline--; | |
| 8677 | 2106 if ((underline == 0) && (imhtml->format_functions & GTK_IMHTML_UNDERLINE) && !imhtml->wbfo) |
| 8061 | 2107 gtk_imhtml_toggle_underline(imhtml); |
| 3922 | 2108 break; |
| 2109 case 13: /* S */ | |
| 2110 case 14: /* STRIKE */ | |
| 9924 | 2111 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 2112 ws[0] = '\0'; wpos = 0; | |
| 2113 if ((strike == 0) && (imhtml->format_functions & GTK_IMHTML_STRIKE)) | |
| 2114 gtk_imhtml_toggle_strike(imhtml); | |
| 3922 | 2115 strike++; |
| 2116 break; | |
| 2117 case 15: /* /S */ | |
| 2118 case 16: /* /STRIKE */ | |
| 9924 | 2119 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 2120 ws[0] = '\0'; wpos = 0; | |
| 3922 | 2121 if (strike) |
| 2122 strike--; | |
| 9924 | 2123 if ((strike == 0) && (imhtml->format_functions & GTK_IMHTML_STRIKE) && !imhtml->wbfo) |
| 2124 gtk_imhtml_toggle_strike(imhtml); | |
| 3922 | 2125 break; |
| 2126 case 17: /* SUB */ | |
| 8677 | 2127 /* FIXME: reimpliment this */ |
| 3922 | 2128 sub++; |
| 2129 break; | |
| 2130 case 18: /* /SUB */ | |
| 8677 | 2131 /* FIXME: reimpliment this */ |
| 3922 | 2132 if (sub) |
| 2133 sub--; | |
| 2134 break; | |
| 2135 case 19: /* SUP */ | |
| 8677 | 2136 /* FIXME: reimplement this */ |
| 3922 | 2137 sup++; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2138 break; |
| 3922 | 2139 case 20: /* /SUP */ |
| 8677 | 2140 /* FIXME: reimplement this */ |
| 3922 | 2141 if (sup) |
| 2142 sup--; | |
| 2143 break; | |
| 2144 case 21: /* PRE */ | |
| 8677 | 2145 /* FIXME: reimplement this */ |
| 3922 | 2146 pre++; |
| 2147 break; | |
| 2148 case 22: /* /PRE */ | |
| 8677 | 2149 /* FIXME: reimplement this */ |
| 3922 | 2150 if (pre) |
| 2151 pre--; | |
| 2152 break; | |
| 2153 case 23: /* TITLE */ | |
| 8677 | 2154 /* FIXME: what was this supposed to do anyway? */ |
| 3922 | 2155 title++; |
| 2156 break; | |
| 2157 case 24: /* /TITLE */ | |
| 8677 | 2158 /* FIXME: make this undo whatever 23 was supposed to do */ |
| 3922 | 2159 if (title) { |
| 2160 if (options & GTK_IMHTML_NO_TITLE) { | |
| 2161 wpos = 0; | |
| 2162 ws [wpos] = '\0'; | |
| 2163 } | |
| 2164 title--; | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2165 } |
| 3922 | 2166 break; |
| 2167 case 25: /* BR */ | |
| 5174 | 2168 case 58: /* BR/ */ |
| 8061 | 2169 case 61: /* BR (opt) */ |
| 3922 | 2170 ws[wpos] = '\n'; |
| 2171 wpos++; | |
| 10217 | 2172 br = TRUE; |
| 6982 | 2173 break; |
| 3922 | 2174 case 26: /* HR */ |
| 2175 case 42: /* HR (opt) */ | |
| 8726 | 2176 { |
| 2177 int minus; | |
| 2178 | |
| 3922 | 2179 ws[wpos++] = '\n'; |
| 8677 | 2180 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 2181 | |
| 5967 | 2182 scalable = gtk_imhtml_hr_new(); |
| 8061 | 2183 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
| 8677 | 2184 scalable->add_to(scalable, imhtml, iter); |
| 8726 | 2185 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + |
| 2186 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
| 2187 scalable->scale(scalable, rect.width - minus, rect.height); | |
| 8061 | 2188 imhtml->scalables = g_list_append(imhtml->scalables, scalable); |
| 2189 ws[0] = '\0'; wpos = 0; | |
| 7942 | 2190 ws[wpos++] = '\n'; |
| 8061 | 2191 |
| 3922 | 2192 break; |
| 8726 | 2193 } |
| 3922 | 2194 case 27: /* /FONT */ |
| 8677 | 2195 if (fonts && !imhtml->wbfo) { |
| 5967 | 2196 GtkIMHtmlFontDetail *font = fonts->data; |
| 8677 | 2197 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2198 ws[0] = '\0'; wpos = 0; |
| 8177 | 2199 /* NEW_BIT (NEW_TEXT_BIT); */ |
| 8677 | 2200 |
| 8698 | 2201 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) { |
| 8061 | 2202 gtk_imhtml_toggle_fontface(imhtml, NULL); |
| 3922 | 2203 g_free (font->face); |
| 8061 | 2204 } |
| 8698 | 2205 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
| 8061 | 2206 gtk_imhtml_toggle_forecolor(imhtml, NULL); |
| 3922 | 2207 g_free (font->fore); |
| 8061 | 2208 } |
| 8698 | 2209 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
| 8061 | 2210 gtk_imhtml_toggle_backcolor(imhtml, NULL); |
| 3922 | 2211 g_free (font->back); |
| 8061 | 2212 } |
| 4032 | 2213 if (font->sml) |
| 2214 g_free (font->sml); | |
| 8309 | 2215 |
| 8698 | 2216 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
| 8309 | 2217 gtk_imhtml_font_set_size(imhtml, 3); |
| 2218 | |
| 9245 | 2219 g_free(font); |
| 2220 | |
| 8309 | 2221 fonts = fonts->next; |
| 2222 if (fonts) { | |
| 2223 GtkIMHtmlFontDetail *font = fonts->data; | |
| 8677 | 2224 |
| 8698 | 2225 if (font->face && (imhtml->format_functions & GTK_IMHTML_FACE)) |
| 8309 | 2226 gtk_imhtml_toggle_fontface(imhtml, font->face); |
| 8698 | 2227 if (font->fore && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
| 8309 | 2228 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
| 8698 | 2229 if (font->back && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
| 8309 | 2230 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
| 8698 | 2231 if ((font->size != 3) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
| 8309 | 2232 gtk_imhtml_font_set_size(imhtml, font->size); |
| 2233 } | |
| 3922 | 2234 } |
| 8309 | 2235 break; |
| 3922 | 2236 case 28: /* /A */ |
| 8677 | 2237 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 2238 gtk_imhtml_toggle_link(imhtml, NULL); | |
| 2239 ws[0] = '\0'; wpos = 0; | |
| 8061 | 2240 break; |
| 8118 | 2241 |
| 3922 | 2242 case 29: /* P */ |
| 2243 case 30: /* /P */ | |
| 2244 case 31: /* H3 */ | |
| 2245 case 32: /* /H3 */ | |
| 2246 case 33: /* HTML */ | |
| 2247 case 34: /* /HTML */ | |
| 2248 case 35: /* BODY */ | |
| 2249 case 36: /* /BODY */ | |
| 2250 case 37: /* FONT */ | |
| 2251 case 38: /* HEAD */ | |
| 2252 case 39: /* /HEAD */ | |
| 6982 | 2253 case 40: /* BINARY */ |
| 2254 case 41: /* /BINARY */ | |
| 3922 | 2255 break; |
| 2256 case 43: /* FONT (opt) */ | |
| 2257 { | |
| 4032 | 2258 gchar *color, *back, *face, *size, *sml; |
| 5967 | 2259 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
| 3922 | 2260 color = gtk_imhtml_get_html_opt (tag, "COLOR="); |
| 2261 back = gtk_imhtml_get_html_opt (tag, "BACK="); | |
| 2262 face = gtk_imhtml_get_html_opt (tag, "FACE="); | |
| 2263 size = gtk_imhtml_get_html_opt (tag, "SIZE="); | |
| 4032 | 2264 sml = gtk_imhtml_get_html_opt (tag, "SML="); |
| 2265 if (!(color || back || face || size || sml)) | |
| 3922 | 2266 break; |
| 8061 | 2267 |
| 8677 | 2268 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2269 ws[0] = '\0'; wpos = 0; |
| 2270 | |
| 5967 | 2271 font = g_new0 (GtkIMHtmlFontDetail, 1); |
| 3922 | 2272 if (fonts) |
| 2273 oldfont = fonts->data; | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2274 |
| 8677 | 2275 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) { |
| 3922 | 2276 font->fore = color; |
| 8061 | 2277 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
| 8677 | 2278 } |
| 8309 | 2279 //else if (oldfont && oldfont->fore) |
| 2280 // font->fore = g_strdup(oldfont->fore); | |
| 8677 | 2281 |
| 2282 if (back && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { | |
| 3922 | 2283 font->back = back; |
| 8061 | 2284 gtk_imhtml_toggle_backcolor(imhtml, font->back); |
| 8309 | 2285 } |
| 2286 //else if (oldfont && oldfont->back) | |
| 2287 // font->back = g_strdup(oldfont->back); | |
| 8677 | 2288 |
| 2289 if (face && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) { | |
| 3922 | 2290 font->face = face; |
| 8061 | 2291 gtk_imhtml_toggle_fontface(imhtml, font->face); |
| 8309 | 2292 } |
| 2293 //else if (oldfont && oldfont->face) | |
| 2294 // font->face = g_strdup(oldfont->face); | |
| 4032 | 2295 |
| 2296 if (sml) | |
| 2297 font->sml = sml; | |
| 2298 else if (oldfont && oldfont->sml) | |
| 2299 font->sml = g_strdup(oldfont->sml); | |
| 2300 | |
| 8677 | 2301 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) { |
| 3922 | 2302 if (*size == '+') { |
| 2303 sscanf (size + 1, "%hd", &font->size); | |
| 2304 font->size += 3; | |
| 2305 } else if (*size == '-') { | |
| 2306 sscanf (size + 1, "%hd", &font->size); | |
| 2307 font->size = MAX (0, 3 - font->size); | |
| 2308 } else if (isdigit (*size)) { | |
| 2309 sscanf (size, "%hd", &font->size); | |
| 8061 | 2310 } |
| 6042 | 2311 if (font->size > 100) |
| 2312 font->size = 100; | |
| 3922 | 2313 } else if (oldfont) |
| 2314 font->size = oldfont->size; | |
| 8309 | 2315 else |
| 2316 font->size = 3; | |
| 8698 | 2317 if ((imhtml->format_functions & (GTK_IMHTML_GROW|GTK_IMHTML_SHRINK))) |
| 2318 gtk_imhtml_font_set_size(imhtml, font->size); | |
| 3922 | 2319 g_free(size); |
| 2320 fonts = g_slist_prepend (fonts, font); | |
| 2321 } | |
| 2322 break; | |
| 2323 case 44: /* BODY (opt) */ | |
| 2324 if (!(options & GTK_IMHTML_NO_COLOURS)) { | |
| 2325 char *bgcolor = gtk_imhtml_get_html_opt (tag, "BGCOLOR="); | |
| 8677 | 2326 if (bgcolor && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) { |
| 2327 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
| 8061 | 2328 ws[0] = '\0'; wpos = 0; |
| 8177 | 2329 /* NEW_BIT(NEW_TEXT_BIT); */ |
| 3922 | 2330 if (bg) |
| 2331 g_free(bg); | |
| 2332 bg = bgcolor; | |
| 8061 | 2333 gtk_imhtml_toggle_backcolor(imhtml, bg); |
|
2885
f72efa29c109
[gaim-migrate @ 2898]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2871
diff
changeset
|
2334 } |
| 1428 | 2335 } |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2336 break; |
| 3922 | 2337 case 45: /* A (opt) */ |
| 2338 { | |
| 2339 gchar *href = gtk_imhtml_get_html_opt (tag, "HREF="); | |
| 8677 | 2340 if (href && (imhtml->format_functions & GTK_IMHTML_LINK)) { |
| 2341 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
| 8061 | 2342 ws[0] = '\0'; wpos = 0; |
| 8677 | 2343 gtk_imhtml_toggle_link(imhtml, href); |
| 3922 | 2344 } |
| 2993 | 2345 } |
| 3922 | 2346 break; |
| 4895 | 2347 case 46: /* IMG (opt) */ |
| 6982 | 2348 case 59: /* IMG */ |
| 4895 | 2349 { |
| 8962 | 2350 const char *id; |
| 2351 | |
| 2352 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
| 2353 ws[0] = '\0'; wpos = 0; | |
| 4895 | 2354 |
| 8677 | 2355 if (!(imhtml->format_functions & GTK_IMHTML_IMAGE)) |
| 2356 break; | |
| 2357 | |
| 8962 | 2358 id = gtk_imhtml_get_html_opt(tag, "ID="); |
| 9186 | 2359 if (!id) |
| 2360 break; | |
| 8962 | 2361 gtk_imhtml_insert_image_at_iter(imhtml, atoi(id), iter); |
| 2362 break; | |
| 4895 | 2363 } |
| 3922 | 2364 case 47: /* P (opt) */ |
| 2365 case 48: /* H3 (opt) */ | |
| 5093 | 2366 case 49: /* HTML (opt) */ |
| 5101 | 2367 case 50: /* CITE */ |
| 2368 case 51: /* /CITE */ | |
| 8026 | 2369 case 56: /* SPAN (opt) */ |
| 8118 | 2370 /* Inline CSS Support - Douglas Thrift |
| 2371 * | |
| 2372 * color | |
| 8686 | 2373 * background |
| 8118 | 2374 * font-family |
| 2375 * font-size | |
| 8686 | 2376 * text-decoration: underline |
| 8118 | 2377 */ |
| 2378 { | |
| 8686 | 2379 gchar *style, *color, *background, *family, *size; |
| 2380 gchar *textdec; | |
| 8118 | 2381 GtkIMHtmlFontDetail *font, *oldfont = NULL; |
| 2382 style = gtk_imhtml_get_html_opt (tag, "style="); | |
| 2383 | |
| 2384 if (!style) break; | |
| 2385 | |
| 2386 color = gtk_imhtml_get_css_opt (style, "color: "); | |
| 8686 | 2387 background = gtk_imhtml_get_css_opt (style, "background: "); |
| 8118 | 2388 family = gtk_imhtml_get_css_opt (style, |
| 2389 "font-family: "); | |
| 2390 size = gtk_imhtml_get_css_opt (style, "font-size: "); | |
| 8686 | 2391 textdec = gtk_imhtml_get_css_opt (style, "text-decoration: "); |
| 2392 | |
| 2393 if (!(color || family || size || background || textdec)) { | |
| 8120 | 2394 g_free(style); |
| 2395 break; | |
| 2396 } | |
| 8118 | 2397 |
| 8677 | 2398 |
| 2399 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
| 8118 | 2400 ws[0] = '\0'; wpos = 0; |
| 8177 | 2401 /* NEW_BIT (NEW_TEXT_BIT); */ |
| 8118 | 2402 |
| 2403 font = g_new0 (GtkIMHtmlFontDetail, 1); | |
| 2404 if (fonts) | |
| 2405 oldfont = fonts->data; | |
| 2406 | |
| 8677 | 2407 if (color && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_FORECOLOR)) |
| 8686 | 2408 { |
| 8118 | 2409 font->fore = color; |
| 8686 | 2410 gtk_imhtml_toggle_forecolor(imhtml, font->fore); |
| 2411 } | |
| 8118 | 2412 else if (oldfont && oldfont->fore) |
| 2413 font->fore = g_strdup(oldfont->fore); | |
| 2414 | |
| 8686 | 2415 if (background && !(options & GTK_IMHTML_NO_COLOURS) && (imhtml->format_functions & GTK_IMHTML_BACKCOLOR)) |
| 2416 { | |
| 2417 font->back = background; | |
| 2418 gtk_imhtml_toggle_backcolor(imhtml, font->back); | |
| 2419 } | |
| 2420 else if (oldfont && oldfont->back) | |
| 8118 | 2421 font->back = g_strdup(oldfont->back); |
| 2422 | |
| 8677 | 2423 if (family && !(options & GTK_IMHTML_NO_FONTS) && (imhtml->format_functions & GTK_IMHTML_FACE)) |
| 8686 | 2424 { |
| 8118 | 2425 font->face = family; |
| 8686 | 2426 gtk_imhtml_toggle_fontface(imhtml, font->face); |
| 2427 } | |
| 8118 | 2428 else if (oldfont && oldfont->face) |
| 2429 font->face = g_strdup(oldfont->face); | |
| 2430 if (font->face && (atoi(font->face) > 100)) { | |
| 8677 | 2431 /* WTF is this? */ |
| 9696 | 2432 /* Maybe it sets a max size on the font face? I seem to |
| 2433 * remember bad things happening if the font size was | |
| 2434 * 2 billion */ | |
| 8118 | 2435 g_free(font->face); |
| 2436 font->face = g_strdup("100"); | |
| 2437 } | |
| 2438 | |
| 2439 if (oldfont && oldfont->sml) | |
| 2440 font->sml = g_strdup(oldfont->sml); | |
| 2441 | |
| 8677 | 2442 if (size && !(options & GTK_IMHTML_NO_SIZES) && (imhtml->format_functions & (GTK_IMHTML_SHRINK|GTK_IMHTML_GROW))) { |
| 8686 | 2443 if (g_ascii_strcasecmp(size, "xx-small") == 0) |
| 2444 font->size = 1; | |
| 2445 else if (g_ascii_strcasecmp(size, "smaller") == 0 | |
| 2446 || g_ascii_strcasecmp(size, "x-small") == 0) | |
| 8118 | 2447 font->size = 2; |
| 8686 | 2448 else if (g_ascii_strcasecmp(size, "larger") == 0 |
| 2449 || g_ascii_strcasecmp(size, "medium") == 0) | |
| 8118 | 2450 font->size = 4; |
| 8686 | 2451 else if (g_ascii_strcasecmp(size, "large") == 0) |
| 2452 font->size = 5; | |
| 2453 else if (g_ascii_strcasecmp(size, "x-large") == 0) | |
| 2454 font->size = 6; | |
| 2455 else if (g_ascii_strcasecmp(size, "xx-large") == 0) | |
| 2456 font->size = 7; | |
| 8118 | 2457 else |
| 2458 font->size = 3; | |
| 8686 | 2459 gtk_imhtml_font_set_size(imhtml, font->size); |
| 2460 } | |
| 2461 else if (oldfont) | |
| 2462 { | |
| 2463 font->size = oldfont->size; | |
| 2464 } | |
| 2465 | |
| 2466 if (oldfont) | |
| 2467 { | |
| 2468 font->underline = oldfont->underline; | |
| 2469 } | |
| 2470 if (textdec && font->underline != 1 | |
| 9025 | 2471 && g_ascii_strcasecmp(textdec, "underline") == 0 |
| 8686 | 2472 && (imhtml->format_functions & GTK_IMHTML_UNDERLINE)) |
| 2473 { | |
| 2474 gtk_imhtml_toggle_underline(imhtml); | |
| 2475 font->underline = 1; | |
| 2476 } | |
| 8118 | 2477 |
| 2478 g_free(style); | |
| 2479 g_free(size); | |
| 2480 fonts = g_slist_prepend (fonts, font); | |
| 2481 } | |
| 2482 break; | |
| 5104 | 2483 case 57: /* /SPAN */ |
| 8118 | 2484 /* Inline CSS Support - Douglas Thrift */ |
| 8677 | 2485 if (fonts && !imhtml->wbfo) { |
| 8686 | 2486 GtkIMHtmlFontDetail *oldfont = NULL; |
| 8118 | 2487 GtkIMHtmlFontDetail *font = fonts->data; |
| 8677 | 2488 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8118 | 2489 ws[0] = '\0'; wpos = 0; |
| 8177 | 2490 /* NEW_BIT (NEW_TEXT_BIT); */ |
| 8118 | 2491 fonts = g_slist_remove (fonts, font); |
| 8692 | 2492 if (fonts) |
| 2493 oldfont = fonts->data; | |
| 2494 | |
| 2495 if (!oldfont) { | |
| 2496 gtk_imhtml_font_set_size(imhtml, 3); | |
| 2497 if (font->underline) | |
| 2498 gtk_imhtml_toggle_underline(imhtml); | |
| 2499 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
| 2500 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
| 2501 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
| 8686 | 2502 } |
| 8692 | 2503 else |
| 8686 | 2504 { |
| 8692 | 2505 |
| 2506 if (font->size != oldfont->size) | |
| 2507 gtk_imhtml_font_set_size(imhtml, oldfont->size); | |
| 2508 | |
| 2509 if (font->underline != oldfont->underline) | |
| 2510 gtk_imhtml_toggle_underline(imhtml); | |
| 2511 | |
| 9286 | 2512 if (font->face && (!oldfont->face || strcmp(font->face, oldfont->face) != 0)) |
| 8692 | 2513 gtk_imhtml_toggle_fontface(imhtml, oldfont->face); |
| 2514 | |
| 9286 | 2515 if (font->fore && (!oldfont->fore || strcmp(font->fore, oldfont->fore) != 0)) |
| 8692 | 2516 gtk_imhtml_toggle_forecolor(imhtml, oldfont->fore); |
| 2517 | |
| 9286 | 2518 if (font->back && (!oldfont->back || strcmp(font->back, oldfont->back) != 0)) |
| 8692 | 2519 gtk_imhtml_toggle_backcolor(imhtml, oldfont->back); |
| 8686 | 2520 } |
| 8692 | 2521 |
| 2522 g_free (font->face); | |
| 2523 g_free (font->fore); | |
| 2524 g_free (font->back); | |
| 2525 g_free (font->sml); | |
| 2526 | |
| 8118 | 2527 g_free (font); |
| 2528 } | |
| 2529 break; | |
| 8026 | 2530 case 60: /* SPAN */ |
| 2993 | 2531 break; |
| 8061 | 2532 case 62: /* comment */ |
| 8177 | 2533 /* NEW_BIT (NEW_TEXT_BIT); */ |
| 8317 | 2534 ws[wpos] = '\0'; |
| 9465 | 2535 |
| 8677 | 2536 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 2537 | |
| 9465 | 2538 if (imhtml->show_comments && !(options & GTK_IMHTML_NO_COMMENTS)) |
| 6124 | 2539 wpos = g_snprintf (ws, len, "%s", tag); |
| 8177 | 2540 /* NEW_BIT (NEW_COMMENT_BIT); */ |
| 3922 | 2541 break; |
| 2542 default: | |
| 6882 | 2543 break; |
| 2993 | 2544 } |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2545 c += tlen; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2546 pos += tlen; |
| 4138 | 2547 if(tag) |
| 2548 g_free(tag); /* This was allocated back in VALID_TAG() */ | |
| 9029 | 2549 } else if (gtk_imhtml_is_smiley(imhtml, fonts, c, &smilelen)) { |
| 8473 | 2550 GtkIMHtmlFontDetail *fd; |
| 2551 | |
| 2552 gchar *sml = NULL; | |
| 2553 if (fonts) { | |
| 2554 fd = fonts->data; | |
| 2555 sml = fd->sml; | |
| 2556 } | |
| 9029 | 2557 if (!sml) |
| 2558 sml = imhtml->protocol_name; | |
| 2559 | |
| 8677 | 2560 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8505 | 2561 wpos = g_snprintf (ws, smilelen + 1, "%s", c); |
| 8473 | 2562 |
| 8677 | 2563 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, ws, iter); |
| 8473 | 2564 |
| 8505 | 2565 c += smilelen; |
| 2566 pos += smilelen; | |
| 8473 | 2567 wpos = 0; |
| 2568 ws[0] = 0; | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2569 } else if (*c == '&' && gtk_imhtml_is_amp_escape (c, &, &tlen)) { |
| 7280 | 2570 while(*amp) { |
| 2571 ws [wpos++] = *amp++; | |
| 2572 } | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2573 c += tlen; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2574 pos += tlen; |
| 1428 | 2575 } else if (*c == '\n') { |
| 2576 if (!(options & GTK_IMHTML_NO_NEWLINE)) { | |
| 3922 | 2577 ws[wpos] = '\n'; |
| 2578 wpos++; | |
| 8677 | 2579 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2580 ws[0] = '\0'; |
| 2581 wpos = 0; | |
| 8177 | 2582 /* NEW_BIT (NEW_TEXT_BIT); */ |
| 10217 | 2583 } else if (!br) { /* Don't insert a space immediately after an HTML break */ |
| 9621 | 2584 /* A newline is defined by HTML as whitespace, which means we have to replace it with a word boundary. |
| 2585 * word breaks vary depending on the language used, so the correct thing to do is to use Pango to determine | |
| 2586 * what language this is, determine the proper word boundary to use, and insert that. I'm just going to insert | |
| 2587 * a space instead. What are the non-English speakers going to do? Complain in a language I'll understand? | |
| 2588 * Bu-wahaha! */ | |
| 2589 ws[wpos] = ' '; | |
| 2590 wpos++; | |
| 2591 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); | |
| 2592 ws[0] = '\0'; | |
| 2593 wpos = 0; | |
| 1428 | 2594 } |
| 2595 c++; | |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2596 pos++; |
| 8334 | 2597 } else if ((len_protocol = gtk_imhtml_is_protocol(c)) > 0){ |
| 2598 while(len_protocol--){ | |
| 8677 | 2599 /* Skip the next len_protocol characters, but make sure they're |
| 8334 | 2600 copied into the ws array. |
| 2601 */ | |
| 2602 ws [wpos++] = *c++; | |
| 2603 pos++; | |
| 2604 } | |
| 8061 | 2605 } else if (*c) { |
| 1428 | 2606 ws [wpos++] = *c++; |
|
2856
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2607 pos++; |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2608 } else { |
|
b1e300a85678
[gaim-migrate @ 2869]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2826
diff
changeset
|
2609 break; |
| 1428 | 2610 } |
| 2611 } | |
| 8677 | 2612 gtk_text_buffer_insert(imhtml->text_buffer, iter, ws, wpos); |
| 8061 | 2613 ws[0] = '\0'; wpos = 0; |
| 2614 | |
| 8177 | 2615 /* NEW_BIT(NEW_TEXT_BIT); */ |
| 8061 | 2616 |
| 4032 | 2617 while (fonts) { |
| 5967 | 2618 GtkIMHtmlFontDetail *font = fonts->data; |
| 4032 | 2619 fonts = g_slist_remove (fonts, font); |
| 2620 if (font->face) | |
| 2621 g_free (font->face); | |
| 2622 if (font->fore) | |
| 2623 g_free (font->fore); | |
| 2624 if (font->back) | |
| 2625 g_free (font->back); | |
| 2626 if (font->sml) | |
| 2627 g_free (font->sml); | |
| 2628 g_free (font); | |
| 2629 } | |
| 8932 | 2630 |
| 2631 g_free(ws); | |
| 2632 if (bg) | |
| 4630 | 2633 g_free(bg); |
| 8677 | 2634 |
| 2635 if (!imhtml->wbfo) | |
| 8698 | 2636 gtk_imhtml_close_tags(imhtml, iter); |
| 8506 | 2637 |
| 2638 object = g_object_ref(G_OBJECT(imhtml)); | |
| 2639 g_signal_emit(object, signals[UPDATE_FORMAT], 0); | |
| 2640 g_object_unref(object); | |
| 2641 | |
| 3922 | 2642 } |
| 2643 | |
| 4892 | 2644 void gtk_imhtml_remove_smileys(GtkIMHtml *imhtml) |
| 2645 { | |
| 4288 | 2646 g_hash_table_destroy(imhtml->smiley_data); |
| 2647 gtk_smiley_tree_destroy(imhtml->default_smilies); | |
| 4892 | 2648 imhtml->smiley_data = g_hash_table_new_full(g_str_hash, g_str_equal, |
| 4902 | 2649 g_free, (GDestroyNotify)gtk_smiley_tree_destroy); |
| 4288 | 2650 imhtml->default_smilies = gtk_smiley_tree_new(); |
| 2651 } | |
| 8481 | 2652 |
| 3922 | 2653 void gtk_imhtml_show_comments (GtkIMHtml *imhtml, |
| 4253 | 2654 gboolean show) |
| 2655 { | |
| 6124 | 2656 imhtml->show_comments = show; |
| 4253 | 2657 } |
|
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2658 |
| 8962 | 2659 void |
| 9029 | 2660 gtk_imhtml_set_protocol_name(GtkIMHtml *imhtml, const gchar *protocol_name) { |
| 2661 if (imhtml->protocol_name) | |
| 2662 g_free(imhtml->protocol_name); | |
| 2663 imhtml->protocol_name = protocol_name ? g_strdup(protocol_name) : NULL; | |
| 8456 | 2664 } |
| 2665 | |
|
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2666 void |
|
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2667 gtk_imhtml_clear (GtkIMHtml *imhtml) |
|
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2668 { |
| 7991 | 2669 GList *del; |
| 3922 | 2670 GtkTextIter start, end; |
| 8427 | 2671 GObject *object = g_object_ref(G_OBJECT(imhtml)); |
| 7991 | 2672 |
| 3922 | 2673 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
| 2674 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
| 2675 gtk_text_buffer_delete(imhtml->text_buffer, &start, &end); | |
| 7991 | 2676 |
| 2677 for(del = imhtml->scalables; del; del = del->next) { | |
| 2678 GtkIMHtmlScalable *scale = del->data; | |
| 2679 scale->free(scale); | |
| 2680 } | |
| 2681 g_list_free(imhtml->scalables); | |
| 2682 imhtml->scalables = NULL; | |
| 8061 | 2683 |
| 8719 | 2684 gtk_imhtml_close_tags(imhtml, &start); |
| 8481 | 2685 |
| 8427 | 2686 g_signal_emit(object, signals[CLEAR_FORMAT], 0); |
| 2687 g_object_unref(object); | |
|
1780
d7cbedd1d651
[gaim-migrate @ 1790]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1738
diff
changeset
|
2688 } |
|
2363
08c66712364c
[gaim-migrate @ 2376]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
2349
diff
changeset
|
2689 |
| 4046 | 2690 void gtk_imhtml_page_up (GtkIMHtml *imhtml) |
| 2691 { | |
| 5282 | 2692 GdkRectangle rect; |
| 2693 GtkTextIter iter; | |
| 4046 | 2694 |
| 5282 | 2695 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); |
| 2696 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
| 2697 rect.y - rect.height); | |
| 2698 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
| 8061 | 2699 |
| 4046 | 2700 } |
| 5282 | 2701 void gtk_imhtml_page_down (GtkIMHtml *imhtml) |
| 2702 { | |
| 2703 GdkRectangle rect; | |
| 2704 GtkTextIter iter; | |
| 2705 | |
| 2706 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
| 2707 gtk_text_view_get_iter_at_location(GTK_TEXT_VIEW(imhtml), &iter, rect.x, | |
| 2708 rect.y + rect.height); | |
| 2709 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &iter, 0, TRUE, 0, 0); | |
| 2710 } | |
| 4735 | 2711 |
| 5967 | 2712 /* GtkIMHtmlScalable, gtk_imhtml_image, gtk_imhtml_hr */ |
| 8962 | 2713 GtkIMHtmlScalable *gtk_imhtml_image_new(GdkPixbuf *img, const gchar *filename, int id) |
| 4735 | 2714 { |
| 5967 | 2715 GtkIMHtmlImage *im_image = g_malloc(sizeof(GtkIMHtmlImage)); |
| 5012 | 2716 GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixbuf(img)); |
| 4895 | 2717 |
| 5967 | 2718 GTK_IMHTML_SCALABLE(im_image)->scale = gtk_imhtml_image_scale; |
| 2719 GTK_IMHTML_SCALABLE(im_image)->add_to = gtk_imhtml_image_add_to; | |
| 2720 GTK_IMHTML_SCALABLE(im_image)->free = gtk_imhtml_image_free; | |
| 5046 | 2721 |
| 2722 im_image->pixbuf = img; | |
| 5012 | 2723 im_image->image = image; |
| 4895 | 2724 im_image->width = gdk_pixbuf_get_width(img); |
| 2725 im_image->height = gdk_pixbuf_get_height(img); | |
| 2726 im_image->mark = NULL; | |
| 6982 | 2727 im_image->filename = filename ? g_strdup(filename) : NULL; |
| 8962 | 2728 im_image->id = id; |
| 9573 | 2729 im_image->filesel = NULL; |
| 4895 | 2730 |
| 5046 | 2731 g_object_ref(img); |
| 4895 | 2732 return GTK_IMHTML_SCALABLE(im_image); |
| 2733 } | |
| 2734 | |
| 5967 | 2735 void gtk_imhtml_image_scale(GtkIMHtmlScalable *scale, int width, int height) |
| 4895 | 2736 { |
| 5967 | 2737 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; |
| 4895 | 2738 |
| 2739 if(image->width > width || image->height > height){ | |
| 2740 GdkPixbuf *new_image = NULL; | |
| 2741 float factor; | |
| 2742 int new_width = image->width, new_height = image->height; | |
| 2743 | |
| 8588 | 2744 if(image->width > (width - 2)){ |
| 4895 | 2745 factor = (float)(width)/image->width; |
| 2746 new_width = width; | |
| 2747 new_height = image->height * factor; | |
| 2748 } | |
| 8588 | 2749 if(new_height >= (height - 2)){ |
| 4895 | 2750 factor = (float)(height)/new_height; |
| 2751 new_height = height; | |
| 2752 new_width = new_width * factor; | |
| 2753 } | |
| 2754 | |
| 5046 | 2755 new_image = gdk_pixbuf_scale_simple(image->pixbuf, new_width, new_height, GDK_INTERP_BILINEAR); |
| 5012 | 2756 gtk_image_set_from_pixbuf(image->image, new_image); |
| 4895 | 2757 g_object_unref(G_OBJECT(new_image)); |
| 2758 } | |
| 2759 } | |
| 2760 | |
| 9573 | 2761 static void |
| 2762 image_save_yes_cb(GtkIMHtmlImage *image, const char *filename) | |
| 5012 | 2763 { |
| 2764 gchar *type = NULL; | |
| 5019 | 2765 GError *error = NULL; |
| 5015 | 2766 #if GTK_CHECK_VERSION(2,2,0) |
| 5012 | 2767 GSList *formats = gdk_pixbuf_get_formats(); |
| 6162 | 2768 #else |
| 2769 char *basename = g_path_get_basename(filename); | |
| 2770 char *ext = strrchr(basename, '.'); | |
| 5959 | 2771 #endif |
| 5012 | 2772 |
| 9573 | 2773 gtk_widget_destroy(image->filesel); |
| 2774 image->filesel = NULL; | |
| 5959 | 2775 |
| 2776 #if GTK_CHECK_VERSION(2,2,0) | |
| 9573 | 2777 while (formats) { |
| 5012 | 2778 GdkPixbufFormat *format = formats->data; |
| 2779 gchar **extensions = gdk_pixbuf_format_get_extensions(format); | |
| 2780 gpointer p = extensions; | |
| 2781 | |
| 2782 while(gdk_pixbuf_format_is_writable(format) && extensions && extensions[0]){ | |
| 2783 gchar *fmt_ext = extensions[0]; | |
| 2784 const gchar* file_ext = filename + strlen(filename) - strlen(fmt_ext); | |
| 2785 | |
| 2786 if(!strcmp(fmt_ext, file_ext)){ | |
| 2787 type = gdk_pixbuf_format_get_name(format); | |
| 2788 break; | |
| 2789 } | |
| 2790 | |
| 2791 extensions++; | |
| 2792 } | |
| 2793 | |
| 2794 g_strfreev(p); | |
| 2795 | |
| 9573 | 2796 if (type) |
| 5012 | 2797 break; |
| 2798 | |
| 2799 formats = formats->next; | |
| 2800 } | |
| 2801 | |
| 5020 | 2802 g_slist_free(formats); |
| 2803 #else | |
| 2804 /* this is really ugly code, but I think it will work */ | |
| 9573 | 2805 if (ext) { |
| 5020 | 2806 ext++; |
| 9573 | 2807 if (!g_ascii_strcasecmp(ext, "jpeg") || !g_ascii_strcasecmp(ext, "jpg")) |
| 5020 | 2808 type = g_strdup("jpeg"); |
| 9573 | 2809 else if (!g_ascii_strcasecmp(ext, "png")) |
| 5020 | 2810 type = g_strdup("png"); |
| 2811 } | |
| 2812 | |
| 2813 g_free(basename); | |
| 2814 #endif | |
| 2815 | |
| 5012 | 2816 /* If I can't find a valid type, I will just tell the user about it and then assume |
| 2817 it's a png */ | |
| 9573 | 2818 if (!type){ |
| 5012 | 2819 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
| 9717 | 2820 _("Unable to guess the image type based on the file extension supplied. Defaulting to PNG.")); |
| 2821 type = g_strdup("png"); | |
| 5012 | 2822 } |
| 2823 | |
| 5046 | 2824 gdk_pixbuf_save(image->pixbuf, filename, type, &error, NULL); |
| 5012 | 2825 |
| 9573 | 2826 if (error){ |
| 5012 | 2827 gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, |
| 2828 _("Error saving image: %s"), error->message); | |
| 2829 g_error_free(error); | |
| 2830 } | |
| 2831 | |
| 2832 g_free(type); | |
| 2833 } | |
| 2834 | |
| 9573 | 2835 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ |
| 2836 static void | |
| 2837 image_save_check_if_exists_cb(GtkWidget *widget, gint response, GtkIMHtmlImage *image) | |
| 2838 { | |
| 2839 gchar *filename; | |
| 2840 | |
| 2841 if (response != GTK_RESPONSE_ACCEPT) { | |
| 2842 gtk_widget_destroy(widget); | |
| 2843 image->filesel = NULL; | |
| 2844 return; | |
| 2845 } | |
| 2846 | |
| 2847 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); | |
| 2848 #else /* FILECHOOSER */ | |
| 2849 static void | |
| 2850 image_save_check_if_exists_cb(GtkWidget *button, GtkIMHtmlImage *image) | |
| 5012 | 2851 { |
| 9573 | 2852 gchar *filename; |
| 2853 | |
| 2854 filename = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION(image->filesel))); | |
| 2855 | |
| 2856 if (g_file_test(filename, G_FILE_TEST_IS_DIR)) { | |
| 2857 gchar *dirname; | |
| 2858 /* append a / is needed */ | |
| 2859 if (filename[strlen(filename) - 1] != G_DIR_SEPARATOR) { | |
| 2860 dirname = g_strconcat(filename, G_DIR_SEPARATOR_S, NULL); | |
| 2861 } else { | |
| 2862 dirname = g_strdup(filename); | |
| 2863 } | |
| 9574 | 2864 gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), dirname); |
| 9573 | 2865 g_free(dirname); |
| 2866 g_free(filename); | |
| 2867 return; | |
| 2868 } | |
| 2869 #endif /* FILECHOOSER */ | |
| 2870 | |
| 2871 /* | |
| 2872 * XXX - We should probably prompt the user to determine if they really | |
| 2873 * want to overwrite the file or not. However, I don't feel like doing | |
| 2874 * that, so we're just always going to overwrite if the file exists. | |
| 2875 */ | |
| 2876 /* | |
| 2877 if (g_file_test(filename, G_FILE_TEST_EXISTS)) { | |
| 2878 } else | |
| 2879 image_save_yes_cb(image, filename); | |
| 2880 */ | |
| 2881 | |
| 2882 image_save_yes_cb(image, filename); | |
| 2883 | |
| 2884 g_free(filename); | |
| 2885 } | |
| 2886 | |
| 2887 #if !GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ | |
| 2888 static void | |
| 2889 image_save_cancel_cb(GtkIMHtmlImage *image) | |
| 2890 { | |
| 2891 gtk_widget_destroy(image->filesel); | |
| 2892 image->filesel = NULL; | |
| 2893 } | |
| 2894 #endif /* FILECHOOSER */ | |
| 2895 | |
| 2896 static void | |
| 2897 gtk_imhtml_image_save(GtkWidget *w, GtkIMHtmlImage *image) | |
| 2898 { | |
| 2899 if (image->filesel != NULL) { | |
| 2900 gtk_window_present(GTK_WINDOW(image->filesel)); | |
| 2901 return; | |
| 2902 } | |
| 2903 | |
| 2904 #if GTK_CHECK_VERSION(2,4,0) /* FILECHOOSER */ | |
| 2905 image->filesel = gtk_file_chooser_dialog_new(_("Save Image"), | |
| 2906 NULL, | |
| 2907 GTK_FILE_CHOOSER_ACTION_SAVE, | |
| 2908 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
| 2909 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, | |
| 2910 NULL); | |
| 2911 gtk_dialog_set_default_response(GTK_DIALOG(image->filesel), GTK_RESPONSE_ACCEPT); | |
| 2912 if (image->filename != NULL) | |
| 2913 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(image->filesel), image->filename); | |
| 2914 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(image->filesel)), "response", | |
| 2915 G_CALLBACK(image_save_check_if_exists_cb), image); | |
| 2916 #else /* FILECHOOSER */ | |
| 2917 image->filesel = gtk_file_selection_new(_("Save Image")); | |
| 2918 if (image->filename != NULL) | |
| 2919 gtk_file_selection_set_filename(GTK_FILE_SELECTION(image->filesel), image->filename); | |
| 9574 | 2920 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)), "delete_event", |
| 2921 G_CALLBACK(image_save_cancel_cb), image); | |
| 2922 g_signal_connect_swapped(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->cancel_button), | |
| 2923 "clicked", G_CALLBACK(image_save_cancel_cb), image); | |
| 9573 | 2924 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(image->filesel)->ok_button), "clicked", |
| 2925 G_CALLBACK(image_save_check_if_exists_cb), image); | |
| 2926 #endif /* FILECHOOSER */ | |
| 2927 | |
| 2928 gtk_widget_show(image->filesel); | |
| 5012 | 2929 } |
| 2930 | |
| 9815 | 2931 /* |
| 2932 * So, um, AIM Direct IM lets you send any file, not just images. You can | |
| 2933 * just insert a sound or a file or whatever in a conversation. It's | |
| 2934 * basically like file transfer, except there is an icon to open the file | |
| 2935 * embedded in the conversation. Someone should make the Gaim core handle | |
| 2936 * all of that. | |
| 2937 */ | |
| 5967 | 2938 static gboolean gtk_imhtml_image_clicked(GtkWidget *w, GdkEvent *event, GtkIMHtmlImage *image) |
| 5012 | 2939 { |
| 2940 GdkEventButton *event_button = (GdkEventButton *) event; | |
| 2941 | |
| 2942 if (event->type == GDK_BUTTON_RELEASE) { | |
| 2943 if(event_button->button == 3) { | |
| 2944 GtkWidget *img, *item, *menu; | |
| 2945 gchar *text = g_strdup_printf(_("_Save Image...")); | |
| 2946 menu = gtk_menu_new(); | |
| 2947 | |
| 2948 /* buttons and such */ | |
| 2949 img = gtk_image_new_from_stock(GTK_STOCK_SAVE, GTK_ICON_SIZE_MENU); | |
| 2950 item = gtk_image_menu_item_new_with_mnemonic(text); | |
| 2951 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), img); | |
| 5967 | 2952 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(gtk_imhtml_image_save), image); |
| 5012 | 2953 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); |
| 2954 | |
| 2955 gtk_widget_show_all(menu); | |
| 2956 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
| 2957 event_button->button, event_button->time); | |
| 2958 | |
| 2959 g_free(text); | |
| 2960 return TRUE; | |
| 2961 } | |
| 2962 } | |
| 2963 if(event->type == GDK_BUTTON_PRESS && event_button->button == 3) | |
| 2964 return TRUE; /* Clicking the right mouse button on a link shouldn't | |
| 2965 be caught by the regular GtkTextView menu */ | |
| 2966 else | |
| 2967 return FALSE; /* Let clicks go through if we didn't catch anything */ | |
| 2968 | |
| 2969 } | |
| 5967 | 2970 void gtk_imhtml_image_free(GtkIMHtmlScalable *scale) |
| 2971 { | |
| 2972 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
| 2973 | |
| 2974 g_object_unref(image->pixbuf); | |
| 6982 | 2975 if (image->filename) |
| 2976 g_free(image->filename); | |
| 9573 | 2977 if (image->filesel) |
| 2978 gtk_widget_destroy(image->filesel); | |
| 5967 | 2979 g_free(scale); |
| 2980 } | |
| 2981 | |
| 2982 void gtk_imhtml_image_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
| 2983 { | |
| 2984 GtkIMHtmlImage *image = (GtkIMHtmlImage *)scale; | |
| 2985 GtkWidget *box = gtk_event_box_new(); | |
| 8962 | 2986 char *tag; |
| 5967 | 2987 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
| 2988 | |
| 2989 gtk_container_add(GTK_CONTAINER(box), GTK_WIDGET(image->image)); | |
| 9229 | 2990 |
| 2991 if(!gtk_check_version(2, 4, 0)) | |
| 2992 g_object_set(G_OBJECT(box), "visible-window", FALSE, NULL); | |
| 5967 | 2993 |
| 2994 gtk_widget_show(GTK_WIDGET(image->image)); | |
| 2995 gtk_widget_show(box); | |
| 2996 | |
| 8962 | 2997 tag = g_strdup_printf("<IMG ID=\"%d\">", image->id); |
| 2998 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", tag, g_free); | |
| 2999 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "[Image]"); | |
| 3000 | |
| 5967 | 3001 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), box, anchor); |
| 3002 g_signal_connect(G_OBJECT(box), "event", G_CALLBACK(gtk_imhtml_image_clicked), image); | |
| 3003 } | |
| 3004 | |
| 3005 GtkIMHtmlScalable *gtk_imhtml_hr_new() | |
| 3006 { | |
| 3007 GtkIMHtmlHr *hr = g_malloc(sizeof(GtkIMHtmlHr)); | |
| 3008 | |
| 3009 GTK_IMHTML_SCALABLE(hr)->scale = gtk_imhtml_hr_scale; | |
| 3010 GTK_IMHTML_SCALABLE(hr)->add_to = gtk_imhtml_hr_add_to; | |
| 3011 GTK_IMHTML_SCALABLE(hr)->free = gtk_imhtml_hr_free; | |
| 3012 | |
| 3013 hr->sep = gtk_hseparator_new(); | |
| 3014 gtk_widget_set_size_request(hr->sep, 5000, 2); | |
| 3015 gtk_widget_show(hr->sep); | |
| 3016 | |
| 3017 return GTK_IMHTML_SCALABLE(hr); | |
| 3018 } | |
| 3019 | |
| 3020 void gtk_imhtml_hr_scale(GtkIMHtmlScalable *scale, int width, int height) | |
| 3021 { | |
| 8588 | 3022 gtk_widget_set_size_request(((GtkIMHtmlHr *)scale)->sep, width - 2, 2); |
| 5967 | 3023 } |
| 3024 | |
| 3025 void gtk_imhtml_hr_add_to(GtkIMHtmlScalable *scale, GtkIMHtml *imhtml, GtkTextIter *iter) | |
| 3026 { | |
| 3027 GtkIMHtmlHr *hr = (GtkIMHtmlHr *)scale; | |
| 3028 GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); | |
| 8698 | 3029 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_htmltext", "<hr>"); |
| 3030 g_object_set_data(G_OBJECT(anchor), "gtkimhtml_plaintext", "\n---\n"); | |
| 5967 | 3031 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), hr->sep, anchor); |
| 3032 } | |
| 3033 | |
| 3034 void gtk_imhtml_hr_free(GtkIMHtmlScalable *scale) | |
| 3035 { | |
| 3036 g_free(scale); | |
| 3037 } | |
| 7295 | 3038 |
| 3039 gboolean gtk_imhtml_search_find(GtkIMHtml *imhtml, const gchar *text) | |
| 3040 { | |
| 3041 GtkTextIter iter, start, end; | |
| 3042 gboolean new_search = TRUE; | |
| 3043 | |
| 3044 g_return_val_if_fail(imhtml != NULL, FALSE); | |
| 3045 g_return_val_if_fail(text != NULL, FALSE); | |
| 8061 | 3046 |
| 7295 | 3047 if (imhtml->search_string && !strcmp(text, imhtml->search_string)) |
| 3048 new_search = FALSE; | |
| 8061 | 3049 |
| 7295 | 3050 if (new_search) { |
| 3051 gtk_imhtml_search_clear(imhtml); | |
| 3052 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
| 3053 } else { | |
| 3054 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, | |
| 8061 | 3055 gtk_text_buffer_get_mark(imhtml->text_buffer, "search")); |
| 7295 | 3056 } |
| 3057 imhtml->search_string = g_strdup(text); | |
| 3058 | |
| 7358 | 3059 if (gtk_source_iter_forward_search(&iter, imhtml->search_string, |
| 3060 GTK_SOURCE_SEARCH_VISIBLE_ONLY | GTK_SOURCE_SEARCH_CASE_INSENSITIVE, | |
| 7295 | 3061 &start, &end, NULL)) { |
| 3062 | |
| 3063 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(imhtml), &start, 0, TRUE, 0, 0); | |
| 3064 gtk_text_buffer_create_mark(imhtml->text_buffer, "search", &end, FALSE); | |
| 3065 if (new_search) { | |
| 3066 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &iter, &end); | |
| 8061 | 3067 do |
| 7295 | 3068 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "search", &start, &end); |
| 8061 | 3069 while (gtk_source_iter_forward_search(&end, imhtml->search_string, |
| 3070 GTK_SOURCE_SEARCH_VISIBLE_ONLY | | |
| 7358 | 3071 GTK_SOURCE_SEARCH_CASE_INSENSITIVE, |
| 7295 | 3072 &start, &end, NULL)); |
| 3073 } | |
| 3074 return TRUE; | |
| 3075 } | |
| 8061 | 3076 |
| 3077 gtk_imhtml_search_clear(imhtml); | |
| 3078 | |
| 7295 | 3079 return FALSE; |
| 3080 } | |
| 3081 | |
| 3082 void gtk_imhtml_search_clear(GtkIMHtml *imhtml) | |
| 3083 { | |
| 3084 GtkTextIter start, end; | |
| 8061 | 3085 |
| 7295 | 3086 g_return_if_fail(imhtml != NULL); |
| 8061 | 3087 |
| 7295 | 3088 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); |
| 3089 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
| 3090 | |
| 3091 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "search", &start, &end); | |
| 3092 if (imhtml->search_string) | |
| 3093 g_free(imhtml->search_string); | |
| 3094 imhtml->search_string = NULL; | |
| 3095 } | |
| 8061 | 3096 |
| 8677 | 3097 static GtkTextTag *find_font_forecolor_tag(GtkIMHtml *imhtml, gchar *color) |
| 3098 { | |
| 3099 gchar str[18]; | |
| 3100 GtkTextTag *tag; | |
| 3101 | |
| 3102 g_snprintf(str, sizeof(str), "FORECOLOR %s", color); | |
| 3103 | |
| 3104 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
| 3105 if (!tag) | |
| 3106 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", color, NULL); | |
| 3107 | |
| 3108 return tag; | |
| 3109 } | |
| 3110 | |
| 3111 static GtkTextTag *find_font_backcolor_tag(GtkIMHtml *imhtml, gchar *color) | |
| 3112 { | |
| 3113 gchar str[18]; | |
| 3114 GtkTextTag *tag; | |
| 3115 | |
| 3116 g_snprintf(str, sizeof(str), "BACKCOLOR %s", color); | |
| 3117 | |
| 3118 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
| 3119 if (!tag) | |
| 3120 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "background", color, NULL); | |
| 3121 | |
| 3122 return tag; | |
| 3123 } | |
| 3124 | |
| 3125 static GtkTextTag *find_font_face_tag(GtkIMHtml *imhtml, gchar *face) | |
| 8061 | 3126 { |
| 8677 | 3127 gchar str[256]; |
| 3128 GtkTextTag *tag; | |
| 3129 | |
| 3130 g_snprintf(str, sizeof(str), "FONT FACE %s", face); | |
| 3131 str[255] = '\0'; | |
| 3132 | |
| 3133 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
| 3134 if (!tag) | |
| 3135 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "family", face, NULL); | |
| 3136 | |
| 3137 return tag; | |
| 3138 } | |
| 3139 | |
|
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3140 static void _init_original_fsize(GtkIMHtml *imhtml) |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3141 { |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3142 GtkTextAttributes *attr; |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3143 attr = gtk_text_view_get_default_attributes(GTK_TEXT_VIEW(imhtml)); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3144 imhtml->original_fsize = pango_font_description_get_size(attr->font); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3145 gtk_text_attributes_unref(attr); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3146 } |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3147 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3148 static void _recalculate_font_sizes(GtkTextTag *tag, gpointer imhtml) |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3149 { |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3150 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) { |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3151 int size; |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3152 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3153 size = strtol(tag->name + 10, NULL, 10); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3154 g_object_set(G_OBJECT(tag), "size", |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3155 (gint) (GTK_IMHTML(imhtml)->original_fsize * |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3156 ((double) _point_sizes[size-1] * GTK_IMHTML(imhtml)->zoom)), NULL); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3157 } |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3158 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3159 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3160 } |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3161 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3162 void gtk_imhtml_font_zoom(GtkIMHtml *imhtml, double zoom) |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3163 { |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3164 GtkRcStyle *s; |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3165 PangoFontDescription *font_desc = pango_font_description_new(); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3166 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3167 imhtml->zoom = zoom; |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3168 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3169 if (!imhtml->original_fsize) |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3170 _init_original_fsize(imhtml); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3171 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3172 gtk_text_tag_table_foreach(gtk_text_buffer_get_tag_table(imhtml->text_buffer), |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3173 _recalculate_font_sizes, imhtml); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3174 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3175 pango_font_description_set_size(font_desc, (gint)((double) imhtml->original_fsize * zoom)); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3176 |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3177 s = gtk_widget_get_modifier_style(GTK_WIDGET(imhtml)); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3178 s->font_desc = font_desc; |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3179 gtk_widget_modify_style(GTK_WIDGET(imhtml), s); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3180 } |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3181 |
| 8677 | 3182 static GtkTextTag *find_font_size_tag(GtkIMHtml *imhtml, int size) |
| 3183 { | |
| 3184 gchar str[24]; | |
| 3185 GtkTextTag *tag; | |
| 3186 | |
|
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3187 if (!imhtml->original_fsize) |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3188 _init_original_fsize(imhtml); |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3189 |
| 8677 | 3190 g_snprintf(str, sizeof(str), "FONT SIZE %d", size); |
| 3191 str[23] = '\0'; | |
| 3192 | |
| 3193 tag = gtk_text_tag_table_lookup(gtk_text_buffer_get_tag_table(imhtml->text_buffer), str); | |
| 3194 if (!tag) { | |
| 3195 /* For reasons I don't understand, setting "scale" here scaled based on some default | |
| 3196 * size other than my theme's default size. Our size 4 was actually smaller than | |
| 3197 * our size 3 for me. So this works around that oddity. | |
| 3198 */ | |
| 3199 tag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "size", | |
|
8740
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3200 (gint) (imhtml->original_fsize * |
|
61a090413b93
[gaim-migrate @ 9495]
Christian Hammond <chipx86@chipx86.com>
parents:
8735
diff
changeset
|
3201 ((double) _point_sizes[size-1] * imhtml->zoom)), NULL); |
| 8061 | 3202 } |
| 3203 | |
| 8677 | 3204 return tag; |
| 3205 } | |
| 3206 | |
| 3207 static void remove_tag_by_prefix(GtkIMHtml *imhtml, const GtkTextIter *i, const GtkTextIter *e, | |
| 3208 const char *prefix, guint len, gboolean homo) | |
| 3209 { | |
| 3210 GSList *tags, *l; | |
| 3211 GtkTextIter iter; | |
| 3212 | |
| 3213 tags = gtk_text_iter_get_tags(i); | |
| 3214 | |
| 3215 for (l = tags; l; l = l->next) { | |
| 3216 GtkTextTag *tag = l->data; | |
| 3217 | |
| 3218 if (tag->name && !strncmp(tag->name, prefix, len)) | |
| 3219 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, i, e); | |
| 8061 | 3220 } |
| 3221 | |
| 8677 | 3222 g_slist_free(tags); |
| 3223 | |
| 3224 if (homo) | |
| 3225 return; | |
| 3226 | |
| 3227 iter = *i; | |
| 3228 | |
| 3229 while (gtk_text_iter_forward_char(&iter) && !gtk_text_iter_equal(&iter, e)) { | |
| 3230 if (gtk_text_iter_begins_tag(&iter, NULL)) { | |
| 3231 tags = gtk_text_iter_get_toggled_tags(&iter, TRUE); | |
| 3232 | |
| 3233 for (l = tags; l; l = l->next) { | |
| 3234 GtkTextTag *tag = l->data; | |
| 3235 | |
| 3236 if (tag->name && !strncmp(tag->name, prefix, len)) | |
| 3237 gtk_text_buffer_remove_tag(imhtml->text_buffer, tag, &iter, e); | |
| 3238 } | |
| 3239 | |
| 3240 g_slist_free(tags); | |
| 3241 } | |
| 8061 | 3242 } |
| 8677 | 3243 } |
| 3244 | |
| 3245 static void remove_font_size(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
| 3246 { | |
| 3247 remove_tag_by_prefix(imhtml, i, e, "FONT SIZE ", 10, homo); | |
| 3248 } | |
| 3249 | |
| 3250 static void remove_font_face(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
| 3251 { | |
| 3252 remove_tag_by_prefix(imhtml, i, e, "FONT FACE ", 10, homo); | |
| 3253 } | |
| 3254 | |
| 3255 static void remove_font_forecolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
| 3256 { | |
| 3257 remove_tag_by_prefix(imhtml, i, e, "FORECOLOR ", 10, homo); | |
| 3258 } | |
| 3259 | |
| 3260 static void remove_font_backcolor(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
| 3261 { | |
| 3262 remove_tag_by_prefix(imhtml, i, e, "BACKCOLOR ", 10, homo); | |
| 3263 } | |
| 3264 | |
| 3265 static void remove_font_link(GtkIMHtml *imhtml, GtkTextIter *i, GtkTextIter *e, gboolean homo) | |
| 3266 { | |
| 3267 remove_tag_by_prefix(imhtml, i, e, "LINK ", 5, homo); | |
| 3268 } | |
| 3269 | |
| 3270 /* Editable stuff */ | |
| 3271 static void preinsert_cb(GtkTextBuffer *buffer, GtkTextIter *iter, gchar *text, gint len, GtkIMHtml *imhtml) | |
| 3272 { | |
| 3273 imhtml->insert_offset = gtk_text_iter_get_offset(iter); | |
| 3274 } | |
| 3275 | |
| 10169 | 3276 static void insert_ca_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextChildAnchor *arg2, gpointer user_data) |
| 3277 { | |
| 3278 GtkTextIter start; | |
| 3279 | |
| 3280 start = *arg1; | |
| 3281 gtk_text_iter_backward_char(&start); | |
| 3282 | |
| 3283 gtk_imhtml_apply_tags_on_insert(user_data, &start, arg1); | |
| 3284 } | |
| 3285 | |
| 8677 | 3286 static void insert_cb(GtkTextBuffer *buffer, GtkTextIter *end, gchar *text, gint len, GtkIMHtml *imhtml) |
| 3287 { | |
| 3288 GtkTextIter start; | |
| 3289 | |
| 3290 if (!len) | |
| 3291 return; | |
| 3292 | |
| 3293 start = *end; | |
| 3294 gtk_text_iter_set_offset(&start, imhtml->insert_offset); | |
| 3295 | |
| 10169 | 3296 gtk_imhtml_apply_tags_on_insert(imhtml, &start, end); |
| 3297 } | |
| 3298 | |
| 3299 static void gtk_imhtml_apply_tags_on_insert(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) | |
| 3300 { | |
| 8677 | 3301 if (imhtml->edit.bold) |
| 10169 | 3302 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", start, end); |
| 8677 | 3303 else |
| 10169 | 3304 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", start, end); |
| 8677 | 3305 |
| 3306 if (imhtml->edit.italic) | |
| 10169 | 3307 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", start, end); |
| 8677 | 3308 else |
| 10169 | 3309 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", start, end); |
| 8677 | 3310 |
| 3311 if (imhtml->edit.underline) | |
| 10169 | 3312 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", start, end); |
| 8677 | 3313 else |
| 10169 | 3314 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", start, end); |
| 8677 | 3315 |
| 9924 | 3316 if (imhtml->edit.strike) |
| 10169 | 3317 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", start, end); |
| 9924 | 3318 else |
| 10169 | 3319 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "STRIKE", start, end); |
| 9924 | 3320 |
| 8677 | 3321 if (imhtml->edit.forecolor) { |
| 10169 | 3322 remove_font_forecolor(imhtml, start, end, TRUE); |
| 8677 | 3323 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
| 3324 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
| 10169 | 3325 start, end); |
| 8061 | 3326 } |
| 3327 | |
| 8677 | 3328 if (imhtml->edit.backcolor) { |
| 10169 | 3329 remove_font_backcolor(imhtml, start, end, TRUE); |
| 8677 | 3330 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
| 3331 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), | |
| 10169 | 3332 start, end); |
| 8677 | 3333 } |
| 3334 | |
| 3335 if (imhtml->edit.fontface) { | |
| 10169 | 3336 remove_font_face(imhtml, start, end, TRUE); |
| 8677 | 3337 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
| 3338 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
| 10169 | 3339 start, end); |
| 8061 | 3340 } |
| 8677 | 3341 |
| 3342 if (imhtml->edit.fontsize) { | |
| 10169 | 3343 remove_font_size(imhtml, start, end, TRUE); |
| 8677 | 3344 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
| 3345 find_font_size_tag(imhtml, imhtml->edit.fontsize), | |
| 10169 | 3346 start, end); |
| 8677 | 3347 } |
| 3348 | |
| 3349 if (imhtml->edit.link) { | |
| 10169 | 3350 remove_font_link(imhtml, start, end, TRUE); |
| 8677 | 3351 gtk_text_buffer_apply_tag(imhtml->text_buffer, |
| 3352 imhtml->edit.link, | |
| 10169 | 3353 start, end); |
| 8677 | 3354 } |
| 8061 | 3355 } |
| 3356 | |
| 3357 void gtk_imhtml_set_editable(GtkIMHtml *imhtml, gboolean editable) | |
| 3358 { | |
| 3359 gtk_text_view_set_editable(GTK_TEXT_VIEW(imhtml), editable); | |
| 8177 | 3360 /* |
| 3361 * We need a visible caret for accessibility, so mouseless | |
| 3362 * people can highlight stuff. | |
| 3363 */ | |
| 3364 /* gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(imhtml), editable); */ | |
| 8061 | 3365 imhtml->editable = editable; |
| 8677 | 3366 imhtml->format_functions = GTK_IMHTML_ALL; |
| 3367 | |
| 3368 if (editable) | |
| 3369 g_signal_connect_after(G_OBJECT(GTK_IMHTML(imhtml)->text_buffer), "mark-set", | |
| 3370 G_CALLBACK(mark_set_cb), imhtml); | |
| 3371 } | |
| 3372 | |
| 3373 void gtk_imhtml_set_whole_buffer_formatting_only(GtkIMHtml *imhtml, gboolean wbfo) | |
| 3374 { | |
| 3375 g_return_if_fail(imhtml != NULL); | |
| 3376 | |
| 3377 imhtml->wbfo = wbfo; | |
| 8420 | 3378 } |
| 3379 | |
| 3380 void gtk_imhtml_set_format_functions(GtkIMHtml *imhtml, GtkIMHtmlButtons buttons) | |
| 3381 { | |
| 3382 GObject *object = g_object_ref(G_OBJECT(imhtml)); | |
| 8677 | 3383 imhtml->format_functions = buttons; |
| 8420 | 3384 g_signal_emit(object, signals[BUTTONS_UPDATE], 0, buttons); |
| 3385 g_object_unref(object); | |
| 8061 | 3386 } |
| 3387 | |
| 8788 | 3388 GtkIMHtmlButtons gtk_imhtml_get_format_functions(GtkIMHtml *imhtml) |
| 3389 { | |
| 3390 return imhtml->format_functions; | |
| 3391 } | |
| 8516 | 3392 |
| 3393 void gtk_imhtml_get_current_format(GtkIMHtml *imhtml, gboolean *bold, | |
| 3394 gboolean *italic, gboolean *underline) | |
| 8481 | 3395 { |
| 8677 | 3396 if (imhtml->edit.bold) |
| 3397 (*bold) = TRUE; | |
| 3398 if (imhtml->edit.italic) | |
| 3399 (*italic) = TRUE; | |
| 3400 if (imhtml->edit.underline) | |
| 3401 (*underline) = TRUE; | |
| 8481 | 3402 } |
| 3403 | |
| 9025 | 3404 char * |
| 3405 gtk_imhtml_get_current_fontface(GtkIMHtml *imhtml) | |
| 3406 { | |
| 3407 if (imhtml->edit.fontface) | |
| 3408 return g_strdup(imhtml->edit.fontface); | |
| 3409 else | |
| 3410 return NULL; | |
| 3411 } | |
| 3412 | |
| 3413 char * | |
| 3414 gtk_imhtml_get_current_forecolor(GtkIMHtml *imhtml) | |
| 3415 { | |
| 3416 if (imhtml->edit.forecolor) | |
| 3417 return g_strdup(imhtml->edit.forecolor); | |
| 3418 else | |
| 3419 return NULL; | |
| 3420 } | |
| 3421 | |
| 3422 char * | |
| 3423 gtk_imhtml_get_current_backcolor(GtkIMHtml *imhtml) | |
| 3424 { | |
| 3425 if (imhtml->edit.backcolor) | |
| 3426 return g_strdup(imhtml->edit.backcolor); | |
| 3427 else | |
| 3428 return NULL; | |
| 3429 } | |
| 3430 | |
| 3431 gint | |
| 3432 gtk_imhtml_get_current_fontsize(GtkIMHtml *imhtml) | |
| 3433 { | |
| 3434 return imhtml->edit.fontsize; | |
| 3435 } | |
| 3436 | |
| 8061 | 3437 gboolean gtk_imhtml_get_editable(GtkIMHtml *imhtml) |
| 3438 { | |
| 3439 return imhtml->editable; | |
| 3440 } | |
| 3441 | |
| 8677 | 3442 /* |
| 3443 * I had this crazy idea about changing the text cursor color to reflex the foreground color | |
| 3444 * of the text about to be entered. This is the place you'd do it, along with the place where | |
| 3445 * we actually set a new foreground color. | |
| 3446 * I may not do this, because people will bitch about Gaim overriding their gtk theme's cursor | |
| 3447 * colors. | |
| 3448 * | |
| 3449 * Just in case I do do this, I asked about what to set the secondary text cursor to. | |
| 3450 * | |
| 8719 | 3451 * (12:45:27) ?? ???: secondary_cursor_color = (rgb(background) + rgb(primary_cursor_color) ) / 2 |
| 3452 * (12:45:55) ?? ???: understand? | |
| 8677 | 3453 * (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
|
3454 * (12:46:56) ?? ???: u might need to extract separate each color from RGB |
| 8677 | 3455 */ |
| 3456 | |
| 3457 static void mark_set_cb(GtkTextBuffer *buffer, GtkTextIter *arg1, GtkTextMark *mark, | |
| 3458 GtkIMHtml *imhtml) | |
| 3459 { | |
| 3460 GSList *tags, *l; | |
| 3461 GtkTextIter iter; | |
| 3462 | |
| 3463 if (mark != gtk_text_buffer_get_insert(buffer)) | |
| 3464 return; | |
| 3465 | |
| 3466 if (!gtk_text_buffer_get_char_count(buffer)) | |
| 3467 return; | |
| 3468 | |
| 9924 | 3469 imhtml->edit.bold = imhtml->edit.italic = imhtml->edit.underline = imhtml->edit.strike = FALSE; |
| 8677 | 3470 if (imhtml->edit.forecolor) |
| 3471 g_free(imhtml->edit.forecolor); | |
| 3472 imhtml->edit.forecolor = NULL; | |
| 3473 if (imhtml->edit.backcolor) | |
| 3474 g_free(imhtml->edit.backcolor); | |
| 3475 imhtml->edit.backcolor = NULL; | |
| 3476 if (imhtml->edit.fontface) | |
| 3477 g_free(imhtml->edit.fontface); | |
| 3478 imhtml->edit.fontface = NULL; | |
| 3479 imhtml->edit.fontsize = 0; | |
| 3480 imhtml->edit.link = NULL; | |
| 3481 | |
| 3482 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
| 3483 | |
| 3484 | |
| 3485 if (gtk_text_iter_is_end(&iter)) | |
| 3486 tags = gtk_text_iter_get_toggled_tags(&iter, FALSE); | |
| 3487 else | |
| 3488 tags = gtk_text_iter_get_tags(&iter); | |
| 3489 | |
| 3490 for (l = tags; l != NULL; l = l->next) { | |
| 3491 GtkTextTag *tag = GTK_TEXT_TAG(l->data); | |
| 3492 | |
| 3493 if (tag->name) { | |
| 3494 if (strcmp(tag->name, "BOLD") == 0) | |
| 3495 imhtml->edit.bold = TRUE; | |
| 3496 if (strcmp(tag->name, "ITALICS") == 0) | |
| 3497 imhtml->edit.italic = TRUE; | |
| 3498 if (strcmp(tag->name, "UNDERLINE") == 0) | |
| 3499 imhtml->edit.underline = TRUE; | |
| 9924 | 3500 if (strcmp(tag->name, "STRIKE") == 0) |
| 3501 imhtml->edit.strike = TRUE; | |
| 8677 | 3502 if (strncmp(tag->name, "FORECOLOR ", 10) == 0) |
| 3503 imhtml->edit.forecolor = g_strdup(&(tag->name)[10]); | |
| 3504 if (strncmp(tag->name, "BACKCOLOR ", 10) == 0) | |
| 3505 imhtml->edit.backcolor = g_strdup(&(tag->name)[10]); | |
| 3506 if (strncmp(tag->name, "FONT FACE ", 10) == 0) | |
| 3507 imhtml->edit.fontface = g_strdup(&(tag->name)[10]); | |
| 3508 if (strncmp(tag->name, "FONT SIZE ", 10) == 0) | |
| 3509 imhtml->edit.fontsize = strtol(&(tag->name)[10], NULL, 10); | |
| 8719 | 3510 if ((strncmp(tag->name, "LINK ", 5) == 0) && !gtk_text_iter_is_end(&iter)) |
| 8677 | 3511 imhtml->edit.link = tag; |
| 3512 } | |
| 3513 } | |
| 3514 | |
| 3515 g_slist_free(tags); | |
| 3516 } | |
| 3517 | |
| 8061 | 3518 gboolean gtk_imhtml_toggle_bold(GtkIMHtml *imhtml) |
| 3519 { | |
| 8481 | 3520 GObject *object; |
| 8677 | 3521 GtkTextIter start, end; |
| 3522 | |
| 3523 imhtml->edit.bold = !imhtml->edit.bold; | |
| 3524 | |
| 3525 if (imhtml->wbfo) { | |
| 3526 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3527 if (imhtml->edit.bold) | |
| 3528 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
| 3529 else | |
| 3530 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
| 3531 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3532 if (imhtml->edit.bold) | |
| 3533 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
| 3534 else | |
| 3535 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "BOLD", &start, &end); | |
| 3536 | |
| 8061 | 3537 } |
| 8481 | 3538 object = g_object_ref(G_OBJECT(imhtml)); |
| 3539 g_object_unref(object); | |
| 3540 | |
| 8677 | 3541 return (imhtml->edit.bold != FALSE); |
| 8061 | 3542 } |
| 3543 | |
| 3544 gboolean gtk_imhtml_toggle_italic(GtkIMHtml *imhtml) | |
| 3545 { | |
| 8481 | 3546 GObject *object; |
| 8677 | 3547 GtkTextIter start, end; |
| 3548 | |
| 3549 imhtml->edit.italic = !imhtml->edit.italic; | |
| 3550 | |
| 3551 if (imhtml->wbfo) { | |
| 3552 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3553 if (imhtml->edit.italic) | |
| 3554 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
| 3555 else | |
| 3556 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
| 3557 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3558 if (imhtml->edit.italic) | |
| 3559 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
| 3560 else | |
| 3561 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "ITALICS", &start, &end); | |
| 8061 | 3562 } |
| 8481 | 3563 object = g_object_ref(G_OBJECT(imhtml)); |
| 3564 g_object_unref(object); | |
| 3565 | |
| 8677 | 3566 return imhtml->edit.italic != FALSE; |
| 8061 | 3567 } |
| 3568 | |
| 3569 gboolean gtk_imhtml_toggle_underline(GtkIMHtml *imhtml) | |
| 3570 { | |
| 8481 | 3571 GObject *object; |
| 8677 | 3572 GtkTextIter start, end; |
| 3573 | |
| 3574 imhtml->edit.underline = !imhtml->edit.underline; | |
| 3575 | |
| 3576 if (imhtml->wbfo) { | |
| 3577 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3578 if (imhtml->edit.underline) | |
| 3579 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
| 3580 else | |
| 3581 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
| 3582 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3583 if (imhtml->edit.underline) | |
| 3584 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
| 3585 else | |
| 3586 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "UNDERLINE", &start, &end); | |
| 8061 | 3587 } |
| 8481 | 3588 object = g_object_ref(G_OBJECT(imhtml)); |
| 3589 g_object_unref(object); | |
| 3590 | |
| 8677 | 3591 return imhtml->edit.underline != FALSE; |
| 8061 | 3592 } |
| 3593 | |
| 9924 | 3594 gboolean gtk_imhtml_toggle_strike(GtkIMHtml *imhtml) |
| 3595 { | |
| 3596 GObject *object; | |
| 3597 GtkTextIter start, end; | |
| 3598 | |
| 3599 imhtml->edit.strike = !imhtml->edit.strike; | |
| 3600 | |
| 3601 if (imhtml->wbfo) { | |
| 3602 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3603 if (imhtml->edit.strike) | |
| 3604 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
| 3605 else | |
| 3606 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
| 3607 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3608 if (imhtml->edit.strike) | |
| 3609 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
| 3610 else | |
| 3611 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "STRIKE", &start, &end); | |
| 3612 } | |
| 3613 object = g_object_ref(G_OBJECT(imhtml)); | |
| 3614 g_object_unref(object); | |
| 3615 | |
| 3616 return imhtml->edit.strike != FALSE; | |
| 3617 } | |
| 3618 | |
| 8061 | 3619 void gtk_imhtml_font_set_size(GtkIMHtml *imhtml, gint size) |
| 3620 { | |
| 9025 | 3621 GObject *object; |
| 8677 | 3622 GtkTextIter start, end; |
| 9025 | 3623 GtkIMHtmlButtons b = 0; |
| 8061 | 3624 |
| 3625 imhtml->edit.fontsize = size; | |
| 3626 | |
| 8677 | 3627 |
| 3628 if (imhtml->wbfo) { | |
| 3629 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3630 remove_font_size(imhtml, &start, &end, TRUE); | |
| 3631 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3632 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
| 3633 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3634 remove_font_size(imhtml, &start, &end, FALSE); | |
| 3635 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3636 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
| 8061 | 3637 } |
| 8677 | 3638 |
| 9025 | 3639 object = g_object_ref(G_OBJECT(imhtml)); |
| 3640 b |= GTK_IMHTML_SHRINK; | |
| 3641 b |= GTK_IMHTML_GROW; | |
| 3642 g_object_unref(object); | |
| 8061 | 3643 } |
| 3644 | |
| 3645 void gtk_imhtml_font_shrink(GtkIMHtml *imhtml) | |
| 3646 { | |
| 9025 | 3647 GObject *object; |
| 8677 | 3648 GtkTextIter start, end; |
| 3649 | |
| 8061 | 3650 if (imhtml->edit.fontsize == 1) |
| 3651 return; | |
| 3652 | |
| 8677 | 3653 if (!imhtml->edit.fontsize) |
| 3654 imhtml->edit.fontsize = 2; | |
| 3655 else | |
| 3656 imhtml->edit.fontsize--; | |
| 3657 | |
| 3658 if (imhtml->wbfo) { | |
| 3659 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3660 remove_font_size(imhtml, &start, &end, TRUE); | |
| 3661 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3662 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
| 3663 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3664 remove_font_size(imhtml, &start, &end, FALSE); | |
| 3665 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3666 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
| 8061 | 3667 } |
| 9025 | 3668 object = g_object_ref(G_OBJECT(imhtml)); |
| 3669 g_object_unref(object); | |
| 8061 | 3670 } |
| 3671 | |
| 3672 void gtk_imhtml_font_grow(GtkIMHtml *imhtml) | |
| 3673 { | |
| 9025 | 3674 GObject *object; |
| 8677 | 3675 GtkTextIter start, end; |
| 3676 | |
| 8061 | 3677 if (imhtml->edit.fontsize == MAX_FONT_SIZE) |
| 3678 return; | |
| 3679 | |
| 8677 | 3680 if (!imhtml->edit.fontsize) |
| 3681 imhtml->edit.fontsize = 4; | |
| 3682 else | |
| 3683 imhtml->edit.fontsize++; | |
| 3684 | |
| 3685 if (imhtml->wbfo) { | |
| 3686 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3687 remove_font_size(imhtml, &start, &end, TRUE); | |
| 3688 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3689 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
| 3690 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3691 remove_font_size(imhtml, &start, &end, FALSE); | |
| 3692 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3693 find_font_size_tag(imhtml, imhtml->edit.fontsize), &start, &end); | |
| 8061 | 3694 } |
| 9025 | 3695 object = g_object_ref(G_OBJECT(imhtml)); |
| 3696 g_object_unref(object); | |
| 8061 | 3697 } |
| 3698 | |
| 3699 gboolean gtk_imhtml_toggle_forecolor(GtkIMHtml *imhtml, const char *color) | |
| 3700 { | |
| 9025 | 3701 GObject *object; |
| 8677 | 3702 GtkTextIter start, end; |
| 3703 | |
| 3704 if (imhtml->edit.forecolor != NULL) | |
| 3705 g_free(imhtml->edit.forecolor); | |
| 3706 | |
| 9025 | 3707 if (color && strcmp(color, "") != 0) { |
| 8677 | 3708 imhtml->edit.forecolor = g_strdup(color); |
| 3709 if (imhtml->wbfo) { | |
| 3710 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3711 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
| 3712 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3713 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), &start, &end); | |
| 3714 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3715 remove_font_forecolor(imhtml, &start, &end, FALSE); | |
| 3716 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3717 find_font_forecolor_tag(imhtml, imhtml->edit.forecolor), | |
| 3718 &start, &end); | |
| 3719 } | |
| 8061 | 3720 } else { |
| 3721 imhtml->edit.forecolor = NULL; | |
| 9025 | 3722 if (imhtml->wbfo) { |
| 3723 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3724 remove_font_forecolor(imhtml, &start, &end, TRUE); | |
| 3725 } | |
| 8061 | 3726 } |
| 3727 | |
| 9025 | 3728 object = g_object_ref(G_OBJECT(imhtml)); |
| 3729 g_object_unref(object); | |
| 3730 | |
| 8061 | 3731 return imhtml->edit.forecolor != NULL; |
| 3732 } | |
| 3733 | |
| 3734 gboolean gtk_imhtml_toggle_backcolor(GtkIMHtml *imhtml, const char *color) | |
| 3735 { | |
| 9025 | 3736 GObject *object; |
| 8677 | 3737 GtkTextIter start, end; |
| 3738 | |
| 3739 if (imhtml->edit.backcolor != NULL) | |
| 3740 g_free(imhtml->edit.backcolor); | |
| 3741 | |
| 9025 | 3742 if (color && strcmp(color, "") != 0) { |
| 8677 | 3743 imhtml->edit.backcolor = g_strdup(color); |
| 3744 | |
| 3745 if (imhtml->wbfo) { | |
| 3746 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3747 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
| 3748 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3749 find_font_backcolor_tag(imhtml, imhtml->edit.backcolor), &start, &end); | |
| 3750 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3751 remove_font_backcolor(imhtml, &start, &end, FALSE); | |
| 3752 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3753 find_font_backcolor_tag(imhtml, | |
| 3754 imhtml->edit.backcolor), &start, &end); | |
| 3755 } | |
| 8061 | 3756 } else { |
| 3757 imhtml->edit.backcolor = NULL; | |
| 9025 | 3758 if (imhtml->wbfo) { |
| 3759 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3760 remove_font_backcolor(imhtml, &start, &end, TRUE); | |
| 3761 } | |
| 8061 | 3762 } |
| 8677 | 3763 |
| 9025 | 3764 object = g_object_ref(G_OBJECT(imhtml)); |
| 3765 g_object_unref(object); | |
| 3766 | |
| 8061 | 3767 return imhtml->edit.backcolor != NULL; |
| 3768 } | |
| 3769 | |
| 3770 gboolean gtk_imhtml_toggle_fontface(GtkIMHtml *imhtml, const char *face) | |
| 3771 { | |
| 9025 | 3772 GObject *object; |
| 8677 | 3773 GtkTextIter start, end; |
| 3774 | |
| 3775 if (imhtml->edit.fontface != NULL) | |
| 3776 g_free(imhtml->edit.fontface); | |
| 3777 | |
| 9025 | 3778 if (face && strcmp(face, "") != 0) { |
| 8677 | 3779 imhtml->edit.fontface = g_strdup(face); |
| 3780 | |
| 3781 if (imhtml->wbfo) { | |
| 3782 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3783 remove_font_face(imhtml, &start, &end, TRUE); | |
| 3784 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3785 find_font_face_tag(imhtml, imhtml->edit.fontface), &start, &end); | |
| 3786 } else if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3787 remove_font_face(imhtml, &start, &end, FALSE); | |
| 3788 gtk_text_buffer_apply_tag(imhtml->text_buffer, | |
| 3789 find_font_face_tag(imhtml, imhtml->edit.fontface), | |
| 3790 &start, &end); | |
| 3791 } | |
| 8061 | 3792 } else { |
| 3793 imhtml->edit.fontface = NULL; | |
| 9025 | 3794 if (imhtml->wbfo) { |
| 3795 gtk_text_buffer_get_bounds(imhtml->text_buffer, &start, &end); | |
| 3796 remove_font_face(imhtml, &start, &end, TRUE); | |
| 3797 } | |
| 8061 | 3798 } |
| 8677 | 3799 |
| 9025 | 3800 object = g_object_ref(G_OBJECT(imhtml)); |
| 3801 g_object_unref(object); | |
| 3802 | |
| 8061 | 3803 return imhtml->edit.fontface != NULL; |
| 3804 } | |
| 3805 | |
| 8677 | 3806 void gtk_imhtml_toggle_link(GtkIMHtml *imhtml, const char *url) |
| 8061 | 3807 { |
| 9025 | 3808 GObject *object; |
| 8677 | 3809 GtkTextIter start, end; |
| 3810 GtkTextTag *linktag; | |
| 3811 static guint linkno = 0; | |
| 3812 gchar str[48]; | |
| 9007 | 3813 GdkColor *color = NULL; |
| 8677 | 3814 |
| 3815 imhtml->edit.link = NULL; | |
| 3816 | |
| 3817 | |
| 3818 | |
| 3819 if (url) { | |
| 3820 g_snprintf(str, sizeof(str), "LINK %d", linkno++); | |
| 3821 str[47] = '\0'; | |
| 3822 | |
| 9007 | 3823 gtk_widget_style_get(GTK_WIDGET(imhtml), "hyperlink-color", &color, NULL); |
| 9008 | 3824 if (color) { |
| 9007 | 3825 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground-gdk", color, "underline", PANGO_UNDERLINE_SINGLE, NULL); |
| 9008 | 3826 gdk_color_free(color); |
| 3827 } else { | |
| 9007 | 3828 imhtml->edit.link = linktag = gtk_text_buffer_create_tag(imhtml->text_buffer, str, "foreground", "blue", "underline", PANGO_UNDERLINE_SINGLE, NULL); |
| 9008 | 3829 } |
| 8677 | 3830 g_object_set_data_full(G_OBJECT(linktag), "link_url", g_strdup(url), g_free); |
| 3831 g_signal_connect(G_OBJECT(linktag), "event", G_CALLBACK(tag_event), NULL); | |
| 3832 | |
| 3833 if (imhtml->editable && gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, &start, &end)) { | |
| 3834 remove_font_link(imhtml, &start, &end, FALSE); | |
| 3835 gtk_text_buffer_apply_tag(imhtml->text_buffer, linktag, &start, &end); | |
| 3836 } | |
| 3837 } | |
| 9025 | 3838 |
| 3839 object = g_object_ref(G_OBJECT(imhtml)); | |
| 3840 g_signal_emit(object, signals[TOGGLE_FORMAT], 0, GTK_IMHTML_LINK); | |
| 3841 g_object_unref(object); | |
| 8677 | 3842 } |
| 3843 | |
| 3844 void gtk_imhtml_insert_link(GtkIMHtml *imhtml, GtkTextMark *mark, const char *url, const char *text) | |
| 3845 { | |
| 8061 | 3846 GtkTextIter iter; |
| 8677 | 3847 |
| 9599 | 3848 if (gtk_text_buffer_get_selection_bounds(imhtml->text_buffer, NULL, NULL)) |
| 3849 gtk_text_buffer_delete_selection(imhtml->text_buffer, TRUE, TRUE); | |
| 3850 | |
| 8677 | 3851 gtk_imhtml_toggle_link(imhtml, url); |
| 8061 | 3852 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); |
| 8677 | 3853 gtk_text_buffer_insert(imhtml->text_buffer, &iter, text, -1); |
| 3854 gtk_imhtml_toggle_link(imhtml, NULL); | |
| 8061 | 3855 } |
| 3856 | |
| 3857 void gtk_imhtml_insert_smiley(GtkIMHtml *imhtml, const char *sml, char *smiley) | |
| 3858 { | |
| 8677 | 3859 GtkTextMark *mark; |
| 8061 | 3860 GtkTextIter iter; |
| 8677 | 3861 |
| 3862 mark = gtk_text_buffer_get_insert(imhtml->text_buffer); | |
| 3863 | |
| 3864 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &iter, mark); | |
| 3865 gtk_imhtml_insert_smiley_at_iter(imhtml, sml, smiley, &iter); | |
| 3866 } | |
| 3867 | |
| 3868 void gtk_imhtml_insert_smiley_at_iter(GtkIMHtml *imhtml, const char *sml, char *smiley, GtkTextIter *iter) | |
| 3869 { | |
| 8061 | 3870 GdkPixbuf *pixbuf = NULL; |
| 3871 GdkPixbufAnimation *annipixbuf = NULL; | |
| 3872 GtkWidget *icon = NULL; | |
| 3873 GtkTextChildAnchor *anchor; | |
| 8505 | 3874 char *unescaped = gaim_unescape_html(smiley); |
| 8061 | 3875 |
| 8505 | 3876 annipixbuf = gtk_smiley_tree_image(imhtml, sml, unescaped); |
| 8061 | 3877 if(annipixbuf) { |
| 3878 if(gdk_pixbuf_animation_is_static_image(annipixbuf)) { | |
| 3879 pixbuf = gdk_pixbuf_animation_get_static_image(annipixbuf); | |
| 3880 if(pixbuf) | |
| 3881 icon = gtk_image_new_from_pixbuf(pixbuf); | |
| 3882 } else { | |
| 3883 icon = gtk_image_new_from_animation(annipixbuf); | |
| 3884 } | |
| 3885 } | |
| 3886 | |
| 3887 if (icon) { | |
| 8890 | 3888 anchor = gtk_text_buffer_create_child_anchor(imhtml->text_buffer, iter); |
| 3889 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_plaintext", g_strdup(unescaped), g_free); | |
| 3890 g_object_set_data_full(G_OBJECT(anchor), "gtkimhtml_htmltext", g_strdup(smiley), g_free); | |
| 3891 | |
| 8061 | 3892 gtk_widget_show(icon); |
| 3893 gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(imhtml), icon, anchor); | |
| 8890 | 3894 } else { |
| 3895 gtk_text_buffer_insert(imhtml->text_buffer, iter, smiley, -1); | |
| 8061 | 3896 } |
| 8890 | 3897 |
| 3898 g_free(unescaped); | |
| 8061 | 3899 } |
| 3900 | |
| 8962 | 3901 void gtk_imhtml_insert_image_at_iter(GtkIMHtml *imhtml, int id, GtkTextIter *iter) |
| 3902 { | |
| 3903 GdkPixbuf *pixbuf = NULL; | |
| 3904 const char *filename = NULL; | |
| 3905 gpointer image; | |
| 3906 GdkRectangle rect; | |
| 3907 GtkIMHtmlScalable *scalable = NULL; | |
| 3908 int minus; | |
| 3909 | |
| 3910 if (!imhtml->funcs || !imhtml->funcs->image_get || | |
| 3911 !imhtml->funcs->image_get_size || !imhtml->funcs->image_get_data || | |
| 3912 !imhtml->funcs->image_get_filename || !imhtml->funcs->image_ref || | |
| 3913 !imhtml->funcs->image_unref) | |
| 3914 return; | |
| 3915 | |
| 3916 image = imhtml->funcs->image_get(id); | |
| 3917 | |
| 3918 if (image) { | |
| 3919 gpointer data; | |
| 3920 size_t len; | |
| 3921 | |
| 3922 data = imhtml->funcs->image_get_data(image); | |
| 3923 len = imhtml->funcs->image_get_size(image); | |
| 3924 | |
| 3925 if (data && len) { | |
| 3926 GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); | |
| 3927 gdk_pixbuf_loader_write(loader, data, len, NULL); | |
| 3928 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader); | |
| 9337 | 3929 if (pixbuf) |
| 3930 g_object_ref(G_OBJECT(pixbuf)); | |
| 8962 | 3931 gdk_pixbuf_loader_close(loader, NULL); |
| 9337 | 3932 g_object_unref(G_OBJECT(loader)); |
| 8962 | 3933 } |
| 3934 | |
| 3935 } | |
| 3936 | |
| 3937 if (pixbuf) { | |
| 3938 filename = imhtml->funcs->image_get_filename(image); | |
| 3939 imhtml->funcs->image_ref(id); | |
| 3940 imhtml->im_images = g_slist_prepend(imhtml->im_images, GINT_TO_POINTER(id)); | |
| 3941 } else { | |
| 3942 pixbuf = gtk_widget_render_icon(GTK_WIDGET(imhtml), GTK_STOCK_MISSING_IMAGE, | |
| 3943 GTK_ICON_SIZE_BUTTON, "gtkimhtml-missing-image"); | |
| 3944 } | |
| 3945 | |
| 3946 scalable = gtk_imhtml_image_new(pixbuf, filename, id); | |
| 3947 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); | |
| 3948 scalable->add_to(scalable, imhtml, iter); | |
| 3949 minus = gtk_text_view_get_left_margin(GTK_TEXT_VIEW(imhtml)) + | |
| 3950 gtk_text_view_get_right_margin(GTK_TEXT_VIEW(imhtml)); | |
| 3951 scalable->scale(scalable, rect.width - minus, rect.height); | |
| 3952 imhtml->scalables = g_list_append(imhtml->scalables, scalable); | |
| 3953 | |
| 3954 g_object_unref(G_OBJECT(pixbuf)); | |
| 3955 } | |
| 3956 | |
| 8677 | 3957 static const gchar *tag_to_html_start(GtkTextTag *tag) |
| 8061 | 3958 { |
| 8677 | 3959 const gchar *name; |
| 3960 static gchar buf[1024]; | |
| 3961 | |
| 3962 name = tag->name; | |
| 3963 g_return_val_if_fail(name != NULL, ""); | |
| 3964 | |
| 3965 if (strcmp(name, "BOLD") == 0) { | |
| 3966 return "<b>"; | |
| 3967 } else if (strcmp(name, "ITALICS") == 0) { | |
| 3968 return "<i>"; | |
| 3969 } else if (strcmp(name, "UNDERLINE") == 0) { | |
| 3970 return "<u>"; | |
| 9924 | 3971 } else if (strcmp(name, "STRIKE") == 0) { |
| 3972 return "<s>"; | |
| 8677 | 3973 } else if (strncmp(name, "LINK ", 5) == 0) { |
| 3974 char *tmp = g_object_get_data(G_OBJECT(tag), "link_url"); | |
| 3975 if (tmp) { | |
| 3976 g_snprintf(buf, sizeof(buf), "<a href=\"%s\">", tmp); | |
| 3977 buf[sizeof(buf)-1] = '\0'; | |
| 3978 return buf; | |
| 3979 } else { | |
| 3980 return ""; | |
| 3981 } | |
| 3982 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
| 3983 g_snprintf(buf, sizeof(buf), "<font color=\"%s\">", &name[10]); | |
| 3984 return buf; | |
| 3985 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
| 3986 g_snprintf(buf, sizeof(buf), "<font back=\"%s\">", &name[10]); | |
| 3987 return buf; | |
| 3988 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
| 3989 g_snprintf(buf, sizeof(buf), "<font face=\"%s\">", &name[10]); | |
| 3990 return buf; | |
| 3991 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
| 3992 g_snprintf(buf, sizeof(buf), "<font size=\"%s\">", &name[10]); | |
| 3993 return buf; | |
| 3994 } else { | |
| 3995 return ""; | |
| 3996 } | |
| 8061 | 3997 } |
| 3998 | |
| 8677 | 3999 static const gchar *tag_to_html_end(GtkTextTag *tag) |
| 8061 | 4000 { |
| 8677 | 4001 const gchar *name; |
| 4002 | |
| 4003 name = tag->name; | |
| 4004 g_return_val_if_fail(name != NULL, ""); | |
| 4005 | |
| 4006 if (strcmp(name, "BOLD") == 0) { | |
| 4007 return "</b>"; | |
| 4008 } else if (strcmp(name, "ITALICS") == 0) { | |
| 4009 return "</i>"; | |
| 4010 } else if (strcmp(name, "UNDERLINE") == 0) { | |
| 4011 return "</u>"; | |
| 9924 | 4012 } else if (strcmp(name, "STRIKE") == 0) { |
| 4013 return "</s>"; | |
| 8677 | 4014 } else if (strncmp(name, "LINK ", 5) == 0) { |
| 4015 return "</a>"; | |
| 4016 } else if (strncmp(name, "FORECOLOR ", 10) == 0) { | |
| 4017 return "</font>"; | |
| 4018 } else if (strncmp(name, "BACKCOLOR ", 10) == 0) { | |
| 4019 return "</font>"; | |
| 4020 } else if (strncmp(name, "FONT FACE ", 10) == 0) { | |
| 4021 return "</font>"; | |
| 4022 } else if (strncmp(name, "FONT SIZE ", 10) == 0) { | |
| 4023 return "</font>"; | |
| 4024 } else { | |
| 4025 return ""; | |
| 4026 } | |
| 4027 } | |
| 4028 | |
| 4029 static gboolean tag_ends_here(GtkTextTag *tag, GtkTextIter *iter, GtkTextIter *niter) | |
| 4030 { | |
| 4031 return ((gtk_text_iter_has_tag(iter, GTK_TEXT_TAG(tag)) && | |
| 4032 !gtk_text_iter_has_tag(niter, GTK_TEXT_TAG(tag))) || | |
| 4033 gtk_text_iter_is_end(niter)); | |
| 8061 | 4034 } |
| 4035 | |
| 4036 /* Basic notion here: traverse through the text buffer one-by-one, non-character elements, such | |
| 4037 * as smileys and IM images are represented by the Unicode "unknown" character. Handle them. Else | |
| 8677 | 4038 * check for tags that are toggled on, insert their html form, and push them on the queue. Then insert |
| 4039 * 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
|
4040 * Finally, replace <, >, &, and " with their HTML equivalent. |
| 8677 | 4041 */ |
| 8061 | 4042 char *gtk_imhtml_get_markup_range(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *end) |
| 4043 { | |
| 4044 gunichar c; | |
| 8677 | 4045 GtkTextIter iter, nextiter; |
| 8061 | 4046 GString *str = g_string_new(""); |
| 8677 | 4047 GSList *tags, *sl; |
| 4048 GQueue *q, *r; | |
| 4049 GtkTextTag *tag; | |
| 4050 | |
| 4051 q = g_queue_new(); | |
| 4052 r = g_queue_new(); | |
| 4053 | |
| 8061 | 4054 |
| 4055 gtk_text_iter_order(start, end); | |
| 8677 | 4056 nextiter = iter = *start; |
| 4057 gtk_text_iter_forward_char(&nextiter); | |
| 4058 | |
| 9071 | 4059 /* First add the tags that are already in progress (we don't care about non-printing tags)*/ |
| 8677 | 4060 tags = gtk_text_iter_get_tags(start); |
| 4061 | |
| 4062 for (sl = tags; sl; sl = sl->next) { | |
| 4063 tag = sl->data; | |
| 4064 if (!gtk_text_iter_toggles_tag(start, GTK_TEXT_TAG(tag))) { | |
| 9071 | 4065 if (strlen(tag_to_html_end(tag)) > 0) |
| 4066 g_string_append(str, tag_to_html_start(tag)); | |
| 8677 | 4067 g_queue_push_tail(q, tag); |
| 8061 | 4068 } |
| 4069 } | |
| 8677 | 4070 g_slist_free(tags); |
| 8061 | 4071 |
| 4072 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, end)) { | |
| 8677 | 4073 |
| 4074 tags = gtk_text_iter_get_tags(&iter); | |
| 4075 | |
| 4076 for (sl = tags; sl; sl = sl->next) { | |
| 4077 tag = sl->data; | |
| 4078 if (gtk_text_iter_begins_tag(&iter, GTK_TEXT_TAG(tag))) { | |
| 9071 | 4079 if (strlen(tag_to_html_end(tag)) > 0) |
| 4080 g_string_append(str, tag_to_html_start(tag)); | |
| 8677 | 4081 g_queue_push_tail(q, tag); |
| 4082 } | |
| 4083 } | |
| 4084 | |
| 4085 | |
| 8061 | 4086 if (c == 0xFFFC) { |
| 4087 GtkTextChildAnchor* anchor = gtk_text_iter_get_child_anchor(&iter); | |
| 9071 | 4088 if (anchor) { |
| 4089 char *text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_htmltext"); | |
| 4090 if (text) | |
| 4091 str = g_string_append(str, text); | |
| 4092 } | |
| 8677 | 4093 } else if (c == '<') { |
| 4094 str = g_string_append(str, "<"); | |
| 4095 } else if (c == '>') { | |
| 4096 str = g_string_append(str, ">"); | |
| 4097 } else if (c == '&') { | |
| 4098 str = g_string_append(str, "&"); | |
| 4099 } else if (c == '"') { | |
| 4100 str = g_string_append(str, """); | |
| 4101 } else if (c == '\n') { | |
| 4102 str = g_string_append(str, "<br>"); | |
| 8061 | 4103 } else { |
| 8677 | 4104 str = g_string_append_unichar(str, c); |
| 4105 } | |
| 4106 | |
| 4107 tags = g_slist_reverse(tags); | |
| 4108 for (sl = tags; sl; sl = sl->next) { | |
| 4109 tag = sl->data; | |
| 9071 | 4110 /** don't worry about non-printing tags ending */ |
| 4111 if (tag_ends_here(tag, &iter, &nextiter) && strlen(tag_to_html_end(tag)) > 0) { | |
| 8677 | 4112 |
| 4113 GtkTextTag *tmp; | |
| 4114 | |
| 4115 while ((tmp = g_queue_pop_tail(q)) != tag) { | |
| 4116 if (tmp == NULL) | |
| 4117 break; | |
| 4118 | |
| 9071 | 4119 if (!tag_ends_here(tmp, &iter, &nextiter) && strlen(tag_to_html_end(tmp)) > 0) |
| 8677 | 4120 g_queue_push_tail(r, tmp); |
| 4121 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tmp))); | |
| 4122 } | |
| 4123 | |
| 4124 if (tmp == NULL) | |
| 4125 gaim_debug_warning("gtkimhtml", "empty queue, more closing tags than open tags!\n"); | |
| 4126 else | |
| 4127 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
| 4128 | |
| 4129 while ((tmp = g_queue_pop_head(r))) { | |
| 4130 g_string_append(str, tag_to_html_start(GTK_TEXT_TAG(tmp))); | |
| 4131 g_queue_push_tail(q, tmp); | |
| 8061 | 4132 } |
| 4133 } | |
| 4134 } | |
| 8677 | 4135 |
| 4136 g_slist_free(tags); | |
| 8061 | 4137 gtk_text_iter_forward_char(&iter); |
| 8677 | 4138 gtk_text_iter_forward_char(&nextiter); |
| 8061 | 4139 } |
| 8677 | 4140 |
| 4141 while ((tag = g_queue_pop_tail(q))) | |
| 4142 g_string_append(str, tag_to_html_end(GTK_TEXT_TAG(tag))); | |
| 4143 | |
| 4144 g_queue_free(q); | |
| 4145 g_queue_free(r); | |
| 8061 | 4146 return g_string_free(str, FALSE); |
| 4147 } | |
| 4148 | |
| 8698 | 4149 void gtk_imhtml_close_tags(GtkIMHtml *imhtml, GtkTextIter *iter) |
| 8061 | 4150 { |
| 4151 if (imhtml->edit.bold) | |
| 4152 gtk_imhtml_toggle_bold(imhtml); | |
| 4153 | |
| 4154 if (imhtml->edit.italic) | |
| 4155 gtk_imhtml_toggle_italic(imhtml); | |
| 4156 | |
| 4157 if (imhtml->edit.underline) | |
| 4158 gtk_imhtml_toggle_underline(imhtml); | |
| 4159 | |
| 9924 | 4160 if (imhtml->edit.strike) |
| 4161 gtk_imhtml_toggle_strike(imhtml); | |
| 4162 | |
| 8061 | 4163 if (imhtml->edit.forecolor) |
| 4164 gtk_imhtml_toggle_forecolor(imhtml, NULL); | |
| 4165 | |
| 4166 if (imhtml->edit.backcolor) | |
| 4167 gtk_imhtml_toggle_backcolor(imhtml, NULL); | |
| 4168 | |
| 4169 if (imhtml->edit.fontface) | |
| 4170 gtk_imhtml_toggle_fontface(imhtml, NULL); | |
| 4171 | |
| 8677 | 4172 imhtml->edit.fontsize = 0; |
| 4173 | |
| 8719 | 4174 if (imhtml->edit.link) |
| 4175 gtk_imhtml_toggle_link(imhtml, NULL); | |
| 4176 | |
| 8698 | 4177 gtk_text_buffer_remove_all_tags(imhtml->text_buffer, iter, iter); |
| 8061 | 4178 |
| 4179 } | |
| 4180 | |
| 4181 char *gtk_imhtml_get_markup(GtkIMHtml *imhtml) | |
| 4182 { | |
| 4183 GtkTextIter start, end; | |
| 4184 | |
| 4185 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
| 4186 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
| 4187 return gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
| 4188 } | |
| 4189 | |
| 8677 | 4190 char **gtk_imhtml_get_markup_lines(GtkIMHtml *imhtml) |
| 4191 { | |
| 4192 int i, j, lines; | |
| 4193 GtkTextIter start, end; | |
| 4194 char **ret; | |
| 4195 | |
| 4196 lines = gtk_text_buffer_get_line_count(imhtml->text_buffer); | |
| 4197 ret = g_new0(char *, lines + 1); | |
| 4198 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &start); | |
| 4199 end = start; | |
| 4200 gtk_text_iter_forward_to_line_end(&end); | |
| 4201 | |
| 4202 for (i = 0, j = 0; i < lines; i++) { | |
| 9612 | 4203 if (gtk_text_iter_get_char(&start) != '\n') { |
| 4204 ret[j] = gtk_imhtml_get_markup_range(imhtml, &start, &end); | |
| 4205 if (ret[j] != NULL) | |
| 4206 j++; | |
| 4207 } | |
| 4208 | |
| 8677 | 4209 gtk_text_iter_forward_line(&start); |
| 4210 end = start; | |
| 4211 gtk_text_iter_forward_to_line_end(&end); | |
| 4212 } | |
| 4213 | |
| 4214 return ret; | |
| 4215 } | |
| 4216 | |
| 4217 char *gtk_imhtml_get_text(GtkIMHtml *imhtml, GtkTextIter *start, GtkTextIter *stop) | |
| 8061 | 4218 { |
| 8519 | 4219 GString *str = g_string_new(""); |
| 4220 GtkTextIter iter, end; | |
| 4221 gunichar c; | |
| 4222 | |
| 8677 | 4223 if (start == NULL) |
| 4224 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &iter); | |
| 4225 else | |
| 4226 iter = *start; | |
| 4227 | |
| 4228 if (stop == NULL) | |
| 4229 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &end); | |
| 4230 else | |
| 4231 end = *stop; | |
| 4232 | |
| 4233 gtk_text_iter_order(&iter, &end); | |
| 8519 | 4234 |
| 4235 while ((c = gtk_text_iter_get_char(&iter)) != 0 && !gtk_text_iter_equal(&iter, &end)) { | |
| 4236 if (c == 0xFFFC) { | |
| 8677 | 4237 GtkTextChildAnchor* anchor; |
| 4238 char *text = NULL; | |
| 4239 | |
| 4240 anchor = gtk_text_iter_get_child_anchor(&iter); | |
| 4241 if (anchor) | |
| 8698 | 4242 text = g_object_get_data(G_OBJECT(anchor), "gtkimhtml_plaintext"); |
| 8677 | 4243 if (text) |
| 4244 str = g_string_append(str, text); | |
| 8519 | 4245 } else { |
| 4246 g_string_append_unichar(str, c); | |
| 4247 } | |
| 4248 gtk_text_iter_forward_char(&iter); | |
| 4249 } | |
| 4250 | |
| 4251 return g_string_free(str, FALSE); | |
| 8061 | 4252 } |
| 8962 | 4253 |
| 4254 void gtk_imhtml_set_funcs(GtkIMHtml *imhtml, GtkIMHtmlFuncs *f) | |
| 4255 { | |
| 4256 g_return_if_fail(imhtml != NULL); | |
| 4257 imhtml->funcs = f; | |
| 4258 } |
