4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
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.
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.
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
27 #include <applet-widget.h>
29 #endif /* USE_APPLET */
32 #endif /* GAIM_PLUGINS */
40 #include <gdk/gdkkeysyms.h>
45 #include "pixmaps/login_icon.xpm"
46 #include "pixmaps/logout_icon.xpm"
47 #include "pixmaps/no_icon.xpm"
49 #include "pixmaps/away_small.xpm"
50 #include "pixmaps/away_big.xpm"
52 #include "pixmaps/add_small.xpm"
53 #include "pixmaps/import_small.xpm"
54 /*#include "pixmaps/export_small.xpm"*/
55 #if defined(GAIM_PLUGINS) || defined(USE_PERL)
56 #include "pixmaps/plugins_small.xpm"
58 #include "pixmaps/prefs_small.xpm"
59 #include "pixmaps/search_small.xpm"
61 #include "pixmaps/close_small.xpm"
63 #include "pixmaps/exit_small.xpm"
65 #include "pixmaps/pounce_small.xpm"
66 #include "pixmaps/about_small.xpm"
68 #include "pixmaps/tmp_send.xpm"
69 #include "pixmaps/send_small.xpm"
70 #include "pixmaps/tb_search.xpm"
71 #include "pixmaps/join.xpm"
72 #include "pixmaps/gnome_add.xpm"
73 #include "pixmaps/gnome_remove.xpm"
74 #include "pixmaps/group.xpm"
75 #include "pixmaps/logout_menu.xpm"
77 static GtkTooltips
*tips
;
78 static GtkAccelGroup
*accel
;
79 static GtkWidget
*editpane
;
80 static GtkWidget
*buddypane
;
81 static GtkWidget
*imchatbox
;
82 static GtkWidget
*edittree
;
83 static GtkWidget
*imbutton
, *infobutton
, *chatbutton
, *awaybutton
;
84 static GtkWidget
*addbutton
, *groupbutton
, *rembutton
;
86 GtkWidget
*blist
= NULL
;
90 void BuddyTickerLogonTimeout(gpointer data
);
91 void BuddyTickerLogoutTimeout(gpointer data
);
106 /* stuff for actual display of buddy list */
114 static GSList
*shows
= NULL
;
116 /* Predefine some functions */
117 static void new_bp_callback(GtkWidget
*w
, struct buddy
*bs
);
118 static struct group_show
*find_group_show(char *group
);
119 static struct buddy_show
*find_buddy_show(struct group_show
*gs
, char *name
);
120 static int group_number(char *group
);
121 static int buddy_number(char *group
, char *buddy
);
122 static struct group_show
*new_group_show(char *group
);
123 static struct buddy_show
*new_buddy_show(struct group_show
*gs
, struct buddy
*buddy
, char **xpm
);
124 static void remove_buddy_show(struct group_show
*gs
, struct buddy_show
*bs
);
125 static struct group_show
*find_gs_by_bs(struct buddy_show
*b
);
126 static void update_num_group(struct group_show
*gs
);
127 static void update_idle_time(struct buddy_show
*bs
);
129 void handle_group_rename(struct group
*g
, char *prevname
)
131 struct group_show
*gs
, *new_gs
;
132 struct buddy_show
*bs
;
137 c
= gtk_ctree_find_by_row_data(GTK_CTREE(edittree
), NULL
, g
);
138 gtk_ctree_node_set_text(GTK_CTREE(edittree
), c
, 0, g
->name
);
140 gs
= find_group_show(prevname
);
144 new_gs
= find_group_show(g
->name
);
146 /* transfer everything that was in gs and is in the same gaim_conn as g
150 bs
= (struct buddy_show
*)m
->data
;
151 if (g_slist_index(bs
->connlist
, g
->gc
) >= 0) {
152 b
= find_buddy(g
->gc
, bs
->name
);
154 bs
->connlist
= g_slist_remove(bs
->connlist
, g
->gc
);
156 gs
->members
= g_slist_remove(gs
->members
, bs
);
157 if (bs
->log_timer
> 0)
158 gtk_timeout_remove(bs
->log_timer
);
160 remove_buddy_show(gs
, bs
);
165 if ((bs
= find_buddy_show(new_gs
, b
->name
)) == NULL
) {
166 if (g
->gc
->prpl
->list_icon
) {
167 bs
= new_buddy_show(new_gs
, b
,
168 g
->gc
->prpl
->list_icon(b
->uc
));
170 bs
= new_buddy_show(new_gs
, b
, (char **)no_icon_xpm
);
173 bs
->connlist
= g_slist_append(bs
->connlist
, g
->gc
);
179 /* we just transferred all of the members out of this group_show,
180 * so this group_show serves no purpose now. */
181 shows
= g_slist_remove(shows
, gs
);
182 gtk_tree_remove_item(GTK_TREE(buddies
), gs
->item
);
186 update_num_group(gs
);
188 update_num_group(new_gs
);
190 /* two possible actions: if gs contains things that are only from g,
191 * just rename gs and fix the label. otherwise, move everything in g
192 * over to another group_show */
193 for (m
= gs
->members
; m
!= NULL
; m
= g_slist_next(m
)) {
194 bs
= (struct buddy_show
*)m
->data
;
195 if (g_slist_index(bs
->connlist
, g
->gc
) < 0 || g_slist_length(bs
->connlist
) > 1) {
200 /* there's something from a different gaim_connection. */
201 new_gs
= new_group_show(g
->name
);
204 bs
= (struct buddy_show
*)m
->data
;
205 if (g_slist_index(bs
->connlist
, g
->gc
) >= 0) {
206 b
= find_buddy(g
->gc
, bs
->name
);
208 bs
->connlist
= g_slist_remove(bs
->connlist
, g
->gc
);
210 gs
->members
= g_slist_remove(gs
->members
, bs
);
211 if (bs
->log_timer
> 0)
212 gtk_timeout_remove(bs
->log_timer
);
214 remove_buddy_show(gs
, bs
);
219 if (g
->gc
->prpl
->list_icon
) {
220 bs
= new_buddy_show(new_gs
, b
,
221 g
->gc
->prpl
->list_icon(b
->uc
));
223 bs
= new_buddy_show(new_gs
, b
, (char **)no_icon_xpm
);
225 bs
->connlist
= g_slist_append(NULL
, g
->gc
);
230 update_num_group(gs
);
231 update_num_group(new_gs
);
234 gs
->name
= g_strdup(g
->name
);
235 update_num_group(gs
);
240 void handle_buddy_rename(struct buddy
*b
, char *prevname
)
242 struct conversation
*cnv
;
243 struct buddy_show
*bs
;
244 struct group_show
*gs
;
249 if (!strcmp(b
->show
, prevname
))
250 g_snprintf(b
->show
, sizeof(b
->show
), "%s", b
->name
);
252 /* well you shouldn't be calling this if nothing changed. duh. */
255 c
= gtk_ctree_find_by_row_data(GTK_CTREE(edittree
), NULL
, b
);
256 if (strcmp(b
->show
, b
->name
))
257 g_snprintf(buf
, sizeof(buf
), "%s (%s)", b
->name
, b
->show
);
259 g_snprintf(buf
, sizeof(buf
), "%s", b
->name
);
260 gtk_ctree_node_set_text(GTK_CTREE(edittree
), c
, 0, buf
);
262 if ((cnv
= find_conversation(b
->name
)) != NULL
)
263 set_convo_title(cnv
);
265 gs
= find_group_show(prevname
);
267 g
= find_group_by_buddy(b
->gc
, b
->name
);
269 /* shouldn't happen */
272 gs
= find_group_show(g
->name
);
276 bs
= find_buddy_show(gs
, prevname
);
278 /* buddy's offline */
282 if (g_strcasecmp(b
->name
, prevname
)) {
283 bs
->connlist
= g_slist_remove(bs
->connlist
, b
->gc
);
285 gs
->members
= g_slist_remove(gs
->members
, bs
);
286 if (bs
->log_timer
> 0)
287 gtk_timeout_remove(bs
->log_timer
);
289 remove_buddy_show(gs
, bs
);
294 update_num_group(gs
);
296 gtk_label_set_text(GTK_LABEL(bs
->label
), b
->show
);
297 update_idle_time(bs
);
304 struct group_show
*g
;
306 struct buddy_show
*b
;
308 g
= (struct group_show
*)s
->data
;
309 debug_printf("group_show still exists: %s\n", g
->name
);
312 b
= (struct buddy_show
*)m
->data
;
313 debug_printf("buddy_show still exists: %s\n", b
->name
);
314 m
= g_slist_remove(m
, b
);
315 if (b
->log_timer
> 0)
316 gtk_timeout_remove(b
->log_timer
);
318 gtk_tree_remove_item(GTK_TREE(g
->tree
), b
->item
);
323 gtk_tree_remove_item(GTK_TREE(buddies
), g
->item
);
324 s
= g_slist_remove(s
, g
);
331 gtk_widget_destroy(blist
);
338 static void adjust_pic(GtkWidget
*button
, const char *c
, gchar
**xpm
)
345 /*if the user had opted to put pictures on the buttons */
346 if (blist_options
& OPT_BLIST_SHOW_BUTTON_XPM
&& xpm
) {
347 pm
= gdk_pixmap_create_from_xpm_d(blist
->window
, &bm
, NULL
, xpm
);
348 pic
= gtk_pixmap_new(pm
, bm
);
349 gtk_widget_show(pic
);
350 gdk_pixmap_unref(pm
);
351 gdk_bitmap_unref(bm
);
352 label
= GTK_BIN(button
)->child
;
353 gtk_container_remove(GTK_CONTAINER(button
), label
);
354 gtk_container_add(GTK_CONTAINER(button
), pic
);
356 label
= gtk_label_new(c
);
357 gtk_widget_show(label
);
358 pic
= GTK_BIN(button
)->child
;
359 gtk_container_remove(GTK_CONTAINER(button
), pic
);
360 gtk_container_add(GTK_CONTAINER(button
), label
);
366 void toggle_show_empty_groups()
368 if (blist_options
& OPT_BLIST_NO_MT_GRP
) {
369 /* remove any group_shows with empty members */
371 struct group_show
*g
;
374 g
= (struct group_show
*)s
->data
;
375 if (!g_slist_length(g
->members
)) {
376 shows
= g_slist_remove(shows
, g
);
378 gtk_tree_remove_item(GTK_TREE(buddies
), g
->item
);
386 /* put back all groups */
387 GSList
*c
= connections
;
388 struct gaim_connection
*gc
;
393 gc
= (struct gaim_connection
*)c
->data
;
396 g
= (struct group
*)m
->data
;
398 if (!find_group_show(g
->name
))
399 new_group_show(g
->name
);
407 void toggle_buddy_pixmaps()
410 struct group_show
*g
;
412 struct buddy_show
*b
;
419 if (blist_options
& OPT_BLIST_SHOW_PIXMAPS
)
420 gtk_widget_show(b
->pix
);
422 gtk_widget_hide(b
->pix
);
429 static void update_num_group(struct group_show
*gs
)
431 GSList
*c
= connections
;
432 struct gaim_connection
*gc
;
434 struct buddy_show
*b
;
435 int total
= 0, on
= 0;
438 if (!g_slist_find(shows
, gs
)) {
439 debug_printf("update_num_group called for unfound group_show %s\n", gs
->name
);
444 gc
= (struct gaim_connection
*)c
->data
;
445 g
= find_group(gc
, gs
->name
);
447 total
+= g_slist_length(g
->members
);
454 b
= (struct buddy_show
*)c
->data
;
455 on
+= g_slist_length(b
->connlist
);
459 if (blist_options
& OPT_BLIST_SHOW_GRPNUM
)
460 g_snprintf(buf
, sizeof buf
, "%s (%d/%d)", gs
->name
, on
, total
);
462 g_snprintf(buf
, sizeof buf
, "%s", gs
->name
);
464 gtk_label_set_text(GTK_LABEL(gs
->label
), buf
);
467 void update_num_groups(void)
470 struct group_show
*g
;
473 g
= (struct group_show
*)s
->data
;
479 void update_button_pix()
482 adjust_pic(addbutton
, _("Add"), (gchar
**)gnome_add_xpm
);
483 adjust_pic(groupbutton
, _("Group"), (gchar
**)group_xpm
);
484 adjust_pic(rembutton
, _("Remove"), (gchar
**)gnome_remove_xpm
);
486 if (!(blist_options
& OPT_BLIST_NO_BUTTONS
)) {
487 adjust_pic(awaybutton
, _("Away"), (gchar
**)away_big_xpm
);
488 adjust_pic(chatbutton
, _("Chat"), (gchar
**)join_xpm
);
489 adjust_pic(imbutton
, _("IM"), (gchar
**)tmp_send_xpm
);
490 adjust_pic(infobutton
, _("Info"), (gchar
**)tb_search_xpm
);
492 gtk_widget_hide(addbutton
->parent
);
493 gtk_widget_show(addbutton
->parent
);
494 if (!(blist_options
& OPT_BLIST_NO_BUTTONS
)) {
495 gtk_widget_hide(chatbutton
->parent
);
496 gtk_widget_show(chatbutton
->parent
);
503 gint
applet_destroy_buddy(GtkWidget
*widget
, GdkEvent
*event
, gpointer
*data
)
505 applet_buddy_show
= FALSE
;
506 gtk_widget_hide(blist
);
512 static int handle_click_group(GtkWidget
*widget
, GdkEventButton
*event
, struct group
*g
)
514 if (event
->type
== GDK_2BUTTON_PRESS
) {
515 if (GTK_TREE_ITEM(widget
)->expanded
)
516 gtk_tree_item_collapse(GTK_TREE_ITEM(widget
));
518 gtk_tree_item_expand(GTK_TREE_ITEM(widget
));
525 void pressed_im_bud(GtkWidget
*widget
, struct buddy
*b
)
527 struct conversation
*c
;
529 c
= find_conversation(b
->name
);
532 gdk_window_show(c
->window
->window
);
534 c
= new_conversation(b
->name
);
536 set_convo_gc(c
, b
->gc
);
540 void pressed_im(GtkWidget
*widget
, struct buddy_show
*b
)
542 struct conversation
*c
;
544 c
= find_conversation(b
->name
);
547 gdk_window_show(c
->window
->window
);
549 c
= new_conversation(b
->name
);
551 set_convo_gc(c
, b
->connlist
->data
);
555 void pressed_log(GtkWidget
*widget
, char *name
)
565 void pressed_ticker(char *buddy
)
567 struct conversation
*c
;
569 c
= find_conversation(buddy
);
572 gdk_window_show(c
->window
->window
);
574 c
= new_conversation(buddy
);
578 void pressed_alias_bs(GtkWidget
*widget
, struct buddy_show
*bs
)
580 alias_dialog_bud(find_buddy(bs
->connlist
->data
, bs
->name
));
583 void pressed_alias_bud(GtkWidget
*widget
, struct buddy
*b
)
588 static void menu_click(GtkObject
*obj
, char *who
)
590 GList
*list
= gtk_object_get_user_data(obj
);
591 GList
*first
= g_list_first(list
);
592 struct proto_buddy_menu
*pbm
= list
->data
;
594 pbm
->callback(pbm
->gc
, who
);
595 g_list_foreach(first
, (GFunc
)g_free
, NULL
);
599 static int handle_click_buddy(GtkWidget
*widget
, GdkEventButton
*event
, struct buddy_show
*b
)
603 if (event
->type
== GDK_2BUTTON_PRESS
&& event
->button
== 1) {
604 struct conversation
*c
;
606 c
= find_conversation(b
->name
);
609 gdk_window_show(c
->window
->window
);
611 c
= new_conversation(b
->name
);
613 set_convo_gc(c
, b
->connlist
->data
);
614 if (im_options
& OPT_IM_ONE_WINDOW
)
616 } else if (event
->type
== GDK_BUTTON_PRESS
&& event
->button
== 3) {
621 GSList
*cn
= b
->connlist
;
622 struct gaim_connection
*g
;
623 /* We're gonna make us a menu right here */
625 menu
= gtk_menu_new();
627 button
= gtk_menu_item_new_with_label(_("IM"));
628 gtk_signal_connect(GTK_OBJECT(button
), "activate", GTK_SIGNAL_FUNC(pressed_im
), b
);
629 gtk_menu_append(GTK_MENU(menu
), button
);
630 gtk_widget_show(button
);
632 button
= gtk_menu_item_new_with_label(_("Alias"));
633 gtk_signal_connect(GTK_OBJECT(button
), "activate", GTK_SIGNAL_FUNC(pressed_alias_bs
), b
);
634 gtk_menu_append(GTK_MENU(menu
), button
);
635 gtk_widget_show(button
);
637 button
= gtk_menu_item_new_with_label(_("Add Buddy Pounce"));
638 gtk_signal_connect(GTK_OBJECT(button
), "activate",
639 GTK_SIGNAL_FUNC(new_bp_callback
),
640 cn
? find_buddy(cn
->data
, b
->name
) : NULL
);
641 gtk_menu_append(GTK_MENU(menu
), button
);
642 gtk_widget_show(button
);
644 button
= gtk_menu_item_new_with_label(_("View Log"));
645 gtk_signal_connect(GTK_OBJECT(button
), "activate",
646 GTK_SIGNAL_FUNC(pressed_log
), b
->name
);
647 gtk_menu_append(GTK_MENU(menu
), button
);
648 gtk_widget_show(button
);
650 if (g_slist_length(cn
) > 1) {
652 g
= (struct gaim_connection
*)cn
->data
;
653 if (g
->prpl
->buddy_menu
) {
654 GList
*mo
= g
->prpl
->buddy_menu(g
, b
->name
);
656 menuitem
= gtk_menu_item_new_with_label(g
->username
);
657 gtk_menu_append(GTK_MENU(menu
), menuitem
);
658 gtk_widget_show(menuitem
);
660 conmenu
= gtk_menu_new();
661 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), conmenu
);
662 gtk_widget_show(conmenu
);
665 struct proto_buddy_menu
*pbm
= mo
->data
;
668 button
= gtk_menu_item_new_with_label(pbm
->label
);
669 gtk_signal_connect(GTK_OBJECT(button
), "activate",
670 GTK_SIGNAL_FUNC(menu_click
), b
->name
);
671 gtk_object_set_user_data(GTK_OBJECT(button
), mo
);
672 gtk_menu_append(GTK_MENU(conmenu
), button
);
673 gtk_widget_show(button
);
678 cn
= g_slist_next(cn
);
681 g
= (struct gaim_connection
*)cn
->data
;
682 if (g
->prpl
->buddy_menu
) {
683 GList
*mo
= g
->prpl
->buddy_menu(g
, b
->name
);
686 struct proto_buddy_menu
*pbm
= mo
->data
;
689 button
= gtk_menu_item_new_with_label(pbm
->label
);
690 gtk_signal_connect(GTK_OBJECT(button
), "activate",
691 GTK_SIGNAL_FUNC(menu_click
), b
->name
);
692 gtk_object_set_user_data(GTK_OBJECT(button
), mo
);
693 gtk_menu_append(GTK_MENU(menu
), button
);
694 gtk_widget_show(button
);
701 /* we send the menu widget so we can add menuitems within a plugin */
702 plugin_event(event_draw_menu
, menu
, b
->name
, 0, 0);
704 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, event
->button
, event
->time
);
706 } else if (event
->type
== GDK_3BUTTON_PRESS
&& event
->button
== 2) {
707 if (!g_strcasecmp("zilding", normalize (b
->name
)))
709 else if (!g_strcasecmp("robflynn", normalize (b
->name
)))
711 else if (!g_strcasecmp("flynorange", normalize (b
->name
)))
713 else if (!g_strcasecmp("ewarmenhoven", normalize (b
->name
)))
715 else if (!g_strcasecmp("markster97", normalize (b
->name
)))
720 /* Anything for other buttons? :) */
726 static void un_alias(GtkWidget
*a
, struct buddy
*b
)
728 struct group
*g
= find_group_by_buddy(b
->gc
, b
->name
);
729 struct group_show
*gs
= find_group_show(g
->name
);
730 struct buddy_show
*bs
= NULL
;
731 GtkCTreeNode
*node
= gtk_ctree_find_by_row_data(GTK_CTREE(edittree
), NULL
, b
);
732 g_snprintf(b
->show
, sizeof(b
->show
), "%s", b
->name
);
733 gtk_ctree_node_set_text(GTK_CTREE(edittree
), node
, 0, b
->name
);
735 bs
= find_buddy_show(gs
, b
->name
);
737 gtk_label_set(GTK_LABEL(bs
->label
), b
->name
);
741 static gboolean
click_edit_tree(GtkWidget
*widget
, GdkEventButton
*event
, gpointer data
)
749 if (event
->button
!= 3 || event
->type
!= GDK_BUTTON_PRESS
)
752 if (!gtk_clist_get_selection_info(GTK_CLIST(edittree
), event
->x
, event
->y
, &row
, &column
))
755 node
= gtk_ctree_node_nth(GTK_CTREE(edittree
), row
);
756 type
= gtk_ctree_node_get_row_data(GTK_CTREE(edittree
), node
);
757 if (*type
== EDIT_GROUP
) {
758 struct group
*group
= (struct group
*)type
;
759 menu
= gtk_menu_new();
761 button
= gtk_menu_item_new_with_label(_("Rename"));
762 gtk_signal_connect(GTK_OBJECT(button
), "activate",
763 GTK_SIGNAL_FUNC(show_rename_group
), group
);
764 gtk_menu_append(GTK_MENU(menu
), button
);
765 gtk_widget_show(button
);
767 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, event
->button
, event
->time
);
770 } else if (*type
== EDIT_BUDDY
) {
771 struct buddy
*b
= (struct buddy
*)type
;
772 menu
= gtk_menu_new();
774 button
= gtk_menu_item_new_with_label(_("IM"));
775 gtk_signal_connect(GTK_OBJECT(button
), "activate", GTK_SIGNAL_FUNC(pressed_im_bud
), b
);
776 gtk_menu_append(GTK_MENU(menu
), button
);
777 gtk_widget_show(button
);
779 button
= gtk_menu_item_new_with_label(_("Alias"));
780 gtk_signal_connect(GTK_OBJECT(button
), "activate",
781 GTK_SIGNAL_FUNC(pressed_alias_bud
), b
);
782 gtk_menu_append(GTK_MENU(menu
), button
);
783 gtk_widget_show(button
);
785 if (strcmp(b
->name
, b
->show
)) {
786 button
= gtk_menu_item_new_with_label(_("Un-Alias"));
787 gtk_signal_connect(GTK_OBJECT(button
), "activate", GTK_SIGNAL_FUNC(un_alias
), b
);
788 gtk_menu_append(GTK_MENU(menu
), button
);
789 gtk_widget_show(button
);
792 button
= gtk_menu_item_new_with_label(_("Rename"));
793 gtk_signal_connect(GTK_OBJECT(button
), "activate",
794 GTK_SIGNAL_FUNC(show_rename_buddy
), b
);
795 gtk_menu_append(GTK_MENU(menu
), button
);
796 gtk_widget_show(button
);
798 button
= gtk_menu_item_new_with_label(_("Add Buddy Pounce"));
799 gtk_signal_connect(GTK_OBJECT(button
), "activate",
800 GTK_SIGNAL_FUNC(new_bp_callback
), b
);
801 gtk_menu_append(GTK_MENU(menu
), button
);
802 gtk_widget_show(button
);
804 button
= gtk_menu_item_new_with_label(_("View Log"));
805 gtk_signal_connect(GTK_OBJECT(button
), "activate",
806 GTK_SIGNAL_FUNC(pressed_log
), b
->name
);
807 gtk_menu_append(GTK_MENU(menu
), button
);
808 gtk_widget_show(button
);
810 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, event
->button
, event
->time
);
819 void ui_remove_buddy(struct gaim_connection
*gc
, struct group
*rem_g
, struct buddy
*rem_b
)
821 struct conversation
*c
;
822 struct group_show
*gs
;
823 struct buddy_show
*bs
;
825 gs
= find_group_show(rem_g
->name
);
827 bs
= find_buddy_show(gs
, rem_b
->name
);
829 if (g_slist_find(bs
->connlist
, gc
)) {
830 bs
->connlist
= g_slist_remove(bs
->connlist
, gc
);
831 update_num_group(gs
);
832 if (!g_slist_length(bs
->connlist
)) {
833 gs
->members
= g_slist_remove(gs
->members
, bs
);
834 if (bs
->log_timer
> 0)
835 gtk_timeout_remove(bs
->log_timer
);
837 remove_buddy_show(gs
, bs
);
841 if (!g_slist_length(gs
->members
) &&
842 (blist_options
& OPT_BLIST_NO_MT_GRP
)) {
843 shows
= g_slist_remove(shows
, gs
);
844 gtk_tree_remove_item(GTK_TREE(buddies
), gs
->item
);
853 c
= find_conversation(rem_b
->name
);
855 update_buttons_by_protocol(c
);
858 void ui_remove_group(struct gaim_connection
*gc
, struct group
*rem_g
)
860 struct group_show
*gs
;
862 if ((gs
= find_group_show(rem_g
->name
)) != NULL
) {
863 shows
= g_slist_remove(shows
, gs
);
864 gtk_tree_remove_item(GTK_TREE(buddies
), gs
->item
);
870 gboolean
edit_drag_compare_func(GtkCTree
*ctree
, GtkCTreeNode
*source_node
,
871 GtkCTreeNode
*new_parent
, GtkCTreeNode
*new_sibling
)
875 type
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree
), source_node
);
877 if (*type
== EDIT_GC
) {
880 } else if (*type
== EDIT_BUDDY
) {
882 type
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree
), new_parent
);
883 if (*type
== EDIT_GROUP
)
888 if (g_slist_length(connections
) > 1 && new_parent
) {
889 type
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree
), new_parent
);
890 if (*type
== EDIT_GC
)
892 } else if (g_slist_length(connections
) == 1 && !new_parent
)
900 /* you really shouldn't call this function */
901 void redo_buddy_list()
903 /* so here we can safely assume that we don't have to add or delete anything, we
904 * just have to go through and reorder everything. remember, nothing is going to
905 * change connections, so we can assume that we don't have to change any user
906 * data or anything. this is just a simple reordering. so calm down. */
907 /* note: we only have to do this if we want to strongly enforce order; however,
908 * order doesn't particularly matter to the stability of the program. but, it's
909 * kind of nice to have */
910 /* the easy way to implement this is just to go through shows and destroy all the
911 * group_shows, then go through the connections and put everything back. though,
912 * there are slight complications with that; most of them deal with timeouts and
913 * people not seeing the login icon for the full 10 seconds. butt fuck them. */
915 struct group_show
*gs
;
917 struct buddy_show
*bs
;
918 GSList
*c
= connections
;
919 struct gaim_connection
*gc
;
928 gs
= (struct group_show
*)s
->data
;
929 s
= g_slist_remove(s
, gs
);
931 gtk_tree_remove_item(GTK_TREE(buddies
), gs
->item
);
933 bs
= (struct buddy_show
*)m
->data
;
934 m
= g_slist_remove(m
, bs
);
935 if (bs
->log_timer
> 0)
936 gtk_timeout_remove(bs
->log_timer
);
946 gc
= (struct gaim_connection
*)c
->data
;
950 g
= (struct group
*)gr
->data
;
952 gs
= find_group_show(g
->name
);
953 if (!gs
&& !(blist_options
& OPT_BLIST_NO_MT_GRP
))
954 gs
= new_group_show(g
->name
);
957 b
= (struct buddy
*)m
->data
;
961 gs
= new_group_show(g
->name
);
962 bs
= find_buddy_show(gs
, b
->name
);
964 if (gc
->prpl
->list_icon
)
965 bs
= new_buddy_show(gs
, b
,
966 gc
->prpl
->list_icon(b
->
969 bs
= new_buddy_show(gs
, b
, (char **)no_icon_xpm
);
971 bs
->connlist
= g_slist_append(bs
->connlist
, gc
);
972 update_num_group(gs
);
980 static void edit_tree_move(GtkCTree
*ctree
, GtkCTreeNode
*child
, GtkCTreeNode
*parent
,
981 GtkCTreeNode
*sibling
, gpointer data
)
983 struct gaim_connection
*gc
, *pc
= NULL
, *sc
= NULL
;
984 int *ctype
, *ptype
= NULL
, *stype
= NULL
;
986 ctype
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree
), child
);
989 ptype
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree
), parent
);
992 stype
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(ctree
), sibling
);
994 if (*ctype
== EDIT_GC
) {
995 /* not that it particularly matters which order the connections
996 * are in, but just for debugging sake, i guess.... */
997 gc
= (struct gaim_connection
*)ctype
;
998 connections
= g_slist_remove(connections
, gc
);
1001 sc
= (struct gaim_connection
*)stype
;
1002 pos
= g_slist_index(connections
, sc
);
1004 connections
= g_slist_insert(connections
, gc
, pos
);
1006 connections
= g_slist_prepend(connections
, gc
);
1008 connections
= g_slist_append(connections
, gc
);
1009 redo_convo_menus(); /* this is evil */
1010 } else if (*ctype
== EDIT_BUDDY
) {
1011 /* we moved a buddy. hopefully we just changed groups or positions or something.
1012 * if we changed connections, we copy the buddy to the new connection. if the new
1013 * connection already had the buddy in its buddy list but in a different group,
1014 * we change the group that the buddy is in */
1015 struct group
*old_g
, *new_g
= (struct group
*)ptype
;
1016 struct buddy
*s
= NULL
, *buddy
= (struct buddy
*)ctype
;
1017 gboolean add
= FALSE
;
1020 if (buddy
->gc
!= new_g
->gc
) {
1021 /* we changed connections */
1024 a
= find_buddy(new_g
->gc
, buddy
->name
);
1027 /* the buddy is in the new connection, so we'll remove it from
1028 * its current group and add it to the proper group below */
1030 og
= find_group_by_buddy(new_g
->gc
, buddy
->name
);
1031 og
->members
= g_slist_remove(og
->members
, a
);
1033 /* we don't have this buddy yet; let's add him */
1038 old_g
= find_group_by_buddy(buddy
->gc
, buddy
->name
);
1040 if (buddy
->gc
== new_g
->gc
)
1041 /* this is the same connection, so we'll remove it from its old group */
1042 old_g
->members
= g_slist_remove(old_g
->members
, buddy
);
1045 s
= (struct buddy
*)stype
;
1046 pos
= g_slist_index(new_g
->members
, s
);
1048 new_g
->members
= g_slist_insert(new_g
->members
, buddy
, pos
);
1050 new_g
->members
= g_slist_prepend(new_g
->members
, buddy
);
1052 new_g
->members
= g_slist_append(new_g
->members
, buddy
);
1054 /* we do the add after it's added locally so that prpls can find it if necessary */
1056 serv_add_buddy(new_g
->gc
, buddy
->name
);
1058 do_export(buddy
->gc
);
1059 if (buddy
->gc
!= new_g
->gc
) {
1060 do_export(new_g
->gc
);
1063 } else { /* group */
1065 /* move the group. if moving connections, copy the group, and each buddy in the
1066 * group. if the buddy exists in the new connection, leave it where it is. */
1068 struct group
*g
, *g2
, *group
;
1071 pc
= (struct gaim_connection
*)ptype
;
1072 group
= (struct group
*)ctype
;
1074 if (g_slist_length(connections
) > 1) {
1075 g
= find_group(pc
, group
->name
);
1077 g
= add_group(pc
, group
->name
);
1079 pc
->groups
= g_slist_remove(pc
->groups
, g
);
1082 g2
= (struct group
*)stype
;
1083 pos
= g_slist_index(pc
->groups
, g2
);
1085 pc
->groups
= g_slist_insert(pc
->groups
, g
, pos
);
1087 pc
->groups
= g_slist_prepend(pc
->groups
, g
);
1089 pc
->groups
= g_slist_append(pc
->groups
, g
);
1091 if (pc
!= group
->gc
) {
1098 b
= (struct buddy
*)mem
->data
;
1099 if (!find_buddy(pc
, b
->name
))
1100 add_buddy(pc
, g
->name
, b
->name
, b
->show
);
1109 gc
->groups
= g_slist_remove(gc
->groups
, g
);
1112 g2
= (struct group
*)stype
;
1113 pos
= g_slist_index(gc
->groups
, g2
);
1115 gc
->groups
= g_slist_insert(gc
->groups
, g
, pos
);
1117 gc
->groups
= g_slist_prepend(gc
->groups
, g
);
1119 gc
->groups
= g_slist_append(gc
->groups
, g
);
1125 update_num_groups();
1130 void build_edit_tree()
1132 GtkCTreeNode
*c
= NULL
, *p
= NULL
, *n
;
1133 GSList
*con
= connections
;
1136 struct gaim_connection
*z
;
1144 gtk_clist_freeze(GTK_CLIST(edittree
));
1145 gtk_clist_clear(GTK_CLIST(edittree
));
1149 z
= (struct gaim_connection
*)con
->data
;
1151 if (g_slist_length(connections
) > 1) {
1152 text
[0] = z
->username
;
1154 c
= gtk_ctree_insert_node(GTK_CTREE(edittree
), NULL
,
1155 NULL
, text
, 5, NULL
, NULL
, NULL
, NULL
, 0, 1);
1157 gtk_ctree_node_set_row_data(GTK_CTREE(edittree
), c
, z
);
1164 g
= (struct group
*)grp
->data
;
1168 p
= gtk_ctree_insert_node(GTK_CTREE(edittree
), c
,
1169 NULL
, text
, 5, NULL
, NULL
, NULL
, NULL
, 0, 1);
1171 gtk_ctree_node_set_row_data(GTK_CTREE(edittree
), p
, g
);
1179 b
= (struct buddy
*)mem
->data
;
1180 if (strcmp(b
->name
, b
->show
)) {
1181 g_snprintf(buf
, sizeof(buf
), "%s (%s)", b
->name
, b
->show
);
1186 n
= gtk_ctree_insert_node(GTK_CTREE(edittree
),
1188 NULL
, NULL
, NULL
, NULL
, 1, 1);
1190 gtk_ctree_node_set_row_data(GTK_CTREE(edittree
), n
, b
);
1195 grp
= g_slist_next(grp
);
1197 con
= g_slist_next(con
);
1200 gtk_clist_thaw(GTK_CLIST(edittree
));
1204 void ui_add_buddy(struct gaim_connection
*gc
, struct group
*g
, struct buddy
*b
)
1206 GtkCTreeNode
*p
= NULL
, *n
;
1209 struct group_show
*gs
= find_group_show(g
->name
);
1211 b
->edittype
= EDIT_BUDDY
;
1214 update_num_group(gs
);
1219 p
= gtk_ctree_find_by_row_data(GTK_CTREE(edittree
), NULL
, g
);
1220 if (strcmp(b
->name
, b
->show
)) {
1221 g_snprintf(buf
, sizeof(buf
), "%s (%s)", b
->name
, b
->show
);
1226 n
= gtk_ctree_insert_node(GTK_CTREE(edittree
), p
, NULL
, text
, 5, NULL
, NULL
, NULL
, NULL
, 1, 1);
1227 gtk_ctree_node_set_row_data(GTK_CTREE(edittree
), n
, b
);
1230 void ui_add_group(struct gaim_connection
*gc
, struct group
*g
)
1232 GtkCTreeNode
*c
= NULL
, *p
;
1235 g
->edittype
= EDIT_GROUP
;
1240 c
= gtk_ctree_find_by_row_data(GTK_CTREE(edittree
), NULL
, gc
);
1242 p
= gtk_ctree_insert_node(GTK_CTREE(edittree
), c
, NULL
, text
, 5, NULL
, NULL
, NULL
, NULL
, 0, 1);
1243 gtk_ctree_node_set_row_data(GTK_CTREE(edittree
), p
, g
);
1245 if (!(blist_options
& OPT_BLIST_NO_MT_GRP
) && !find_group_show(g
->name
))
1246 new_group_show(g
->name
);
1250 static void do_del_buddy(GtkWidget
*w
, GtkCTree
*ctree
)
1258 i
= GTK_CLIST(edittree
)->selection
;
1261 type
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree
), node
);
1263 if (*type
== EDIT_BUDDY
) {
1264 struct gaim_connection
*gct
;
1265 b
= (struct buddy
*)type
;
1266 g
= find_group_by_buddy(b
->gc
, b
->name
);
1268 serv_remove_buddy(b
->gc
, b
->name
, g
->name
);
1269 remove_buddy(b
->gc
, g
, b
);
1270 gtk_ctree_remove_node(GTK_CTREE(edittree
), node
);
1272 } else if (*type
== EDIT_GROUP
) {
1273 struct gaim_connection
*gc
= ((struct group
*)type
)->gc
;
1274 remove_group(gc
, (struct group
*)type
);
1275 gtk_ctree_remove_node(GTK_CTREE(edittree
), node
);
1280 /* Nothing selected. */
1285 void import_callback(GtkWidget
*widget
, void *null
)
1287 show_import_dialog();
1296 /* first we tell those who have requested it we're quitting */
1297 plugin_event(event_quit
, 0, 0, 0, 0);
1301 /* then we remove everyone in a mass suicide */
1302 remove_all_plugins();
1304 system_log(log_quit
, NULL
, NULL
, OPT_LOG_BUDDY_SIGNON
| OPT_LOG_MY_SIGNON
);
1312 void add_buddy_callback(GtkWidget
*widget
, void *dummy
)
1317 struct gaim_connection
*gc
= NULL
;
1320 i
= GTK_CLIST(edittree
)->selection
;
1323 type
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree
), node
);
1325 if (*type
== EDIT_BUDDY
) {
1326 struct buddy
*b
= (struct buddy
*)type
;
1327 struct group
*g
= find_group_by_buddy(b
->gc
, b
->name
);
1330 } else if (*type
== EDIT_GROUP
) {
1331 struct group
*g
= (struct group
*)type
;
1335 gc
= (struct gaim_connection
*)type
;
1338 show_add_buddy(gc
, NULL
, grp
, NULL
);
1342 void add_group_callback(GtkWidget
*widget
, void *dummy
)
1346 struct gaim_connection
*gc
= NULL
;
1349 i
= GTK_CLIST(edittree
)->selection
;
1352 type
= (int *)gtk_ctree_node_get_row_data(GTK_CTREE(edittree
), node
);
1353 if (*type
== EDIT_BUDDY
)
1354 gc
= ((struct buddy
*)type
)->gc
;
1355 else if (*type
== EDIT_GROUP
)
1356 gc
= ((struct group
*)type
)->gc
;
1358 gc
= (struct gaim_connection
*)type
;
1363 static void im_callback(GtkWidget
*widget
, GtkTree
*tree
)
1366 struct buddy_show
*b
= NULL
;
1367 struct conversation
*c
;
1368 i
= GTK_TREE_SELECTION(tree
);
1370 b
= gtk_object_get_user_data(GTK_OBJECT(i
->data
));
1379 c
= find_conversation(b
->name
);
1381 c
= new_conversation(b
->name
);
1383 gdk_window_raise(c
->window
->window
);
1386 set_convo_gc(c
, b
->connlist
->data
);
1390 static void info_callback(GtkWidget
*widget
, GtkTree
*tree
)
1393 struct buddy_show
*b
= NULL
;
1394 i
= GTK_TREE_SELECTION(tree
);
1396 b
= gtk_object_get_user_data(GTK_OBJECT(i
->data
));
1405 serv_get_info(b
->connlist
->data
, b
->name
);
1409 void chat_callback(GtkWidget
*widget
, GtkTree
*tree
)
1414 static void away_callback(GtkWidget
*widget
, GtkTree
*tree
)
1416 GSList
*awy
= away_messages
;
1418 GtkWidget
*menuitem
;
1423 menu
= gtk_menu_new();
1426 struct away_message
*a
= awy
->data
;
1428 menuitem
= gtk_menu_item_new_with_label(a
->name
);
1429 gtk_menu_append(GTK_MENU(menu
), menuitem
);
1430 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate",
1431 GTK_SIGNAL_FUNC(do_away_message
), a
);
1432 gtk_widget_show(menuitem
);
1437 gtk_menu_popup(GTK_MENU(menu
), NULL
, NULL
, NULL
, NULL
, 1, time(NULL
));
1440 void rem_bp(GtkWidget
*w
, struct buddy_pounce
*b
)
1442 buddy_pounces
= g_list_remove(buddy_pounces
, b
);
1447 void do_pounce(struct gaim_connection
*gc
, char *name
, int when
)
1451 struct buddy_pounce
*b
;
1452 struct conversation
*c
;
1455 GList
*bp
= buddy_pounces
;
1457 who
= g_strdup(normalize (name
));
1460 b
= (struct buddy_pounce
*)bp
->data
;
1461 bp
= bp
->next
; /* increment the list here because rem_bp can make our handle bad */
1463 if (!(b
->options
& when
))
1466 u
= find_user(b
->pouncer
, b
->protocol
); /* find our user */
1470 /* check and see if we're signed on as the pouncer */
1474 if (!g_strcasecmp(who
, normalize (b
->name
))) { /* find someone to pounce */
1475 if (b
->options
& OPT_POUNCE_POPUP
) {
1476 c
= find_conversation(name
);
1478 c
= new_conversation(name
);
1480 set_convo_gc(c
, u
->gc
);
1482 if (b
->options
& OPT_POUNCE_NOTIFY
) {
1485 /* I know the line below is really ugly. I only did it this way
1486 * because I thought it'd be funny :-) */
1488 g_snprintf(tmp
, sizeof(tmp
), "%s has %s", name
,
1489 (b
->options
& OPT_POUNCE_SIGNON
) ? "signed on" :
1490 (b
->options
& OPT_POUNCE_UNIDLE
) ? "returned from being idle" :
1491 "returned from being away");
1493 do_error_dialog(tmp
, _("Buddy Pounce"));
1495 if (b
->options
& OPT_POUNCE_SEND_IM
) {
1496 if (strlen(b
->message
) > 0) {
1497 c
= find_conversation(name
);
1500 c
= new_conversation(name
);
1502 set_convo_gc(c
, u
->gc
);
1504 write_to_conv(c
, b
->message
, WFLAG_SEND
, NULL
, time(NULL
), -1);
1505 serv_send_im(u
->gc
, name
, b
->message
, 0);
1508 if (b
->options
& OPT_POUNCE_COMMAND
) {
1515 args
[2] = b
->command
;
1517 execvp(args
[0], args
);
1519 } else if (pid
> 0) {
1520 gtk_timeout_add(100, (GtkFunction
)clean_pid
, NULL
);
1523 if (b
->options
& OPT_POUNCE_SOUND
) {
1524 if (strlen(b
->sound
))
1525 play_file(b
->sound
);
1527 play_sound(POUNCE_DEFAULT
);
1530 if (!(b
->options
& OPT_POUNCE_SAVE
))
1538 static void new_bp_callback(GtkWidget
*w
, struct buddy
*b
)
1541 show_new_bp(b
->name
, b
->gc
, b
->idle
, b
->uc
& UC_UNAVAILABLE
);
1543 show_new_bp(NULL
, NULL
, 0, 0);
1548 GtkWidget
*menuitem
, *mess
, *messmenu
;
1549 static GtkWidget
*remmenu
;
1553 struct buddy_pounce
*b
;
1554 GList
*bp
= buddy_pounces
;
1556 l
= gtk_container_children(GTK_CONTAINER(bpmenu
));
1559 gtk_widget_destroy(GTK_WIDGET(l
->data
));
1563 remmenu
= gtk_menu_new();
1565 menuitem
= gtk_menu_item_new_with_label(_("New Buddy Pounce"));
1566 gtk_menu_append(GTK_MENU(bpmenu
), menuitem
);
1567 gtk_widget_show(menuitem
);
1568 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate", GTK_SIGNAL_FUNC(new_bp_callback
), NULL
);
1573 b
= (struct buddy_pounce
*)bp
->data
;
1574 remitem
= gtk_menu_item_new_with_label(b
->name
);
1575 gtk_menu_append(GTK_MENU(remmenu
), remitem
);
1576 gtk_widget_show(remitem
);
1577 gtk_signal_connect(GTK_OBJECT(remitem
), "activate", GTK_SIGNAL_FUNC(rem_bp
), b
);
1583 menuitem
= gtk_menu_item_new_with_label(_("Remove Buddy Pounce"));
1584 gtk_menu_append(GTK_MENU(bpmenu
), menuitem
);
1585 gtk_widget_show(menuitem
);
1586 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), remmenu
);
1587 gtk_widget_show(remmenu
);
1589 sep
= gtk_hseparator_new();
1590 menuitem
= gtk_menu_item_new();
1591 gtk_menu_append(GTK_MENU(bpmenu
), menuitem
);
1592 gtk_container_add(GTK_CONTAINER(menuitem
), sep
);
1593 gtk_widget_set_sensitive(menuitem
, FALSE
);
1594 gtk_widget_show(menuitem
);
1595 gtk_widget_show(sep
);
1601 b
= (struct buddy_pounce
*)bp
->data
;
1603 menuitem
= gtk_menu_item_new_with_label(b
->name
);
1604 gtk_menu_append(GTK_MENU(bpmenu
), menuitem
);
1605 messmenu
= gtk_menu_new();
1606 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), messmenu
);
1607 gtk_widget_show(menuitem
);
1609 mess
= gtk_menu_item_new_with_label(b
->message
);
1610 gtk_menu_append(GTK_MENU(messmenu
), mess
);
1611 gtk_widget_show(mess
);
1620 static struct group_show
*find_group_show(char *group
)
1623 struct group_show
*g
= NULL
;
1624 char *who
= g_strdup(normalize (group
));
1627 g
= (struct group_show
*)m
->data
;
1628 if (!g_strcasecmp(normalize (g
->name
), who
))
1638 static struct buddy_show
*find_buddy_show(struct group_show
*gs
, char *name
)
1640 GSList
*m
= gs
->members
;
1641 struct buddy_show
*b
= NULL
;
1642 char *who
= g_strdup(normalize (name
));
1645 b
= (struct buddy_show
*)m
->data
;
1646 if (!g_strcasecmp(normalize (b
->name
), who
))
1656 static int group_number(char *group
)
1658 GSList
*c
= connections
;
1659 struct gaim_connection
*g
;
1665 g
= (struct gaim_connection
*)c
->data
;
1668 p
= (struct group
*)m
->data
;
1669 if (!strcmp(p
->name
, group
))
1671 if (find_group_show(p
->name
))
1677 /* um..... we'll never get here */
1681 static int buddy_number(char *group
, char *buddy
)
1683 GSList
*c
= connections
;
1684 struct gaim_connection
*g
;
1689 char *tmp1
= g_strdup(normalize (buddy
));
1690 struct group_show
*gs
= find_group_show(group
);
1693 g
= (struct gaim_connection
*)c
->data
;
1694 p
= find_group(g
, group
);
1701 b
= (struct buddy
*)z
->data
;
1702 if (!strcmp(tmp1
, normalize (b
->name
))) {
1706 if (find_buddy_show(gs
, b
->name
))
1712 /* we shouldn't ever get here */
1713 debug_printf("got to bad place in buddy_number\n");
1718 static struct group_show
*new_group_show(char *group
)
1720 struct group_show
*g
= g_new0(struct group_show
, 1);
1721 int pos
= group_number(group
);
1723 g
->name
= g_strdup(group
);
1725 g
->item
= gtk_tree_item_new();
1726 gtk_tree_insert(GTK_TREE(buddies
), g
->item
, pos
);
1727 gtk_signal_connect(GTK_OBJECT(g
->item
), "button_press_event",
1728 GTK_SIGNAL_FUNC(handle_click_group
), g
);
1729 gtk_widget_show(g
->item
);
1731 g
->label
= gtk_label_new(group
);
1732 gtk_misc_set_alignment(GTK_MISC(g
->label
), 0.0, 0.5);
1733 gtk_container_add(GTK_CONTAINER(g
->item
), g
->label
);
1734 gtk_widget_show(g
->label
);
1736 shows
= g_slist_insert(shows
, g
, pos
);
1737 update_num_group(g
);
1741 static struct buddy_show
*new_buddy_show(struct group_show
*gs
, struct buddy
*buddy
, char **xpm
)
1743 struct buddy_show
*b
= g_new0(struct buddy_show
, 1);
1747 int pos
= buddy_number(gs
->name
, buddy
->name
);
1750 if (gs
->members
== NULL
) {
1751 gs
->tree
= gtk_tree_new();
1752 gtk_tree_item_set_subtree(GTK_TREE_ITEM(gs
->item
), gs
->tree
);
1753 gtk_tree_item_expand(GTK_TREE_ITEM(gs
->item
));
1754 gtk_widget_show(gs
->tree
);
1757 b
->name
= g_strdup(buddy
->name
);
1758 b
->show
= g_strdup(buddy
->show
);
1760 b
->item
= gtk_tree_item_new();
1761 gtk_tree_insert(GTK_TREE(gs
->tree
), b
->item
, pos
);
1762 gtk_object_set_user_data(GTK_OBJECT(b
->item
), b
);
1763 gtk_signal_connect(GTK_OBJECT(b
->item
), "button_press_event",
1764 GTK_SIGNAL_FUNC(handle_click_buddy
), b
);
1765 gtk_widget_show(b
->item
);
1767 box
= gtk_hbox_new(FALSE
, 1);
1768 gtk_container_add(GTK_CONTAINER(b
->item
), box
);
1769 gtk_widget_show(box
);
1771 pm
= gdk_pixmap_create_from_xpm_d(blist
->window
, &bm
, NULL
, xpm
? xpm
: no_icon_xpm
);
1772 b
->pix
= gtk_pixmap_new(pm
, bm
);
1773 gtk_box_pack_start(GTK_BOX(box
), b
->pix
, FALSE
, FALSE
, 1);
1774 gtk_widget_show(b
->pix
);
1775 if (!(blist_options
& OPT_BLIST_SHOW_PIXMAPS
))
1776 gtk_widget_hide(b
->pix
);
1777 gdk_pixmap_unref(pm
);
1778 gdk_bitmap_unref(bm
);
1780 b
->label
= gtk_label_new(buddy
->show
);
1781 gtk_misc_set_alignment(GTK_MISC(b
->label
), 0.0, 0.5);
1782 gtk_box_pack_start(GTK_BOX(box
), b
->label
, FALSE
, FALSE
, 1);
1783 gtk_widget_show(b
->label
);
1785 b
->warn
= gtk_label_new("");
1786 gtk_box_pack_start(GTK_BOX(box
), b
->warn
, FALSE
, FALSE
, 1);
1787 gtk_widget_show(b
->warn
);
1789 b
->idle
= gtk_label_new("");
1790 gtk_box_pack_end(GTK_BOX(box
), b
->idle
, FALSE
, FALSE
, 1);
1791 gtk_widget_show(b
->idle
);
1793 gs
->members
= g_slist_insert(gs
->members
, b
, pos
);
1794 update_num_group(gs
);
1798 static void remove_buddy_show(struct group_show
*gs
, struct buddy_show
*bs
)
1800 /* the name of this function may be misleading, but don't let it fool you. the point
1801 * of this is to remove bs->item from gs->tree, and make sure gs->tree still exists
1802 * and is a valid tree afterwards. Otherwise, Bad Things will happen. */
1803 gtk_tree_remove_item(GTK_TREE(gs
->tree
), bs
->item
);
1807 static struct group_show
*find_gs_by_bs(struct buddy_show
*b
)
1810 struct group_show
*g
= NULL
;
1811 struct buddy_show
*h
;
1815 g
= (struct group_show
*)m
->data
;
1818 h
= (struct buddy_show
*)n
->data
;
1830 static gint
log_timeout(struct buddy_show
*b
)
1832 /* this part is really just a bad hack because of a bug I can't find */
1835 struct group_show
*gs
= s
->data
;
1836 GSList
*m
= gs
->members
;
1849 /* this is the real part. */
1851 struct group_show
*g
= find_gs_by_bs(b
);
1852 g
->members
= g_slist_remove(g
->members
, b
);
1854 remove_buddy_show(g
, b
);
1856 debug_printf("log_timeout but buddy list not available\n");
1857 if ((g
->members
== NULL
) && (blist_options
& OPT_BLIST_NO_MT_GRP
)) {
1858 shows
= g_slist_remove(shows
, g
);
1860 gtk_tree_remove_item(GTK_TREE(buddies
), g
->item
);
1864 gtk_timeout_remove(b
->log_timer
);
1870 /* um.... what do we have to do here? just update the pixmap? */
1874 struct buddy
*light
= find_buddy(b
->connlist
->data
, b
->name
);
1875 if (((struct gaim_connection
*)b
->connlist
->data
)->prpl
->list_icon
)
1877 (*((struct gaim_connection
*)b
->connlist
->data
)->prpl
->list_icon
)(light
->uc
);
1879 xpm
= (char **)no_icon_xpm
;
1880 pm
= gdk_pixmap_create_from_xpm_d(blist
->window
, &bm
, NULL
, xpm
);
1881 gtk_widget_hide(b
->pix
);
1882 gtk_pixmap_set(GTK_PIXMAP(b
->pix
), pm
, bm
);
1883 gtk_widget_show(b
->pix
);
1884 if (!(blist_options
& OPT_BLIST_SHOW_PIXMAPS
))
1885 gtk_widget_hide(b
->pix
);
1886 if (misc_options
& OPT_MISC_BUDDY_TICKER
)
1887 BuddyTickerSetPixmap(b
->name
, pm
, bm
);
1888 gdk_pixmap_unref(pm
);
1889 gdk_bitmap_unref(bm
);
1890 gtk_timeout_remove(b
->log_timer
);
1897 static char *caps_string(guint caps
)
1899 static char buf
[256], *tmp
;
1900 int count
= 0, i
= 0;
1902 while (bit
<= 0x10000) {
1906 tmp
= _("Buddy Icon");
1912 tmp
= _("IM Image");
1918 tmp
= _("Get File");
1921 tmp
= _("Send File");
1931 tmp
= _("Send Buddy List");
1934 tmp
= _("EveryBuddy Bug");
1943 tmp
= _("Nihilist");
1946 tmp
= _("ICQ Server Relay");
1949 tmp
= _("ICQ Unknown");
1952 tmp
= _("Trillian Encryption");
1959 i
+= g_snprintf(buf
+ i
, sizeof(buf
) - i
, "%s%s", (count
? ", " : ""),
1968 /* for this we're just going to assume the first connection that registered the buddy.
1969 * if it's not the one you were hoping for then you're shit out of luck */
1970 static void update_idle_time(struct buddy_show
*bs
)
1972 /* this also updates the tooltip since that has idle time in it */
1973 char idlet
[16], warnl
[16];
1982 char *sotime
= NULL
, *itime
;
1989 b
= find_buddy(bs
->connlist
->data
, bs
->name
);
1992 ihrs
= (t
- b
->idle
) / 3600;
1993 imin
= ((t
- b
->idle
) / 60) % 60;
1996 g_snprintf(idlet
, sizeof idlet
, "(%d:%02d)", ihrs
, imin
);
1998 g_snprintf(idlet
, sizeof idlet
, "(%d)", imin
);
2000 gtk_widget_hide(bs
->idle
);
2002 gtk_label_set(GTK_LABEL(bs
->idle
), idlet
);
2004 gtk_label_set(GTK_LABEL(bs
->idle
), "");
2005 if (blist_options
& OPT_BLIST_SHOW_IDLETIME
)
2006 gtk_widget_show(bs
->idle
);
2008 style
= gtk_style_new();
2009 gdk_font_unref(gtk_style_get_font(style
));
2010 gtk_style_set_font(style
, gdk_font_ref(gtk_style_get_font(bs
->label
->style
)));
2011 for (i
= 0; i
< 5; i
++)
2012 style
->fg
[i
] = bs
->idle
->style
->fg
[i
];
2013 if ((blist_options
& OPT_BLIST_GREY_IDLERS
) && (b
->idle
)) {
2014 style
->fg
[GTK_STATE_NORMAL
].red
=
2015 (style
->fg
[GTK_STATE_NORMAL
].red
/ 2) + (style
->base
[GTK_STATE_NORMAL
].red
/ 2);
2016 style
->fg
[GTK_STATE_NORMAL
].green
=
2017 (style
->fg
[GTK_STATE_NORMAL
].green
/ 2) + (style
->base
[GTK_STATE_NORMAL
].green
/ 2);
2018 style
->fg
[GTK_STATE_NORMAL
].blue
=
2019 (style
->fg
[GTK_STATE_NORMAL
].blue
/ 2) + (style
->base
[GTK_STATE_NORMAL
].blue
/ 2);
2021 gtk_widget_set_style(bs
->label
, style
);
2022 gtk_style_unref(style
);
2024 /* now we do the tooltip */
2026 char *stime
= sec_to_text(t
- b
->signon
+
2027 ((struct gaim_connection
*)bs
->connlist
->data
)->
2029 sotime
= g_strdup_printf(_("Logged in: %s\n"), stime
);
2034 itime
= sec_to_text(t
- b
->idle
);
2036 itime
= g_malloc(1);
2041 g_snprintf(warn
, sizeof warn
, _("Warnings: %d%%\n"), b
->evil
);
2042 g_snprintf(warnl
, sizeof warnl
, "(%d%%)", b
->evil
);
2047 gtk_widget_hide(bs
->warn
);
2048 gtk_label_set(GTK_LABEL(bs
->warn
), warnl
);
2049 if (blist_options
& OPT_BLIST_SHOW_WARN
)
2050 gtk_widget_show(bs
->warn
);
2053 g_snprintf(caps
, sizeof caps
, _("Capabilities: %s\n"), caps_string(b
->caps
));
2057 g_snprintf(infotip
, sizeof infotip
, _("Alias: %s \nScreen Name: %s\n"
2060 (b
->signon
? sotime
: ""), warn
,
2061 (b
->idle
? _("Idle: ") : ""), itime
, (b
->idle
? "\n" : ""), caps
);
2063 gtk_tooltips_set_tip(tips
, GTK_WIDGET(bs
->item
), infotip
, "");
2070 void update_idle_times()
2072 GSList
*grp
= shows
;
2074 struct buddy_show
*b
;
2075 struct group_show
*g
;
2078 g
= (struct group_show
*)grp
->data
;
2081 b
= (struct buddy_show
*)mem
->data
;
2082 update_idle_time(b
);
2089 void set_buddy(struct gaim_connection
*gc
, struct buddy
*b
)
2091 struct group
*g
= find_group_by_buddy(gc
, b
->name
);
2092 struct group_show
*gs
;
2093 struct buddy_show
*bs
;
2102 if ((gs
= find_group_show(g
->name
)) == NULL
)
2103 gs
= new_group_show(g
->name
);
2104 if ((bs
= find_buddy_show(gs
, b
->name
)) == NULL
)
2105 bs
= new_buddy_show(gs
, b
, (char **)login_icon_xpm
);
2106 if (!g_slist_find(bs
->connlist
, gc
)) {
2107 bs
->connlist
= g_slist_append(bs
->connlist
, gc
);
2108 update_num_group(gs
);
2110 if (b
->present
== 1) {
2112 play_sound(BUDDY_ARRIVE
);
2113 pm
= gdk_pixmap_create_from_xpm_d(blist
->window
, &bm
,
2114 NULL
, (char **)login_icon_xpm
);
2115 gtk_widget_hide(bs
->pix
);
2116 gtk_pixmap_set(GTK_PIXMAP(bs
->pix
), pm
, bm
);
2117 gtk_widget_show(bs
->pix
);
2118 if (misc_options
& OPT_MISC_BUDDY_TICKER
) {
2119 BuddyTickerAddUser(b
->name
, pm
, bm
);
2120 gtk_timeout_add(10000, (GtkFunction
)BuddyTickerLogonTimeout
, b
->name
);
2122 gdk_pixmap_unref(pm
);
2123 gdk_bitmap_unref(bm
);
2125 if (bs
->log_timer
> 0)
2126 gtk_timeout_remove(bs
->log_timer
);
2127 bs
->log_timer
= gtk_timeout_add(10000, (GtkFunction
)log_timeout
, bs
);
2128 if ((bs
->sound
!= 2) && (im_options
& OPT_IM_LOGON
)) {
2129 struct conversation
*c
= find_conversation(b
->name
);
2132 g_snprintf(tmp
, sizeof(tmp
), _("%s logged in."), b
->name
);
2133 write_to_conv(c
, tmp
, WFLAG_SYSTEM
, NULL
, time(NULL
), -1);
2134 } else if (clistqueue
&& find_queue_total_by_name(b
->name
)) {
2135 struct queued_message
*qm
= g_new0(struct queued_message
, 1);
2136 qm
->message
= g_strdup_printf(_("%s logged in."), b
->name
);
2138 qm
->tm
= time(NULL
);
2139 qm
->flags
= WFLAG_SYSTEM
;
2141 message_queue
= g_slist_append(message_queue
, qm
);
2145 } else if (bs
->log_timer
== 0) {
2146 if (gc
->prpl
->list_icon
)
2147 xpm
= gc
->prpl
->list_icon(b
->uc
);
2149 xpm
= (char **)no_icon_xpm
;
2150 pm
= gdk_pixmap_create_from_xpm_d(blist
->window
, &bm
, NULL
, xpm
);
2151 gtk_widget_hide(bs
->pix
);
2152 gtk_pixmap_set(GTK_PIXMAP(bs
->pix
), pm
, bm
);
2153 gtk_widget_show(bs
->pix
);
2154 if (!(blist_options
& OPT_BLIST_SHOW_PIXMAPS
))
2155 gtk_widget_hide(bs
->pix
);
2156 if (misc_options
& OPT_MISC_BUDDY_TICKER
)
2157 BuddyTickerSetPixmap(b
->name
, pm
, bm
);
2158 gdk_pixmap_unref(pm
);
2159 gdk_bitmap_unref(bm
);
2161 update_idle_time(bs
);
2163 gs
= find_group_show(g
->name
);
2166 bs
= find_buddy_show(gs
, b
->name
);
2170 return; /* we won't do signoff updates for
2171 buddies that have already signed
2174 play_sound(BUDDY_LEAVE
);
2176 bs
->connlist
= g_slist_remove(bs
->connlist
, gc
);
2177 update_num_group(gs
);
2178 if (bs
->log_timer
> 0)
2179 gtk_timeout_remove(bs
->log_timer
);
2180 bs
->log_timer
= gtk_timeout_add(10000, (GtkFunction
)log_timeout
, bs
);
2181 pm
= gdk_pixmap_create_from_xpm_d(blist
->window
, &bm
, NULL
, logout_icon_xpm
);
2182 gtk_widget_hide(bs
->pix
);
2183 gtk_pixmap_set(GTK_PIXMAP(bs
->pix
), pm
, bm
);
2184 gtk_widget_show(bs
->pix
);
2185 if (misc_options
& OPT_MISC_BUDDY_TICKER
) {
2186 BuddyTickerSetPixmap(b
->name
, pm
, bm
);
2187 gtk_timeout_add(10000, (GtkFunction
)BuddyTickerLogoutTimeout
, b
->name
);
2189 gdk_pixmap_unref(pm
);
2190 gdk_bitmap_unref(bm
);
2191 if ((bs
->sound
!= 1) && (im_options
& OPT_IM_LOGON
)) {
2192 struct conversation
*c
= find_conversation(b
->name
);
2195 g_snprintf(tmp
, sizeof(tmp
), _("%s logged out."), b
->name
);
2196 write_to_conv(c
, tmp
, WFLAG_SYSTEM
, NULL
, time(NULL
), -1);
2197 } else if (clistqueue
&& find_queue_total_by_name(b
->name
)) {
2198 struct queued_message
*qm
= g_new0(struct queued_message
, 1);
2199 qm
->message
= g_strdup_printf(_("%s logged out."), b
->name
);
2201 qm
->tm
= time(NULL
);
2202 qm
->flags
= WFLAG_SYSTEM
;
2204 message_queue
= g_slist_append(message_queue
, qm
);
2213 static void move_blist_window(GtkWidget
*w
, GdkEventConfigure
*e
, void *dummy
)
2215 int x
, y
, width
, height
;
2217 gdk_window_get_position(blist
->window
, &x
, &y
);
2218 gdk_window_get_size(blist
->window
, &width
, &height
);
2220 if (e
->send_event
) { /* Is a position event */
2221 if (blist_pos
.x
!= x
|| blist_pos
.y
!= y
)
2225 } else { /* Is a size event */
2226 if (blist_pos
.xoff
!= x
|| blist_pos
.yoff
!= y
|| blist_pos
.width
!= width
)
2229 blist_pos
.width
= width
;
2230 blist_pos
.height
= height
;
2241 /*******************************************************************
2243 * Helper funs for making the menu
2245 *******************************************************************/
2247 void gaim_separator(GtkWidget
*menu
)
2249 GtkWidget
*sep
, *menuitem
;
2250 sep
= gtk_hseparator_new();
2251 menuitem
= gtk_menu_item_new();
2252 gtk_menu_append(GTK_MENU(menu
), menuitem
);
2253 gtk_container_add(GTK_CONTAINER(menuitem
), sep
);
2254 gtk_widget_set_sensitive(menuitem
, FALSE
);
2255 gtk_widget_show(menuitem
);
2256 gtk_widget_show(sep
);
2259 GtkWidget
*gaim_new_item(GtkWidget
*menu
, const char *str
)
2261 GtkWidget
*menuitem
;
2264 menuitem
= gtk_menu_item_new();
2266 gtk_menu_append(GTK_MENU(menu
), menuitem
);
2267 gtk_widget_show(menuitem
);
2269 label
= gtk_label_new(str
);
2270 gtk_label_set_pattern(GTK_LABEL(label
), "_");
2271 gtk_container_add(GTK_CONTAINER(menuitem
), label
);
2272 gtk_widget_show(label
);
2274 gtk_widget_add_accelerator(menuitem
, "activate-item", accel
, str
[0],
2275 GDK_MOD1_MASK
, GTK_ACCEL_LOCKED
);
2276 gtk_widget_lock_accelerators(menuitem
);
2281 GtkWidget
*gaim_new_item_with_pixmap(GtkWidget
*menu
, const char *str
, char **xpm
, GtkSignalFunc sf
,
2282 guint accel_key
, guint accel_mods
, char *mod
)
2284 GtkWidget
*menuitem
;
2291 menuitem
= gtk_menu_item_new();
2293 gtk_menu_append(GTK_MENU(menu
), menuitem
);
2295 /* passing 1 is necessary so if we sign off closing the account editor doesn't exit */
2296 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate", sf
, (void *)1);
2297 gtk_widget_show(menuitem
);
2299 /* Create our container */
2300 hbox
= gtk_hbox_new(FALSE
, 2);
2301 gtk_container_add(GTK_CONTAINER(menuitem
), hbox
);
2302 gtk_widget_show(hbox
);
2304 /* Create our pixmap and pack it */
2305 gtk_widget_realize(menu
->parent
);
2306 pm
= gdk_pixmap_create_from_xpm_d(menu
->parent
->window
, &mask
, NULL
, xpm
);
2307 pixmap
= gtk_pixmap_new(pm
, mask
);
2308 gtk_widget_show(pixmap
);
2309 gdk_pixmap_unref(pm
);
2310 gdk_bitmap_unref(mask
);
2311 gtk_box_pack_start(GTK_BOX(hbox
), pixmap
, FALSE
, FALSE
, 2);
2313 /* Create our label and pack it */
2314 label
= gtk_label_new(str
);
2315 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 2);
2316 gtk_widget_show(label
);
2319 label
= gtk_label_new(mod
);
2320 gtk_box_pack_end(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 2);
2321 gtk_widget_show(label
);
2325 gtk_widget_add_accelerator(menuitem
, "activate", accel
, accel_key
,
2326 accel_mods
, GTK_ACCEL_LOCKED
);
2327 gtk_widget_lock_accelerators(menuitem
);
2335 void build_imchat_box(gboolean on
)
2341 imbutton
= gtk_button_new_with_label(_("IM"));
2342 infobutton
= gtk_button_new_with_label(_("Info"));
2343 chatbutton
= gtk_button_new_with_label(_("Chat"));
2344 awaybutton
= gtk_button_new_with_label(_("Away"));
2346 imchatbox
= gtk_hbox_new(TRUE
, 10);
2348 if (misc_options
& OPT_MISC_COOL_LOOK
) {
2349 gtk_button_set_relief(GTK_BUTTON(imbutton
), GTK_RELIEF_NONE
);
2350 gtk_button_set_relief(GTK_BUTTON(infobutton
), GTK_RELIEF_NONE
);
2351 gtk_button_set_relief(GTK_BUTTON(chatbutton
), GTK_RELIEF_NONE
);
2352 gtk_button_set_relief(GTK_BUTTON(awaybutton
), GTK_RELIEF_NONE
);
2355 /* Put the buttons in the hbox */
2356 gtk_widget_show(imbutton
);
2357 gtk_widget_show(infobutton
);
2358 gtk_widget_show(chatbutton
);
2359 gtk_widget_show(awaybutton
);
2361 gtk_box_pack_start(GTK_BOX(imchatbox
), imbutton
, TRUE
, TRUE
, 0);
2362 gtk_box_pack_start(GTK_BOX(imchatbox
), infobutton
, TRUE
, TRUE
, 0);
2363 gtk_box_pack_start(GTK_BOX(imchatbox
), chatbutton
, TRUE
, TRUE
, 0);
2364 gtk_box_pack_start(GTK_BOX(imchatbox
), awaybutton
, TRUE
, TRUE
, 0);
2365 gtk_container_border_width(GTK_CONTAINER(imchatbox
), 5);
2367 gtk_signal_connect(GTK_OBJECT(imbutton
), "clicked", GTK_SIGNAL_FUNC(im_callback
),
2369 gtk_signal_connect(GTK_OBJECT(infobutton
), "clicked", GTK_SIGNAL_FUNC(info_callback
),
2371 gtk_signal_connect(GTK_OBJECT(chatbutton
), "clicked", GTK_SIGNAL_FUNC(chat_callback
),
2373 gtk_signal_connect(GTK_OBJECT(awaybutton
), "clicked", GTK_SIGNAL_FUNC(away_callback
),
2376 gtk_tooltips_set_tip(tips
, infobutton
, _("Information on selected Buddy"), "Penguin");
2377 gtk_tooltips_set_tip(tips
, imbutton
, _("Send Instant Message"), "Penguin");
2378 gtk_tooltips_set_tip(tips
, chatbutton
, _("Start/join a Buddy Chat"), "Penguin");
2379 gtk_tooltips_set_tip(tips
, awaybutton
, _("Activate Away Message"), "Penguin");
2381 gtk_box_pack_start(GTK_BOX(buddypane
), imchatbox
, FALSE
, FALSE
, 0);
2383 gtk_widget_show(imchatbox
);
2386 gtk_widget_destroy(imchatbox
);
2393 void show_buddy_list()
2396 /* Build the buddy list, based on *config */
2401 GtkWidget
*perlmenu
;
2405 GtkWidget
*findmenu
;
2409 GtkWidget
*menuitem
;
2410 GtkWidget
*notebook
;
2416 gtk_widget_show(blist
);
2423 blist
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
2426 gtk_window_set_wmclass(GTK_WINDOW(blist
), "buddy_list", "Gaim");
2428 gtk_widget_realize(blist
);
2429 aol_icon(blist
->window
);
2431 gtk_window_set_policy(GTK_WINDOW(blist
), TRUE
, TRUE
, TRUE
);
2433 accel
= gtk_accel_group_new();
2434 gtk_accel_group_attach(accel
, GTK_OBJECT(blist
));
2436 menubar
= gtk_menu_bar_new();
2438 menu
= gtk_menu_new();
2439 gtk_menu_set_accel_group(GTK_MENU(menu
), accel
);
2442 menuitem
= gaim_new_item(NULL
, _("File"));
2443 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), menu
);
2444 gtk_menu_bar_append(GTK_MENU_BAR(menubar
), menuitem
);
2446 gaim_new_item_with_pixmap(menu
, _("Add A Buddy"), add_small_xpm
,
2447 GTK_SIGNAL_FUNC(add_buddy_callback
), 'b', GDK_CONTROL_MASK
, "Ctl+B");
2448 gaim_new_item_with_pixmap(menu
, _("Join A Chat"), pounce_small_xpm
,
2449 GTK_SIGNAL_FUNC(chat_callback
), 'c', GDK_CONTROL_MASK
, "Ctl+C");
2450 gaim_new_item_with_pixmap(menu
, _("New Instant Message"), send_small_xpm
,
2451 GTK_SIGNAL_FUNC(show_im_dialog
), 'i', GDK_CONTROL_MASK
, "Ctl+I");
2452 gaim_new_item_with_pixmap(menu
, _("Get User Info"), search_small_xpm
,
2453 GTK_SIGNAL_FUNC(show_info_dialog
), 'j', GDK_CONTROL_MASK
, "Ctl+J");
2455 gaim_separator(menu
);
2457 gaim_new_item_with_pixmap(menu
, _("Import Buddy List"), import_small_xpm
,
2458 GTK_SIGNAL_FUNC(import_callback
), 0, 0, 0);
2459 /*gaim_new_item_with_pixmap(menu, _("Export Buddy List"), export_small_xpm,
2460 GTK_SIGNAL_FUNC(show_export_dialog), 0, 0, 0); */
2461 gaim_separator(menu
);
2462 gaim_new_item_with_pixmap(menu
, _("Signoff"), logout_menu_xpm
,
2463 GTK_SIGNAL_FUNC(signoff_all
), 'd', GDK_CONTROL_MASK
, "Ctl+D");
2466 gaim_new_item_with_pixmap(menu
, _("Quit"), exit_small_xpm
,
2467 GTK_SIGNAL_FUNC(do_quit
), 'q', GDK_CONTROL_MASK
, "Ctl+Q");
2469 gaim_new_item_with_pixmap(menu
, _("Close"), close_small_xpm
,
2470 GTK_SIGNAL_FUNC(applet_destroy_buddy
), 'x', GDK_CONTROL_MASK
, "Ctl+X");
2473 menu
= gtk_menu_new();
2475 menuitem
= gaim_new_item(NULL
, _("Tools"));
2476 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), menu
);
2477 gtk_menu_bar_append(GTK_MENU_BAR(menubar
), menuitem
);
2479 awaymenu
= gtk_menu_new();
2480 menuitem
= gaim_new_item_with_pixmap(menu
, _("Away"), away_small_xpm
, NULL
, 0, 0, 0);
2481 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), awaymenu
);
2484 bpmenu
= gtk_menu_new();
2485 menuitem
= gaim_new_item_with_pixmap(menu
, _("Buddy Pounce"), pounce_small_xpm
, NULL
, 0, 0, 0);
2486 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), bpmenu
);
2489 gaim_separator(menu
);
2492 gaim_new_item_with_pixmap(menu
, _("Accounts"), add_small_xpm
,
2493 GTK_SIGNAL_FUNC(account_editor
), 'a', GDK_CONTROL_MASK
, "Ctl+A");
2496 protomenu
= gtk_menu_new();
2498 gaim_new_item_with_pixmap(menu
, _("Protocol Actions"), prefs_small_xpm
, NULL
, 0, 0, 0);
2499 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), protomenu
);
2502 gaim_new_item_with_pixmap(menu
, _("Preferences"), prefs_small_xpm
,
2503 GTK_SIGNAL_FUNC(show_prefs
), 'p', GDK_CONTROL_MASK
, "Ctl+P");
2504 gaim_new_item_with_pixmap(menu
, _("View System Log"), prefs_small_xpm
,
2505 GTK_SIGNAL_FUNC(show_syslog
), 0, 0, 0);
2507 gaim_separator(menu
);
2510 gaim_new_item_with_pixmap(menu
, _("Plugins"), plugins_small_xpm
, GTK_SIGNAL_FUNC(show_plugins
),
2514 perlmenu
= gtk_menu_new();
2515 gtk_widget_show(perlmenu
);
2516 menuitem
= gaim_new_item_with_pixmap(menu
, _("Perl"), plugins_small_xpm
, NULL
, 0, 0, 0);
2517 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), perlmenu
);
2518 gtk_widget_show(menuitem
);
2519 menuitem
= gtk_menu_item_new_with_label(_("Load Script"));
2520 gtk_menu_append(GTK_MENU(perlmenu
), menuitem
);
2521 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate", GTK_SIGNAL_FUNC(load_perl_script
), NULL
);
2522 gtk_widget_show(menuitem
);
2523 menuitem
= gtk_menu_item_new_with_label(_("Unload All Scripts"));
2524 gtk_menu_append(GTK_MENU(perlmenu
), menuitem
);
2525 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate", GTK_SIGNAL_FUNC(unload_perl_scripts
), NULL
);
2526 gtk_widget_show(menuitem
);
2527 menuitem
= gtk_menu_item_new_with_label(_("List Scripts"));
2528 gtk_menu_append(GTK_MENU(perlmenu
), menuitem
);
2529 gtk_signal_connect(GTK_OBJECT(menuitem
), "activate", GTK_SIGNAL_FUNC(list_perl_scripts
), NULL
);
2530 gtk_widget_show(menuitem
);
2533 menu
= gtk_menu_new();
2535 menuitem
= gaim_new_item(NULL
, _("Help"));
2536 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem
), menu
);
2537 gtk_menu_item_right_justify(GTK_MENU_ITEM(menuitem
));
2538 gtk_menu_bar_append(GTK_MENU_BAR(menubar
), menuitem
);
2540 gaim_new_item_with_pixmap(menu
, _("About Gaim"), about_small_xpm
, show_about
, GDK_F1
, 0, NULL
);
2542 gtk_widget_show(menubar
);
2544 vbox
= gtk_vbox_new(FALSE
, 0);
2546 notebook
= gtk_notebook_new();
2551 /* Do buddy list stuff */
2552 /* FIXME: spacing on both panes is ad hoc */
2553 buddypane
= gtk_vbox_new(FALSE
, 1);
2555 buddies
= gtk_tree_new();
2556 sw
= gtk_scrolled_window_new(NULL
, NULL
);
2558 tips
= gtk_tooltips_new();
2559 gtk_object_set_data(GTK_OBJECT(blist
), _("Buddy List"), tips
);
2561 /* Now the buddy list */
2562 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw
), buddies
);
2563 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
2564 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2565 gtk_widget_set_usize(sw
, 200, 200);
2566 gtk_widget_show(buddies
);
2567 gtk_widget_show(sw
);
2569 gtk_box_pack_start(GTK_BOX(buddypane
), sw
, TRUE
, TRUE
, 0);
2570 gtk_widget_show(buddypane
);
2572 if (!(blist_options
& OPT_BLIST_NO_BUTTONS
))
2573 build_imchat_box(TRUE
);
2576 /* Swing the edit buddy */
2577 editpane
= gtk_vbox_new(FALSE
, 1);
2579 addbutton
= gtk_button_new_with_label(_("Add"));
2580 groupbutton
= gtk_button_new_with_label(_("Group"));
2581 rembutton
= gtk_button_new_with_label(_("Remove"));
2583 if (misc_options
& OPT_MISC_COOL_LOOK
) {
2584 gtk_button_set_relief(GTK_BUTTON(addbutton
), GTK_RELIEF_NONE
);
2585 gtk_button_set_relief(GTK_BUTTON(groupbutton
), GTK_RELIEF_NONE
);
2586 gtk_button_set_relief(GTK_BUTTON(rembutton
), GTK_RELIEF_NONE
);
2589 edittree
= gtk_ctree_new(1, 0);
2590 gtk_ctree_set_line_style(GTK_CTREE(edittree
), GTK_CTREE_LINES_SOLID
);
2591 gtk_ctree_set_expander_style(GTK_CTREE(edittree
), GTK_CTREE_EXPANDER_SQUARE
);
2592 gtk_clist_set_reorderable(GTK_CLIST(edittree
), TRUE
);
2593 gtk_signal_connect(GTK_OBJECT(edittree
), "button_press_event",
2594 GTK_SIGNAL_FUNC(click_edit_tree
), NULL
);
2596 gtk_ctree_set_drag_compare_func(GTK_CTREE(edittree
),
2597 (GtkCTreeCompareDragFunc
) edit_drag_compare_func
);
2600 gtk_signal_connect_after(GTK_OBJECT(edittree
), "tree_move",
2601 GTK_SIGNAL_FUNC(edit_tree_move
), NULL
);
2604 bbox
= gtk_hbox_new(TRUE
, 5);
2605 gtk_container_set_border_width(GTK_CONTAINER(bbox
), 5);
2606 tbox
= gtk_scrolled_window_new(NULL
, NULL
);
2607 /* Put the buttons in the box */
2608 gtk_box_pack_start(GTK_BOX(bbox
), addbutton
, TRUE
, TRUE
, 0);
2609 gtk_box_pack_start(GTK_BOX(bbox
), groupbutton
, TRUE
, TRUE
, 0);
2610 gtk_box_pack_start(GTK_BOX(bbox
), rembutton
, TRUE
, TRUE
, 0);
2612 gtk_tooltips_set_tip(tips
, addbutton
, _("Add a new Buddy"), "Penguin");
2613 gtk_tooltips_set_tip(tips
, groupbutton
, _("Add a new Group"), "Penguin");
2614 gtk_tooltips_set_tip(tips
, rembutton
, _("Remove selected Buddy/Group"), "Penguin");
2616 /* And the boxes in the box */
2617 gtk_box_pack_start(GTK_BOX(editpane
), tbox
, TRUE
, TRUE
, 0);
2618 gtk_box_pack_start(GTK_BOX(editpane
), bbox
, FALSE
, FALSE
, 0);
2620 /* Handle closes right */
2625 gtk_widget_show(addbutton
);
2626 gtk_widget_show(groupbutton
);
2627 gtk_widget_show(rembutton
);
2628 gtk_widget_show(edittree
);
2629 gtk_widget_show(tbox
);
2630 gtk_widget_show(bbox
);
2631 gtk_widget_show(editpane
);
2635 update_button_pix();
2639 label
= gtk_label_new(_("Online"));
2640 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), buddypane
, label
);
2641 label
= gtk_label_new(_("Edit Buddies"));
2642 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), editpane
, label
);
2644 gtk_widget_show_all(notebook
);
2646 /* Pack things in the vbox */
2647 gtk_widget_show(vbox
);
2650 gtk_widget_show(notebook
);
2652 /* Enable buttons */
2654 gtk_signal_connect(GTK_OBJECT(rembutton
), "clicked", GTK_SIGNAL_FUNC(do_del_buddy
), edittree
);
2655 gtk_signal_connect(GTK_OBJECT(addbutton
), "clicked", GTK_SIGNAL_FUNC(add_buddy_callback
), NULL
);
2656 gtk_signal_connect(GTK_OBJECT(groupbutton
), "clicked", GTK_SIGNAL_FUNC(add_group_callback
),
2658 gtk_box_pack_start(GTK_BOX(vbox
), menubar
, FALSE
, TRUE
, 0);
2659 gtk_box_pack_start(GTK_BOX(vbox
), notebook
, TRUE
, TRUE
, 0);
2661 gtk_container_add(GTK_CONTAINER(blist
), vbox
);
2664 gtk_signal_connect(GTK_OBJECT(blist
), "delete_event", GTK_SIGNAL_FUNC(do_quit
), blist
);
2666 gtk_signal_connect(GTK_OBJECT(blist
), "delete_event", GTK_SIGNAL_FUNC(applet_destroy_buddy
),
2670 gtk_signal_connect(GTK_OBJECT(blist
), "configure_event", GTK_SIGNAL_FUNC(move_blist_window
),
2676 gtk_container_add(GTK_CONTAINER(tbox
), edittree
);
2677 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(tbox
),
2678 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
2681 gtk_window_set_title(GTK_WINDOW(blist
), _("Gaim - Buddy List"));
2683 if (blist_options
& OPT_BLIST_SAVED_WINDOWS
) {
2684 if (blist_pos
.width
!= 0) { /* Sanity check! */
2685 gtk_widget_set_uposition(blist
, blist_pos
.x
- blist_pos
.xoff
,
2686 blist_pos
.y
- blist_pos
.yoff
);
2687 gtk_widget_set_usize(blist
, blist_pos
.width
, blist_pos
.height
);
2692 void refresh_buddy_window()
2696 update_button_pix();
2697 gtk_widget_show(blist
);