Mercurial > pidgin
annotate src/gtkutils.c @ 5105:4cfc49e31c2e
[gaim-migrate @ 5468]
David Brigada (jsi) writes:
" This patch changes GTK_WRAP_WORD to GTK_WRAP_WORD_CHAR
throughout the sources. That fixes a bug where long
single-word input into GtkTextViews and similar would
cause the textview to expand, causing the window to
expand. This fix depends on a patch to GTK+ that is in
current CVS but not yet released. To address the
backwards-compatibility issue, GTK_WRAP_WORD_CHAR is
#defined to GTK_WRAP_WORD when not defined by GTK+'s
header files.
The only problem I can forsee is binary compatibility;
if Gaim is compiled under a GTK+ CVS (or a future
release) environment, and then run under a GTK+ 2.2.1
or earlier environment, behavior is undefined; the text
area will probably not wrap at all. However, source
compatibility is maintained."
basically, gaim will start wrapping text in any version of gtk2 that supports it,
and should work exactly the same in any version that still has the bug.
many thanks to David for his hard work.
committer: Tailor Script <tailor@pidgin.im>
author | Luke Schierer <lschiere@pidgin.im> |
---|---|
date | Fri, 11 Apr 2003 04:23:55 +0000 |
parents | a9a831508b43 |
children | 91ea5ef2278b |
rev | line source |
---|---|
4359 | 1 /* |
2 * gaim | |
3 * | |
4 * Copyright (C) 2002-2003, Christian Hammond <chipx86@gnupdate.org> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 #ifdef HAVE_CONFIG_H | |
22 #include <config.h> | |
23 #endif | |
24 #include <string.h> | |
25 #ifndef _WIN32 | |
26 #include <sys/time.h> | |
27 #include <unistd.h> | |
28 #include <gdk/gdkx.h> | |
29 #include <X11/Xlib.h> | |
30 #else | |
31 #ifdef small | |
32 #undef small | |
33 #endif | |
34 #endif /*_WIN32*/ | |
35 #include <sys/types.h> | |
36 #include <sys/stat.h> | |
37 #include <stdio.h> | |
38 #include <stdlib.h> | |
39 #include <errno.h> | |
40 #include <ctype.h> | |
41 #include <gtk/gtk.h> | |
42 #ifdef USE_GTKSPELL | |
43 #include <gtkspell/gtkspell.h> | |
44 #endif | |
45 #include "gtkimhtml.h" | |
46 #include <gdk/gdkkeysyms.h> | |
47 #include "prpl.h" | |
48 #include "ui.h" | |
49 | |
4859
a9a831508b43
[gaim-migrate @ 5186]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4793
diff
changeset
|
50 #ifdef _WIN32 |
a9a831508b43
[gaim-migrate @ 5186]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4793
diff
changeset
|
51 #include "wspell.h" |
a9a831508b43
[gaim-migrate @ 5186]
Herman Bloggs <hermanator12002@yahoo.com>
parents:
4793
diff
changeset
|
52 #endif |
4359 | 53 |
54 void | |
55 gaim_setup_imhtml(GtkWidget *imhtml) | |
56 { | |
57 g_return_if_fail(imhtml != NULL); | |
58 g_return_if_fail(GTK_IS_IMHTML(imhtml)); | |
59 | |
60 if (!(convo_options & OPT_CONVO_SHOW_SMILEY)) | |
61 gtk_imhtml_show_smileys(GTK_IMHTML(imhtml), FALSE); | |
62 | |
63 g_signal_connect(G_OBJECT(imhtml), "url_clicked", | |
64 G_CALLBACK(open_url), NULL); | |
65 | |
66 smiley_themeize(imhtml); | |
67 } | |
68 | |
69 void | |
70 toggle_sensitive(GtkWidget *widget, GtkWidget *to_toggle) | |
71 { | |
72 gboolean sensitivity = GTK_WIDGET_IS_SENSITIVE(to_toggle); | |
73 | |
74 gtk_widget_set_sensitive(to_toggle, !sensitivity); | |
75 } | |
76 | |
77 static void | |
78 gaim_gtk_remove_tags(struct gaim_gtk_conversation *gtkconv, const char *tag) | |
79 { | |
80 GtkTextIter start, end, m_start, m_end; | |
81 | |
82 if (gtkconv == NULL || tag == NULL) | |
83 return; | |
84 | |
85 if (!gtk_text_buffer_get_selection_bounds(gtkconv->entry_buffer, | |
86 &start, &end)) | |
87 return; | |
88 | |
89 /* FIXMEif (strstr(tag, "<FONT SIZE=")) { | |
90 while ((t = strstr(t, "<FONT SIZE="))) { | |
91 if (((t - s) < finish) && ((t - s) >= start)) { | |
92 gtk_editable_delete_text(GTK_EDITABLE(entry), (t - s), | |
93 (t - s) + strlen(tag)); | |
94 g_free(s); | |
95 s = gtk_editable_get_chars(GTK_EDITABLE(entry), 0, -1); | |
96 t = s; | |
97 } else | |
98 t++; | |
99 } | |
100 } else*/ { | |
101 while (gtk_text_iter_forward_search(&start, tag, 0, &m_start, | |
102 &m_end, &end)) { | |
103 | |
104 gtk_text_buffer_delete(gtkconv->entry_buffer, &m_start, &m_end); | |
105 gtk_text_buffer_get_selection_bounds(gtkconv->entry_buffer, | |
106 &start, &end); | |
107 } | |
108 } | |
109 } | |
110 | |
111 void | |
112 gaim_gtk_surround(struct gaim_gtk_conversation *gtkconv, | |
113 const char *pre, const char *post) | |
114 { | |
115 GtkTextIter start, end; | |
116 GtkTextMark *mark_start, *mark_end; | |
117 GtkTextBuffer *entry_buffer; | |
118 | |
119 if (gtkconv == NULL || pre == NULL || post == NULL) | |
120 return; | |
121 | |
122 entry_buffer = gtkconv->entry_buffer; | |
123 | |
124 if (gtk_text_buffer_get_selection_bounds(entry_buffer, | |
125 &start, &end)) { | |
126 gaim_gtk_remove_tags(gtkconv, pre); | |
127 gaim_gtk_remove_tags(gtkconv, post); | |
128 | |
129 mark_start = gtk_text_buffer_create_mark(entry_buffer, "m1", | |
130 &start, TRUE); | |
131 mark_end = gtk_text_buffer_create_mark(entry_buffer, "m2", | |
132 &end, FALSE); | |
133 gtk_text_buffer_insert(entry_buffer, &start, pre, -1); | |
134 gtk_text_buffer_get_selection_bounds(entry_buffer, &start, &end); | |
135 gtk_text_buffer_insert(entry_buffer, &end, post, -1); | |
136 gtk_text_buffer_get_iter_at_mark(entry_buffer, &start, mark_start); | |
137 gtk_text_buffer_move_mark_by_name(entry_buffer, "selection_bound", | |
138 &start); | |
139 } else { | |
140 gtk_text_buffer_insert(entry_buffer, &start, pre, -1); | |
141 gtk_text_buffer_insert(entry_buffer, &start, post, -1); | |
142 mark_start = gtk_text_buffer_get_insert(entry_buffer); | |
143 gtk_text_buffer_get_iter_at_mark(entry_buffer, &start, mark_start); | |
144 gtk_text_iter_backward_chars(&start, strlen(post)); | |
145 gtk_text_buffer_place_cursor(entry_buffer, &start); | |
146 } | |
147 | |
148 gtk_widget_grab_focus(gtkconv->entry); | |
149 } | |
150 | |
151 static gboolean | |
152 invert_tags(GtkTextBuffer *buffer, const char *s1, const char *s2, | |
153 gboolean really) | |
154 { | |
155 GtkTextIter start1, start2, end1, end2; | |
156 char *b1, *b2; | |
157 | |
158 if (gtk_text_buffer_get_selection_bounds(buffer, &start1, &end2)) { | |
159 start2 = start1; | |
160 end1 = end2; | |
161 | |
162 if (!gtk_text_iter_forward_chars(&start2, strlen(s1))) | |
163 return FALSE; | |
164 | |
165 if (!gtk_text_iter_backward_chars(&end1, strlen(s2))) | |
166 return FALSE; | |
167 | |
168 b1 = gtk_text_buffer_get_text(buffer, &start1, &start2, FALSE); | |
169 b2 = gtk_text_buffer_get_text(buffer, &end1, &end2, FALSE); | |
170 | |
4793 | 171 if (!g_ascii_strncasecmp(b1, s1, strlen(s1)) && |
172 !g_ascii_strncasecmp(b2, s2, strlen(s2))) { | |
4359 | 173 |
174 if (really) { | |
175 GtkTextMark *m_end1, *m_end2; | |
176 | |
177 m_end1= gtk_text_buffer_create_mark(buffer, "m1", &end1, TRUE); | |
178 m_end2= gtk_text_buffer_create_mark(buffer, "m2", &end2, TRUE); | |
179 | |
180 gtk_text_buffer_delete(buffer, &start1, &start2); | |
181 gtk_text_buffer_get_iter_at_mark(buffer, &end1, m_end1); | |
182 gtk_text_buffer_get_iter_at_mark(buffer, &end2, m_end2); | |
183 gtk_text_buffer_delete(buffer, &end1, &end2); | |
184 gtk_text_buffer_delete_mark(buffer, m_end1); | |
185 gtk_text_buffer_delete_mark(buffer, m_end2); | |
186 } | |
187 | |
188 g_free(b1); | |
189 g_free(b2); | |
190 | |
191 return TRUE; | |
192 } | |
193 | |
194 g_free(b1); | |
195 g_free(b2); | |
196 } | |
197 | |
198 return FALSE; | |
199 } | |
200 | |
201 void | |
202 gaim_gtk_advance_past(struct gaim_gtk_conversation *gtkconv, | |
203 const char *pre, const char *post) | |
204 { | |
205 GtkTextIter current_pos, start, end; | |
206 | |
207 if (invert_tags(gtkconv->entry_buffer, pre, post, TRUE)) | |
208 return; | |
209 | |
210 gtk_text_buffer_get_iter_at_mark(gtkconv->entry_buffer, ¤t_pos, | |
211 gtk_text_buffer_get_insert(gtkconv->entry_buffer)); | |
212 | |
213 if (gtk_text_iter_forward_search(¤t_pos, post, 0, | |
214 &start, &end, NULL)) | |
215 gtk_text_buffer_place_cursor(gtkconv->entry_buffer, &end); | |
216 else | |
217 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, post, -1); | |
218 | |
219 gtk_widget_grab_focus(gtkconv->entry); | |
220 } | |
221 | |
222 void | |
223 gaim_gtk_set_font_face(struct gaim_gtk_conversation *gtkconv, | |
224 const char *font) | |
225 { | |
226 char *pre_fontface; | |
227 | |
228 if (gtkconv == NULL || font == NULL) | |
229 return; | |
230 | |
231 strncpy(gtkconv->fontface, | |
232 (font && *font ? font : DEFAULT_FONT_FACE), | |
233 sizeof(gtkconv->fontface)); | |
234 | |
235 gtkconv->has_font = TRUE; | |
236 | |
237 pre_fontface = g_strconcat("<FONT FACE=\"", | |
238 gtkconv->fontface, "\">", NULL); | |
239 gaim_gtk_surround(gtkconv, pre_fontface, "</FONT>"); | |
240 | |
241 gtk_widget_grab_focus(gtkconv->entry); | |
242 | |
243 g_free(pre_fontface); | |
244 } | |
245 | |
246 static int | |
247 des_save_icon(GtkObject *obj, GdkEvent *e, | |
248 struct gaim_gtk_conversation *gtkconv) | |
249 { | |
250 gtk_widget_destroy(gtkconv->u.im->save_icon); | |
251 gtkconv->u.im->save_icon = NULL; | |
252 | |
253 return TRUE; | |
254 } | |
255 | |
256 static void | |
257 do_save_icon(GtkObject *obj, struct gaim_conversation *c) | |
258 { | |
259 struct gaim_gtk_conversation *gtkconv; | |
260 FILE *file; | |
261 const char *f; | |
262 | |
263 gtkconv = GAIM_GTK_CONVERSATION(c); | |
264 | |
265 f = gtk_file_selection_get_filename( | |
266 GTK_FILE_SELECTION(gtkconv->u.im->save_icon)); | |
267 | |
268 if (file_is_dir(f, gtkconv->u.im->save_icon)) | |
269 return; | |
270 | |
271 if ((file = fopen(f, "w")) != NULL) { | |
272 int len; | |
273 void *data = get_icon_data(gaim_conversation_get_gc(c), | |
274 normalize(gaim_conversation_get_name(c)), | |
275 &len); | |
276 | |
277 if (data) | |
278 fwrite(data, 1, len, file); | |
279 | |
280 fclose(file); | |
281 } else { | |
282 do_error_dialog("Can't save icon file to disk", | |
283 strerror(errno), GAIM_ERROR); | |
284 } | |
285 | |
286 gtk_widget_destroy(gtkconv->u.im->save_icon); | |
287 gtkconv->u.im->save_icon = NULL; | |
288 } | |
289 | |
290 static void | |
291 cancel_save_icon(GtkObject *obj, struct gaim_gtk_conversation *gtkconv) | |
292 { | |
293 gtk_widget_destroy(gtkconv->u.im->save_icon); | |
294 gtkconv->u.im->save_icon = NULL; | |
295 } | |
296 | |
297 | |
298 void | |
299 gaim_gtk_save_icon_dialog(GtkObject *obj, struct gaim_conversation *conv) | |
300 { | |
301 struct gaim_gtk_conversation *gtkconv; | |
302 char buf[BUF_LEN]; | |
303 | |
304 if (conv == NULL || gaim_conversation_get_type(conv) != GAIM_CONV_IM) | |
305 return; | |
306 | |
4398
a8249a5250b6
[gaim-migrate @ 4667]
Christian Hammond <chipx86@chipx86.com>
parents:
4359
diff
changeset
|
307 if (!GAIM_IS_GTK_CONVERSATION(conv)) |
4359 | 308 return; |
309 | |
310 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
311 | |
312 if (gtkconv->u.im->save_icon != NULL) | |
313 { | |
314 gdk_window_raise(gtkconv->u.im->save_icon->window); | |
315 return; | |
316 } | |
317 | |
318 gtkconv->u.im->save_icon = gtk_file_selection_new(_("Gaim - Save Icon")); | |
319 | |
320 gtk_file_selection_hide_fileop_buttons( | |
321 GTK_FILE_SELECTION(gtkconv->u.im->save_icon)); | |
322 | |
323 g_snprintf(buf, BUF_LEN - 1, | |
324 "%s" G_DIR_SEPARATOR_S "%s.icon", | |
325 gaim_home_dir(), gaim_conversation_get_name(conv)); | |
326 | |
327 gtk_file_selection_set_filename( | |
328 GTK_FILE_SELECTION(gtkconv->u.im->save_icon), buf); | |
329 | |
330 g_signal_connect(GTK_OBJECT(gtkconv->u.im->save_icon), "delete_event", | |
331 G_CALLBACK(des_save_icon), gtkconv); | |
332 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(gtkconv->u.im->save_icon)->ok_button), "clicked", | |
333 G_CALLBACK(do_save_icon), conv); | |
334 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(gtkconv->u.im->save_icon)->cancel_button), "clicked", | |
335 G_CALLBACK(cancel_save_icon), gtkconv); | |
336 | |
337 gtk_widget_show(gtkconv->u.im->save_icon); | |
338 } | |
339 | |
340 int | |
341 gaim_gtk_get_dispstyle(GaimConversationType type) | |
342 { | |
343 int dispstyle = 2; | |
344 | |
345 if (type == GAIM_CONV_CHAT) { | |
346 switch (chat_options & (OPT_CHAT_BUTTON_TEXT | OPT_CHAT_BUTTON_XPM)) { | |
347 | |
348 case OPT_CHAT_BUTTON_TEXT: dispstyle = 1; break; | |
349 case OPT_CHAT_BUTTON_XPM: dispstyle = 0; break; | |
350 default: dispstyle = 2; break; /* both/neither */ | |
351 } | |
352 } | |
353 else if (type == GAIM_CONV_IM) { | |
354 switch (im_options & (OPT_IM_BUTTON_TEXT | OPT_IM_BUTTON_XPM)) { | |
355 | |
356 case OPT_IM_BUTTON_TEXT: dispstyle = 1; break; | |
357 case OPT_IM_BUTTON_XPM: dispstyle = 0; break; | |
358 default: dispstyle = 2; break; /* both/neither */ | |
359 } | |
360 } | |
361 | |
362 return dispstyle; | |
363 } | |
364 | |
365 GtkWidget * | |
366 gaim_gtk_change_text(const char *text, GtkWidget *button, | |
367 const char *stock, GaimConversationType type) | |
368 { | |
369 int dispstyle = gaim_gtk_get_dispstyle(type); | |
370 | |
371 if (button != NULL) | |
372 gtk_widget_destroy(button); | |
373 | |
374 button = gaim_pixbuf_button_from_stock((dispstyle == 0 ? NULL : text), | |
375 (dispstyle == 1 ? NULL : stock), | |
376 GAIM_BUTTON_VERTICAL); | |
377 | |
378 gtk_widget_show(button); | |
379 | |
380 return button; | |
381 } | |
382 | |
383 void | |
384 gaim_gtk_toggle_sensitive(GtkWidget *widget, GtkWidget *to_toggle) | |
385 { | |
386 gboolean sensitivity; | |
387 | |
388 if (to_toggle == NULL) | |
389 return; | |
390 | |
391 sensitivity = GTK_WIDGET_IS_SENSITIVE(to_toggle); | |
392 | |
393 gtk_widget_set_sensitive(to_toggle, !sensitivity); | |
394 } | |
395 | |
4687 | 396 void gaim_separator(GtkWidget *menu) |
397 { | |
398 GtkWidget *menuitem; | |
399 | |
400 menuitem = gtk_separator_menu_item_new(); | |
401 gtk_widget_show(menuitem); | |
402 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
403 } |