Mercurial > pidgin
comparison src/gtkconv.c @ 4359:5fb47ec9bfe4
[gaim-migrate @ 4625]
Wow, okay, where to begin with this one ;)
I rewrote the whole conversation backend. It is now core/UI split. Here's
how it works..
Every conversation is represented by a gaim_conversation structure. This
branches out into gaim_im and gaim_chat structures. Every conversation
lives in (well, normally, but it doesn't have to) a gaim_window structure.
This is a _CORE_ representation of a window. There can be multiple
gaim_window structures around.
The gaim_window and gaim_conversation structures have UI-specific operation
structures associated with them. At the moment, the only UI is GTK+, and
this will be for some time. Don't start thinking you can write a QT UI now.
It's just not going to happen.
Everything that is done on a conversation is done through the core API.
This API does core processing and then calls the UI operations for the
rendering and anything else.
Now, what does this give the user?
- Multiple windows.
- Multiple tabs per window.
- Draggable tabs.
- Send As menu is moved to the menubar.
- Menubar for chats.
- Some very cool stuff in the future, like replacing, say, IRC chat windows
with an X-Chat interface, or whatever.
- Later on, customizable window/conversation positioning.
For developers:
- Fully documented API
- Core/UI split
- Variable checking and mostly sane handling of incorrect variables.
- Logical structure to conversations, both core and UI.
- Some very cool stuff in the future, like replacing, say, IRC chat windows
with an X-Chat interface, or whatever.
- Later on, customizable window/conversation positioning.
- Oh yeah, and the beginning of a stock icon system.
Now, there are things that aren't there yet. You will see tabs even if you
have them turned off. This will be fixed in time. Also, the preferences
will change to work with the new structure. I'm starting school in 2 days,
so it may not be done immediately, but hopefully in the next week.
Enjoy!
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Mon, 20 Jan 2003 09:10:23 +0000 |
parents | |
children | c435a29370b8 |
comparison
equal
deleted
inserted
replaced
4358:2b8abf7f9cc1 | 4359:5fb47ec9bfe4 |
---|---|
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 "gtkimhtml.h" | |
49 #include "dnd-hints.h" | |
50 | |
51 static char nick_colors[][8] = { | |
52 "#ba55d3", /* Medium Orchid */ | |
53 "#ee82ee", /* Violet */ | |
54 "#c715b4", /* Medium Violet Red */ | |
55 "#ff69b4", /* Hot Pink */ | |
56 "#ff6347", /* Tomato */ | |
57 "#fa8c00", /* Dark Orange */ | |
58 "#fa8072", /* Salmon */ | |
59 "#b22222", /* Fire Brick */ | |
60 "#f4a460", /* Sandy Brown */ | |
61 "#cd5c5c", /* Indian Red */ | |
62 "#bc8f8f", /* Rosy Brown */ | |
63 "#f0e68c", /* Khaki */ | |
64 "#bdb76b", /* Dark Khaki */ | |
65 "#228b22", /* Forest Green */ | |
66 "#9acd32", /* Yellow Green */ | |
67 "#32cd32", /* Lime Green */ | |
68 "#3cb371", /* Medium Sea Green */ | |
69 "#2e8b57", /* Sea Green */ | |
70 "#8fbc8f", /* Dark Sea Green */ | |
71 "#66cdaa", /* Medium Aquamarine */ | |
72 "#5f9ea0", /* Cadet Blue */ | |
73 "#48d1cc", /* Medium Turquoise */ | |
74 "#00ced1", /* Dark Turquoise */ | |
75 "#4682b4", /* Stell Blue */ | |
76 "#00bfff", /* Deep Sky Blue */ | |
77 "#1690ff", /* Dodger Blue */ | |
78 "#4169ff", /* Royal Blue */ | |
79 "#6a5acd", /* Slate Blue */ | |
80 "#6495ed", /* Cornflower Blue */ | |
81 "#708090", /* Slate gray */ | |
82 "#ffdead", /* Navajo White */ | |
83 }; | |
84 #define NUM_NICK_COLORS (sizeof(nick_colors) / sizeof(*nick_colors)) | |
85 | |
86 #define SCALE(x) \ | |
87 ((gdk_pixbuf_animation_get_width(x) <= 48 && \ | |
88 gdk_pixbuf_animation_get_height(x) <= 48) ? 48 : 50) | |
89 | |
90 struct InviteBuddyInfo | |
91 { | |
92 GtkWidget *window; | |
93 | |
94 GtkWidget *entry; | |
95 GtkWidget *message; | |
96 | |
97 struct gaim_conversation *conv; | |
98 }; | |
99 | |
100 char fontface[128] = { 0 }; | |
101 int fontsize = 3; | |
102 | |
103 static GtkWidget *invite_dialog = NULL; | |
104 #if 0 | |
105 static GtkWidget *invite_entry; | |
106 static GtkWidget *invite_mess; | |
107 #endif | |
108 | |
109 static volatile gboolean state_lock = FALSE; | |
110 | |
111 /* Prototypes. <-- because Paco-Paco hates this comment. */ | |
112 static void check_everything(GtkTextBuffer *buffer); | |
113 static void quiet_set(GtkWidget *tb, gboolean active); | |
114 static void move_next_tab(struct gaim_conversation *conv); | |
115 static void do_bold(GtkWidget *bold, struct gaim_gtk_conversation *gtkconv); | |
116 static void do_italic(GtkWidget *italic, struct gaim_gtk_conversation *gtkconv); | |
117 static void do_underline(GtkWidget *underline, struct gaim_gtk_conversation *gtkconv); | |
118 static void do_small(GtkWidget *small, struct gaim_gtk_conversation *gtkconv); | |
119 static void do_normal(GtkWidget *small, struct gaim_gtk_conversation *gtkconv); | |
120 static void do_big(GtkWidget *small, struct gaim_gtk_conversation *gtkconv); | |
121 static void toggle_font(GtkWidget *font, struct gaim_conversation *conv); | |
122 static void toggle_fg_color(GtkWidget *color, struct gaim_conversation *conv); | |
123 static void toggle_bg_color(GtkWidget *color, struct gaim_conversation *conv); | |
124 static void got_typing_keypress(struct gaim_conversation *conv, gboolean first); | |
125 static GList *generate_invite_user_names(struct gaim_connection *gc); | |
126 static void add_chat_buddy_common(struct gaim_conversation *conv, | |
127 const char *name, int pos); | |
128 static void tab_complete(struct gaim_conversation *conv); | |
129 static void update_send_as_selection(struct gaim_window *win); | |
130 | |
131 /************************************************************************** | |
132 * Callbacks | |
133 **************************************************************************/ | |
134 static void | |
135 do_insert_image_cb(GObject *obj, GtkWidget *wid) | |
136 { | |
137 struct gaim_conversation *conv; | |
138 struct gaim_gtk_conversation *gtkconv; | |
139 struct gaim_im *im; | |
140 const char *name; | |
141 const char *filename; | |
142 char *buf; | |
143 struct stat st; | |
144 int id; | |
145 | |
146 conv = g_object_get_data(obj, "user_data"); | |
147 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
148 im = GAIM_IM(conv); | |
149 name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(wid)); | |
150 id = g_slist_length(im->images) + 1; | |
151 | |
152 if (file_is_dir(name, wid)) | |
153 return; | |
154 | |
155 gtk_widget_destroy(wid); | |
156 | |
157 if (!name) | |
158 return; | |
159 | |
160 if (stat(name, &st) != 0) { | |
161 debug_printf("Could not stat %s\n", name); | |
162 return; | |
163 } | |
164 | |
165 filename = name; | |
166 while (strchr(filename, '/')) | |
167 filename = strchr(filename, '/') + 1; | |
168 | |
169 buf = g_strdup_printf("<IMG SRC=\"file://%s\" ID=\"%d\" DATASIZE=\"%d\">", | |
170 filename, id, (int)st.st_size); | |
171 im->images = g_slist_append(im->images, g_strdup(name)); | |
172 gtk_text_buffer_insert_at_cursor(GTK_TEXT_BUFFER(gtkconv->entry_buffer), | |
173 buf, -1); | |
174 g_free(buf); | |
175 } | |
176 | |
177 static gint | |
178 close_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d) | |
179 { | |
180 struct gaim_window *win = (struct gaim_window *)d; | |
181 | |
182 gaim_window_destroy(win); | |
183 } | |
184 | |
185 static gint | |
186 close_conv_cb(GtkWidget *w, gpointer d) | |
187 { | |
188 struct gaim_conversation *conv = (struct gaim_conversation *)d; | |
189 | |
190 gaim_conversation_destroy(conv); | |
191 } | |
192 | |
193 static void | |
194 insert_image_cb(GtkWidget *save, struct gaim_conversation *conv) | |
195 { | |
196 struct gaim_gtk_conversation *gtkconv; | |
197 char buf[BUF_LONG]; | |
198 GtkWidget *window; | |
199 | |
200 if (gaim_gtk_is_state_locked()) | |
201 return; | |
202 | |
203 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
204 | |
205 window = gtk_file_selection_new(_("Gaim - Insert Image")); | |
206 g_snprintf(buf, sizeof(buf), "%s" G_DIR_SEPARATOR_S, gaim_home_dir()); | |
207 gtk_file_selection_set_filename(GTK_FILE_SELECTION(window), buf); | |
208 | |
209 g_object_set_data(G_OBJECT(GTK_FILE_SELECTION(window)->ok_button), | |
210 "user_data", conv); | |
211 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(window)->ok_button), | |
212 "clicked", G_CALLBACK(do_insert_image_cb), window); | |
213 g_signal_connect_swapped( | |
214 G_OBJECT(GTK_FILE_SELECTION(window)->cancel_button), | |
215 "clicked", G_CALLBACK(gtk_widget_destroy), window); | |
216 | |
217 gtk_widget_show(window); | |
218 | |
219 gaim_gtk_set_state_lock(TRUE); | |
220 gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(gtkconv->toolbar.image), | |
221 FALSE); | |
222 gaim_gtk_set_state_lock(FALSE); | |
223 } | |
224 | |
225 static void | |
226 insert_link_cb(GtkWidget *w, struct gaim_conversation *conv) | |
227 { | |
228 struct gaim_gtk_conversation *gtkconv; | |
229 | |
230 if (gaim_gtk_is_state_locked()) | |
231 return; | |
232 | |
233 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
234 | |
235 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtkconv->toolbar.link))) | |
236 show_insert_link(gtkconv->toolbar.link, conv); | |
237 else if (gtkconv->dialogs.link) | |
238 cancel_link(gtkconv->toolbar.link, conv); | |
239 else | |
240 gaim_gtk_advance_past(gtkconv, "<A HREF>", "</A>"); | |
241 | |
242 gtk_widget_grab_focus(gtkconv->entry); | |
243 } | |
244 | |
245 static void | |
246 insert_smiley_cb(GtkWidget *smiley, struct gaim_conversation *conv) | |
247 { | |
248 struct gaim_gtk_conversation *gtkconv; | |
249 | |
250 if (gaim_gtk_is_state_locked()) | |
251 return; | |
252 | |
253 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
254 | |
255 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(smiley))) | |
256 show_smiley_dialog(conv, smiley); | |
257 else if (gtkconv->dialogs.smiley) | |
258 close_smiley_dialog(smiley, conv); | |
259 | |
260 gtk_widget_grab_focus(gtkconv->entry); | |
261 } | |
262 | |
263 static void | |
264 menu_save_as_cb(gpointer data, guint action, GtkWidget *widget) | |
265 { | |
266 struct gaim_window *win = (struct gaim_window *)data; | |
267 | |
268 save_convo(NULL, gaim_window_get_active_conversation(win)); | |
269 } | |
270 | |
271 static void | |
272 menu_view_history_cb(gpointer data, guint action, GtkWidget *widget) | |
273 { | |
274 struct gaim_window *win = (struct gaim_window *)data; | |
275 | |
276 conv_show_log(NULL, gaim_window_get_active_conversation(win)); | |
277 } | |
278 static void | |
279 menu_insert_link_cb(gpointer data, guint action, GtkWidget *widget) | |
280 { | |
281 struct gaim_window *win = (struct gaim_window *)data; | |
282 struct gaim_conversation *conv; | |
283 struct gaim_gtk_conversation *gtkconv; | |
284 | |
285 conv = gaim_window_get_active_conversation(win); | |
286 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
287 | |
288 show_insert_link(gtkconv->toolbar.link, conv); | |
289 } | |
290 | |
291 static void | |
292 menu_insert_image_cb(gpointer data, guint action, GtkWidget *widget) | |
293 { | |
294 struct gaim_window *win = (struct gaim_window *)data; | |
295 | |
296 insert_image_cb(NULL, gaim_window_get_active_conversation(win)); | |
297 } | |
298 | |
299 static void | |
300 menu_close_conv_cb(gpointer data, guint action, GtkWidget *widget) | |
301 { | |
302 struct gaim_window *win = (struct gaim_window *)data; | |
303 | |
304 close_conv_cb(NULL, gaim_window_get_active_conversation(win)); | |
305 } | |
306 | |
307 static void | |
308 menu_logging_cb(gpointer data, guint action, GtkWidget *widget) | |
309 { | |
310 struct gaim_window *win = (struct gaim_window *)data; | |
311 struct gaim_conversation *conv; | |
312 | |
313 if (gaim_gtk_is_state_locked()) | |
314 return; | |
315 | |
316 conv = gaim_window_get_active_conversation(win); | |
317 | |
318 gaim_conversation_set_logging(conv, !gaim_conversation_is_logging(conv)); | |
319 } | |
320 | |
321 static void | |
322 menu_sounds_cb(gpointer data, guint action, GtkWidget *widget) | |
323 { | |
324 struct gaim_window *win = (struct gaim_window *)data; | |
325 struct gaim_conversation *conv; | |
326 struct gaim_gtk_conversation *gtkconv; | |
327 | |
328 if (gaim_gtk_is_state_locked()) | |
329 return; | |
330 | |
331 conv = gaim_window_get_active_conversation(win); | |
332 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
333 | |
334 gtkconv->make_sound = !gtkconv->make_sound; | |
335 } | |
336 | |
337 static gboolean | |
338 entry_key_pressed_cb_1(GtkTextBuffer *buffer) | |
339 { | |
340 check_everything(buffer); | |
341 | |
342 return FALSE; | |
343 } | |
344 | |
345 static void | |
346 send_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
347 { | |
348 struct gaim_gtk_conversation *gtkconv; | |
349 char *buf, *buf2; | |
350 GtkTextIter start_iter, end_iter; | |
351 int limit; | |
352 | |
353 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
354 | |
355 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, &start_iter); | |
356 gtk_text_buffer_get_end_iter(gtkconv->entry_buffer, &end_iter); | |
357 buf2 = gtk_text_buffer_get_text(gtkconv->entry_buffer, | |
358 &start_iter, &end_iter, FALSE); | |
359 | |
360 quiet_set(gtkconv->toolbar.bold, FALSE); | |
361 quiet_set(gtkconv->toolbar.italic, FALSE); | |
362 quiet_set(gtkconv->toolbar.underline, FALSE); | |
363 quiet_set(gtkconv->toolbar.normal_size, FALSE); | |
364 quiet_set(gtkconv->toolbar.fgcolor, FALSE); | |
365 quiet_set(gtkconv->toolbar.bgcolor, FALSE); | |
366 quiet_set(gtkconv->toolbar.link, FALSE); | |
367 | |
368 gtk_widget_grab_focus(gtkconv->entry); | |
369 | |
370 limit = 32 * 1024; /* This will be done again in gaim_im_send. *shrug* */ | |
371 | |
372 buf = g_malloc(limit); | |
373 strncpy(buf, buf2, limit); | |
374 | |
375 g_free(buf2); | |
376 | |
377 if (strlen(buf) == 0) { | |
378 g_free(buf); | |
379 | |
380 return; | |
381 } | |
382 | |
383 buf2 = g_malloc(limit); | |
384 | |
385 if (gaim_conversation_get_gc(conv)->flags & OPT_CONN_HTML) { | |
386 if (font_options & OPT_FONT_BOLD) { | |
387 g_snprintf(buf2, limit, "<B>%s</B>", buf); | |
388 strcpy(buf, buf2); | |
389 } | |
390 | |
391 if (font_options & OPT_FONT_ITALIC) { | |
392 g_snprintf(buf2, limit, "<I>%s</I>", buf); | |
393 strcpy(buf, buf2); | |
394 } | |
395 | |
396 if (font_options & OPT_FONT_UNDERLINE) { | |
397 g_snprintf(buf2, limit, "<U>%s</U>", buf); | |
398 strcpy(buf, buf2); | |
399 } | |
400 | |
401 if (font_options & OPT_FONT_STRIKE) { | |
402 g_snprintf(buf2, limit, "<STRIKE>%s</STRIKE>", buf); | |
403 strcpy(buf, buf2); | |
404 } | |
405 | |
406 if ((font_options & OPT_FONT_FACE) || gtkconv->has_font) { | |
407 g_snprintf(buf2, limit, | |
408 "<FONT FACE=\"%s\">%s</FONT>", gtkconv->fontface, buf); | |
409 strcpy(buf, buf2); | |
410 } | |
411 | |
412 if (font_options & OPT_FONT_SIZE) { | |
413 g_snprintf(buf2, limit, | |
414 "<FONT SIZE=\"%d\">%s</FONT>", fontsize, buf); | |
415 strcpy(buf, buf2); | |
416 } | |
417 | |
418 if ((font_options & OPT_FONT_FGCOL) || gtkconv->has_fg) { | |
419 g_snprintf(buf2, limit, | |
420 "<FONT COLOR=\"#%02X%02X%02X\">%s</FONT>", | |
421 gtkconv->fg_color.red / 256, | |
422 gtkconv->fg_color.green / 256, | |
423 gtkconv->fg_color.blue / 256, buf); | |
424 strcpy(buf, buf2); | |
425 } | |
426 | |
427 if ((font_options & OPT_FONT_BGCOL) || gtkconv->has_bg) { | |
428 g_snprintf(buf2, limit, | |
429 "<BODY BGCOLOR=\"#%02X%02X%02X\">%s</BODY>", | |
430 gtkconv->fg_color.red / 256, | |
431 gtkconv->fg_color.green / 256, | |
432 gtkconv->fg_color.blue / 256, buf); | |
433 strcpy(buf, buf2); | |
434 } | |
435 } | |
436 | |
437 g_free(buf2); | |
438 | |
439 if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) | |
440 gaim_im_send(GAIM_IM(conv), buf); | |
441 else | |
442 gaim_chat_send(GAIM_CHAT(conv), buf); | |
443 | |
444 g_free(buf); | |
445 | |
446 gtk_text_buffer_set_text(gtkconv->entry_buffer, "", -1); | |
447 } | |
448 | |
449 static void | |
450 add_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
451 { | |
452 struct gaim_connection *gc; | |
453 struct buddy *b; | |
454 const char *name; | |
455 | |
456 gc = gaim_conversation_get_gc(conv); | |
457 name = gaim_conversation_get_name(conv); | |
458 b = find_buddy(gc->user, name); | |
459 | |
460 if (b != NULL) | |
461 show_confirm_del(gc, (char *)name); | |
462 else if (gc != NULL) | |
463 show_add_buddy(gc, (char *)name, NULL, NULL); | |
464 | |
465 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry); | |
466 } | |
467 | |
468 static void | |
469 info_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
470 { | |
471 struct gaim_gtk_conversation *gtkconv; | |
472 | |
473 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
474 | |
475 if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) { | |
476 struct gaim_gtk_chat_pane *gtkchat; | |
477 GtkTreeIter iter; | |
478 GtkTreeModel *model; | |
479 GtkTreeSelection *sel; | |
480 const char *name; | |
481 | |
482 gtkchat = gtkconv->u.chat; | |
483 | |
484 model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); | |
485 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list)); | |
486 | |
487 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) | |
488 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &name, -1); | |
489 else | |
490 return; | |
491 | |
492 serv_get_info(gaim_conversation_get_gc(conv), (char *)name); | |
493 } | |
494 else { | |
495 serv_get_info(gaim_conversation_get_gc(conv), | |
496 (char *)gaim_conversation_get_name(conv)); | |
497 | |
498 gtk_widget_grab_focus(gtkconv->entry); | |
499 } | |
500 } | |
501 | |
502 static void | |
503 warn_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
504 { | |
505 show_warn_dialog(gaim_conversation_get_gc(conv), | |
506 (char *)gaim_conversation_get_name(conv)); | |
507 | |
508 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry); | |
509 } | |
510 | |
511 static void | |
512 block_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
513 { | |
514 struct gaim_connection *gc; | |
515 | |
516 gc = gaim_conversation_get_gc(conv); | |
517 | |
518 if (gc != NULL) | |
519 show_add_perm(gc, (char *)gaim_conversation_get_name(conv), FALSE); | |
520 | |
521 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry); | |
522 } | |
523 | |
524 void | |
525 im_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
526 { | |
527 struct gaim_conversation *conv2; | |
528 struct gaim_gtk_conversation *gtkconv; | |
529 struct gaim_gtk_chat_pane *gtkchat; | |
530 GtkTreeIter iter; | |
531 GtkTreeModel *model; | |
532 GtkTreeSelection *sel; | |
533 const char *name; | |
534 | |
535 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
536 gtkchat = gtkconv->u.chat; | |
537 | |
538 model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); | |
539 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list)); | |
540 | |
541 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) | |
542 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &name, -1); | |
543 else | |
544 return; | |
545 | |
546 if (*name == '@') name++; | |
547 if (*name == '+') name++; | |
548 | |
549 conv2 = gaim_find_conversation(name); | |
550 | |
551 if (conv2 != NULL) | |
552 gaim_window_raise(gaim_conversation_get_window(conv2)); | |
553 else | |
554 conv2 = gaim_conversation_new(GAIM_CONV_IM, name); | |
555 | |
556 gaim_conversation_set_user(conv2, gaim_conversation_get_user(conv)); | |
557 } | |
558 | |
559 static void | |
560 ignore_cb(GtkWidget *w, struct gaim_conversation *conv) | |
561 { | |
562 struct gaim_gtk_conversation *gtkconv; | |
563 struct gaim_gtk_chat_pane *gtkchat; | |
564 struct gaim_chat *chat; | |
565 GtkTreeIter iter; | |
566 GtkTreeModel *model; | |
567 GtkTreeSelection *sel; | |
568 const char *name; | |
569 int pos; | |
570 | |
571 chat = GAIM_CHAT(conv); | |
572 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
573 gtkchat = gtkconv->u.chat; | |
574 | |
575 model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); | |
576 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list)); | |
577 | |
578 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) { | |
579 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &name, -1); | |
580 gtk_list_store_remove(GTK_LIST_STORE(model), &iter); | |
581 } | |
582 else | |
583 return; | |
584 | |
585 pos = g_list_index(gaim_chat_get_users(chat), name); | |
586 | |
587 if (gaim_chat_is_user_ignored(chat, name)) | |
588 gaim_chat_unignore(chat, name); | |
589 else | |
590 gaim_chat_ignore(chat, name); | |
591 | |
592 add_chat_buddy_common(conv, name, pos); | |
593 } | |
594 | |
595 static void | |
596 menu_im_cb(GtkWidget *w, struct gaim_conversation *conv) | |
597 { | |
598 const char *who; | |
599 struct gaim_conversation *conv2; | |
600 | |
601 who = g_object_get_data(G_OBJECT(w), "user_data"); | |
602 | |
603 conv2 = gaim_find_conversation(who); | |
604 | |
605 if (conv2 != NULL) | |
606 gaim_window_show(gaim_conversation_get_window(conv2)); | |
607 else { | |
608 conv2 = gaim_conversation_new(GAIM_CONV_IM, who); | |
609 gaim_conversation_set_user(conv2, gaim_conversation_get_user(conv)); | |
610 } | |
611 } | |
612 | |
613 static void | |
614 menu_info_cb(GtkWidget *w, struct gaim_conversation *conv) | |
615 { | |
616 struct gaim_connection *gc; | |
617 char *who; | |
618 | |
619 gc = gaim_conversation_get_gc(conv); | |
620 who = g_object_get_data(G_OBJECT(w), "user_data"); | |
621 | |
622 if (gc != NULL) { | |
623 /* | |
624 * If there are special needs for getting info on users in | |
625 * buddy chat "rooms"... | |
626 */ | |
627 if (gc->prpl->get_cb_info != NULL) | |
628 gc->prpl->get_cb_info(gc, gaim_chat_get_id(GAIM_CHAT(conv)), who); | |
629 else | |
630 gc->prpl->get_info(gc, who); | |
631 } | |
632 } | |
633 | |
634 static void | |
635 menu_away_cb(GtkWidget *w, struct gaim_conversation *conv) | |
636 { | |
637 struct gaim_connection *gc; | |
638 char *who; | |
639 | |
640 gc = gaim_conversation_get_gc(conv); | |
641 who = g_object_get_data(G_OBJECT(w), "user_data"); | |
642 | |
643 if (gc != NULL) { | |
644 /* | |
645 * May want to expand this to work similarly to menu_info_cb? | |
646 */ | |
647 | |
648 if (gc->prpl->get_cb_away != NULL) | |
649 gc->prpl->get_cb_away(gc, gaim_chat_get_id(GAIM_CHAT(conv)), who); | |
650 } | |
651 } | |
652 | |
653 static void | |
654 menu_add_cb(GtkWidget *w, struct gaim_conversation *conv) | |
655 { | |
656 struct gaim_connection *gc; | |
657 struct buddy *b; | |
658 char *name; | |
659 | |
660 gc = gaim_conversation_get_gc(conv); | |
661 name = g_object_get_data(G_OBJECT(w), "user_data"); | |
662 b = find_buddy(gc->user, name); | |
663 | |
664 if (b != NULL) | |
665 show_confirm_del(gc, name); | |
666 else if (gc != NULL) | |
667 show_add_buddy(gc, name, NULL, NULL); | |
668 | |
669 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry); | |
670 } | |
671 | |
672 static gint | |
673 right_click_chat_cb(GtkWidget *widget, GdkEventButton *event, | |
674 struct gaim_conversation *conv) | |
675 { | |
676 struct gaim_gtk_conversation *gtkconv; | |
677 struct gaim_gtk_chat_pane *gtkchat; | |
678 struct gaim_connection *gc; | |
679 struct aim_user *user; | |
680 GtkTreePath *path; | |
681 GtkTreeIter iter; | |
682 GtkTreeModel *model; | |
683 GtkTreeViewColumn *column; | |
684 gchar *who; | |
685 int x, y; | |
686 | |
687 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
688 gtkchat = gtkconv->u.chat; | |
689 user = gaim_conversation_get_user(conv); | |
690 gc = user->gc; | |
691 | |
692 model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); | |
693 | |
694 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(gtkchat->list), | |
695 event->x, event->y, &path, &column, &x, &y); | |
696 | |
697 if (path == NULL) | |
698 return FALSE; | |
699 | |
700 gtk_tree_selection_select_path(GTK_TREE_SELECTION( | |
701 gtk_tree_view_get_selection(GTK_TREE_VIEW(gtkchat->list))), path); | |
702 | |
703 gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path); | |
704 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &who, -1); | |
705 | |
706 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS) { | |
707 struct gaim_conversation *c; | |
708 | |
709 if ((c = gaim_find_conversation(who)) == NULL) | |
710 c = gaim_conversation_new(GAIM_CONV_IM, who); | |
711 | |
712 gaim_conversation_set_user(c, user); | |
713 } | |
714 else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { | |
715 static GtkWidget *menu = NULL; | |
716 GtkWidget *button; | |
717 | |
718 /* | |
719 * If a menu already exists, destroy it before creating a new one, | |
720 * thus freeing-up the memory it occupied. | |
721 */ | |
722 | |
723 if (menu) | |
724 gtk_widget_destroy(menu); | |
725 | |
726 menu = gtk_menu_new(); | |
727 | |
728 button = gtk_menu_item_new_with_label(_("IM")); | |
729 g_signal_connect(G_OBJECT(button), "activate", | |
730 G_CALLBACK(menu_im_cb), conv); | |
731 g_object_set_data(G_OBJECT(button), "user_data", who); | |
732 gtk_menu_append(GTK_MENU(menu), button); | |
733 gtk_widget_show(button); | |
734 | |
735 if (gaim_chat_is_user_ignored(GAIM_CHAT(conv), who)) | |
736 button = gtk_menu_item_new_with_label(_("Un-Ignore")); | |
737 else | |
738 button = gtk_menu_item_new_with_label(_("Ignore")); | |
739 | |
740 g_signal_connect(G_OBJECT(button), "activate", | |
741 G_CALLBACK(ignore_cb), conv); | |
742 g_object_set_data(G_OBJECT(button), "user_data", who); | |
743 gtk_menu_append(GTK_MENU(menu), button); | |
744 gtk_widget_show(button); | |
745 | |
746 if (gc && gc->prpl->get_info) { | |
747 button = gtk_menu_item_new_with_label(_("Info")); | |
748 g_signal_connect(G_OBJECT(button), "activate", | |
749 G_CALLBACK(menu_info_cb), conv); | |
750 g_object_set_data(G_OBJECT(button), "user_data", who); | |
751 gtk_menu_append(GTK_MENU(menu), button); | |
752 gtk_widget_show(button); | |
753 } | |
754 | |
755 if (gc && gc->prpl->get_cb_away) { | |
756 button = gtk_menu_item_new_with_label(_("Get Away Msg")); | |
757 g_signal_connect(G_OBJECT(button), "activate", | |
758 G_CALLBACK(menu_away_cb), conv); | |
759 g_object_set_data(G_OBJECT(button), "user_data", who); | |
760 gtk_menu_append(GTK_MENU(menu), button); | |
761 gtk_widget_show(button); | |
762 } | |
763 | |
764 /* Added by Jonas <jonas@birme.se> */ | |
765 if (gc) { | |
766 if (find_buddy(gc->user, who)) | |
767 button = gtk_menu_item_new_with_label(_("Remove")); | |
768 else | |
769 button = gtk_menu_item_new_with_label(_("Add")); | |
770 | |
771 g_signal_connect(G_OBJECT(button), "activate", | |
772 G_CALLBACK(menu_add_cb), conv); | |
773 | |
774 g_object_set_data(G_OBJECT(button), "user_data", who); | |
775 gtk_menu_append(GTK_MENU(menu), button); | |
776 gtk_widget_show(button); | |
777 } | |
778 /* End Jonas */ | |
779 | |
780 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, | |
781 event->button, event->time); | |
782 } | |
783 | |
784 return TRUE; | |
785 } | |
786 | |
787 static void | |
788 do_invite(GtkWidget *w, int resp, struct InviteBuddyInfo *info) | |
789 { | |
790 const char *buddy, *message; | |
791 struct gaim_gtk_conversation *gtkconv; | |
792 | |
793 gtkconv = GAIM_GTK_CONVERSATION(info->conv); | |
794 | |
795 if (resp == GTK_RESPONSE_OK) { | |
796 buddy = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(info->entry)->entry)); | |
797 message = gtk_entry_get_text(GTK_ENTRY(info->message)); | |
798 | |
799 if (!g_strcasecmp(buddy, "")) { | |
800 g_free(info); | |
801 | |
802 return; | |
803 } | |
804 | |
805 serv_chat_invite(gaim_conversation_get_gc(info->conv), | |
806 gaim_chat_get_id(GAIM_CHAT(info->conv)), | |
807 message, buddy); | |
808 } | |
809 | |
810 gtk_widget_destroy(invite_dialog); | |
811 invite_dialog = NULL; | |
812 | |
813 g_free(info); | |
814 } | |
815 | |
816 static void | |
817 invite_cb(GtkWidget *widget, struct gaim_conversation *conv) | |
818 { | |
819 struct InviteBuddyInfo *info = NULL; | |
820 | |
821 if (invite_dialog == NULL) { | |
822 struct gaim_connection *gc; | |
823 struct gaim_window *win; | |
824 struct gaim_gtk_window *gtkwin; | |
825 char *filename; | |
826 GtkWidget *label; | |
827 GtkWidget *vbox, *hbox; | |
828 GtkWidget *table; | |
829 GtkWidget *img; | |
830 | |
831 filename = g_build_filename(DATADIR, "pixmaps", "gaim", "dialogs", | |
832 "gaim_question.png", NULL); | |
833 | |
834 img = gtk_image_new_from_file(filename); | |
835 | |
836 g_free(filename); | |
837 | |
838 | |
839 info = g_new0(struct InviteBuddyInfo, 1); | |
840 info->conv = conv; | |
841 | |
842 gc = gaim_conversation_get_gc(conv); | |
843 win = gaim_conversation_get_window(conv); | |
844 gtkwin = GAIM_GTK_WINDOW(win); | |
845 | |
846 /* Create the new dialog. */ | |
847 invite_dialog = gtk_dialog_new_with_buttons( | |
848 _("Gaim - Invite Buddy Into Chat Room"), | |
849 GTK_WINDOW(gtkwin->window), | |
850 GTK_DIALOG_MODAL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
851 GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); | |
852 | |
853 gtk_dialog_set_default_response(GTK_DIALOG(invite_dialog), | |
854 GTK_RESPONSE_OK); | |
855 gtk_container_set_border_width(GTK_CONTAINER(invite_dialog), 6); | |
856 gtk_window_set_resizable(GTK_WINDOW(invite_dialog), FALSE); | |
857 gtk_dialog_set_has_separator(GTK_DIALOG(invite_dialog), FALSE); | |
858 | |
859 /* Setup the outside spacing. */ | |
860 vbox = GTK_DIALOG(invite_dialog)->vbox; | |
861 | |
862 gtk_box_set_spacing(GTK_BOX(vbox), 12); | |
863 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6); | |
864 | |
865 /* Setup the inner hbox and put the dialog's icon in it. */ | |
866 hbox = gtk_hbox_new(FALSE, 12); | |
867 gtk_container_add(GTK_CONTAINER(vbox), hbox); | |
868 gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); | |
869 gtk_misc_set_alignment(GTK_MISC(img), 0, 0); | |
870 | |
871 /* Setup the right vbox. */ | |
872 vbox = gtk_vbox_new(FALSE, 0); | |
873 gtk_container_add(GTK_CONTAINER(hbox), vbox); | |
874 | |
875 /* Put our happy label in it. */ | |
876 label = gtk_label_new(_("Please enter the name of the user you wish " | |
877 "to invite, along with an optional invite " | |
878 "message.")); | |
879 gtk_widget_set_size_request(label, 350, -1); | |
880 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); | |
881 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); | |
882 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0); | |
883 | |
884 /* hbox for the table, and to give it some spacing on the left. */ | |
885 hbox = gtk_hbox_new(FALSE, 6); | |
886 gtk_container_add(GTK_CONTAINER(vbox), hbox); | |
887 | |
888 /* Setup the table we're going to use to lay stuff out. */ | |
889 table = gtk_table_new(2, 2, FALSE); | |
890 gtk_table_set_row_spacings(GTK_TABLE(table), 6); | |
891 gtk_table_set_col_spacings(GTK_TABLE(table), 6); | |
892 gtk_container_set_border_width(GTK_CONTAINER(table), 12); | |
893 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0); | |
894 | |
895 /* Now the Buddy label */ | |
896 label = gtk_label_new(NULL); | |
897 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Buddy:")); | |
898 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); | |
899 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); | |
900 | |
901 /* Now the Buddy drop-down entry field. */ | |
902 info->entry = gtk_combo_new(); | |
903 gtk_combo_set_case_sensitive(GTK_COMBO(info->entry), FALSE); | |
904 gtk_entry_set_activates_default( | |
905 GTK_ENTRY(GTK_COMBO(info->entry)->entry), TRUE); | |
906 | |
907 gtk_table_attach_defaults(GTK_TABLE(table), info->entry, 1, 2, 0, 1); | |
908 gtk_label_set_mnemonic_widget(GTK_LABEL(label), info->entry); | |
909 | |
910 /* Fill in the names. */ | |
911 gtk_combo_set_popdown_strings(GTK_COMBO(info->entry), | |
912 generate_invite_user_names(gc)); | |
913 | |
914 | |
915 /* Now the label for "Message" */ | |
916 label = gtk_label_new(NULL); | |
917 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), _("_Message:")); | |
918 gtk_misc_set_alignment(GTK_MISC(label), 0, 0); | |
919 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2); | |
920 | |
921 | |
922 /* And finally, the Message entry field. */ | |
923 info->message = gtk_entry_new(); | |
924 gtk_entry_set_activates_default(GTK_ENTRY(info->message), TRUE); | |
925 | |
926 gtk_table_attach_defaults(GTK_TABLE(table), info->message, 1, 2, 1, 2); | |
927 gtk_label_set_mnemonic_widget(GTK_LABEL(label), info->message); | |
928 | |
929 /* Connect the signals. */ | |
930 g_signal_connect(G_OBJECT(invite_dialog), "response", | |
931 G_CALLBACK(do_invite), info); | |
932 } | |
933 | |
934 gtk_widget_show_all(invite_dialog); | |
935 | |
936 if (info != NULL) | |
937 gtk_widget_grab_focus(GTK_COMBO(info->entry)->entry); | |
938 } | |
939 | |
940 static gboolean | |
941 entry_key_pressed_cb_2(GtkWidget *entry, GdkEventKey *event, gpointer data) | |
942 { | |
943 struct gaim_window *win; | |
944 struct gaim_conversation *conv; | |
945 struct gaim_gtk_conversation *gtkconv; | |
946 | |
947 conv = (struct gaim_conversation *)data; | |
948 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
949 win = gaim_conversation_get_window(conv); | |
950 | |
951 if (event->keyval == GDK_Escape) { | |
952 if (convo_options & OPT_CONVO_ESC_CAN_CLOSE) { | |
953 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
954 gaim_conversation_destroy(conv); | |
955 } | |
956 } | |
957 else if (event->keyval == GDK_Page_Up) { | |
958 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
959 | |
960 if (!(event->state & GDK_CONTROL_MASK)) | |
961 gtk_imhtml_page_up(GTK_IMHTML(gtkconv->imhtml)); | |
962 } | |
963 else if (event->keyval == GDK_Page_Down) { | |
964 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
965 | |
966 if (!(event->state & GDK_CONTROL_MASK)) | |
967 gtk_imhtml_page_down(GTK_IMHTML(gtkconv->imhtml)); | |
968 } | |
969 else if ((event->keyval == GDK_F2) && | |
970 (convo_options & OPT_CONVO_F2_TOGGLES)) { | |
971 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), | |
972 !GTK_IMHTML(gtkconv->imhtml)->comments); | |
973 } | |
974 else if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) { | |
975 if ((event->state & GDK_CONTROL_MASK) && | |
976 (convo_options & OPT_CONVO_CTL_ENTER)) { | |
977 | |
978 send_cb(NULL, conv); | |
979 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
980 | |
981 return TRUE; | |
982 } | |
983 else if (!(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) && | |
984 (convo_options & OPT_CONVO_ENTER_SENDS)) { | |
985 | |
986 send_cb(NULL, conv); | |
987 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
988 | |
989 return TRUE; | |
990 } | |
991 | |
992 return FALSE; | |
993 } | |
994 else if ((event->state & GDK_CONTROL_MASK) && (event->keyval == 'm')) { | |
995 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
996 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, "\n", 1); | |
997 } | |
998 else if (event->state & GDK_CONTROL_MASK) { | |
999 switch (event->keyval) { | |
1000 case GDK_Up: | |
1001 if (!conv->send_history) | |
1002 break; | |
1003 | |
1004 if (!conv->send_history->prev) { | |
1005 GtkTextIter start, end; | |
1006 | |
1007 if (conv->send_history->data) | |
1008 g_free(conv->send_history->data); | |
1009 | |
1010 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, | |
1011 &start); | |
1012 gtk_text_buffer_get_end_iter(gtkconv->entry_buffer, &end); | |
1013 | |
1014 conv->send_history->data = | |
1015 gtk_text_buffer_get_text(gtkconv->entry_buffer, | |
1016 &start, &end, FALSE); | |
1017 } | |
1018 | |
1019 if (conv->send_history->next && | |
1020 conv->send_history->next->data) { | |
1021 | |
1022 conv->send_history = conv->send_history->next; | |
1023 gtk_text_buffer_set_text(gtkconv->entry_buffer, | |
1024 conv->send_history->data, -1); | |
1025 } | |
1026 | |
1027 break; | |
1028 | |
1029 case GDK_Down: | |
1030 if (!conv->send_history) | |
1031 break; | |
1032 | |
1033 if (conv->send_history->prev) { | |
1034 conv->send_history = conv->send_history->prev; | |
1035 | |
1036 if (conv->send_history->data) | |
1037 gtk_text_buffer_set_text(gtkconv->entry_buffer, | |
1038 conv->send_history->data, -1); | |
1039 } | |
1040 | |
1041 break; | |
1042 } | |
1043 | |
1044 if (convo_options & OPT_CONVO_CTL_CHARS) { | |
1045 switch (event->keyval) { | |
1046 case 'i': | |
1047 case 'I': | |
1048 quiet_set(gtkconv->toolbar.italic, | |
1049 !gtk_toggle_button_get_active( | |
1050 GTK_TOGGLE_BUTTON(gtkconv->toolbar.italic))); | |
1051 | |
1052 do_italic(gtkconv->toolbar.italic, gtkconv); | |
1053 | |
1054 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1055 "key_press_event"); | |
1056 break; | |
1057 | |
1058 case 'u': /* ctrl-u is GDK_Clear, which clears the line. */ | |
1059 case 'U': | |
1060 quiet_set(gtkconv->toolbar.underline, | |
1061 !gtk_toggle_button_get_active( | |
1062 GTK_TOGGLE_BUTTON(gtkconv->toolbar.underline))); | |
1063 | |
1064 do_underline(gtkconv->toolbar.underline, gtkconv); | |
1065 | |
1066 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1067 "key_press_event"); | |
1068 break; | |
1069 | |
1070 case 'b': /* ctrl-b is GDK_Left, which moves backwards. */ | |
1071 case 'B': | |
1072 quiet_set(gtkconv->toolbar.bold, | |
1073 !gtk_toggle_button_get_active( | |
1074 GTK_TOGGLE_BUTTON(gtkconv->toolbar.bold))); | |
1075 | |
1076 do_bold(gtkconv->toolbar.bold, gtkconv); | |
1077 | |
1078 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1079 "key_press_event"); | |
1080 break; | |
1081 | |
1082 case '-': | |
1083 do_small(NULL, gtkconv); | |
1084 | |
1085 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1086 "key_press_event"); | |
1087 break; | |
1088 | |
1089 case '=': | |
1090 case '+': | |
1091 do_big(NULL, gtkconv); | |
1092 | |
1093 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1094 "key_press_event"); | |
1095 break; | |
1096 | |
1097 case '0': | |
1098 do_normal(NULL, gtkconv); | |
1099 | |
1100 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1101 "key_press_event"); | |
1102 break; | |
1103 | |
1104 case 'f': | |
1105 case 'F': | |
1106 quiet_set(gtkconv->toolbar.normal_size, | |
1107 !gtk_toggle_button_get_active( | |
1108 GTK_TOGGLE_BUTTON(gtkconv->toolbar.normal_size))); | |
1109 | |
1110 toggle_font(gtkconv->toolbar.normal_size, conv); | |
1111 | |
1112 g_signal_stop_emission_by_name(G_OBJECT(entry), | |
1113 "key_press_event"); | |
1114 break; | |
1115 } | |
1116 } | |
1117 | |
1118 if (convo_options & OPT_CONVO_CTL_SMILEYS) { | |
1119 char buf[7]; | |
1120 | |
1121 *buf = '\0'; | |
1122 | |
1123 switch (event->keyval) { | |
1124 case '1': strcpy(buf, ":-)"); break; | |
1125 case '2': strcpy(buf, ":-("); break; | |
1126 case '3': strcpy(buf, ";-)"); break; | |
1127 case '4': strcpy(buf, ":-P"); break; | |
1128 case '5': strcpy(buf, "=-O"); break; | |
1129 case '6': strcpy(buf, ":-*"); break; | |
1130 case '7': strcpy(buf, ">:o"); break; | |
1131 case '8': strcpy(buf, "8-)"); break; | |
1132 case '!': strcpy(buf, ":-$"); break; | |
1133 case '@': strcpy(buf, ":-!"); break; | |
1134 case '#': strcpy(buf, ":-["); break; | |
1135 case '$': strcpy(buf, "O:-)"); break; | |
1136 case '%': strcpy(buf, ":-/"); break; | |
1137 case '^': strcpy(buf, ":'("); break; | |
1138 case '&': strcpy(buf, ":-X"); break; | |
1139 case '*': strcpy(buf, ":-D"); break; | |
1140 default: break; | |
1141 } | |
1142 | |
1143 if (*buf) { | |
1144 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, | |
1145 buf, -1); | |
1146 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1147 } | |
1148 } | |
1149 | |
1150 if (event->keyval == 'l') { | |
1151 gtk_imhtml_clear(GTK_IMHTML(gtkconv->imhtml)); | |
1152 g_string_free(conv->history, TRUE); | |
1153 conv->history = g_string_new(""); | |
1154 } | |
1155 else if ((event->keyval == 'w') && | |
1156 (convo_options & OPT_CONVO_CTL_W_CLOSES)) { | |
1157 | |
1158 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1159 gaim_conversation_destroy(conv); | |
1160 return TRUE; | |
1161 } | |
1162 else if (event->keyval == 'n') { | |
1163 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1164 | |
1165 show_im_dialog(); | |
1166 } | |
1167 else if (event->keyval == 'z') { | |
1168 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1169 | |
1170 #ifdef _WIN32 | |
1171 XIconifyWindow(GDK_DISPLAY(), | |
1172 GDK_WINDOW_XWINDOW(gtkwin->window->window), | |
1173 ((_XPrivDisplay)GDK_DISPALY())->default_screen); | |
1174 #endif | |
1175 } | |
1176 else if (event->keyval == '[') { | |
1177 gaim_window_switch_conversation(win, | |
1178 gaim_conversation_get_index(conv) - 1); | |
1179 | |
1180 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1181 } | |
1182 else if (event->keyval == ']') { | |
1183 gaim_window_switch_conversation(win, | |
1184 gaim_conversation_get_index(conv) + 1); | |
1185 | |
1186 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1187 } | |
1188 else if (event->keyval == GDK_Tab) { | |
1189 move_next_tab(conv); | |
1190 | |
1191 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1192 | |
1193 return TRUE; | |
1194 } | |
1195 } | |
1196 else if ((event->keyval == GDK_Tab) && | |
1197 gaim_conversation_get_type(conv) == GAIM_CONV_CHAT && | |
1198 (chat_options & OPT_CHAT_TAB_COMPLETE)) { | |
1199 | |
1200 tab_complete(conv); | |
1201 | |
1202 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1203 | |
1204 return TRUE; | |
1205 } | |
1206 else if ((event->state & GDK_MOD1_MASK) && | |
1207 event->keyval > '0' && event->keyval <= '9') { | |
1208 | |
1209 gaim_window_switch_conversation(win, event->keyval - '1'); | |
1210 | |
1211 g_signal_stop_emission_by_name(G_OBJECT(entry), "key_press_event"); | |
1212 } | |
1213 | |
1214 return FALSE; | |
1215 } | |
1216 | |
1217 /* | |
1218 * NOTE: | |
1219 * This guy just kills a single right click from being propagated any | |
1220 * further. I have no idea *why* we need this, but we do ... It | |
1221 * prevents right clicks on the GtkTextView in a convo dialog from | |
1222 * going all the way down to the notebook. I suspect a bug in | |
1223 * GtkTextView, but I'm not ready to point any fingers yet. | |
1224 */ | |
1225 static gboolean | |
1226 entry_stop_rclick_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) | |
1227 { | |
1228 if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { | |
1229 /* Right single click */ | |
1230 g_signal_stop_emission_by_name(G_OBJECT(widget), "button_press_event"); | |
1231 | |
1232 return TRUE; | |
1233 } | |
1234 | |
1235 return FALSE; | |
1236 } | |
1237 | |
1238 static void | |
1239 menu_conv_sel_send_cb(GObject *m, struct aim_user *user) | |
1240 { | |
1241 struct gaim_window *win = g_object_get_data(m, "user_data"); | |
1242 struct gaim_conversation *conv; | |
1243 | |
1244 if (gaim_gtk_is_state_locked()) | |
1245 return; | |
1246 | |
1247 conv = gaim_window_get_active_conversation(win); | |
1248 | |
1249 gaim_conversation_set_user(conv, user); | |
1250 } | |
1251 | |
1252 static void | |
1253 insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position, | |
1254 gchar *new_text, gint new_text_length, gpointer user_data) | |
1255 { | |
1256 struct gaim_conversation *conv = (struct gaim_conversation *)user_data; | |
1257 | |
1258 if (conv == NULL) | |
1259 return; | |
1260 | |
1261 if (misc_options & OPT_MISC_STEALTH_TYPING) | |
1262 return; | |
1263 | |
1264 got_typing_keypress(conv, (gtk_text_iter_is_start(position) && | |
1265 gtk_text_iter_is_end(position))); | |
1266 } | |
1267 | |
1268 static void | |
1269 delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos, | |
1270 GtkTextIter *end_pos, gpointer user_data) | |
1271 { | |
1272 struct gaim_conversation *conv = (struct gaim_conversation *)user_data; | |
1273 struct gaim_im *im; | |
1274 | |
1275 if (conv == NULL) | |
1276 return; | |
1277 | |
1278 if (misc_options & OPT_MISC_STEALTH_TYPING) | |
1279 return; | |
1280 | |
1281 im = GAIM_IM(conv); | |
1282 | |
1283 if (gtk_text_iter_is_start(start_pos) && gtk_text_iter_is_end(end_pos)) { | |
1284 | |
1285 /* We deleted all the text, so turn off typing. */ | |
1286 if (gaim_im_get_type_again_timeout(im)) | |
1287 gaim_im_stop_type_again_timeout(im); | |
1288 | |
1289 /* XXX The (char *) should go away! Somebody add consts to stuff! */ | |
1290 serv_send_typing(gaim_conversation_get_gc(conv), | |
1291 (char *)gaim_conversation_get_name(conv), | |
1292 NOT_TYPING); | |
1293 } | |
1294 else { | |
1295 /* We're deleting, but not all of it, so it counts as typing. */ | |
1296 got_typing_keypress(conv, FALSE); | |
1297 } | |
1298 } | |
1299 | |
1300 static void | |
1301 notebook_init_grab(struct gaim_gtk_window *gtkwin, GtkWidget *widget) | |
1302 { | |
1303 static GdkCursor *cursor = NULL; | |
1304 | |
1305 gtkwin->in_drag = TRUE; | |
1306 | |
1307 if (gtkwin->drag_leave_signal) { | |
1308 g_signal_handler_disconnect(G_OBJECT(widget), | |
1309 gtkwin->drag_leave_signal); | |
1310 | |
1311 gtkwin->drag_leave_signal = 0; | |
1312 } | |
1313 | |
1314 if (cursor == NULL) | |
1315 cursor = gdk_cursor_new(GDK_FLEUR); | |
1316 | |
1317 /* Grab the pointer */ | |
1318 gtk_grab_add(gtkwin->notebook); | |
1319 gdk_pointer_grab(gtkwin->notebook->window, FALSE, | |
1320 GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, | |
1321 NULL, cursor, GDK_CURRENT_TIME); | |
1322 } | |
1323 | |
1324 static gboolean | |
1325 notebook_motion_cb(GtkWidget *widget, GdkEventButton *e, | |
1326 struct gaim_window *win) | |
1327 { | |
1328 struct gaim_gtk_window *gtkwin; | |
1329 | |
1330 gtkwin = GAIM_GTK_WINDOW(win); | |
1331 | |
1332 /* | |
1333 * Make sure the user moved the mouse far enough for the | |
1334 * drag to be initiated. | |
1335 */ | |
1336 if (gtkwin->in_predrag) { | |
1337 if (e->x_root < gtkwin->drag_min_x || | |
1338 e->x_root >= gtkwin->drag_max_x || | |
1339 e->y_root < gtkwin->drag_min_y || | |
1340 e->y_root >= gtkwin->drag_max_y) { | |
1341 | |
1342 gtkwin->in_predrag = FALSE; | |
1343 notebook_init_grab(gtkwin, widget); | |
1344 } | |
1345 } | |
1346 else { /* Otherwise, draw the arrows. */ | |
1347 struct gaim_window *dest_win; | |
1348 struct gaim_gtk_window *dest_gtkwin; | |
1349 GtkNotebook *dest_notebook; | |
1350 GtkWidget *tab, *last_vis_tab = NULL; | |
1351 gint nb_x, nb_y, page_num, i, last_vis_tab_loc = -1; | |
1352 gint arrow1_x, arrow1_y, arrow2_x, arrow2_y; | |
1353 gboolean horiz_tabs = FALSE, tab_found = FALSE; | |
1354 GList *l; | |
1355 | |
1356 /* Get the window that the cursor is over. */ | |
1357 dest_win = gaim_gtkwin_get_at_xy(e->x_root, e->y_root); | |
1358 | |
1359 if (dest_win == NULL) { | |
1360 dnd_hints_hide_all(); | |
1361 | |
1362 return TRUE; | |
1363 } | |
1364 | |
1365 dest_gtkwin = GAIM_GTK_WINDOW(dest_win); | |
1366 | |
1367 dest_notebook = GTK_NOTEBOOK(dest_gtkwin->notebook); | |
1368 | |
1369 gdk_window_get_origin(GTK_WIDGET(dest_notebook)->window, &nb_x, &nb_y); | |
1370 | |
1371 arrow1_x = arrow2_x = nb_x; | |
1372 arrow1_y = arrow2_y = nb_y; | |
1373 | |
1374 page_num = gaim_gtkconv_get_dest_tab_at_xy(dest_win, | |
1375 e->x_root, e->y_root); | |
1376 | |
1377 if (gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_TOP || | |
1378 gtk_notebook_get_tab_pos(dest_notebook) == GTK_POS_BOTTOM) { | |
1379 | |
1380 horiz_tabs = TRUE; | |
1381 } | |
1382 | |
1383 /* Find out where to put the arrows. */ | |
1384 for (l = gaim_window_get_conversations(dest_win), i = 0; | |
1385 l != NULL; | |
1386 l = l->next, i++) { | |
1387 | |
1388 struct gaim_conversation *conv = l->data; | |
1389 | |
1390 tab = GAIM_GTK_CONVERSATION(conv)->tabby; | |
1391 | |
1392 /* | |
1393 * If this is the correct tab, record the positions | |
1394 * for the arrows. | |
1395 */ | |
1396 if (i == page_num) { | |
1397 if (horiz_tabs) { | |
1398 arrow1_x = arrow2_x = nb_x + tab->allocation.x; | |
1399 arrow1_y = nb_y + tab->allocation.y; | |
1400 arrow2_y = nb_y + tab->allocation.y + | |
1401 tab->allocation.height; | |
1402 } | |
1403 else { | |
1404 arrow1_x = nb_x + tab->allocation.x; | |
1405 arrow2_x = nb_x + tab->allocation.x + | |
1406 tab->allocation.width; | |
1407 arrow1_y = arrow2_y = nb_y + tab->allocation.y; | |
1408 } | |
1409 | |
1410 tab_found = TRUE; | |
1411 break; | |
1412 } | |
1413 else { /* Keep track of the right-most tab that we see. */ | |
1414 if (horiz_tabs && tab->allocation.x > last_vis_tab_loc) { | |
1415 last_vis_tab = tab; | |
1416 last_vis_tab_loc = tab->allocation.x; | |
1417 } | |
1418 else if (!horiz_tabs && tab->allocation.y > last_vis_tab_loc) { | |
1419 last_vis_tab = tab; | |
1420 last_vis_tab_loc = tab->allocation.y; | |
1421 } | |
1422 } | |
1423 } | |
1424 | |
1425 /* | |
1426 * If we didn't find the tab, then we'll just place the | |
1427 * arrows to the right/bottom of the last visible tab. | |
1428 */ | |
1429 if (!tab_found && last_vis_tab) { | |
1430 if (horiz_tabs) { | |
1431 arrow1_x = arrow2_x = nb_x + last_vis_tab->allocation.x + | |
1432 last_vis_tab->allocation.width; | |
1433 arrow1_y = nb_y + last_vis_tab->allocation.y; | |
1434 arrow2_y = nb_y + last_vis_tab->allocation.y + | |
1435 last_vis_tab->allocation.height; | |
1436 } | |
1437 else { | |
1438 arrow1_x = nb_x + last_vis_tab->allocation.x; | |
1439 arrow2_x = nb_x + last_vis_tab->allocation.x + | |
1440 last_vis_tab->allocation.width; | |
1441 arrow1_y = arrow2_y = nb_y + last_vis_tab->allocation.y + | |
1442 last_vis_tab->allocation.height; | |
1443 } | |
1444 } | |
1445 | |
1446 if (horiz_tabs) { | |
1447 dnd_hints_show(HINT_ARROW_DOWN, arrow1_x, arrow1_y); | |
1448 dnd_hints_show(HINT_ARROW_UP, arrow2_x, arrow2_y); | |
1449 } | |
1450 else { | |
1451 dnd_hints_show(HINT_ARROW_RIGHT, arrow1_x, arrow1_y); | |
1452 dnd_hints_show(HINT_ARROW_LEFT, arrow2_x, arrow2_y); | |
1453 } | |
1454 } | |
1455 | |
1456 return TRUE; | |
1457 } | |
1458 | |
1459 static gboolean | |
1460 notebook_leave_cb(GtkWidget *widget, GdkEventCrossing *e, | |
1461 struct gaim_window *win) | |
1462 { | |
1463 struct gaim_gtk_window *gtkwin; | |
1464 | |
1465 gtkwin = GAIM_GTK_WINDOW(win); | |
1466 | |
1467 if (gtkwin->in_drag) | |
1468 return FALSE; | |
1469 | |
1470 if (e->x_root < gtkwin->drag_min_x || | |
1471 e->x_root >= gtkwin->drag_max_x || | |
1472 e->y_root < gtkwin->drag_min_y || | |
1473 e->y_root >= gtkwin->drag_max_y) { | |
1474 | |
1475 gtkwin->in_predrag = FALSE; | |
1476 notebook_init_grab(gtkwin, widget); | |
1477 } | |
1478 | |
1479 return TRUE; | |
1480 } | |
1481 | |
1482 /* | |
1483 * THANK YOU GALEON! | |
1484 */ | |
1485 static gboolean | |
1486 notebook_press_cb(GtkWidget *widget, GdkEventButton *e, | |
1487 struct gaim_window *win) | |
1488 { | |
1489 struct gaim_gtk_window *gtkwin; | |
1490 gint nb_x, nb_y, x_rel, y_rel; | |
1491 GList *l; | |
1492 int tab_clicked; | |
1493 | |
1494 debug_printf("notebook_press_cb\n"); | |
1495 if (e->button != 1 || e->type != GDK_BUTTON_PRESS) | |
1496 return FALSE; | |
1497 | |
1498 gtkwin = GAIM_GTK_WINDOW(win); | |
1499 | |
1500 debug_printf("notebook_press_cb: 1\n"); | |
1501 if (gtkwin->in_drag) { | |
1502 debug_printf("Already in the middle of a window " | |
1503 "drag at tab_press_cb\n"); | |
1504 return FALSE; | |
1505 } | |
1506 | |
1507 /* | |
1508 * Make sure a tab was actually clicked. The arrow buttons | |
1509 * mess things up. | |
1510 */ | |
1511 tab_clicked = gaim_gtkconv_get_tab_at_xy(win, e->x_root, e->y_root); | |
1512 | |
1513 printf("tab_clicked == %d\n", tab_clicked); | |
1514 | |
1515 if (tab_clicked == -1) | |
1516 return FALSE; | |
1517 | |
1518 /* | |
1519 * Get the relative position of the press event, with regards to | |
1520 * the position of the notebook. | |
1521 */ | |
1522 gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y); | |
1523 | |
1524 x_rel = e->x_root - nb_x; | |
1525 y_rel = e->y_root - nb_y; | |
1526 | |
1527 /* Reset the min/max x/y */ | |
1528 gtkwin->drag_min_x = 0; | |
1529 gtkwin->drag_min_y = 0; | |
1530 gtkwin->drag_max_x = 0; | |
1531 gtkwin->drag_max_y = 0; | |
1532 | |
1533 /* Find out which tab was dragged. */ | |
1534 for (l = gaim_window_get_conversations(win); l != NULL; l = l->next) { | |
1535 struct gaim_conversation *conv = l->data; | |
1536 GtkWidget *tab = GAIM_GTK_CONVERSATION(conv)->tabby; | |
1537 | |
1538 debug_printf("Tab: %d\n", gaim_conversation_get_index(conv)); | |
1539 if (!GTK_WIDGET_VISIBLE(tab)) | |
1540 continue; | |
1541 | |
1542 debug_printf("Tab Visible.\n"); | |
1543 if (tab->allocation.x > x_rel || tab->allocation.y > y_rel) | |
1544 break; | |
1545 | |
1546 /* Save the borders of the tab. */ | |
1547 gtkwin->drag_min_x = tab->allocation.x + nb_x; | |
1548 gtkwin->drag_min_y = tab->allocation.y + nb_y; | |
1549 gtkwin->drag_max_x = tab->allocation.width + gtkwin->drag_min_x; | |
1550 gtkwin->drag_max_y = tab->allocation.height + gtkwin->drag_min_y; | |
1551 } | |
1552 | |
1553 debug_printf("notebook_press_cb: 3\n"); | |
1554 | |
1555 /* Make sure the click occurred in the tab. */ | |
1556 if (e->x_root < gtkwin->drag_min_x || | |
1557 e->x_root >= gtkwin->drag_max_x || | |
1558 e->y_root < gtkwin->drag_min_y || | |
1559 e->y_root >= gtkwin->drag_max_y) { | |
1560 | |
1561 debug_printf("Passing this down.\n"); | |
1562 return FALSE; | |
1563 } | |
1564 | |
1565 debug_printf("notebook_press_cb: 4\n"); | |
1566 gtkwin->in_predrag = TRUE; | |
1567 | |
1568 /* Connect the new motion signals. */ | |
1569 gtkwin->drag_motion_signal = | |
1570 g_signal_connect(G_OBJECT(widget), "motion_notify_event", | |
1571 G_CALLBACK(notebook_motion_cb), win); | |
1572 | |
1573 gtkwin->drag_leave_signal = | |
1574 g_signal_connect(G_OBJECT(widget), "leave_notify_event", | |
1575 G_CALLBACK(notebook_leave_cb), win); | |
1576 | |
1577 debug_printf("notebook_press_cb: 5\n"); | |
1578 return FALSE; | |
1579 } | |
1580 | |
1581 static gboolean | |
1582 notebook_release_cb(GtkWidget *widget, GdkEventButton *e, | |
1583 struct gaim_window *win) | |
1584 { | |
1585 struct gaim_window *dest_win; | |
1586 struct gaim_gtk_window *gtkwin; | |
1587 struct gaim_gtk_window *dest_gtkwin; | |
1588 struct gaim_conversation *conv; | |
1589 GtkNotebook *dest_notebook; | |
1590 gint dest_page_num; | |
1591 | |
1592 /* | |
1593 * Don't check to make sure that the event's window matches the | |
1594 * widget's, because we may be getting an event passed on from the | |
1595 * close button. | |
1596 */ | |
1597 if (e->button != 1 && e->type != GDK_BUTTON_RELEASE) | |
1598 return FALSE; | |
1599 | |
1600 if (gdk_pointer_is_grabbed()) { | |
1601 gdk_pointer_ungrab(GDK_CURRENT_TIME); | |
1602 gtk_grab_remove(widget); | |
1603 } | |
1604 | |
1605 gtkwin = GAIM_GTK_WINDOW(win); | |
1606 | |
1607 if (!gtkwin->in_predrag && !gtkwin->in_drag) { | |
1608 printf("Not in predrag.\n"); | |
1609 return TRUE; | |
1610 } | |
1611 | |
1612 /* Disconnect the motion signal. */ | |
1613 if (gtkwin->drag_motion_signal) { | |
1614 g_signal_handler_disconnect(G_OBJECT(widget), | |
1615 gtkwin->drag_motion_signal); | |
1616 | |
1617 gtkwin->drag_motion_signal = 0; | |
1618 } | |
1619 | |
1620 /* | |
1621 * If we're in a pre-drag, we'll also need to disconnect the leave | |
1622 * signal. | |
1623 */ | |
1624 if (gtkwin->in_predrag) { | |
1625 gtkwin->in_predrag = FALSE; | |
1626 | |
1627 if (gtkwin->drag_leave_signal) { | |
1628 g_signal_handler_disconnect(G_OBJECT(widget), | |
1629 gtkwin->drag_leave_signal); | |
1630 | |
1631 gtkwin->drag_leave_signal = 0; | |
1632 } | |
1633 } | |
1634 | |
1635 /* If we're not in drag... */ | |
1636 /* We're perfectly normal people! */ | |
1637 if (!gtkwin->in_drag) { | |
1638 debug_printf("Not in drag.\n"); | |
1639 return FALSE; | |
1640 } | |
1641 | |
1642 gtkwin->in_drag = FALSE; | |
1643 | |
1644 dnd_hints_hide_all(); | |
1645 | |
1646 dest_win = gaim_gtkwin_get_at_xy(e->x_root, e->y_root); | |
1647 dest_gtkwin = GAIM_GTK_WINDOW(dest_win); | |
1648 | |
1649 conv = gaim_window_get_active_conversation(win); | |
1650 | |
1651 if (dest_win == NULL) { | |
1652 if (gaim_window_get_conversation_count(win) < 2) | |
1653 return FALSE; | |
1654 | |
1655 if (gaim_window_get_conversation_count(win) > 1) { | |
1656 /* Make a new window to stick this to. */ | |
1657 struct gaim_window *new_win; | |
1658 | |
1659 new_win = gaim_window_new(); | |
1660 gaim_window_remove_conversation(win, | |
1661 gaim_conversation_get_index(conv)); | |
1662 gaim_window_add_conversation(new_win, conv); | |
1663 gaim_window_show(new_win); | |
1664 } | |
1665 | |
1666 return TRUE; | |
1667 } | |
1668 | |
1669 /* Get the destination notebook. */ | |
1670 dest_notebook = GTK_NOTEBOOK(gtkwin->notebook); | |
1671 | |
1672 /* Get the destination page number. */ | |
1673 dest_page_num = gaim_gtkconv_get_dest_tab_at_xy(dest_win, | |
1674 e->x_root, e->y_root); | |
1675 | |
1676 if (win == dest_win) { | |
1677 gaim_window_move_conversation(win, | |
1678 gaim_conversation_get_index(conv), dest_page_num); | |
1679 } | |
1680 else { | |
1681 size_t pos; | |
1682 | |
1683 gaim_window_remove_conversation(win, | |
1684 gaim_conversation_get_index(conv)); | |
1685 | |
1686 pos = gaim_window_add_conversation(dest_win, conv); | |
1687 | |
1688 gaim_window_move_conversation(dest_win, pos, dest_page_num); | |
1689 | |
1690 gaim_window_switch_conversation(dest_win, dest_page_num); | |
1691 } | |
1692 | |
1693 gtk_widget_grab_focus(GAIM_GTK_CONVERSATION(conv)->entry); | |
1694 | |
1695 debug_printf("release cb returning.\n"); | |
1696 return TRUE; | |
1697 } | |
1698 | |
1699 static void | |
1700 switch_conv_cb(GtkNotebook *notebook, GtkWidget *page, gint page_num, | |
1701 gpointer user_data) | |
1702 { | |
1703 struct gaim_window *win; | |
1704 struct gaim_conversation *conv; | |
1705 struct gaim_gtk_conversation *gtkconv; | |
1706 struct gaim_gtk_window *gtkwin; | |
1707 struct gaim_connection *gc; | |
1708 | |
1709 if (gaim_gtk_is_state_locked()) | |
1710 return; | |
1711 | |
1712 debug_printf("Switching conversation\n"); | |
1713 | |
1714 win = (struct gaim_window *)user_data; | |
1715 | |
1716 conv = gaim_window_get_conversation_at(win, page_num); | |
1717 gc = gaim_conversation_get_gc(conv); | |
1718 gtkwin = GAIM_GTK_WINDOW(win); | |
1719 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
1720 | |
1721 gaim_conversation_set_unseen(conv, GAIM_UNSEEN_NONE); | |
1722 | |
1723 /* Update the menubar */ | |
1724 if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) { | |
1725 gtk_widget_set_sensitive(gtkwin->menu.view_history, TRUE); | |
1726 gtk_widget_set_sensitive(gtkwin->menu.insert_image, | |
1727 (gc && gc->prpl->options & OPT_PROTO_IM_IMAGE)); | |
1728 | |
1729 if (gtkwin->menu.send_as != NULL) | |
1730 update_send_as_selection(win); | |
1731 } | |
1732 else { | |
1733 gtk_widget_set_sensitive(gtkwin->menu.view_history, FALSE); | |
1734 gtk_widget_set_sensitive(gtkwin->menu.insert_image, FALSE); | |
1735 | |
1736 if (gtkwin->menu.send_as != NULL) | |
1737 gtk_widget_hide(gtkwin->menu.send_as); | |
1738 } | |
1739 | |
1740 gaim_gtk_set_state_lock(TRUE); | |
1741 | |
1742 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.logging), | |
1743 gaim_conversation_is_logging(conv)); | |
1744 | |
1745 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtkwin->menu.sounds), | |
1746 gtkconv->make_sound); | |
1747 | |
1748 gaim_gtk_set_state_lock(FALSE); | |
1749 | |
1750 gtk_widget_grab_focus(gtkconv->entry); | |
1751 } | |
1752 | |
1753 /************************************************************************** | |
1754 * Utility functions | |
1755 **************************************************************************/ | |
1756 static void | |
1757 do_bold(GtkWidget *bold, struct gaim_gtk_conversation *gtkconv) | |
1758 { | |
1759 if (gaim_gtk_is_state_locked()) | |
1760 return; | |
1761 | |
1762 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(bold))) | |
1763 gaim_gtk_surround(gtkconv, "<B>", "</B>"); | |
1764 else | |
1765 gaim_gtk_advance_past(gtkconv, "<B>", "</B>"); | |
1766 | |
1767 gtk_widget_grab_focus(gtkconv->entry); | |
1768 } | |
1769 | |
1770 static void | |
1771 do_italic(GtkWidget *italic, struct gaim_gtk_conversation *gtkconv) | |
1772 { | |
1773 if (gaim_gtk_is_state_locked()) | |
1774 return; | |
1775 | |
1776 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(italic))) | |
1777 gaim_gtk_surround(gtkconv, "<I>", "</I>"); | |
1778 else | |
1779 gaim_gtk_advance_past(gtkconv, "<I>", "</I>"); | |
1780 | |
1781 gtk_widget_grab_focus(gtkconv->entry); | |
1782 } | |
1783 | |
1784 static void | |
1785 do_underline(GtkWidget *underline, struct gaim_gtk_conversation *gtkconv) | |
1786 { | |
1787 if (gaim_gtk_is_state_locked()) | |
1788 return; | |
1789 | |
1790 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(underline))) | |
1791 gaim_gtk_surround(gtkconv, "<U>", "</U>"); | |
1792 else | |
1793 gaim_gtk_advance_past(gtkconv, "<U>", "</U>"); | |
1794 | |
1795 gtk_widget_grab_focus(gtkconv->entry); | |
1796 } | |
1797 | |
1798 static void | |
1799 do_small(GtkWidget *small, struct gaim_gtk_conversation *gtkconv) | |
1800 { | |
1801 if (gaim_gtk_is_state_locked()) | |
1802 return; | |
1803 | |
1804 gaim_gtk_surround(gtkconv, "<FONT SIZE=\"1\">", "</FONT>"); | |
1805 | |
1806 gtk_widget_grab_focus(gtkconv->entry); | |
1807 } | |
1808 | |
1809 static void | |
1810 do_normal(GtkWidget *small, struct gaim_gtk_conversation *gtkconv) | |
1811 { | |
1812 if (gaim_gtk_is_state_locked()) | |
1813 return; | |
1814 | |
1815 gaim_gtk_surround(gtkconv, "<FONT SIZE=\"3\">", "</FONT>"); | |
1816 | |
1817 gtk_widget_grab_focus(gtkconv->entry); | |
1818 } | |
1819 | |
1820 static void | |
1821 do_big(GtkWidget *small, struct gaim_gtk_conversation *gtkconv) | |
1822 { | |
1823 if (gaim_gtk_is_state_locked()) | |
1824 return; | |
1825 | |
1826 gaim_gtk_surround(gtkconv, "<FONT SIZE=\"5\">", "</FONT>"); | |
1827 | |
1828 gtk_widget_grab_focus(gtkconv->entry); | |
1829 } | |
1830 | |
1831 static void | |
1832 toggle_font(GtkWidget *font, struct gaim_conversation *conv) | |
1833 { | |
1834 struct gaim_gtk_conversation *gtkconv; | |
1835 | |
1836 if (gaim_gtk_is_state_locked()) | |
1837 return; | |
1838 | |
1839 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
1840 | |
1841 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(font))) | |
1842 show_font_dialog(conv, font); | |
1843 else if (gtkconv->dialogs.fg_color != NULL) | |
1844 cancel_font(font, conv); | |
1845 else | |
1846 gaim_gtk_advance_past(gtkconv, "<FONT FACE>", "</FONT>"); | |
1847 } | |
1848 | |
1849 static void | |
1850 toggle_fg_color(GtkWidget *color, struct gaim_conversation *conv) | |
1851 { | |
1852 struct gaim_gtk_conversation *gtkconv; | |
1853 | |
1854 if (gaim_gtk_is_state_locked()) | |
1855 return; | |
1856 | |
1857 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
1858 | |
1859 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(color))) | |
1860 show_fgcolor_dialog(conv, color); | |
1861 else if (gtkconv->dialogs.fg_color != NULL) | |
1862 cancel_fgcolor(color, conv); | |
1863 else | |
1864 gaim_gtk_advance_past(gtkconv, "<FONT COLOR>", "</FONT>"); | |
1865 } | |
1866 | |
1867 static void | |
1868 toggle_bg_color(GtkWidget *color, struct gaim_conversation *conv) | |
1869 { | |
1870 struct gaim_gtk_conversation *gtkconv; | |
1871 | |
1872 if (gaim_gtk_is_state_locked()) | |
1873 return; | |
1874 | |
1875 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
1876 | |
1877 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(color))) | |
1878 show_bgcolor_dialog(conv, color); | |
1879 else if (gtkconv->dialogs.bg_color != NULL) | |
1880 cancel_bgcolor(color, conv); | |
1881 else | |
1882 gaim_gtk_advance_past(gtkconv, "<BODY BGCOLOR>", "</BODY>"); | |
1883 } | |
1884 | |
1885 static void | |
1886 check_everything(GtkTextBuffer *buffer) | |
1887 { | |
1888 struct gaim_conversation *conv; | |
1889 struct gaim_gtk_conversation *gtkconv; | |
1890 | |
1891 conv = (struct gaim_conversation *)g_object_get_data(G_OBJECT(buffer), | |
1892 "user_data"); | |
1893 | |
1894 if (conv == NULL) | |
1895 return; | |
1896 | |
1897 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
1898 | |
1899 /* CONV TODO */ | |
1900 } | |
1901 | |
1902 static void | |
1903 quiet_set(GtkWidget *tb, gboolean active) | |
1904 { | |
1905 gaim_gtk_set_state_lock(TRUE); | |
1906 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tb), active); | |
1907 gaim_gtk_set_state_lock(FALSE); | |
1908 } | |
1909 | |
1910 static void | |
1911 got_typing_keypress(struct gaim_conversation *conv, gboolean first) | |
1912 { | |
1913 struct gaim_im *im; | |
1914 | |
1915 /* | |
1916 * We know we got something, so we at least have to make sure we don't | |
1917 * send TYPED any time soon. | |
1918 */ | |
1919 | |
1920 im = GAIM_IM(conv); | |
1921 | |
1922 if (gaim_im_get_type_again_timeout(im)) | |
1923 gaim_im_stop_type_again_timeout(im); | |
1924 | |
1925 gaim_im_start_type_again_timeout(im); | |
1926 | |
1927 if (first || (gaim_im_get_type_again(im) != 0 && | |
1928 time(NULL) > gaim_im_get_type_again(im))) { | |
1929 | |
1930 int timeout = serv_send_typing(gaim_conversation_get_gc(conv), | |
1931 (char *)gaim_conversation_get_name(conv), | |
1932 TYPING); | |
1933 | |
1934 if (timeout) | |
1935 gaim_im_set_type_again(im, time(NULL) + timeout); | |
1936 else | |
1937 gaim_im_set_type_again(im, 0); | |
1938 } | |
1939 } | |
1940 | |
1941 static void | |
1942 update_send_as_selection(struct gaim_window *win) | |
1943 { | |
1944 struct aim_user *user; | |
1945 struct gaim_conversation *conv; | |
1946 struct gaim_gtk_window *gtkwin; | |
1947 const char *username; | |
1948 GtkWidget *menu; | |
1949 GList *child; | |
1950 | |
1951 conv = gaim_window_get_active_conversation(win); | |
1952 | |
1953 if (conv == NULL) | |
1954 return; | |
1955 | |
1956 user = gaim_conversation_get_user(conv); | |
1957 gtkwin = GAIM_GTK_WINDOW(win); | |
1958 | |
1959 username = (user->gc == NULL ? user->username : user->gc->username); | |
1960 | |
1961 gtk_widget_show(gtkwin->menu.send_as); | |
1962 | |
1963 menu = gtk_menu_item_get_submenu( | |
1964 GTK_MENU_ITEM(gtkwin->menu.send_as)); | |
1965 | |
1966 gaim_gtk_set_state_lock(TRUE); | |
1967 | |
1968 for (child = gtk_container_get_children(GTK_CONTAINER(menu)); | |
1969 child != NULL; | |
1970 child = child->next) { | |
1971 | |
1972 GtkWidget *item = child->data; | |
1973 GtkWidget *label; | |
1974 const char *title; | |
1975 | |
1976 label = gtk_bin_get_child(GTK_BIN(item)); | |
1977 | |
1978 if (!GTK_IS_LABEL(label)) | |
1979 continue; | |
1980 | |
1981 title = gtk_label_get_text(GTK_LABEL(label)); | |
1982 | |
1983 if (!strcmp(title, username)) { | |
1984 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE); | |
1985 break; | |
1986 } | |
1987 } | |
1988 | |
1989 gaim_gtk_set_state_lock(FALSE); | |
1990 } | |
1991 | |
1992 static void | |
1993 generate_send_as_items(struct gaim_window *win) | |
1994 { | |
1995 struct gaim_gtk_window *gtkwin; | |
1996 GtkWidget *menu; | |
1997 GtkWidget *menuitem; | |
1998 GSList *gcs; | |
1999 GList *convs; | |
2000 GSList *group = NULL; | |
2001 gboolean first_offline = TRUE; | |
2002 gboolean found_online = FALSE; | |
2003 | |
2004 gtkwin = GAIM_GTK_WINDOW(win); | |
2005 | |
2006 if (gtkwin->menu.send_as != NULL) | |
2007 gtk_widget_destroy(gtkwin->menu.send_as); | |
2008 | |
2009 /* See if we have > 1 connection active. */ | |
2010 if (g_slist_length(connections) < 2) { | |
2011 /* Now make sure we don't have any Offline entries. */ | |
2012 gboolean found_offline = FALSE; | |
2013 | |
2014 for (convs = gaim_get_conversations(); | |
2015 convs != NULL; | |
2016 convs = convs->next) { | |
2017 | |
2018 struct gaim_conversation *conv; | |
2019 struct aim_user *user; | |
2020 | |
2021 conv = (struct gaim_conversation *)convs->data; | |
2022 user = gaim_conversation_get_user(conv); | |
2023 | |
2024 if (user->gc == NULL) { | |
2025 found_offline = TRUE; | |
2026 break; | |
2027 } | |
2028 } | |
2029 | |
2030 if (!found_offline) { | |
2031 gtkwin->menu.send_as = NULL; | |
2032 return; | |
2033 } | |
2034 } | |
2035 | |
2036 /* Build the Send As menu */ | |
2037 gtkwin->menu.send_as = gtk_menu_item_new_with_mnemonic(_("_Send As")); | |
2038 gtk_widget_show(gtkwin->menu.send_as); | |
2039 | |
2040 menu = gtk_menu_new(); | |
2041 | |
2042 gtk_menu_shell_append(GTK_MENU_SHELL(gtkwin->menu.menubar), | |
2043 gtkwin->menu.send_as); | |
2044 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gtkwin->menu.send_as), menu); | |
2045 | |
2046 gtk_widget_show(menu); | |
2047 | |
2048 /* Fill it with entries. */ | |
2049 for (gcs = connections; gcs != NULL; gcs = gcs->next) { | |
2050 struct gaim_connection *gc; | |
2051 | |
2052 found_online = TRUE; | |
2053 | |
2054 gc = (struct gaim_connection *)gcs->data; | |
2055 | |
2056 menuitem = gtk_radio_menu_item_new_with_label(group, gc->username); | |
2057 group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menuitem)); | |
2058 | |
2059 g_object_set_data(G_OBJECT(menuitem), "user_data", win); | |
2060 | |
2061 g_signal_connect(G_OBJECT(menuitem), "activate", | |
2062 G_CALLBACK(menu_conv_sel_send_cb), gc->user); | |
2063 | |
2064 gtk_widget_show(menuitem); | |
2065 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
2066 } | |
2067 | |
2068 /* | |
2069 * Fill it with any accounts that still has an open (yet disabled) window | |
2070 * (signed off accounts with a window open). | |
2071 */ | |
2072 for (convs = gaim_get_conversations(); | |
2073 convs != NULL; | |
2074 convs = convs->next) { | |
2075 | |
2076 struct gaim_conversation *conv; | |
2077 struct aim_user *user; | |
2078 | |
2079 conv = (struct gaim_conversation *)convs->data; | |
2080 user = gaim_conversation_get_user(conv); | |
2081 | |
2082 if (user->gc == NULL) { | |
2083 if (first_offline && found_online) { | |
2084 menuitem = gtk_separator_menu_item_new(); | |
2085 gtk_widget_show(menuitem); | |
2086 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
2087 | |
2088 first_offline = FALSE; | |
2089 } | |
2090 | |
2091 printf("Adding '%s'\n", user->username); | |
2092 | |
2093 menuitem = gtk_radio_menu_item_new_with_label(group, | |
2094 user->username); | |
2095 group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menuitem)); | |
2096 | |
2097 gtk_widget_set_sensitive(menuitem, FALSE); | |
2098 | |
2099 gtk_widget_show(menuitem); | |
2100 gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); | |
2101 } | |
2102 } | |
2103 | |
2104 gtk_widget_show(gtkwin->menu.send_as); | |
2105 update_send_as_selection(win); | |
2106 } | |
2107 | |
2108 static GList * | |
2109 generate_invite_user_names(struct gaim_connection *gc) | |
2110 { | |
2111 GSList *grp; | |
2112 GSList *bl; | |
2113 struct group *g; | |
2114 struct buddy *buddy; | |
2115 static GList *tmp = NULL; | |
2116 | |
2117 if (tmp) | |
2118 g_list_free(tmp); | |
2119 | |
2120 tmp = g_list_append(NULL, ""); | |
2121 | |
2122 if (gc != NULL) { | |
2123 for (grp = groups; grp != NULL; grp = grp->next) { | |
2124 g = (struct group *)grp->data; | |
2125 | |
2126 for (bl = g->members; bl != NULL; bl = bl->next) { | |
2127 buddy = (struct buddy *)bl->data; | |
2128 | |
2129 if (buddy->present) | |
2130 tmp = g_list_append(tmp, buddy->name); | |
2131 } | |
2132 } | |
2133 } | |
2134 | |
2135 return tmp; | |
2136 } | |
2137 | |
2138 static void | |
2139 add_chat_buddy_common(struct gaim_conversation *conv, const char *name, | |
2140 int pos) | |
2141 { | |
2142 struct gaim_gtk_conversation *gtkconv; | |
2143 struct gaim_gtk_chat_pane *gtkchat; | |
2144 struct gaim_chat *chat; | |
2145 GtkTreeIter iter; | |
2146 GtkListStore *ls; | |
2147 | |
2148 chat = GAIM_CHAT(conv); | |
2149 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2150 gtkchat = gtkconv->u.chat; | |
2151 | |
2152 ls = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list))); | |
2153 | |
2154 gtk_list_store_append(ls, &iter); | |
2155 gtk_list_store_set(ls, &iter, 0, | |
2156 (gaim_chat_is_user_ignored(chat, name) ? "X" : " "), | |
2157 1, name, -1); | |
2158 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), 1, | |
2159 GTK_SORT_ASCENDING); | |
2160 } | |
2161 | |
2162 static void | |
2163 tab_complete(struct gaim_conversation *conv) | |
2164 { | |
2165 struct gaim_gtk_conversation *gtkconv; | |
2166 struct gaim_chat *chat; | |
2167 GtkTextIter cursor, word_start, start_buffer; | |
2168 int start; | |
2169 int most_matched = -1; | |
2170 char *entered, *partial = NULL; | |
2171 char *text; | |
2172 GList *matches = NULL; | |
2173 GList *nicks = NULL; | |
2174 | |
2175 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2176 chat = GAIM_CHAT(conv); | |
2177 | |
2178 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, &start_buffer); | |
2179 gtk_text_buffer_get_iter_at_mark(gtkconv->entry_buffer, &cursor, | |
2180 gtk_text_buffer_get_insert(gtkconv->entry_buffer)); | |
2181 | |
2182 word_start = cursor; | |
2183 | |
2184 /* if there's nothing there just return */ | |
2185 if (!gtk_text_iter_compare(&cursor, &start_buffer)) | |
2186 return; | |
2187 | |
2188 text = gtk_text_buffer_get_text(gtkconv->entry_buffer, &start_buffer, | |
2189 &cursor, FALSE); | |
2190 | |
2191 /* if we're at the end of ": " we need to move back 2 spaces */ | |
2192 start = strlen(text) - 1; | |
2193 | |
2194 if (strlen(text) >= 2 && !strncmp(&text[start-1], ": ", 2)) | |
2195 gtk_text_iter_backward_chars(&word_start, 2); | |
2196 | |
2197 /* find the start of the word that we're tabbing */ | |
2198 while (start >= 0 && text[start] != ' ') { | |
2199 gtk_text_iter_backward_char(&word_start); | |
2200 start--; | |
2201 } | |
2202 | |
2203 g_free(text); | |
2204 | |
2205 entered = gtk_text_buffer_get_text(gtkconv->entry_buffer, &word_start, | |
2206 &cursor, FALSE); | |
2207 | |
2208 if (chat_options & OPT_CHAT_OLD_STYLE_TAB) { | |
2209 if (strlen(entered) >= 2 && | |
2210 !strncmp(": ", entered + strlen(entered) - 2, 2)) { | |
2211 | |
2212 entered[strlen(entered) - 2] = 0; | |
2213 } | |
2214 } | |
2215 | |
2216 if (!strlen(entered)) { | |
2217 g_free(entered); | |
2218 return; | |
2219 } | |
2220 | |
2221 for (nicks = gaim_chat_get_users(chat); | |
2222 nicks != NULL; | |
2223 nicks = nicks->next) { | |
2224 | |
2225 char *nick = nicks->data; | |
2226 /* this checks to see if the current nick could be a completion */ | |
2227 if (g_strncasecmp(nick, entered, strlen(entered))) { | |
2228 if (nick[0] != '+' && nick[0] != '@') | |
2229 continue; | |
2230 | |
2231 if (g_strncasecmp(nick + 1, entered, strlen(entered))) { | |
2232 if (nick[0] != '@' || nick[1] != '+') | |
2233 continue; | |
2234 | |
2235 if (g_strncasecmp(nick + 2, entered, strlen(entered))) | |
2236 continue; | |
2237 else | |
2238 nick += 2; | |
2239 } | |
2240 else | |
2241 nick++; | |
2242 } | |
2243 | |
2244 /* if we're here, it's a possible completion */ | |
2245 | |
2246 /* if we're doing old-style, just fill in the completion */ | |
2247 if (chat_options & OPT_CHAT_OLD_STYLE_TAB) { | |
2248 gtk_text_buffer_delete(gtkconv->entry_buffer, | |
2249 &word_start, &cursor); | |
2250 | |
2251 if (strlen(nick) == strlen(entered)) { | |
2252 nicks = (nicks->next | |
2253 ? nicks->next | |
2254 : gaim_chat_get_users(chat)); | |
2255 | |
2256 nick = nicks->data; | |
2257 | |
2258 if (*nick == '@') nick++; | |
2259 if (*nick == '+') nick++; | |
2260 } | |
2261 | |
2262 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, | |
2263 &start_buffer); | |
2264 gtk_text_buffer_get_iter_at_mark(gtkconv->entry_buffer, &cursor, | |
2265 gtk_text_buffer_get_insert(gtkconv->entry_buffer)); | |
2266 | |
2267 if (!gtk_text_iter_compare(&cursor, &start_buffer)) { | |
2268 char *tmp = g_strdup_printf("%s: ", nick); | |
2269 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, | |
2270 tmp, -1); | |
2271 g_free(tmp); | |
2272 } | |
2273 else | |
2274 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, | |
2275 nick, -1); | |
2276 | |
2277 g_free(entered); | |
2278 | |
2279 return; | |
2280 } | |
2281 | |
2282 /* we're only here if we're doing new style */ | |
2283 if (most_matched == -1) { | |
2284 /* | |
2285 * this will only get called once, since from now | |
2286 * on most_matched is >= 0 | |
2287 */ | |
2288 most_matched = strlen(nick); | |
2289 partial = g_strdup(nick); | |
2290 } | |
2291 else if (most_matched) { | |
2292 while (g_strncasecmp(nick, partial, most_matched)) | |
2293 most_matched--; | |
2294 | |
2295 partial[most_matched] = 0; | |
2296 } | |
2297 | |
2298 matches = g_list_append(matches, nick); | |
2299 } | |
2300 | |
2301 /* we're only here if we're doing new style */ | |
2302 | |
2303 /* if there weren't any matches, return */ | |
2304 if (!matches) { | |
2305 /* if matches isn't set partials won't be either */ | |
2306 g_free(entered); | |
2307 return; | |
2308 } | |
2309 | |
2310 gtk_text_buffer_delete(gtkconv->entry_buffer, &word_start, &cursor); | |
2311 | |
2312 if (!matches->next) { | |
2313 /* there was only one match. fill it in. */ | |
2314 gtk_text_buffer_get_start_iter(gtkconv->entry_buffer, &start_buffer); | |
2315 gtk_text_buffer_get_iter_at_mark(gtkconv->entry_buffer, &cursor, | |
2316 gtk_text_buffer_get_insert(gtkconv->entry_buffer)); | |
2317 | |
2318 if (!gtk_text_iter_compare(&cursor, &start_buffer)) { | |
2319 char *tmp = g_strdup_printf("%s: ", (char *)matches->data); | |
2320 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, tmp, -1); | |
2321 g_free(tmp); | |
2322 } | |
2323 else | |
2324 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, | |
2325 matches->data, -1); | |
2326 | |
2327 matches = g_list_remove(matches, matches->data); | |
2328 } | |
2329 else { | |
2330 /* | |
2331 * there were lots of matches, fill in as much as possible | |
2332 * and display all of them | |
2333 */ | |
2334 char *addthis = g_malloc0(1); | |
2335 | |
2336 while (matches) { | |
2337 char *tmp = addthis; | |
2338 addthis = g_strconcat(tmp, matches->data, " ", NULL); | |
2339 g_free(tmp); | |
2340 matches = g_list_remove(matches, matches->data); | |
2341 } | |
2342 | |
2343 gaim_conversation_write(conv, NULL, addthis, -1, WFLAG_NOLOG, | |
2344 time(NULL)); | |
2345 gtk_text_buffer_insert_at_cursor(gtkconv->entry_buffer, partial, -1); | |
2346 g_free(addthis); | |
2347 } | |
2348 | |
2349 g_free(entered); | |
2350 g_free(partial); | |
2351 } | |
2352 | |
2353 static gboolean | |
2354 meify(char *message, size_t len) | |
2355 { | |
2356 /* | |
2357 * Read /me-ify: If the message (post-HTML) starts with /me, | |
2358 * remove the "/me " part of it (including that space) and return TRUE. | |
2359 */ | |
2360 char *c; | |
2361 gboolean inside_html = 0; | |
2362 | |
2363 if (message == NULL) | |
2364 return FALSE; /* Umm.. this would be very bad if this happens. */ | |
2365 | |
2366 if (len == -1) | |
2367 len = strlen(message); | |
2368 | |
2369 for (c = message; *c != '\0'; c++, len--) { | |
2370 if (inside_html) { | |
2371 if (*c == '>') | |
2372 inside_html = FALSE; | |
2373 } | |
2374 else { | |
2375 if (*c == '<') | |
2376 inside_html = TRUE; | |
2377 else | |
2378 break; | |
2379 } | |
2380 } | |
2381 | |
2382 if (*c != '\0' && !g_strncasecmp(c, "/me ", 4)) { | |
2383 memmove(c, c + 4, len - 3); | |
2384 | |
2385 return TRUE; | |
2386 } | |
2387 | |
2388 return FALSE; | |
2389 } | |
2390 | |
2391 static GtkItemFactoryEntry menu_items[] = | |
2392 { | |
2393 /* Conversation menu */ | |
2394 { "/_Conversation", NULL, NULL, 0, "<Branch>" }, | |
2395 { "/Conversation/_Save As...", NULL, menu_save_as_cb, 0, | |
2396 "<StockItem>", GTK_STOCK_SAVE_AS }, | |
2397 { "/Conversation/View _History...", NULL, menu_view_history_cb, 0, NULL }, | |
2398 { "/Conversation/sep1", NULL, NULL, 0, "<Separator>" }, | |
2399 { "/Conversation/Insert _URL...", NULL, menu_insert_link_cb, 0, | |
2400 "<StockItem>", GAIM_STOCK_LINK }, | |
2401 { "/Conversation/Insert _Image...", NULL, menu_insert_image_cb, 0, | |
2402 "<StockItem>", GAIM_STOCK_IMAGE }, | |
2403 { "/Conversation/sep2", NULL, NULL, 0, "<Separator>" }, | |
2404 { "/Conversation/_Close", NULL, menu_close_conv_cb, 0, | |
2405 "<StockItem>", GTK_STOCK_CLOSE }, | |
2406 | |
2407 /* Options */ | |
2408 { "/_Options", NULL, NULL, 0, "<Branch>" }, | |
2409 { "/Options/Enable _Logging", NULL, menu_logging_cb, 0, "<CheckItem>" }, | |
2410 { "/Options/Enable _Sounds", NULL, menu_sounds_cb, 0, "<CheckItem>" }, | |
2411 }; | |
2412 | |
2413 static const int menu_item_count = | |
2414 sizeof(menu_items) / sizeof(*menu_items); | |
2415 | |
2416 static GtkWidget * | |
2417 setup_menubar(struct gaim_window *win) | |
2418 { | |
2419 struct gaim_gtk_window *gtkwin; | |
2420 GtkWidget *hb; | |
2421 GtkItemFactory *item_factory; | |
2422 | |
2423 gtkwin = GAIM_GTK_WINDOW(win); | |
2424 | |
2425 /* Create the handle box. */ | |
2426 hb = gtk_handle_box_new(); | |
2427 | |
2428 item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", NULL); | |
2429 | |
2430 gtk_item_factory_create_items(item_factory, menu_item_count, | |
2431 menu_items, win); | |
2432 | |
2433 gtkwin->menu.menubar = gtk_item_factory_get_widget(item_factory, "<main>"); | |
2434 gtkwin->menu.view_history = gtk_item_factory_get_widget(item_factory, | |
2435 "/Conversation/View History..."); | |
2436 gtkwin->menu.insert_link = gtk_item_factory_get_widget(item_factory, | |
2437 "/Conversation/Insert URL..."); | |
2438 gtkwin->menu.insert_image = gtk_item_factory_get_widget(item_factory, | |
2439 "/Conversation/Insert Image..."); | |
2440 gtkwin->menu.logging = gtk_item_factory_get_widget(item_factory, | |
2441 "/Options/Enable Logging"); | |
2442 gtkwin->menu.sounds = gtk_item_factory_get_widget(item_factory, | |
2443 "/Options/Enable Sounds"); | |
2444 | |
2445 generate_send_as_items(win); | |
2446 | |
2447 gtk_container_add(GTK_CONTAINER(hb), gtkwin->menu.menubar); | |
2448 | |
2449 gtk_widget_show(gtkwin->menu.menubar); | |
2450 gtk_widget_show(hb); | |
2451 | |
2452 return hb; | |
2453 } | |
2454 | |
2455 static void | |
2456 setup_im_buttons(struct gaim_conversation *conv, GtkWidget *parent) | |
2457 { | |
2458 struct gaim_connection *gc; | |
2459 struct gaim_gtk_conversation *gtkconv; | |
2460 struct gaim_gtk_im_pane *gtkim; | |
2461 struct gaim_gtk_window *gtkwin; | |
2462 GaimConversationType type = GAIM_CONV_IM; | |
2463 | |
2464 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2465 gtkim = gtkconv->u.im; | |
2466 gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv)); | |
2467 gc = gaim_conversation_get_gc(conv); | |
2468 | |
2469 /* From right to left... */ | |
2470 | |
2471 /* Send button */ | |
2472 gtkconv->send = gaim_gtk_change_text(_("Send"), gtkconv->send, | |
2473 GAIM_STOCK_SEND, type); | |
2474 gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->send, _("Send"), NULL); | |
2475 | |
2476 gtk_box_pack_end(GTK_BOX(parent), gtkconv->send, FALSE, FALSE, 0); | |
2477 | |
2478 /* Separator */ | |
2479 if (gtkim->sep2 != NULL) | |
2480 gtk_widget_destroy(gtkim->sep2); | |
2481 | |
2482 gtkim->sep2 = gtk_vseparator_new(); | |
2483 gtk_box_pack_end(GTK_BOX(parent), gtkim->sep2, FALSE, TRUE, 0); | |
2484 gtk_widget_show(gtkim->sep2); | |
2485 | |
2486 /* Now, um, just kind of all over the place. Huh? */ | |
2487 | |
2488 /* Add button */ | |
2489 if (find_buddy(gaim_conversation_get_gc(conv)->user, | |
2490 gaim_conversation_get_name(conv)) == NULL) { | |
2491 gtkim->add = gaim_gtk_change_text(_("Add"), gtkim->add, | |
2492 GTK_STOCK_ADD, type); | |
2493 gtk_tooltips_set_tip(gtkconv->tooltips, gtkim->add, | |
2494 _("Add buddy"), NULL); | |
2495 } | |
2496 else { | |
2497 gtkim->add = gaim_gtk_change_text(_("Remove"), gtkim->add, | |
2498 GTK_STOCK_REMOVE, type); | |
2499 gtk_tooltips_set_tip(gtkconv->tooltips, gtkim->add, | |
2500 _("Remove buddy"), NULL); | |
2501 } | |
2502 | |
2503 gtk_box_pack_start(GTK_BOX(parent), gtkim->add, | |
2504 FALSE, FALSE, 0); | |
2505 | |
2506 /* Warn button */ | |
2507 gtkim->warn = gaim_gtk_change_text(_("Warn"), gtkim->warn, | |
2508 GAIM_STOCK_WARN, type); | |
2509 gtk_box_pack_start(GTK_BOX(parent), gtkim->warn, FALSE, FALSE, 0); | |
2510 gtk_tooltips_set_tip(gtkconv->tooltips, gtkim->add, | |
2511 _("Remove buddy"), NULL); | |
2512 | |
2513 /* Info button */ | |
2514 gtkconv->info = gaim_gtk_change_text(_("Info"), gtkconv->info, | |
2515 GAIM_STOCK_INFO, type); | |
2516 gtk_box_pack_start(GTK_BOX(parent), gtkconv->info, FALSE, FALSE, 0); | |
2517 gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->info, | |
2518 _("Get user information"), NULL); | |
2519 | |
2520 /* Block button */ | |
2521 gtkim->block = gaim_gtk_change_text(_("Block"), gtkim->block, | |
2522 GAIM_STOCK_BLOCK, type); | |
2523 gtk_box_pack_start(GTK_BOX(parent), gtkim->block, FALSE, FALSE, 0); | |
2524 gtk_tooltips_set_tip(gtkconv->tooltips, gtkim->block, | |
2525 _("Block user"), NULL); | |
2526 | |
2527 gtk_button_set_relief(GTK_BUTTON(gtkconv->info), GTK_RELIEF_NONE); | |
2528 gtk_button_set_relief(GTK_BUTTON(gtkim->add), GTK_RELIEF_NONE); | |
2529 gtk_button_set_relief(GTK_BUTTON(gtkim->warn), GTK_RELIEF_NONE); | |
2530 gtk_button_set_relief(GTK_BUTTON(gtkconv->send), GTK_RELIEF_NONE); | |
2531 gtk_button_set_relief(GTK_BUTTON(gtkim->block), GTK_RELIEF_NONE); | |
2532 | |
2533 gtk_size_group_add_widget(gtkconv->sg, gtkconv->info); | |
2534 gtk_size_group_add_widget(gtkconv->sg, gtkim->add); | |
2535 gtk_size_group_add_widget(gtkconv->sg, gtkim->warn); | |
2536 gtk_size_group_add_widget(gtkconv->sg, gtkconv->send); | |
2537 gtk_size_group_add_widget(gtkconv->sg, gtkim->block); | |
2538 | |
2539 gtk_box_reorder_child(GTK_BOX(parent), gtkim->warn, 1); | |
2540 gtk_box_reorder_child(GTK_BOX(parent), gtkim->block, 2); | |
2541 gtk_box_reorder_child(GTK_BOX(parent), gtkconv->info, 4); | |
2542 | |
2543 gaim_gtkconv_update_buttons_by_protocol(conv); | |
2544 | |
2545 g_signal_connect(G_OBJECT(gtkconv->send), "clicked", | |
2546 G_CALLBACK(send_cb), conv); | |
2547 g_signal_connect(G_OBJECT(gtkconv->info), "clicked", | |
2548 G_CALLBACK(info_cb), conv); | |
2549 g_signal_connect(G_OBJECT(gtkim->warn), "clicked", | |
2550 G_CALLBACK(warn_cb), conv); | |
2551 g_signal_connect(G_OBJECT(gtkim->block), "clicked", | |
2552 G_CALLBACK(block_cb), conv); | |
2553 } | |
2554 | |
2555 static void | |
2556 setup_chat_buttons(struct gaim_conversation *conv, GtkWidget *parent) | |
2557 { | |
2558 struct gaim_connection *gc; | |
2559 struct gaim_gtk_conversation *gtkconv; | |
2560 struct gaim_gtk_chat_pane *gtkchat; | |
2561 struct gaim_gtk_window *gtkwin; | |
2562 GtkWidget *sep; | |
2563 | |
2564 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2565 gtkchat = gtkconv->u.chat; | |
2566 gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv)); | |
2567 gc = gaim_conversation_get_gc(conv); | |
2568 | |
2569 /* Send button */ | |
2570 gtkconv->send = gaim_gtk_change_text(_("Send"), gtkconv->send, | |
2571 GAIM_STOCK_SEND, GAIM_CONV_CHAT); | |
2572 gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->send, _("Send"), NULL); | |
2573 | |
2574 gtk_box_pack_end(GTK_BOX(parent), gtkconv->send, FALSE, FALSE, 0); | |
2575 | |
2576 /* Separator */ | |
2577 sep = gtk_vseparator_new(); | |
2578 gtk_box_pack_end(GTK_BOX(parent), sep, FALSE, TRUE, 0); | |
2579 gtk_widget_show(sep); | |
2580 | |
2581 /* Invite */ | |
2582 gtkchat->invite = gaim_gtk_change_text(_("Invite"), gtkchat->invite, | |
2583 GAIM_STOCK_INVITE, GAIM_CONV_CHAT); | |
2584 gtk_tooltips_set_tip(gtkconv->tooltips, gtkchat->invite, | |
2585 _("Invite a user"), NULL); | |
2586 gtk_box_pack_end(GTK_BOX(parent), gtkchat->invite, FALSE, FALSE, 0); | |
2587 | |
2588 /* Set the relief on these. */ | |
2589 gtk_button_set_relief(GTK_BUTTON(gtkchat->invite), GTK_RELIEF_NONE); | |
2590 gtk_button_set_relief(GTK_BUTTON(gtkconv->send), GTK_RELIEF_NONE); | |
2591 | |
2592 /* Callbacks */ | |
2593 g_signal_connect(G_OBJECT(gtkconv->send), "clicked", | |
2594 G_CALLBACK(send_cb), conv); | |
2595 g_signal_connect(G_OBJECT(gtkchat->invite), "clicked", | |
2596 G_CALLBACK(invite_cb), conv); | |
2597 } | |
2598 | |
2599 static GtkWidget * | |
2600 build_conv_toolbar(struct gaim_conversation *conv) | |
2601 { | |
2602 struct gaim_gtk_conversation *gtkconv; | |
2603 GtkWidget *vbox; | |
2604 GtkWidget *hbox; | |
2605 GtkWidget *button; | |
2606 GtkWidget *sep; | |
2607 GtkSizeGroup *sg; | |
2608 | |
2609 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2610 | |
2611 sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH); | |
2612 | |
2613 vbox = gtk_vbox_new(FALSE, 0); | |
2614 sep = gtk_hseparator_new(); | |
2615 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); | |
2616 | |
2617 hbox = gtk_hbox_new(FALSE, 5); | |
2618 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
2619 | |
2620 /* Bold */ | |
2621 button = gaim_pixbuf_toolbar_button_from_stock(GTK_STOCK_BOLD); | |
2622 gtk_size_group_add_widget(sg, button); | |
2623 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2624 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Bold"), NULL); | |
2625 | |
2626 g_signal_connect(G_OBJECT(button), "clicked", | |
2627 G_CALLBACK(do_bold), gtkconv); | |
2628 | |
2629 gtkconv->toolbar.bold = button; | |
2630 | |
2631 /* Italic */ | |
2632 button = gaim_pixbuf_toolbar_button_from_stock(GTK_STOCK_ITALIC); | |
2633 gtk_size_group_add_widget(sg, button); | |
2634 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2635 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Italic"), NULL); | |
2636 | |
2637 g_signal_connect(G_OBJECT(button), "clicked", | |
2638 G_CALLBACK(do_italic), gtkconv); | |
2639 | |
2640 gtkconv->toolbar.italic = button; | |
2641 | |
2642 /* Underline */ | |
2643 button = gaim_pixbuf_toolbar_button_from_stock(GTK_STOCK_UNDERLINE); | |
2644 gtk_size_group_add_widget(sg, button); | |
2645 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2646 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Underline"), NULL); | |
2647 | |
2648 g_signal_connect(G_OBJECT(button), "clicked", | |
2649 G_CALLBACK(do_underline), gtkconv); | |
2650 | |
2651 gtkconv->toolbar.underline = button; | |
2652 | |
2653 /* Sep */ | |
2654 sep = gtk_vseparator_new(); | |
2655 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0); | |
2656 | |
2657 /* Increase font size */ | |
2658 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_TEXT_BIGGER); | |
2659 gtk_size_group_add_widget(sg, button); | |
2660 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2661 gtk_tooltips_set_tip(gtkconv->tooltips, button, | |
2662 _("Larger font size"), NULL); | |
2663 | |
2664 g_signal_connect(G_OBJECT(button), "clicked", | |
2665 G_CALLBACK(do_big), gtkconv); | |
2666 | |
2667 /* Normal font size */ | |
2668 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_TEXT_NORMAL); | |
2669 gtk_size_group_add_widget(sg, button); | |
2670 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2671 gtk_tooltips_set_tip(gtkconv->tooltips, button, | |
2672 _("Normal font size"), NULL); | |
2673 | |
2674 g_signal_connect(G_OBJECT(button), "clicked", | |
2675 G_CALLBACK(do_normal), gtkconv); | |
2676 | |
2677 gtkconv->toolbar.normal_size = button; | |
2678 | |
2679 /* Decrease font size */ | |
2680 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_TEXT_SMALLER); | |
2681 gtk_size_group_add_widget(sg, button); | |
2682 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2683 gtk_tooltips_set_tip(gtkconv->tooltips, button, | |
2684 _("Smaller font size"), NULL); | |
2685 | |
2686 g_signal_connect(G_OBJECT(button), "clicked", | |
2687 G_CALLBACK(do_small), gtkconv); | |
2688 | |
2689 /* Sep */ | |
2690 sep = gtk_vseparator_new(); | |
2691 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0); | |
2692 | |
2693 /* Foreground Color */ | |
2694 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_FGCOLOR); | |
2695 gtk_size_group_add_widget(sg, button); | |
2696 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2697 gtk_tooltips_set_tip(gtkconv->tooltips, button, | |
2698 _("Foreground font color"), NULL); | |
2699 | |
2700 g_signal_connect(G_OBJECT(button), "clicked", | |
2701 G_CALLBACK(toggle_fg_color), conv); | |
2702 | |
2703 gtkconv->toolbar.fgcolor = button; | |
2704 | |
2705 /* Background Color */ | |
2706 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_BGCOLOR); | |
2707 gtk_size_group_add_widget(sg, button); | |
2708 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2709 gtk_tooltips_set_tip(gtkconv->tooltips, button, | |
2710 _("Background color"), NULL); | |
2711 | |
2712 g_signal_connect(G_OBJECT(button), "clicked", | |
2713 G_CALLBACK(toggle_bg_color), conv); | |
2714 | |
2715 gtkconv->toolbar.bgcolor = button; | |
2716 | |
2717 /* Sep */ | |
2718 sep = gtk_vseparator_new(); | |
2719 gtk_box_pack_start(GTK_BOX(hbox), sep, FALSE, FALSE, 0); | |
2720 | |
2721 /* Insert IM Image */ | |
2722 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_IMAGE); | |
2723 gtk_size_group_add_widget(sg, button); | |
2724 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2725 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Insert image"), NULL); | |
2726 | |
2727 g_signal_connect(G_OBJECT(button), "clicked", | |
2728 G_CALLBACK(insert_image_cb), conv); | |
2729 | |
2730 gtkconv->toolbar.image = button; | |
2731 | |
2732 /* Insert Link */ | |
2733 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_LINK); | |
2734 gtk_size_group_add_widget(sg, button); | |
2735 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2736 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Insert link"), NULL); | |
2737 | |
2738 g_signal_connect(G_OBJECT(button), "clicked", | |
2739 G_CALLBACK(insert_link_cb), conv); | |
2740 | |
2741 gtkconv->toolbar.link = button; | |
2742 | |
2743 /* Insert Smiley */ | |
2744 button = gaim_pixbuf_toolbar_button_from_stock(GAIM_STOCK_SMILEY); | |
2745 gtk_size_group_add_widget(sg, button); | |
2746 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
2747 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Insert smiley"), NULL); | |
2748 | |
2749 g_signal_connect(G_OBJECT(button), "clicked", | |
2750 G_CALLBACK(insert_smiley_cb), conv); | |
2751 | |
2752 gtkconv->toolbar.smiley = button; | |
2753 | |
2754 | |
2755 sep = gtk_hseparator_new(); | |
2756 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); | |
2757 | |
2758 gtk_widget_show_all(vbox); | |
2759 | |
2760 return vbox; | |
2761 } | |
2762 | |
2763 static GtkWidget * | |
2764 setup_chat_pane(struct gaim_conversation *conv) | |
2765 { | |
2766 struct gaim_gtk_conversation *gtkconv; | |
2767 struct gaim_gtk_chat_pane *gtkchat; | |
2768 struct gaim_connection *gc; | |
2769 GtkWidget *vpaned, *hpaned; | |
2770 GtkWidget *vbox, *hbox; | |
2771 GtkWidget *lbox, *bbox; | |
2772 GtkWidget *label; | |
2773 GtkWidget *sw2; | |
2774 GtkWidget *list; | |
2775 GtkWidget *button; | |
2776 GtkWidget *frame; | |
2777 GtkListStore *ls; | |
2778 GtkCellRenderer *rend; | |
2779 GtkTreeViewColumn *col; | |
2780 | |
2781 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2782 gtkchat = gtkconv->u.chat; | |
2783 gc = gaim_conversation_get_gc(conv); | |
2784 | |
2785 /* Setup the outer pane. */ | |
2786 vpaned = gtk_vpaned_new(); | |
2787 gtk_paned_set_gutter_size(GTK_PANED(vpaned), 15); | |
2788 gtk_widget_show(vpaned); | |
2789 | |
2790 /* Setup the top part of the pane. */ | |
2791 vbox = gtk_vbox_new(FALSE, 5); | |
2792 gtk_paned_pack1(GTK_PANED(vpaned), vbox, TRUE, FALSE); | |
2793 gtk_widget_show(vbox); | |
2794 | |
2795 if (gc->prpl->options & OPT_PROTO_CHAT_TOPIC) | |
2796 { | |
2797 hbox = gtk_hbox_new(FALSE, 0); | |
2798 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); | |
2799 gtk_widget_show(hbox); | |
2800 | |
2801 label = gtk_label_new(_("Topic:")); | |
2802 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); | |
2803 gtk_widget_show(label); | |
2804 | |
2805 gtkchat->topic_text = gtk_entry_new(); | |
2806 gtk_entry_set_editable(GTK_ENTRY(gtkchat->topic_text), FALSE); | |
2807 gtk_box_pack_start(GTK_BOX(hbox), gtkchat->topic_text, TRUE, TRUE, 5); | |
2808 gtk_widget_show(gtkchat->topic_text); | |
2809 } | |
2810 | |
2811 /* Setup the horizontal pane. */ | |
2812 hpaned = gtk_hpaned_new(); | |
2813 gtk_paned_set_gutter_size(GTK_PANED(hpaned), 15); | |
2814 gtk_box_pack_start(GTK_BOX(vbox), hpaned, TRUE, TRUE, 5); | |
2815 gtk_widget_show(hpaned); | |
2816 | |
2817 /* Setup the scrolled window to put gtkimhtml in. */ | |
2818 gtkconv->sw = gtk_scrolled_window_new(NULL, NULL); | |
2819 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkconv->sw), | |
2820 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); | |
2821 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkconv->sw), | |
2822 GTK_SHADOW_IN); | |
2823 gtk_paned_pack1(GTK_PANED(hpaned), gtkconv->sw, TRUE, TRUE); | |
2824 | |
2825 gtk_widget_set_size_request(gtkconv->sw, | |
2826 buddy_chat_size.width, buddy_chat_size.height); | |
2827 gtk_widget_show(gtkconv->sw); | |
2828 | |
2829 /* Setup gtkihmtml. */ | |
2830 gtkconv->imhtml = gtk_imhtml_new(NULL, NULL); | |
2831 gtk_container_add(GTK_CONTAINER(gtkconv->sw), gtkconv->imhtml); | |
2832 | |
2833 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), | |
2834 (convo_options & OPT_CONVO_SHOW_TIME)); | |
2835 | |
2836 g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event", | |
2837 G_CALLBACK(entry_stop_rclick_cb), NULL); | |
2838 | |
2839 gaim_setup_imhtml(gtkconv->imhtml); | |
2840 | |
2841 gtk_widget_show(gtkconv->imhtml); | |
2842 | |
2843 /* Build the right pane. */ | |
2844 lbox = gtk_vbox_new(FALSE, 5); | |
2845 gtk_paned_pack2(GTK_PANED(hpaned), lbox, TRUE, TRUE); | |
2846 gtk_widget_show(lbox); | |
2847 | |
2848 /* Setup the label telling how many people are in the room. */ | |
2849 gtkchat->count = gtk_label_new(_("0 people in room")); | |
2850 gtk_box_pack_start(GTK_BOX(lbox), gtkchat->count, FALSE, FALSE, 0); | |
2851 gtk_widget_show(gtkchat->count); | |
2852 | |
2853 /* Setup the list of users. */ | |
2854 sw2 = gtk_scrolled_window_new(NULL, NULL); | |
2855 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw2), | |
2856 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); | |
2857 gtk_box_pack_start(GTK_BOX(lbox), sw2, TRUE, TRUE, 0); | |
2858 gtk_widget_show(sw2); | |
2859 | |
2860 ls = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); | |
2861 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), 1, | |
2862 GTK_SORT_ASCENDING); | |
2863 | |
2864 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls)); | |
2865 | |
2866 rend = gtk_cell_renderer_text_new(); | |
2867 col = gtk_tree_view_column_new_with_attributes(NULL, rend, | |
2868 "text", 0, NULL); | |
2869 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(col), TRUE); | |
2870 | |
2871 g_signal_connect(G_OBJECT(list), "button_press_event", | |
2872 G_CALLBACK(right_click_chat_cb), conv); | |
2873 | |
2874 gtk_tree_view_append_column(GTK_TREE_VIEW(list), col); | |
2875 | |
2876 col = gtk_tree_view_column_new_with_attributes(NULL, rend, | |
2877 "text", 1, NULL); | |
2878 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(col), TRUE); | |
2879 | |
2880 #if 0 | |
2881 g_signal_connect(G_OBJECT(list), "button_press_event", | |
2882 G_CALLBACK(right_click_chat), conv); | |
2883 #endif | |
2884 | |
2885 gtk_tree_view_append_column(GTK_TREE_VIEW(list), col); | |
2886 | |
2887 gtk_widget_set_size_request(list, 150, -1); | |
2888 | |
2889 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE); | |
2890 gtk_widget_show(list); | |
2891 | |
2892 gtkchat->list = list; | |
2893 | |
2894 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw2), list); | |
2895 | |
2896 /* Setup the user list toolbar. */ | |
2897 bbox = gtk_hbox_new(TRUE, 5); | |
2898 gtk_box_pack_start(GTK_BOX(lbox), bbox, FALSE, FALSE, 0); | |
2899 gtk_widget_show(bbox); | |
2900 | |
2901 /* IM */ | |
2902 button = gaim_pixbuf_button_from_stock(NULL, GTK_STOCK_REDO, | |
2903 GAIM_BUTTON_VERTICAL); | |
2904 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2905 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
2906 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("IM"), NULL); | |
2907 g_signal_connect(G_OBJECT(button), "clicked", | |
2908 G_CALLBACK(im_cb), conv); | |
2909 | |
2910 gtk_widget_show(button); | |
2911 | |
2912 /* Ignore */ | |
2913 button = gaim_pixbuf_button_from_stock(NULL, GAIM_STOCK_IGNORE, | |
2914 GAIM_BUTTON_VERTICAL); | |
2915 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2916 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
2917 gtk_tooltips_set_tip(gtkconv->tooltips, button, _("Ignore user"), NULL); | |
2918 g_signal_connect(G_OBJECT(button), "clicked", | |
2919 G_CALLBACK(ignore_cb), conv); | |
2920 gtk_widget_show(button); | |
2921 | |
2922 /* Info */ | |
2923 button = gaim_pixbuf_button_from_stock(NULL, GAIM_STOCK_INFO, | |
2924 GAIM_BUTTON_VERTICAL); | |
2925 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); | |
2926 gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0); | |
2927 gtk_tooltips_set_tip(gtkconv->tooltips, button, | |
2928 _("Get user information"), NULL); | |
2929 g_signal_connect(G_OBJECT(button), "clicked", | |
2930 G_CALLBACK(info_cb), conv); | |
2931 | |
2932 gtk_widget_show(button); | |
2933 | |
2934 gtkconv->info = button; | |
2935 | |
2936 /* Build the toolbar. */ | |
2937 vbox = gtk_vbox_new(FALSE, 5); | |
2938 gtk_paned_pack2(GTK_PANED(vpaned), vbox, TRUE, FALSE); | |
2939 gtk_widget_show(vbox); | |
2940 | |
2941 gtkconv->toolbar.toolbar = build_conv_toolbar(conv); | |
2942 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->toolbar.toolbar, | |
2943 FALSE, FALSE, 0); | |
2944 | |
2945 /* Setup the entry widget. */ | |
2946 frame = gtk_frame_new(NULL); | |
2947 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); | |
2948 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); | |
2949 gtk_widget_show(frame); | |
2950 | |
2951 gtkconv->entry_buffer = gtk_text_buffer_new(NULL); | |
2952 g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", conv); | |
2953 gtkconv->entry = gtk_text_view_new_with_buffer(gtkconv->entry_buffer); | |
2954 | |
2955 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gtkconv->entry), GTK_WRAP_WORD); | |
2956 gtk_widget_set_size_request(gtkconv->entry, buddy_chat_size.width, | |
2957 MAX(buddy_chat_size.entry_height, 25)); | |
2958 | |
2959 /* Connect the signal handlers. */ | |
2960 g_signal_connect_swapped(G_OBJECT(gtkconv->entry), "key_press_event", | |
2961 G_CALLBACK(entry_key_pressed_cb_1), | |
2962 gtkconv->entry_buffer); | |
2963 g_signal_connect_after(G_OBJECT(gtkconv->entry), "button_press_event", | |
2964 G_CALLBACK(entry_stop_rclick_cb), NULL); | |
2965 g_signal_connect(G_OBJECT(gtkconv->entry), "key_press_event", | |
2966 G_CALLBACK(entry_key_pressed_cb_2), conv); | |
2967 | |
2968 #ifdef USE_GTKSPELL | |
2969 if (convo_options & OPT_CONVO_CHECK_SPELLING) | |
2970 gtkspell_new_attach(GTK_TEXT_VIEW(gtkconv->entry), NULL, NULL); | |
2971 #endif | |
2972 | |
2973 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(gtkconv->entry)); | |
2974 gtk_widget_show(gtkconv->entry); | |
2975 | |
2976 /* Setup the bottom button box. */ | |
2977 gtkconv->bbox = gtk_hbox_new(FALSE, 5); | |
2978 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->bbox, FALSE, FALSE, 0); | |
2979 gtk_widget_show(gtkconv->bbox); | |
2980 | |
2981 setup_chat_buttons(conv, gtkconv->bbox); | |
2982 | |
2983 return vpaned; | |
2984 } | |
2985 | |
2986 static GtkWidget * | |
2987 setup_im_pane(struct gaim_conversation *conv) | |
2988 { | |
2989 struct gaim_gtk_conversation *gtkconv; | |
2990 struct gaim_gtk_im_pane *gtkim; | |
2991 GtkWidget *paned; | |
2992 GtkWidget *vbox; | |
2993 GtkWidget *vbox2; | |
2994 GtkWidget *frame; | |
2995 | |
2996 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
2997 gtkim = gtkconv->u.im; | |
2998 | |
2999 /* Setup the outer pane. */ | |
3000 paned = gtk_vpaned_new(); | |
3001 gtk_paned_set_gutter_size(GTK_PANED(paned), 15); | |
3002 gtk_widget_show(paned); | |
3003 | |
3004 /* Setup the top part of the pane. */ | |
3005 vbox = gtk_vbox_new(FALSE, 5); | |
3006 gtk_paned_pack1(GTK_PANED(paned), vbox, FALSE, TRUE); | |
3007 gtk_widget_show(vbox); | |
3008 | |
3009 /* Setup the gtkimhtml widget. */ | |
3010 gtkconv->sw = gtk_scrolled_window_new(NULL, NULL); | |
3011 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(gtkconv->sw), | |
3012 GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); | |
3013 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(gtkconv->sw), | |
3014 GTK_SHADOW_IN); | |
3015 gtk_box_pack_start(GTK_BOX(vbox), gtkconv->sw, TRUE, TRUE, 0); | |
3016 gtk_widget_set_size_request(gtkconv->sw, conv_size.width, conv_size.height); | |
3017 gtk_widget_show(gtkconv->sw); | |
3018 | |
3019 gtkconv->imhtml = gtk_imhtml_new(NULL, NULL); | |
3020 gtk_container_add(GTK_CONTAINER(gtkconv->sw), gtkconv->imhtml); | |
3021 | |
3022 g_signal_connect_after(G_OBJECT(gtkconv->imhtml), "button_press_event", | |
3023 G_CALLBACK(entry_stop_rclick_cb), NULL); | |
3024 | |
3025 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), | |
3026 (convo_options & OPT_CONVO_SHOW_TIME)); | |
3027 | |
3028 gaim_setup_imhtml(gtkconv->imhtml); | |
3029 | |
3030 gtk_widget_show(gtkconv->imhtml); | |
3031 | |
3032 vbox2 = gtk_vbox_new(FALSE, 5); | |
3033 gtk_paned_pack2(GTK_PANED(paned), vbox2, FALSE, FALSE); | |
3034 gtk_widget_show(vbox2); | |
3035 | |
3036 /* Build the toolbar. */ | |
3037 gtkconv->toolbar.toolbar = build_conv_toolbar(conv); | |
3038 gtk_box_pack_start(GTK_BOX(vbox2), gtkconv->toolbar.toolbar, | |
3039 FALSE, FALSE, 0); | |
3040 | |
3041 /* Setup the entry widget. */ | |
3042 frame = gtk_frame_new(NULL); | |
3043 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); | |
3044 gtk_box_pack_start(GTK_BOX(vbox2), frame, TRUE, TRUE, 0); | |
3045 gtk_widget_show(frame); | |
3046 | |
3047 gtkconv->entry_buffer = gtk_text_buffer_new(NULL); | |
3048 g_object_set_data(G_OBJECT(gtkconv->entry_buffer), "user_data", conv); | |
3049 gtkconv->entry = gtk_text_view_new_with_buffer(gtkconv->entry_buffer); | |
3050 | |
3051 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(gtkconv->entry), GTK_WRAP_WORD); | |
3052 gtk_widget_set_size_request(gtkconv->entry, conv_size.width - 20, | |
3053 MAX(conv_size.entry_height, 25)); | |
3054 | |
3055 /* Connect the signal handlers. */ | |
3056 g_signal_connect_swapped(G_OBJECT(gtkconv->entry), "key_press_event", | |
3057 G_CALLBACK(entry_key_pressed_cb_1), | |
3058 gtkconv->entry_buffer); | |
3059 g_signal_connect(G_OBJECT(gtkconv->entry), "key_press_event", | |
3060 G_CALLBACK(entry_key_pressed_cb_2), conv); | |
3061 g_signal_connect_after(G_OBJECT(gtkconv->entry), "button_press_event", | |
3062 G_CALLBACK(entry_stop_rclick_cb), NULL); | |
3063 | |
3064 g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "insert_text", | |
3065 G_CALLBACK(insert_text_cb), conv); | |
3066 g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "delete_range", | |
3067 G_CALLBACK(delete_text_cb), conv); | |
3068 | |
3069 #ifdef USE_GTKSPELL | |
3070 if (convo_options & OPT_CONVO_CHECK_SPELLING) | |
3071 gtkspell_new_attach(GTK_TEXT_VIEW(gtkconv->entry), NULL, NULL); | |
3072 #endif | |
3073 | |
3074 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(gtkconv->entry)); | |
3075 gtk_widget_show(gtkconv->entry); | |
3076 | |
3077 gtkconv->bbox = gtk_hbox_new(FALSE, 5); | |
3078 gtk_box_pack_start(GTK_BOX(vbox2), gtkconv->bbox, FALSE, FALSE, 0); | |
3079 gtk_widget_show(gtkconv->bbox); | |
3080 | |
3081 setup_im_buttons(conv, gtkconv->bbox); | |
3082 | |
3083 return paned; | |
3084 } | |
3085 | |
3086 static void | |
3087 move_next_tab(struct gaim_conversation *conv) | |
3088 { | |
3089 struct gaim_conversation *next_conv = NULL; | |
3090 struct gaim_window *win; | |
3091 GList *l; | |
3092 int index, i; | |
3093 | |
3094 win = gaim_conversation_get_window(conv); | |
3095 index = gaim_conversation_get_index(conv); | |
3096 | |
3097 /* First check the tabs after this position. */ | |
3098 for (l = g_list_nth(gaim_window_get_conversations(win), index); | |
3099 l != NULL; | |
3100 l = l->next) { | |
3101 | |
3102 next_conv = (struct gaim_conversation *)l->data; | |
3103 | |
3104 if (gaim_conversation_get_unseen(next_conv) > 0) | |
3105 break; | |
3106 | |
3107 next_conv = NULL; | |
3108 } | |
3109 | |
3110 if (next_conv == NULL) { | |
3111 | |
3112 /* Now check before this position. */ | |
3113 for (l = gaim_window_get_conversations(win), i = 0; | |
3114 l != NULL && i < index; | |
3115 l = l->next) { | |
3116 | |
3117 next_conv = (struct gaim_conversation *)l->data; | |
3118 | |
3119 if (gaim_conversation_get_unseen(next_conv) > 0) | |
3120 break; | |
3121 | |
3122 next_conv = NULL; | |
3123 } | |
3124 | |
3125 if (next_conv == NULL) { | |
3126 /* Okay, just grab the next conversation tab. */ | |
3127 if (index == gaim_window_get_conversation_count(win) - 1) | |
3128 next_conv = gaim_window_get_conversation_at(win, 0); | |
3129 else | |
3130 next_conv = gaim_window_get_conversation_at(win, index + 1); | |
3131 } | |
3132 } | |
3133 | |
3134 if (next_conv != NULL && next_conv != conv) { | |
3135 gaim_window_switch_conversation(win, | |
3136 gaim_conversation_get_index(next_conv)); | |
3137 } | |
3138 } | |
3139 | |
3140 | |
3141 /************************************************************************** | |
3142 * GTK+ window ops | |
3143 **************************************************************************/ | |
3144 static struct gaim_conversation_ops * | |
3145 gaim_gtk_get_conversation_ops(void) | |
3146 { | |
3147 return gaim_get_gtk_conversation_ops(); | |
3148 } | |
3149 | |
3150 static void | |
3151 gaim_gtk_new_window(struct gaim_window *win) | |
3152 { | |
3153 struct gaim_gtk_window *gtkwin; | |
3154 GtkPositionType pos; | |
3155 GtkWidget *testidea; | |
3156 GtkWidget *menubar; | |
3157 | |
3158 gtkwin = g_malloc0(sizeof(struct gaim_gtk_window)); | |
3159 | |
3160 win->ui_data = gtkwin; | |
3161 | |
3162 /* Create the window. */ | |
3163 gtkwin->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
3164 gtk_window_set_role(GTK_WINDOW(gtkwin->window), "conversation"); | |
3165 gtk_window_set_policy(GTK_WINDOW(gtkwin->window), TRUE, TRUE, FALSE); | |
3166 gtk_container_border_width(GTK_CONTAINER(gtkwin->window), 0); | |
3167 gtk_widget_realize(gtkwin->window); | |
3168 gtk_window_set_title(GTK_WINDOW(gtkwin->window), _("Gaim - Conversations")); | |
3169 | |
3170 g_signal_connect(G_OBJECT(gtkwin->window), "delete_event", | |
3171 G_CALLBACK(close_win_cb), win); | |
3172 | |
3173 /* Create the notebook. */ | |
3174 gtkwin->notebook = gtk_notebook_new(); | |
3175 | |
3176 pos = ((im_options & OPT_IM_SIDE_TAB) | |
3177 ? ((im_options & OPT_IM_BR_TAB) ? GTK_POS_RIGHT : GTK_POS_LEFT) | |
3178 : ((im_options & OPT_IM_BR_TAB) ? GTK_POS_BOTTOM : GTK_POS_TOP)); | |
3179 | |
3180 #if 0 | |
3181 gtk_notebook_set_tab_hborder(GTK_NOTEBOOK(gtkwin->notebook), 0); | |
3182 gtk_notebook_set_tab_vborder(GTK_NOTEBOOK(gtkwin->notebook), 0); | |
3183 #endif | |
3184 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkwin->notebook), pos); | |
3185 gtk_notebook_set_scrollable(GTK_NOTEBOOK(gtkwin->notebook), TRUE); | |
3186 gtk_notebook_popup_enable(GTK_NOTEBOOK(gtkwin->notebook)); | |
3187 gtk_widget_show(gtkwin->notebook); | |
3188 | |
3189 g_signal_connect_after(G_OBJECT(gtkwin->notebook), "switch_page", | |
3190 G_CALLBACK(switch_conv_cb), win); | |
3191 | |
3192 /* Setup the tab drag and drop signals. */ | |
3193 gtk_widget_add_events(gtkwin->notebook, | |
3194 GDK_BUTTON1_MOTION_MASK | GDK_LEAVE_NOTIFY_MASK); | |
3195 g_signal_connect(G_OBJECT(gtkwin->notebook), "button_press_event", | |
3196 G_CALLBACK(notebook_press_cb), win); | |
3197 g_signal_connect(G_OBJECT(gtkwin->notebook), "button_release_event", | |
3198 G_CALLBACK(notebook_release_cb), win); | |
3199 | |
3200 testidea = gtk_vbox_new(FALSE, 0); | |
3201 | |
3202 /* Setup the menubar. */ | |
3203 menubar = setup_menubar(win); | |
3204 gtk_box_pack_start(GTK_BOX(testidea), menubar, FALSE, TRUE, 0); | |
3205 | |
3206 gtk_box_pack_start(GTK_BOX(testidea), gtkwin->notebook, TRUE, TRUE, 0); | |
3207 | |
3208 gtk_container_add(GTK_CONTAINER(gtkwin->window), testidea); | |
3209 | |
3210 gtk_widget_show(testidea); | |
3211 } | |
3212 | |
3213 static void | |
3214 gaim_gtk_destroy_window(struct gaim_window *win) | |
3215 { | |
3216 struct gaim_gtk_window *gtkwin = GAIM_GTK_WINDOW(win); | |
3217 | |
3218 gtk_widget_destroy(gtkwin->window); | |
3219 | |
3220 g_free(gtkwin); | |
3221 win->ui_data = NULL; | |
3222 } | |
3223 | |
3224 static void | |
3225 gaim_gtk_show(struct gaim_window *win) | |
3226 { | |
3227 struct gaim_gtk_window *gtkwin = GAIM_GTK_WINDOW(win); | |
3228 | |
3229 gtk_widget_show(gtkwin->window); | |
3230 } | |
3231 | |
3232 static void | |
3233 gaim_gtk_hide(struct gaim_window *win) | |
3234 { | |
3235 struct gaim_gtk_window *gtkwin = GAIM_GTK_WINDOW(win); | |
3236 | |
3237 gtk_widget_hide(gtkwin->window); | |
3238 } | |
3239 | |
3240 static void | |
3241 gaim_gtk_raise(struct gaim_window *win) | |
3242 { | |
3243 struct gaim_gtk_window *gtkwin = GAIM_GTK_WINDOW(win); | |
3244 | |
3245 gdk_window_raise(gtkwin->window->window); | |
3246 } | |
3247 | |
3248 static void | |
3249 gaim_gtk_flash(struct gaim_window *win) | |
3250 { | |
3251 #ifdef _WIN32 | |
3252 struct gaim_gtk_window *gtkwin = GAIM_GTK_WINDOW(win); | |
3253 | |
3254 wgaim_im_blink(gtkwin->window); | |
3255 #endif | |
3256 } | |
3257 | |
3258 static void | |
3259 gaim_gtk_switch_conversation(struct gaim_window *win, unsigned int index) | |
3260 { | |
3261 struct gaim_gtk_window *gtkwin; | |
3262 | |
3263 gtkwin = GAIM_GTK_WINDOW(win); | |
3264 | |
3265 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), index); | |
3266 } | |
3267 | |
3268 static void | |
3269 gaim_gtk_add_conversation(struct gaim_window *win, | |
3270 struct gaim_conversation *conv) | |
3271 { | |
3272 struct gaim_gtk_window *gtkwin; | |
3273 struct gaim_gtk_conversation *gtkconv; | |
3274 GtkWidget *pane = NULL; | |
3275 GtkWidget *tab_cont; | |
3276 GtkWidget *tabby; | |
3277 gboolean new_ui; | |
3278 | |
3279 gtkwin = GAIM_GTK_WINDOW(win); | |
3280 | |
3281 if (conv->ui_data != NULL) { | |
3282 gtkconv = (struct gaim_gtk_conversation *)conv->ui_data; | |
3283 | |
3284 tab_cont = gtkconv->tab_cont; | |
3285 | |
3286 new_ui = FALSE; | |
3287 } | |
3288 else { | |
3289 gtkconv = g_malloc0(sizeof(struct gaim_gtk_conversation)); | |
3290 conv->ui_data = gtkconv; | |
3291 | |
3292 /* Setup some initial variables. */ | |
3293 gtkconv->sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); | |
3294 gtkconv->tooltips = gtk_tooltips_new(); | |
3295 | |
3296 if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) { | |
3297 gtkconv->u.chat = g_malloc0(sizeof(struct gaim_gtk_chat_pane)); | |
3298 | |
3299 pane = setup_chat_pane(conv); | |
3300 } | |
3301 else if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) { | |
3302 gtkconv->u.im = g_malloc0(sizeof(struct gaim_gtk_im_pane)); | |
3303 gtkconv->u.im->a_virgin = TRUE; | |
3304 | |
3305 pane = setup_im_pane(conv); | |
3306 } | |
3307 | |
3308 if (pane == NULL) { | |
3309 if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) { | |
3310 g_free(gtkconv->u.chat); | |
3311 } | |
3312 else if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) { | |
3313 g_free(gtkconv->u.im); | |
3314 }; | |
3315 | |
3316 g_free(gtkconv); | |
3317 conv->ui_data = NULL; | |
3318 | |
3319 return; | |
3320 } | |
3321 | |
3322 /* Setup the container for the tab. */ | |
3323 gtkconv->tab_cont = tab_cont = gtk_vbox_new(FALSE, 5); | |
3324 gtk_container_set_border_width(GTK_CONTAINER(tab_cont), 5); | |
3325 gtk_container_add(GTK_CONTAINER(tab_cont), pane); | |
3326 gtk_widget_show(pane); | |
3327 | |
3328 new_ui = TRUE; | |
3329 | |
3330 gtkconv->make_sound = TRUE; | |
3331 } | |
3332 | |
3333 gtkconv->tabby = tabby = gtk_hbox_new(FALSE, 5); | |
3334 | |
3335 /* Close button. */ | |
3336 gtkconv->close = gtk_button_new(); | |
3337 gtk_widget_set_size_request(GTK_WIDGET(gtkconv->close), 16, 16); | |
3338 gtk_container_add(GTK_CONTAINER(gtkconv->close), | |
3339 gtk_image_new_from_stock(GTK_STOCK_CLOSE, | |
3340 GTK_ICON_SIZE_MENU)); | |
3341 gtk_button_set_relief(GTK_BUTTON(gtkconv->close), GTK_RELIEF_NONE); | |
3342 gtk_tooltips_set_tip(gtkconv->tooltips, gtkconv->close, | |
3343 _("Close conversation"), NULL); | |
3344 | |
3345 g_signal_connect(G_OBJECT(gtkconv->close), "clicked", | |
3346 G_CALLBACK(close_conv_cb), conv); | |
3347 | |
3348 /* Tab label. */ | |
3349 gtkconv->tab_label = gtk_label_new(gaim_conversation_get_title(conv)); | |
3350 #if 0 | |
3351 gtk_misc_set_alignment(GTK_MISC(gtkconv->tab_label), 0.00, 0.5); | |
3352 gtk_misc_set_padding(GTK_MISC(gtkconv->tab_label), 4, 0); | |
3353 #endif | |
3354 | |
3355 /* Pack it all together. */ | |
3356 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->tab_label, TRUE, TRUE, 0); | |
3357 gtk_box_pack_start(GTK_BOX(tabby), gtkconv->close, FALSE, FALSE, 0); | |
3358 gtk_widget_show_all(tabby); | |
3359 | |
3360 | |
3361 /* Add this pane to the conversations notebook. */ | |
3362 gtk_notebook_append_page(GTK_NOTEBOOK(gtkwin->notebook), tab_cont, tabby); | |
3363 gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(gtkwin->notebook), tab_cont, | |
3364 gaim_conversation_get_title(conv)); | |
3365 | |
3366 gtk_widget_show(tab_cont); | |
3367 | |
3368 /* Er, bug in notebooks? Switch to the page manually. */ | |
3369 if (gaim_window_get_conversation_count(win) == 1) | |
3370 gtk_notebook_set_current_page(GTK_NOTEBOOK(gtkwin->notebook), 0); | |
3371 | |
3372 debug_printf("*** Current page = %d\n", | |
3373 gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook))); | |
3374 | |
3375 if ((gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook)) == 0) || | |
3376 (conv == g_list_nth_data(gaim_window_get_conversations(win), 0))) { | |
3377 | |
3378 gtk_widget_grab_focus(gtkconv->entry); | |
3379 } | |
3380 | |
3381 gaim_gtkconv_update_buddy_icon(conv); | |
3382 | |
3383 if (!new_ui) | |
3384 g_object_unref(gtkconv->tab_cont); | |
3385 | |
3386 if (gaim_window_get_conversation_count(win) == 1) | |
3387 update_send_as_selection(win); | |
3388 } | |
3389 | |
3390 static void | |
3391 gaim_gtk_remove_conversation(struct gaim_window *win, | |
3392 struct gaim_conversation *conv) | |
3393 { | |
3394 struct gaim_gtk_window *gtkwin; | |
3395 struct gaim_gtk_conversation *gtkconv; | |
3396 unsigned int index; | |
3397 | |
3398 index = gaim_conversation_get_index(conv); | |
3399 | |
3400 gtkwin = GAIM_GTK_WINDOW(win); | |
3401 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3402 | |
3403 g_object_ref(gtkconv->tab_cont); | |
3404 gtk_object_sink(GTK_OBJECT(gtkconv->tab_cont)); | |
3405 | |
3406 gaim_gtk_set_state_lock(TRUE); | |
3407 | |
3408 gtk_notebook_remove_page(GTK_NOTEBOOK(gtkwin->notebook), index); | |
3409 | |
3410 gaim_gtk_set_state_lock(FALSE); | |
3411 | |
3412 /* If this window is setup with an inactive gc, regenerate the menu. */ | |
3413 debug_printf("remove_conv: user == %p\n", gaim_conversation_get_user(conv)); | |
3414 debug_printf("remove_conv: user->gc == %p\n", gaim_conversation_get_user(conv)->gc); | |
3415 debug_printf("remove_conv: gc == %p\n", gaim_conversation_get_gc(conv)); | |
3416 if (gaim_conversation_get_type(conv) == GAIM_CONV_IM && | |
3417 gaim_conversation_get_gc(conv) == NULL) { | |
3418 | |
3419 debug_printf("Going to generate send as items.\n"); | |
3420 generate_send_as_items(win); | |
3421 } | |
3422 } | |
3423 | |
3424 static void | |
3425 gaim_gtk_move_conversation(struct gaim_window *win, | |
3426 struct gaim_conversation *conv, | |
3427 unsigned int new_index) | |
3428 { | |
3429 struct gaim_gtk_window *gtkwin; | |
3430 struct gaim_gtk_conversation *gtkconv; | |
3431 | |
3432 gtkwin = GAIM_GTK_WINDOW(win); | |
3433 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3434 | |
3435 gtk_notebook_reorder_child(GTK_NOTEBOOK(gtkwin->notebook), | |
3436 gtkconv->tab_cont, new_index); | |
3437 } | |
3438 | |
3439 static int | |
3440 gaim_gtk_get_active_index(const struct gaim_window *win) | |
3441 { | |
3442 struct gaim_gtk_window *gtkwin; | |
3443 | |
3444 gtkwin = GAIM_GTK_WINDOW(win); | |
3445 | |
3446 return gtk_notebook_get_current_page(GTK_NOTEBOOK(gtkwin->notebook)); | |
3447 } | |
3448 | |
3449 static struct gaim_window_ops window_ops = | |
3450 { | |
3451 gaim_gtk_get_conversation_ops, | |
3452 gaim_gtk_new_window, | |
3453 gaim_gtk_destroy_window, | |
3454 gaim_gtk_show, | |
3455 gaim_gtk_hide, | |
3456 gaim_gtk_raise, | |
3457 gaim_gtk_flash, | |
3458 gaim_gtk_switch_conversation, | |
3459 gaim_gtk_add_conversation, | |
3460 gaim_gtk_remove_conversation, | |
3461 gaim_gtk_move_conversation, | |
3462 gaim_gtk_get_active_index | |
3463 }; | |
3464 | |
3465 static void | |
3466 update_convo_add_button(struct gaim_conversation *conv) | |
3467 { | |
3468 struct gaim_gtk_conversation *gtkconv; | |
3469 struct gaim_connection *gc; | |
3470 GaimConversationType type; | |
3471 GtkWidget *parent; | |
3472 gboolean rebuild = FALSE; | |
3473 | |
3474 type = gaim_conversation_get_type(conv); | |
3475 gc = gaim_conversation_get_gc(conv); | |
3476 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3477 parent = gtk_widget_get_parent(gtkconv->u.im->add); | |
3478 | |
3479 if (find_buddy(gc->user, gaim_conversation_get_name(conv))) { | |
3480 if (!g_object_get_data(G_OBJECT(gtkconv->u.im->add), "user_data")) { | |
3481 gtkconv->u.im->add = | |
3482 gaim_gtk_change_text(_("Remove"), gtkconv->u.im->add, | |
3483 GTK_STOCK_REMOVE, type); | |
3484 | |
3485 rebuild = TRUE; | |
3486 } | |
3487 | |
3488 gtk_widget_set_sensitive(gtkconv->u.im->add, | |
3489 (gc != NULL && gc->prpl->remove_buddy != NULL)); | |
3490 | |
3491 g_object_set_data(G_OBJECT(gtkconv->u.im->add), "user_data", conv); | |
3492 | |
3493 } else { | |
3494 if (g_object_get_data(G_OBJECT(gtkconv->u.im->add), "user_data")) { | |
3495 gtkconv->u.im->add = | |
3496 gaim_gtk_change_text(_("Add"), gtkconv->u.im->add, | |
3497 GTK_STOCK_ADD, type); | |
3498 | |
3499 rebuild = TRUE; | |
3500 } | |
3501 | |
3502 gtk_widget_set_sensitive(gtkconv->u.im->add, | |
3503 (gc != NULL && gc->prpl->add_buddy != NULL)); | |
3504 } | |
3505 | |
3506 if (rebuild) { | |
3507 g_signal_connect(G_OBJECT(gtkconv->u.im->add), "clicked", | |
3508 G_CALLBACK(add_cb), conv); | |
3509 | |
3510 gtk_box_pack_start(GTK_BOX(parent), gtkconv->u.im->add, | |
3511 FALSE, FALSE, 0); | |
3512 gtk_box_reorder_child(GTK_BOX(parent), gtkconv->u.im->add, 3); | |
3513 gtk_button_set_relief(GTK_BUTTON(gtkconv->u.im->add), GTK_RELIEF_NONE); | |
3514 gtk_size_group_add_widget(gtkconv->sg, gtkconv->u.im->add); | |
3515 } | |
3516 } | |
3517 | |
3518 struct gaim_window_ops * | |
3519 gaim_get_gtk_window_ops(void) | |
3520 { | |
3521 return &window_ops; | |
3522 } | |
3523 | |
3524 /************************************************************************** | |
3525 * Conversation ops | |
3526 **************************************************************************/ | |
3527 static void | |
3528 gaim_gtkconv_destroy(struct gaim_conversation *conv) | |
3529 { | |
3530 struct gaim_gtk_conversation *gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3531 | |
3532 if (gtkconv->dialogs.fg_color != NULL) | |
3533 gtk_widget_destroy(gtkconv->dialogs.fg_color); | |
3534 | |
3535 if (gtkconv->dialogs.bg_color != NULL) | |
3536 gtk_widget_destroy(gtkconv->dialogs.bg_color); | |
3537 | |
3538 if (gtkconv->dialogs.font != NULL) | |
3539 gtk_widget_destroy(gtkconv->dialogs.font); | |
3540 | |
3541 if (gtkconv->dialogs.smiley != NULL) | |
3542 gtk_widget_destroy(gtkconv->dialogs.smiley); | |
3543 | |
3544 if (gtkconv->dialogs.link != NULL) | |
3545 gtk_widget_destroy(gtkconv->dialogs.link); | |
3546 | |
3547 if (gtkconv->dialogs.log != NULL) | |
3548 gtk_widget_destroy(gtkconv->dialogs.log); | |
3549 | |
3550 if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) { | |
3551 if (gtkconv->u.im->save_icon != NULL) | |
3552 gtk_widget_destroy(gtkconv->u.im->save_icon); | |
3553 | |
3554 if (gtkconv->u.im->anim != NULL) | |
3555 gdk_pixbuf_animation_unref(gtkconv->u.im->anim); | |
3556 | |
3557 g_free(gtkconv->u.im); | |
3558 } | |
3559 else if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) { | |
3560 g_free(gtkconv->u.chat); | |
3561 } | |
3562 | |
3563 g_free(gtkconv); | |
3564 } | |
3565 | |
3566 static void | |
3567 gaim_gtkconv_write_im(struct gaim_conversation *conv, const char *who, | |
3568 const char *message, size_t len, int flags, time_t mtime) | |
3569 { | |
3570 struct gaim_gtk_conversation *gtkconv; | |
3571 | |
3572 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3573 | |
3574 debug_printf("Write IM\n"); | |
3575 | |
3576 if (gtkconv->make_sound) { | |
3577 if (flags & WFLAG_RECV) { | |
3578 if (gtkconv->u.im->a_virgin && | |
3579 (sound_options & OPT_SOUND_FIRST_RCV)) { | |
3580 | |
3581 play_sound(SND_FIRST_RECEIVE); | |
3582 } | |
3583 else | |
3584 play_sound(SND_RECEIVE); | |
3585 } | |
3586 else { | |
3587 debug_printf("Playing SND_SEND\n"); | |
3588 play_sound(SND_SEND); | |
3589 } | |
3590 } | |
3591 | |
3592 gtkconv->u.im->a_virgin = FALSE; | |
3593 | |
3594 gaim_conversation_write(conv, who, message, len, flags, mtime); | |
3595 } | |
3596 | |
3597 static void | |
3598 gaim_gtkconv_write_chat(struct gaim_conversation *conv, const char *who, | |
3599 const char *message, int flags, time_t mtime) | |
3600 { | |
3601 struct gaim_gtk_conversation *gtkconv; | |
3602 | |
3603 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3604 | |
3605 if (gtkconv->make_sound) { | |
3606 if (!(flags & WFLAG_WHISPER) && (flags & WFLAG_SEND)) | |
3607 play_sound(SND_CHAT_YOU_SAY); | |
3608 else if (flags & WFLAG_RECV) { | |
3609 if ((flags & WFLAG_NICK) && (sound_options & OPT_SOUND_CHAT_NICK)) | |
3610 play_sound(SND_CHAT_NICK); | |
3611 else | |
3612 play_sound(SND_CHAT_SAY); | |
3613 } | |
3614 } | |
3615 | |
3616 if (chat_options & OPT_CHAT_COLORIZE) | |
3617 flags |= WFLAG_COLORIZE; | |
3618 | |
3619 gaim_conversation_write(conv, who, message, -1, flags, mtime); | |
3620 } | |
3621 | |
3622 static void | |
3623 gaim_gtkconv_write_conv(struct gaim_conversation *conv, const char *who, | |
3624 const char *message, size_t length, int flags, | |
3625 time_t mtime) | |
3626 { | |
3627 struct gaim_gtk_conversation *gtkconv; | |
3628 struct gaim_connection *gc; | |
3629 int gtk_font_options = 0; | |
3630 GString *log_str; | |
3631 FILE *fd; | |
3632 char buf[BUF_LONG]; | |
3633 char buf2[BUF_LONG]; | |
3634 char mdate[64]; | |
3635 char color[10]; | |
3636 char *str; | |
3637 char *with_font_tag; | |
3638 | |
3639 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3640 gc = gaim_conversation_get_gc(conv); | |
3641 | |
3642 strftime(mdate, sizeof(mdate), "%H:%M:%S", localtime(&mtime)); | |
3643 | |
3644 gtk_font_options ^= GTK_IMHTML_NO_COMMENTS; | |
3645 | |
3646 if (convo_options & OPT_CONVO_IGNORE_COLOUR) | |
3647 gtk_font_options ^= GTK_IMHTML_NO_COLOURS; | |
3648 | |
3649 if (convo_options & OPT_CONVO_IGNORE_FONTS) | |
3650 gtk_font_options ^= GTK_IMHTML_NO_FONTS; | |
3651 | |
3652 if (convo_options & OPT_CONVO_IGNORE_SIZES) | |
3653 gtk_font_options ^= GTK_IMHTML_NO_SIZES; | |
3654 | |
3655 if (!(logging_options & OPT_LOG_STRIP_HTML)) | |
3656 gtk_font_options ^= GTK_IMHTML_RETURN_LOG; | |
3657 | |
3658 if (flags & WFLAG_SYSTEM) { | |
3659 if (convo_options & OPT_CONVO_SHOW_TIME) | |
3660 g_snprintf(buf, BUF_LONG, "<FONT SIZE=\"2\">(%s) </FONT><B>%s</B>", | |
3661 mdate, message); | |
3662 else | |
3663 g_snprintf(buf, BUF_LONG, "<B>%s</B>", message); | |
3664 | |
3665 g_snprintf(buf2, sizeof(buf2), | |
3666 "<FONT SIZE=\"2\"><!--(%s) --></FONT><B>%s</B><BR>", | |
3667 mdate, message); | |
3668 | |
3669 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, -1, 0); | |
3670 | |
3671 if (logging_options & OPT_LOG_STRIP_HTML) { | |
3672 char *t1 = strip_html(buf); | |
3673 | |
3674 conv->history = g_string_append(conv->history, t1); | |
3675 conv->history = g_string_append(conv->history, "\n"); | |
3676 | |
3677 g_free(t1); | |
3678 } | |
3679 else { | |
3680 conv->history = g_string_append(conv->history, buf); | |
3681 conv->history = g_string_append(conv->history, "<BR>\n"); | |
3682 } | |
3683 | |
3684 if (!(flags & WFLAG_NOLOG) && gaim_conversation_is_logging(conv)) { | |
3685 /* | |
3686 XXX | |
3687 ((gaim_conversation_get_type(conv) == GAIM_CONV_CHAT && | |
3688 (logging_options & OPT_LOG_CHATS)) || | |
3689 (gaim_conversation_get_type(conv) == GAIM_CONV_IM && | |
3690 (logging_options & OPT_LOG_CONVOS)) || | |
3691 find_log_info(gaim_conversation_get_name(conv)))) { | |
3692 */ | |
3693 | |
3694 char *t1; | |
3695 char nm[256]; | |
3696 | |
3697 if (logging_options & OPT_LOG_STRIP_HTML) | |
3698 t1 = strip_html(buf); | |
3699 else | |
3700 t1 = buf; | |
3701 | |
3702 if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) | |
3703 g_snprintf(nm, sizeof(nm), "%s.chat", | |
3704 gaim_conversation_get_name(conv)); | |
3705 else | |
3706 strncpy(nm, gaim_conversation_get_name(conv), sizeof(nm)); | |
3707 | |
3708 fd = open_log_file(nm, | |
3709 (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT)); | |
3710 | |
3711 if (fd) { | |
3712 if (logging_options & OPT_LOG_STRIP_HTML) | |
3713 fprintf(fd, "%s\n", t1); | |
3714 else | |
3715 fprintf(fd, "%s<BR>\n", t1); | |
3716 | |
3717 fclose(fd); | |
3718 } | |
3719 | |
3720 if (logging_options & OPT_LOG_STRIP_HTML) | |
3721 g_free(t1); | |
3722 } | |
3723 } | |
3724 else if (flags & WFLAG_NOLOG) { | |
3725 g_snprintf(buf, BUF_LONG, | |
3726 "<B><FONT COLOR=\"#777777\">%s</FONT></B><BR>", | |
3727 message); | |
3728 | |
3729 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf, -1, 0); | |
3730 } | |
3731 else { | |
3732 char *new_message = g_strdup(message); | |
3733 | |
3734 if (flags & WFLAG_WHISPER) { | |
3735 str = g_malloc(1024); | |
3736 | |
3737 /* If we're whispering, it's not an autoresponse. */ | |
3738 if (meify(new_message, length)) { | |
3739 g_snprintf(str, 1024, "***%s", who); | |
3740 strcpy(color, "#6C2585"); | |
3741 } | |
3742 else { | |
3743 g_snprintf(str, 1024, "*%s*:", who); | |
3744 strcpy(color, "#00FF00"); | |
3745 } | |
3746 } | |
3747 else { | |
3748 if (meify(new_message, length)) { | |
3749 str = g_malloc(1024); | |
3750 | |
3751 if (flags & WFLAG_AUTO) | |
3752 g_snprintf(str, 1024, "%s ***%s", AUTO_RESPONSE, who); | |
3753 else | |
3754 g_snprintf(str, 1024, "***%s", who); | |
3755 | |
3756 if (flags & WFLAG_NICK) | |
3757 strcpy(color, "#AF7F00"); | |
3758 else | |
3759 strcpy(color, "#062585"); | |
3760 } | |
3761 else { | |
3762 str = g_malloc(1024); | |
3763 | |
3764 if (flags & WFLAG_AUTO) | |
3765 g_snprintf(str, 1024, "%s %s", who, AUTO_RESPONSE); | |
3766 else | |
3767 g_snprintf(str, 1024, "%s:", who); | |
3768 | |
3769 if (flags & WFLAG_NICK) | |
3770 strcpy(color, "#AF7F00"); | |
3771 else if (flags & WFLAG_RECV) { | |
3772 if (flags & WFLAG_COLORIZE) { | |
3773 const char *u; | |
3774 int m = 0; | |
3775 | |
3776 for (u = who; *u != '\0'; u++) | |
3777 m += *u; | |
3778 | |
3779 m = m % NUM_NICK_COLORS; | |
3780 | |
3781 strcpy(color, nick_colors[m]); | |
3782 } | |
3783 else | |
3784 strcpy(color, "#A82F2F"); | |
3785 } | |
3786 else if (flags & WFLAG_SEND) | |
3787 strcpy(color, "#16569E"); | |
3788 } | |
3789 } | |
3790 | |
3791 if (convo_options & OPT_CONVO_SHOW_TIME) | |
3792 g_snprintf(buf, BUF_LONG, | |
3793 "<FONT COLOR=\"%s\"><FONT SIZE=\"2\">(%s) </FONT>" | |
3794 "<B>%s</B></FONT> ", color, mdate, str); | |
3795 else | |
3796 g_snprintf(buf, BUF_LONG, | |
3797 "<FONT COLOR=\"%s\"><B>%s</B></FONT> ", color, str); | |
3798 | |
3799 g_snprintf(buf2, BUF_LONG, | |
3800 "<FONT COLOR=\"%s\"><FONT SIZE=\"2\"><!--(%s) --></FONT>" | |
3801 "<B>%s</B></FONT> ", | |
3802 color, mdate, str); | |
3803 | |
3804 g_free(str); | |
3805 | |
3806 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), buf2, -1, 0); | |
3807 | |
3808 with_font_tag = g_strdup_printf("<font sml=\"%s\">%s</font>", | |
3809 gc->prpl->name, new_message); | |
3810 | |
3811 log_str = gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), | |
3812 with_font_tag, length, | |
3813 gtk_font_options); | |
3814 | |
3815 gtk_imhtml_append_text(GTK_IMHTML(gtkconv->imhtml), "<BR>", -1, 0); | |
3816 | |
3817 /* XXX This needs to be updated for the new length argument. */ | |
3818 if (logging_options & OPT_LOG_STRIP_HTML) { | |
3819 char *t1, *t2; | |
3820 | |
3821 t1 = strip_html(buf); | |
3822 t2 = strip_html(new_message); | |
3823 | |
3824 conv->history = g_string_append(conv->history, t1); | |
3825 conv->history = g_string_append(conv->history, t2); | |
3826 conv->history = g_string_append(conv->history, "\n"); | |
3827 | |
3828 g_free(t1); | |
3829 g_free(t2); | |
3830 } | |
3831 else { | |
3832 char *t1, *t2; | |
3833 | |
3834 t1 = html_logize(buf); | |
3835 t2 = html_logize(new_message); | |
3836 | |
3837 conv->history = g_string_append(conv->history, t1); | |
3838 conv->history = g_string_append(conv->history, t2); | |
3839 conv->history = g_string_append(conv->history, "\n"); | |
3840 conv->history = g_string_append(conv->history, log_str->str); | |
3841 conv->history = g_string_append(conv->history, "<BR>\n"); | |
3842 | |
3843 g_free(t1); | |
3844 g_free(t2); | |
3845 } | |
3846 | |
3847 /* XXX This needs to be updated for the new length argument. */ | |
3848 if (gaim_conversation_is_logging(conv)) { | |
3849 /* | |
3850 XXX | |
3851 if ((gaim_conversation_get_type(conv) == GAIM_CONV_CHAT && | |
3852 (logging_options & OPT_LOG_CHATS)) || | |
3853 (gaim_conversation_get_type(conv) == GAIM_CONV_IM && | |
3854 (logging_options & OPT_LOG_CONVOS)) || | |
3855 find_log_info(gaim_conversation_get_name(conv))) { | |
3856 */ | |
3857 | |
3858 char *t1, *t2; | |
3859 char nm[256]; | |
3860 | |
3861 if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) | |
3862 g_snprintf(nm, sizeof(nm), "%s.chat", | |
3863 gaim_conversation_get_name(conv)); | |
3864 else | |
3865 strncpy(nm, gaim_conversation_get_name(conv), sizeof(nm)); | |
3866 | |
3867 if (logging_options & OPT_LOG_STRIP_HTML) { | |
3868 t1 = strip_html(buf); | |
3869 t2 = strip_html(with_font_tag); | |
3870 } | |
3871 else { | |
3872 t1 = html_logize(buf); | |
3873 t2 = html_logize(with_font_tag); | |
3874 } | |
3875 | |
3876 fd = open_log_file(nm, | |
3877 (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT)); | |
3878 | |
3879 if (fd) { | |
3880 if (logging_options & OPT_LOG_STRIP_HTML) | |
3881 fprintf(fd, "%s%s\n", t1, t2); | |
3882 else { | |
3883 fprintf(fd, "%s%s%s<BR>\n", t1, t2, log_str->str); | |
3884 g_string_free(log_str, TRUE); | |
3885 } | |
3886 | |
3887 fclose(fd); | |
3888 } | |
3889 | |
3890 g_free(t1); | |
3891 g_free(t2); | |
3892 } | |
3893 | |
3894 g_free(with_font_tag); | |
3895 g_free(new_message); | |
3896 } | |
3897 } | |
3898 | |
3899 static void | |
3900 gaim_gtkconv_chat_add_user(struct gaim_conversation *conv, const char *user) | |
3901 { | |
3902 struct gaim_chat *chat; | |
3903 struct gaim_gtk_conversation *gtkconv; | |
3904 struct gaim_gtk_chat_pane *gtkchat; | |
3905 char tmp[BUF_LONG]; | |
3906 int num_users; | |
3907 int pos; | |
3908 | |
3909 chat = GAIM_CHAT(conv); | |
3910 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3911 gtkchat = gtkconv->u.chat; | |
3912 | |
3913 num_users = g_list_length(gaim_chat_get_users(chat)); | |
3914 | |
3915 g_snprintf(tmp, sizeof(tmp), | |
3916 ngettext("%d person in room", "%d people in room", | |
3917 num_users), | |
3918 num_users); | |
3919 | |
3920 gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp); | |
3921 | |
3922 if (gtkconv->make_sound) | |
3923 play_sound(SND_CHAT_JOIN); | |
3924 | |
3925 pos = g_list_index(gaim_chat_get_users(chat), user); | |
3926 | |
3927 add_chat_buddy_common(conv, user, pos); | |
3928 } | |
3929 | |
3930 static void | |
3931 gaim_gtkconv_chat_rename_user(struct gaim_conversation *conv, | |
3932 const char *old_name, const char *new_name) | |
3933 { | |
3934 struct gaim_chat *chat; | |
3935 struct gaim_gtk_conversation *gtkconv; | |
3936 struct gaim_gtk_chat_pane *gtkchat; | |
3937 GtkTreeIter iter; | |
3938 GtkTreeModel *model; | |
3939 GList *names; | |
3940 int pos; | |
3941 int f = 1; | |
3942 | |
3943 chat = GAIM_CHAT(conv); | |
3944 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3945 gtkchat = gtkconv->u.chat; | |
3946 | |
3947 for (names = gaim_chat_get_users(chat); | |
3948 names != NULL; | |
3949 names = names->next) { | |
3950 | |
3951 char *u = (char *)names->data; | |
3952 | |
3953 if (!g_strcasecmp(u, old_name)) { | |
3954 model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); | |
3955 | |
3956 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) | |
3957 break; | |
3958 | |
3959 while (f != 0) { | |
3960 char *val; | |
3961 | |
3962 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &val, -1); | |
3963 | |
3964 if (!g_strcasecmp(old_name, val)) | |
3965 gtk_list_store_remove(GTK_LIST_STORE(model), &iter); | |
3966 | |
3967 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); | |
3968 | |
3969 g_free(val); | |
3970 } | |
3971 | |
3972 break; | |
3973 } | |
3974 } | |
3975 | |
3976 if (!names) | |
3977 return; | |
3978 | |
3979 pos = g_list_index(gaim_chat_get_users(chat), new_name); | |
3980 | |
3981 add_chat_buddy_common(conv, new_name, pos); | |
3982 } | |
3983 | |
3984 static void | |
3985 gaim_gtkconv_chat_remove_user(struct gaim_conversation *conv, const char *user) | |
3986 { | |
3987 struct gaim_chat *chat; | |
3988 struct gaim_gtk_conversation *gtkconv; | |
3989 struct gaim_gtk_chat_pane *gtkchat; | |
3990 GtkTreeIter iter; | |
3991 GtkTreeModel *model; | |
3992 GList *names; | |
3993 char tmp[BUF_LONG]; | |
3994 int num_users; | |
3995 int f = 1; | |
3996 | |
3997 chat = GAIM_CHAT(conv); | |
3998 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
3999 gtkchat = gtkconv->u.chat; | |
4000 | |
4001 num_users = g_list_length(gaim_chat_get_users(chat)) - 1; | |
4002 | |
4003 for (names = gaim_chat_get_users(chat); | |
4004 names != NULL; | |
4005 names = names->next) { | |
4006 | |
4007 char *u = (char *)names->data; | |
4008 | |
4009 if (!g_strcasecmp(u, user)) { | |
4010 model = gtk_tree_view_get_model(GTK_TREE_VIEW(gtkchat->list)); | |
4011 | |
4012 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(model), &iter)) | |
4013 break; | |
4014 | |
4015 while (f != 0) { | |
4016 char *val; | |
4017 | |
4018 gtk_tree_model_get(GTK_TREE_MODEL(model), &iter, 1, &val, -1); | |
4019 | |
4020 if (!g_strcasecmp(user, val)) | |
4021 gtk_list_store_remove(GTK_LIST_STORE(model), &iter); | |
4022 | |
4023 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(model), &iter); | |
4024 | |
4025 g_free(val); | |
4026 } | |
4027 | |
4028 break; | |
4029 } | |
4030 } | |
4031 | |
4032 if (names == NULL) | |
4033 return; | |
4034 | |
4035 g_snprintf(tmp, sizeof(tmp), | |
4036 ngettext("%d person in room", "%d people in room", | |
4037 num_users), num_users); | |
4038 | |
4039 gtk_label_set_text(GTK_LABEL(gtkchat->count), tmp); | |
4040 | |
4041 if (gtkconv->make_sound) | |
4042 play_sound(SND_CHAT_LEAVE); | |
4043 } | |
4044 | |
4045 static void | |
4046 gaim_gtkconv_set_title(struct gaim_conversation *conv, const char *title) | |
4047 { | |
4048 struct gaim_gtk_conversation *gtkconv; | |
4049 | |
4050 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4051 | |
4052 gtk_label_set_text(GTK_LABEL(gtkconv->tab_label), title); | |
4053 } | |
4054 | |
4055 static void | |
4056 gaim_gtkconv_updated(struct gaim_conversation *conv, GaimConvUpdateType type) | |
4057 { | |
4058 struct gaim_window *win; | |
4059 struct gaim_gtk_conversation *gtkconv; | |
4060 struct gaim_gtk_chat_pane *gtkchat; | |
4061 struct gaim_chat *chat; | |
4062 | |
4063 win = gaim_conversation_get_window(conv); | |
4064 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4065 | |
4066 if (type == GAIM_CONV_UPDATE_USER) { | |
4067 gaim_conversation_autoset_title(conv); | |
4068 gaim_gtkconv_update_buddy_icon(conv); | |
4069 gaim_gtkconv_update_buttons_by_protocol(conv); | |
4070 | |
4071 update_send_as_selection(win); | |
4072 | |
4073 smiley_themeize(gtkconv->imhtml); | |
4074 } | |
4075 else if (type == GAIM_CONV_UPDATE_TYPING || | |
4076 type == GAIM_CONV_UPDATE_UNSEEN) { | |
4077 | |
4078 GtkStyle *style; | |
4079 struct gaim_im *im = NULL; | |
4080 | |
4081 if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) | |
4082 im = GAIM_IM(conv); | |
4083 | |
4084 style = gtk_style_new(); | |
4085 | |
4086 if (!GTK_WIDGET_REALIZED(gtkconv->tab_label)) | |
4087 gtk_widget_realize(gtkconv->tab_label); | |
4088 | |
4089 gtk_style_set_font(style, | |
4090 gdk_font_ref(gtk_style_get_font(gtk_widget_get_style( | |
4091 gtkconv->tab_label)))); | |
4092 | |
4093 if (im != NULL && gaim_im_get_typing_state(im) == TYPING) { | |
4094 style->fg[0].red = 0x0000; | |
4095 style->fg[0].green = 0x9999; | |
4096 style->fg[0].blue = 0x0000; | |
4097 } | |
4098 else if (im != NULL && gaim_im_get_typing_state(im) == TYPED) { | |
4099 style->fg[0].red = 0xFFFF; | |
4100 style->fg[0].green = 0xBBBB; | |
4101 style->fg[0].blue = 0x2222; | |
4102 } | |
4103 else if (gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_NICK) { | |
4104 style->fg[0].red = 0x0000; | |
4105 style->fg[0].green = 0x0000; | |
4106 style->fg[0].blue = 0xCCCC; | |
4107 } | |
4108 else if (gaim_conversation_get_unseen(conv) == GAIM_UNSEEN_TEXT) { | |
4109 style->fg[0].red = 0xCCCC; | |
4110 style->fg[0].green = 0x0000; | |
4111 style->fg[0].blue = 0x0000; | |
4112 } | |
4113 | |
4114 gtk_widget_set_style(gtkconv->tab_label, style); | |
4115 gtk_style_unref(style); | |
4116 } | |
4117 else if (type == GAIM_CONV_UPDATE_TOPIC) { | |
4118 chat = GAIM_CHAT(conv); | |
4119 gtkchat = gtkconv->u.chat; | |
4120 | |
4121 gtk_entry_set_text(GTK_ENTRY(gtkchat->topic_text), | |
4122 gaim_chat_get_topic(chat)); | |
4123 } | |
4124 else if (type == GAIM_CONV_ACCOUNT_ONLINE || | |
4125 type == GAIM_CONV_ACCOUNT_OFFLINE) { | |
4126 | |
4127 generate_send_as_items(win); | |
4128 } | |
4129 } | |
4130 | |
4131 static struct gaim_conversation_ops conversation_ops = | |
4132 { | |
4133 gaim_gtkconv_destroy, /* destroy_conversation */ | |
4134 gaim_gtkconv_write_chat, /* write_chat */ | |
4135 gaim_gtkconv_write_im, /* write_im */ | |
4136 gaim_gtkconv_write_conv, /* write_conv */ | |
4137 gaim_gtkconv_chat_add_user, /* chat_add_user */ | |
4138 gaim_gtkconv_chat_rename_user, /* chat_rename_user */ | |
4139 gaim_gtkconv_chat_remove_user, /* chat_remove_user */ | |
4140 gaim_gtkconv_set_title, /* set_title */ | |
4141 NULL, /* update_progress */ | |
4142 gaim_gtkconv_updated /* updated */ | |
4143 }; | |
4144 | |
4145 struct gaim_conversation_ops * | |
4146 gaim_get_gtk_conversation_ops(void) | |
4147 { | |
4148 return &conversation_ops;; | |
4149 } | |
4150 | |
4151 /************************************************************************** | |
4152 * Public conversation utility functions | |
4153 **************************************************************************/ | |
4154 void | |
4155 gaim_gtk_set_state_lock(gboolean lock) | |
4156 { | |
4157 state_lock = lock; | |
4158 } | |
4159 | |
4160 gboolean | |
4161 gaim_gtk_is_state_locked(void) | |
4162 { | |
4163 return state_lock; | |
4164 } | |
4165 | |
4166 void | |
4167 gaim_gtkconv_toggle_smileys(void) | |
4168 { | |
4169 GList *cl; | |
4170 struct gaim_conversation *conv; | |
4171 struct gaim_gtk_conversation *gtkconv; | |
4172 | |
4173 for (cl = gaim_get_conversations(); cl != NULL; cl = cl->next) { | |
4174 | |
4175 conv = (struct gaim_conversation *)cl->data; | |
4176 | |
4177 if (gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops()) | |
4178 continue; | |
4179 | |
4180 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4181 | |
4182 gtk_imhtml_show_smileys(GTK_IMHTML(gtkconv->imhtml), | |
4183 (convo_options & OPT_CONVO_SHOW_SMILEY)); | |
4184 } | |
4185 } | |
4186 | |
4187 void | |
4188 gaim_gtkconv_toggle_timestamps(void) | |
4189 { | |
4190 GList *cl; | |
4191 struct gaim_conversation *conv; | |
4192 struct gaim_gtk_conversation *gtkconv; | |
4193 | |
4194 for (cl = gaim_get_conversations(); cl != NULL; cl = cl->next) { | |
4195 | |
4196 conv = (struct gaim_conversation *)cl->data; | |
4197 | |
4198 if (gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops()) | |
4199 continue; | |
4200 | |
4201 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4202 | |
4203 gtk_imhtml_show_comments(GTK_IMHTML(gtkconv->imhtml), | |
4204 (convo_options & OPT_CONVO_SHOW_TIME)); | |
4205 } | |
4206 } | |
4207 | |
4208 void | |
4209 gaim_gtkconv_toggle_spellchk(void) | |
4210 { | |
4211 #ifdef USE_GTKSPELL | |
4212 GList *cl; | |
4213 struct gaim_conversation *conv; | |
4214 struct gaim_gtk_conversation *gtkconv; | |
4215 GtkSpell *spell; | |
4216 | |
4217 for (cl = gaim_get_conversations(); cl != NULL; cl = cl->next) { | |
4218 | |
4219 conv = (struct gaim_conversation *)cl->data; | |
4220 | |
4221 if (gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops()) | |
4222 continue; | |
4223 | |
4224 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4225 | |
4226 if (convo_options & OPT_CONVO_CHECK_SPELLING) | |
4227 gtkspell_new_attach(GTK_TEXT_VIEW(gtkconv->entry), NULL, NULL); | |
4228 else { | |
4229 spell = gtkspell_get_from_text_view(GTK_TEXT_VIEW(gtkconv->entry)); | |
4230 gtkspell_detach(spell); | |
4231 } | |
4232 } | |
4233 #endif | |
4234 } | |
4235 | |
4236 static void | |
4237 remove_icon(struct gaim_gtk_conversation *gtkconv) | |
4238 { | |
4239 if (gtkconv == NULL) | |
4240 return; | |
4241 | |
4242 if (gtkconv->u.im->icon != NULL) | |
4243 gtk_container_remove(GTK_CONTAINER(gtkconv->bbox), | |
4244 gtkconv->u.im->icon->parent->parent); | |
4245 | |
4246 if (gtkconv->u.im->anim != NULL) | |
4247 gdk_pixbuf_animation_unref(gtkconv->u.im->anim); | |
4248 | |
4249 if (gtkconv->u.im->icon_timer != 0) | |
4250 g_source_remove(gtkconv->u.im->icon_timer); | |
4251 | |
4252 if (gtkconv->u.im->iter != NULL) | |
4253 g_object_unref(G_OBJECT(gtkconv->u.im->iter)); | |
4254 | |
4255 gtkconv->u.im->icon_timer = 0; | |
4256 gtkconv->u.im->icon = NULL; | |
4257 gtkconv->u.im->anim = NULL; | |
4258 gtkconv->u.im->iter = NULL; | |
4259 } | |
4260 | |
4261 static gboolean | |
4262 redraw_icon(gpointer data) | |
4263 { | |
4264 struct gaim_conversation *conv = (struct gaim_conversation *)data; | |
4265 struct gaim_gtk_conversation *gtkconv; | |
4266 | |
4267 GdkPixbuf *buf; | |
4268 GdkPixbuf *scale; | |
4269 GdkPixmap *pm; | |
4270 GdkBitmap *bm; | |
4271 gint delay; | |
4272 | |
4273 if (!g_list_find(gaim_get_ims(), conv)) { | |
4274 debug_printf("I think this is a bug.\n"); | |
4275 return FALSE; | |
4276 } | |
4277 | |
4278 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4279 | |
4280 gdk_pixbuf_animation_iter_advance(gtkconv->u.im->iter, NULL); | |
4281 buf = gdk_pixbuf_animation_iter_get_pixbuf(gtkconv->u.im->iter); | |
4282 | |
4283 scale = gdk_pixbuf_scale_simple(buf, | |
4284 MAX(gdk_pixbuf_get_width(buf) * SCALE(gtkconv->u.im->anim) / | |
4285 gdk_pixbuf_animation_get_width(gtkconv->u.im->anim), 1), | |
4286 MAX(gdk_pixbuf_get_height(buf) * SCALE(gtkconv->u.im->anim) / | |
4287 gdk_pixbuf_animation_get_height(gtkconv->u.im->anim), 1), | |
4288 GDK_INTERP_NEAREST); | |
4289 | |
4290 gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 100); | |
4291 gdk_pixbuf_unref(scale); | |
4292 gtk_pixmap_set(GTK_PIXMAP(gtkconv->u.im->icon), pm, bm); | |
4293 gdk_pixmap_unref(pm); | |
4294 gtk_widget_queue_draw(gtkconv->u.im->icon); | |
4295 | |
4296 if (bm) | |
4297 gdk_bitmap_unref(bm); | |
4298 | |
4299 delay = gdk_pixbuf_animation_iter_get_delay_time(gtkconv->u.im->iter) / 10; | |
4300 | |
4301 gtkconv->u.im->icon_timer = g_timeout_add(delay * 10, redraw_icon, conv); | |
4302 | |
4303 return FALSE; | |
4304 } | |
4305 | |
4306 static void | |
4307 start_anim(GtkObject *obj, struct gaim_conversation *conv) | |
4308 { | |
4309 struct gaim_gtk_conversation *gtkconv; | |
4310 int delay; | |
4311 | |
4312 if (gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops()) | |
4313 return; | |
4314 | |
4315 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4316 | |
4317 delay = gdk_pixbuf_animation_iter_get_delay_time(gtkconv->u.im->iter) / 10; | |
4318 | |
4319 if (gtkconv->u.im->anim) | |
4320 gtkconv->u.im->icon_timer = g_timeout_add(delay * 10, redraw_icon, | |
4321 conv); | |
4322 } | |
4323 | |
4324 static void | |
4325 stop_anim(GtkObject *obj, struct gaim_conversation *conv) | |
4326 { | |
4327 struct gaim_gtk_conversation *gtkconv; | |
4328 | |
4329 if (gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops()) | |
4330 return; | |
4331 | |
4332 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4333 | |
4334 if (gtkconv->u.im->icon_timer != 0) | |
4335 g_source_remove(gtkconv->u.im->icon_timer); | |
4336 | |
4337 gtkconv->u.im->icon_timer = 0; | |
4338 } | |
4339 | |
4340 static gboolean | |
4341 icon_menu(GtkObject *obj, GdkEventButton *e, struct gaim_conversation *conv) | |
4342 { | |
4343 struct gaim_gtk_conversation *gtkconv; | |
4344 static GtkWidget *menu = NULL; | |
4345 GtkWidget *button; | |
4346 | |
4347 if (e->button != 3 || e->type != GDK_BUTTON_PRESS) | |
4348 return FALSE; | |
4349 | |
4350 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4351 | |
4352 /* | |
4353 * If a menu already exists, destroy it before creating a new one, | |
4354 * thus freeing-up the memory it occupied. | |
4355 */ | |
4356 if (menu != NULL) | |
4357 gtk_widget_destroy(menu); | |
4358 | |
4359 menu = gtk_menu_new(); | |
4360 | |
4361 if (gtkconv->u.im->icon_timer) { | |
4362 button = gtk_menu_item_new_with_label(_("Disable Animation")); | |
4363 g_signal_connect(GTK_OBJECT(button), "activate", | |
4364 G_CALLBACK(stop_anim), conv); | |
4365 gtk_menu_shell_append(GTK_MENU_SHELL(menu), button); | |
4366 gtk_widget_show(button); | |
4367 } | |
4368 else if (gtkconv->u.im->anim && | |
4369 !(gdk_pixbuf_animation_is_static_image(gtkconv->u.im->anim))) | |
4370 { | |
4371 button = gtk_menu_item_new_with_label(_("Enable Animation")); | |
4372 g_signal_connect(GTK_OBJECT(button), "activate", | |
4373 G_CALLBACK(start_anim), conv); | |
4374 gtk_menu_shell_append(GTK_MENU_SHELL(menu), button); | |
4375 gtk_widget_show(button); | |
4376 } | |
4377 | |
4378 button = gtk_menu_item_new_with_label(_("Hide Icon")); | |
4379 g_signal_connect_swapped(GTK_OBJECT(button), "activate", | |
4380 G_CALLBACK(remove_icon), conv); | |
4381 gtk_menu_shell_append(GTK_MENU_SHELL(menu), button); | |
4382 gtk_widget_show(button); | |
4383 | |
4384 button = gtk_menu_item_new_with_label(_("Save Icon As...")); | |
4385 g_signal_connect(GTK_OBJECT(button), "activate", | |
4386 G_CALLBACK(gaim_gtk_save_icon_dialog), conv); | |
4387 gtk_menu_shell_append(GTK_MENU_SHELL(menu), button); | |
4388 gtk_widget_show(button); | |
4389 | |
4390 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, e->button, e->time); | |
4391 | |
4392 return TRUE; | |
4393 } | |
4394 | |
4395 void | |
4396 gaim_gtkconv_update_buddy_icon(struct gaim_conversation *conv) | |
4397 { | |
4398 struct gaim_gtk_conversation *gtkconv; | |
4399 | |
4400 char filename[256]; | |
4401 FILE *file; | |
4402 GError *err = NULL; | |
4403 | |
4404 void *data; | |
4405 int len, delay; | |
4406 | |
4407 GdkPixbuf *buf; | |
4408 | |
4409 GtkWidget *event; | |
4410 GtkWidget *frame; | |
4411 GdkPixbuf *scale; | |
4412 GdkPixmap *pm; | |
4413 GdkBitmap *bm; | |
4414 int sf = 0; | |
4415 | |
4416 if (conv == NULL || | |
4417 gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops() || | |
4418 gaim_conversation_get_type(conv) != GAIM_CONV_IM) { | |
4419 | |
4420 return; | |
4421 } | |
4422 | |
4423 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4424 | |
4425 remove_icon(gtkconv); | |
4426 | |
4427 if (im_options & OPT_IM_HIDE_ICONS) | |
4428 return; | |
4429 | |
4430 if (gaim_conversation_get_gc(conv) == NULL) | |
4431 return; | |
4432 | |
4433 data = get_icon_data(gaim_conversation_get_gc(conv), | |
4434 normalize(gaim_conversation_get_name(conv)), | |
4435 &len); | |
4436 | |
4437 if (!data) | |
4438 return; | |
4439 | |
4440 /* this is such an evil hack, i don't know why i'm even considering it. | |
4441 * we'll do it differently when gdk-pixbuf-loader isn't leaky anymore. */ | |
4442 g_snprintf(filename, sizeof(filename), | |
4443 "%s" G_DIR_SEPARATOR_S "gaimicon-%s.%d", | |
4444 g_get_tmp_dir(), gaim_conversation_get_name(conv), getpid()); | |
4445 | |
4446 if (!(file = fopen(filename, "w"))) | |
4447 return; | |
4448 | |
4449 fwrite(data, 1, len, file); | |
4450 fclose(file); | |
4451 | |
4452 gtkconv->u.im->anim = gdk_pixbuf_animation_new_from_file(filename, &err); | |
4453 | |
4454 if (err) { | |
4455 debug_printf("Buddy icon error: %s\n", err->message); | |
4456 g_error_free(err); | |
4457 } | |
4458 | |
4459 /* make sure we remove the file as soon as possible */ | |
4460 unlink(filename); | |
4461 | |
4462 if (!gtkconv->u.im->anim) | |
4463 return; | |
4464 | |
4465 if (gdk_pixbuf_animation_is_static_image(gtkconv->u.im->anim)) { | |
4466 gtkconv->u.im->iter = NULL; | |
4467 delay = 0; | |
4468 buf = gdk_pixbuf_animation_get_static_image(gtkconv->u.im->anim); | |
4469 } else { | |
4470 gtkconv->u.im->iter = | |
4471 gdk_pixbuf_animation_get_iter(gtkconv->u.im->anim, NULL); | |
4472 buf = gdk_pixbuf_animation_iter_get_pixbuf(gtkconv->u.im->iter); | |
4473 delay = gdk_pixbuf_animation_iter_get_delay_time(gtkconv->u.im->iter); | |
4474 delay = delay / 10; | |
4475 } | |
4476 | |
4477 sf = SCALE(gtkconv->u.im->anim); | |
4478 scale = gdk_pixbuf_scale_simple(buf, | |
4479 MAX(gdk_pixbuf_get_width(buf) * sf / | |
4480 gdk_pixbuf_animation_get_width(gtkconv->u.im->anim), 1), | |
4481 MAX(gdk_pixbuf_get_height(buf) * sf / | |
4482 gdk_pixbuf_animation_get_height(gtkconv->u.im->anim), 1), | |
4483 GDK_INTERP_NEAREST); | |
4484 | |
4485 if (delay) | |
4486 gtkconv->u.im->icon_timer = g_timeout_add(delay * 10, redraw_icon, | |
4487 conv); | |
4488 | |
4489 gdk_pixbuf_render_pixmap_and_mask(scale, &pm, &bm, 100); | |
4490 gdk_pixbuf_unref(scale); | |
4491 | |
4492 frame = gtk_frame_new(NULL); | |
4493 gtk_frame_set_shadow_type(GTK_FRAME(frame), | |
4494 (bm ? GTK_SHADOW_NONE : GTK_SHADOW_IN)); | |
4495 gtk_box_pack_start(GTK_BOX(gtkconv->bbox), frame, FALSE, FALSE, 5); | |
4496 gtk_box_reorder_child(GTK_BOX(gtkconv->bbox), frame, 0); | |
4497 gtk_widget_show(frame); | |
4498 | |
4499 event = gtk_event_box_new(); | |
4500 gtk_container_add(GTK_CONTAINER(frame), event); | |
4501 g_signal_connect(GTK_OBJECT(event), "button-press-event", | |
4502 G_CALLBACK(icon_menu), conv); | |
4503 gtk_widget_show(event); | |
4504 | |
4505 gtkconv->u.im->icon = gtk_pixmap_new(pm, bm); | |
4506 gtk_widget_set_size_request(gtkconv->u.im->icon, sf, sf); | |
4507 gtk_container_add(GTK_CONTAINER(event), gtkconv->u.im->icon); | |
4508 gtk_widget_show(gtkconv->u.im->icon); | |
4509 | |
4510 if(im_options & OPT_IM_NO_ANIMATION) | |
4511 stop_anim(NULL, conv); | |
4512 | |
4513 gdk_pixmap_unref(pm); | |
4514 | |
4515 if (bm) | |
4516 gdk_bitmap_unref(bm); | |
4517 } | |
4518 | |
4519 void | |
4520 gaim_gtkconv_hide_buddy_icons(void) | |
4521 { | |
4522 gaim_conversation_foreach(gaim_gtkconv_update_buddy_icon); | |
4523 } | |
4524 | |
4525 void | |
4526 gaim_gtkconv_set_anim(void) | |
4527 { | |
4528 GList *l; | |
4529 | |
4530 if (im_options & OPT_IM_HIDE_ICONS) | |
4531 return; | |
4532 | |
4533 if (im_options & OPT_IM_NO_ANIMATION) { | |
4534 for (l = gaim_get_ims(); l != NULL; l = l->next) | |
4535 stop_anim(NULL, (struct gaim_conversation *)l->data); | |
4536 } else { | |
4537 for (l = gaim_get_ims(); l != NULL; l = l->next) | |
4538 start_anim(NULL, (struct gaim_conversation *)l->data); | |
4539 } | |
4540 } | |
4541 | |
4542 void | |
4543 gaim_gtkconv_update_font_buttons(void) | |
4544 { | |
4545 GList *l; | |
4546 struct gaim_conversation *conv; | |
4547 struct gaim_gtk_conversation *gtkconv; | |
4548 | |
4549 for (l = gaim_get_ims(); l != NULL; l = l->next) { | |
4550 conv = (struct gaim_conversation *)l->data; | |
4551 | |
4552 if (gaim_conversation_get_ops(conv) != | |
4553 gaim_get_gtk_conversation_ops()) | |
4554 continue; | |
4555 | |
4556 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4557 | |
4558 if (gtkconv->toolbar.bold != NULL) | |
4559 gtk_widget_set_sensitive(gtkconv->toolbar.bold, | |
4560 (!(font_options & OPT_FONT_BOLD))); | |
4561 | |
4562 if (gtkconv->toolbar.italic != NULL) | |
4563 gtk_widget_set_sensitive(gtkconv->toolbar.italic, | |
4564 (!(font_options & OPT_FONT_ITALIC))); | |
4565 | |
4566 if (gtkconv->toolbar.underline != NULL) | |
4567 gtk_widget_set_sensitive(gtkconv->toolbar.underline, | |
4568 (!(font_options & OPT_FONT_UNDERLINE))); | |
4569 } | |
4570 } | |
4571 | |
4572 void | |
4573 gaim_gtkconv_update_tabs(void) | |
4574 { | |
4575 GList *l; | |
4576 GtkPositionType pos; | |
4577 struct gaim_window *win; | |
4578 struct gaim_gtk_window *gtkwin; | |
4579 | |
4580 pos = ((im_options & OPT_IM_SIDE_TAB) | |
4581 ? ((im_options & OPT_IM_BR_TAB) ? GTK_POS_RIGHT : GTK_POS_LEFT) | |
4582 : ((im_options & OPT_IM_BR_TAB) ? GTK_POS_BOTTOM : GTK_POS_TOP)); | |
4583 | |
4584 for (l = gaim_get_windows(); l != NULL; l = l->next) { | |
4585 win = (struct gaim_window *)l->data; | |
4586 | |
4587 if (gaim_window_get_ops(win) != gaim_get_gtk_window_ops()) | |
4588 continue; | |
4589 | |
4590 gtkwin = GAIM_GTK_WINDOW(win); | |
4591 | |
4592 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(gtkwin->notebook), pos); | |
4593 } | |
4594 } | |
4595 | |
4596 void | |
4597 gaim_gtkconv_update_chat_button_style() | |
4598 { | |
4599 GSList *l; | |
4600 struct gaim_connection *g; | |
4601 GtkWidget *parent; | |
4602 GaimConversationType type = GAIM_CONV_CHAT; | |
4603 | |
4604 for (l = connections; l != NULL; l = l->next) { | |
4605 GSList *bcs; | |
4606 struct gaim_conversation *conv; | |
4607 struct gaim_gtk_conversation *gtkconv; | |
4608 struct gaim_gtk_window *gtkwin; | |
4609 | |
4610 g = (struct gaim_connection *)l->data; | |
4611 | |
4612 for (bcs = g->buddy_chats; bcs != NULL; bcs = bcs->next) { | |
4613 conv = (struct gaim_conversation *)bcs->data; | |
4614 | |
4615 if (gaim_conversation_get_type(conv) != GAIM_CONV_CHAT) | |
4616 continue; | |
4617 | |
4618 if (gaim_conversation_get_ops(conv) != | |
4619 gaim_get_gtk_conversation_ops()) | |
4620 continue; | |
4621 | |
4622 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4623 gtkwin = GAIM_GTK_WINDOW(gaim_conversation_get_window(conv)); | |
4624 parent = gtk_widget_get_parent(gtkconv->send); | |
4625 | |
4626 gtkconv->send = | |
4627 gaim_gtk_change_text(_("Send"), | |
4628 gtkconv->send, GAIM_STOCK_SEND, type); | |
4629 gtkconv->u.chat->invite = | |
4630 gaim_gtk_change_text(_("Invite"), | |
4631 gtkconv->u.chat->invite, | |
4632 GAIM_STOCK_INVITE, type); | |
4633 | |
4634 gtk_box_pack_end(GTK_BOX(parent), gtkconv->send, FALSE, FALSE, | |
4635 type); | |
4636 gtk_box_pack_end(GTK_BOX(parent), gtkconv->u.chat->invite, | |
4637 FALSE, FALSE, 0); | |
4638 | |
4639 g_signal_connect(G_OBJECT(gtkconv->send), "clicked", | |
4640 G_CALLBACK(send_cb), conv); | |
4641 g_signal_connect(G_OBJECT(gtkconv->u.chat->invite), "clicked", | |
4642 G_CALLBACK(invite_cb), conv); | |
4643 | |
4644 gtk_button_set_relief(GTK_BUTTON(gtkconv->send), | |
4645 GTK_RELIEF_NONE); | |
4646 gtk_button_set_relief(GTK_BUTTON(gtkconv->u.chat->invite), | |
4647 GTK_RELIEF_NONE); | |
4648 | |
4649 gaim_gtkconv_update_buttons_by_protocol(conv); | |
4650 } | |
4651 } | |
4652 } | |
4653 | |
4654 void | |
4655 gaim_gtkconv_update_im_button_style() | |
4656 { | |
4657 GList *l; | |
4658 struct gaim_conversation *conv; | |
4659 struct gaim_gtk_conversation *gtkconv; | |
4660 | |
4661 for (l = gaim_get_ims(); l != NULL; l = l->next) { | |
4662 conv = (struct gaim_conversation *)l->data; | |
4663 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4664 | |
4665 setup_im_buttons(conv, gtk_widget_get_parent(gtkconv->send)); | |
4666 } | |
4667 } | |
4668 | |
4669 void | |
4670 gaim_gtkconv_update_buttons_by_protocol(struct gaim_conversation *conv) | |
4671 { | |
4672 struct gaim_window *win; | |
4673 struct gaim_gtk_window *gtkwin = NULL; | |
4674 struct gaim_gtk_conversation *gtkconv; | |
4675 struct gaim_connection *gc; | |
4676 | |
4677 if (gaim_conversation_get_ops(conv) != gaim_get_gtk_conversation_ops()) | |
4678 return; | |
4679 | |
4680 gc = gaim_conversation_get_gc(conv); | |
4681 win = gaim_conversation_get_window(conv); | |
4682 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
4683 | |
4684 if (win != NULL) | |
4685 gtkwin = GAIM_GTK_WINDOW(win); | |
4686 | |
4687 if (gc == NULL) { | |
4688 gtk_widget_set_sensitive(gtkconv->send, FALSE); | |
4689 | |
4690 if (gaim_window_get_active_conversation(win) == conv) { | |
4691 gtk_widget_set_sensitive(gtkwin->menu.insert_link, FALSE); | |
4692 } | |
4693 } | |
4694 | |
4695 if (gaim_conversation_get_type(conv) == GAIM_CONV_IM) { | |
4696 if (gc == NULL) { | |
4697 gtk_widget_set_sensitive(gtkconv->info, FALSE); | |
4698 gtk_widget_set_sensitive(gtkconv->u.im->warn, FALSE); | |
4699 gtk_widget_set_sensitive(gtkconv->u.im->block, FALSE); | |
4700 gtk_widget_set_sensitive(gtkconv->u.im->add, FALSE); | |
4701 | |
4702 if (win != NULL && | |
4703 gaim_window_get_active_conversation(win) == conv) { | |
4704 | |
4705 gtk_widget_set_sensitive(gtkwin->menu.insert_image, FALSE); | |
4706 } | |
4707 | |
4708 return; | |
4709 } | |
4710 | |
4711 gtk_widget_set_sensitive(gtkconv->info, | |
4712 (gc->prpl->get_info != NULL)); | |
4713 | |
4714 gtk_widget_set_sensitive(gtkconv->toolbar.image, | |
4715 (gc->prpl->options & OPT_PROTO_IM_IMAGE)); | |
4716 | |
4717 if (win != NULL && gaim_window_get_active_conversation(win) == conv) { | |
4718 gtk_widget_set_sensitive(gtkwin->menu.insert_image, | |
4719 (gc->prpl->options & OPT_PROTO_IM_IMAGE)); | |
4720 } | |
4721 | |
4722 gtk_widget_set_sensitive(gtkconv->u.im->warn, | |
4723 (gc->prpl->warn != NULL)); | |
4724 | |
4725 gtk_widget_set_sensitive(gtkconv->u.im->block, | |
4726 (gc->prpl->add_permit != NULL)); | |
4727 | |
4728 update_convo_add_button(conv); | |
4729 } | |
4730 else if (gaim_conversation_get_type(conv) == GAIM_CONV_CHAT) { | |
4731 if (gc == NULL) { | |
4732 gtk_widget_set_sensitive(gtkconv->u.chat->whisper, FALSE); | |
4733 gtk_widget_set_sensitive(gtkconv->u.chat->invite, FALSE); | |
4734 | |
4735 return; | |
4736 } | |
4737 | |
4738 gtk_widget_set_sensitive(gtkconv->send, (gc->prpl->chat_send != NULL)); | |
4739 | |
4740 gtk_widget_set_sensitive(gtkconv->toolbar.image, FALSE); | |
4741 /* gtk_widget_set_sensitive(gtkwin->menu.insert_image, FALSE); */ | |
4742 | |
4743 gtk_widget_set_sensitive(gtkconv->u.chat->whisper, | |
4744 (gc->prpl->chat_whisper != NULL)); | |
4745 | |
4746 gtk_widget_set_sensitive(gtkconv->u.chat->invite, | |
4747 (gc->prpl->chat_invite != NULL)); | |
4748 } | |
4749 } | |
4750 | |
4751 struct gaim_window * | |
4752 gaim_gtkwin_get_at_xy(int x, int y) | |
4753 { | |
4754 struct gaim_window *win = NULL; | |
4755 struct gaim_gtk_window *gtkwin; | |
4756 GdkWindow *gdkwin; | |
4757 GList *l; | |
4758 | |
4759 gdkwin = gdk_window_at_pointer(&x, &y); | |
4760 | |
4761 if (gdkwin) | |
4762 gdkwin = gdk_window_get_toplevel(gdkwin); | |
4763 | |
4764 for (l = gaim_get_windows(); l != NULL; l = l->next) { | |
4765 win = (struct gaim_window *)l->data; | |
4766 | |
4767 if (gaim_window_get_ops(win) != gaim_get_gtk_window_ops()) | |
4768 continue; | |
4769 | |
4770 gtkwin = GAIM_GTK_WINDOW(win); | |
4771 | |
4772 if (gdkwin == gtkwin->window->window) | |
4773 return win; | |
4774 } | |
4775 | |
4776 return NULL; | |
4777 } | |
4778 | |
4779 int | |
4780 gaim_gtkconv_get_tab_at_xy(struct gaim_window *win, int x, int y) | |
4781 { | |
4782 struct gaim_gtk_window *gtkwin; | |
4783 GList *l; | |
4784 gint nb_x, nb_y, x_rel, y_rel; | |
4785 GtkNotebook *notebook; | |
4786 GtkWidget *tab; | |
4787 gint i, page_num = 0; | |
4788 gboolean first_visible = TRUE; | |
4789 | |
4790 if (gaim_window_get_ops(win) != gaim_get_gtk_window_ops()) | |
4791 return -1; | |
4792 | |
4793 gtkwin = GAIM_GTK_WINDOW(win); | |
4794 notebook = GTK_NOTEBOOK(gtkwin->notebook); | |
4795 | |
4796 gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y); | |
4797 x_rel = x - nb_x; | |
4798 y_rel = y - nb_y; | |
4799 | |
4800 for (l = gaim_window_get_conversations(win), i = 0; | |
4801 l != NULL; | |
4802 l = l->next, i++) { | |
4803 | |
4804 struct gaim_conversation *conv = l->data; | |
4805 tab = GAIM_GTK_CONVERSATION(conv)->tab_label; | |
4806 | |
4807 if (!GTK_WIDGET_MAPPED(tab)) | |
4808 continue; | |
4809 | |
4810 if (first_visible) { | |
4811 first_visible = FALSE; | |
4812 | |
4813 if (x_rel < tab->allocation.x) x_rel = tab->allocation.x; | |
4814 if (y_rel < tab->allocation.y) y_rel = tab->allocation.y; | |
4815 } | |
4816 | |
4817 if (gtk_notebook_get_tab_pos(notebook) == GTK_POS_TOP || | |
4818 gtk_notebook_get_tab_pos(notebook) == GTK_POS_BOTTOM) { | |
4819 | |
4820 if (tab->allocation.x <= x_rel) { | |
4821 if (tab->allocation.x + tab->allocation.width <= x_rel) | |
4822 page_num = i + 1; | |
4823 else | |
4824 page_num = i; | |
4825 } | |
4826 else | |
4827 break; | |
4828 } | |
4829 else { | |
4830 if (tab->allocation.y <= y_rel) { | |
4831 if (tab->allocation.y + tab->allocation.height <= y_rel) | |
4832 page_num = i + 1; | |
4833 else | |
4834 page_num = i; | |
4835 } | |
4836 else | |
4837 break; | |
4838 } | |
4839 } | |
4840 | |
4841 if (i == gaim_window_get_conversation_count(win) + 1) | |
4842 return -1; | |
4843 | |
4844 return page_num; | |
4845 } | |
4846 | |
4847 int | |
4848 gaim_gtkconv_get_dest_tab_at_xy(struct gaim_window *win, int x, int y) | |
4849 { | |
4850 struct gaim_gtk_window *gtkwin; | |
4851 GList *l; | |
4852 gint nb_x, nb_y, x_rel, y_rel; | |
4853 GtkNotebook *notebook; | |
4854 GtkWidget *tab; | |
4855 gint i, page_num = 0; | |
4856 | |
4857 if (gaim_window_get_ops(win) != gaim_get_gtk_window_ops()) | |
4858 return -1; | |
4859 | |
4860 gtkwin = GAIM_GTK_WINDOW(win); | |
4861 notebook = GTK_NOTEBOOK(gtkwin->notebook); | |
4862 | |
4863 gdk_window_get_origin(gtkwin->notebook->window, &nb_x, &nb_y); | |
4864 x_rel = x - nb_x; | |
4865 y_rel = y - nb_y; | |
4866 | |
4867 for (l = gaim_window_get_conversations(win), i = 0; | |
4868 l != NULL; | |
4869 l = l->next, i++) { | |
4870 | |
4871 struct gaim_conversation *conv = l->data; | |
4872 tab = GAIM_GTK_CONVERSATION(conv)->tab_label; | |
4873 | |
4874 if (!GTK_WIDGET_MAPPED(tab)) | |
4875 continue; | |
4876 | |
4877 if (gtk_notebook_get_tab_pos(notebook) == GTK_POS_TOP || | |
4878 gtk_notebook_get_tab_pos(notebook) == GTK_POS_BOTTOM) { | |
4879 | |
4880 if (tab->allocation.x <= x_rel) { | |
4881 if (tab->allocation.x + (tab->allocation.width / 2) <= x_rel) | |
4882 page_num = i + 1; | |
4883 else | |
4884 page_num = i; | |
4885 } | |
4886 else | |
4887 break; | |
4888 } | |
4889 else { | |
4890 if (tab->allocation.y <= y_rel) { | |
4891 if (tab->allocation.y + (tab->allocation.height / 2) <= y_rel) | |
4892 page_num = i + 1; | |
4893 else | |
4894 page_num = i; | |
4895 } | |
4896 else | |
4897 break; | |
4898 } | |
4899 } | |
4900 | |
4901 if (i == gaim_window_get_conversation_count(win) + 1) | |
4902 return -1; | |
4903 | |
4904 return page_num; | |
4905 } |