comparison src/buddy_chat.c @ 4359:5fb47ec9bfe4

[gaim-migrate @ 4625] Wow, okay, where to begin with this one ;) I rewrote the whole conversation backend. It is now core/UI split. Here's how it works.. Every conversation is represented by a gaim_conversation structure. This branches out into gaim_im and gaim_chat structures. Every conversation lives in (well, normally, but it doesn't have to) a gaim_window structure. This is a _CORE_ representation of a window. There can be multiple gaim_window structures around. The gaim_window and gaim_conversation structures have UI-specific operation structures associated with them. At the moment, the only UI is GTK+, and this will be for some time. Don't start thinking you can write a QT UI now. It's just not going to happen. Everything that is done on a conversation is done through the core API. This API does core processing and then calls the UI operations for the rendering and anything else. Now, what does this give the user? - Multiple windows. - Multiple tabs per window. - Draggable tabs. - Send As menu is moved to the menubar. - Menubar for chats. - Some very cool stuff in the future, like replacing, say, IRC chat windows with an X-Chat interface, or whatever. - Later on, customizable window/conversation positioning. For developers: - Fully documented API - Core/UI split - Variable checking and mostly sane handling of incorrect variables. - Logical structure to conversations, both core and UI. - Some very cool stuff in the future, like replacing, say, IRC chat windows with an X-Chat interface, or whatever. - Later on, customizable window/conversation positioning. - Oh yeah, and the beginning of a stock icon system. Now, there are things that aren't there yet. You will see tabs even if you have them turned off. This will be fixed in time. Also, the preferences will change to work with the new structure. I'm starting school in 2 days, so it may not be done immediately, but hopefully in the next week. Enjoy! committer: Tailor Script <tailor@pidgin.im>
author Christian Hammond <chipx86@chipx86.com>
date Mon, 20 Jan 2003 09:10:23 +0000
parents 0c68d402f59f
children 4bb433a7331c
comparison
equal deleted inserted replaced
4358:2b8abf7f9cc1 4359:5fb47ec9bfe4
33 #ifdef USE_GTKSPELL 33 #ifdef USE_GTKSPELL
34 #include <gtkspell/gtkspell.h> 34 #include <gtkspell/gtkspell.h>
35 #endif 35 #endif
36 #include <gdk/gdkkeysyms.h> 36 #include <gdk/gdkkeysyms.h>
37 37
38 #include "convo.h"
39 #include "prpl.h" 38 #include "prpl.h"
40 39
41 /*#include "pixmaps/tb_forward.xpm"*/ 40 static GList *chatentries = NULL;
42 #include "pixmaps/join.xpm" 41 static GtkWidget *joinchat = NULL;
43 /*#include "pixmaps/close.xpm"*/ 42 static GtkWidget *jc_vbox = NULL;
44 #include "pixmaps/cancel.xpm"
45
46 GtkWidget *joinchat;
47 static struct gaim_connection *joinchatgc; 43 static struct gaim_connection *joinchatgc;
48 static GtkWidget *invite; 44
49 static GtkWidget *inviteentry; 45 static void
50 static GtkWidget *invitemess; 46 do_join_chat()
51 static GtkWidget *jc_vbox = NULL;
52 static GList *chatentries = NULL;
53 extern int state_lock;
54
55 GList *chats = NULL;
56 GtkWidget *all_chats = NULL;
57 GtkWidget *chat_notebook = NULL;
58
59 static char *ignored(struct conversation *b, char *who)
60 {
61 GList *ignore = b->ignored;
62
63 while (ignore) {
64 char *ign = ignore->data;
65 if (!g_strcasecmp(who, ign))
66 return ign;
67 if (*ign == '+' && !g_strcasecmp(who, ign + 1))
68 return ign;
69 if (*ign == '@') {
70 ign++;
71 if (*ign == '+' && !g_strcasecmp(who, ign + 1))
72 return ign;
73 if (*ign != '+' && !g_strcasecmp(who, ign))
74 return ign;
75 }
76 ignore = ignore->next;
77 }
78 return NULL;
79 }
80
81
82 static void destroy_join_chat()
83 {
84 if (joinchat)
85 gtk_widget_destroy(joinchat);
86 joinchat = NULL;
87 }
88
89 static void destroy_invite()
90 {
91 if (invite)
92 gtk_widget_destroy(invite);
93 invite = NULL;
94 }
95
96
97 void do_join_chat()
98 { 47 {
99 if (joinchat) { 48 if (joinchat) {
100 GList *data = NULL; 49 GList *data = NULL;
101 GList *tmp = chatentries; 50 GList *tmp;
102 int *ival; 51 int *ival;
103 char *sval; 52 char *sval;
104 while (tmp) { 53
54 for (tmp = chatentries; tmp != NULL; tmp = tmp->next) {
105 if (gtk_object_get_user_data(tmp->data)) { 55 if (gtk_object_get_user_data(tmp->data)) {
106 ival = g_new0(int, 1); 56 ival = g_new0(int, 1);
107 *ival = gtk_spin_button_get_value_as_int(tmp->data); 57 *ival = gtk_spin_button_get_value_as_int(tmp->data);
108 data = g_list_append(data, ival); 58 data = g_list_append(data, ival);
109 } else { 59 }
60 else {
110 sval = g_strdup(gtk_entry_get_text(tmp->data)); 61 sval = g_strdup(gtk_entry_get_text(tmp->data));
111 data = g_list_append(data, sval); 62 data = g_list_append(data, sval);
112 } 63 }
113 tmp = tmp->next;
114 } 64 }
65
115 serv_join_chat(joinchatgc, data); 66 serv_join_chat(joinchatgc, data);
116 67
117 tmp = data; 68 for (tmp = data; tmp != NULL; tmp = tmp->next)
118 while (tmp) {
119 g_free(tmp->data); 69 g_free(tmp->data);
120 tmp = tmp->next; 70
121 }
122 g_list_free(data); 71 g_list_free(data);
123 72
124 gtk_widget_destroy(joinchat); 73 gtk_widget_destroy(joinchat);
74
125 if (chatentries) 75 if (chatentries)
126 g_list_free(chatentries); 76 g_list_free(chatentries);
77
127 chatentries = NULL; 78 chatentries = NULL;
128 } 79 joinchat = NULL;
129 joinchat = NULL; 80 }
130 } 81 }
131 82
132 static void rebuild_jc() 83 static void
84 rebuild_jc()
133 { 85 {
134 GList *list, *tmp; 86 GList *list, *tmp;
135 struct proto_chat_entry *pce; 87 struct proto_chat_entry *pce;
136 gboolean focus = TRUE; 88 gboolean focus = TRUE;
137 89
139 return; 91 return;
140 92
141 while (GTK_BOX(jc_vbox)->children) 93 while (GTK_BOX(jc_vbox)->children)
142 gtk_container_remove(GTK_CONTAINER(jc_vbox), 94 gtk_container_remove(GTK_CONTAINER(jc_vbox),
143 ((GtkBoxChild *)GTK_BOX(jc_vbox)->children->data)->widget); 95 ((GtkBoxChild *)GTK_BOX(jc_vbox)->children->data)->widget);
96
144 if (chatentries) 97 if (chatentries)
145 g_list_free(chatentries); 98 g_list_free(chatentries);
99
146 chatentries = NULL; 100 chatentries = NULL;
147 101
148 tmp = list = joinchatgc->prpl->chat_info(joinchatgc); 102 list = joinchatgc->prpl->chat_info(joinchatgc);
149 while (list) { 103
104 for (tmp = list; tmp != NULL; tmp = tmp->next) {
150 GtkWidget *label; 105 GtkWidget *label;
151 GtkWidget *rowbox; 106 GtkWidget *rowbox;
152 pce = list->data; 107
108 pce = tmp->data;
153 109
154 rowbox = gtk_hbox_new(FALSE, 5); 110 rowbox = gtk_hbox_new(FALSE, 5);
155 gtk_box_pack_start(GTK_BOX(jc_vbox), rowbox, TRUE, TRUE, 0); 111 gtk_box_pack_start(GTK_BOX(jc_vbox), rowbox, TRUE, TRUE, 0);
156 gtk_widget_show(rowbox); 112 gtk_widget_show(rowbox);
157 113
160 gtk_widget_show(label); 116 gtk_widget_show(label);
161 117
162 if (pce->is_int) { 118 if (pce->is_int) {
163 GtkObject *adjust; 119 GtkObject *adjust;
164 GtkWidget *spin; 120 GtkWidget *spin;
165 adjust = gtk_adjustment_new(pce->min, pce->min, pce->max, 1, 10, 10); 121 adjust = gtk_adjustment_new(pce->min, pce->min,
122 pce->max, 1, 10, 10);
166 spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0); 123 spin = gtk_spin_button_new(GTK_ADJUSTMENT(adjust), 1, 0);
167 gtk_object_set_user_data(GTK_OBJECT(spin), (void *)1); 124 gtk_object_set_user_data(GTK_OBJECT(spin), (void *)1);
168 chatentries = g_list_append(chatentries, spin); 125 chatentries = g_list_append(chatentries, spin);
169 gtk_widget_set_usize(spin, 50, -1); 126 gtk_widget_set_usize(spin, 50, -1);
170 gtk_box_pack_end(GTK_BOX(rowbox), spin, FALSE, FALSE, 0); 127 gtk_box_pack_end(GTK_BOX(rowbox), spin, FALSE, FALSE, 0);
171 gtk_widget_show(spin); 128 gtk_widget_show(spin);
172 } else { 129 }
130 else {
173 GtkWidget *entry; 131 GtkWidget *entry;
132
174 entry = gtk_entry_new(); 133 entry = gtk_entry_new();
134 gtk_box_pack_end(GTK_BOX(rowbox), entry, FALSE, FALSE, 0);
135
175 chatentries = g_list_append(chatentries, entry); 136 chatentries = g_list_append(chatentries, entry);
176 gtk_box_pack_end(GTK_BOX(rowbox), entry, FALSE, FALSE, 0); 137
177 if (pce->def) 138 if (pce->def)
178 gtk_entry_set_text(GTK_ENTRY(entry), pce->def); 139 gtk_entry_set_text(GTK_ENTRY(entry), pce->def);
140
179 if (focus) { 141 if (focus) {
180 gtk_widget_grab_focus(entry); 142 gtk_widget_grab_focus(entry);
181 focus = FALSE; 143 focus = FALSE;
182 } 144 }
183 g_signal_connect(GTK_OBJECT(entry), "activate", 145
184 G_CALLBACK(do_join_chat), NULL); 146 g_signal_connect(G_OBJECT(entry), "activate",
147 G_CALLBACK(do_join_chat), NULL);
148
185 gtk_widget_show(entry); 149 gtk_widget_show(entry);
186 } 150 }
187 151
188 g_free(pce); 152 g_free(pce);
189 list = list->next; 153 }
190 } 154
191 g_list_free(tmp); 155 g_list_free(list);
192 } 156 }
193 157
194 static void joinchat_choose(GtkWidget *w, struct gaim_connection *g) 158 static void
159 joinchat_choose(GtkWidget *w, struct gaim_connection *g)
195 { 160 {
196 if (joinchatgc == g) 161 if (joinchatgc == g)
197 return; 162 return;
163
198 joinchatgc = g; 164 joinchatgc = g;
165
199 rebuild_jc(); 166 rebuild_jc();
200 } 167 }
201 168
202 static void create_joinchat_menu(GtkWidget *box) 169 static void
170 create_joinchat_menu(GtkWidget *box)
203 { 171 {
204 GtkWidget *optmenu; 172 GtkWidget *optmenu;
205 GtkWidget *menu; 173 GtkWidget *menu;
206 GtkWidget *opt; 174 GtkWidget *opt;
207 GSList *c = connections; 175 GSList *c;
208 struct gaim_connection *g; 176 struct gaim_connection *g;
209 char buf[2048]; 177 char buf[2048];
210 178
211 optmenu = gtk_option_menu_new(); 179 optmenu = gtk_option_menu_new();
212 gtk_box_pack_start(GTK_BOX(box), optmenu, FALSE, FALSE, 0); 180 gtk_box_pack_start(GTK_BOX(box), optmenu, FALSE, FALSE, 0);
213 181
214 menu = gtk_menu_new(); 182 menu = gtk_menu_new();
215 joinchatgc = NULL; 183 joinchatgc = NULL;
216 184
217 while (c) { 185 for (c = connections; c != NULL; c = c->next) {
218 g = (struct gaim_connection *)c->data; 186 g = (struct gaim_connection *)c->data;
219 c = c->next; 187
220 if (!g->prpl->join_chat) 188 if (!g->prpl->join_chat)
221 continue; 189 continue;
190
222 if (!joinchatgc) 191 if (!joinchatgc)
223 joinchatgc = g; 192 joinchatgc = g;
224 g_snprintf(buf, sizeof buf, "%s (%s)", g->username, g->prpl->name); 193
194 g_snprintf(buf, sizeof(buf), "%s (%s)", g->username, g->prpl->name);
225 opt = gtk_menu_item_new_with_label(buf); 195 opt = gtk_menu_item_new_with_label(buf);
196
226 gtk_object_set_user_data(GTK_OBJECT(opt), g); 197 gtk_object_set_user_data(GTK_OBJECT(opt), g);
227 g_signal_connect(GTK_OBJECT(opt), "activate", G_CALLBACK(joinchat_choose), g); 198
199 g_signal_connect(G_OBJECT(opt), "activate",
200 G_CALLBACK(joinchat_choose), g);
201
228 gtk_menu_append(GTK_MENU(menu), opt); 202 gtk_menu_append(GTK_MENU(menu), opt);
229 gtk_widget_show(opt); 203 gtk_widget_show(opt);
230 } 204 }
231 205
232 gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); 206 gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu);
233 gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), 0); 207 gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), 0);
234 } 208 }
235 209
236 void join_chat() 210 static void
211 destroy_join_chat()
212 {
213 if (joinchat)
214 gtk_widget_destroy(joinchat);
215
216 joinchat = NULL;
217 }
218
219 void
220 join_chat()
237 { 221 {
238 GtkWidget *mainbox; 222 GtkWidget *mainbox;
239 GtkWidget *frame; 223 GtkWidget *frame;
240 GtkWidget *fbox; 224 GtkWidget *fbox;
241 GtkWidget *rowbox; 225 GtkWidget *rowbox;
242 GtkWidget *bbox; 226 GtkWidget *bbox;
243 GtkWidget *join; 227 GtkWidget *join;
244 GtkWidget *cancel; 228 GtkWidget *cancel;
245 GtkWidget *label; 229 GtkWidget *label;
246 GSList *c = connections; 230 GtkWidget *sep;
231 GSList *c;
247 struct gaim_connection *gc = NULL; 232 struct gaim_connection *gc = NULL;
248 233
249 while (c) { 234 for (c = connections; c != NULL; c = c->next) {
250 gc = c->data; 235 gc = c->data;
236
251 if (gc->prpl->join_chat) 237 if (gc->prpl->join_chat)
252 break; 238 break;
239
253 gc = NULL; 240 gc = NULL;
254 c = c->next; 241 }
255 } 242
256 if (gc == NULL) { 243 if (gc == NULL) {
257 do_error_dialog("You are not currently signed on with any protocols that have " 244 do_error_dialog(
258 "the ability to chat.", NULL, GAIM_ERROR); 245 _("You are not currently signed on with any protocols that have "
246 "the ability to chat."), NULL, GAIM_ERROR);
247
259 return; 248 return;
260 } 249 }
261 250
262 if (!joinchat) { 251 if (!joinchat) {
263 GAIM_DIALOG(joinchat); 252 GAIM_DIALOG(joinchat);
264 gtk_window_set_role(GTK_WINDOW(joinchat), "joinchat"); 253 gtk_window_set_role(GTK_WINDOW(joinchat), "joinchat");
265 gtk_window_set_policy(GTK_WINDOW(joinchat), FALSE, TRUE, TRUE); 254 gtk_window_set_policy(GTK_WINDOW(joinchat), FALSE, TRUE, TRUE);
266 gtk_widget_realize(joinchat); 255 gtk_widget_realize(joinchat);
267 g_signal_connect(GTK_OBJECT(joinchat), "delete_event", 256 g_signal_connect(G_OBJECT(joinchat), "delete_event",
268 G_CALLBACK(destroy_join_chat), joinchat); 257 G_CALLBACK(destroy_join_chat), joinchat);
269 gtk_window_set_title(GTK_WINDOW(joinchat), _("Join Chat")); 258 gtk_window_set_title(GTK_WINDOW(joinchat), _("Join Chat"));
270 259
271 mainbox = gtk_vbox_new(FALSE, 5); 260 mainbox = gtk_vbox_new(FALSE, 5);
272 gtk_container_set_border_width(GTK_CONTAINER(mainbox), 5); 261 gtk_container_set_border_width(GTK_CONTAINER(mainbox), 5);
273 gtk_container_add(GTK_CONTAINER(joinchat), mainbox); 262 gtk_container_add(GTK_CONTAINER(joinchat), mainbox);
274 263
275 frame = gtk_frame_new(_("Buddy Chat")); 264 frame = make_frame(mainbox, _("Buddy Chat"));
276 gtk_box_pack_start(GTK_BOX(mainbox), frame, TRUE, TRUE, 0);
277 265
278 fbox = gtk_vbox_new(FALSE, 5); 266 fbox = gtk_vbox_new(FALSE, 5);
279 gtk_container_set_border_width(GTK_CONTAINER(fbox), 5); 267 gtk_container_set_border_width(GTK_CONTAINER(fbox), 5);
280 gtk_container_add(GTK_CONTAINER(frame), fbox); 268 gtk_container_add(GTK_CONTAINER(frame), fbox);
281 269
286 label = gtk_label_new(_("Join Chat As:")); 274 label = gtk_label_new(_("Join Chat As:"));
287 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0); 275 gtk_box_pack_start(GTK_BOX(rowbox), label, FALSE, FALSE, 0);
288 276
289 create_joinchat_menu(rowbox); 277 create_joinchat_menu(rowbox);
290 278
291 { 279 jc_vbox = gtk_vbox_new(FALSE, 5);
292 GtkWidget *tmp = fbox; 280 gtk_container_add(GTK_CONTAINER(fbox), jc_vbox);
293 fbox = gtk_vbox_new(FALSE, 5); 281 gtk_container_set_border_width(GTK_CONTAINER(jc_vbox), 0);
294 gtk_container_add(GTK_CONTAINER(tmp), fbox); 282
295 gtk_container_set_border_width(GTK_CONTAINER(fbox), 0);
296 jc_vbox = fbox;
297 }
298 #else 283 #else
299 joinchatgc = connections->data; 284 joinchatgc = connections->data;
300 #endif 285 #endif
301 rebuild_jc(); 286 rebuild_jc();
302 /* buttons */ 287 /* buttons */
303 288
289 sep = gtk_hseparator_new();
290 gtk_widget_show(sep);
291 gtk_box_pack_start(GTK_BOX(mainbox), sep, FALSE, FALSE, 0);
292
304 bbox = gtk_hbox_new(FALSE, 5); 293 bbox = gtk_hbox_new(FALSE, 5);
305 gtk_box_pack_start(GTK_BOX(mainbox), bbox, FALSE, FALSE, 0); 294 gtk_box_pack_start(GTK_BOX(mainbox), bbox, FALSE, FALSE, 0);
306 295
307 join = picture_button(joinchat, _("Join"), join_xpm); 296 /* Cancel button. */
297 cancel = gaim_pixbuf_button_from_stock(_("Cancel"), GTK_STOCK_CANCEL,
298 GAIM_BUTTON_HORIZONTAL);
299 gtk_box_pack_end(GTK_BOX(bbox), cancel, FALSE, FALSE, 0);
300 g_signal_connect(G_OBJECT(cancel), "clicked",
301 G_CALLBACK(destroy_join_chat), joinchat);
302
303 /* Join button. */
304 join = gaim_pixbuf_button_from_stock(_("Join"), GTK_STOCK_JUMP_TO,
305 GAIM_BUTTON_HORIZONTAL);
308 gtk_box_pack_end(GTK_BOX(bbox), join, FALSE, FALSE, 0); 306 gtk_box_pack_end(GTK_BOX(bbox), join, FALSE, FALSE, 0);
309 g_signal_connect(GTK_OBJECT(join), "clicked", G_CALLBACK(do_join_chat), NULL); 307 g_signal_connect(G_OBJECT(join), "clicked",
310 308 G_CALLBACK(do_join_chat), NULL);
311 cancel = picture_button(joinchat, _("Cancel"), cancel_xpm); 309 }
312 gtk_box_pack_end(GTK_BOX(bbox), cancel, FALSE, FALSE, 0); 310
313 g_signal_connect(GTK_OBJECT(cancel), "clicked",
314 G_CALLBACK(destroy_join_chat), joinchat);
315 }
316 gtk_widget_show_all(joinchat); 311 gtk_widget_show_all(joinchat);
317 } 312 }
318
319
320 static void do_invite(GtkWidget *w, struct conversation *b)
321 {
322 const char *buddy;
323 const char *mess;
324
325 if (!b->is_chat) {
326 debug_printf("do_invite: expecting chat, got IM\n");
327 return;
328 }
329
330 buddy = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(inviteentry)->entry));
331 mess = gtk_entry_get_text(GTK_ENTRY(invitemess));
332
333 if (invite) {
334 serv_chat_invite(b->gc, b->id, mess, buddy);
335 gtk_widget_destroy(invite);
336 }
337 invite = NULL;
338 }
339
340
341 GList *generate_invite_user_names(struct gaim_connection *gc)
342 {
343 GSList *grp;
344 GSList *bl;
345 struct group *g;
346 struct buddy *buddy;
347
348 static GList *tmp = NULL;
349
350 if (tmp)
351 g_list_free(tmp);
352 tmp = NULL;
353
354 tmp = g_list_append(tmp, "");
355
356 if (gc) {
357 grp = groups;
358
359 while (grp) {
360 g = (struct group *)grp->data;
361
362 bl = g->members;
363
364 while (bl) {
365 buddy = (struct buddy *)bl->data;
366
367 if (buddy->user->gc == gc && buddy->present)
368 tmp = g_list_append(tmp, buddy->name);
369
370 bl = g_slist_next(bl);
371 }
372
373 grp = g_slist_next(grp);
374 }
375 }
376
377 return tmp;
378
379 }
380
381 void invite_callback(GtkWidget *w, struct conversation *b)
382 {
383 GtkWidget *cancel;
384 GtkWidget *invite_btn;
385 GtkWidget *label;
386 GtkWidget *bbox;
387 GtkWidget *vbox;
388 GtkWidget *table;
389 GtkWidget *frame;
390
391 if (!invite) {
392 GAIM_DIALOG(invite);
393 gtk_widget_realize(invite);
394
395 cancel = picture_button(invite, _("Cancel"), cancel_xpm);
396 invite_btn = picture_button(invite, _("Invite"), join_xpm);
397 inviteentry = gtk_combo_new();
398 invitemess = gtk_entry_new();
399 frame = gtk_frame_new(_("Invite"));
400 table = gtk_table_new(2, 2, FALSE);
401
402 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
403 gtk_table_set_col_spacings(GTK_TABLE(table), 5);
404 gtk_container_set_border_width(GTK_CONTAINER(table), 5);
405
406 gtk_container_set_border_width(GTK_CONTAINER(frame), 5);
407
408 /* Now we should fill out all of the names */
409 gtk_combo_set_popdown_strings(GTK_COMBO(inviteentry), generate_invite_user_names(b->gc));
410
411 vbox = gtk_vbox_new(FALSE, 0);
412 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
413 gtk_container_add(GTK_CONTAINER(frame), table);
414
415 label = gtk_label_new(_("Buddy"));
416 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
417 gtk_widget_show(label);
418 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0);
419
420 label = gtk_label_new(_("Message"));
421 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
422 gtk_widget_show(label);
423 gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0);
424
425 /* Now the right side of the table */
426 gtk_table_attach(GTK_TABLE(table), inviteentry, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0,
427 0);
428 gtk_table_attach(GTK_TABLE(table), invitemess, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0,
429 0);
430
431 /* And now for the button box */
432 bbox = gtk_hbox_new(FALSE, 10);
433 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
434
435 gtk_box_pack_end(GTK_BOX(bbox), cancel, FALSE, FALSE, 0);
436 gtk_box_pack_end(GTK_BOX(bbox), invite_btn, FALSE, FALSE, 0);
437
438 /* Handle closes right */
439 g_signal_connect(GTK_OBJECT(invite), "delete_event",
440 G_CALLBACK(destroy_invite), invite);
441
442 g_signal_connect(GTK_OBJECT(cancel), "clicked", G_CALLBACK(destroy_invite), b);
443 g_signal_connect(GTK_OBJECT(invite_btn), "clicked", G_CALLBACK(do_invite), b);
444 g_signal_connect(GTK_OBJECT(GTK_ENTRY(GTK_COMBO(inviteentry)->entry)), "activate",
445 G_CALLBACK(do_invite), b);
446
447 /* Finish up */
448 gtk_widget_set_usize(GTK_WIDGET(invite), 550, 115);
449 gtk_widget_show(invite_btn);
450 gtk_widget_show(cancel);
451 gtk_widget_show(inviteentry);
452 gtk_widget_show(invitemess);
453 gtk_widget_show(vbox);
454 gtk_widget_show(bbox);
455 gtk_widget_show(table);
456 gtk_widget_show(frame);
457 gtk_window_set_title(GTK_WINDOW(invite), _("Gaim - Invite Buddy Into Chat Room"));
458 gtk_window_set_focus(GTK_WINDOW(invite), GTK_WIDGET(GTK_COMBO(inviteentry)->entry));
459 gtk_container_add(GTK_CONTAINER(invite), vbox);
460
461
462 }
463 gtk_widget_show(invite);
464 }
465
466 void tab_complete(struct conversation *c)
467 {
468 GtkTextIter cursor, word_start, start_buffer;
469 int start;
470 int most_matched = -1;
471 char *entered, *partial = NULL;
472 char *text;
473 GList *matches = NULL;
474 GList *nicks = NULL;
475
476 gtk_text_buffer_get_start_iter(c->entry_buffer, &start_buffer);
477 gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &cursor,
478 gtk_text_buffer_get_insert(c->entry_buffer));
479 word_start = cursor;
480
481 /* if there's nothing there just return */
482 if (!gtk_text_iter_compare(&cursor, &start_buffer))
483 return;
484
485 text = gtk_text_buffer_get_text(c->entry_buffer, &start_buffer, &cursor, FALSE);
486
487 /* if we're at the end of ": " we need to move back 2 spaces */
488 start = strlen(text)-1;
489 if (strlen(text)>=2 && !strncmp(&text[start-1], ": ", 2)) {
490 gtk_text_iter_backward_chars(&word_start, 2);
491 }
492
493 /* find the start of the word that we're tabbing */
494 while (start >= 0 && text[start] != ' ') {
495 gtk_text_iter_backward_char(&word_start);
496 start--;
497 }
498 g_free(text);
499
500 entered = gtk_text_buffer_get_text(c->entry_buffer, &word_start, &cursor, FALSE);
501 if (chat_options & OPT_CHAT_OLD_STYLE_TAB) {
502 if (strlen(entered) >= 2 && !strncmp(": ", entered + strlen(entered) - 2, 2))
503 entered[strlen(entered) - 2] = 0;
504 }
505
506 if (!strlen(entered)) {
507 g_free(entered);
508 return;
509 }
510
511 debug_printf("checking tab-completion for %s\n", entered);
512
513 nicks = c->in_room;
514 while (nicks) {
515 char *nick = nicks->data;
516 /* this checks to see if the current nick could be a completion */
517 if (g_strncasecmp(nick, entered, strlen(entered))) {
518 if (nick[0] != '+' && nick[0] != '@') {
519 nicks = nicks->next;
520 continue;
521 }
522 if (g_strncasecmp(nick + 1, entered, strlen(entered))) {
523 if (nick[0] != '@' || nick[1] != '+') {
524 nicks = nicks->next;
525 continue;
526 }
527 if (g_strncasecmp(nick + 2, entered, strlen(entered))) {
528 nicks = nicks->next;
529 continue;
530 }
531 else
532 nick += 2;
533 } else
534 nick++;
535 }
536 /* if we're here, it's a possible completion */
537 debug_printf("possible completion: %s\n", nick);
538
539 /* if we're doing old-style, just fill in the completion */
540 if (chat_options & OPT_CHAT_OLD_STYLE_TAB) {
541 gtk_text_buffer_delete(c->entry_buffer, &word_start, &cursor);
542 if (strlen(nick) == strlen(entered)) {
543 nicks = nicks->next ? nicks->next : c->in_room;
544 nick = nicks->data;
545 if (*nick == '@')
546 nick++;
547 if (*nick == '+')
548 nick++;
549 }
550
551 gtk_text_buffer_get_start_iter(c->entry_buffer, &start_buffer);
552 gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &cursor,
553 gtk_text_buffer_get_insert(c->entry_buffer));
554 if (!gtk_text_iter_compare(&cursor, &start_buffer)) {
555 char *tmp = g_strdup_printf("%s: ", nick);
556 gtk_text_buffer_insert_at_cursor(c->entry_buffer, tmp, -1);
557 g_free(tmp);
558 } else {
559 gtk_text_buffer_insert_at_cursor(c->entry_buffer, nick, -1);
560 }
561 g_free(entered);
562 return;
563 }
564
565 /* we're only here if we're doing new style */
566 if (most_matched == -1) {
567 /* this will only get called once, since from now on most_matched is >= 0 */
568 most_matched = strlen(nick);
569 partial = g_strdup(nick);
570 } else if (most_matched) {
571 while (g_strncasecmp(nick, partial, most_matched))
572 most_matched--;
573 partial[most_matched] = 0;
574 }
575 matches = g_list_append(matches, nick);
576
577 nicks = nicks->next;
578 }
579 /* we're only here if we're doing new style */
580
581 /* if there weren't any matches, return */
582 if (!matches) {
583 /* if matches isn't set partials won't be either */
584 g_free(entered);
585 return;
586 }
587
588 gtk_text_buffer_delete(c->entry_buffer, &word_start, &cursor);
589 if (!matches->next) {
590 /* there was only one match. fill it in. */
591 gtk_text_buffer_get_start_iter(c->entry_buffer, &start_buffer);
592 gtk_text_buffer_get_iter_at_mark(c->entry_buffer, &cursor,
593 gtk_text_buffer_get_insert(c->entry_buffer));
594 if (!gtk_text_iter_compare(&cursor, &start_buffer)) {
595 char *tmp = g_strdup_printf("%s: ", (char *)matches->data);
596 gtk_text_buffer_insert_at_cursor(c->entry_buffer, tmp, -1);
597 g_free(tmp);
598 } else {
599 gtk_text_buffer_insert_at_cursor(c->entry_buffer, matches->data, -1);
600 }
601 matches = g_list_remove(matches, matches->data);
602 } else {
603 /* there were lots of matches, fill in as much as possible and display all of them */
604 char *addthis = g_malloc0(1);
605 while (matches) {
606 char *tmp = addthis;
607 addthis = g_strconcat(tmp, matches->data, " ", NULL);
608 g_free(tmp);
609 matches = g_list_remove(matches, matches->data);
610 }
611 write_to_conv(c, addthis, WFLAG_NOLOG, NULL, time(NULL), -1);
612 gtk_text_buffer_insert_at_cursor(c->entry_buffer, partial, -1);
613 g_free(addthis);
614 }
615
616 g_free(entered);
617 g_free(partial);
618 }
619
620 gboolean meify(char *message, int len)
621 {
622 /* read /me-ify : if the message (post-HTML) starts with /me, remove
623 * the "/me " part of it (including that space) and return TRUE */
624 char *c = message;
625 int inside_HTML = 0; /* i really don't like descriptive names */
626 if (!c)
627 return FALSE; /* um... this would be very bad if this happens */
628 if (len == -1)
629 len = strlen(message);
630 while (*c) {
631 if (inside_HTML) {
632 if (*c == '>')
633 inside_HTML = 0;
634 } else {
635 if (*c == '<')
636 inside_HTML = 1;
637 else
638 break;
639 }
640 c++; /* i really don't like c++ either */
641 len--;
642 }
643 /* k, so now we've gotten past all the HTML who. */
644 if (!*c)
645 return FALSE;
646 if (!g_strncasecmp(c, "/me ", 4)) {
647 memmove(c, c + 4, len - 3);
648 return TRUE;
649 } else
650 return FALSE;
651 }
652
653 static gboolean find_nick(struct gaim_connection *gc, char *message)
654 {
655 char *msg = g_strdup(message), *who, *p;
656 int n;
657 g_strdown(msg);
658
659 who = g_strdup(gc->username);
660 n = strlen(who);
661 g_strdown(who);
662
663 if ((p = strstr(msg, who)) != NULL) {
664 if (((p == msg) || !isalnum(*(p - 1))) && !isalnum(*(p + n))) {
665 g_free(who);
666 g_free(msg);
667 return TRUE;
668 }
669 }
670 g_free(who);
671
672 if (!g_strcasecmp(gc->username, gc->displayname)) {
673 g_free(msg);
674 return FALSE;
675 }
676
677 who = g_strdup(gc->displayname);
678 n = strlen(who);
679 g_strdown(who);
680
681 if (n > 0 && (p = strstr(msg, who)) != NULL) {
682 if (((p == msg) || !isalnum(*(p - 1))) && !isalnum(*(p + n))) {
683 g_free(who);
684 g_free(msg);
685 return TRUE;
686 }
687 }
688 g_free(who);
689 g_free(msg);
690 return FALSE;
691 }
692
693 void chat_write(struct conversation *b, char *who, int flag, char *message, time_t mtime)
694 {
695 char *str;
696
697 if (!b->is_chat) {
698 debug_printf("chat_write: expecting chat, got IM\n");
699 return;
700 }
701
702 if (ignored(b, who))
703 return;
704
705 if (!(flag & WFLAG_WHISPER)) {
706 str = g_strdup(normalize (who));
707 if (!g_strcasecmp(str, normalize(b->gc->username))) {
708 if (b->makesound)
709 play_sound(SND_CHAT_YOU_SAY);
710 flag |= WFLAG_SEND;
711 } else if (!g_strcasecmp(str, normalize(b->gc->displayname))) {
712 if (b->makesound)
713 play_sound(SND_CHAT_YOU_SAY);
714 flag |= WFLAG_SEND;
715 } else {
716 flag |= WFLAG_RECV;
717 if (find_nick(b->gc, message))
718 flag |= WFLAG_NICK;
719 }
720 g_free(str);
721 }
722
723 if (flag & WFLAG_RECV && b->makesound) {
724 if (flag & WFLAG_NICK && (sound_options & OPT_SOUND_CHAT_NICK)) {
725 play_sound(SND_CHAT_NICK);
726 } else {
727 play_sound(SND_CHAT_SAY);
728 }
729 }
730
731 if (chat_options & OPT_CHAT_COLORIZE)
732 flag |= WFLAG_COLORIZE;
733 write_to_conv(b, message, flag, who, mtime, -1);
734 }
735
736 static gint insertname(gconstpointer one, gconstpointer two)
737 {
738 const char *a = (const char *)one;
739 const char *b = (const char *)two;
740
741 if (*a == '@') {
742 if (*b != '@')
743 return -1;
744 return (strcasecmp(a + 1, b + 1));
745 } else if (*a == '+') {
746 if (*b == '@')
747 return 1;
748 if (*b != '+')
749 return -1;
750 return (strcasecmp(a + 1, b + 1));
751 } else {
752 if (*b == '@' || *b == '+')
753 return 1;
754 return strcasecmp(a, b);
755 }
756 }
757
758 static void chat_press_im(GtkObject *obj, struct conversation *b)
759 {
760 struct conversation *c;
761
762 c = find_conversation(gtk_object_get_user_data(obj));
763
764 if (c != NULL)
765 gdk_window_show(c->window->window);
766 else {
767 c = new_conversation(gtk_object_get_user_data(obj));
768 set_convo_gc(c, b->gc);
769 }
770 }
771
772 static void chat_press_ign(GtkWidget *obj, struct conversation *b)
773 {
774 ignore_callback(obj, b);
775 }
776
777 static void chat_press_info(GtkObject *obj, struct conversation *b)
778 {
779 if (b->gc) {
780 /*
781 * If there are special needs for getting info on users in
782 * buddy chat "rooms"...
783 */
784 if(b->gc->prpl->get_cb_info != NULL) {
785 b->gc->prpl->get_cb_info(b->gc, b->id, gtk_object_get_user_data(obj));
786 } else {
787 b->gc->prpl->get_info(b->gc, gtk_object_get_user_data(obj));
788 }
789 }
790 }
791
792
793 static void chat_press_away(GtkObject *obj, struct conversation *b)
794 {
795 if (b->gc) {
796 /*
797 * May want to expand this to work similarly to chat_press_info?
798 */
799 if(b->gc->prpl->get_cb_away != NULL) {
800 b->gc->prpl->get_cb_away(b->gc, b->id, gtk_object_get_user_data(obj));
801 }
802 }
803 }
804
805 /* Added by Jonas <jonas@birme.se> */
806 static void chat_press_add(GtkObject *obj, struct conversation *c)
807 {
808 char *name = gtk_object_get_user_data(obj);
809 struct buddy *b = find_buddy(c->gc->user, name);
810
811 if (b) {
812 show_confirm_del(c->gc, name);
813 } else if (c->gc)
814 show_add_buddy(c->gc, name, NULL, NULL);
815
816 gtk_widget_grab_focus(c->entry);
817 }
818 /* End Jonas */
819
820 static gint right_click_chat(GtkObject *obj, GdkEventButton *event, struct conversation *b)
821 {
822 GtkTreePath *path;
823 int x;
824 int y;
825 GtkTreeIter iter;
826 GtkTreeModel *mod;
827 GtkTreeViewColumn *column;
828 gchar *who;
829
830
831 mod = gtk_tree_view_get_model(GTK_TREE_VIEW(b->list));
832
833 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(b->list), event->x, event->y, &path, &column, &x, &y);
834
835 if (path == NULL)
836 return FALSE;
837
838 gtk_tree_selection_select_path(GTK_TREE_SELECTION(gtk_tree_view_get_selection(GTK_TREE_VIEW(b->list))), path);
839 gtk_tree_model_get_iter(GTK_TREE_MODEL(mod), &iter, path);
840 gtk_tree_model_get(GTK_TREE_MODEL(mod), &iter, 1, &who, -1);
841
842 if ((event->button == 1) && (event->type == GDK_2BUTTON_PRESS)) {
843 struct conversation *c;
844
845 if ((c = find_conversation(who)) == NULL)
846 c = new_conversation(who);
847
848 set_convo_gc(c, b->gc);
849 } else if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
850 static GtkWidget *menu = NULL;
851 GtkWidget *button;
852
853 /*
854 * If a menu already exists, destroy it before creating a new one,
855 * thus freeing-up the memory it occupied.
856 */
857
858 if(menu)
859 gtk_widget_destroy(menu);
860
861 menu = gtk_menu_new();
862
863 button = gtk_menu_item_new_with_label(_("IM"));
864 g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(chat_press_im), b);
865 gtk_object_set_user_data(GTK_OBJECT(button), who);
866 gtk_menu_append(GTK_MENU(menu), button);
867 gtk_widget_show(button);
868
869 if (ignored(b, gtk_object_get_user_data(obj)))
870 button = gtk_menu_item_new_with_label(_("Un-Ignore"));
871 else
872 button = gtk_menu_item_new_with_label(_("Ignore"));
873
874 g_signal_connect(GTK_OBJECT(button), "activate", G_CALLBACK(chat_press_ign), b);
875 gtk_object_set_user_data(GTK_OBJECT(button), who);
876 gtk_menu_append(GTK_MENU(menu), button);
877 gtk_widget_show(button);
878
879 if (b->gc && b->gc->prpl->get_info) {
880 button = gtk_menu_item_new_with_label(_("Info"));
881 g_signal_connect(GTK_OBJECT(button), "activate",
882 G_CALLBACK(chat_press_info), b);
883 gtk_object_set_user_data(GTK_OBJECT(button), who);
884 gtk_menu_append(GTK_MENU(menu), button);
885 gtk_widget_show(button);
886 }
887
888 if (b->gc && b->gc->prpl->get_cb_away) {
889 button = gtk_menu_item_new_with_label(_("Get Away Msg"));
890 g_signal_connect(GTK_OBJECT(button), "activate",
891 G_CALLBACK(chat_press_away), b);
892 gtk_object_set_user_data(GTK_OBJECT(button), who);
893 gtk_menu_append(GTK_MENU(menu), button);
894 gtk_widget_show(button);
895 }
896
897 /* Added by Jonas <jonas@birme.se> */
898 if (b->gc) {
899 if (find_buddy(b->gc->user, who))
900 button = gtk_menu_item_new_with_label(_("Remove"));
901 else
902 button = gtk_menu_item_new_with_label(_("Add"));
903 g_signal_connect(GTK_OBJECT(button), "activate",
904 G_CALLBACK(chat_press_add), b);
905 gtk_object_set_user_data(GTK_OBJECT(button),
906 who);
907 gtk_menu_append(GTK_MENU(menu), button);
908 gtk_widget_show(button);
909 }
910 /* End Jonas */
911
912 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time);
913
914 return TRUE;
915 }
916
917 return TRUE;
918 }
919
920 /*
921 * Common code for adding a chat buddy to the list
922 */
923 static void add_chat_buddy_common(struct conversation *b, char *name, int pos)
924 {
925 GtkTreeIter iter;
926 GtkListStore *ls;
927
928
929 ls = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(b->list)));
930
931 gtk_list_store_append(ls, &iter);
932 gtk_list_store_set(ls, &iter, 0, ignored(b, name) ? "X" : " ", 1, name, -1);
933 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), 1, GTK_SORT_ASCENDING);
934 }
935
936 void add_chat_buddy(struct conversation *b, char *buddy, char *extra_msg)
937 {
938 char *name = g_strdup(buddy);
939 char tmp[BUF_LONG];
940 int pos;
941
942 plugin_event(event_chat_buddy_join, b->gc, b->id, name);
943 b->in_room = g_list_insert_sorted(b->in_room, name, insertname);
944 pos = g_list_index(b->in_room, name);
945
946 add_chat_buddy_common(b, name, pos);
947
948 g_snprintf(tmp, sizeof(tmp), ngettext("%d person in room", "%d people in room",
949 g_list_length(b->in_room)), g_list_length(b->in_room));
950 gtk_label_set_text(GTK_LABEL(b->count), tmp);
951
952 if (b->makesound)
953 play_sound(SND_CHAT_JOIN);
954
955 if (chat_options & OPT_CHAT_LOGON) {
956 if (!extra_msg)
957 g_snprintf(tmp, sizeof(tmp), _("%s entered the room."), name);
958 else
959 g_snprintf(tmp, sizeof(tmp), _("%s [<I>%s</I>] entered the room."), name,
960 extra_msg);
961 write_to_conv(b, tmp, WFLAG_SYSTEM, NULL, time(NULL), -1);
962 }
963 }
964
965
966 void rename_chat_buddy(struct conversation *b, char *old, char *new)
967 {
968 GList *names = b->in_room;
969 char *name = g_strdup(new);
970 char *ign;
971 int pos;
972 char tmp[BUF_LONG];
973 GtkTreeIter iter;
974 GtkTreeModel *mod;
975 int f = 1;
976
977 while (names) {
978 if (!g_strcasecmp((char *)names->data, old)) {
979 char *tmp2 = names->data;
980 b->in_room = g_list_remove(b->in_room, names->data);
981
982 mod = gtk_tree_view_get_model(GTK_TREE_VIEW(b->list));
983
984 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mod), &iter))
985 break;
986
987 while (f != 0) {
988 gchar *val;
989
990 gtk_tree_model_get(GTK_TREE_MODEL(mod), &iter, 1, &val, -1);
991
992
993 if (!g_strcasecmp(old, val))
994 gtk_list_store_remove(GTK_LIST_STORE(mod), &iter);
995
996 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(mod), &iter);
997
998 g_free(val);
999 }
1000
1001 g_free(tmp2);
1002 break;
1003 }
1004 names = names->next;
1005 }
1006
1007 if (!names) {
1008 g_free(name);
1009 return;
1010 }
1011
1012 b->in_room = g_list_insert_sorted(b->in_room, name, insertname);
1013 pos = g_list_index(b->in_room, name);
1014
1015 ign = ignored(b, old);
1016
1017 if (ign) {
1018 g_free(ign);
1019 b->ignored = g_list_remove(b->ignored, ign);
1020
1021 /* we haven't added them yet. if we find them, don't add them again */
1022 if (!ignored(b, new))
1023 b->ignored = g_list_append(b->ignored, g_strdup(name));
1024
1025 } else {
1026 if ((ign = ignored(b, new)) != NULL) {
1027 /* if they weren't ignored and change to someone who is ignored,
1028 * assume it's someone else. that may seem a little backwards but
1029 * it's better when it *is* actually someone else. Sorry Sean. */
1030 g_free(ign);
1031 b->ignored = g_list_remove(b->ignored, ign);
1032 }
1033 }
1034
1035 add_chat_buddy_common(b, name, pos);
1036
1037 if (chat_options & OPT_CHAT_LOGON) {
1038 g_snprintf(tmp, sizeof(tmp), _("%s is now known as %s"), old, new);
1039 write_to_conv(b, tmp, WFLAG_SYSTEM, NULL, time(NULL), -1);
1040 }
1041 }
1042
1043
1044 void remove_chat_buddy(struct conversation *b, char *buddy, char *reason)
1045 {
1046 GList *names = b->in_room;
1047 char tmp[BUF_LONG];
1048 GtkTreeIter iter;
1049 GtkTreeModel *mod;
1050 int f = 1;
1051
1052 plugin_event(event_chat_buddy_leave, b->gc, b->id, buddy);
1053
1054 while (names) {
1055 if (!g_strcasecmp((char *)names->data, buddy)) {
1056 b->in_room = g_list_remove(b->in_room, names->data);
1057
1058 mod = gtk_tree_view_get_model(GTK_TREE_VIEW(b->list));
1059
1060 if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(mod), &iter))
1061 break;
1062
1063 while (f != 0) {
1064 gchar *val;
1065
1066 gtk_tree_model_get(GTK_TREE_MODEL(mod), &iter, 1, &val, -1);
1067
1068
1069 if (!g_strcasecmp(buddy, val))
1070 gtk_list_store_remove(GTK_LIST_STORE(mod), &iter);
1071
1072 f = gtk_tree_model_iter_next(GTK_TREE_MODEL(mod), &iter);
1073
1074 g_free(val);
1075 }
1076
1077 break;
1078 }
1079
1080 names = names->next;
1081 }
1082
1083 if (!names)
1084 return;
1085
1086 /* don't remove them from ignored in case they re-enter */
1087 g_snprintf(tmp, sizeof(tmp), ngettext("%d person in room", "%d people in room",
1088 g_list_length(b->in_room)), g_list_length(b->in_room));
1089 gtk_label_set_text(GTK_LABEL(b->count), tmp);
1090
1091 if (b->makesound)
1092 play_sound(SND_CHAT_LEAVE);
1093
1094 if (chat_options & OPT_CHAT_LOGON) {
1095 if (reason && *reason)
1096 g_snprintf(tmp, sizeof(tmp), _("%s left the room (%s)."), buddy, reason);
1097 else
1098 g_snprintf(tmp, sizeof(tmp), _("%s left the room."), buddy);
1099 write_to_conv(b, tmp, WFLAG_SYSTEM, NULL, time(NULL), -1);
1100 }
1101 }
1102
1103
1104 void im_callback(GtkWidget *w, struct conversation *b)
1105 {
1106 gchar *name;
1107 struct conversation *c;
1108 GtkTreeIter iter;
1109 GtkTreeModel *mod = gtk_tree_view_get_model(GTK_TREE_VIEW(b->list));
1110 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(b->list));
1111
1112 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) {
1113 gtk_tree_model_get(GTK_TREE_MODEL(mod), &iter, 1, &name, -1);
1114 } else {
1115 return;
1116 }
1117
1118 if (*name == '@')
1119 name++;
1120 if (*name == '+')
1121 name++;
1122
1123 c = find_conversation(name);
1124
1125 if (c != NULL) {
1126 gdk_window_raise(c->window->window);
1127 } else {
1128 c = new_conversation(name);
1129 }
1130
1131 set_convo_gc(c, b->gc);
1132 }
1133
1134 void ignore_callback(GtkWidget *w, struct conversation *b)
1135 {
1136 GtkTreeIter iter;
1137 GtkTreeModel *mod = gtk_tree_view_get_model(GTK_TREE_VIEW(b->list));
1138 GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(b->list));
1139 char *name;
1140 char *ign;
1141 int pos;
1142
1143 if (gtk_tree_selection_get_selected(sel, NULL, &iter)) {
1144 gtk_tree_model_get(GTK_TREE_MODEL(mod), &iter, 1, &name, -1);
1145 gtk_list_store_remove(GTK_LIST_STORE(mod), &iter);
1146 } else {
1147 return;
1148 }
1149
1150 pos = g_list_index(b->in_room, name);
1151
1152 ign = ignored(b, name);
1153
1154 if (ign) {
1155 g_free(ign);
1156 b->ignored = g_list_remove(b->ignored, ign);
1157 } else {
1158 b->ignored = g_list_append(b->ignored, g_strdup(name));
1159 }
1160
1161 add_chat_buddy_common(b, name, pos);
1162 }
1163
1164 void show_new_buddy_chat(struct conversation *b)
1165 {
1166 GtkWidget *win;
1167 GtkWidget *cont;
1168 GtkWidget *text;
1169 /*GtkWidget *close;*/
1170 GtkWidget *frame;
1171 GtkWidget *chatentry;
1172 GtkWidget *lbox;
1173 GtkWidget *bbox;
1174 GtkWidget *bbox2;
1175 GtkWidget *button;
1176 GtkWidget *sw;
1177 GtkWidget *sw2;
1178 GtkWidget *vbox;
1179 GtkWidget *vpaned;
1180 GtkWidget *hpaned;
1181 GtkWidget *toolbar;
1182 GtkWidget *sep;
1183 GtkListStore *ls;
1184 GtkWidget *list;
1185 GtkCellRenderer *rend;
1186 GtkTreeViewColumn *col;
1187 GtkWidget *tabby;
1188
1189 char buf[BUF_LONG];
1190
1191 int dispstyle = set_dispstyle(1);
1192
1193 if (chat_options & OPT_CHAT_ONE_WINDOW) {
1194 if (!all_chats) {
1195 GtkWidget *testidea;
1196
1197 win = all_chats = b->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1198 if ((convo_options & OPT_CONVO_COMBINE) && (im_options & OPT_IM_ONE_WINDOW))
1199 all_convos = all_chats;
1200 gtk_window_set_role(GTK_WINDOW(win), "buddy_chat");
1201 gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, FALSE);
1202 gtk_container_border_width(GTK_CONTAINER(win), 0);
1203 gtk_widget_realize(win);
1204 gtk_window_set_title(GTK_WINDOW(win), _("Gaim - Group Chats"));
1205 g_signal_connect(GTK_OBJECT(win), "delete_event",
1206 G_CALLBACK(delete_all_convo), NULL);
1207
1208 chat_notebook = gtk_notebook_new();
1209 if ((convo_options & OPT_CONVO_COMBINE) && (im_options & OPT_IM_ONE_WINDOW))
1210 convo_notebook = chat_notebook;
1211 if (chat_options & OPT_CHAT_SIDE_TAB) {
1212 if (chat_options & OPT_CHAT_BR_TAB) {
1213 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(chat_notebook),
1214 GTK_POS_RIGHT);
1215 } else {
1216 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(chat_notebook),
1217 GTK_POS_LEFT);
1218 }
1219 } else {
1220 if (chat_options & OPT_CHAT_BR_TAB) {
1221 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(chat_notebook),
1222 GTK_POS_BOTTOM);
1223 } else {
1224 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(chat_notebook),
1225 GTK_POS_TOP);
1226 }
1227 }
1228
1229 testidea = gtk_vbox_new(FALSE, 0);
1230 gtk_box_pack_start(GTK_BOX(testidea), chat_notebook, TRUE, TRUE, 0);
1231 gtk_widget_show(testidea);
1232
1233 gtk_notebook_set_scrollable(GTK_NOTEBOOK(chat_notebook), TRUE);
1234 gtk_notebook_popup_enable(GTK_NOTEBOOK(chat_notebook));
1235 gtk_container_add(GTK_CONTAINER(win), testidea);
1236 g_signal_connect_after(GTK_OBJECT(chat_notebook), "switch-page",
1237 G_CALLBACK(convo_switch), NULL);
1238 gtk_widget_show(chat_notebook);
1239 } else
1240 win = b->window = all_chats;
1241
1242 cont = gtk_vbox_new(FALSE, 5);
1243 gtk_container_set_border_width(GTK_CONTAINER(cont), 5);
1244
1245 tabby = gtk_hbox_new(FALSE, 5);
1246 b->close = gtk_button_new();
1247 gtk_widget_set_size_request(GTK_WIDGET(b->close), 16, 16);
1248 gtk_container_add(GTK_CONTAINER(b->close), gtk_image_new_from_stock(GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU));
1249 gtk_button_set_relief(GTK_BUTTON(b->close), GTK_RELIEF_NONE);
1250 b->tab_label = gtk_label_new(b->name);
1251
1252 g_signal_connect(GTK_OBJECT(b->close), "clicked", G_CALLBACK(close_callback), b);
1253
1254 gtk_box_pack_start(GTK_BOX(tabby), b->tab_label, FALSE, FALSE, 0);
1255 gtk_box_pack_start(GTK_BOX(tabby), b->close, FALSE, FALSE, 0);
1256 gtk_widget_show_all(tabby);
1257 gtk_notebook_append_page(GTK_NOTEBOOK(chat_notebook), cont, tabby);
1258 gtk_notebook_set_menu_label_text(GTK_NOTEBOOK(chat_notebook), cont,
1259 b->name);
1260 gtk_widget_show(cont);
1261 } else {
1262 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1263 b->window = win;
1264 gtk_object_set_user_data(GTK_OBJECT(win), b);
1265 gtk_window_set_role(GTK_WINDOW(win), "buddy_chat");
1266 gtk_window_set_policy(GTK_WINDOW(win), TRUE, TRUE, TRUE);
1267 gtk_container_border_width(GTK_CONTAINER(win), 10);
1268 gtk_widget_realize(win);
1269 g_snprintf(buf, sizeof(buf), "Gaim - %s (chat)", b->name);
1270 gtk_window_set_title(GTK_WINDOW(win), buf);
1271 g_signal_connect(GTK_OBJECT(win), "destroy", G_CALLBACK(close_callback), b);
1272
1273 cont = gtk_vbox_new(FALSE, 5);
1274 gtk_container_add(GTK_CONTAINER(win), cont);
1275 gtk_widget_show(cont);
1276 }
1277
1278 if (b->gc->prpl->options & OPT_PROTO_CHAT_TOPIC) {
1279 GtkWidget *hbox;
1280 GtkWidget *label;
1281
1282 hbox = gtk_hbox_new(FALSE, 0);
1283 gtk_box_pack_start(GTK_BOX(cont), hbox, FALSE, FALSE, 5);
1284 gtk_widget_show(hbox);
1285
1286 label = gtk_label_new(_("Topic:"));
1287 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
1288 gtk_widget_show(label);
1289
1290 b->topic_text = gtk_entry_new();
1291 gtk_entry_set_editable(GTK_ENTRY(b->topic_text), FALSE);
1292 gtk_box_pack_start(GTK_BOX(hbox), b->topic_text, TRUE, TRUE, 5);
1293 gtk_widget_show(b->topic_text);
1294 }
1295
1296 vpaned = gtk_vpaned_new();
1297 gtk_paned_set_gutter_size(GTK_PANED(vpaned), 15);
1298 gtk_container_add(GTK_CONTAINER(cont), vpaned);
1299 gtk_widget_show(vpaned);
1300
1301 hpaned = gtk_hpaned_new();
1302 gtk_paned_set_gutter_size(GTK_PANED(hpaned), 15);
1303 gtk_paned_pack1(GTK_PANED(vpaned), hpaned, TRUE, FALSE);
1304 gtk_widget_show(hpaned);
1305
1306 sw = gtk_scrolled_window_new(NULL, NULL);
1307 b->sw = sw;
1308 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
1309 gtk_paned_pack1(GTK_PANED(hpaned), sw, TRUE, TRUE);
1310 gtk_widget_set_usize(sw, buddy_chat_size.width, buddy_chat_size.height);
1311 gtk_widget_show(sw);
1312
1313 text = gtk_imhtml_new(NULL, NULL);
1314 b->text = text;
1315 gtk_container_add(GTK_CONTAINER(sw), text);
1316 if (convo_options & OPT_CONVO_SHOW_TIME)
1317 gtk_imhtml_show_comments(GTK_IMHTML(text), TRUE);
1318 else
1319 gtk_imhtml_show_comments(GTK_IMHTML(text), FALSE);
1320 gaim_setup_imhtml(text);
1321 gtk_widget_show(text);
1322
1323 lbox = gtk_vbox_new(FALSE, 5);
1324 gtk_paned_pack2(GTK_PANED(hpaned), lbox, TRUE, TRUE);
1325 gtk_widget_show(lbox);
1326
1327 b->count = gtk_label_new(_("0 people in room"));
1328 gtk_box_pack_start(GTK_BOX(lbox), b->count, FALSE, FALSE, 0);
1329 gtk_widget_show(b->count);
1330
1331 sw2 = gtk_scrolled_window_new(NULL, NULL);
1332 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw2), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1333 gtk_box_pack_start(GTK_BOX(lbox), sw2, TRUE, TRUE, 0);
1334 gtk_widget_show(sw2);
1335
1336 ls = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
1337 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(ls), 1, GTK_SORT_ASCENDING);
1338 list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ls));
1339
1340 rend = gtk_cell_renderer_text_new();
1341 col = gtk_tree_view_column_new_with_attributes(NULL, rend, "text", 0, NULL);
1342 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(col), TRUE);
1343 g_signal_connect(GTK_OBJECT(list), "button_press_event",
1344 G_CALLBACK(right_click_chat), b);
1345 gtk_tree_view_append_column(GTK_TREE_VIEW(list), col);
1346
1347 col = gtk_tree_view_column_new_with_attributes(NULL, rend, "text", 1, NULL);
1348 gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(col), TRUE);
1349 g_signal_connect(GTK_OBJECT(list), "button_press_event",
1350 G_CALLBACK(right_click_chat), b);
1351 gtk_tree_view_append_column(GTK_TREE_VIEW(list), col);
1352
1353 gtk_widget_set_usize(list, 150, -1);
1354
1355 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), FALSE);
1356 gtk_widget_show(list);
1357 b->list = list;
1358
1359 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw2), list);
1360
1361 bbox2 = gtk_hbox_new(TRUE, 5);
1362 gtk_box_pack_start(GTK_BOX(lbox), bbox2, FALSE, FALSE, 0);
1363 gtk_widget_show(bbox2);
1364
1365 button = gaim_pixbuf_button_from_stock(NULL, "gtk-redo", GAIM_BUTTON_VERTICAL);
1366 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1367 gtk_box_pack_start(GTK_BOX(bbox2), button, FALSE, FALSE, 0);
1368 g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(im_callback), b);
1369 gtk_widget_show(button);
1370
1371 button = gaim_pixbuf_button_from_stock(NULL, "gtk-dialog-error", GAIM_BUTTON_VERTICAL);
1372 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1373 gtk_box_pack_start(GTK_BOX(bbox2), button, FALSE, FALSE, 0);
1374 g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(ignore_callback), b);
1375 gtk_widget_show(button);
1376
1377 button = gaim_pixbuf_button_from_stock(NULL, "gtk-find", GAIM_BUTTON_VERTICAL);
1378 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1379 gtk_box_pack_start(GTK_BOX(bbox2), button, FALSE, FALSE, 0);
1380 g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(info_callback), b);
1381 gtk_widget_show(button);
1382 b->info = button;
1383
1384 vbox = gtk_vbox_new(FALSE, 5);
1385 gtk_paned_pack2(GTK_PANED(vpaned), vbox, TRUE, FALSE);
1386 gtk_widget_show(vbox);
1387
1388 toolbar = build_conv_toolbar(b);
1389 gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
1390
1391 frame = gtk_frame_new(NULL);
1392 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
1393 gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(frame), TRUE, TRUE, 0);
1394 gtk_widget_show(frame);
1395
1396 b->entry_buffer = gtk_text_buffer_new(NULL);
1397 g_object_set_data(G_OBJECT(b->entry_buffer), "user_data", b);
1398 chatentry = gtk_text_view_new_with_buffer(b->entry_buffer);
1399 b->entry = chatentry;
1400 if (!(chat_options & OPT_CHAT_ONE_WINDOW)
1401 || ((gtk_notebook_get_current_page(GTK_NOTEBOOK(chat_notebook)) == 0)
1402 && (b == g_list_nth_data(chats, 0))))
1403 gtk_widget_grab_focus(b->entry);
1404
1405
1406 b->makesound = 1; /* Need to do this until we get a menu */
1407
1408 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(b->entry), GTK_WRAP_WORD);
1409 g_signal_connect(G_OBJECT(b->entry), "key_press_event", G_CALLBACK(keypress_callback), b);
1410 g_signal_connect_after(G_OBJECT(b->entry), "button_press_event",
1411 G_CALLBACK(stop_rclick_callback), NULL);
1412 g_signal_connect_swapped(G_OBJECT(chatentry), "key_press_event",
1413 G_CALLBACK(entry_key_pressed), chatentry);
1414 gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(chatentry));
1415 gtk_widget_set_usize(chatentry, buddy_chat_size.width, MAX(buddy_chat_size.entry_height, 25));
1416 gtk_window_set_focus(GTK_WINDOW(win), chatentry);
1417 gtk_widget_show(chatentry);
1418 #ifdef USE_GTKSPELL
1419 if (convo_options & OPT_CONVO_CHECK_SPELLING)
1420 gtkspell_attach(GTK_TEXT_VIEW(chatentry));
1421 #endif
1422 bbox = gtk_hbox_new(FALSE, 5);
1423 gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
1424 gtk_widget_show(bbox);
1425
1426 /*
1427 close = picture_button2(win, _("Close"), cancel_xpm, dispstyle);
1428 b->close = close;
1429 gtk_object_set_user_data(GTK_OBJECT(close), b);
1430 g_signal_connect(GTK_OBJECT(close), "clicked", G_CALLBACK(close_callback), b);
1431 gtk_box_pack_end(GTK_BOX(bbox), close, dispstyle, dispstyle, 0);
1432 */
1433
1434 /* Send */
1435 button = gaim_pixbuf_button_from_stock(
1436 (dispstyle == 0 ? NULL : _("Send")),
1437 (dispstyle == 1 ? NULL : "gtk-convert"),
1438 GAIM_BUTTON_VERTICAL);
1439
1440 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1441 g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(send_callback), b);
1442 gtk_widget_show(button);
1443 gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1444 b->send = button;
1445
1446 /* Sep */
1447 sep = gtk_vseparator_new();
1448 gtk_box_pack_start(GTK_BOX(bbox), sep, FALSE, FALSE, 0);
1449
1450 /* Invite */
1451 button = gaim_pixbuf_button_from_stock(
1452 (dispstyle == 0 ? NULL : _("Invite")),
1453 (dispstyle == 1 ? NULL : "gtk-jump-to"),
1454 GAIM_BUTTON_VERTICAL);
1455
1456 g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(invite_callback), b);
1457 gtk_widget_show(button);
1458 gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0);
1459 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1460 b->invite = button;
1461
1462
1463 b->font_dialog = NULL;
1464 b->fg_color_dialog = NULL;
1465 b->bg_color_dialog = NULL;
1466 b->smiley_dialog = NULL;
1467 b->link_dialog = NULL;
1468 b->log_dialog = NULL;
1469 sprintf(b->fontface, "%s", fontface);
1470 b->hasfont = 0;
1471 b->bgcol = bgcolor;
1472 b->hasbg = 0;
1473 b->fgcol = fgcolor;
1474 b->hasfg = 0;
1475
1476 update_buttons_by_protocol(b);
1477
1478 gtk_widget_show(win);
1479 }
1480
1481 void chat_set_topic(struct conversation *b, char *who, char *topic)
1482 {
1483 gtk_entry_set_text(GTK_ENTRY(b->topic_text), topic);
1484 if (b->topic)
1485 g_free(b->topic);
1486 b->topic = g_strdup(topic);
1487 }
1488
1489
1490
1491 void delete_chat(struct conversation *b)
1492 {
1493 while (b->in_room) {
1494 g_free(b->in_room->data);
1495 b->in_room = g_list_remove(b->in_room, b->in_room->data);
1496 }
1497 while (b->ignored) {
1498 g_free(b->ignored->data);
1499 b->ignored = g_list_remove(b->ignored, b->ignored->data);
1500 }
1501 g_string_free(b->history, TRUE);
1502 if (b->topic)
1503 g_free(b->topic);
1504 g_free(b);
1505 }
1506
1507 static GtkWidget *change_text(GtkWidget *win, char *text, GtkWidget *button, char *stock, int chat)
1508 {
1509 int dispstyle = set_dispstyle(chat);
1510 gtk_widget_destroy(button);
1511 /* XXX button = picture_button2(win, text, xpm, dispstyle); */
1512 button = gaim_pixbuf_button_from_stock((dispstyle == 0 ? NULL : text),
1513 (dispstyle == 1 ? NULL : stock),
1514 GAIM_BUTTON_VERTICAL);
1515 #if 0
1516 if (chat == 1)
1517 gtk_box_pack_start(GTK_BOX(parent), button, dispstyle, dispstyle, 5);
1518 else
1519 gtk_box_pack_end(GTK_BOX(parent), button, dispstyle, dispstyle, 0);
1520
1521 gtk_box_pack_start(GTK_BOX(parent), button, dispstyle, dispstyle, 0);
1522 #endif
1523
1524 gtk_widget_show(button);
1525 return button;
1526 }
1527
1528 void update_chat_button_pix()
1529 {
1530 GSList *C = connections;
1531 struct gaim_connection *g;
1532 GtkWidget *parent;
1533
1534 while (C) {
1535 GSList *bcs;
1536 struct conversation *c;
1537 int opt = 1;
1538 g = (struct gaim_connection *)C->data;
1539 bcs = g->buddy_chats;
1540
1541 while (bcs) {
1542 c = (struct conversation *)bcs->data;
1543 parent = c->send->parent;
1544
1545 c->send = change_text(c->window, _("Send"), c->send, "gtk-convert", opt);
1546 c->invite = change_text(c->window, _("Invite"), c->invite, "gtk-jump-to", opt);
1547 gtk_box_pack_end(GTK_BOX(parent), c->send, FALSE, FALSE, 0);
1548 gtk_box_pack_end(GTK_BOX(parent), c->invite, FALSE, FALSE, 0);
1549
1550 g_signal_connect(GTK_OBJECT(c->send), "clicked",
1551 G_CALLBACK(send_callback), c);
1552 g_signal_connect(GTK_OBJECT(c->invite), "clicked",
1553 G_CALLBACK(invite_callback), c);
1554
1555 gtk_button_set_relief(GTK_BUTTON(c->send), GTK_RELIEF_NONE);
1556 gtk_button_set_relief(GTK_BUTTON(c->invite), GTK_RELIEF_NONE);
1557
1558 update_buttons_by_protocol(c);
1559
1560 bcs = bcs->next;
1561 }
1562 C = C->next;
1563 }
1564 }
1565
1566 void update_im_button_pix()
1567 {
1568 GList *bcs = conversations;
1569 struct conversation *c;
1570 GtkWidget *parent;
1571 int opt = 0;
1572
1573 while (bcs) {
1574 c = (struct conversation *)bcs->data;
1575 parent = c->send->parent;
1576
1577 c->send = change_text(c->window, _("Send"), c->send, "gtk-convert", opt);
1578 gtk_box_pack_end(GTK_BOX(parent), c->send, FALSE, FALSE, 0);
1579
1580 gtk_widget_destroy(c->sep2);
1581 c->sep2 = gtk_vseparator_new();
1582 gtk_box_pack_end(GTK_BOX(parent), c->sep2, FALSE, TRUE, 0);
1583 gtk_widget_show(c->sep2);
1584
1585 if (find_buddy(c->gc->user, c->name) == NULL)
1586 c->add = change_text(c->window, _("Add"), c->add, "gtk-add", opt);
1587 else
1588 c->add = change_text(c->window, _("Remove"), c->add, "gtk-remove", opt);
1589
1590 gtk_box_pack_start(GTK_BOX(parent), c->add, FALSE, FALSE, 0);
1591
1592 c->warn = change_text(c->window, _("Warn"), c->warn, "gtk-dialog-warning", opt);
1593 gtk_box_pack_start(GTK_BOX(parent), c->warn, FALSE, FALSE, 0);
1594
1595 c->info = change_text(c->window, _("Info"), c->info, "gtk-find", opt);
1596 gtk_box_pack_start(GTK_BOX(parent), c->info, FALSE, FALSE, 0);
1597
1598 c->block = change_text(c->window, _("Block"), c->block, "gtk-stop", opt);
1599 gtk_box_pack_start(GTK_BOX(parent), c->block, FALSE, FALSE, 0);
1600
1601 gtk_button_set_relief(GTK_BUTTON(c->info), GTK_RELIEF_NONE);
1602 gtk_button_set_relief(GTK_BUTTON(c->add), GTK_RELIEF_NONE);
1603 gtk_button_set_relief(GTK_BUTTON(c->warn), GTK_RELIEF_NONE);
1604 gtk_button_set_relief(GTK_BUTTON(c->send), GTK_RELIEF_NONE);
1605 gtk_button_set_relief(GTK_BUTTON(c->block), GTK_RELIEF_NONE);
1606
1607 gtk_size_group_add_widget(c->sg, c->info);
1608 gtk_size_group_add_widget(c->sg, c->add);
1609 gtk_size_group_add_widget(c->sg, c->warn);
1610 gtk_size_group_add_widget(c->sg, c->send);
1611 gtk_size_group_add_widget(c->sg, c->block);
1612
1613 gtk_box_reorder_child(GTK_BOX(parent), c->warn, 1);
1614 gtk_box_reorder_child(GTK_BOX(parent), c->block, 2);
1615 gtk_box_reorder_child(GTK_BOX(parent), c->info, 4);
1616
1617
1618 update_buttons_by_protocol(c);
1619
1620 g_signal_connect(GTK_OBJECT(c->send), "clicked", G_CALLBACK(send_callback), c);
1621 g_signal_connect(GTK_OBJECT(c->info), "clicked", G_CALLBACK(info_callback), c);
1622 g_signal_connect(GTK_OBJECT(c->warn), "clicked", G_CALLBACK(warn_callback), c);
1623 g_signal_connect(GTK_OBJECT(c->block), "clicked", G_CALLBACK(block_callback), c);
1624 bcs = bcs->next;
1625 }
1626 }
1627
1628 void chat_tabize()
1629 {
1630 int pos = 0;
1631 char tmp[BUF_LONG];
1632 /* evil, evil i tell you! evil! */
1633 if (chat_options & OPT_CHAT_ONE_WINDOW) {
1634 GList *x = chats;
1635 if ((convo_options & OPT_CONVO_COMBINE) && (im_options & OPT_IM_ONE_WINDOW)) {
1636 all_chats = all_convos;
1637 chat_notebook = convo_notebook;
1638 }
1639 while (x) {
1640 struct conversation *c = x->data;
1641 GtkWidget *imhtml, *win;
1642 GList *r = c->in_room;
1643
1644 imhtml = c->text;
1645 win = c->window;
1646 show_new_buddy_chat(c);
1647 gtk_widget_destroy(c->text);
1648 gtk_widget_reparent(imhtml, c->sw);
1649 c->text = imhtml;
1650 gtk_signal_disconnect_by_func(GTK_OBJECT(win),
1651 G_CALLBACK(close_callback), c);
1652 gtk_widget_destroy(win);
1653
1654 if (c->topic)
1655 gtk_entry_set_text(GTK_ENTRY(c->topic_text), c->topic);
1656
1657 g_snprintf(tmp, sizeof(tmp), ngettext("%d person in room", "%d people in room",
1658 g_list_length(c->in_room)), g_list_length(c->in_room));
1659 gtk_label_set_text(GTK_LABEL(c->count), tmp);
1660
1661 while (r) {
1662 char *name = r->data;
1663
1664 add_chat_buddy_common(c, name, pos);
1665
1666 r = r->next;
1667 pos++;
1668 }
1669
1670 x = x->next;
1671 }
1672 } else {
1673 GList *x, *m;
1674 x = m = chats;
1675 chats = NULL;
1676 while (x) {
1677 struct conversation *c = x->data;
1678 GtkWidget *imhtml;
1679 GList *r = c->in_room;
1680
1681 imhtml = c->text;
1682 show_new_buddy_chat(c);
1683 gtk_widget_destroy(c->text);
1684 gtk_widget_reparent(imhtml, c->sw);
1685 c->text = imhtml;
1686
1687 if (c->topic)
1688 gtk_entry_set_text(GTK_ENTRY(c->topic_text), c->topic);
1689
1690 g_snprintf(tmp, sizeof(tmp), ngettext("%d person in room", "%d people in room",
1691 g_list_length(c->in_room)), g_list_length(c->in_room));
1692 gtk_label_set_text(GTK_LABEL(c->count), tmp);
1693
1694 while (r) {
1695 char *name = r->data;
1696
1697 add_chat_buddy_common(c, name, pos);
1698
1699 r = r->next;
1700 pos++;
1701 }
1702
1703 x = x->next;
1704 }
1705 chats = m;
1706 if ((convo_options & OPT_CONVO_COMBINE) &&
1707 (im_options & OPT_IM_ONE_WINDOW) && conversations) {
1708 while (m) {
1709 gtk_notebook_remove_page(GTK_NOTEBOOK(chat_notebook),
1710 g_list_length(conversations));
1711 m = m->next;
1712 }
1713 } else if (all_chats)
1714 gtk_widget_destroy(all_chats);
1715 all_chats = NULL;
1716 chat_notebook = NULL;
1717 }
1718 }