comparison src/gtkblist.c @ 8986:8cf32769ba1b

[gaim-migrate @ 9761] " This patch adds a Plugin Actions menu item after the Account Actions menu. The Plugin Actions menu is populated from the added 'actions' slot in GaimPluginInfo. As a demonstration, the Idle Maker plugin has been converted to no longer require GTK code and the Preferences interface just to perform its actions. Instead, it uses a Plugin Action to spawn a Fields Request. There's also a minor fix for consistency in the menu building for buddy actions. The pre-existing method for instructing a menu list to display a separator was to insert a NULL rather than a proto_buddy_menu into the GList of actions. The code for the buddy menus was instead checking for a proto_buddy_menu with a '-' label. This has been fixed, and it now correctly uses NULL to indicate a separator." "Date: 2004-05-16 02:25 Sender: taliesein Logged In: YES user_id=77326 I need to add a callback to this patch to watch for loading/unloading of plugins (to determine when to rebuild the menu). Since the appropriate way to handle Plugin Actions is still mildly up for debate, I'm holding of on correcting the patch until I know for sure whether I should fix this patch, or scrap it and write a new one using a different method." "Date: 2004-05-18 12:26 Sender: taliesein Logged In: YES user_id=77326 I've completed changes to this patch to also add plugin load and unload signals (it looks like plugin.c actually had pre-signal callbacks in place, but they were never used or converted to signals) This patch now will correctly update the Plugin Action menu as plugins load and unload." I'm not entirely sure i like the ui of a plugins actions menu, but i think that having some way for plugins to add actions on an account is a good thing, and i'm not sure that every viable action fits under the accounts actions menu. we may want to merge the two (the existing accounts actions and this plugins actions), but both times it came up in #gaim no one seemed to want to comment, and on one commented to the gaim-devel post either. committer: Tailor Script <tailor@pidgin.im>
author Luke Schierer <lschiere@pidgin.im>
date Thu, 20 May 2004 05:11:44 +0000
parents 574393ccd705
children d494fd1bd90b
comparison
equal deleted inserted replaced
8985:8abc99ed5d93 8986:8cf32769ba1b
27 #include "debug.h" 27 #include "debug.h"
28 #include "multi.h" 28 #include "multi.h"
29 #include "notify.h" 29 #include "notify.h"
30 #include "prpl.h" 30 #include "prpl.h"
31 #include "prefs.h" 31 #include "prefs.h"
32 #include "plugin.h"
32 #include "request.h" 33 #include "request.h"
33 #include "signals.h" 34 #include "signals.h"
34 #include "sound.h" 35 #include "sound.h"
35 #include "stock.h" 36 #include "stock.h"
36 #include "util.h" 37 #include "util.h"
97 98
98 GList *entries; 99 GList *entries;
99 } GaimGtkJoinChatData; 100 } GaimGtkJoinChatData;
100 101
101 102
102 static GtkWidget *protomenu = NULL; 103 static GtkWidget *protomenu = NULL, *pluginmenu = NULL;
103 104
104 GSList *gaim_gtk_blist_sort_methods = NULL; 105 GSList *gaim_gtk_blist_sort_methods = NULL;
105 static struct gaim_gtk_blist_sort_method *current_sort_method = NULL; 106 static struct gaim_gtk_blist_sort_method *current_sort_method = NULL;
106 static GtkTreeIter sort_method_none(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur); 107 static GtkTreeIter sort_method_none(GaimBlistNode *node, GaimBuddyList *blist, GtkTreeIter groupiter, GtkTreeIter *cur);
107 108
1092 list = prpl_info->buddy_menu(b->account->gc, b->name); 1093 list = prpl_info->buddy_menu(b->account->gc, b->name);
1093 1094
1094 for(l = list; l; l = l->next) { 1095 for(l = list; l; l = l->next) {
1095 struct proto_buddy_menu *pbm = l->data; 1096 struct proto_buddy_menu *pbm = l->data;
1096 1097
1097 /* draw "-" titled menu items as a separator. Since the 1098 /* draw NULL menu items as a separator. Since the
1098 pbm is not being used in a callback, it needs to be 1099 pbm is not being used in a callback, it needs to be
1099 freed. Also, do some simple checking to prevent 1100 freed. Also, do some simple checking to prevent
1100 doubled-up separators */ 1101 doubled-up separators */
1101 if('-' == *pbm->label) { 1102 if(pbm == NULL) {
1102 if(! dup_separator) { 1103 if(! dup_separator) {
1103 gaim_separator(menu); 1104 gaim_separator(menu);
1104 dup_separator = TRUE; 1105 dup_separator = TRUE;
1105 } 1106 }
1106 g_free(pbm);
1107 continue; 1107 continue;
1108 } else { 1108 } else {
1109 dup_separator = FALSE; 1109 dup_separator = FALSE;
1110 } 1110 }
1111 1111
1122 plugins. */ 1122 plugins. */
1123 list = gaim_buddy_get_extended_menu(b); 1123 list = gaim_buddy_get_extended_menu(b);
1124 for(l = list; l; l = l->next) { 1124 for(l = list; l; l = l->next) {
1125 struct proto_buddy_menu *pbm = l->data; 1125 struct proto_buddy_menu *pbm = l->data;
1126 1126
1127 /* draw "-" titled menu items as a separator. see previous, 1127 /* draw NULL menu items as a separator. see previous,
1128 identical-looking code. */ 1128 identical-looking code. */
1129 if('-' == *pbm->label) { 1129 if(pbm == NULL) {
1130 if(! dup_separator) { 1130 if(! dup_separator) {
1131 gaim_separator(menu); 1131 gaim_separator(menu);
1132 dup_separator = TRUE; 1132 dup_separator = TRUE;
1133 } 1133 }
1134 g_free(pbm); 1134 g_free(pbm);
1211 1211
1212 list = gaim_group_get_extended_menu(g); 1212 list = gaim_group_get_extended_menu(g);
1213 for(l = list; l; l = l->next) { 1213 for(l = list; l; l = l->next) {
1214 struct proto_group_menu *pgm = l->data; 1214 struct proto_group_menu *pgm = l->data;
1215 1215
1216 /* draw "-" titled menu items as a separator. see previous, 1216 /* draw NULL menu items as a separator. see previous,
1217 identical-looking code. (in make_buddy_menu)*/ 1217 identical-looking code. (in make_buddy_menu)*/
1218 if(pgm == NULL) { 1218 if(pgm == NULL) {
1219 if(! dup_separator) { 1219 if(! dup_separator) {
1220 gaim_separator(menu); 1220 gaim_separator(menu);
1221 dup_separator = TRUE; 1221 dup_separator = TRUE;
2353 /* Tools */ 2353 /* Tools */
2354 { N_("/_Tools"), NULL, NULL, 0, "<Branch>" }, 2354 { N_("/_Tools"), NULL, NULL, 0, "<Branch>" },
2355 { N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" }, 2355 { N_("/Tools/_Away"), NULL, NULL, 0, "<Branch>" },
2356 { N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" }, 2356 { N_("/Tools/Buddy _Pounce"), NULL, NULL, 0, "<Branch>" },
2357 { N_("/Tools/Account Ac_tions"), NULL, NULL, 0, "<Branch>" }, 2357 { N_("/Tools/Account Ac_tions"), NULL, NULL, 0, "<Branch>" },
2358 { N_("/Tools/Pl_ugin Actions"), NULL, NULL, 0, "<Branch>" },
2358 { "/Tools/sep1", NULL, NULL, 0, "<Separator>" }, 2359 { "/Tools/sep1", NULL, NULL, 0, "<Separator>" },
2359 { N_("/Tools/A_ccounts"), "<CTL>A", gaim_gtk_accounts_window_show, 0, "<StockItem>", GAIM_STOCK_ACCOUNTS }, 2360 { N_("/Tools/A_ccounts"), "<CTL>A", gaim_gtk_accounts_window_show, 0, "<StockItem>", GAIM_STOCK_ACCOUNTS },
2360 { N_("/Tools/_File Transfers"), NULL, gaim_show_xfer_dialog, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER }, 2361 { N_("/Tools/_File Transfers"), NULL, gaim_show_xfer_dialog, 0, "<StockItem>", GAIM_STOCK_FILE_TRANSFER },
2361 { N_("/Tools/R_oom List"), NULL, gaim_gtk_roomlist_dialog_show, 0, NULL }, 2362 { N_("/Tools/R_oom List"), NULL, gaim_gtk_roomlist_dialog_show, 0, NULL },
2362 { N_("/Tools/Pr_eferences"), "<CTL>P", gaim_gtk_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES }, 2363 { N_("/Tools/Pr_eferences"), "<CTL>P", gaim_gtk_prefs_show, 0, "<StockItem>", GTK_STOCK_PREFERENCES },
2925 2926
2926 widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Privacy")); 2927 widget = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Privacy"));
2927 gtk_widget_set_sensitive(widget, gaim_gtk_privacy_is_showable()); 2928 gtk_widget_set_sensitive(widget, gaim_gtk_privacy_is_showable());
2928 } 2929 }
2929 2930
2931
2932 static void
2933 plugin_changed_cb(GaimPlugin *p, gpointer *data)
2934 {
2935 gaim_gtk_blist_update_plugin_actions();
2936 }
2937
2938
2930 /* this is called on all sorts of signals, and we have no reason to pass 2939 /* this is called on all sorts of signals, and we have no reason to pass
2931 * it anything, so it remains without arguments. If you need anything 2940 * it anything, so it remains without arguments. If you need anything
2932 * more specific, do as below, and create another callback that calls 2941 * more specific, do as below, and create another callback that calls
2933 * this */ 2942 * this */
2934 static void 2943 static void
3066 gtkblist->bpmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Buddy Pounce")); 3075 gtkblist->bpmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Buddy Pounce"));
3067 gaim_gtkpounce_menu_build(gtkblist->bpmenu); 3076 gaim_gtkpounce_menu_build(gtkblist->bpmenu);
3068 3077
3069 protomenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Account Actions")); 3078 protomenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Account Actions"));
3070 gaim_gtk_blist_update_protocol_actions(); 3079 gaim_gtk_blist_update_protocol_actions();
3080
3081 pluginmenu = gtk_item_factory_get_widget(gtkblist->ift, N_("/Tools/Plugin Actions"));
3082 gaim_gtk_blist_update_plugin_actions();
3071 /****************************** GtkTreeView **********************************/ 3083 /****************************** GtkTreeView **********************************/
3072 sw = gtk_scrolled_window_new(NULL,NULL); 3084 sw = gtk_scrolled_window_new(NULL,NULL);
3073 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN); 3085 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);
3074 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 3086 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
3075 3087
3280 gaim_signal_connect(gaim_connections_get_handle(), "signed-on", 3292 gaim_signal_connect(gaim_connections_get_handle(), "signed-on",
3281 gtkblist, GAIM_CALLBACK(sign_on_off_cb), list); 3293 gtkblist, GAIM_CALLBACK(sign_on_off_cb), list);
3282 gaim_signal_connect(gaim_connections_get_handle(), "signed-off", 3294 gaim_signal_connect(gaim_connections_get_handle(), "signed-off",
3283 gtkblist, GAIM_CALLBACK(sign_on_off_cb), list); 3295 gtkblist, GAIM_CALLBACK(sign_on_off_cb), list);
3284 3296
3297 gaim_signal_connect(gaim_plugins_get_handle(), "plugin-load",
3298 gtkblist, GAIM_CALLBACK(plugin_changed_cb), NULL);
3299 gaim_signal_connect(gaim_plugins_get_handle(), "plugin-unload",
3300 gtkblist, GAIM_CALLBACK(plugin_changed_cb), NULL);
3301
3285 /* emit our created signal */ 3302 /* emit our created signal */
3286 gaim_signal_emit(gaim_gtk_blist_get_handle(), "gtkblist-created", list); 3303 gaim_signal_emit(gaim_gtk_blist_get_handle(), "gtkblist-created", list);
3287 } 3304 }
3288 3305
3289 /* XXX: does this need fixing? */ 3306 /* XXX: does this need fixing? */
3791 gtkblist->idle_column = NULL; 3808 gtkblist->idle_column = NULL;
3792 gtkblist->warning_column = gtkblist->buddy_icon_column = NULL; 3809 gtkblist->warning_column = gtkblist->buddy_icon_column = NULL;
3793 gtkblist->bbox = NULL; 3810 gtkblist->bbox = NULL;
3794 g_object_unref(G_OBJECT(gtkblist->ift)); 3811 g_object_unref(G_OBJECT(gtkblist->ift));
3795 protomenu = NULL; 3812 protomenu = NULL;
3813 pluginmenu = NULL;
3796 awaymenu = NULL; 3814 awaymenu = NULL;
3797 gtkblist = NULL; 3815 gtkblist = NULL;
3798 3816
3799 while(blist_prefs_callbacks) { 3817 while(blist_prefs_callbacks) {
3800 gaim_prefs_disconnect_callback(GPOINTER_TO_INT(blist_prefs_callbacks->data)); 3818 gaim_prefs_disconnect_callback(GPOINTER_TO_INT(blist_prefs_callbacks->data));
4876 { 4894 {
4877 if (pam->callback && pam->gc) 4895 if (pam->callback && pam->gc)
4878 pam->callback(pam->gc); 4896 pam->callback(pam->gc);
4879 } 4897 }
4880 4898
4899
4900 static void
4901 plugin_act(GtkObject *obk, struct plugin_actions_menu *pam)
4902 {
4903 if (pam->callback && pam->plugin)
4904 pam->callback(pam->plugin);
4905 }
4906
4907
4881 void 4908 void
4882 gaim_gtk_blist_update_protocol_actions(void) 4909 gaim_gtk_blist_update_protocol_actions(void)
4883 { 4910 {
4884 GtkWidget *menuitem; 4911 GtkWidget *menuitem;
4885 GtkWidget *submenu; 4912 GtkWidget *submenu;
5006 gaim_separator(submenu); 5033 gaim_separator(submenu);
5007 } 5034 }
5008 } 5035 }
5009 } 5036 }
5010 } 5037 }
5038
5039
5040
5041 void
5042 gaim_gtk_blist_update_plugin_actions(void)
5043 {
5044 GtkWidget *menuitem;
5045 GtkWidget *submenu;
5046 GaimPluginInfo *plugin_info = NULL;
5047 GList *l;
5048 GList *c;
5049 struct plugin_actions_menu *pam;
5050 int count = 0;
5051
5052 if (pluginmenu == NULL)
5053 return;
5054
5055 for (l = gtk_container_get_children(GTK_CONTAINER(pluginmenu));
5056 l != NULL;
5057 l = l->next) {
5058
5059 menuitem = l->data;
5060 pam = g_object_get_data(G_OBJECT(menuitem), "plugin_actions_menu");
5061 g_free(pam);
5062
5063 gtk_container_remove(GTK_CONTAINER(pluginmenu), GTK_WIDGET(menuitem));
5064 }
5065
5066 for (c = gaim_plugins_get_loaded(); c != NULL; c = c->next) {
5067 plugin_info = ((GaimPlugin *)c->data)->info;
5068 if (plugin_info->actions)
5069 count++;
5070 }
5071
5072 if (count == 0) {
5073 menuitem = gtk_menu_item_new_with_label(_("No actions available"));
5074 gtk_menu_shell_append(GTK_MENU_SHELL(pluginmenu), menuitem);
5075 gtk_widget_show(menuitem);
5076
5077 }
5078 else if (count == 1) {
5079 GList *act;
5080 GaimPlugin *plugin = NULL;
5081
5082 for (c = gaim_plugins_get_loaded(); c != NULL; c = c->next) {
5083 plugin = (GaimPlugin *) c->data;
5084 plugin_info = plugin->info;
5085 if (plugin_info->actions != NULL)
5086 break;
5087 }
5088
5089 for (act = plugin_info->actions(plugin); act != NULL; act = act->next) {
5090 if (act->data) {
5091 struct plugin_actions_menu *pam = act->data;
5092 menuitem = gtk_menu_item_new_with_label(pam->label);
5093 gtk_menu_shell_append(GTK_MENU_SHELL(pluginmenu), menuitem);
5094 g_signal_connect(G_OBJECT(menuitem), "activate",
5095 G_CALLBACK(plugin_act), pam);
5096 g_object_set_data(G_OBJECT(menuitem), "plugin_actions_menu", pam);
5097 gtk_widget_show(menuitem);
5098 }
5099 else
5100 gaim_separator(pluginmenu);
5101 }
5102 }
5103 else {
5104 for (c = gaim_plugins_get_loaded(); c != NULL; c = c->next) {
5105 GList *act;
5106 GaimPlugin *plugin;
5107
5108 plugin = (GaimPlugin *) c->data;
5109 plugin_info = plugin->info;
5110 if (plugin_info->actions == NULL)
5111 continue;
5112
5113 menuitem = gtk_image_menu_item_new_with_label(plugin_info->name);
5114 gtk_menu_shell_append(GTK_MENU_SHELL(pluginmenu), menuitem);
5115 gtk_widget_show(menuitem);
5116
5117 submenu = gtk_menu_new();
5118 gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu);
5119 gtk_widget_show(submenu);
5120
5121 for (act = plugin_info->actions(plugin); act != NULL; act = act->next) {
5122 if (act->data) {
5123 struct plugin_actions_menu *pam = act->data;
5124 menuitem = gtk_menu_item_new_with_label(pam->label);
5125 gtk_menu_shell_append(GTK_MENU_SHELL(submenu), menuitem);
5126 g_signal_connect(G_OBJECT(menuitem), "activate",
5127 G_CALLBACK(plugin_act), pam);
5128 g_object_set_data(G_OBJECT(menuitem), "plugin_actions_menu", pam);
5129 gtk_widget_show(menuitem);
5130 }
5131 else {
5132 gaim_separator(submenu);
5133 }
5134 }
5135 }
5136 }
5137 }
5138