use DESTDIR for easy packaging
[claws-mail-plugin-reloader.git] / plugin-reloader.c
1 /*
2  * claws-mail-plugin-reloader -- Quick plugin reloader plugin for Claws Mail
3  * Copyright (C) 2015 Charles Lehner and the Claws Mail Team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <glib.h>
20
21 #define GETTEXT_PACKAGE "claws-mail-plugin-reloader"
22 #include <glib/gi18n-lib.h>
23
24 #include <gtk/gtk.h>
25
26 #include "plugin.h"
27 #include "mainwindow.h"
28 #include "menu.h"
29 #include "alertpanel.h"
30
31 #define PLUGIN_NAME (_("Plugin Reloader"))
32 #define VERSION "1.0.0"
33
34 static void update_reload_plugins_menu(void);
35
36 GtkWidget *plugins_menuitem;
37 MainWindow *mainwin;
38 static guint main_menu_id = 0;
39
40 const gchar *plugin_name(void) { return PLUGIN_NAME; }
41 const gchar *plugin_version(void) { return VERSION; }
42 const gchar *plugin_type(void) { return "GTK2"; }
43 const gchar *plugin_licence(void) { return "GPL3+"; }
44
45 struct PluginFeature *plugin_provides(void)
46 {
47         static struct PluginFeature features[] = 
48                 { {PLUGIN_UTILITY, N_("Plugin Reloader")},
49                   {PLUGIN_NOTHING, NULL}};
50         return features;
51 }
52
53 const gchar *plugin_desc(void)
54 {
55         return _("This plugin lets you quickly reload other plugins. "
56                 "It is meant as a tool to help speed up plugin development.");
57 }
58
59 static GtkActionEntry reloader_main_menu[] = {
60         {"Tools/ReloadPlugin", NULL, N_("Reload Plugin"), NULL, NULL,
61                 G_CALLBACK(gtk_false)}
62 };
63
64 gint plugin_init(gchar **error)
65 {
66         mainwin = mainwindow_get_mainwindow();
67
68         gtk_action_group_add_actions(mainwin->action_group, reloader_main_menu,
69                         G_N_ELEMENTS(reloader_main_menu), mainwin);
70
71         MENUITEM_ADDUI_ID_MANAGER(mainwin->ui_manager,
72                         "/Menu/Tools", "ReloadPlugin", "Tools/ReloadPlugin",
73                         GTK_UI_MANAGER_MENUITEM, main_menu_id);
74
75         debug_print("Plugin Reloader plug-in loaded\n");
76
77         plugins_menuitem = gtk_ui_manager_get_widget(mainwin->ui_manager,
78                         "/Menu/Tools/ReloadPlugin");
79         g_signal_connect(G_OBJECT(plugins_menuitem), "activate",
80                         G_CALLBACK(update_reload_plugins_menu), NULL);
81
82         update_reload_plugins_menu();
83
84         return 0;
85 }
86
87 gboolean plugin_done(void)
88 {
89         MainWindow *mainwin = mainwindow_get_mainwindow();
90
91         if (mainwin == NULL)
92                 return TRUE;
93
94         MENUITEM_REMUI_MANAGER(mainwin->ui_manager, mainwin->action_group,
95                         "Tools/ReloadPlugin", main_menu_id);
96         main_menu_id = 0;
97
98         debug_print("Plugin Reloader plugin unloaded\n");
99
100         return TRUE;
101 }
102
103 static void reload_plugin_cb(GtkAction *action, gpointer data)
104 {
105         Plugin *plugin = data;
106         struct {
107                 gchar *filename;
108         } *pluginfoo = data;
109         gchar *filename;
110         gchar *err = NULL;
111         
112         Xstrdup_a(filename, pluginfoo->filename, return)
113
114         if (plugin_get_name(plugin) == PLUGIN_NAME) {
115                 alertpanel_error(_("Can't do that."));
116                 /* Can't remove self because then we would return into unloaded code.
117                  * Can't remove in a timeout/idle because those need to return false */
118                 return;
119         }
120
121         plugin_unload(plugin);
122         plugin_load(filename, &err);
123
124         if (err) {
125                 alertpanel_error(err);
126                 g_free(err);
127         }
128
129         update_reload_plugins_menu();
130 }
131
132 static void update_reload_plugins_menu(void)
133 {
134         GSList *cur;
135         GtkWidget *menu = gtk_menu_new();
136         GSList *plugins_list = plugin_get_list();
137         GtkUIManager *ui_manager = mainwin->ui_manager;
138         static const gchar *accel_group = "<ReloadPlugins>/";
139         gchar *accel_path;
140
141         gtk_menu_set_accel_group(GTK_MENU(menu),
142                         gtk_ui_manager_get_accel_group(ui_manager));
143
144         gtk_menu_item_set_submenu(GTK_MENU_ITEM(plugins_menuitem), NULL);
145
146         for (cur = plugins_list; cur != NULL; cur = cur->next) {
147                 Plugin *plugin = cur->data;
148                 const gchar *plugin_name = plugin_get_name(plugin);
149                 GtkWidget *item = gtk_menu_item_new_with_label(plugin_name);
150
151                 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
152                 g_signal_connect(G_OBJECT(item), "activate",
153                                 G_CALLBACK(reload_plugin_cb), plugin);
154
155                 Xstrcat_a(accel_path, accel_group, plugin_name, continue);
156                 gtk_menu_item_set_accel_path(GTK_MENU_ITEM(item), accel_path);
157         }
158
159         gtk_widget_show_all(menu);
160         gtk_menu_item_set_submenu(GTK_MENU_ITEM(plugins_menuitem), menu);
161
162         g_slist_free(plugins_list);
163 }
164