pidgin/purple-plugin-pack

Instead of trying to fix this plugin up with the existing code, I've decided
org.guifications.plugins.smartear
2007-07-05, rekkanoryo
d2d1be982de1
Parents 1b2df7dcbe16
Children 531fa0e12bbe
Instead of trying to fix this plugin up with the existing code, I've decided
to give it a complete rewrite. The intent is that by being as generic as
possible I'll be able to make this plugin work for Finch, Pidgin, and any
other libpurple app that decides to implement sound. We might end up with
some cleaner code out of the process too. :)
--- a/smartear/Makefile.am Tue Jul 03 04:45:10 2007 -0400
+++ b/smartear/Makefile.am Thu Jul 05 05:46:17 2007 -0400
@@ -1,34 +1,26 @@
-EXTRA_DIST=\
+EXTRA_DIST= \
.build \
- .pidgin-plugin \
- Makefile.mingw \
- smartear.glade \
- interface.c \
- make-interface.sh
+ .purple-plugin \
+ Makefile.mingw
smarteardir = $(PIDGIN_LIBDIR)
smartear_la_LDFLAGS = -module -avoid-version
-if HAVE_PIDGIN
+if HAVE_PURPLE
smartear_LTLIBRARIES = smartear.la
-smartear_la_SOURCES = \
- smartear.c \
- smartear-interface.c
+smartear_la_SOURCES = smartear.c
-smartear_la_LIBADD = \
- $(GTK_LIBS) \
- $(PIDGIN_LIBS)
+smartear_la_LIBADD = $(PURPLE_LIBS)
endif
AM_CPPFLAGS = \
- -DLIBDIR=\"$(PIDGIN_LIBDIR)\" \
- -DDATADIR=\"$(PIDGIN_DATADIR)\" \
- -DPIXMAPSDIR=\"$(PIDGIN_PIXMAPSDIR)\" \
+ -DLIBDIR=\"$(PURPLE_LIBDIR)\" \
+ -DDATADIR=\"$(PURPLE_DATADIR)\" \
+ -DPIXMAPSDIR=\"$(PURPLE_PIXMAPSDIR)\" \
$(DEBUG_CFLAGS) \
- $(GTK_CFLAGS) \
- $(PIDGIN_CFLAGS)
+ $(PURPLE_CFLAGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smartear/old-smartear-interface.c Thu Jul 05 05:46:17 2007 -0400
@@ -0,0 +1,546 @@
+/* GPL Header */
+
+#ifdef HAVE_CONFIG_H
+# include "../pp_config.h"
+#endif
+
+#include <gtk/gtk.h>
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+GtkWidget*
+create_config (void)
+{
+ GtkWidget *config_vbox;
+ GtkWidget *frame1;
+ GtkWidget *table1;
+ GtkWidget *label9;
+ GtkObject *delay_spin_adj;
+ GtkWidget *delay_spin;
+ GtkWidget *focus_but;
+ GtkWidget *timer_but;
+ GtkWidget *label8;
+ GtkWidget *frame2;
+ GtkWidget *table2;
+ GtkWidget *delete_but;
+ GtkWidget *new_but;
+ GtkWidget *scrolledwindow2;
+ GtkWidget *treeview;
+ GtkWidget *edit_but;
+ GtkWidget *label7;
+ GtkWidget *hbuttonbox1;
+ GtkWidget *revert_but;
+ GtkWidget *save_but;
+
+
+ config_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_widget_set_size_request (config_vbox, -1, 640);
+
+ frame1 = gtk_frame_new (NULL);
+ gtk_widget_show (frame1);
+ gtk_box_pack_start (GTK_BOX (config_vbox), frame1, FALSE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (frame1), 5);
+
+ table1 = gtk_table_new (3, 2, FALSE);
+ gtk_widget_show (table1);
+ gtk_container_add (GTK_CONTAINER (frame1), table1);
+ gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
+ gtk_table_set_row_spacings (GTK_TABLE (table1), 10);
+ gtk_table_set_col_spacings (GTK_TABLE (table1), 10);
+
+ label9 = gtk_label_new ("Time delay between playing sounds for a particular buddy:");
+ gtk_widget_show (label9);
+ gtk_table_attach (GTK_TABLE (table1), label9, 0, 1, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label9), 0, 0.5);
+
+ delay_spin_adj = gtk_adjustment_new (60, 0, 1000000, 1, 10, 10);
+ delay_spin = gtk_spin_button_new (GTK_ADJUSTMENT (delay_spin_adj), 1, 0);
+ gtk_widget_show (delay_spin);
+ gtk_table_attach (GTK_TABLE (table1), delay_spin, 1, 2, 0, 1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (delay_spin), GTK_UPDATE_IF_VALID);
+
+ focus_but = gtk_check_button_new_with_mnemonic ("Don't play sounds for the conversation that has focus.");
+ gtk_widget_show (focus_but);
+ gtk_table_attach (GTK_TABLE (table1), focus_but, 0, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ timer_but = gtk_check_button_new_with_mnemonic ("Also play sounds if you don't respond to a particular IM within a delay period.");
+ gtk_widget_show (timer_but);
+ gtk_table_attach (GTK_TABLE (table1), timer_but, 0, 2, 2, 3,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ label8 = gtk_label_new ("Options");
+ gtk_widget_show (label8);
+ gtk_frame_set_label_widget (GTK_FRAME (frame1), label8);
+
+ frame2 = gtk_frame_new (NULL);
+ gtk_widget_show (frame2);
+ gtk_box_pack_start (GTK_BOX (config_vbox), frame2, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (frame2), 5);
+
+ table2 = gtk_table_new (2, 3, FALSE);
+ gtk_widget_show (table2);
+ gtk_container_add (GTK_CONTAINER (frame2), table2);
+ gtk_container_set_border_width (GTK_CONTAINER (table2), 5);
+ gtk_table_set_row_spacings (GTK_TABLE (table2), 10);
+ gtk_table_set_col_spacings (GTK_TABLE (table2), 10);
+
+ delete_but = gtk_button_new_from_stock ("gtk-delete");
+ gtk_widget_show (delete_but);
+ gtk_table_attach (GTK_TABLE (table2), delete_but, 2, 3, 1, 2,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ GTK_WIDGET_SET_FLAGS (delete_but, GTK_CAN_DEFAULT);
+
+ new_but = gtk_button_new_from_stock ("gtk-new");
+ gtk_widget_show (new_but);
+ gtk_table_attach (GTK_TABLE (table2), new_but, 0, 1, 1, 2,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ GTK_WIDGET_SET_FLAGS (new_but, GTK_CAN_DEFAULT);
+
+ scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow2);
+ gtk_table_attach (GTK_TABLE (table2), scrolledwindow2, 0, 3, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ treeview = gtk_tree_view_new ();
+ gtk_widget_show (treeview);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow2), treeview);
+
+ edit_but = gtk_button_new_from_stock ("gtk-properties");
+ gtk_widget_show (edit_but);
+ gtk_table_attach (GTK_TABLE (table2), edit_but, 1, 2, 1, 2,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ label7 = gtk_label_new ("Entries");
+ gtk_widget_show (label7);
+ gtk_frame_set_label_widget (GTK_FRAME (frame2), label7);
+
+ hbuttonbox1 = gtk_hbutton_box_new ();
+ gtk_widget_show (hbuttonbox1);
+ gtk_box_pack_start (GTK_BOX (config_vbox), hbuttonbox1, FALSE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 5);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD);
+
+ revert_but = gtk_button_new_from_stock ("gtk-revert-to-saved");
+ gtk_widget_show (revert_but);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox1), revert_but);
+ GTK_WIDGET_SET_FLAGS (revert_but, GTK_CAN_DEFAULT);
+
+ save_but = gtk_button_new_from_stock ("gtk-save");
+ gtk_widget_show (save_but);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox1), save_but);
+ GTK_WIDGET_SET_FLAGS (save_but, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) config_vbox, "destroy",
+ G_CALLBACK (on_config_destroy),
+ NULL);
+ g_signal_connect ((gpointer) delay_spin, "changed",
+ G_CALLBACK (on_delay_changed),
+ NULL);
+ g_signal_connect ((gpointer) focus_but, "toggled",
+ G_CALLBACK (on_focus_toggled),
+ NULL);
+ g_signal_connect ((gpointer) timer_but, "toggled",
+ G_CALLBACK (on_timer_toggled),
+ NULL);
+ g_signal_connect ((gpointer) delete_but, "clicked",
+ G_CALLBACK (on_delete_clicked),
+ NULL);
+ g_signal_connect ((gpointer) new_but, "clicked",
+ G_CALLBACK (on_new_clicked),
+ NULL);
+ g_signal_connect ((gpointer) edit_but, "clicked",
+ G_CALLBACK (on_edit_clicked),
+ NULL);
+ g_signal_connect ((gpointer) revert_but, "clicked",
+ G_CALLBACK (on_revert_clicked),
+ NULL);
+ g_signal_connect ((gpointer) save_but, "clicked",
+ G_CALLBACK (on_save_clicked),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, config_vbox, "config_vbox");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, frame1, "frame1");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, table1, "table1");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, label9, "label9");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, delay_spin, "delay_spin");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, focus_but, "focus_but");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, timer_but, "timer_but");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, label8, "label8");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, frame2, "frame2");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, table2, "table2");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, delete_but, "delete_but");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, new_but, "new_but");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, scrolledwindow2, "scrolledwindow2");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, treeview, "treeview");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, edit_but, "edit_but");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, label7, "label7");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, hbuttonbox1, "hbuttonbox1");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, revert_but, "revert_but");
+ GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, save_but, "save_but");
+
+ return config_vbox;
+}
+
+GtkWidget*
+create_file_browse (void)
+{
+ GtkWidget *file_browse;
+ GtkWidget *ok_button1;
+ GtkWidget *cancel_button1;
+
+ file_browse = gtk_file_selection_new ("Select Sound");
+ gtk_container_set_border_width (GTK_CONTAINER (file_browse), 10);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (file_browse), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (file_browse), GDK_WINDOW_TYPE_HINT_DIALOG);
+
+ ok_button1 = GTK_FILE_SELECTION (file_browse)->ok_button;
+ gtk_widget_show (ok_button1);
+ GTK_WIDGET_SET_FLAGS (ok_button1, GTK_CAN_DEFAULT);
+
+ cancel_button1 = GTK_FILE_SELECTION (file_browse)->cancel_button;
+ gtk_widget_show (cancel_button1);
+ GTK_WIDGET_SET_FLAGS (cancel_button1, GTK_CAN_DEFAULT);
+
+ g_signal_connect ((gpointer) file_browse, "destroy",
+ G_CALLBACK (on_file_browse_destroy),
+ NULL);
+ g_signal_connect ((gpointer) ok_button1, "clicked",
+ G_CALLBACK (on_browse_ok_clicked),
+ NULL);
+ g_signal_connect_swapped ((gpointer) ok_button1, "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ GTK_OBJECT (file_browse));
+ g_signal_connect_swapped ((gpointer) cancel_button1, "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ GTK_OBJECT (file_browse));
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (file_browse, file_browse, "file_browse");
+ GLADE_HOOKUP_OBJECT_NO_REF (file_browse, ok_button1, "ok_button1");
+ GLADE_HOOKUP_OBJECT_NO_REF (file_browse, cancel_button1, "cancel_button1");
+
+ return file_browse;
+}
+
+GtkWidget*
+create_edit_win (void)
+{
+ GtkWidget *edit_win;
+ GtkWidget *vbox1;
+ GtkWidget *hbox1;
+ GtkWidget *label29;
+ GtkWidget *name_entry;
+ GtkWidget *label30;
+ GtkWidget *type_option;
+ GtkWidget *menu1;
+ GtkWidget *item_buddy;
+ GtkWidget *item_group;
+ GtkWidget *hbuttonbox2;
+ GtkWidget *applysave_but;
+ GtkWidget *apply_but;
+ GtkWidget *cancel_but;
+ GtkWidget *frame3;
+ GtkWidget *table5;
+ GtkWidget *label31;
+ GtkWidget *label34;
+ GtkWidget *label33;
+ GtkWidget *label32;
+ GtkWidget *unaway_sound_entry;
+ GtkWidget *unidle_sound_entry;
+ GtkWidget *signon_sound_entry;
+ GtkWidget *unaway_test_but;
+ GtkWidget *unidle_test_but;
+ GtkWidget *signon_test_but;
+ GtkWidget *unaway_browse_but;
+ GtkWidget *unidle_browse_but;
+ GtkWidget *signon_browse_but;
+ GtkWidget *im_browse_but;
+ GtkWidget *im_sound_entry;
+ GtkWidget *im_test_but;
+ GtkWidget *label24;
+
+ edit_win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_size_request (edit_win, 600, 300);
+ gtk_window_set_title (GTK_WINDOW (edit_win), "Edit Entry");
+ gtk_window_set_default_size (GTK_WINDOW (edit_win), 600, 300);
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_show (vbox1);
+ gtk_container_add (GTK_CONTAINER (edit_win), vbox1);
+
+ hbox1 = gtk_hbox_new (FALSE, 5);
+ gtk_widget_show (hbox1);
+ gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, TRUE, 10);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5);
+
+ label29 = gtk_label_new ("Name:");
+ gtk_widget_show (label29);
+ gtk_box_pack_start (GTK_BOX (hbox1), label29, FALSE, FALSE, 0);
+ gtk_misc_set_alignment (GTK_MISC (label29), 1, 0.5);
+
+ name_entry = gtk_entry_new ();
+ gtk_widget_show (name_entry);
+ gtk_box_pack_start (GTK_BOX (hbox1), name_entry, TRUE, TRUE, 0);
+
+ label30 = gtk_label_new ("Type:");
+ gtk_widget_show (label30);
+ gtk_box_pack_start (GTK_BOX (hbox1), label30, FALSE, TRUE, 0);
+ gtk_misc_set_alignment (GTK_MISC (label30), 1, 0.5);
+
+ type_option = gtk_option_menu_new ();
+ gtk_widget_show (type_option);
+ gtk_box_pack_start (GTK_BOX (hbox1), type_option, FALSE, FALSE, 0);
+
+ menu1 = gtk_menu_new ();
+
+ item_buddy = gtk_menu_item_new_with_mnemonic ("Buddy");
+ gtk_widget_show (item_buddy);
+ gtk_container_add (GTK_CONTAINER (menu1), item_buddy);
+
+ item_group = gtk_menu_item_new_with_mnemonic ("Group");
+ gtk_widget_show (item_group);
+ gtk_container_add (GTK_CONTAINER (menu1), item_group);
+
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (type_option), menu1);
+
+ hbuttonbox2 = gtk_hbutton_box_new ();
+ gtk_widget_show (hbuttonbox2);
+ gtk_box_pack_end (GTK_BOX (vbox1), hbuttonbox2, FALSE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox2), 5);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_SPREAD);
+
+ applysave_but = gtk_button_new_with_mnemonic ("Apply and Save");
+ gtk_widget_show (applysave_but);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), applysave_but);
+ GTK_WIDGET_SET_FLAGS (applysave_but, GTK_CAN_DEFAULT);
+
+ apply_but = gtk_button_new_from_stock ("gtk-apply");
+ gtk_widget_show (apply_but);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), apply_but);
+ GTK_WIDGET_SET_FLAGS (apply_but, GTK_CAN_DEFAULT);
+
+ cancel_but = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (cancel_but);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), cancel_but);
+ GTK_WIDGET_SET_FLAGS (cancel_but, GTK_CAN_DEFAULT);
+
+ frame3 = gtk_frame_new (NULL);
+ gtk_widget_show (frame3);
+ gtk_box_pack_start (GTK_BOX (vbox1), frame3, FALSE, FALSE, 0);
+ gtk_widget_set_size_request (frame3, -1, 200);
+ gtk_container_set_border_width (GTK_CONTAINER (frame3), 5);
+
+ table5 = gtk_table_new (4, 5, FALSE);
+ gtk_widget_show (table5);
+ gtk_container_add (GTK_CONTAINER (frame3), table5);
+ gtk_widget_set_size_request (table5, 600, 400);
+ gtk_container_set_border_width (GTK_CONTAINER (table5), 5);
+ gtk_table_set_row_spacings (GTK_TABLE (table5), 10);
+ gtk_table_set_col_spacings (GTK_TABLE (table5), 10);
+
+ label31 = gtk_label_new ("Play On IM:");
+ gtk_widget_show (label31);
+ gtk_table_attach (GTK_TABLE (table5), label31, 0, 1, 0, 1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label31), 0, 0.5);
+
+ label34 = gtk_label_new ("Play On Unaway:");
+ gtk_widget_show (label34);
+ gtk_table_attach (GTK_TABLE (table5), label34, 0, 1, 3, 4,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label34), 0, 0.5);
+
+ label33 = gtk_label_new ("Play On Unidle:");
+ gtk_widget_show (label33);
+ gtk_table_attach (GTK_TABLE (table5), label33, 0, 1, 2, 3,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label33), 0, 0.5);
+
+ label32 = gtk_label_new ("Play On Signon:");
+ gtk_widget_show (label32);
+ gtk_table_attach (GTK_TABLE (table5), label32, 0, 1, 1, 2,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (label32), 0, 0.5);
+
+ unaway_sound_entry = gtk_entry_new ();
+ gtk_widget_show (unaway_sound_entry);
+ gtk_table_attach (GTK_TABLE (table5), unaway_sound_entry, 1, 3, 3, 4,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ unidle_sound_entry = gtk_entry_new ();
+ gtk_widget_show (unidle_sound_entry);
+ gtk_table_attach (GTK_TABLE (table5), unidle_sound_entry, 1, 3, 2, 3,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ signon_sound_entry = gtk_entry_new ();
+ gtk_widget_show (signon_sound_entry);
+ gtk_table_attach (GTK_TABLE (table5), signon_sound_entry, 1, 3, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ unaway_test_but = gtk_button_new_with_mnemonic ("Test");
+ gtk_widget_show (unaway_test_but);
+ gtk_table_attach (GTK_TABLE (table5), unaway_test_but, 4, 5, 3, 4,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ unidle_test_but = gtk_button_new_with_mnemonic ("Test");
+ gtk_widget_show (unidle_test_but);
+ gtk_table_attach (GTK_TABLE (table5), unidle_test_but, 4, 5, 2, 3,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ signon_test_but = gtk_button_new_with_mnemonic ("Test");
+ gtk_widget_show (signon_test_but);
+ gtk_table_attach (GTK_TABLE (table5), signon_test_but, 4, 5, 1, 2,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ unaway_browse_but = gtk_button_new_from_stock ("gtk-open");
+ gtk_widget_show (unaway_browse_but);
+ gtk_table_attach (GTK_TABLE (table5), unaway_browse_but, 3, 4, 3, 4,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ unidle_browse_but = gtk_button_new_from_stock ("gtk-open");
+ gtk_widget_show (unidle_browse_but);
+ gtk_table_attach (GTK_TABLE (table5), unidle_browse_but, 3, 4, 2, 3,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ signon_browse_but = gtk_button_new_from_stock ("gtk-open");
+ gtk_widget_show (signon_browse_but);
+ gtk_table_attach (GTK_TABLE (table5), signon_browse_but, 3, 4, 1, 2,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ im_browse_but = gtk_button_new_from_stock ("gtk-open");
+ gtk_widget_show (im_browse_but);
+ gtk_table_attach (GTK_TABLE (table5), im_browse_but, 3, 4, 0, 1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ im_sound_entry = gtk_entry_new ();
+ gtk_widget_show (im_sound_entry);
+ gtk_table_attach (GTK_TABLE (table5), im_sound_entry, 1, 3, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ im_test_but = gtk_button_new_with_mnemonic ("Test");
+ gtk_widget_show (im_test_but);
+ gtk_table_attach (GTK_TABLE (table5), im_test_but, 4, 5, 0, 1,
+ (GtkAttachOptions) (0),
+ (GtkAttachOptions) (0), 0, 0);
+
+ label24 = gtk_label_new ("Sound Events");
+ gtk_widget_show (label24);
+ gtk_frame_set_label_widget (GTK_FRAME (frame3), label24);
+
+ g_signal_connect ((gpointer) edit_win, "destroy",
+ G_CALLBACK (on_edit_win_destroy),
+ NULL);
+ g_signal_connect ((gpointer) applysave_but, "clicked",
+ G_CALLBACK (on_apply_clicked),
+ NULL);
+ g_signal_connect ((gpointer) applysave_but, "clicked",
+ G_CALLBACK (on_save_clicked),
+ NULL);
+ g_signal_connect_swapped ((gpointer) applysave_but, "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ GTK_OBJECT (edit_win));
+ g_signal_connect ((gpointer) apply_but, "clicked",
+ G_CALLBACK (on_apply_clicked),
+ NULL);
+ g_signal_connect_swapped ((gpointer) apply_but, "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ GTK_OBJECT (edit_win));
+ g_signal_connect_swapped ((gpointer) cancel_but, "clicked",
+ G_CALLBACK (gtk_widget_destroy),
+ GTK_OBJECT (edit_win));
+ g_signal_connect ((gpointer) unaway_test_but, "clicked",
+ G_CALLBACK (on_unaway_test_clicked),
+ NULL);
+ g_signal_connect ((gpointer) unidle_test_but, "clicked",
+ G_CALLBACK (on_unidle_test_clicked),
+ NULL);
+ g_signal_connect ((gpointer) signon_test_but, "clicked",
+ G_CALLBACK (on_signon_test_clicked),
+ NULL);
+ g_signal_connect ((gpointer) unaway_browse_but, "clicked",
+ G_CALLBACK (on_unaway_browse_clicked),
+ NULL);
+ g_signal_connect ((gpointer) unidle_browse_but, "clicked",
+ G_CALLBACK (on_unidle_browse_clicked),
+ NULL);
+ g_signal_connect ((gpointer) signon_browse_but, "clicked",
+ G_CALLBACK (on_signon_browse_clicked),
+ NULL);
+ g_signal_connect ((gpointer) im_browse_but, "clicked",
+ G_CALLBACK (on_im_browse_clicked),
+ NULL);
+ g_signal_connect ((gpointer) im_test_but, "clicked",
+ G_CALLBACK (on_im_test_clicked),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (edit_win, edit_win, "edit_win");
+ GLADE_HOOKUP_OBJECT (edit_win, vbox1, "vbox1");
+ GLADE_HOOKUP_OBJECT (edit_win, hbox1, "hbox1");
+ GLADE_HOOKUP_OBJECT (edit_win, label29, "label29");
+ GLADE_HOOKUP_OBJECT (edit_win, name_entry, "name_entry");
+ GLADE_HOOKUP_OBJECT (edit_win, label30, "label30");
+ GLADE_HOOKUP_OBJECT (edit_win, type_option, "type_option");
+ GLADE_HOOKUP_OBJECT (edit_win, menu1, "menu1");
+ GLADE_HOOKUP_OBJECT (edit_win, item_buddy, "item_buddy");
+ GLADE_HOOKUP_OBJECT (edit_win, item_group, "item_group");
+ GLADE_HOOKUP_OBJECT (edit_win, hbuttonbox2, "hbuttonbox2");
+ GLADE_HOOKUP_OBJECT (edit_win, applysave_but, "applysave_but");
+ GLADE_HOOKUP_OBJECT (edit_win, apply_but, "apply_but");
+ GLADE_HOOKUP_OBJECT (edit_win, cancel_but, "cancel_but");
+ GLADE_HOOKUP_OBJECT (edit_win, frame3, "frame3");
+ GLADE_HOOKUP_OBJECT (edit_win, table5, "table5");
+ GLADE_HOOKUP_OBJECT (edit_win, label31, "label31");
+ GLADE_HOOKUP_OBJECT (edit_win, label34, "label34");
+ GLADE_HOOKUP_OBJECT (edit_win, label33, "label33");
+ GLADE_HOOKUP_OBJECT (edit_win, label32, "label32");
+ GLADE_HOOKUP_OBJECT (edit_win, unaway_sound_entry, "unaway_sound_entry");
+ GLADE_HOOKUP_OBJECT (edit_win, unidle_sound_entry, "unidle_sound_entry");
+ GLADE_HOOKUP_OBJECT (edit_win, signon_sound_entry, "signon_sound_entry");
+ GLADE_HOOKUP_OBJECT (edit_win, unaway_test_but, "unaway_test_but");
+ GLADE_HOOKUP_OBJECT (edit_win, unidle_test_but, "unidle_test_but");
+ GLADE_HOOKUP_OBJECT (edit_win, signon_test_but, "signon_test_but");
+ GLADE_HOOKUP_OBJECT (edit_win, unaway_browse_but, "unaway_browse_but");
+ GLADE_HOOKUP_OBJECT (edit_win, unidle_browse_but, "unidle_browse_but");
+ GLADE_HOOKUP_OBJECT (edit_win, signon_browse_but, "signon_browse_but");
+ GLADE_HOOKUP_OBJECT (edit_win, im_browse_but, "im_browse_but");
+ GLADE_HOOKUP_OBJECT (edit_win, im_sound_entry, "im_sound_entry");
+ GLADE_HOOKUP_OBJECT (edit_win, im_test_but, "im_test_but");
+ GLADE_HOOKUP_OBJECT (edit_win, label24, "label24");
+
+ return edit_win;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/smartear/old-smartear.c Thu Jul 05 05:46:17 2007 -0400
@@ -0,0 +1,1280 @@
+/* SmartEar by Matt Perry
+ * Works for purple 2.0.0
+ * Plugin to assign different sounds to different buddies and groups.
+ * TODO: figure out contact support
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "../pp_config.h"
+#endif
+#include "../common/i18n.h"
+
+#include "pidgin.h"
+
+#include "gtkplugin.h"
+#include "gtkutils.h"
+#include "version.h"
+
+#include "debug.h"
+#include "util.h"
+#include "sound.h"
+#include "gtkprefs.h"
+#include "gtkblist.h"
+#include "signals.h"
+
+#ifndef PURPLE_PLUGINS
+#define PURPLE_PLUGINS
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <time.h>
+
+#ifdef _WIN32
+#include "win32dep.h"
+#endif
+
+#define BUF_LEN 2048 /* lifted from libpurple's internal.h */
+
+#define RCFILE_VERSION 2
+#define RC_EMPTY_SOUND " " /* must be at least 1 char long for sscanf */
+
+#define SMARTEAR_PLUGIN_ID "smartear"
+#define SMARTEAR_VERSION VERSION ".1"
+
+#define FIND(s) lookup_widget(config, s)
+#define EFIND(s) lookup_widget(edit_win, s)
+
+/* an entry in the prefs file to indicate what to play for who and when. */
+struct smartear_entry {
+ char type; /* B,G */
+ char *name;
+#define EVENT_M 0
+#define EVENT_S 1
+#define EVENT_I 2
+#define EVENT_A 3
+#define EVENT_NUM 4
+ char *sound[EVENT_NUM];
+};
+
+struct timer_data {
+ int event;
+ guint id;
+};
+
+struct message_data {
+ PurpleAccount *account;
+ char *buddy;
+ time_t last_active;
+ time_t last_sent;
+ struct timer_data *timer;
+};
+
+enum { /* Treeview columns */
+ DATA_COL = 0,
+ TYPE_COL = 0,
+ NAME_COL,
+ ON_MESSAGE_COL,
+ ON_SIGNON_COL,
+ ON_UNIDLE_COL,
+ ON_UNAWAY_COL,
+ NUM_COLS
+};
+
+#define DEFAULT_NAME "(Default)"
+#define IS_DEFAULT(entry) (strcmp(entry->name, DEFAULT_NAME)==0)
+#define IS_EMPTY(str) (!str || !str[0])
+struct smartear_entry default_entry = {'B', DEFAULT_NAME, {"", "", "", ""}};
+
+int message_delay = 60;
+int focused_quiet = TRUE;
+int smartear_timers = FALSE;
+
+GtkWidget *config = NULL;
+GtkWidget *edit_win = NULL;
+GtkWidget *file_browse = NULL;
+GtkWidget *file_browse_entry = NULL;
+GtkTreeView *treeview = NULL;
+GtkTreeSelection *treeselect = NULL;
+GtkTreeModel *treemodel = NULL;
+
+struct smartear_entry *selected_entry = NULL;
+GtkTreeIter selected_iter;
+
+GSList *sounds_list = NULL;
+GSList *messages_list = NULL;
+
+GtkWidget *create_file_browse(void);
+GtkWidget *create_edit_win(void);
+GtkWidget *create_config(void);
+
+static void new_entry(struct smartear_entry *entry);
+static gboolean get_selection(void);
+static void clear_selection(void);
+static void populate_edit_win(struct smartear_entry *entry);
+static void update_list(void);
+static void populate_list(GtkListStore *store);
+static void list_set(GtkListStore *store, GtkTreeIter *iter, struct smartear_entry *entry);
+static void set_option_entries(void);
+
+static gint sound_cmp(gconstpointer p1, gconstpointer p2);
+static struct smartear_entry *sound_new_with_name(gchar *name);
+static struct smartear_entry *sound_dup(struct smartear_entry *entry);
+static void sound_free(struct smartear_entry *entry, int free_entry);
+static void soundlist_free(void);
+
+static gchar *get_basename(gchar *path);
+
+static void on_treeselect_changed(GtkTreeSelection *selection, gpointer data);
+
+static void smartear_save(void);
+static void smartear_load(void);
+
+static void play_sound_alias(char *sound, PurpleAccount* account);
+
+/*** Glade's Support Function ***/
+
+GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name)
+{
+ GtkWidget *found_widget;
+ found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("smartear: Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+/*** GTK Callbacks ***/
+
+/* Options Frame */
+
+void on_delay_changed (GtkEditable *editable, gpointer user_data)
+{
+ gchar *text = gtk_editable_get_chars(editable, 0, -1);
+ message_delay = atoi(text);
+ g_free(text);
+}
+
+void on_focus_toggled (GtkToggleButton *togglebutton, gpointer user_data)
+{
+ focused_quiet = gtk_toggle_button_get_active(togglebutton);
+}
+
+void on_timer_toggled (GtkToggleButton *togglebutton, gpointer user_data)
+{
+ smartear_timers = gtk_toggle_button_get_active(togglebutton);
+}
+
+/* Entries Frame */
+
+void on_cell_edited(GtkCellRendererText *cell, gchar *path, gchar *text, gpointer data)
+{
+ GtkTreeIter iter;
+ gint col = GPOINTER_TO_INT(data);
+ struct smartear_entry *entry;
+
+ if (!gtk_tree_model_get_iter_from_string(treemodel, &iter, path))
+ return;
+
+ gtk_tree_model_get(treemodel, &iter, DATA_COL, &entry, -1);
+ switch (col) {
+ case NAME_COL:
+ if (IS_DEFAULT(entry))
+ return;
+ g_free(entry->name);
+ entry->name = g_strdup(text);
+ update_list();
+ break;
+ }
+}
+
+void on_treeselect_changed(GtkTreeSelection *selection, gpointer data)
+{
+ get_selection();
+ update_list();
+}
+
+
+void on_new_clicked (GtkButton *button, gpointer user_data)
+{
+ if (edit_win)
+ return;
+
+ new_entry(sound_new_with_name(""));
+}
+
+void on_delete_clicked (GtkButton *button, gpointer user_data)
+{
+ GtkTreeIter iter;
+
+ if (edit_win)
+ return;
+
+ if (!get_selection())
+ return;
+
+ if (IS_DEFAULT(selected_entry))
+ return;
+
+ iter = selected_iter;
+
+ sounds_list = g_slist_remove(sounds_list, selected_entry);
+ sound_free(selected_entry, TRUE);
+
+ if (!gtk_tree_model_iter_next(treemodel, &iter)) {
+ GtkTreePath *path = gtk_tree_model_get_path(treemodel, &selected_iter);
+ gtk_tree_path_prev(path);
+ gtk_tree_model_get_iter(treemodel, &iter, path);
+ gtk_tree_path_free(path);
+ }
+ g_signal_handlers_block_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
+ gtk_list_store_remove(GTK_LIST_STORE(treemodel), &selected_iter);
+ gtk_tree_selection_select_iter(treeselect, &iter);
+ g_signal_handlers_unblock_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
+
+ get_selection();
+ update_list();
+}
+
+void on_edit_clicked (GtkButton *button, gpointer user_data)
+{
+ if (!get_selection())
+ return;
+
+ if (edit_win)
+ return;
+
+ edit_win = create_edit_win();
+ gtk_widget_show_all(edit_win);
+
+ populate_edit_win(selected_entry);
+}
+
+void on_save_clicked (GtkButton *button, gpointer user_data)
+{
+ smartear_save();
+}
+
+void on_revert_clicked (GtkButton *button, gpointer user_data)
+{
+ selected_entry = NULL;
+ if (edit_win) {
+ gtk_widget_destroy(edit_win);
+ edit_win = NULL;
+ }
+
+ soundlist_free();
+ smartear_load();
+ gtk_list_store_clear(GTK_LIST_STORE(treemodel));
+ populate_list(GTK_LIST_STORE(treemodel));
+ update_list();
+ set_option_entries();
+}
+
+/* Edit Window */
+
+void on_browse_ok_clicked (GtkButton *button, gpointer user_data)
+{
+ gtk_entry_set_text(GTK_ENTRY(file_browse_entry),
+ gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_browse)));
+}
+
+void on_file_browse_destroy (GtkObject *object, gpointer user_data)
+{
+ file_browse = NULL;
+ file_browse_entry = NULL;
+}
+
+void on_browse_clicked (GtkButton *button, gchar *user_data)
+{
+ gchar *text;
+ if (file_browse)
+ return;
+
+ file_browse = create_file_browse();
+ gtk_widget_show(file_browse);
+
+ file_browse_entry = EFIND(user_data);
+ text = gtk_editable_get_chars(GTK_EDITABLE(file_browse_entry), 0, -1);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_browse), text);
+ g_free(text);
+}
+
+void on_im_browse_clicked (GtkButton *button, gpointer user_data)
+{
+ on_browse_clicked(button, "im_sound_entry");
+}
+
+void on_signon_browse_clicked (GtkButton *button, gpointer user_data)
+{
+ on_browse_clicked(button, "signon_sound_entry");
+}
+
+void on_unidle_browse_clicked (GtkButton *button, gpointer user_data)
+{
+ on_browse_clicked(button, "unidle_sound_entry");
+}
+
+void on_unaway_browse_clicked (GtkButton *button, gpointer user_data)
+{
+ on_browse_clicked(button, "unaway_sound_entry");
+}
+
+void on_test_clicked (GtkButton *button, gchar *user_data)
+{
+ gchar *text =
+ gtk_editable_get_chars(GTK_EDITABLE(EFIND(user_data)), 0, -1);
+ play_sound_alias(text, NULL);
+ g_free(text);
+}
+
+void on_im_test_clicked (GtkButton *button, gpointer user_data)
+{
+ on_test_clicked(button, "im_sound_entry");
+}
+
+void on_signon_test_clicked (GtkButton *button, gpointer user_data)
+{
+ on_test_clicked(button, "signon_sound_entry");
+}
+
+void on_unidle_test_clicked (GtkButton *button, gpointer user_data)
+{
+ on_test_clicked(button, "unidle_sound_entry");
+}
+
+void on_unaway_test_clicked (GtkButton *button, gpointer user_data)
+{
+ on_test_clicked(button, "unaway_sound_entry");
+}
+
+void on_apply_clicked (GtkButton *button, gpointer user_data)
+{
+ struct smartear_entry *entry, tmp;
+
+ if (get_selection()) {
+ entry = selected_entry;
+
+ g_free(entry->name);
+ g_free(entry->sound[0]);
+ g_free(entry->sound[1]);
+ g_free(entry->sound[2]);
+ g_free(entry->sound[3]);
+ }
+ else {
+ entry = &tmp;
+ }
+
+ entry->name =
+ gtk_editable_get_chars(GTK_EDITABLE(EFIND("name_entry")), 0, -1);
+ entry->type =
+ gtk_option_menu_get_history(GTK_OPTION_MENU(EFIND("type_option"))) == 0
+ ? 'B' : 'G';
+ entry->sound[EVENT_M] =
+ gtk_editable_get_chars(GTK_EDITABLE(EFIND("im_sound_entry")), 0, -1);
+ entry->sound[EVENT_S] =
+ gtk_editable_get_chars(GTK_EDITABLE(EFIND("signon_sound_entry")), 0, -1);
+ entry->sound[EVENT_I] =
+ gtk_editable_get_chars(GTK_EDITABLE(EFIND("unidle_sound_entry")), 0, -1);
+ entry->sound[EVENT_A] =
+ gtk_editable_get_chars(GTK_EDITABLE(EFIND("unaway_sound_entry")), 0, -1);
+
+ if (!selected_entry) {
+ GSList *lp;
+ if ((lp = g_slist_find_custom(sounds_list, entry, (GCompareFunc)sound_cmp))) {
+ sound_free((struct smartear_entry*)lp->data, FALSE);
+ *(struct smartear_entry*)lp->data = *entry;
+ }
+ else {
+ struct smartear_entry *copy = g_new(struct smartear_entry, 1);
+ *copy = *entry;
+ new_entry(copy);
+ }
+ }
+
+ update_list();
+}
+
+void on_edit_win_destroy (GtkObject *object, gpointer user_data)
+{
+ edit_win = NULL;
+
+ if (config) {
+ gtk_widget_set_sensitive(GTK_WIDGET(treeview), TRUE);
+ }
+}
+
+void on_config_destroy (GtkObject *object, gpointer user_data)
+{
+ config = NULL;
+}
+
+/*** Util Functions ***/
+
+static void new_entry(struct smartear_entry *entry)
+{
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeViewColumn *name_column;
+
+ sounds_list = g_slist_append(sounds_list, entry);
+
+ if (!config)
+ return;
+
+ if (get_selection())
+ gtk_list_store_insert_after(GTK_LIST_STORE(treemodel), &iter, &selected_iter);
+ else
+ gtk_list_store_append(GTK_LIST_STORE(treemodel), &iter);
+
+ path = gtk_tree_model_get_path(treemodel, &iter);
+ list_set(GTK_LIST_STORE(treemodel), &iter, entry);
+
+ g_signal_handlers_block_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
+ path = gtk_tree_model_get_path(treemodel, &iter);
+ name_column = gtk_tree_view_get_column(treeview, NAME_COL);
+ if (entry->name && entry->name[0])
+ gtk_tree_view_set_cursor(treeview, path, 0, FALSE);
+ else {
+ gtk_tree_view_set_cursor(treeview, path, name_column, TRUE);
+ }
+ gtk_tree_path_free(path);
+ g_signal_handlers_unblock_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
+
+ get_selection();
+}
+
+static gboolean get_selection(void)
+{
+ selected_entry = NULL;
+
+ if (!config)
+ return FALSE;
+
+ if (!gtk_tree_selection_get_selected(treeselect, &treemodel, &selected_iter))
+ return FALSE;
+
+ gtk_tree_model_get(treemodel, &selected_iter, DATA_COL, &selected_entry, -1);
+ return TRUE;
+}
+
+void clear_selection(void)
+{
+ selected_entry = NULL;
+
+ if (!config)
+ return;
+
+ if (gtk_tree_selection_get_selected(treeselect, &treemodel, &selected_iter)) {
+ gtk_tree_selection_unselect_iter(treeselect, &selected_iter);
+ }
+}
+
+static void list_set(GtkListStore *store, GtkTreeIter *iter, struct smartear_entry *entry)
+{
+ gtk_list_store_set(store, iter, DATA_COL, entry, -1);
+}
+
+static char *my_normalize(const char *input)
+{
+ static char buf[BUF_LEN];
+ char *str, *beg;
+ int i=0;
+
+ g_return_val_if_fail((input != NULL), NULL);
+
+ beg = str = g_strdup(input);
+
+ while (*str && i <= BUF_LEN) {
+ if (*str != ' ')
+ buf[i++] = *str;
+ str++;
+ }
+ buf[i] = '\0';
+ g_free(beg);
+
+ return buf;
+
+}
+
+static struct smartear_entry *sound_new_with_name(gchar *name)
+{
+ struct smartear_entry tmp = default_entry;
+ tmp.name = name;
+ return sound_dup(&tmp);
+}
+
+static struct smartear_entry *sound_dup(struct smartear_entry *entry)
+{
+ struct smartear_entry *edup = g_new(struct smartear_entry, 1);
+ int i;
+
+ edup->type = entry->type;
+ edup->name = g_strdup(my_normalize(entry->name));
+ for (i = 0; i < EVENT_NUM; i++) {
+ edup->sound[i] = g_strdup(entry->sound[i]);
+ }
+
+ return edup;
+}
+
+static void sound_free(struct smartear_entry *entry, int free_entry)
+{
+ g_free(entry->name);
+ g_free(entry->sound[0]);
+ g_free(entry->sound[1]);
+ g_free(entry->sound[2]);
+ g_free(entry->sound[3]);
+ if (free_entry) {
+ g_free(entry);
+ }
+}
+
+static void soundlist_free(void)
+{
+ GSList *lp;
+ for (lp = sounds_list; lp; lp = g_slist_next(lp))
+ sound_free((struct smartear_entry*)lp->data, TRUE);
+ if (sounds_list) {
+ g_slist_free(sounds_list);
+ sounds_list = 0;
+ }
+}
+
+static gint sound_cmp(gconstpointer p1, gconstpointer p2)
+{
+ struct smartear_entry *entry1 = (struct smartear_entry*)p1;
+ struct smartear_entry *entry2 = (struct smartear_entry*)p2;
+
+ if (!entry1 || IS_DEFAULT(entry1))
+ return -1;
+ if (!entry2 || IS_DEFAULT(entry2))
+ return 1;
+
+ /* only compare types if both are nonzero */
+ if (entry1->type != entry2->type &&
+ entry1->type != 0 && entry2->type != 0)
+ return (entry1->type - entry2->type);
+ return (g_strcasecmp(entry1->name, entry2->name));
+}
+
+static void populate_edit_win(struct smartear_entry *entry)
+{
+ gtk_entry_set_text(GTK_ENTRY(EFIND("name_entry")), entry->name);
+ gtk_entry_set_text(GTK_ENTRY(EFIND("im_sound_entry")),
+ entry->sound[EVENT_M]);
+ gtk_entry_set_text(GTK_ENTRY(EFIND("signon_sound_entry")),
+ entry->sound[EVENT_S]);
+ gtk_entry_set_text(GTK_ENTRY(EFIND("unidle_sound_entry")),
+ entry->sound[EVENT_I]);
+ gtk_entry_set_text(GTK_ENTRY(EFIND("unaway_sound_entry")),
+ entry->sound[EVENT_A]);
+ gtk_option_menu_set_history(GTK_OPTION_MENU(EFIND("type_option")),
+ (entry->type == 'B' ? 0 : 1));
+
+ if (IS_DEFAULT(entry)) {
+ gtk_widget_set_sensitive(EFIND("name_entry"), FALSE);
+ gtk_widget_set_sensitive(EFIND("type_menu"), FALSE);
+ }
+
+ if (config) {
+ gtk_widget_set_sensitive(GTK_WIDGET(treeview), FALSE);
+ }
+}
+
+static void set_option_entries(void)
+{
+ GtkSpinButton *delay_spin = GTK_SPIN_BUTTON(FIND("delay_spin"));
+ GtkToggleButton *focus_but = GTK_TOGGLE_BUTTON(FIND("focus_but"));
+ GtkToggleButton *timer_but = GTK_TOGGLE_BUTTON(FIND("timer_but"));
+
+ g_signal_handlers_block_by_func(G_OBJECT(delay_spin), on_delay_changed, 0);
+ g_signal_handlers_block_by_func(G_OBJECT(focus_but), on_focus_toggled, 0);
+ g_signal_handlers_block_by_func(G_OBJECT(timer_but), on_timer_toggled, 0);
+
+ gtk_spin_button_set_value(delay_spin, (gdouble)message_delay);
+ gtk_toggle_button_set_active(focus_but, focused_quiet);
+ gtk_toggle_button_set_active(timer_but, smartear_timers);
+
+ g_signal_handlers_unblock_by_func(G_OBJECT(delay_spin), on_delay_changed, 0);
+ g_signal_handlers_unblock_by_func(G_OBJECT(focus_but), on_focus_toggled, 0);
+ g_signal_handlers_unblock_by_func(G_OBJECT(timer_but), on_timer_toggled, 0);
+}
+
+static void update_list(void)
+{
+ if (selected_entry)
+ list_set(GTK_LIST_STORE(treemodel), &selected_iter, selected_entry);
+}
+
+static gchar* get_basename(gchar *path)
+{
+ static gchar base[BUF_LEN];
+ gchar *p;
+
+ if (!path || !path[0]) {
+ return "";
+ }
+
+ if ((p = strrchr(path, '/'))) {
+ p++;
+ }
+ else {
+ p = path;
+ }
+
+ strncpy(base, p, sizeof(base));
+
+ return base;
+}
+
+/*** Init Functions ***/
+
+static void populate_list(GtkListStore *store)
+{
+ GtkTreeIter iter;
+ GSList *lp;
+
+ sounds_list = g_slist_sort(sounds_list, (GCompareFunc)sound_cmp);
+
+ for (lp = sounds_list; lp; lp = g_slist_next(lp)) {
+ struct smartear_entry *entry = (struct smartear_entry*)lp->data;
+ gtk_list_store_append(store, &iter);
+ list_set(store, &iter, entry);
+ if (entry == selected_entry)
+ selected_iter = iter;
+ }
+}
+
+static void render_type(GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+ struct smartear_entry *entry;
+ gtk_tree_model_get(model, iter, DATA_COL, &entry, -1);
+ if (IS_DEFAULT(entry))
+ g_object_set(cell, "text", "", NULL);
+ else
+ g_object_set(cell, "text", entry->type == 'B' ? "Buddy" : "Group", NULL);
+}
+
+static void render_name(GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+ struct smartear_entry *entry;
+ gtk_tree_model_get(model, iter, DATA_COL, &entry, -1);
+ g_object_set(cell, "text", entry->name, NULL);
+}
+
+static void render_when(GtkTreeViewColumn *column, GtkCellRenderer *cell,
+ GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
+{
+ struct smartear_entry *entry;
+ gint which = GPOINTER_TO_INT(data);
+ gtk_tree_model_get(model, iter, DATA_COL, &entry, -1);
+ g_object_set(cell, "text", get_basename(entry->sound[which]), NULL);
+}
+
+static gint list_cmp(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer d)
+{
+ struct smartear_entry *entry1, *entry2;
+
+ gtk_tree_model_get(model, a, DATA_COL, &entry1, -1);
+ gtk_tree_model_get(model, b, DATA_COL, &entry2, -1);
+
+ return sound_cmp(entry1, entry2);
+}
+
+static void setup_list(void)
+{
+ GtkListStore *store;
+ GtkCellRenderer *cell;
+
+ treeview = GTK_TREE_VIEW(FIND("treeview"));
+
+ store = gtk_list_store_new(1, G_TYPE_POINTER);
+ populate_list(store);
+
+ gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
+ g_object_unref(G_OBJECT(store)); // treeview has it's own copy.
+ treemodel = gtk_tree_view_get_model(treeview);
+ gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(treemodel),
+ (GtkTreeIterCompareFunc)&list_cmp, 0, 0);
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(treemodel),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+
+ treeselect = gtk_tree_view_get_selection(treeview);
+ gtk_tree_selection_set_mode(treeselect, GTK_SELECTION_SINGLE);
+ g_signal_connect(G_OBJECT(treeselect), "changed",
+ G_CALLBACK(on_treeselect_changed), NULL);
+
+ /* Type column */
+ cell = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_data_func(treeview, -1, "Type",
+ cell, render_type, 0, 0);
+
+ /* Name column */
+ cell = gtk_cell_renderer_text_new();
+ g_signal_connect(G_OBJECT(cell), "edited",
+ G_CALLBACK(on_cell_edited), GINT_TO_POINTER(NAME_COL));
+ g_object_set(G_OBJECT(cell), "editable", TRUE, NULL);
+ gtk_tree_view_insert_column_with_data_func(treeview, -1, "Name",
+ cell, render_name, 0, 0);
+
+ cell = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Message",
+ cell, render_when, GINT_TO_POINTER(EVENT_M), 0);
+
+ cell = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Signon",
+ cell, render_when, GINT_TO_POINTER(EVENT_S), 0);
+
+ cell = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Unidle",
+ cell, render_when, GINT_TO_POINTER(EVENT_I), 0);
+
+ cell = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Unaway",
+ cell, render_when, GINT_TO_POINTER(EVENT_A), 0);
+}
+
+static void smartear_save(void)
+{
+ char file[BUF_LEN] = "smartear.rc - you have no home dir";
+ FILE *fp = NULL;
+ GSList *lp;
+ struct smartear_entry *entry;
+
+ if (purple_user_dir()) {
+ g_snprintf(file, sizeof(file), "%s/smartear.rc", purple_user_dir());
+ fp = fopen(file, "w");
+ }
+
+ if (fp == NULL) {
+ g_warning("couldn't open %s\n", file);
+ return;
+ }
+
+ fprintf(fp, "version %d\n", RCFILE_VERSION);
+ fprintf(fp, "smartear_timers %d\n", smartear_timers);
+ fprintf(fp, "delay %d\n", message_delay);
+ fprintf(fp, "focused_quiet %d\n", focused_quiet);
+
+ /* save empties as a single space so scanf doesn't get confused */
+#define SAVE_STR(str) (IS_EMPTY(str) ? RC_EMPTY_SOUND : str)
+ for (lp = sounds_list; lp; lp = g_slist_next(lp)) {
+ entry = (struct smartear_entry*)lp->data;
+ fprintf(fp, "%c {%s} {%s} {%s} {%s} {%s}\n",
+ entry->type, entry->name,
+ SAVE_STR(entry->sound[EVENT_M]),
+ SAVE_STR(entry->sound[EVENT_S]),
+ SAVE_STR(entry->sound[EVENT_I]),
+ SAVE_STR(entry->sound[EVENT_A]));
+ }
+
+ fclose(fp);
+}
+
+static void smartear_load(void)
+{
+ char file[BUF_LEN] = "smartear.rc - you have no home dir";
+ FILE *fp = NULL;
+ struct smartear_entry *entry;
+ char buf[BUF_LEN];
+ gboolean has_default = FALSE;
+ int rcfile_version = 1;
+
+ if (purple_user_dir()) {
+ g_snprintf(file, sizeof(file), "%s/smartear.rc", purple_user_dir());
+ fp = fopen(file, "r");
+ }
+
+ if (fp == NULL) {
+ g_warning("smartear: couldn't open %s\n", file);
+ sounds_list = g_slist_append(sounds_list, sound_dup(&default_entry));
+ return;
+ }
+
+ while ((fgets(buf, sizeof(buf), fp))) {
+ int tmp;
+ if (sscanf(buf, "version %d", &tmp) == 1)
+ rcfile_version = tmp;
+ else if (sscanf(buf, "smarterear_timers %d", &tmp) == 1)
+ smartear_timers = tmp;
+ else if (sscanf(buf, "smartear_timers %d", &tmp) == 1)
+ smartear_timers = tmp;
+ else if (sscanf(buf, "delay %d", &tmp) == 1)
+ message_delay = tmp;
+ else if (sscanf(buf, "focused_quiet %d", &tmp) == 1)
+ focused_quiet = tmp;
+ else if (rcfile_version == 1) {
+ char name[BUF_LEN];
+ char flags[BUF_LEN];
+ char sound[BUF_LEN];
+ char type;
+
+ if (sscanf(buf, "%c {%[^}]} {%[^}]} {%[^}]}",
+ &type, name, flags, sound) == 4) {
+ if (type != 'G' && type != 'B') {
+ g_warning("smartear: rc no such type: %c", type);
+ continue;
+ }
+
+ entry = g_new(struct smartear_entry, 1);
+ entry->type = type;
+ entry->name = g_strdup(my_normalize(name));
+ if (strchr(flags, 'M')) entry->sound[EVENT_M] = g_strdup(sound);
+ else entry->sound[EVENT_M] = g_strdup("");
+ if (strchr(flags, 'S')) entry->sound[EVENT_S] = g_strdup(sound);
+ else entry->sound[EVENT_S] = g_strdup("");
+ if (strchr(flags, 'I')) entry->sound[EVENT_I] = g_strdup(sound);
+ else entry->sound[EVENT_I] = g_strdup("");
+ if (strchr(flags, 'A')) entry->sound[EVENT_A] = g_strdup(sound);
+ else entry->sound[EVENT_A] = g_strdup("");
+
+ sounds_list = g_slist_append(sounds_list, entry);
+
+ if (IS_DEFAULT(entry)) {
+ default_entry = *entry;
+ has_default = TRUE;
+ }
+ }
+ else
+ g_warning("smartear: rc1 syntax error: %s", buf);
+ }
+ else if (rcfile_version == 2) {
+ char name[BUF_LEN];
+ char sound[EVENT_NUM][BUF_LEN];
+ char type;
+ int i;
+
+ if (sscanf(buf, "%c {%[^}]} {%[^}]} {%[^}]} {%[^}]} {%[^}]}",
+ &type, name, sound[EVENT_M], sound[EVENT_S],
+ sound[EVENT_I], sound[EVENT_A]) == 6) {
+ if (type != 'G' && type != 'B') {
+ g_warning("smartear: rc no such type: %c", type);
+ continue;
+ }
+
+ for (i = 0; i < EVENT_NUM; i++) {
+ if (strcmp(sound[i], RC_EMPTY_SOUND) == 0)
+ sound[i][0] = 0;
+ }
+
+ entry = g_new(struct smartear_entry, 1);
+ entry->type = type;
+ entry->name = g_strdup(my_normalize(name));
+ entry->sound[EVENT_M] = g_strdup(sound[EVENT_M]);
+ entry->sound[EVENT_S] = g_strdup(sound[EVENT_S]);
+ entry->sound[EVENT_I] = g_strdup(sound[EVENT_I]);
+ entry->sound[EVENT_A] = g_strdup(sound[EVENT_A]);
+
+ sounds_list = g_slist_append(sounds_list, entry);
+
+ if (IS_DEFAULT(entry)) {
+ default_entry = *entry;
+ has_default = TRUE;
+ }
+ }
+ else
+ g_warning("smartear: rc2 syntax error: %s", buf);
+ }
+ else
+ g_warning("smartear: rc syntax error: %s", buf);
+ }
+ if (!has_default)
+ sounds_list = g_slist_append(sounds_list, sound_dup(&default_entry));
+
+ fclose(fp);
+}
+
+/*** Purple callbacks ***/
+
+static struct message_data *find_message_by_name(PurpleAccount *account, const char *pname)
+{
+ GSList *lp;
+ struct message_data *msg = NULL;
+ char *name = g_strdup(my_normalize(pname));
+
+ for (lp = messages_list; lp; lp = g_slist_next(lp)) {
+ msg = (struct message_data*)lp->data;
+ if (msg->account == account
+ && g_strcasecmp(msg->buddy, name) == 0)
+ break;
+ }
+
+ g_free(name);
+
+ if (lp)
+ return msg;
+ return 0;
+}
+
+static void message_timer_remove(struct message_data *msg)
+{
+ if (msg && msg->timer) {
+ g_source_remove(msg->timer->id);
+ g_free(msg->timer);
+ msg->timer = NULL;
+ }
+}
+
+static void message_free(struct message_data *msg)
+{
+ message_timer_remove(msg);
+ g_free(msg->buddy);
+ g_free(msg);
+}
+
+static void messagelist_free()
+{
+ GSList *lp;
+ for (lp = messages_list; lp; lp = g_slist_next(lp))
+ message_free((struct message_data*)lp->data);
+ if (messages_list) {
+ g_slist_free(messages_list);
+ messages_list = NULL;
+ }
+}
+
+static void on_smartear_clicked(PurpleBlistNode* node, gpointer data)
+{
+ struct smartear_entry tmp, *entry;
+ GSList *lp;
+
+ clear_selection();
+
+ if (!edit_win) {
+ edit_win = create_edit_win();
+ }
+ gtk_widget_show_all(edit_win);
+
+ tmp = default_entry;
+
+ if (!node) {
+ return;
+ }
+ else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+ tmp.type = 'B';
+ tmp.name = ((PurpleBuddy*)node)->name;
+ purple_debug(PURPLE_DEBUG_INFO, "smartear", "adding buddy %s", tmp.name);
+ }
+ else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
+ tmp.type = 'B';
+ tmp.name = ((PurpleContact*)node)->alias;
+ if (!tmp.name) {
+ tmp.name = ((PurpleContact*)node)->priority->name;
+ }
+ purple_debug(PURPLE_DEBUG_INFO, "smartear", "adding contact %s", tmp.name);
+ }
+ else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
+ tmp.type = 'G';
+ tmp.name = ((PurpleGroup*)node)->name;
+ g_warning("group %p, %p %s", node, tmp.name, tmp.name);
+ purple_debug(PURPLE_DEBUG_INFO, "smartear", "adding group %s", tmp.name);
+ }
+ else {
+ return;
+ }
+
+ if ((lp = g_slist_find_custom(sounds_list, &tmp, (GCompareFunc)sound_cmp))) {
+ entry = (struct smartear_entry*)lp->data;
+ }
+ else {
+ entry = &tmp;
+ }
+
+ populate_edit_win(entry);
+}
+
+static void play_sound_alias(char *sound, PurpleAccount* account)
+{
+ struct smartear_entry tmp, *entry;
+ GSList *lp;
+
+ if (!sound || !*sound)
+ return;
+
+ /* sound aliases: mostly so you can put (Default) for sound, and it'll
+ * play that one */
+ tmp.type = 0;
+ tmp.name = sound;
+ if ((lp = g_slist_find_custom(sounds_list, &tmp, (GCompareFunc)sound_cmp))) {
+ entry = (struct smartear_entry*)lp->data;
+ play_sound_alias(entry->sound[EVENT_M], account);
+ }
+ else {
+ purple_sound_play_file(sound, account);
+ }
+}
+
+void play_matching_sound(PurpleBuddy *buddy, int event)
+{
+ GSList *lp;
+ struct smartear_entry *entry;
+ char *sound = NULL;
+ char *name = buddy ? g_strdup(my_normalize(buddy->name)) : NULL;
+ PurpleGroup *g = buddy ? purple_buddy_get_group(buddy) : NULL;
+
+ for (lp = sounds_list; lp; lp = g_slist_next(lp)) {
+ entry = (struct smartear_entry*)lp->data;
+ if (!entry->sound[event])
+ continue;
+
+ if (entry->type == 'B' && name
+ && g_strcasecmp(name, entry->name) == 0) {
+ sound = entry->sound[event];
+ /* found a buddy match.. this takes precedence, so stop */
+ break;
+ }
+ if (entry->type == 'G' && g
+ && g_strcasecmp(my_normalize(g->name), entry->name) == 0) {
+ sound = entry->sound[event];
+ /* keep going... buddy overrides group */
+ }
+ if (IS_DEFAULT(entry)) {
+ if (!sound)
+ sound = entry->sound[event];
+ /* keep going.. other 2 override default */
+ }
+ }
+ if (!IS_EMPTY(sound)) {
+ purple_debug(PURPLE_DEBUG_INFO, "smartear",
+ "found %s for %s on event %d\n", sound, name, event);
+ play_sound_alias(sound, purple_buddy_get_account(buddy));
+ }
+ else {
+ purple_debug(PURPLE_DEBUG_INFO, "smartear",
+ "no sound found for %s on event %d\n", name, event);
+ }
+ g_free(name);
+}
+
+static gint play_sound_timer_hook(gpointer data)
+{
+ struct message_data *msg = (struct message_data *)data;
+
+ if(!msg || !msg->timer) {
+ g_warning("smartear: timer called without being active!\n");
+ return FALSE;
+ }
+
+ play_matching_sound(purple_find_buddy(msg->account, msg->buddy), msg->timer->event);
+
+ g_free(msg->timer);
+ msg->timer = NULL;
+
+ return FALSE;
+}
+
+static gboolean on_im_recv(PurpleAccount *account, char *who, char *what, gint32 flags, void *junk)
+{
+ struct message_data *msg;
+ time_t now = time(0);
+ PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
+ PidginConversation *gtkconv = conv ? PIDGIN_CONVERSATION(conv) : NULL;
+
+ /* FIXME: message list is never trimmed. However, if we DO trim it,
+ * we need to consider race conditions on the msg field of the timer_hook */
+
+ if ((msg = find_message_by_name(account, who))) {
+ /* only install a timer if there's no active timers and we've just
+ * sent a message. If we haven't just sent a message, then
+ * a beep will go off anyways when the IM arrives. */
+ if(smartear_timers && !msg->timer
+ && msg->last_sent + message_delay > now) {
+ msg->timer = g_new0(struct timer_data, 1);
+ msg->timer->event = EVENT_M;
+ msg->timer->id = g_timeout_add(message_delay*1000,
+ play_sound_timer_hook, msg);
+ }
+
+ if (msg->last_active + message_delay > now && conv) {
+ purple_debug(PURPLE_DEBUG_INFO, "smartear",
+ "received IM from %s, but only %d/%d seconds passed.\n",
+ who, now - msg->last_active, message_delay);
+ return FALSE;
+ }
+ }
+ else {
+ msg = g_new0(struct message_data, 1);
+ msg->account = account;
+ msg->buddy = g_strdup(my_normalize(who));
+ msg->timer = NULL;
+
+ messages_list = g_slist_append(messages_list, msg);
+ }
+
+ msg->last_active = now;
+
+ if (focused_quiet && gtkconv && GTK_WIDGET_HAS_FOCUS(gtkconv->entry))
+ return FALSE; /* don't play sounds for the focused convo */
+ if (gtkconv && !gtkconv->make_sound)
+ return FALSE;
+
+ play_matching_sound(purple_find_buddy(msg->account, msg->buddy), EVENT_M);
+
+ return FALSE;
+}
+
+static void on_im_send(PurpleAccount *account, char *who, char *what, void *junk)
+{
+ struct message_data *msg;
+ time_t now = time(0);
+
+ if ((msg = find_message_by_name(account, who))) {
+ message_timer_remove(msg);
+ }
+ else {
+ msg = g_new0(struct message_data, 1);
+ msg->account = account;
+ msg->buddy = g_strdup(my_normalize(who));
+ msg->timer = NULL;
+
+ messages_list = g_slist_append(messages_list, msg);
+ }
+
+ msg->last_active = now;
+ msg->last_sent = now;
+}
+
+static void on_buddy_signon(PurpleBuddy *buddy, void *data)
+{
+ play_matching_sound(buddy, EVENT_S);
+}
+
+static void on_buddy_back(PurpleBuddy *buddy, void *data)
+{
+ play_matching_sound(buddy, EVENT_A);
+}
+
+static void on_buddy_unidle(PurpleBuddy *buddy, void *data)
+{
+ play_matching_sound(buddy, EVENT_I);
+}
+
+static void on_signon(PurpleConnection *gc, void *m)
+{
+}
+
+static void on_signoff(PurpleConnection *gc, void *m)
+{
+ messagelist_free();
+}
+
+static void on_blist_node_extended_menu(PurpleBlistNode *node, GList **menu)
+{
+ PurpleMenuAction *menu_action;
+ menu_action = purple_menu_action_new(_("Edit SmartEar Entry"),
+ PURPLE_CALLBACK(on_smartear_clicked), NULL, NULL);
+ *menu = g_list_append(*menu, menu_action);
+}
+
+static gboolean purple_plugin_init(PurplePlugin *plugin)
+{
+ void *blist_handle = purple_blist_get_handle();
+ void *conv_handle = purple_conversations_get_handle();
+
+ config = NULL;
+
+ smartear_load();
+
+ purple_signal_connect(blist_handle, "blist-node-extended-menu",
+ plugin, PURPLE_CALLBACK(on_blist_node_extended_menu), NULL);
+
+ purple_signal_connect(blist_handle, "buddy-signed-on",
+ plugin, PURPLE_CALLBACK(on_buddy_signon), NULL);
+ purple_signal_connect(blist_handle, "buddy-back",
+ plugin, PURPLE_CALLBACK(on_buddy_back), NULL);
+ purple_signal_connect(blist_handle, "buddy-unidle",
+ plugin, PURPLE_CALLBACK(on_buddy_unidle), NULL);
+
+ purple_signal_connect(conv_handle, "received-im-msg",
+ plugin, PURPLE_CALLBACK(on_im_recv), NULL);
+ purple_signal_connect(conv_handle, "sent-im-msg",
+ plugin, PURPLE_CALLBACK(on_im_send), NULL);
+
+ purple_signal_connect(purple_connections_get_handle(), "signed-on",
+ plugin, PURPLE_CALLBACK(on_signon), NULL);
+ purple_signal_connect(purple_connections_get_handle(), "signed-off",
+ plugin, PURPLE_CALLBACK(on_signoff), NULL);
+
+ return TRUE;
+}
+
+static gboolean purple_plugin_remove(PurplePlugin *h)
+{
+ config = NULL;
+
+ soundlist_free();
+ messagelist_free();
+
+ return TRUE;
+}
+
+static GtkWidget *purple_plugin_config_gtk(PurplePlugin *plugin)
+{
+ config = create_config();
+
+ setup_list();
+ set_option_entries();
+
+ gtk_widget_show_all(config);
+
+ return config;
+}
+
+static PurplePluginUiInfo ui_info = {
+ purple_plugin_config_gtk,
+ 0 /* page_num (reserved) */
+};
+
+static PurplePluginInfo info =
+{
+ PURPLE_PLUGIN_MAGIC,
+ PURPLE_MAJOR_VERSION,
+ PURPLE_MINOR_VERSION,
+ PURPLE_PLUGIN_STANDARD,
+ PIDGIN_PLUGIN_TYPE,
+ 0,
+ NULL,
+ PURPLE_PRIORITY_DEFAULT,
+ SMARTEAR_PLUGIN_ID,
+ NULL,
+ PP_VERSION,
+ NULL,
+ NULL,
+ "Matt Perry <guy@fscked.org>",
+ PP_WEBSITE,
+ purple_plugin_init,
+ purple_plugin_remove,
+ NULL,
+ &ui_info,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void init_plugin(PurplePlugin *plugin)
+{
+#ifdef ENABLE_NLS
+ bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
+ bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ info.name= _("Smart Ear");
+ info.summary = _("Assign different sounds to different buddies and groups");
+ info.description =
+ _("Allows you to assign different sounds to play for different buddies "
+ "or whole groups of buddies. Smart Ear allows you to opt to play "
+ "sounds when a buddy sends you an IM, signs on, returns from away "
+ "or idle, or any combination of these, so you'll know by the sound "
+ "what the important people are doing.");
+}
+
+PURPLE_INIT_PLUGIN(smartear, init_plugin, info);
--- a/smartear/smartear-interface.c Tue Jul 03 04:45:10 2007 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,546 +0,0 @@
-/* GPL Header */
-
-#ifdef HAVE_CONFIG_H
-# include "../pp_config.h"
-#endif
-
-#include <gtk/gtk.h>
-
-#define GLADE_HOOKUP_OBJECT(component,widget,name) \
- g_object_set_data_full (G_OBJECT (component), name, \
- gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
-
-#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
- g_object_set_data (G_OBJECT (component), name, widget)
-
-GtkWidget*
-create_config (void)
-{
- GtkWidget *config_vbox;
- GtkWidget *frame1;
- GtkWidget *table1;
- GtkWidget *label9;
- GtkObject *delay_spin_adj;
- GtkWidget *delay_spin;
- GtkWidget *focus_but;
- GtkWidget *timer_but;
- GtkWidget *label8;
- GtkWidget *frame2;
- GtkWidget *table2;
- GtkWidget *delete_but;
- GtkWidget *new_but;
- GtkWidget *scrolledwindow2;
- GtkWidget *treeview;
- GtkWidget *edit_but;
- GtkWidget *label7;
- GtkWidget *hbuttonbox1;
- GtkWidget *revert_but;
- GtkWidget *save_but;
-
-
- config_vbox = gtk_vbox_new (FALSE, 0);
- gtk_widget_set_size_request (config_vbox, -1, 640);
-
- frame1 = gtk_frame_new (NULL);
- gtk_widget_show (frame1);
- gtk_box_pack_start (GTK_BOX (config_vbox), frame1, FALSE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (frame1), 5);
-
- table1 = gtk_table_new (3, 2, FALSE);
- gtk_widget_show (table1);
- gtk_container_add (GTK_CONTAINER (frame1), table1);
- gtk_container_set_border_width (GTK_CONTAINER (table1), 5);
- gtk_table_set_row_spacings (GTK_TABLE (table1), 10);
- gtk_table_set_col_spacings (GTK_TABLE (table1), 10);
-
- label9 = gtk_label_new ("Time delay between playing sounds for a particular buddy:");
- gtk_widget_show (label9);
- gtk_table_attach (GTK_TABLE (table1), label9, 0, 1, 0, 1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label9), 0, 0.5);
-
- delay_spin_adj = gtk_adjustment_new (60, 0, 1000000, 1, 10, 10);
- delay_spin = gtk_spin_button_new (GTK_ADJUSTMENT (delay_spin_adj), 1, 0);
- gtk_widget_show (delay_spin);
- gtk_table_attach (GTK_TABLE (table1), delay_spin, 1, 2, 0, 1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (delay_spin), GTK_UPDATE_IF_VALID);
-
- focus_but = gtk_check_button_new_with_mnemonic ("Don't play sounds for the conversation that has focus.");
- gtk_widget_show (focus_but);
- gtk_table_attach (GTK_TABLE (table1), focus_but, 0, 2, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- timer_but = gtk_check_button_new_with_mnemonic ("Also play sounds if you don't respond to a particular IM within a delay period.");
- gtk_widget_show (timer_but);
- gtk_table_attach (GTK_TABLE (table1), timer_but, 0, 2, 2, 3,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- label8 = gtk_label_new ("Options");
- gtk_widget_show (label8);
- gtk_frame_set_label_widget (GTK_FRAME (frame1), label8);
-
- frame2 = gtk_frame_new (NULL);
- gtk_widget_show (frame2);
- gtk_box_pack_start (GTK_BOX (config_vbox), frame2, TRUE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (frame2), 5);
-
- table2 = gtk_table_new (2, 3, FALSE);
- gtk_widget_show (table2);
- gtk_container_add (GTK_CONTAINER (frame2), table2);
- gtk_container_set_border_width (GTK_CONTAINER (table2), 5);
- gtk_table_set_row_spacings (GTK_TABLE (table2), 10);
- gtk_table_set_col_spacings (GTK_TABLE (table2), 10);
-
- delete_but = gtk_button_new_from_stock ("gtk-delete");
- gtk_widget_show (delete_but);
- gtk_table_attach (GTK_TABLE (table2), delete_but, 2, 3, 1, 2,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- GTK_WIDGET_SET_FLAGS (delete_but, GTK_CAN_DEFAULT);
-
- new_but = gtk_button_new_from_stock ("gtk-new");
- gtk_widget_show (new_but);
- gtk_table_attach (GTK_TABLE (table2), new_but, 0, 1, 1, 2,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- GTK_WIDGET_SET_FLAGS (new_but, GTK_CAN_DEFAULT);
-
- scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
- gtk_widget_show (scrolledwindow2);
- gtk_table_attach (GTK_TABLE (table2), scrolledwindow2, 0, 3, 0, 1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow2), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-
- treeview = gtk_tree_view_new ();
- gtk_widget_show (treeview);
- gtk_container_add (GTK_CONTAINER (scrolledwindow2), treeview);
-
- edit_but = gtk_button_new_from_stock ("gtk-properties");
- gtk_widget_show (edit_but);
- gtk_table_attach (GTK_TABLE (table2), edit_but, 1, 2, 1, 2,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- label7 = gtk_label_new ("Entries");
- gtk_widget_show (label7);
- gtk_frame_set_label_widget (GTK_FRAME (frame2), label7);
-
- hbuttonbox1 = gtk_hbutton_box_new ();
- gtk_widget_show (hbuttonbox1);
- gtk_box_pack_start (GTK_BOX (config_vbox), hbuttonbox1, FALSE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 5);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD);
-
- revert_but = gtk_button_new_from_stock ("gtk-revert-to-saved");
- gtk_widget_show (revert_but);
- gtk_container_add (GTK_CONTAINER (hbuttonbox1), revert_but);
- GTK_WIDGET_SET_FLAGS (revert_but, GTK_CAN_DEFAULT);
-
- save_but = gtk_button_new_from_stock ("gtk-save");
- gtk_widget_show (save_but);
- gtk_container_add (GTK_CONTAINER (hbuttonbox1), save_but);
- GTK_WIDGET_SET_FLAGS (save_but, GTK_CAN_DEFAULT);
-
- g_signal_connect ((gpointer) config_vbox, "destroy",
- G_CALLBACK (on_config_destroy),
- NULL);
- g_signal_connect ((gpointer) delay_spin, "changed",
- G_CALLBACK (on_delay_changed),
- NULL);
- g_signal_connect ((gpointer) focus_but, "toggled",
- G_CALLBACK (on_focus_toggled),
- NULL);
- g_signal_connect ((gpointer) timer_but, "toggled",
- G_CALLBACK (on_timer_toggled),
- NULL);
- g_signal_connect ((gpointer) delete_but, "clicked",
- G_CALLBACK (on_delete_clicked),
- NULL);
- g_signal_connect ((gpointer) new_but, "clicked",
- G_CALLBACK (on_new_clicked),
- NULL);
- g_signal_connect ((gpointer) edit_but, "clicked",
- G_CALLBACK (on_edit_clicked),
- NULL);
- g_signal_connect ((gpointer) revert_but, "clicked",
- G_CALLBACK (on_revert_clicked),
- NULL);
- g_signal_connect ((gpointer) save_but, "clicked",
- G_CALLBACK (on_save_clicked),
- NULL);
-
- /* Store pointers to all widgets, for use by lookup_widget(). */
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, config_vbox, "config_vbox");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, frame1, "frame1");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, table1, "table1");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, label9, "label9");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, delay_spin, "delay_spin");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, focus_but, "focus_but");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, timer_but, "timer_but");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, label8, "label8");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, frame2, "frame2");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, table2, "table2");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, delete_but, "delete_but");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, new_but, "new_but");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, scrolledwindow2, "scrolledwindow2");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, treeview, "treeview");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, edit_but, "edit_but");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, label7, "label7");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, hbuttonbox1, "hbuttonbox1");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, revert_but, "revert_but");
- GLADE_HOOKUP_OBJECT_NO_REF (config_vbox, save_but, "save_but");
-
- return config_vbox;
-}
-
-GtkWidget*
-create_file_browse (void)
-{
- GtkWidget *file_browse;
- GtkWidget *ok_button1;
- GtkWidget *cancel_button1;
-
- file_browse = gtk_file_selection_new ("Select Sound");
- gtk_container_set_border_width (GTK_CONTAINER (file_browse), 10);
- gtk_window_set_destroy_with_parent (GTK_WINDOW (file_browse), TRUE);
- gtk_window_set_type_hint (GTK_WINDOW (file_browse), GDK_WINDOW_TYPE_HINT_DIALOG);
-
- ok_button1 = GTK_FILE_SELECTION (file_browse)->ok_button;
- gtk_widget_show (ok_button1);
- GTK_WIDGET_SET_FLAGS (ok_button1, GTK_CAN_DEFAULT);
-
- cancel_button1 = GTK_FILE_SELECTION (file_browse)->cancel_button;
- gtk_widget_show (cancel_button1);
- GTK_WIDGET_SET_FLAGS (cancel_button1, GTK_CAN_DEFAULT);
-
- g_signal_connect ((gpointer) file_browse, "destroy",
- G_CALLBACK (on_file_browse_destroy),
- NULL);
- g_signal_connect ((gpointer) ok_button1, "clicked",
- G_CALLBACK (on_browse_ok_clicked),
- NULL);
- g_signal_connect_swapped ((gpointer) ok_button1, "clicked",
- G_CALLBACK (gtk_widget_destroy),
- GTK_OBJECT (file_browse));
- g_signal_connect_swapped ((gpointer) cancel_button1, "clicked",
- G_CALLBACK (gtk_widget_destroy),
- GTK_OBJECT (file_browse));
-
- /* Store pointers to all widgets, for use by lookup_widget(). */
- GLADE_HOOKUP_OBJECT_NO_REF (file_browse, file_browse, "file_browse");
- GLADE_HOOKUP_OBJECT_NO_REF (file_browse, ok_button1, "ok_button1");
- GLADE_HOOKUP_OBJECT_NO_REF (file_browse, cancel_button1, "cancel_button1");
-
- return file_browse;
-}
-
-GtkWidget*
-create_edit_win (void)
-{
- GtkWidget *edit_win;
- GtkWidget *vbox1;
- GtkWidget *hbox1;
- GtkWidget *label29;
- GtkWidget *name_entry;
- GtkWidget *label30;
- GtkWidget *type_option;
- GtkWidget *menu1;
- GtkWidget *item_buddy;
- GtkWidget *item_group;
- GtkWidget *hbuttonbox2;
- GtkWidget *applysave_but;
- GtkWidget *apply_but;
- GtkWidget *cancel_but;
- GtkWidget *frame3;
- GtkWidget *table5;
- GtkWidget *label31;
- GtkWidget *label34;
- GtkWidget *label33;
- GtkWidget *label32;
- GtkWidget *unaway_sound_entry;
- GtkWidget *unidle_sound_entry;
- GtkWidget *signon_sound_entry;
- GtkWidget *unaway_test_but;
- GtkWidget *unidle_test_but;
- GtkWidget *signon_test_but;
- GtkWidget *unaway_browse_but;
- GtkWidget *unidle_browse_but;
- GtkWidget *signon_browse_but;
- GtkWidget *im_browse_but;
- GtkWidget *im_sound_entry;
- GtkWidget *im_test_but;
- GtkWidget *label24;
-
- edit_win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
- gtk_widget_set_size_request (edit_win, 600, 300);
- gtk_window_set_title (GTK_WINDOW (edit_win), "Edit Entry");
- gtk_window_set_default_size (GTK_WINDOW (edit_win), 600, 300);
-
- vbox1 = gtk_vbox_new (FALSE, 0);
- gtk_widget_show (vbox1);
- gtk_container_add (GTK_CONTAINER (edit_win), vbox1);
-
- hbox1 = gtk_hbox_new (FALSE, 5);
- gtk_widget_show (hbox1);
- gtk_box_pack_start (GTK_BOX (vbox1), hbox1, FALSE, TRUE, 10);
- gtk_container_set_border_width (GTK_CONTAINER (hbox1), 5);
-
- label29 = gtk_label_new ("Name:");
- gtk_widget_show (label29);
- gtk_box_pack_start (GTK_BOX (hbox1), label29, FALSE, FALSE, 0);
- gtk_misc_set_alignment (GTK_MISC (label29), 1, 0.5);
-
- name_entry = gtk_entry_new ();
- gtk_widget_show (name_entry);
- gtk_box_pack_start (GTK_BOX (hbox1), name_entry, TRUE, TRUE, 0);
-
- label30 = gtk_label_new ("Type:");
- gtk_widget_show (label30);
- gtk_box_pack_start (GTK_BOX (hbox1), label30, FALSE, TRUE, 0);
- gtk_misc_set_alignment (GTK_MISC (label30), 1, 0.5);
-
- type_option = gtk_option_menu_new ();
- gtk_widget_show (type_option);
- gtk_box_pack_start (GTK_BOX (hbox1), type_option, FALSE, FALSE, 0);
-
- menu1 = gtk_menu_new ();
-
- item_buddy = gtk_menu_item_new_with_mnemonic ("Buddy");
- gtk_widget_show (item_buddy);
- gtk_container_add (GTK_CONTAINER (menu1), item_buddy);
-
- item_group = gtk_menu_item_new_with_mnemonic ("Group");
- gtk_widget_show (item_group);
- gtk_container_add (GTK_CONTAINER (menu1), item_group);
-
- gtk_option_menu_set_menu (GTK_OPTION_MENU (type_option), menu1);
-
- hbuttonbox2 = gtk_hbutton_box_new ();
- gtk_widget_show (hbuttonbox2);
- gtk_box_pack_end (GTK_BOX (vbox1), hbuttonbox2, FALSE, TRUE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox2), 5);
- gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_SPREAD);
-
- applysave_but = gtk_button_new_with_mnemonic ("Apply and Save");
- gtk_widget_show (applysave_but);
- gtk_container_add (GTK_CONTAINER (hbuttonbox2), applysave_but);
- GTK_WIDGET_SET_FLAGS (applysave_but, GTK_CAN_DEFAULT);
-
- apply_but = gtk_button_new_from_stock ("gtk-apply");
- gtk_widget_show (apply_but);
- gtk_container_add (GTK_CONTAINER (hbuttonbox2), apply_but);
- GTK_WIDGET_SET_FLAGS (apply_but, GTK_CAN_DEFAULT);
-
- cancel_but = gtk_button_new_from_stock ("gtk-cancel");
- gtk_widget_show (cancel_but);
- gtk_container_add (GTK_CONTAINER (hbuttonbox2), cancel_but);
- GTK_WIDGET_SET_FLAGS (cancel_but, GTK_CAN_DEFAULT);
-
- frame3 = gtk_frame_new (NULL);
- gtk_widget_show (frame3);
- gtk_box_pack_start (GTK_BOX (vbox1), frame3, FALSE, FALSE, 0);
- gtk_widget_set_size_request (frame3, -1, 200);
- gtk_container_set_border_width (GTK_CONTAINER (frame3), 5);
-
- table5 = gtk_table_new (4, 5, FALSE);
- gtk_widget_show (table5);
- gtk_container_add (GTK_CONTAINER (frame3), table5);
- gtk_widget_set_size_request (table5, 600, 400);
- gtk_container_set_border_width (GTK_CONTAINER (table5), 5);
- gtk_table_set_row_spacings (GTK_TABLE (table5), 10);
- gtk_table_set_col_spacings (GTK_TABLE (table5), 10);
-
- label31 = gtk_label_new ("Play On IM:");
- gtk_widget_show (label31);
- gtk_table_attach (GTK_TABLE (table5), label31, 0, 1, 0, 1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label31), 0, 0.5);
-
- label34 = gtk_label_new ("Play On Unaway:");
- gtk_widget_show (label34);
- gtk_table_attach (GTK_TABLE (table5), label34, 0, 1, 3, 4,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label34), 0, 0.5);
-
- label33 = gtk_label_new ("Play On Unidle:");
- gtk_widget_show (label33);
- gtk_table_attach (GTK_TABLE (table5), label33, 0, 1, 2, 3,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label33), 0, 0.5);
-
- label32 = gtk_label_new ("Play On Signon:");
- gtk_widget_show (label32);
- gtk_table_attach (GTK_TABLE (table5), label32, 0, 1, 1, 2,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (label32), 0, 0.5);
-
- unaway_sound_entry = gtk_entry_new ();
- gtk_widget_show (unaway_sound_entry);
- gtk_table_attach (GTK_TABLE (table5), unaway_sound_entry, 1, 3, 3, 4,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- unidle_sound_entry = gtk_entry_new ();
- gtk_widget_show (unidle_sound_entry);
- gtk_table_attach (GTK_TABLE (table5), unidle_sound_entry, 1, 3, 2, 3,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- signon_sound_entry = gtk_entry_new ();
- gtk_widget_show (signon_sound_entry);
- gtk_table_attach (GTK_TABLE (table5), signon_sound_entry, 1, 3, 1, 2,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- unaway_test_but = gtk_button_new_with_mnemonic ("Test");
- gtk_widget_show (unaway_test_but);
- gtk_table_attach (GTK_TABLE (table5), unaway_test_but, 4, 5, 3, 4,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- unidle_test_but = gtk_button_new_with_mnemonic ("Test");
- gtk_widget_show (unidle_test_but);
- gtk_table_attach (GTK_TABLE (table5), unidle_test_but, 4, 5, 2, 3,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- signon_test_but = gtk_button_new_with_mnemonic ("Test");
- gtk_widget_show (signon_test_but);
- gtk_table_attach (GTK_TABLE (table5), signon_test_but, 4, 5, 1, 2,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- unaway_browse_but = gtk_button_new_from_stock ("gtk-open");
- gtk_widget_show (unaway_browse_but);
- gtk_table_attach (GTK_TABLE (table5), unaway_browse_but, 3, 4, 3, 4,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- unidle_browse_but = gtk_button_new_from_stock ("gtk-open");
- gtk_widget_show (unidle_browse_but);
- gtk_table_attach (GTK_TABLE (table5), unidle_browse_but, 3, 4, 2, 3,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- signon_browse_but = gtk_button_new_from_stock ("gtk-open");
- gtk_widget_show (signon_browse_but);
- gtk_table_attach (GTK_TABLE (table5), signon_browse_but, 3, 4, 1, 2,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- im_browse_but = gtk_button_new_from_stock ("gtk-open");
- gtk_widget_show (im_browse_but);
- gtk_table_attach (GTK_TABLE (table5), im_browse_but, 3, 4, 0, 1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- im_sound_entry = gtk_entry_new ();
- gtk_widget_show (im_sound_entry);
- gtk_table_attach (GTK_TABLE (table5), im_sound_entry, 1, 3, 0, 1,
- (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- im_test_but = gtk_button_new_with_mnemonic ("Test");
- gtk_widget_show (im_test_but);
- gtk_table_attach (GTK_TABLE (table5), im_test_but, 4, 5, 0, 1,
- (GtkAttachOptions) (0),
- (GtkAttachOptions) (0), 0, 0);
-
- label24 = gtk_label_new ("Sound Events");
- gtk_widget_show (label24);
- gtk_frame_set_label_widget (GTK_FRAME (frame3), label24);
-
- g_signal_connect ((gpointer) edit_win, "destroy",
- G_CALLBACK (on_edit_win_destroy),
- NULL);
- g_signal_connect ((gpointer) applysave_but, "clicked",
- G_CALLBACK (on_apply_clicked),
- NULL);
- g_signal_connect ((gpointer) applysave_but, "clicked",
- G_CALLBACK (on_save_clicked),
- NULL);
- g_signal_connect_swapped ((gpointer) applysave_but, "clicked",
- G_CALLBACK (gtk_widget_destroy),
- GTK_OBJECT (edit_win));
- g_signal_connect ((gpointer) apply_but, "clicked",
- G_CALLBACK (on_apply_clicked),
- NULL);
- g_signal_connect_swapped ((gpointer) apply_but, "clicked",
- G_CALLBACK (gtk_widget_destroy),
- GTK_OBJECT (edit_win));
- g_signal_connect_swapped ((gpointer) cancel_but, "clicked",
- G_CALLBACK (gtk_widget_destroy),
- GTK_OBJECT (edit_win));
- g_signal_connect ((gpointer) unaway_test_but, "clicked",
- G_CALLBACK (on_unaway_test_clicked),
- NULL);
- g_signal_connect ((gpointer) unidle_test_but, "clicked",
- G_CALLBACK (on_unidle_test_clicked),
- NULL);
- g_signal_connect ((gpointer) signon_test_but, "clicked",
- G_CALLBACK (on_signon_test_clicked),
- NULL);
- g_signal_connect ((gpointer) unaway_browse_but, "clicked",
- G_CALLBACK (on_unaway_browse_clicked),
- NULL);
- g_signal_connect ((gpointer) unidle_browse_but, "clicked",
- G_CALLBACK (on_unidle_browse_clicked),
- NULL);
- g_signal_connect ((gpointer) signon_browse_but, "clicked",
- G_CALLBACK (on_signon_browse_clicked),
- NULL);
- g_signal_connect ((gpointer) im_browse_but, "clicked",
- G_CALLBACK (on_im_browse_clicked),
- NULL);
- g_signal_connect ((gpointer) im_test_but, "clicked",
- G_CALLBACK (on_im_test_clicked),
- NULL);
-
- /* Store pointers to all widgets, for use by lookup_widget(). */
- GLADE_HOOKUP_OBJECT_NO_REF (edit_win, edit_win, "edit_win");
- GLADE_HOOKUP_OBJECT (edit_win, vbox1, "vbox1");
- GLADE_HOOKUP_OBJECT (edit_win, hbox1, "hbox1");
- GLADE_HOOKUP_OBJECT (edit_win, label29, "label29");
- GLADE_HOOKUP_OBJECT (edit_win, name_entry, "name_entry");
- GLADE_HOOKUP_OBJECT (edit_win, label30, "label30");
- GLADE_HOOKUP_OBJECT (edit_win, type_option, "type_option");
- GLADE_HOOKUP_OBJECT (edit_win, menu1, "menu1");
- GLADE_HOOKUP_OBJECT (edit_win, item_buddy, "item_buddy");
- GLADE_HOOKUP_OBJECT (edit_win, item_group, "item_group");
- GLADE_HOOKUP_OBJECT (edit_win, hbuttonbox2, "hbuttonbox2");
- GLADE_HOOKUP_OBJECT (edit_win, applysave_but, "applysave_but");
- GLADE_HOOKUP_OBJECT (edit_win, apply_but, "apply_but");
- GLADE_HOOKUP_OBJECT (edit_win, cancel_but, "cancel_but");
- GLADE_HOOKUP_OBJECT (edit_win, frame3, "frame3");
- GLADE_HOOKUP_OBJECT (edit_win, table5, "table5");
- GLADE_HOOKUP_OBJECT (edit_win, label31, "label31");
- GLADE_HOOKUP_OBJECT (edit_win, label34, "label34");
- GLADE_HOOKUP_OBJECT (edit_win, label33, "label33");
- GLADE_HOOKUP_OBJECT (edit_win, label32, "label32");
- GLADE_HOOKUP_OBJECT (edit_win, unaway_sound_entry, "unaway_sound_entry");
- GLADE_HOOKUP_OBJECT (edit_win, unidle_sound_entry, "unidle_sound_entry");
- GLADE_HOOKUP_OBJECT (edit_win, signon_sound_entry, "signon_sound_entry");
- GLADE_HOOKUP_OBJECT (edit_win, unaway_test_but, "unaway_test_but");
- GLADE_HOOKUP_OBJECT (edit_win, unidle_test_but, "unidle_test_but");
- GLADE_HOOKUP_OBJECT (edit_win, signon_test_but, "signon_test_but");
- GLADE_HOOKUP_OBJECT (edit_win, unaway_browse_but, "unaway_browse_but");
- GLADE_HOOKUP_OBJECT (edit_win, unidle_browse_but, "unidle_browse_but");
- GLADE_HOOKUP_OBJECT (edit_win, signon_browse_but, "signon_browse_but");
- GLADE_HOOKUP_OBJECT (edit_win, im_browse_but, "im_browse_but");
- GLADE_HOOKUP_OBJECT (edit_win, im_sound_entry, "im_sound_entry");
- GLADE_HOOKUP_OBJECT (edit_win, im_test_but, "im_test_but");
- GLADE_HOOKUP_OBJECT (edit_win, label24, "label24");
-
- return edit_win;
-}
-
--- a/smartear/smartear.c Tue Jul 03 04:45:10 2007 -0400
+++ b/smartear/smartear.c Thu Jul 05 05:46:17 2007 -0400
@@ -1,1280 +1,105 @@
-/* SmartEar by Matt Perry
- * Works for purple 2.0.0
- * Plugin to assign different sounds to different buddies and groups.
- * TODO: figure out contact support
+/*
+ * smartear.c - SmartEar plugin for libpurple
+ * Copyright (c) 2007 John Bailey <rekkanoryo@rekkanoryo.org>
+ *
+ * Original code copyright (c) 2003-2007 Matt Perry
+ *
+ * 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
*/
+#define PURPLE_PLUGINS
+
#ifdef HAVE_CONFIG_H
-# include "../pp_config.h"
-#endif
-#include "../common/i18n.h"
-
-#include "pidgin.h"
-
-#include "gtkplugin.h"
-#include "gtkutils.h"
-#include "version.h"
-
-#include "debug.h"
-#include "util.h"
-#include "sound.h"
-#include "gtkprefs.h"
-#include "gtkblist.h"
-#include "signals.h"
-
-#ifndef PURPLE_PLUGINS
-#define PURPLE_PLUGINS
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <time.h>
-
-#ifdef _WIN32
-#include "win32dep.h"
-#endif
-
-#define BUF_LEN 2048 /* lifted from libpurple's internal.h */
-
-#define RCFILE_VERSION 2
-#define RC_EMPTY_SOUND " " /* must be at least 1 char long for sscanf */
-
-#define SMARTEAR_PLUGIN_ID "smartear"
-#define SMARTEAR_VERSION VERSION ".1"
-
-#define FIND(s) lookup_widget(config, s)
-#define EFIND(s) lookup_widget(edit_win, s)
-
-/* an entry in the prefs file to indicate what to play for who and when. */
-struct smartear_entry {
- char type; /* B,G */
- char *name;
-#define EVENT_M 0
-#define EVENT_S 1
-#define EVENT_I 2
-#define EVENT_A 3
-#define EVENT_NUM 4
- char *sound[EVENT_NUM];
-};
-
-struct timer_data {
- int event;
- guint id;
-};
-
-struct message_data {
- PurpleAccount *account;
- char *buddy;
- time_t last_active;
- time_t last_sent;
- struct timer_data *timer;
-};
-
-enum { /* Treeview columns */
- DATA_COL = 0,
- TYPE_COL = 0,
- NAME_COL,
- ON_MESSAGE_COL,
- ON_SIGNON_COL,
- ON_UNIDLE_COL,
- ON_UNAWAY_COL,
- NUM_COLS
-};
-
-#define DEFAULT_NAME "(Default)"
-#define IS_DEFAULT(entry) (strcmp(entry->name, DEFAULT_NAME)==0)
-#define IS_EMPTY(str) (!str || !str[0])
-struct smartear_entry default_entry = {'B', DEFAULT_NAME, {"", "", "", ""}};
-
-int message_delay = 60;
-int focused_quiet = TRUE;
-int smartear_timers = FALSE;
-
-GtkWidget *config = NULL;
-GtkWidget *edit_win = NULL;
-GtkWidget *file_browse = NULL;
-GtkWidget *file_browse_entry = NULL;
-GtkTreeView *treeview = NULL;
-GtkTreeSelection *treeselect = NULL;
-GtkTreeModel *treemodel = NULL;
-
-struct smartear_entry *selected_entry = NULL;
-GtkTreeIter selected_iter;
-
-GSList *sounds_list = NULL;
-GSList *messages_list = NULL;
-
-GtkWidget *create_file_browse(void);
-GtkWidget *create_edit_win(void);
-GtkWidget *create_config(void);
-
-static void new_entry(struct smartear_entry *entry);
-static gboolean get_selection(void);
-static void clear_selection(void);
-static void populate_edit_win(struct smartear_entry *entry);
-static void update_list(void);
-static void populate_list(GtkListStore *store);
-static void list_set(GtkListStore *store, GtkTreeIter *iter, struct smartear_entry *entry);
-static void set_option_entries(void);
-
-static gint sound_cmp(gconstpointer p1, gconstpointer p2);
-static struct smartear_entry *sound_new_with_name(gchar *name);
-static struct smartear_entry *sound_dup(struct smartear_entry *entry);
-static void sound_free(struct smartear_entry *entry, int free_entry);
-static void soundlist_free(void);
-
-static gchar *get_basename(gchar *path);
-
-static void on_treeselect_changed(GtkTreeSelection *selection, gpointer data);
-
-static void smartear_save(void);
-static void smartear_load(void);
-
-static void play_sound_alias(char *sound, PurpleAccount* account);
-
-/*** Glade's Support Function ***/
-
-GtkWidget* lookup_widget (GtkWidget *widget, const gchar *widget_name)
-{
- GtkWidget *found_widget;
- found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
- widget_name);
- if (!found_widget)
- g_warning ("smartear: Widget not found: %s", widget_name);
- return found_widget;
-}
-
-/*** GTK Callbacks ***/
-
-/* Options Frame */
-
-void on_delay_changed (GtkEditable *editable, gpointer user_data)
-{
- gchar *text = gtk_editable_get_chars(editable, 0, -1);
- message_delay = atoi(text);
- g_free(text);
-}
-
-void on_focus_toggled (GtkToggleButton *togglebutton, gpointer user_data)
-{
- focused_quiet = gtk_toggle_button_get_active(togglebutton);
-}
-
-void on_timer_toggled (GtkToggleButton *togglebutton, gpointer user_data)
-{
- smartear_timers = gtk_toggle_button_get_active(togglebutton);
-}
-
-/* Entries Frame */
-
-void on_cell_edited(GtkCellRendererText *cell, gchar *path, gchar *text, gpointer data)
-{
- GtkTreeIter iter;
- gint col = GPOINTER_TO_INT(data);
- struct smartear_entry *entry;
-
- if (!gtk_tree_model_get_iter_from_string(treemodel, &iter, path))
- return;
-
- gtk_tree_model_get(treemodel, &iter, DATA_COL, &entry, -1);
- switch (col) {
- case NAME_COL:
- if (IS_DEFAULT(entry))
- return;
- g_free(entry->name);
- entry->name = g_strdup(text);
- update_list();
- break;
- }
-}
-
-void on_treeselect_changed(GtkTreeSelection *selection, gpointer data)
-{
- get_selection();
- update_list();
-}
-
-
-void on_new_clicked (GtkButton *button, gpointer user_data)
-{
- if (edit_win)
- return;
-
- new_entry(sound_new_with_name(""));
-}
-
-void on_delete_clicked (GtkButton *button, gpointer user_data)
-{
- GtkTreeIter iter;
-
- if (edit_win)
- return;
-
- if (!get_selection())
- return;
-
- if (IS_DEFAULT(selected_entry))
- return;
-
- iter = selected_iter;
-
- sounds_list = g_slist_remove(sounds_list, selected_entry);
- sound_free(selected_entry, TRUE);
-
- if (!gtk_tree_model_iter_next(treemodel, &iter)) {
- GtkTreePath *path = gtk_tree_model_get_path(treemodel, &selected_iter);
- gtk_tree_path_prev(path);
- gtk_tree_model_get_iter(treemodel, &iter, path);
- gtk_tree_path_free(path);
- }
- g_signal_handlers_block_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
- gtk_list_store_remove(GTK_LIST_STORE(treemodel), &selected_iter);
- gtk_tree_selection_select_iter(treeselect, &iter);
- g_signal_handlers_unblock_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
-
- get_selection();
- update_list();
-}
-
-void on_edit_clicked (GtkButton *button, gpointer user_data)
-{
- if (!get_selection())
- return;
-
- if (edit_win)
- return;
-
- edit_win = create_edit_win();
- gtk_widget_show_all(edit_win);
-
- populate_edit_win(selected_entry);
-}
-
-void on_save_clicked (GtkButton *button, gpointer user_data)
-{
- smartear_save();
-}
-
-void on_revert_clicked (GtkButton *button, gpointer user_data)
-{
- selected_entry = NULL;
- if (edit_win) {
- gtk_widget_destroy(edit_win);
- edit_win = NULL;
- }
-
- soundlist_free();
- smartear_load();
- gtk_list_store_clear(GTK_LIST_STORE(treemodel));
- populate_list(GTK_LIST_STORE(treemodel));
- update_list();
- set_option_entries();
-}
-
-/* Edit Window */
-
-void on_browse_ok_clicked (GtkButton *button, gpointer user_data)
-{
- gtk_entry_set_text(GTK_ENTRY(file_browse_entry),
- gtk_file_selection_get_filename(GTK_FILE_SELECTION(file_browse)));
-}
-
-void on_file_browse_destroy (GtkObject *object, gpointer user_data)
-{
- file_browse = NULL;
- file_browse_entry = NULL;
-}
-
-void on_browse_clicked (GtkButton *button, gchar *user_data)
-{
- gchar *text;
- if (file_browse)
- return;
-
- file_browse = create_file_browse();
- gtk_widget_show(file_browse);
+# include "../pp_config.h"
+#endif /* HAVE_CONFIG_H */
- file_browse_entry = EFIND(user_data);
- text = gtk_editable_get_chars(GTK_EDITABLE(file_browse_entry), 0, -1);
- gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_browse), text);
- g_free(text);
-}
-
-void on_im_browse_clicked (GtkButton *button, gpointer user_data)
-{
- on_browse_clicked(button, "im_sound_entry");
-}
-
-void on_signon_browse_clicked (GtkButton *button, gpointer user_data)
-{
- on_browse_clicked(button, "signon_sound_entry");
-}
-
-void on_unidle_browse_clicked (GtkButton *button, gpointer user_data)
-{
- on_browse_clicked(button, "unidle_sound_entry");
-}
-
-void on_unaway_browse_clicked (GtkButton *button, gpointer user_data)
-{
- on_browse_clicked(button, "unaway_sound_entry");
-}
-
-void on_test_clicked (GtkButton *button, gchar *user_data)
-{
- gchar *text =
- gtk_editable_get_chars(GTK_EDITABLE(EFIND(user_data)), 0, -1);
- play_sound_alias(text, NULL);
- g_free(text);
-}
-
-void on_im_test_clicked (GtkButton *button, gpointer user_data)
-{
- on_test_clicked(button, "im_sound_entry");
-}
-
-void on_signon_test_clicked (GtkButton *button, gpointer user_data)
-{
- on_test_clicked(button, "signon_sound_entry");
-}
-
-void on_unidle_test_clicked (GtkButton *button, gpointer user_data)
-{
- on_test_clicked(button, "unidle_sound_entry");
-}
-
-void on_unaway_test_clicked (GtkButton *button, gpointer user_data)
-{
- on_test_clicked(button, "unaway_sound_entry");
-}
-
-void on_apply_clicked (GtkButton *button, gpointer user_data)
-{
- struct smartear_entry *entry, tmp;
-
- if (get_selection()) {
- entry = selected_entry;
-
- g_free(entry->name);
- g_free(entry->sound[0]);
- g_free(entry->sound[1]);
- g_free(entry->sound[2]);
- g_free(entry->sound[3]);
- }
- else {
- entry = &tmp;
- }
-
- entry->name =
- gtk_editable_get_chars(GTK_EDITABLE(EFIND("name_entry")), 0, -1);
- entry->type =
- gtk_option_menu_get_history(GTK_OPTION_MENU(EFIND("type_option"))) == 0
- ? 'B' : 'G';
- entry->sound[EVENT_M] =
- gtk_editable_get_chars(GTK_EDITABLE(EFIND("im_sound_entry")), 0, -1);
- entry->sound[EVENT_S] =
- gtk_editable_get_chars(GTK_EDITABLE(EFIND("signon_sound_entry")), 0, -1);
- entry->sound[EVENT_I] =
- gtk_editable_get_chars(GTK_EDITABLE(EFIND("unidle_sound_entry")), 0, -1);
- entry->sound[EVENT_A] =
- gtk_editable_get_chars(GTK_EDITABLE(EFIND("unaway_sound_entry")), 0, -1);
-
- if (!selected_entry) {
- GSList *lp;
- if ((lp = g_slist_find_custom(sounds_list, entry, (GCompareFunc)sound_cmp))) {
- sound_free((struct smartear_entry*)lp->data, FALSE);
- *(struct smartear_entry*)lp->data = *entry;
- }
- else {
- struct smartear_entry *copy = g_new(struct smartear_entry, 1);
- *copy = *entry;
- new_entry(copy);
- }
- }
-
- update_list();
-}
-
-void on_edit_win_destroy (GtkObject *object, gpointer user_data)
-{
- edit_win = NULL;
-
- if (config) {
- gtk_widget_set_sensitive(GTK_WIDGET(treeview), TRUE);
- }
-}
-
-void on_config_destroy (GtkObject *object, gpointer user_data)
-{
- config = NULL;
-}
-
-/*** Util Functions ***/
-
-static void new_entry(struct smartear_entry *entry)
-{
- GtkTreeIter iter;
- GtkTreePath *path;
- GtkTreeViewColumn *name_column;
-
- sounds_list = g_slist_append(sounds_list, entry);
-
- if (!config)
- return;
-
- if (get_selection())
- gtk_list_store_insert_after(GTK_LIST_STORE(treemodel), &iter, &selected_iter);
- else
- gtk_list_store_append(GTK_LIST_STORE(treemodel), &iter);
-
- path = gtk_tree_model_get_path(treemodel, &iter);
- list_set(GTK_LIST_STORE(treemodel), &iter, entry);
-
- g_signal_handlers_block_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
- path = gtk_tree_model_get_path(treemodel, &iter);
- name_column = gtk_tree_view_get_column(treeview, NAME_COL);
- if (entry->name && entry->name[0])
- gtk_tree_view_set_cursor(treeview, path, 0, FALSE);
- else {
- gtk_tree_view_set_cursor(treeview, path, name_column, TRUE);
- }
- gtk_tree_path_free(path);
- g_signal_handlers_unblock_by_func(G_OBJECT(treeselect), on_treeselect_changed, 0);
-
- get_selection();
-}
-
-static gboolean get_selection(void)
-{
- selected_entry = NULL;
-
- if (!config)
- return FALSE;
-
- if (!gtk_tree_selection_get_selected(treeselect, &treemodel, &selected_iter))
- return FALSE;
-
- gtk_tree_model_get(treemodel, &selected_iter, DATA_COL, &selected_entry, -1);
- return TRUE;
-}
-
-void clear_selection(void)
-{
- selected_entry = NULL;
-
- if (!config)
- return;
-
- if (gtk_tree_selection_get_selected(treeselect, &treemodel, &selected_iter)) {
- gtk_tree_selection_unselect_iter(treeselect, &selected_iter);
- }
-}
-
-static void list_set(GtkListStore *store, GtkTreeIter *iter, struct smartear_entry *entry)
-{
- gtk_list_store_set(store, iter, DATA_COL, entry, -1);
-}
-
-static char *my_normalize(const char *input)
-{
- static char buf[BUF_LEN];
- char *str, *beg;
- int i=0;
-
- g_return_val_if_fail((input != NULL), NULL);
-
- beg = str = g_strdup(input);
-
- while (*str && i <= BUF_LEN) {
- if (*str != ' ')
- buf[i++] = *str;
- str++;
- }
- buf[i] = '\0';
- g_free(beg);
-
- return buf;
-
-}
-
-static struct smartear_entry *sound_new_with_name(gchar *name)
-{
- struct smartear_entry tmp = default_entry;
- tmp.name = name;
- return sound_dup(&tmp);
-}
-
-static struct smartear_entry *sound_dup(struct smartear_entry *entry)
-{
- struct smartear_entry *edup = g_new(struct smartear_entry, 1);
- int i;
-
- edup->type = entry->type;
- edup->name = g_strdup(my_normalize(entry->name));
- for (i = 0; i < EVENT_NUM; i++) {
- edup->sound[i] = g_strdup(entry->sound[i]);
- }
-
- return edup;
-}
-
-static void sound_free(struct smartear_entry *entry, int free_entry)
-{
- g_free(entry->name);
- g_free(entry->sound[0]);
- g_free(entry->sound[1]);
- g_free(entry->sound[2]);
- g_free(entry->sound[3]);
- if (free_entry) {
- g_free(entry);
- }
-}
-
-static void soundlist_free(void)
-{
- GSList *lp;
- for (lp = sounds_list; lp; lp = g_slist_next(lp))
- sound_free((struct smartear_entry*)lp->data, TRUE);
- if (sounds_list) {
- g_slist_free(sounds_list);
- sounds_list = 0;
- }
-}
-
-static gint sound_cmp(gconstpointer p1, gconstpointer p2)
-{
- struct smartear_entry *entry1 = (struct smartear_entry*)p1;
- struct smartear_entry *entry2 = (struct smartear_entry*)p2;
-
- if (!entry1 || IS_DEFAULT(entry1))
- return -1;
- if (!entry2 || IS_DEFAULT(entry2))
- return 1;
-
- /* only compare types if both are nonzero */
- if (entry1->type != entry2->type &&
- entry1->type != 0 && entry2->type != 0)
- return (entry1->type - entry2->type);
- return (g_strcasecmp(entry1->name, entry2->name));
-}
-
-static void populate_edit_win(struct smartear_entry *entry)
-{
- gtk_entry_set_text(GTK_ENTRY(EFIND("name_entry")), entry->name);
- gtk_entry_set_text(GTK_ENTRY(EFIND("im_sound_entry")),
- entry->sound[EVENT_M]);
- gtk_entry_set_text(GTK_ENTRY(EFIND("signon_sound_entry")),
- entry->sound[EVENT_S]);
- gtk_entry_set_text(GTK_ENTRY(EFIND("unidle_sound_entry")),
- entry->sound[EVENT_I]);
- gtk_entry_set_text(GTK_ENTRY(EFIND("unaway_sound_entry")),
- entry->sound[EVENT_A]);
- gtk_option_menu_set_history(GTK_OPTION_MENU(EFIND("type_option")),
- (entry->type == 'B' ? 0 : 1));
-
- if (IS_DEFAULT(entry)) {
- gtk_widget_set_sensitive(EFIND("name_entry"), FALSE);
- gtk_widget_set_sensitive(EFIND("type_menu"), FALSE);
- }
-
- if (config) {
- gtk_widget_set_sensitive(GTK_WIDGET(treeview), FALSE);
- }
-}
-
-static void set_option_entries(void)
-{
- GtkSpinButton *delay_spin = GTK_SPIN_BUTTON(FIND("delay_spin"));
- GtkToggleButton *focus_but = GTK_TOGGLE_BUTTON(FIND("focus_but"));
- GtkToggleButton *timer_but = GTK_TOGGLE_BUTTON(FIND("timer_but"));
-
- g_signal_handlers_block_by_func(G_OBJECT(delay_spin), on_delay_changed, 0);
- g_signal_handlers_block_by_func(G_OBJECT(focus_but), on_focus_toggled, 0);
- g_signal_handlers_block_by_func(G_OBJECT(timer_but), on_timer_toggled, 0);
-
- gtk_spin_button_set_value(delay_spin, (gdouble)message_delay);
- gtk_toggle_button_set_active(focus_but, focused_quiet);
- gtk_toggle_button_set_active(timer_but, smartear_timers);
+#include "../common/pp_internal.h"
- g_signal_handlers_unblock_by_func(G_OBJECT(delay_spin), on_delay_changed, 0);
- g_signal_handlers_unblock_by_func(G_OBJECT(focus_but), on_focus_toggled, 0);
- g_signal_handlers_unblock_by_func(G_OBJECT(timer_but), on_timer_toggled, 0);
-}
-
-static void update_list(void)
-{
- if (selected_entry)
- list_set(GTK_LIST_STORE(treemodel), &selected_iter, selected_entry);
-}
-
-static gchar* get_basename(gchar *path)
-{
- static gchar base[BUF_LEN];
- gchar *p;
-
- if (!path || !path[0]) {
- return "";
- }
-
- if ((p = strrchr(path, '/'))) {
- p++;
- }
- else {
- p = path;
- }
-
- strncpy(base, p, sizeof(base));
-
- return base;
-}
-
-/*** Init Functions ***/
-
-static void populate_list(GtkListStore *store)
-{
- GtkTreeIter iter;
- GSList *lp;
-
- sounds_list = g_slist_sort(sounds_list, (GCompareFunc)sound_cmp);
-
- for (lp = sounds_list; lp; lp = g_slist_next(lp)) {
- struct smartear_entry *entry = (struct smartear_entry*)lp->data;
- gtk_list_store_append(store, &iter);
- list_set(store, &iter, entry);
- if (entry == selected_entry)
- selected_iter = iter;
- }
-}
-
-static void render_type(GtkTreeViewColumn *column, GtkCellRenderer *cell,
- GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
-{
- struct smartear_entry *entry;
- gtk_tree_model_get(model, iter, DATA_COL, &entry, -1);
- if (IS_DEFAULT(entry))
- g_object_set(cell, "text", "", NULL);
- else
- g_object_set(cell, "text", entry->type == 'B' ? "Buddy" : "Group", NULL);
-}
-
-static void render_name(GtkTreeViewColumn *column, GtkCellRenderer *cell,
- GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
-{
- struct smartear_entry *entry;
- gtk_tree_model_get(model, iter, DATA_COL, &entry, -1);
- g_object_set(cell, "text", entry->name, NULL);
-}
-
-static void render_when(GtkTreeViewColumn *column, GtkCellRenderer *cell,
- GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
-{
- struct smartear_entry *entry;
- gint which = GPOINTER_TO_INT(data);
- gtk_tree_model_get(model, iter, DATA_COL, &entry, -1);
- g_object_set(cell, "text", get_basename(entry->sound[which]), NULL);
-}
-
-static gint list_cmp(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer d)
-{
- struct smartear_entry *entry1, *entry2;
-
- gtk_tree_model_get(model, a, DATA_COL, &entry1, -1);
- gtk_tree_model_get(model, b, DATA_COL, &entry2, -1);
-
- return sound_cmp(entry1, entry2);
-}
-
-static void setup_list(void)
-{
- GtkListStore *store;
- GtkCellRenderer *cell;
-
- treeview = GTK_TREE_VIEW(FIND("treeview"));
-
- store = gtk_list_store_new(1, G_TYPE_POINTER);
- populate_list(store);
-
- gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(store));
- g_object_unref(G_OBJECT(store)); // treeview has it's own copy.
- treemodel = gtk_tree_view_get_model(treeview);
- gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(treemodel),
- (GtkTreeIterCompareFunc)&list_cmp, 0, 0);
- gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(treemodel),
- GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
-
- treeselect = gtk_tree_view_get_selection(treeview);
- gtk_tree_selection_set_mode(treeselect, GTK_SELECTION_SINGLE);
- g_signal_connect(G_OBJECT(treeselect), "changed",
- G_CALLBACK(on_treeselect_changed), NULL);
-
- /* Type column */
- cell = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_data_func(treeview, -1, "Type",
- cell, render_type, 0, 0);
-
- /* Name column */
- cell = gtk_cell_renderer_text_new();
- g_signal_connect(G_OBJECT(cell), "edited",
- G_CALLBACK(on_cell_edited), GINT_TO_POINTER(NAME_COL));
- g_object_set(G_OBJECT(cell), "editable", TRUE, NULL);
- gtk_tree_view_insert_column_with_data_func(treeview, -1, "Name",
- cell, render_name, 0, 0);
-
- cell = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Message",
- cell, render_when, GINT_TO_POINTER(EVENT_M), 0);
-
- cell = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Signon",
- cell, render_when, GINT_TO_POINTER(EVENT_S), 0);
-
- cell = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Unidle",
- cell, render_when, GINT_TO_POINTER(EVENT_I), 0);
-
- cell = gtk_cell_renderer_text_new();
- gtk_tree_view_insert_column_with_data_func(treeview, -1, "On Unaway",
- cell, render_when, GINT_TO_POINTER(EVENT_A), 0);
-}
-
-static void smartear_save(void)
-{
- char file[BUF_LEN] = "smartear.rc - you have no home dir";
- FILE *fp = NULL;
- GSList *lp;
- struct smartear_entry *entry;
-
- if (purple_user_dir()) {
- g_snprintf(file, sizeof(file), "%s/smartear.rc", purple_user_dir());
- fp = fopen(file, "w");
- }
-
- if (fp == NULL) {
- g_warning("couldn't open %s\n", file);
- return;
- }
-
- fprintf(fp, "version %d\n", RCFILE_VERSION);
- fprintf(fp, "smartear_timers %d\n", smartear_timers);
- fprintf(fp, "delay %d\n", message_delay);
- fprintf(fp, "focused_quiet %d\n", focused_quiet);
-
- /* save empties as a single space so scanf doesn't get confused */
-#define SAVE_STR(str) (IS_EMPTY(str) ? RC_EMPTY_SOUND : str)
- for (lp = sounds_list; lp; lp = g_slist_next(lp)) {
- entry = (struct smartear_entry*)lp->data;
- fprintf(fp, "%c {%s} {%s} {%s} {%s} {%s}\n",
- entry->type, entry->name,
- SAVE_STR(entry->sound[EVENT_M]),
- SAVE_STR(entry->sound[EVENT_S]),
- SAVE_STR(entry->sound[EVENT_I]),
- SAVE_STR(entry->sound[EVENT_A]));
- }
-
- fclose(fp);
-}
-
-static void smartear_load(void)
-{
- char file[BUF_LEN] = "smartear.rc - you have no home dir";
- FILE *fp = NULL;
- struct smartear_entry *entry;
- char buf[BUF_LEN];
- gboolean has_default = FALSE;
- int rcfile_version = 1;
-
- if (purple_user_dir()) {
- g_snprintf(file, sizeof(file), "%s/smartear.rc", purple_user_dir());
- fp = fopen(file, "r");
- }
-
- if (fp == NULL) {
- g_warning("smartear: couldn't open %s\n", file);
- sounds_list = g_slist_append(sounds_list, sound_dup(&default_entry));
- return;
- }
-
- while ((fgets(buf, sizeof(buf), fp))) {
- int tmp;
- if (sscanf(buf, "version %d", &tmp) == 1)
- rcfile_version = tmp;
- else if (sscanf(buf, "smarterear_timers %d", &tmp) == 1)
- smartear_timers = tmp;
- else if (sscanf(buf, "smartear_timers %d", &tmp) == 1)
- smartear_timers = tmp;
- else if (sscanf(buf, "delay %d", &tmp) == 1)
- message_delay = tmp;
- else if (sscanf(buf, "focused_quiet %d", &tmp) == 1)
- focused_quiet = tmp;
- else if (rcfile_version == 1) {
- char name[BUF_LEN];
- char flags[BUF_LEN];
- char sound[BUF_LEN];
- char type;
-
- if (sscanf(buf, "%c {%[^}]} {%[^}]} {%[^}]}",
- &type, name, flags, sound) == 4) {
- if (type != 'G' && type != 'B') {
- g_warning("smartear: rc no such type: %c", type);
- continue;
- }
-
- entry = g_new(struct smartear_entry, 1);
- entry->type = type;
- entry->name = g_strdup(my_normalize(name));
- if (strchr(flags, 'M')) entry->sound[EVENT_M] = g_strdup(sound);
- else entry->sound[EVENT_M] = g_strdup("");
- if (strchr(flags, 'S')) entry->sound[EVENT_S] = g_strdup(sound);
- else entry->sound[EVENT_S] = g_strdup("");
- if (strchr(flags, 'I')) entry->sound[EVENT_I] = g_strdup(sound);
- else entry->sound[EVENT_I] = g_strdup("");
- if (strchr(flags, 'A')) entry->sound[EVENT_A] = g_strdup(sound);
- else entry->sound[EVENT_A] = g_strdup("");
-
- sounds_list = g_slist_append(sounds_list, entry);
-
- if (IS_DEFAULT(entry)) {
- default_entry = *entry;
- has_default = TRUE;
- }
- }
- else
- g_warning("smartear: rc1 syntax error: %s", buf);
- }
- else if (rcfile_version == 2) {
- char name[BUF_LEN];
- char sound[EVENT_NUM][BUF_LEN];
- char type;
- int i;
-
- if (sscanf(buf, "%c {%[^}]} {%[^}]} {%[^}]} {%[^}]} {%[^}]}",
- &type, name, sound[EVENT_M], sound[EVENT_S],
- sound[EVENT_I], sound[EVENT_A]) == 6) {
- if (type != 'G' && type != 'B') {
- g_warning("smartear: rc no such type: %c", type);
- continue;
- }
-
- for (i = 0; i < EVENT_NUM; i++) {
- if (strcmp(sound[i], RC_EMPTY_SOUND) == 0)
- sound[i][0] = 0;
- }
-
- entry = g_new(struct smartear_entry, 1);
- entry->type = type;
- entry->name = g_strdup(my_normalize(name));
- entry->sound[EVENT_M] = g_strdup(sound[EVENT_M]);
- entry->sound[EVENT_S] = g_strdup(sound[EVENT_S]);
- entry->sound[EVENT_I] = g_strdup(sound[EVENT_I]);
- entry->sound[EVENT_A] = g_strdup(sound[EVENT_A]);
-
- sounds_list = g_slist_append(sounds_list, entry);
-
- if (IS_DEFAULT(entry)) {
- default_entry = *entry;
- has_default = TRUE;
- }
- }
- else
- g_warning("smartear: rc2 syntax error: %s", buf);
- }
- else
- g_warning("smartear: rc syntax error: %s", buf);
- }
- if (!has_default)
- sounds_list = g_slist_append(sounds_list, sound_dup(&default_entry));
-
- fclose(fp);
-}
-
-/*** Purple callbacks ***/
-
-static struct message_data *find_message_by_name(PurpleAccount *account, const char *pname)
-{
- GSList *lp;
- struct message_data *msg = NULL;
- char *name = g_strdup(my_normalize(pname));
+/* libpurple headers */
+#include <blist.h>
+#include <debug.h>
+#include <plugin.h>
+#include <pluginpref.h>
+#include <sound.h>
+#include <version.h>
- for (lp = messages_list; lp; lp = g_slist_next(lp)) {
- msg = (struct message_data*)lp->data;
- if (msg->account == account
- && g_strcasecmp(msg->buddy, name) == 0)
- break;
- }
-
- g_free(name);
-
- if (lp)
- return msg;
- return 0;
-}
-
-static void message_timer_remove(struct message_data *msg)
-{
- if (msg && msg->timer) {
- g_source_remove(msg->timer->id);
- g_free(msg->timer);
- msg->timer = NULL;
- }
-}
-
-static void message_free(struct message_data *msg)
-{
- message_timer_remove(msg);
- g_free(msg->buddy);
- g_free(msg);
-}
-
-static void messagelist_free()
-{
- GSList *lp;
- for (lp = messages_list; lp; lp = g_slist_next(lp))
- message_free((struct message_data*)lp->data);
- if (messages_list) {
- g_slist_free(messages_list);
- messages_list = NULL;
- }
-}
-
-static void on_smartear_clicked(PurpleBlistNode* node, gpointer data)
+static gboolean
+smartear_load(PurplePlugin *plugin)
{
- struct smartear_entry tmp, *entry;
- GSList *lp;
-
- clear_selection();
-
- if (!edit_win) {
- edit_win = create_edit_win();
- }
- gtk_widget_show_all(edit_win);
-
- tmp = default_entry;
-
- if (!node) {
- return;
- }
- else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- tmp.type = 'B';
- tmp.name = ((PurpleBuddy*)node)->name;
- purple_debug(PURPLE_DEBUG_INFO, "smartear", "adding buddy %s", tmp.name);
- }
- else if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
- tmp.type = 'B';
- tmp.name = ((PurpleContact*)node)->alias;
- if (!tmp.name) {
- tmp.name = ((PurpleContact*)node)->priority->name;
- }
- purple_debug(PURPLE_DEBUG_INFO, "smartear", "adding contact %s", tmp.name);
- }
- else if (PURPLE_BLIST_NODE_IS_GROUP(node)) {
- tmp.type = 'G';
- tmp.name = ((PurpleGroup*)node)->name;
- g_warning("group %p, %p %s", node, tmp.name, tmp.name);
- purple_debug(PURPLE_DEBUG_INFO, "smartear", "adding group %s", tmp.name);
- }
- else {
- return;
- }
-
- if ((lp = g_slist_find_custom(sounds_list, &tmp, (GCompareFunc)sound_cmp))) {
- entry = (struct smartear_entry*)lp->data;
- }
- else {
- entry = &tmp;
- }
-
- populate_edit_win(entry);
-}
-
-static void play_sound_alias(char *sound, PurpleAccount* account)
-{
- struct smartear_entry tmp, *entry;
- GSList *lp;
-
- if (!sound || !*sound)
- return;
-
- /* sound aliases: mostly so you can put (Default) for sound, and it'll
- * play that one */
- tmp.type = 0;
- tmp.name = sound;
- if ((lp = g_slist_find_custom(sounds_list, &tmp, (GCompareFunc)sound_cmp))) {
- entry = (struct smartear_entry*)lp->data;
- play_sound_alias(entry->sound[EVENT_M], account);
- }
- else {
- purple_sound_play_file(sound, account);
- }
-}
-
-void play_matching_sound(PurpleBuddy *buddy, int event)
-{
- GSList *lp;
- struct smartear_entry *entry;
- char *sound = NULL;
- char *name = buddy ? g_strdup(my_normalize(buddy->name)) : NULL;
- PurpleGroup *g = buddy ? purple_buddy_get_group(buddy) : NULL;
-
- for (lp = sounds_list; lp; lp = g_slist_next(lp)) {
- entry = (struct smartear_entry*)lp->data;
- if (!entry->sound[event])
- continue;
+ /* TODO: make this unset all the pidgin/finch sound prefs */
- if (entry->type == 'B' && name
- && g_strcasecmp(name, entry->name) == 0) {
- sound = entry->sound[event];
- /* found a buddy match.. this takes precedence, so stop */
- break;
- }
- if (entry->type == 'G' && g
- && g_strcasecmp(my_normalize(g->name), entry->name) == 0) {
- sound = entry->sound[event];
- /* keep going... buddy overrides group */
- }
- if (IS_DEFAULT(entry)) {
- if (!sound)
- sound = entry->sound[event];
- /* keep going.. other 2 override default */
- }
- }
- if (!IS_EMPTY(sound)) {
- purple_debug(PURPLE_DEBUG_INFO, "smartear",
- "found %s for %s on event %d\n", sound, name, event);
- play_sound_alias(sound, purple_buddy_get_account(buddy));
- }
- else {
- purple_debug(PURPLE_DEBUG_INFO, "smartear",
- "no sound found for %s on event %d\n", name, event);
- }
- g_free(name);
-}
-
-static gint play_sound_timer_hook(gpointer data)
-{
- struct message_data *msg = (struct message_data *)data;
-
- if(!msg || !msg->timer) {
- g_warning("smartear: timer called without being active!\n");
- return FALSE;
- }
-
- play_matching_sound(purple_find_buddy(msg->account, msg->buddy), msg->timer->event);
-
- g_free(msg->timer);
- msg->timer = NULL;
-
- return FALSE;
-}
-
-static gboolean on_im_recv(PurpleAccount *account, char *who, char *what, gint32 flags, void *junk)
-{
- struct message_data *msg;
- time_t now = time(0);
- PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY, who, account);
- PidginConversation *gtkconv = conv ? PIDGIN_CONVERSATION(conv) : NULL;
-
- /* FIXME: message list is never trimmed. However, if we DO trim it,
- * we need to consider race conditions on the msg field of the timer_hook */
-
- if ((msg = find_message_by_name(account, who))) {
- /* only install a timer if there's no active timers and we've just
- * sent a message. If we haven't just sent a message, then
- * a beep will go off anyways when the IM arrives. */
- if(smartear_timers && !msg->timer
- && msg->last_sent + message_delay > now) {
- msg->timer = g_new0(struct timer_data, 1);
- msg->timer->event = EVENT_M;
- msg->timer->id = g_timeout_add(message_delay*1000,
- play_sound_timer_hook, msg);
- }
-
- if (msg->last_active + message_delay > now && conv) {
- purple_debug(PURPLE_DEBUG_INFO, "smartear",
- "received IM from %s, but only %d/%d seconds passed.\n",
- who, now - msg->last_active, message_delay);
- return FALSE;
- }
- }
- else {
- msg = g_new0(struct message_data, 1);
- msg->account = account;
- msg->buddy = g_strdup(my_normalize(who));
- msg->timer = NULL;
-
- messages_list = g_slist_append(messages_list, msg);
- }
-
- msg->last_active = now;
-
- if (focused_quiet && gtkconv && GTK_WIDGET_HAS_FOCUS(gtkconv->entry))
- return FALSE; /* don't play sounds for the focused convo */
- if (gtkconv && !gtkconv->make_sound)
- return FALSE;
-
- play_matching_sound(purple_find_buddy(msg->account, msg->buddy), EVENT_M);
-
- return FALSE;
-}
-
-static void on_im_send(PurpleAccount *account, char *who, char *what, void *junk)
-{
- struct message_data *msg;
- time_t now = time(0);
-
- if ((msg = find_message_by_name(account, who))) {
- message_timer_remove(msg);
- }
- else {
- msg = g_new0(struct message_data, 1);
- msg->account = account;
- msg->buddy = g_strdup(my_normalize(who));
- msg->timer = NULL;
-
- messages_list = g_slist_append(messages_list, msg);
- }
-
- msg->last_active = now;
- msg->last_sent = now;
-}
-
-static void on_buddy_signon(PurpleBuddy *buddy, void *data)
-{
- play_matching_sound(buddy, EVENT_S);
-}
-
-static void on_buddy_back(PurpleBuddy *buddy, void *data)
-{
- play_matching_sound(buddy, EVENT_A);
-}
-
-static void on_buddy_unidle(PurpleBuddy *buddy, void *data)
-{
- play_matching_sound(buddy, EVENT_I);
-}
-
-static void on_signon(PurpleConnection *gc, void *m)
-{
-}
-
-static void on_signoff(PurpleConnection *gc, void *m)
-{
- messagelist_free();
-}
-
-static void on_blist_node_extended_menu(PurpleBlistNode *node, GList **menu)
-{
- PurpleMenuAction *menu_action;
- menu_action = purple_menu_action_new(_("Edit SmartEar Entry"),
- PURPLE_CALLBACK(on_smartear_clicked), NULL, NULL);
- *menu = g_list_append(*menu, menu_action);
-}
-
-static gboolean purple_plugin_init(PurplePlugin *plugin)
-{
- void *blist_handle = purple_blist_get_handle();
- void *conv_handle = purple_conversations_get_handle();
-
- config = NULL;
-
- smartear_load();
-
- purple_signal_connect(blist_handle, "blist-node-extended-menu",
- plugin, PURPLE_CALLBACK(on_blist_node_extended_menu), NULL);
-
- purple_signal_connect(blist_handle, "buddy-signed-on",
- plugin, PURPLE_CALLBACK(on_buddy_signon), NULL);
- purple_signal_connect(blist_handle, "buddy-back",
- plugin, PURPLE_CALLBACK(on_buddy_back), NULL);
- purple_signal_connect(blist_handle, "buddy-unidle",
- plugin, PURPLE_CALLBACK(on_buddy_unidle), NULL);
-
- purple_signal_connect(conv_handle, "received-im-msg",
- plugin, PURPLE_CALLBACK(on_im_recv), NULL);
- purple_signal_connect(conv_handle, "sent-im-msg",
- plugin, PURPLE_CALLBACK(on_im_send), NULL);
-
- purple_signal_connect(purple_connections_get_handle(), "signed-on",
- plugin, PURPLE_CALLBACK(on_signon), NULL);
- purple_signal_connect(purple_connections_get_handle(), "signed-off",
- plugin, PURPLE_CALLBACK(on_signoff), NULL);
+ /* XXX: do we want to "migrate" the pidgin/finch sound prefs by making them
+ * the default for each group if they're turned on? */
return TRUE;
}
-static gboolean purple_plugin_remove(PurplePlugin *h)
+static gboolean
+smartear_unload(PurplePlugin *plugin)
{
- config = NULL;
-
- soundlist_free();
- messagelist_free();
+ /* XXX: since we're going to unset all the pidgin and finch sound prefs,
+ * do we want to keep track of their values and restore them on unload? */
return TRUE;
}
-static GtkWidget *purple_plugin_config_gtk(PurplePlugin *plugin)
+PurplePluginInfo smartear_info =
{
- config = create_config();
-
- setup_list();
- set_option_entries();
-
- gtk_widget_show_all(config);
-
- return config;
+ PURPLE_PLUGIN_MAGIC, /* Magic, my ass */
+ PURPLE_MAJOR_VERSION, /* libpurple major version */
+ PURPLE_MINOR_VERSION, /* libpurple minor version */
+ PURPLE_PLUGIN_STANDARD, /* plugin type - this is a normal plugin */
+ NULL, /* UI requirement - we have none */
+ 0, /* flags - we have none */
+ NULL, /* dependencies - we have none */
+ PURPLE_PRIORITY_DEFAULT, /* priority - nothing special here */
+ "core-plugin_pack-smartear", /* Plugin ID */
+ NULL, /* name - defined later for i18n */
+ PP_VERSION, /* plugin version - use plugin pack version */
+ NULL, /* summary - defined later for i18n */
+ NULL, /* description - defined later for i18n */
+ "John Bailey <rekkanoryo@rekkanoryo.org>", /* author */
+ PP_WEBSITE, /* plugin website - use plugin pack website */
+ gtksmartear_load, /* plugin load - purple calls this when loading */
+ gtksmartear_unload, /* plugin unload - purple calls this when unloading */
+ NULL, /* plugin destroy - we don't need one */
+ NULL, /* ui_info - we don't need this */
+ NULL, /* extra_info - we don't need this */
+ NULL, /* prefs_info - we don't need this yet */
+ NULL, /* actions - we don't have any */
+ NULL, /* reserved 1 */
+ NULL, /* reserved 2 */
+ NULL, /* reserved 3 */
+ NULL /* reserved 4 */
}
-static PurplePluginUiInfo ui_info = {
- purple_plugin_config_gtk,
- 0 /* page_num (reserved) */
-};
-
-static PurplePluginInfo info =
-{
- PURPLE_PLUGIN_MAGIC,
- PURPLE_MAJOR_VERSION,
- PURPLE_MINOR_VERSION,
- PURPLE_PLUGIN_STANDARD,
- PIDGIN_PLUGIN_TYPE,
- 0,
- NULL,
- PURPLE_PRIORITY_DEFAULT,
- SMARTEAR_PLUGIN_ID,
- NULL,
- PP_VERSION,
- NULL,
- NULL,
- "Matt Perry <guy@fscked.org>",
- PP_WEBSITE,
- purple_plugin_init,
- purple_plugin_remove,
- NULL,
- &ui_info,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-static void init_plugin(PurplePlugin *plugin)
+static void
+smartear_init(PurplePlugin *plugin)
{
#ifdef ENABLE_NLS
bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR);
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
#endif
- info.name= _("Smart Ear");
- info.summary = _("Assign different sounds to different buddies and groups");
- info.description =
- _("Allows you to assign different sounds to play for different buddies "
- "or whole groups of buddies. Smart Ear allows you to opt to play "
- "sounds when a buddy sends you an IM, signs on, returns from away "
- "or idle, or any combination of these, so you'll know by the sound "
- "what the important people are doing.");
+ info.name = _("Smart Ear");
+ info.summary = _("Assign sounds on a per-buddy or per-group basis");
+ info.description = _("Smart Ear allows you to assign sounds on a per-buddy or "
+ "per-group basis. You can configure sounds for sign on, sign off, IM, "
+ "and status change events. Using these features, you can know by the "
+ "sounds Pidgin emits which person on your buddy list is doing what.");
}
-PURPLE_INIT_PLUGIN(smartear, init_plugin, info);
+PURPLE_INIT_PLUGIN(smartear, smartear_init, smartear_info)