4359
|
1 /*
|
|
2 * gaim
|
|
3 *
|
|
4 * Copyright (C) 2002-2003, Christian Hammond <chipx86@gnupdate.org>
|
|
5 *
|
|
6 * This program is free software; you can redistribute it and/or modify
|
|
7 * it under the terms of the GNU General Public License as published by
|
|
8 * the Free Software Foundation; either version 2 of the License, or
|
|
9 * (at your option) any later version.
|
|
10 *
|
|
11 * This program is distributed in the hope that it will be useful,
|
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 * GNU General Public License for more details.
|
|
15 *
|
|
16 * You should have received a copy of the GNU General Public License
|
|
17 * along with this program; if not, write to the Free Software
|
|
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19 *
|
|
20 */
|
|
21 #ifdef HAVE_CONFIG_H
|
|
22 #include <config.h>
|
|
23 #endif
|
|
24 #include <string.h>
|
|
25 #ifndef _WIN32
|
|
26 #include <sys/time.h>
|
|
27 #include <unistd.h>
|
|
28 #include <gdk/gdkx.h>
|
|
29 #include <X11/Xlib.h>
|
|
30 #else
|
|
31 #ifdef small
|
|
32 #undef small
|
|
33 #endif
|
|
34 #endif /*_WIN32*/
|
|
35 #include <sys/types.h>
|
|
36 #include <sys/stat.h>
|
|
37 #include <stdio.h>
|
|
38 #include <stdlib.h>
|
|
39 #include <errno.h>
|
|
40 #include <ctype.h>
|
|
41 #include <gtk/gtk.h>
|
|
42 #ifdef USE_GTKSPELL
|
|
43 #include <gtkspell/gtkspell.h>
|
|
44 #endif
|
|
45 #include "gtkimhtml.h"
|
|
46 #include <gdk/gdkkeysyms.h>
|
|
47 #include "prpl.h"
|
|
48 #include "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 }
|