Mercurial > pidgin.yaz
view plugins/crazychat/cc_gaim_plugin.c @ 13962:b43aec5fa9eb
[gaim-migrate @ 16515]
Fix a tiny and rare memleak when unloading a plugin that was
designed for an older version of Gaim.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Tue, 18 Jul 2006 06:33:36 +0000 |
parents | f09c6e8df82c |
children |
line wrap: on
line source
#include <stdio.h> #include <assert.h> #include "internal.h" #include "plugin.h" #include "gtkplugin.h" #include "gtkblist.h" #include "gtkutils.h" #include "connection.h" #include "conversation.h" #include "network.h" #include <gtk/gtkgl.h> #include <GL/gl.h> #include <GL/glu.h> #include "crazychat.h" #include "cc_network.h" #include "cc_interface.h" #include "cc_gtk_gl.h" #include "util.h" /* --- begin type and global variable definitions --- */ static struct crazychat cc_info; /* --- begin function declarations --- */ /** * Called by gaim plugin to start CrazyChat * @param cc the crazychat struct */ static void cc_init(struct crazychat *cc); /** * Called by gaim plugin to destroy CrazyChat * @param cc the crazychat struct */ static void cc_destroy(struct crazychat *cc); /** * Buddy menu drawing callback. Adds a CrazyChat menuitem. * @param menu the buddy menu widget * @param b the buddy whose menu this is */ static gboolean cc_buddy_menu(GtkWidget *menu, GaimBuddy *b); /** * Buddy menu callback. Initiates the CrazyChat session. * @param item the gtk buddy menu item * @param b the buddy whose menu the item was in */ static void cc_menu_cb(GtkMenuItem *item, GaimBuddy *b); /** * IM callback. Handles receiving a CrazyChat session request. * @param account the account we received the IM on * @param sender the buddy who we received the message from * @param message the message we received * @param flags IM flags * @param data user data */ static gboolean receive_im_cb(GaimAccount *account, char **sender, char **message, int *flags, void *data); /** * Displaying IM callback. Drops CrazyChat messages from IM window. * @param account the account we are displaying the IM on * @param conv the conversation we are displaying the IM on * @param message the message we are displaying * @param data user data */ static gboolean display_im_cb(GaimAccount *account, const char *who, char **message, GaimConnection *conv, GaimMessageFlags flags, void *data); /** * Callback for CrazyChat plugin configuration frame * @param plugin the plugin data * @return the configuration frame */ static GtkWidget *get_config_frame(GaimPlugin *plugin); /** * TCP port callback. Changes the port used to listen for new CC sessions * @param spin the spinner button whose value changed * @param data user data */ static void tcp_port_cb(GtkSpinButton *spin, struct crazychat *cc); /** * UDP port callback. Changes the port used to send/recv CC session frames * @param spin the spinner button whose value changed * @param data user data */ static void udp_port_cb(GtkSpinButton *spin, struct crazychat *cc); /** * Features enabling/disabling callback. Initializes the input processing * or shuts it down. * @param data user data */ static void features_enable_cb(struct crazychat *cc); /** * User signed on callback. Now we have a buddy list to connect a signal * handler to. * @param gc the gaim connection we are signed on * @param plugin our plugin struct */ static gboolean cc_signed_on(GaimConnection *gc, void *plugin); /** * Plugin loading callback. If a buddy list exists, connect our buddy menu * drawing callback to the signal handler, otherwise, connect a signed on * signal handler so we know when we get a buddy list. * @param plugin our plugin struct */ static gboolean plugin_load(GaimPlugin *plugin); /** * Plugin unloading callback. Disconnect all handlers and free data. * @param plugin our plugin struct */ static gboolean plugin_unload(GaimPlugin *plugin); /* --- end function declarations --- */ #define CRAZYCHAT_PLUGIN_ID "gtk-crazychat" static GaimGtkPluginUiInfo ui_info = { get_config_frame /**< get_config_frame */ }; static GaimPluginInfo info = { 2, /**< api_version */ GAIM_PLUGIN_STANDARD, /**< type */ GAIM_GTK_PLUGIN_TYPE, /**< ui_requirement */ 0, /**< flags */ NULL, /**< dependencies */ GAIM_PRIORITY_DEFAULT, /**< priority */ CRAZYCHAT_PLUGIN_ID, /**< id */ N_("Crazychat"), /**< name */ VERSION, /**< version */ /** summary */ N_("Plugin to establish a Crazychat session."), /** description */ N_("Uses Gaim to obtain buddy ips to connect for a Crazychat session"), "\n" "William Chan <chanman@stanford.edu>\n" "Ian Spiro <ispiro@stanford.edu>\n" "Charlie Stockman<stockman@stanford.edu>\n" "Steve Yelderman<scy@stanford.edu>", /**< author */ GAIM_WEBSITE, /**< homepage */ plugin_load, /**< load */ plugin_unload, /**< unload */ NULL, /**< destroy */ &ui_info, /**< ui_info */ &cc_info /**< extra_info */ }; /* --- end plugin struct definition --- */ static void cc_init(struct crazychat *cc) { /* initialize main crazychat thread */ assert(cc); memset(cc, 0, sizeof(*cc)); /* initialize network configuration */ cc->tcp_port = DEFAULT_CC_PORT; cc->udp_port = DEFAULT_CC_PORT; /* disable input subsystem */ //cc->features_state = 0; /* initialize input subsystem */ cc->features_state = 1; cc->input_data = init_input(cc); } static void cc_destroy(struct crazychat *cc) { assert(cc); if (cc->features_state) { destroy_input(cc->input_data); } memset(cc, 0, sizeof(*cc)); } static gboolean cc_buddy_menu(GtkWidget *menu, GaimBuddy *b) { GtkWidget *menuitem; menuitem = gtk_menu_item_new_with_mnemonic("CrazyChat"); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(cc_menu_cb), b); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); return FALSE; } static void cc_menu_cb(GtkMenuItem *item, GaimBuddy *b) { assert(item); assert(b); /* send the invite */ cc_net_send_invite(&cc_info, b->name, b->account); } static gboolean receive_im_cb(GaimAccount *account, char **sender, char **message, int *flags, void *data) { struct crazychat *cc; cc = (struct crazychat*)data; assert(cc); if (!strncmp(*message, CRAZYCHAT_INVITE_CODE, strlen(CRAZYCHAT_INVITE_CODE))) { Debug(*message); char *split = strchr(*message, '!'); assert(split); *split = 0; split++; cc_net_recv_invite(account, cc, *sender, &(*message)[strlen(CRAZYCHAT_INVITE_CODE)], split); return TRUE; } else if (!strncmp(*message, CRAZYCHAT_ACCEPT_CODE, strlen(CRAZYCHAT_ACCEPT_CODE))) { cc_net_recv_accept(account, cc, *sender, &(*message)[strlen(CRAZYCHAT_ACCEPT_CODE)]); return TRUE; } else if (!strncmp(*message, CRAZYCHAT_READY_CODE, strlen(CRAZYCHAT_READY_CODE))) { cc_net_recv_ready(account, cc, *sender); return TRUE; } return FALSE; } static gboolean display_im_cb(GaimAccount *account, GaimConversation *conv, char **message, void *data) { struct crazychat *cc; cc = (struct crazychat*)data; assert(cc); if (!strncmp(*message, CRAZYCHAT_INVITE_CODE, strlen(CRAZYCHAT_INVITE_CODE))) { return TRUE; } else if (!strncmp(*message, CRAZYCHAT_ACCEPT_CODE, strlen(CRAZYCHAT_ACCEPT_CODE))) { return TRUE; } else if (!strncmp(*message, CRAZYCHAT_READY_CODE, strlen(CRAZYCHAT_READY_CODE))) { return TRUE; } return FALSE; } static GtkWidget *get_config_frame(GaimPlugin *plugin) { GtkWidget *ret; GtkWidget *frame; GtkWidget *vbox, *hbox; GtkWidget *drawing_area; GtkWidget *label; GtkAdjustment *adj; GtkWidget *spinner; GtkWidget *button, *button1, *button2; GSList *group; struct draw_info *info; struct crazychat *cc; cc = (struct crazychat*)plugin->info->extra_info; assert(cc); /* create widgets */ /* creating the config frame */ ret = gtk_vbox_new(FALSE, 18); gtk_container_set_border_width(GTK_CONTAINER(ret), 12); /* make the network configuration frame */ frame = gaim_gtk_make_frame(ret, _("Network Configuration")); gtk_widget_show(frame); /* add boxes for packing purposes */ vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(frame), vbox, TRUE, TRUE, 0); gtk_widget_show(vbox); /* add widgets to row 1 */ hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); gtk_widget_show(hbox); label = gtk_label_new(_("TCP port")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); gtk_widget_show(label); adj = (GtkAdjustment*)gtk_adjustment_new(DEFAULT_CC_PORT, 1, G_MAXUSHORT, 1, 1000, 0); spinner = gtk_spin_button_new(adj, 1, 0); g_signal_connect(G_OBJECT(spinner), "value_changed", G_CALLBACK(tcp_port_cb), cc); gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0); gtk_widget_show(spinner); label = gtk_label_new(_("UDP port")); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 15); gtk_widget_show(label); adj = (GtkAdjustment*)gtk_adjustment_new(DEFAULT_CC_PORT, 1, G_MAXUSHORT, 1, 1000, 0); spinner = gtk_spin_button_new(adj, 1, 0); g_signal_connect(G_OBJECT(spinner), "value_changed", G_CALLBACK(udp_port_cb), cc); gtk_box_pack_start(GTK_BOX(hbox), spinner, FALSE, FALSE, 0); gtk_widget_show(spinner); /* make the feature configuration frame */ frame = gaim_gtk_make_frame(ret, _("Feature Calibration")); gtk_widget_show(frame); /* add hbox for packing purposes */ hbox = gtk_hbox_new(TRUE, 40); gtk_box_pack_start(GTK_BOX(frame), hbox, TRUE, TRUE, 0); gtk_widget_show(hbox); /* add feature calibration options */ /* add vbox for packing purposes */ vbox = gtk_vbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); gtk_widget_show(vbox); /* add enabled / disabled */ button1 = gtk_radio_button_new_with_label(NULL, _("Enabled")); gtk_box_pack_start(GTK_BOX(vbox), button1, TRUE, TRUE, 0); gtk_widget_show(button1); group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(button1)); button2 = gtk_radio_button_new_with_label(group, _("Disabled")); gtk_box_pack_start(GTK_BOX(vbox), button2, TRUE, TRUE, 0); gtk_widget_show(button2); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button1), cc->features_state); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button2), !cc->features_state); g_signal_connect_swapped(G_OBJECT(button1), "toggled", G_CALLBACK(features_enable_cb), cc); /* add vbox for packing purposes */ vbox = gtk_vbox_new(TRUE, 0); gtk_box_pack_end(GTK_BOX(hbox), vbox, TRUE, TRUE, 0); gtk_widget_show(vbox); /* add calibrate button */ button = gtk_button_new_with_label("Calibrate"); gtk_box_pack_start(GTK_BOX(vbox), button, TRUE, FALSE, 0); gtk_widget_show(button); gtk_widget_show(ret); return ret; } static void tcp_port_cb(GtkSpinButton *spin, struct crazychat *cc) { assert(spin); assert(cc); cc->tcp_port = gtk_spin_button_get_value_as_int(spin); Debug("New tcp port: %d\n", cc->tcp_port); } static void udp_port_cb(GtkSpinButton *spin, struct crazychat *cc) { assert(spin); assert(cc); cc->udp_port = gtk_spin_button_get_value_as_int(spin); Debug("New udp port: %d\n", cc->udp_port); } static void features_enable_cb(struct crazychat *cc) { Debug("Changing features state\n"); cc->features_state = !cc->features_state; if (cc->features_state) { cc->input_data = init_input(cc); } else { if (cc->input_data) { gtk_widget_destroy(cc->input_data->widget); } } } static gboolean cc_signed_on(GaimConnection *gc, void *plugin) { struct crazychat *extra; void *conv_handle; assert(plugin); extra = (struct crazychat*)((GaimPlugin*)plugin)->info->extra_info; gaim_signal_disconnect (gaim_connections_get_handle(), "signed-on", plugin, GAIM_CALLBACK(cc_signed_on)); gaim_signal_connect(GAIM_GTK_BLIST (gaim_get_blist()), "drawing-menu", plugin, GAIM_CALLBACK(cc_buddy_menu), NULL); conv_handle = gaim_conversations_get_handle(); gaim_signal_connect(conv_handle, "received-im-msg", plugin, GAIM_CALLBACK(receive_im_cb), extra); gaim_signal_connect(conv_handle, "displaying-im-msg", plugin, GAIM_CALLBACK(display_im_cb), extra); return FALSE; } static gboolean plugin_load(GaimPlugin *plugin) { GaimBuddyList *buddy_list; void *conv_handle; if (cc_init_gtk_gl()) return FALSE; cc_init(&cc_info); buddy_list = gaim_get_blist(); if (buddy_list) { gaim_signal_connect(GAIM_GTK_BLIST (buddy_list), "drawing-menu", plugin, GAIM_CALLBACK(cc_buddy_menu), NULL); conv_handle = gaim_conversations_get_handle(); gaim_signal_connect(conv_handle, "received-im-msg", plugin, GAIM_CALLBACK(receive_im_cb), &cc_info); gaim_signal_connect(conv_handle, "displaying-im-msg", plugin, GAIM_CALLBACK(display_im_cb), &cc_info); } else { gaim_signal_connect (gaim_connections_get_handle(), "signed-on", plugin, GAIM_CALLBACK(cc_signed_on), plugin); } Debug("CrazyChat plugin loaded.\n"); return TRUE; } static gboolean plugin_unload(GaimPlugin *plugin) { void *conv_handle; struct crazychat *extra; assert(plugin); extra = (struct crazychat*) plugin->info->extra_info; cc_destroy(extra); conv_handle = gaim_conversations_get_handle(); gaim_signal_disconnect(GAIM_GTK_BLIST (gaim_get_blist()), "drawing-menu", plugin, GAIM_CALLBACK(cc_buddy_menu)); gaim_signal_disconnect(conv_handle, "received-im", plugin, GAIM_CALLBACK(receive_im_cb)); gaim_signal_disconnect(conv_handle, "displaying-im-msg", plugin, GAIM_CALLBACK(display_im_cb)); Debug("CrazyChat plugin unloaded.\n"); return TRUE; } static void init_plugin(GaimPlugin *plugin) { gtk_gl_init(NULL, NULL); memset(&cc_info, 0, sizeof(cc_info)); Debug("CrazyChat plugin initialized\n"); } GAIM_INIT_PLUGIN(crazychat, init_plugin, info)