Mercurial > pidgin.yaz
view src/pounce.c @ 4866:703e02e52262
[gaim-migrate @ 5196]
Added new typed and typing images to replace the gear.
Missing stock icons now result in critical errors being shown.
Restored the away button icon.
Yay! You may now serve me cheese.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Sat, 22 Mar 2003 22:24:33 +0000 |
parents | 677d3cb193a1 |
children | cb700c07ee07 |
line wrap: on
line source
/* * gaim * * Copyright (C) 1998-2003, Mark Spencer <markster@marko.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <unistd.h> #include "gaim.h" #include "prpl.h" #include "pounce.h" GtkWidget *bpmenu = NULL; void rem_bp(GtkWidget *w, struct buddy_pounce *b) { buddy_pounces = g_list_remove(buddy_pounces, b); do_bp_menu(); save_prefs(); } void do_pounce(struct gaim_connection *gc, char *name, int when) { char *who; struct buddy_pounce *b; struct gaim_conversation *c; struct gaim_account *account; GList *bp = buddy_pounces; who = g_strdup(normalize (name)); while (bp) { b = (struct buddy_pounce *)bp->data; bp = bp->next; /* increment the list here because rem_bp can make our handle bad */ if (!(b->options & when)) continue; account = gaim_account_find(b->pouncer, b->protocol); /* find our user */ if (account == NULL) continue; /* check and see if we're signed on as the pouncer */ if (account->gc != gc) continue; if (!gaim_utf8_strcasecmp(who, normalize (b->name))) { /* find someone to pounce */ if (b->options & OPT_POUNCE_POPUP) { c = gaim_find_conversation(name); if (c == NULL) c = gaim_conversation_new(GAIM_CONV_IM, account, name); else gaim_conversation_set_account(c, account); } if (b->options & OPT_POUNCE_NOTIFY) { char tmp[1024]; /* I know the line below is really ugly. I only did it this way * because I thought it'd be funny :-) */ g_snprintf(tmp, sizeof(tmp), (when & OPT_POUNCE_TYPING) ? _("%s has started typing to you") : (when & OPT_POUNCE_SIGNON) ? _("%s has signed on") : (when & OPT_POUNCE_UNIDLE) ? _("%s has returned from being idle") : _("%s has returned from being away"), name); do_error_dialog(tmp, NULL, GAIM_INFO); } if (b->options & OPT_POUNCE_SEND_IM) { if (strlen(b->message) > 0) { c = gaim_find_conversation(name); if (c == NULL) c = gaim_conversation_new(GAIM_CONV_IM, account, name); else gaim_conversation_set_account(c, account); gaim_conversation_write(c, NULL, b->message, -1, WFLAG_SEND, time(NULL)); serv_send_im(account->gc, name, b->message, -1, 0); } } if (b->options & OPT_POUNCE_COMMAND) { #ifndef _WIN32 int pid = fork(); if (pid == 0) { char *args[4]; args[0] = "sh"; args[1] = "-c"; args[2] = b->command; args[3] = NULL; execvp(args[0], args); _exit(0); } #else STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si) ); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); CreateProcess( NULL, b->command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); CloseHandle( pi.hProcess ); CloseHandle( pi.hThread ); #endif /*_WIN32*/ } /* if (b->options & OPT_POUNCE_SOUND) { if (strlen(b->sound)) play_file(b->sound); else play_sound(SND_POUNCE_DEFAULT); }*/ if (!(b->options & OPT_POUNCE_SAVE)) rem_bp(NULL, b); } } g_free(who); } static void new_bp_callback(GtkWidget *w, struct buddy *b) { if (b) show_new_bp(b->name, b->account->gc, b->idle, b->uc & UC_UNAVAILABLE, NULL); else show_new_bp(NULL, NULL, 0, 0, NULL); } static void edit_bp_callback(GtkWidget *w, struct buddy_pounce *b) { show_new_bp(NULL, NULL, 0, 0, b); } static GtkTooltips *bp_tooltip = NULL; void do_bp_menu() { GtkWidget *menuitem, *mess, *messmenu; static GtkWidget *remmenu; GtkWidget *remitem; GtkWidget *sep; GList *l; struct buddy_pounce *b; GList *bp = buddy_pounces; /* Tooltip for editing bp's */ if(!bp_tooltip) bp_tooltip = gtk_tooltips_new(); l = gtk_container_get_children(GTK_CONTAINER(bpmenu)); while (l) { gtk_widget_destroy(GTK_WIDGET(l->data)); l = l->next; } remmenu = gtk_menu_new(); menuitem = gtk_menu_item_new_with_label(_("New Buddy Pounce")); gtk_menu_shell_append(GTK_MENU_SHELL(bpmenu), menuitem); gtk_widget_show(menuitem); g_signal_connect(GTK_OBJECT(menuitem), "activate", G_CALLBACK(new_bp_callback), NULL); while (bp) { b = (struct buddy_pounce *)bp->data; remitem = gtk_menu_item_new_with_label(b->name); gtk_menu_shell_append(GTK_MENU_SHELL(remmenu), remitem); gtk_widget_show(remitem); g_signal_connect(GTK_OBJECT(remitem), "activate", G_CALLBACK(rem_bp), b); bp = bp->next; } menuitem = gtk_menu_item_new_with_label(_("Remove Buddy Pounce")); gtk_menu_shell_append(GTK_MENU_SHELL(bpmenu), menuitem); gtk_widget_show(menuitem); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), remmenu); gtk_widget_show(remmenu); sep = gtk_hseparator_new(); menuitem = gtk_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(bpmenu), menuitem); gtk_container_add(GTK_CONTAINER(menuitem), sep); gtk_widget_set_sensitive(menuitem, FALSE); gtk_widget_show(menuitem); gtk_widget_show(sep); bp = buddy_pounces; while (bp) { b = (struct buddy_pounce *)bp->data; menuitem = gtk_menu_item_new_with_label(b->name); gtk_menu_shell_append(GTK_MENU_SHELL(bpmenu), menuitem); messmenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), messmenu); gtk_widget_show(menuitem); if (strlen(b->message)) mess = gtk_menu_item_new_with_label(b->message); else mess = gtk_menu_item_new_with_label(_("[no message]")); gtk_menu_shell_append(GTK_MENU_SHELL(messmenu), mess); gtk_tooltips_set_tip(bp_tooltip, GTK_WIDGET(mess), _("[Click to edit]"), NULL); gtk_widget_show(mess); g_signal_connect(GTK_OBJECT(mess), "activate", G_CALLBACK(edit_bp_callback), b); bp = bp->next; } } /*------------------------------------------------------------------------*/ /* The dialog for new buddy pounces */ /*------------------------------------------------------------------------*/ void do_new_bp(GtkWidget *w, struct addbp *b) { struct buddy_pounce *bp; if (strlen(gtk_entry_get_text(GTK_ENTRY(b->nameentry))) == 0) { do_error_dialog(_("Please enter a buddy to pounce."), NULL, GAIM_ERROR); return; } if(!b->buddy_pounce) bp = g_new0(struct buddy_pounce, 1); else bp = b->buddy_pounce; g_snprintf(bp->name, 80, "%s", gtk_entry_get_text(GTK_ENTRY(b->nameentry))); g_snprintf(bp->message, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->messentry))); g_snprintf(bp->command, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->commentry))); g_snprintf(bp->sound, 2048, "%s", gtk_entry_get_text(GTK_ENTRY(b->soundentry))); g_snprintf(bp->pouncer, 80, "%s", b->account->username); bp->protocol = b->account->protocol; bp->options = 0; if (GTK_TOGGLE_BUTTON(b->popupnotify)->active) bp->options |= OPT_POUNCE_NOTIFY; if (GTK_TOGGLE_BUTTON(b->openwindow)->active) bp->options |= OPT_POUNCE_POPUP; if (GTK_TOGGLE_BUTTON(b->sendim)->active) bp->options |= OPT_POUNCE_SEND_IM; if (GTK_TOGGLE_BUTTON(b->command)->active) bp->options |= OPT_POUNCE_COMMAND; if (GTK_TOGGLE_BUTTON(b->sound)->active) bp->options |= OPT_POUNCE_SOUND; if (GTK_TOGGLE_BUTTON(b->p_signon)->active) bp->options |= OPT_POUNCE_SIGNON; if (GTK_TOGGLE_BUTTON(b->p_unaway)->active) bp->options |= OPT_POUNCE_UNAWAY; if (GTK_TOGGLE_BUTTON(b->p_unidle)->active) bp->options |= OPT_POUNCE_UNIDLE; if (GTK_TOGGLE_BUTTON(b->p_typing)->active) bp->options |= OPT_POUNCE_TYPING; if (GTK_TOGGLE_BUTTON(b->save)->active) bp->options |= OPT_POUNCE_SAVE; if(!b->buddy_pounce) buddy_pounces = g_list_append(buddy_pounces, bp); do_bp_menu(); gtk_widget_destroy(b->window); save_prefs(); g_free(b); } static void pounce_choose(GtkWidget *opt, struct addbp *b) { struct gaim_account *account = g_object_get_data(G_OBJECT(opt), "gaim_account"); b->account = account; } static GtkWidget *pounce_user_menu(struct addbp *b, struct gaim_connection *gc) { GtkWidget *optmenu; GtkWidget *menu; GtkWidget *opt; GSList *u = gaim_accounts; struct gaim_account *account; struct prpl *p; int count = 0; int place = 0; char buf[2048]; optmenu = gtk_option_menu_new(); menu = gtk_menu_new(); while (u) { account = (struct gaim_account *)u->data; p = (struct prpl *)find_prpl(account->protocol); g_snprintf(buf, sizeof buf, "%s (%s)", account->username, (p && p->name)?p->name:_("Unknown")); opt = gtk_menu_item_new_with_label(buf); g_object_set_data(G_OBJECT(opt), "gaim_account", account); g_signal_connect(GTK_OBJECT(opt), "activate", G_CALLBACK(pounce_choose), b); gtk_menu_shell_append(GTK_MENU_SHELL(menu), opt); gtk_widget_show(opt); if (b->account == account) { gtk_menu_item_activate(GTK_MENU_ITEM(opt)); place = count; } count++; u = u->next; } gtk_option_menu_set_menu(GTK_OPTION_MENU(optmenu), menu); gtk_option_menu_set_history(GTK_OPTION_MENU(optmenu), place); b->menu = optmenu; return optmenu; } void show_new_bp(char *name, struct gaim_connection *gc, int idle, int away, struct buddy_pounce *edit_bp) { GtkWidget *label; GtkWidget *bbox; GtkWidget *vbox; GtkWidget *button; GtkWidget *frame; GtkWidget *table; GtkWidget *optmenu; GtkWidget *sep; GtkSizeGroup *sg; struct addbp *b = g_new0(struct addbp, 1); if(edit_bp) { b->buddy_pounce = edit_bp; b->account = gaim_account_find(edit_bp->pouncer, edit_bp->protocol); } else { b->account = gc ? gc->account : gaim_accounts->data; b->buddy_pounce = NULL; } GAIM_DIALOG(b->window); gtk_window_set_resizable(GTK_WINDOW(b->window), TRUE); gtk_window_set_role(GTK_WINDOW(b->window), "new_bp"); gtk_window_set_title(GTK_WINDOW(b->window), _("New Buddy Pounce")); g_signal_connect(GTK_OBJECT(b->window), "destroy", G_CALLBACK(gtk_widget_destroy), b->window); gtk_widget_realize(b->window); vbox = gtk_vbox_new(FALSE, 5); gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); gtk_container_add(GTK_CONTAINER(b->window), vbox); gtk_widget_show(vbox); /* <pounce type="who"> */ frame = gtk_frame_new(_("Pounce Who")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(frame)); table = gtk_table_new(2, 2, FALSE); gtk_container_add(GTK_CONTAINER(frame), table); gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_table_set_col_spacings(GTK_TABLE(table), 5); gtk_table_set_row_spacings(GTK_TABLE(table), 5); gtk_widget_show(table); label = gtk_label_new(_("Account")); gtk_misc_set_alignment(GTK_MISC(label), 0, .5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); gtk_widget_show(label); optmenu = pounce_user_menu(b, gc); gtk_table_attach(GTK_TABLE(table), optmenu, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); gtk_widget_show(optmenu); label = gtk_label_new(_("Buddy")); gtk_misc_set_alignment(GTK_MISC(label), 0, .5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show(label); b->nameentry = gtk_entry_new(); gtk_table_attach(GTK_TABLE(table), b->nameentry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); if (name !=NULL) gtk_entry_set_text(GTK_ENTRY(b->nameentry), name); else if(edit_bp) gtk_entry_set_text(GTK_ENTRY(b->nameentry), edit_bp->name); gtk_window_set_focus(GTK_WINDOW(b->window), b->nameentry); gtk_widget_show(b->nameentry); /* </pounce type="who"> */ /* <pounce type="when"> */ frame = gtk_frame_new(_("Pounce When")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(frame)); table = gtk_table_new(2, 2, FALSE); gtk_container_add(GTK_CONTAINER(frame), table); gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_table_set_col_spacings(GTK_TABLE(table), 5); gtk_widget_show(table); b->p_signon = gtk_check_button_new_with_label(_("Pounce on sign on")); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_signon), (edit_bp->options & OPT_POUNCE_SIGNON) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_signon), TRUE); gtk_table_attach(GTK_TABLE(table), b->p_signon, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); gtk_widget_show(b->p_signon); b->p_unaway = gtk_check_button_new_with_label(_("Pounce on return from away")); if (away) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unaway), TRUE); else if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unaway), (edit_bp->options & OPT_POUNCE_UNAWAY) ? TRUE : FALSE); gtk_table_attach(GTK_TABLE(table), b->p_unaway, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); gtk_widget_show(b->p_unaway); b->p_unidle = gtk_check_button_new_with_label(_("Pounce on return from idle")); if (idle) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unidle), TRUE); else if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_unidle), (edit_bp->options & OPT_POUNCE_UNIDLE) ? TRUE : FALSE); gtk_table_attach(GTK_TABLE(table), b->p_unidle, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show(b->p_unidle); b->p_typing = gtk_check_button_new_with_label(_("Pounce when buddy is typing to you")); if (edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->p_typing), (edit_bp->options & OPT_POUNCE_TYPING) ? TRUE : FALSE); gtk_table_attach(GTK_TABLE(table), b->p_typing,1,2,1,2, GTK_FILL | GTK_EXPAND, 0, 0, 0); gtk_widget_show(b->p_typing); /* </pounce type="when"> */ /* <pounce type="action"> */ frame = gtk_frame_new(_("Pounce Action")); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(frame)); table = gtk_table_new(4, 2, FALSE); gtk_container_add(GTK_CONTAINER(frame), table); gtk_container_set_border_width(GTK_CONTAINER(table), 5); gtk_table_set_col_spacings(GTK_TABLE(table), 5); gtk_table_set_row_spacings(GTK_TABLE(table), 5); gtk_widget_show(table); b->openwindow = gtk_check_button_new_with_label(_("Open IM Window")); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->openwindow), (edit_bp->options & OPT_POUNCE_POPUP) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->openwindow), FALSE); gtk_table_attach(GTK_TABLE(table), b->openwindow, 0, 1, 0, 1, GTK_FILL, 0, 0, 0); gtk_widget_show(b->openwindow); b->popupnotify = gtk_check_button_new_with_label(_("Popup Notification")); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->popupnotify), (edit_bp->options & OPT_POUNCE_NOTIFY) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->popupnotify), FALSE); gtk_table_attach(GTK_TABLE(table), b->popupnotify, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); gtk_widget_show(b->popupnotify); b->sendim = gtk_check_button_new_with_label(_("Send Message")); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sendim), (edit_bp->options & OPT_POUNCE_SEND_IM) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sendim), TRUE); gtk_table_attach(GTK_TABLE(table), b->sendim, 0, 1, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_show(b->sendim); b->messentry = gtk_entry_new(); gtk_table_attach(GTK_TABLE(table), b->messentry, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); g_signal_connect(GTK_OBJECT(b->messentry), "activate", G_CALLBACK(do_new_bp), b); if(edit_bp) { gtk_widget_set_sensitive(GTK_WIDGET(b->messentry), (edit_bp->options & OPT_POUNCE_SEND_IM) ? TRUE : FALSE); gtk_entry_set_text(GTK_ENTRY(b->messentry), edit_bp->message); } gtk_widget_show(b->messentry); g_signal_connect(GTK_OBJECT(b->sendim), "clicked", G_CALLBACK(gaim_gtk_toggle_sensitive), b->messentry); b->command = gtk_check_button_new_with_label(_("Execute command on pounce")); gtk_table_attach(GTK_TABLE(table), b->command, 0, 1, 2, 3, GTK_FILL, 0, 0, 0); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->command), (edit_bp->options & OPT_POUNCE_COMMAND) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->command), FALSE); gtk_widget_show(b->command); b->commentry = gtk_entry_new(); gtk_table_attach(GTK_TABLE(table), b->commentry, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0); g_signal_connect(GTK_OBJECT(b->commentry), "activate", G_CALLBACK(do_new_bp), b); if(edit_bp) { gtk_widget_set_sensitive(GTK_WIDGET(b->commentry), (edit_bp->options & OPT_POUNCE_COMMAND) ? TRUE : FALSE); gtk_entry_set_text(GTK_ENTRY(b->commentry), edit_bp->command); } else gtk_widget_set_sensitive(GTK_WIDGET(b->commentry), FALSE); gtk_widget_show(b->commentry); g_signal_connect(GTK_OBJECT(b->command), "clicked", G_CALLBACK(gaim_gtk_toggle_sensitive), b->commentry); b->sound = gtk_check_button_new_with_label(_("Play sound on pounce")); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sound), (edit_bp->options & OPT_POUNCE_SOUND) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->sound), FALSE); gtk_table_attach(GTK_TABLE(table), b->sound, 0, 1, 3, 4, GTK_FILL, 0, 0, 0); gtk_widget_show(b->sound); b->soundentry = gtk_entry_new(); gtk_table_attach(GTK_TABLE(table), b->soundentry, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, 0, 0, 0); g_signal_connect(GTK_OBJECT(b->soundentry), "activate", G_CALLBACK(do_new_bp), b); if(edit_bp) { gtk_widget_set_sensitive(GTK_WIDGET(b->soundentry), (edit_bp->options & OPT_POUNCE_SOUND) ? TRUE : FALSE); gtk_entry_set_text(GTK_ENTRY(b->soundentry), edit_bp->sound); } else gtk_widget_set_sensitive(GTK_WIDGET(b->soundentry), FALSE); gtk_widget_show(b->soundentry); g_signal_connect(GTK_OBJECT(b->sound), "clicked", G_CALLBACK(gaim_gtk_toggle_sensitive), b->soundentry); /* </pounce type="action"> */ b->save = gtk_check_button_new_with_label(_("Save this pounce after activation")); gtk_container_set_border_width(GTK_CONTAINER(b->save), 7); if(edit_bp) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->save), (edit_bp->options & OPT_POUNCE_SAVE) ? TRUE : FALSE); else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(b->save), FALSE); gtk_box_pack_start(GTK_BOX(vbox), b->save, FALSE, FALSE, 0); gtk_widget_show(b->save); sep = gtk_hseparator_new(); gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); gtk_widget_show(sep); bbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); gtk_widget_show(bbox); sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); button = gaim_pixbuf_button_from_stock(_("_Save"), "gtk-execute", GAIM_BUTTON_HORIZONTAL); gtk_size_group_add_widget(sg, button); g_signal_connect(GTK_OBJECT(button), "clicked", G_CALLBACK(do_new_bp), b); gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); button = gaim_pixbuf_button_from_stock(_("C_ancel"), "gtk-cancel", GAIM_BUTTON_HORIZONTAL); gtk_size_group_add_widget(sg, button); g_signal_connect_swapped(GTK_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), b->window); gtk_box_pack_end(GTK_BOX(bbox), button, FALSE, FALSE, 0); gtk_widget_show(button); gtk_widget_show(b->window); }