gaim/gaim

I feel dumb that it took me so long to get this right.
oldstatus v1_2_1
2005-04-03, Mark Doliner
b59671364e74
I feel dumb that it took me so long to get this right.
I hope it's right. I'm going to do a bit o' testing.
/**
* @file gtkpounce.c GTK+ Buddy Pounce API
* @ingroup gtkui
*
* gaim
*
* Gaim is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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 "internal.h"
#include "gtkgaim.h"
#include "account.h"
#include "conversation.h"
#include "debug.h"
#include "notify.h"
#include "prpl.h"
#include "request.h"
#include "server.h"
#include "sound.h"
#include "util.h"
#include "gtkblist.h"
#include "gtkdialogs.h"
#include "gtkpounce.h"
#include "gtkutils.h"
typedef struct
{
/* Pounce data */
GaimPounce *pounce;
GaimAccount *account;
/* The window */
GtkWidget *window;
/* Pounce Who */
GtkWidget *account_menu;
GtkWidget *buddy_entry;
/* Pounce When */
GtkWidget *signon;
GtkWidget *signoff;
GtkWidget *away;
GtkWidget *away_return;
GtkWidget *idle;
GtkWidget *idle_return;
GtkWidget *typing;
GtkWidget *stop_typing;
/* Pounce Action */
GtkWidget *open_win;
GtkWidget *popup;
GtkWidget *send_msg;
GtkWidget *send_msg_entry;
GtkWidget *exec_cmd;
GtkWidget *exec_cmd_entry;
GtkWidget *exec_cmd_browse;
GtkWidget *play_sound;
GtkWidget *play_sound_entry;
GtkWidget *play_sound_browse;
GtkWidget *play_sound_test;
GtkWidget *save_pounce;
/* Buttons */
GtkWidget *save_button;
} GaimGtkPounceDialog;
/**************************************************************************
* Callbacks
**************************************************************************/
static gint
delete_win_cb(GtkWidget *w, GdkEventAny *e, GaimGtkPounceDialog *dialog)
{
gtk_widget_destroy(dialog->window);
g_free(dialog);
return TRUE;
}
static void
delete_cb(GtkWidget *w, GaimGtkPounceDialog *dialog)
{
gaim_pounce_destroy(dialog->pounce);
delete_win_cb(NULL, NULL, dialog);
}
static void
cancel_cb(GtkWidget *w, GaimGtkPounceDialog *dialog)
{
delete_win_cb(NULL, NULL, dialog);
}
static void
pounce_update_entry_fields(void *user_data, const char *filename)
{
GtkWidget *entry = (GtkWidget *)user_data;
gtk_entry_set_text(GTK_ENTRY(entry), filename);
}
static void
filesel(GtkWidget *widget, gpointer data)
{
GtkWidget *entry;
const gchar *name;
entry = (GtkWidget *)data;
name = gtk_entry_get_text(GTK_ENTRY(entry));
gaim_request_file(entry, _("Select a file"), name, FALSE,
G_CALLBACK(pounce_update_entry_fields), NULL, entry);
}
static void
pounce_test_sound(GtkWidget *w, GtkWidget *entry)
{
const char *filename;
filename = gtk_entry_get_text(GTK_ENTRY(entry));
if (filename != NULL && *filename != '\0')
gaim_sound_play_file((char *) filename);
else
gaim_sound_play_event(GAIM_SOUND_POUNCE_DEFAULT);
}
static void
save_pounce_cb(GtkWidget *w, GaimGtkPounceDialog *dialog)
{
const char *name;
const char *message, *command, *sound;
GaimBuddyList *blist;
GaimGtkBuddyList *gtkblist;
GaimPounceEvent events = GAIM_POUNCE_NONE;
name = gtk_entry_get_text(GTK_ENTRY(dialog->buddy_entry));
if (*name == '\0')
{
gaim_notify_error(NULL, NULL,
_("Please enter a buddy to pounce."), NULL);
return;
}
/* Events */
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->signon)))
events |= GAIM_POUNCE_SIGNON;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->signoff)))
events |= GAIM_POUNCE_SIGNOFF;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->away)))
events |= GAIM_POUNCE_AWAY;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->away_return)))
events |= GAIM_POUNCE_AWAY_RETURN;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->idle)))
events |= GAIM_POUNCE_IDLE;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->idle_return)))
events |= GAIM_POUNCE_IDLE_RETURN;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->typing)))
events |= GAIM_POUNCE_TYPING;
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->stop_typing)))
events |= GAIM_POUNCE_TYPING_STOPPED;
/* Data fields */
message = gtk_entry_get_text(GTK_ENTRY(dialog->send_msg_entry));
command = gtk_entry_get_text(GTK_ENTRY(dialog->exec_cmd_entry));
sound = gtk_entry_get_text(GTK_ENTRY(dialog->play_sound_entry));
if (*message == '\0') message = NULL;
if (*command == '\0') command = NULL;
if (*sound == '\0') sound = NULL;
if (dialog->pounce == NULL)
{
dialog->pounce = gaim_pounce_new(GAIM_GTK_UI, dialog->account,
name, events);
}
else {
gaim_pounce_set_events(dialog->pounce, events);
gaim_pounce_set_pouncer(dialog->pounce, dialog->account);
gaim_pounce_set_pouncee(dialog->pounce, name);
}
/* Actions */
gaim_pounce_action_set_enabled(dialog->pounce, "open-window",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->open_win)));
gaim_pounce_action_set_enabled(dialog->pounce, "popup-notify",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->popup)));
gaim_pounce_action_set_enabled(dialog->pounce, "send-message",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->send_msg)));
gaim_pounce_action_set_enabled(dialog->pounce, "execute-command",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd)));
gaim_pounce_action_set_enabled(dialog->pounce, "play-sound",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->play_sound)));
gaim_pounce_action_set_attribute(dialog->pounce, "send-message",
"message", message);
gaim_pounce_action_set_attribute(dialog->pounce, "execute-command",
"command", command);
gaim_pounce_action_set_attribute(dialog->pounce, "play-sound",
"filename", sound);
/* Set the defaults for next time. */
gaim_prefs_set_bool("/gaim/gtk/pounces/default_actions/open-window",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->open_win)));
gaim_prefs_set_bool("/gaim/gtk/pounces/default_actions/popup-notify",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->popup)));
gaim_prefs_set_bool("/gaim/gtk/pounces/default_actions/send-message",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->send_msg)));
gaim_prefs_set_bool("/gaim/gtk/pounces/default_actions/execute-command",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd)));
gaim_prefs_set_bool("/gaim/gtk/pounces/default_actions/play-sound",
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->play_sound)));
gaim_pounce_set_save(dialog->pounce,
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->save_pounce)));
delete_win_cb(NULL, NULL, dialog);
gaim_pounces_sync();
/* Rebuild the pounce menu */
blist = gaim_get_blist();
if (GAIM_IS_GTK_BLIST(blist))
{
gtkblist = GAIM_GTK_BLIST(blist);
gaim_gtkpounce_menu_build(gtkblist->bpmenu);
}
}
static void
pounce_choose_cb(GtkWidget *item, GaimAccount *account,
GaimGtkPounceDialog *dialog)
{
dialog->account = account;
}
static void
buddy_changed_cb(GtkEntry *entry, GaimGtkPounceDialog *dialog)
{
if (dialog->save_button == NULL)
return;
gtk_widget_set_sensitive(dialog->save_button,
*gtk_entry_get_text(entry) != '\0');
}
static void
pounce_dnd_recv(GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
GtkSelectionData *sd, guint info, guint t, gpointer data)
{
GaimGtkPounceDialog *dialog;
if (sd->target == gdk_atom_intern("GAIM_BLIST_NODE", FALSE))
{
GaimBlistNode *node = NULL;
GaimBuddy *buddy;
memcpy(&node, sd->data, sizeof(node));
if (GAIM_BLIST_NODE_IS_CONTACT(node))
buddy = gaim_contact_get_priority_buddy((GaimContact *)node);
else if (GAIM_BLIST_NODE_IS_BUDDY(node))
buddy = (GaimBuddy *)node;
else
return;
dialog = (GaimGtkPounceDialog *)data;
gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry), buddy->name);
dialog->account = buddy->account;
gaim_gtk_account_option_menu_set_selected(dialog->account_menu, buddy->account);
gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
}
else if (sd->target == gdk_atom_intern("application/x-im-contact", FALSE))
{
char *protocol = NULL;
char *username = NULL;
GaimAccount *account;
if (gaim_gtk_parse_x_im_contact(sd->data, FALSE, &account,
&protocol, &username, NULL))
{
if (account == NULL)
{
gaim_notify_error(NULL, NULL,
_("You are not currently signed on with an account that "
"can add that buddy."), NULL);
}
else
{
dialog = (GaimGtkPounceDialog *)data;
gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry), username);
dialog->account = account;
gaim_gtk_account_option_menu_set_selected(dialog->account_menu, account);
}
}
if (username != NULL) g_free(username);
if (protocol != NULL) g_free(protocol);
gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
}
}
static const GtkTargetEntry dnd_targets[] =
{
{"GAIM_BLIST_NODE", GTK_TARGET_SAME_APP, 0},
{"application/x-im-contact", 0, 1}
};
void
gaim_gtkpounce_dialog_show(GaimAccount *account, const char *name,
GaimPounce *cur_pounce)
{
GaimGtkPounceDialog *dialog;
GtkWidget *window;
GtkWidget *label;
GtkWidget *bbox;
GtkWidget *vbox1, *vbox2;
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *frame;
GtkWidget *table;
GtkWidget *sep;
GtkSizeGroup *sg;
GPtrArray *sound_widgets;
GPtrArray *exec_widgets;
dialog = g_new0(GaimGtkPounceDialog, 1);
if (cur_pounce != NULL)
{
dialog->pounce = cur_pounce;
dialog->account = gaim_pounce_get_pouncer(cur_pounce);
}
else if (account != NULL)
{
dialog->pounce = NULL;
dialog->account = account;
}
else
{
GaimConnection *gc;
gc = (GaimConnection *)gaim_connections_get_all()->data;
dialog->pounce = NULL;
dialog->account = gaim_connection_get_account(gc);
}
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
/* Create the window. */
dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
gtk_window_set_role(GTK_WINDOW(window), "buddy_pounce");
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_window_set_title(GTK_WINDOW(window),
(cur_pounce == NULL
? _("New Buddy Pounce") : _("Edit Buddy Pounce")));
gtk_container_set_border_width(GTK_CONTAINER(window), 12);
g_signal_connect(G_OBJECT(window), "delete_event",
G_CALLBACK(delete_win_cb), dialog);
/* Create the parent vbox for everything. */
vbox1 = gtk_vbox_new(FALSE, 12);
gtk_container_add(GTK_CONTAINER(window), vbox1);
gtk_widget_show(vbox1);
/* Create the vbox that will contain all the prefs stuff. */
vbox2 = gtk_vbox_new(FALSE, 18);
gtk_box_pack_start(GTK_BOX(vbox1), vbox2, TRUE, TRUE, 0);
/* Create the "Pounce Who" frame. */
frame = gaim_gtk_make_frame(vbox2, _("Pounce Who"));
/* Account: */
hbox = gtk_hbox_new(FALSE, 6);
gtk_box_pack_start(GTK_BOX(frame), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
label = gtk_label_new_with_mnemonic(_("_Account:"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gtk_widget_show(label);
gtk_size_group_add_widget(sg, label);
dialog->account_menu =
gaim_gtk_account_option_menu_new(dialog->account, FALSE,
G_CALLBACK(pounce_choose_cb),
NULL, dialog);
gtk_box_pack_start(GTK_BOX(hbox), dialog->account_menu, FALSE, FALSE, 0);
gtk_widget_show(dialog->account_menu);
gaim_set_accessible_label (dialog->account_menu, label);
/* Buddy: */
hbox = gtk_hbox_new(FALSE, 6);
gtk_box_pack_start(GTK_BOX(frame), hbox, FALSE, FALSE, 0);
gtk_widget_show(hbox);
label = gtk_label_new_with_mnemonic(_("_Buddy name:"));
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
gtk_widget_show(label);
gtk_size_group_add_widget(sg, label);
dialog->buddy_entry = gtk_entry_new();
gtk_box_pack_start(GTK_BOX(hbox), dialog->buddy_entry, TRUE, TRUE, 0);
gtk_widget_show(dialog->buddy_entry);
g_signal_connect(G_OBJECT(dialog->buddy_entry), "changed",
G_CALLBACK(buddy_changed_cb), dialog);
gaim_set_accessible_label (dialog->buddy_entry, label);
if (cur_pounce != NULL) {
gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry),
gaim_pounce_get_pouncee(cur_pounce));
}
else if (name != NULL) {
gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry), name);
}
/* Create the "Pounce When" frame. */
frame = gaim_gtk_make_frame(vbox2, _("Pounce When"));
table = gtk_table_new(2, 4, FALSE);
gtk_container_add(GTK_CONTAINER(frame), table);
gtk_table_set_col_spacings(GTK_TABLE(table), 12);
gtk_widget_show(table);
dialog->signon =
gtk_check_button_new_with_mnemonic(_("Si_gn on"));
dialog->signoff =
gtk_check_button_new_with_mnemonic(_("Sign _off"));
dialog->away =
gtk_check_button_new_with_mnemonic(_("A_way"));
dialog->away_return =
gtk_check_button_new_with_mnemonic(_("_Return from away"));
dialog->idle =
gtk_check_button_new_with_mnemonic(_("_Idle"));
dialog->idle_return =
gtk_check_button_new_with_mnemonic(_("Retur_n from idle"));
dialog->typing =
gtk_check_button_new_with_mnemonic(_("Buddy starts _typing"));
dialog->stop_typing =
gtk_check_button_new_with_mnemonic(_("Buddy stops t_yping"));
gtk_table_attach(GTK_TABLE(table), dialog->signon, 0, 1, 0, 1,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->signoff, 1, 2, 0, 1,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->away, 0, 1, 1, 2,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->away_return, 1, 2, 1, 2,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->idle, 0, 1, 2, 3,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->idle_return, 1, 2, 2, 3,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->typing, 0, 1, 3, 4,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->stop_typing, 1, 2, 3, 5,
GTK_FILL, 0, 0, 0);
gtk_widget_show(dialog->signon);
gtk_widget_show(dialog->signoff);
gtk_widget_show(dialog->away);
gtk_widget_show(dialog->away_return);
gtk_widget_show(dialog->idle);
gtk_widget_show(dialog->idle_return);
gtk_widget_show(dialog->typing);
gtk_widget_show(dialog->stop_typing);
/* Create the "Pounce Action" frame. */
frame = gaim_gtk_make_frame(vbox2, _("Pounce Action"));
table = gtk_table_new(3, 5, FALSE);
gtk_container_add(GTK_CONTAINER(frame), table);
gtk_table_set_col_spacings(GTK_TABLE(table), 12);
gtk_widget_show(table);
dialog->open_win
= gtk_check_button_new_with_mnemonic(_("Op_en an IM window"));
dialog->popup
= gtk_check_button_new_with_mnemonic(_("_Popup notification"));
dialog->send_msg
= gtk_check_button_new_with_mnemonic(_("Send a _message"));
dialog->exec_cmd
= gtk_check_button_new_with_mnemonic(_("E_xecute a command"));
dialog->play_sound
= gtk_check_button_new_with_mnemonic(_("P_lay a sound"));
dialog->send_msg_entry = gtk_entry_new();
dialog->exec_cmd_entry = gtk_entry_new();
dialog->exec_cmd_browse = gtk_button_new_with_mnemonic(_("B_rowse..."));
dialog->play_sound_entry = gtk_entry_new();
dialog->play_sound_browse = gtk_button_new_with_mnemonic(_("Bro_wse..."));
dialog->play_sound_test = gtk_button_new_with_mnemonic(_("Pre_view"));
gtk_widget_set_sensitive(dialog->send_msg_entry, FALSE);
gtk_widget_set_sensitive(dialog->exec_cmd_entry, FALSE);
gtk_widget_set_sensitive(dialog->exec_cmd_browse, FALSE);
gtk_widget_set_sensitive(dialog->play_sound_entry, FALSE);
gtk_widget_set_sensitive(dialog->play_sound_browse, FALSE);
gtk_widget_set_sensitive(dialog->play_sound_test, FALSE);
gtk_table_attach(GTK_TABLE(table), dialog->open_win, 0, 1, 0, 1,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->popup, 0, 1, 1, 2,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->send_msg, 0, 1, 2, 3,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->send_msg_entry, 1, 4, 2, 3,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd, 0, 1, 3, 4,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_entry, 1, 2, 3, 4,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_browse, 2, 3, 3, 4,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->play_sound, 0, 1, 4, 5,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->play_sound_entry, 1, 2, 4, 5,
GTK_FILL, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->play_sound_browse, 2, 3, 4, 5,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_table_attach(GTK_TABLE(table), dialog->play_sound_test, 3, 4, 4, 5,
GTK_FILL | GTK_EXPAND, 0, 0, 0);
gtk_widget_show(dialog->open_win);
gtk_widget_show(dialog->popup);
gtk_widget_show(dialog->send_msg);
gtk_widget_show(dialog->send_msg_entry);
gtk_widget_show(dialog->exec_cmd);
gtk_widget_show(dialog->exec_cmd_entry);
gtk_widget_show(dialog->exec_cmd_browse);
gtk_widget_show(dialog->play_sound);
gtk_widget_show(dialog->play_sound_entry);
gtk_widget_show(dialog->play_sound_browse);
gtk_widget_show(dialog->play_sound_test);
g_signal_connect(G_OBJECT(dialog->send_msg), "clicked",
G_CALLBACK(gaim_gtk_toggle_sensitive),
dialog->send_msg_entry);
exec_widgets = g_ptr_array_new();
g_ptr_array_add(exec_widgets,dialog->exec_cmd_entry);
g_ptr_array_add(exec_widgets,dialog->exec_cmd_browse);
g_signal_connect(G_OBJECT(dialog->exec_cmd), "clicked",
G_CALLBACK(gtk_toggle_sensitive_array),
exec_widgets);
g_signal_connect(G_OBJECT(dialog->exec_cmd_browse), "clicked",
G_CALLBACK(filesel),
dialog->exec_cmd_entry);
sound_widgets = g_ptr_array_new();
g_ptr_array_add(sound_widgets,dialog->play_sound_entry);
g_ptr_array_add(sound_widgets,dialog->play_sound_browse);
g_ptr_array_add(sound_widgets,dialog->play_sound_test);
g_signal_connect(G_OBJECT(dialog->play_sound), "clicked",
G_CALLBACK(gtk_toggle_sensitive_array),
sound_widgets);
g_signal_connect(G_OBJECT(dialog->play_sound_browse), "clicked",
G_CALLBACK(filesel),
dialog->play_sound_entry);
g_signal_connect(G_OBJECT(dialog->play_sound_test), "clicked",
G_CALLBACK(pounce_test_sound),
dialog->play_sound_entry);
g_signal_connect(G_OBJECT(dialog->send_msg_entry), "activate",
G_CALLBACK(save_pounce_cb), dialog);
g_signal_connect(G_OBJECT(dialog->exec_cmd_entry), "activate",
G_CALLBACK(save_pounce_cb), dialog);
g_signal_connect(G_OBJECT(dialog->play_sound_entry), "activate",
G_CALLBACK(save_pounce_cb), dialog);
/* Now the last part, where we have the Save checkbox */
dialog->save_pounce = gtk_check_button_new_with_mnemonic(
_("Sav_e this pounce after activation"));
gtk_box_pack_start(GTK_BOX(vbox2), dialog->save_pounce, FALSE, FALSE, 0);
/* Separator... */
sep = gtk_hseparator_new();
gtk_box_pack_start(GTK_BOX(vbox1), sep, FALSE, FALSE, 0);
gtk_widget_show(sep);
/* Now the button box! */
bbox = gtk_hbutton_box_new();
gtk_box_set_spacing(GTK_BOX(bbox), 6);
gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
gtk_box_pack_end(GTK_BOX(vbox1), bbox, FALSE, FALSE, 0);
gtk_widget_show(bbox);
/* Delete button */
button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
if (cur_pounce == NULL)
gtk_widget_set_sensitive(button, FALSE);
gtk_widget_show(button);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(delete_cb), dialog);
/* Cancel button */
button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(cancel_cb), dialog);
/* Save button */
dialog->save_button = button = gtk_button_new_from_stock(GTK_STOCK_SAVE);
gtk_box_pack_start(GTK_BOX(bbox), button, FALSE, FALSE, 0);
gtk_widget_show(button);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(save_pounce_cb), dialog);
if (*gtk_entry_get_text(GTK_ENTRY(dialog->buddy_entry)) == '\0')
gtk_widget_set_sensitive(button, FALSE);
/* Setup drag-and-drop */
gtk_drag_dest_set(window,
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_DROP,
dnd_targets,
sizeof(dnd_targets) / sizeof(GtkTargetEntry),
GDK_ACTION_COPY);
gtk_drag_dest_set(dialog->buddy_entry,
GTK_DEST_DEFAULT_MOTION |
GTK_DEST_DEFAULT_DROP,
dnd_targets,
sizeof(dnd_targets) / sizeof(GtkTargetEntry),
GDK_ACTION_COPY);
g_signal_connect(G_OBJECT(window), "drag_data_received",
G_CALLBACK(pounce_dnd_recv), dialog);
g_signal_connect(G_OBJECT(dialog->buddy_entry), "drag_data_received",
G_CALLBACK(pounce_dnd_recv), dialog);
/* Set the values of stuff. */
if (cur_pounce != NULL)
{
GaimPounceEvent events = gaim_pounce_get_events(cur_pounce);
const char *value;
/* Events */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->signon),
(events & GAIM_POUNCE_SIGNON));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->signoff),
(events & GAIM_POUNCE_SIGNOFF));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->away),
(events & GAIM_POUNCE_AWAY));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->away_return),
(events & GAIM_POUNCE_AWAY_RETURN));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->idle),
(events & GAIM_POUNCE_IDLE));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->idle_return),
(events & GAIM_POUNCE_IDLE_RETURN));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->typing),
(events & GAIM_POUNCE_TYPING));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->stop_typing),
(events & GAIM_POUNCE_TYPING_STOPPED));
/* Actions */
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->open_win),
gaim_pounce_action_is_enabled(cur_pounce, "open-window"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->popup),
gaim_pounce_action_is_enabled(cur_pounce, "popup-notify"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->send_msg),
gaim_pounce_action_is_enabled(cur_pounce, "send-message"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd),
gaim_pounce_action_is_enabled(cur_pounce, "execute-command"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->play_sound),
gaim_pounce_action_is_enabled(cur_pounce, "play-sound"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->save_pounce),
gaim_pounce_get_save(cur_pounce));
if ((value = gaim_pounce_action_get_attribute(cur_pounce,
"send-message",
"message")) != NULL)
{
gtk_entry_set_text(GTK_ENTRY(dialog->send_msg_entry), value);
}
if ((value = gaim_pounce_action_get_attribute(cur_pounce,
"execute-command",
"command")) != NULL)
{
gtk_entry_set_text(GTK_ENTRY(dialog->exec_cmd_entry), value);
}
if ((value = gaim_pounce_action_get_attribute(cur_pounce,
"play-sound",
"filename")) != NULL)
{
gtk_entry_set_text(GTK_ENTRY(dialog->play_sound_entry), value);
}
}
else
{
GaimBuddy *buddy = NULL;
if (name != NULL)
buddy = gaim_find_buddy(account, name);
/* Set some defaults */
if (buddy == NULL)
{
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(dialog->signon), TRUE);
}
else
{
if (!GAIM_BUDDY_IS_ONLINE(buddy))
{
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(dialog->signon), TRUE);
}
else
{
gboolean default_set = FALSE;
if (buddy->idle)
{
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(dialog->idle_return), TRUE);
default_set = TRUE;
}
if (buddy->uc & UC_UNAVAILABLE)
{
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(dialog->away_return), TRUE);
default_set = TRUE;
}
if (!default_set)
{
gtk_toggle_button_set_active(
GTK_TOGGLE_BUTTON(dialog->signon), TRUE);
}
}
}
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->open_win),
gaim_prefs_get_bool("/gaim/gtk/pounces/default_actions/open-window"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->popup),
gaim_prefs_get_bool("/gaim/gtk/pounces/default_actions/popup-notify"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->send_msg),
gaim_prefs_get_bool("/gaim/gtk/pounces/default_actions/send-message"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd),
gaim_prefs_get_bool("/gaim/gtk/pounces/default_actions/execute-command"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->play_sound),
gaim_prefs_get_bool("/gaim/gtk/pounces/default_actions/play-sound"));
}
gtk_widget_show_all(vbox2);
gtk_widget_show(window);
}
static void
new_pounce_cb(GtkWidget *w, GaimBuddy *b)
{
if (b == NULL)
gaim_gtkpounce_dialog_show(NULL, NULL, NULL);
else
gaim_gtkpounce_dialog_show(b->account, b->name, NULL);
}
static void
delete_pounce_cb(GtkWidget *w, GaimPounce *pounce)
{
gaim_pounce_destroy(pounce);
}
static void
edit_pounce_cb(GtkWidget *w, GaimPounce *pounce)
{
gaim_gtkpounce_dialog_show(NULL, NULL, pounce);
}
static gboolean
fill_menu(GtkWidget *menu, GCallback cb)
{
GtkWidget *image;
GtkWidget *item;
GdkPixbuf *pixbuf, *scale;
GaimPounce *pounce;
const char *buddy;
gboolean has_items = FALSE;
GList *bp;
for (bp = gaim_pounces_get_all(); bp != NULL; bp = bp->next)
{
pounce = (GaimPounce *)bp->data;
buddy = gaim_pounce_get_pouncee(pounce);
/* Check if account is online, if not skip it */
if (!gaim_account_is_connected(pounce->pouncer))
continue;
has_items = TRUE;
/* Build the menu item */
item = gtk_image_menu_item_new_with_label(buddy);
/* Create a pixmap for the protocol icon. */
pixbuf = create_prpl_icon(gaim_pounce_get_pouncer(pounce));
if (pixbuf != NULL)
{
scale = gdk_pixbuf_scale_simple(pixbuf, 16, 16,
GDK_INTERP_BILINEAR);
/* Now convert it to GtkImage */
image = gtk_image_new_from_pixbuf(scale);
g_object_unref(G_OBJECT(scale));
g_object_unref(G_OBJECT(pixbuf));
gtk_widget_show(image);
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
}
/* Put the item in the menu */
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_show(item);
/* Set our callbacks. */
g_signal_connect(G_OBJECT(item), "activate", cb, pounce);
}
return has_items;
}
void
gaim_gtkpounce_menu_build(GtkWidget *menu)
{
GtkWidget *remmenu;
GtkWidget *item;
GList *children, *l;
gboolean has_items;
g_return_if_fail(menu != NULL);
if ((children = gtk_container_get_children(GTK_CONTAINER(menu))) != NULL)
{
for (l = children; l != NULL; l = l->next)
gtk_widget_destroy(GTK_WIDGET(l->data));
g_list_free(children);
}
/* "New Buddy Pounce" */
item = gtk_menu_item_new_with_label(_("New Buddy Pounce"));
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_show(item);
g_signal_connect(G_OBJECT(item), "activate",
G_CALLBACK(new_pounce_cb), NULL);
/* "Remove Buddy Pounce" */
item = gtk_menu_item_new_with_label(_("Remove Buddy Pounce"));
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
/* "Remove Buddy Pounce" menu */
remmenu = gtk_menu_new();
has_items = fill_menu(remmenu, G_CALLBACK(delete_pounce_cb));
if (!has_items)
gtk_widget_set_sensitive(item, FALSE);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), remmenu);
gtk_widget_show(remmenu);
gtk_widget_show(item);
/* Separator */
item = gtk_separator_menu_item_new();
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
gtk_widget_show(item);
fill_menu(menu, G_CALLBACK(edit_pounce_cb));
}
static void
pounce_cb(GaimPounce *pounce, GaimPounceEvent events, void *data)
{
GaimConversation *conv;
GaimAccount *account;
GaimBuddy *buddy;
const char *pouncee;
const char *alias;
pouncee = gaim_pounce_get_pouncee(pounce);
account = gaim_pounce_get_pouncer(pounce);
buddy = gaim_find_buddy(account, pouncee);
alias = gaim_buddy_get_alias(buddy);
if (gaim_pounce_action_is_enabled(pounce, "open-window"))
{
conv = gaim_find_conversation_with_account(pouncee, account);
if (conv == NULL)
conv = gaim_conversation_new(GAIM_CONV_IM, account, pouncee);
}
if (gaim_pounce_action_is_enabled(pounce, "popup-notify"))
{
char tmp[1024];
const char *name_shown;
char *escaped;
escaped = g_markup_escape_text(alias, -1);
/*
* Here we place the protocol name in the pounce dialog to lessen
* confusion about what protocol a pounce is for.
*/
g_snprintf(tmp, sizeof(tmp),
(events & GAIM_POUNCE_TYPING) ?
_("%s has started typing to you (%s)") :
(events & GAIM_POUNCE_SIGNON) ?
_("%s has signed on (%s)") :
(events & GAIM_POUNCE_IDLE_RETURN) ?
_("%s has returned from being idle (%s)") :
(events & GAIM_POUNCE_AWAY_RETURN) ?
_("%s has returned from being away (%s)") :
(events & GAIM_POUNCE_TYPING_STOPPED) ?
_("%s has stopped typing to you (%s)") :
(events & GAIM_POUNCE_SIGNOFF) ?
_("%s has signed off (%s)") :
(events & GAIM_POUNCE_IDLE) ?
_("%s has become idle (%s)") :
(events & GAIM_POUNCE_AWAY) ?
_("%s has gone away. (%s)") :
_("Unknown pounce event. Please report this!"),
escaped, gaim_account_get_protocol_name(account));
g_free(escaped);
/*
* Ok here is where I change the second argument, title, from
* NULL to the account name if that's all we have or the account
* alias if we have that
*/
if ((name_shown = gaim_account_get_alias(account)) == NULL)
name_shown = gaim_account_get_username(account);
gaim_notify_info(NULL, name_shown, tmp, gaim_date_full());
}
if (gaim_pounce_action_is_enabled(pounce, "send-message"))
{
const char *message;
message = gaim_pounce_action_get_attribute(pounce, "send-message",
"message");
if (message != NULL)
{
conv = gaim_find_conversation_with_account(pouncee, account);
if (conv == NULL)
conv = gaim_conversation_new(GAIM_CONV_IM, account, pouncee);
gaim_conversation_write(conv, NULL, message,
GAIM_MESSAGE_SEND, time(NULL));
serv_send_im(account->gc, (char *)pouncee, (char *)message, 0);
}
}
if (gaim_pounce_action_is_enabled(pounce, "execute-command"))
{
const char *command;
command = gaim_pounce_action_get_attribute(pounce, "execute-command",
"command");
if (command != NULL)
{
#ifndef _WIN32
int pid = fork();
if (pid == 0) {
char *args[4];
args[0] = "sh";
args[1] = "-c";
args[2] = (char *)command;
args[3] = NULL;
execvp(args[0], args);
_exit(0);
}
#else /* !_WIN32 */
STARTUPINFO StartInfo;
PROCESS_INFORMATION ProcInfo;
memset(&ProcInfo, 0, sizeof(ProcInfo));
memset(&StartInfo, 0 , sizeof(StartInfo));
StartInfo.cb = sizeof(StartInfo);
CreateProcess(NULL, (char *)command, NULL, NULL, 0, 0, NULL,
NULL, &StartInfo, &ProcInfo);
gaim_debug_info("pounce",
"Pounce execute command called for: %s\n",
command);
#endif /* !_WIN32 */
}
}
if (gaim_pounce_action_is_enabled(pounce, "play-sound"))
{
const char *sound;
sound = gaim_pounce_action_get_attribute(pounce,
"play-sound", "filename");
if (sound != NULL)
gaim_sound_play_file(sound);
else
gaim_sound_play_event(GAIM_SOUND_POUNCE_DEFAULT);
}
}
static void
free_pounce(GaimPounce *pounce)
{
GaimBuddyList *blist;
GaimGtkBuddyList *gtkblist;
/* Rebuild the pounce menu */
blist = gaim_get_blist();
if (GAIM_IS_GTK_BLIST(blist))
{
gtkblist = GAIM_GTK_BLIST(blist);
gaim_gtkpounce_menu_build(gtkblist->bpmenu);
}
}
static void
new_pounce(GaimPounce *pounce)
{
gaim_pounce_action_register(pounce, "open-window");
gaim_pounce_action_register(pounce, "popup-notify");
gaim_pounce_action_register(pounce, "send-message");
gaim_pounce_action_register(pounce, "execute-command");
gaim_pounce_action_register(pounce, "play-sound");
}
void
gaim_gtk_pounces_init(void)
{
gaim_pounces_register_handler(GAIM_GTK_UI, pounce_cb, new_pounce,
free_pounce);
gaim_prefs_add_none("/gaim/gtk/pounces");
gaim_prefs_add_none("/gaim/gtk/pounces/default_actions");
gaim_prefs_add_bool("/gaim/gtk/pounces/default_actions/open-window",
FALSE);
gaim_prefs_add_bool("/gaim/gtk/pounces/default_actions/popup-notify",
FALSE);
gaim_prefs_add_bool("/gaim/gtk/pounces/default_actions/send-message",
TRUE);
gaim_prefs_add_bool("/gaim/gtk/pounces/default_actions/execute-command",
FALSE);
gaim_prefs_add_bool("/gaim/gtk/pounces/default_actions/play-sound",
FALSE);
}