comparison src/plugins.c @ 3551:cd938f18f3f8

[gaim-migrate @ 3626] In the interest of continued progress, I pulled what's usable out of my development tree and am committing it. Here, we have gotten rid of the plugins dialog and perl menu under Tools and put them both in preferences. Perl scripts now work like plugins--you have to load them explicitly (it will probe $prefix/lib/gaim and $HOME/.gaim for them) and you can unload them (although right now, this is entirely unreliable) Oh, and I broke all your perl scripts. Sorry about that. Don't try fixing them yet, though--I'm gonna make unloading single scripts more reliable tommorow. I should also finish Phase Two tommorow as well. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Thu, 26 Sep 2002 07:37:52 +0000
parents cfbdfe334975
children
comparison
equal deleted inserted replaced
3550:e9b2003ee562 3551:cd938f18f3f8
1 /*
2 * gaim
3 *
4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * ----------------
21 * The Plug-in plug
22 *
23 * Plugin support is currently being maintained by Mike Saraf
24 * msaraf@dwc.edu
25 *
26 * Well, I didn't see any work done on it for a while, so I'm going to try
27 * my hand at it. - Eric warmenhoven@yahoo.com
28 *
29 * Mike is my roomate. I can assure you that he's lazy :-P -- Rob rob@marko.net
30 *
31 */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
36
37 #ifdef GAIM_PLUGINS
38
39 #include <string.h>
40 #include <sys/time.h>
41
42 #include <sys/types.h>
43 #include <sys/stat.h>
44
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <gtk/gtk.h>
49 #include "gaim.h"
50
51 #include "pixmaps/gnome_add.xpm"
52 #include "pixmaps/gnome_remove.xpm"
53 #include "pixmaps/gnome_preferences.xpm"
54 #include "pixmaps/refresh.xpm"
55 #include "pixmaps/cancel.xpm"
56
57 #define PATHSIZE 1024 /* XXX: stolen from dialogs.c */
58
59
60 /* ------------------ Local Variables ------------------------ */
61
62 static GtkWidget *plugin_dialog = NULL;
63
64 static GtkWidget *pluglist = NULL;
65 static GtkWidget *plugtext = NULL;
66 static GtkWidget *plugwindow = NULL;
67 static GtkWidget *plugentry = NULL;
68
69 static GtkTooltips *tooltips = NULL;
70
71 static GtkWidget *config = NULL;
72 static guint confighandle = 0;
73 static GtkWidget *reload = NULL;
74 static GtkWidget *unload = NULL;
75 extern char *last_dir;
76
77 /* --------------- Function Declarations --------------------- */
78
79 void show_plugins(GtkWidget *, gpointer);
80
81 /* UI button callbacks */
82 static void unload_plugin_cb(GtkWidget *, gpointer);
83 static void plugin_reload_cb(GtkWidget *, gpointer);
84
85 static const gchar *plugin_makelistname(GModule *);
86
87 static void destroy_plugins(GtkWidget *, gpointer);
88 static void load_file(GtkWidget *, gpointer);
89 static void load_which_plugin(GtkWidget *, gpointer);
90 void update_show_plugins();
91 static void hide_plugins(GtkWidget *, gpointer);
92 static void clear_plugin_display();
93 static struct gaim_plugin *get_selected_plugin(GtkWidget *);
94 static void select_plugin(GtkWidget *w, struct gaim_plugin *p);
95 static void list_clicked(GtkWidget *, gpointer);
96
97 /* ------------------ Code Below ---------------------------- */
98
99 static void destroy_plugins(GtkWidget *w, gpointer data)
100 {
101 if (plugin_dialog)
102 gtk_widget_destroy(plugin_dialog);
103 plugin_dialog = NULL;
104 }
105
106 static void load_file(GtkWidget *w, gpointer data)
107 {
108 gchar *buf;
109
110 if (plugin_dialog) {
111 gtk_widget_show(plugin_dialog);
112 gdk_window_raise(plugin_dialog->window);
113 return;
114 }
115
116 plugin_dialog = gtk_file_selection_new(_("Gaim - Plugin List"));
117
118 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(plugin_dialog));
119
120 if (!last_dir)
121 buf = g_strdup(LIBDIR);
122 else
123 buf = g_strconcat(last_dir, G_DIR_SEPARATOR_S, NULL);
124
125 gtk_file_selection_set_filename(GTK_FILE_SELECTION(plugin_dialog), buf);
126 gtk_file_selection_complete(GTK_FILE_SELECTION(plugin_dialog), "*.so");
127 gtk_signal_connect(GTK_OBJECT(plugin_dialog), "destroy",
128 GTK_SIGNAL_FUNC(destroy_plugins), plugin_dialog);
129
130 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(plugin_dialog)->ok_button),
131 "clicked", GTK_SIGNAL_FUNC(load_which_plugin), NULL);
132
133 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(plugin_dialog)->cancel_button),
134 "clicked", GTK_SIGNAL_FUNC(destroy_plugins), NULL);
135
136 g_free(buf);
137 gtk_widget_show(plugin_dialog);
138 gdk_window_raise(plugin_dialog->window);
139 }
140
141 static void load_which_plugin(GtkWidget *w, gpointer data)
142 {
143 const char *file;
144 struct gaim_plugin *p;
145
146 file = (char *)gtk_file_selection_get_filename(GTK_FILE_SELECTION(plugin_dialog));
147 if (file_is_dir(file, plugin_dialog)) {
148 return;
149 }
150
151 if (file)
152 p = load_plugin(file);
153 else
154 p = NULL;
155
156 if (plugin_dialog)
157 gtk_widget_destroy(plugin_dialog);
158 plugin_dialog = NULL;
159
160 update_show_plugins();
161 /* Select newly loaded plugin */
162 if(p == NULL)
163 return;
164 select_plugin(pluglist, p);
165 }
166
167 void show_plugins(GtkWidget *w, gpointer data)
168 {
169 /* most of this code was shamelessly stolen from Glade */
170 GtkWidget *mainvbox;
171 GtkWidget *tophbox;
172 GtkWidget *bothbox;
173 GtkWidget *hbox;
174 GtkWidget *vbox;
175 GtkWidget *frame;
176 GtkWidget *scrolledwindow;
177 GtkWidget *label;
178 GtkWidget *add;
179 GtkWidget *close;
180 /* stuff needed for GtkTreeView *pluglist */
181 GtkListStore *store;
182 GtkCellRenderer *renderer;
183 GtkTreeViewColumn *column;
184 GtkTreeSelection *selection;
185 /* needed for GtkTextView *plugtext */
186 GtkTextBuffer *buffer;
187
188 if (plugwindow) {
189 gtk_window_present(GTK_WINDOW(plugwindow));
190 return;
191 }
192
193 GAIM_DIALOG(plugwindow);
194 gtk_window_set_wmclass(GTK_WINDOW(plugwindow), "plugins", "Gaim");
195 gtk_widget_realize(plugwindow);
196 gtk_window_set_title(GTK_WINDOW(plugwindow), _("Gaim - Plugins"));
197 gtk_signal_connect(GTK_OBJECT(plugwindow), "destroy", GTK_SIGNAL_FUNC(hide_plugins), NULL);
198
199 mainvbox = gtk_vbox_new(FALSE, 0);
200 gtk_container_add(GTK_CONTAINER(plugwindow), mainvbox);
201 gtk_widget_show(mainvbox);
202
203 /* Build the top */
204 tophbox = gtk_hbox_new(FALSE, 0);
205 gtk_box_pack_start(GTK_BOX(mainvbox), tophbox, TRUE, TRUE, 0);
206 gtk_widget_show(tophbox);
207
208 /* Left side: frame with list of plugin file names */
209 frame = gtk_frame_new(_("Loaded Plugins"));
210 gtk_box_pack_start(GTK_BOX(tophbox), frame, FALSE, FALSE, 0);
211 gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
212 gtk_frame_set_label_align(GTK_FRAME(frame), 0.05, 0.5);
213 gtk_widget_show(frame);
214
215 scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
216 gtk_container_add(GTK_CONTAINER(frame), scrolledwindow);
217 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
218 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
219 gtk_widget_show(scrolledwindow);
220 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow),
221 GTK_SHADOW_IN);
222
223 /* Create & show plugin list */
224 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
225 pluglist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
226 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pluglist), FALSE);
227 renderer = gtk_cell_renderer_text_new();
228 column = gtk_tree_view_column_new_with_attributes("text",
229 renderer, "text", 0, NULL);
230 gtk_tree_view_append_column(GTK_TREE_VIEW(pluglist), column);
231 gtk_container_add(GTK_CONTAINER(scrolledwindow), pluglist);
232
233 g_object_unref(G_OBJECT(store));
234
235 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pluglist));
236 g_signal_connect(G_OBJECT(selection), "changed",
237 G_CALLBACK(list_clicked),
238 NULL);
239
240 gtk_widget_show(pluglist);
241
242 /* Right side: frame with description and the filepath of plugin */
243 frame = gtk_frame_new(_("Selected Plugin"));
244 gtk_box_pack_start(GTK_BOX(tophbox), frame, TRUE, TRUE, 0);
245 gtk_container_set_border_width(GTK_CONTAINER(frame), 6);
246 gtk_frame_set_label_align(GTK_FRAME(frame), 0.05, 0.5);
247 gtk_widget_show(frame);
248
249 vbox = gtk_vbox_new(FALSE, 0);
250 gtk_container_add(GTK_CONTAINER(frame), vbox);
251 gtk_widget_show(vbox);
252
253 scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
254 gtk_box_pack_start(GTK_BOX(vbox), scrolledwindow, TRUE, TRUE, 0);
255 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
256 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
257 gtk_widget_show(scrolledwindow);
258 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow),
259 GTK_SHADOW_IN);
260
261 /* Create & show the plugin description widget */
262 plugtext = gtk_text_view_new();
263 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(plugtext), GTK_WRAP_WORD);
264 gtk_text_view_set_editable(GTK_TEXT_VIEW(plugtext), FALSE);
265 gtk_container_add(GTK_CONTAINER(scrolledwindow), plugtext);
266 gtk_widget_set_size_request(GTK_WIDGET(plugtext), -1, 200);
267
268 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(plugtext));
269 gtk_text_buffer_create_tag(buffer, "bold", "weight",
270 PANGO_WEIGHT_BOLD, NULL);
271 gtk_widget_show(plugtext);
272
273 hbox = gtk_hbox_new(FALSE, 5);
274 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
275 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
276 gtk_widget_show(hbox);
277
278 label = gtk_label_new(_("Filepath:"));
279 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
280 gtk_widget_show(label);
281
282 plugentry = gtk_entry_new();
283 gtk_box_pack_start(GTK_BOX(hbox), plugentry, TRUE, TRUE, 0);
284 gtk_entry_set_editable(GTK_ENTRY(plugentry), FALSE);
285 gtk_widget_show(plugentry);
286
287 /* Build the bottom button bar */
288 bothbox = gtk_hbox_new(TRUE, 3);
289 gtk_box_pack_start(GTK_BOX(mainvbox), bothbox, FALSE, FALSE, 0);
290 gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
291 gtk_widget_show(bothbox);
292
293 if (!tooltips)
294 tooltips = gtk_tooltips_new();
295
296 add = picture_button(plugwindow, _("Load"), gnome_add_xpm);
297 gtk_signal_connect(GTK_OBJECT(add), "clicked", GTK_SIGNAL_FUNC(load_file), NULL);
298 gtk_box_pack_start_defaults(GTK_BOX(bothbox), add);
299 gtk_tooltips_set_tip(tooltips, add, _("Load a plugin from a file"), "");
300
301 config = picture_button(plugwindow, _("Configure"), gnome_preferences_xpm);
302 gtk_widget_set_sensitive(config, FALSE);
303 gtk_box_pack_start_defaults(GTK_BOX(bothbox), config);
304 gtk_tooltips_set_tip(tooltips, config, _("Configure settings of the selected plugin"), "");
305
306 reload = picture_button(plugwindow, _("Reload"), refresh_xpm);
307 gtk_widget_set_sensitive(reload, FALSE);
308 gtk_signal_connect(GTK_OBJECT(reload), "clicked", GTK_SIGNAL_FUNC(plugin_reload_cb), NULL);
309 gtk_box_pack_start_defaults(GTK_BOX(bothbox), reload);
310 gtk_tooltips_set_tip(tooltips, reload, _("Reload the selected plugin"), "");
311
312 unload = picture_button(plugwindow, _("Unload"), gnome_remove_xpm);
313 gtk_signal_connect(GTK_OBJECT(unload), "clicked", GTK_SIGNAL_FUNC(unload_plugin_cb), pluglist);
314 gtk_box_pack_start_defaults(GTK_BOX(bothbox), unload);
315 gtk_tooltips_set_tip(tooltips, unload, _("Unload the selected plugin"), "");
316
317 close = picture_button(plugwindow, _("Close"), cancel_xpm);
318 gtk_signal_connect(GTK_OBJECT(close), "clicked", GTK_SIGNAL_FUNC(hide_plugins), NULL);
319 gtk_box_pack_start_defaults(GTK_BOX(bothbox), close);
320 gtk_tooltips_set_tip(tooltips, close, _("Close this window"), "");
321
322 update_show_plugins();
323 gtk_widget_show(plugwindow);
324 }
325
326 void update_show_plugins()
327 {
328 GList *plugs = plugins;
329 struct gaim_plugin *p;
330 int pnum = 0;
331 GtkListStore *store;
332 GtkTreeIter iter;
333
334 if (plugwindow == NULL)
335 return;
336
337 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(pluglist)));
338 gtk_list_store_clear(store);
339 while (plugs) {
340 p = (struct gaim_plugin *)plugs->data;
341 gtk_list_store_append(store, &iter);
342 gtk_list_store_set(store, &iter, 0, plugin_makelistname(p->handle), -1);
343 gtk_list_store_set(store, &iter, 1, pnum++, -1);
344 plugs = g_list_next(plugs);
345 }
346
347 clear_plugin_display();
348 }
349
350 static void unload_plugin_cb(GtkWidget *w, gpointer data)
351 {
352 struct gaim_plugin *p;
353 p = get_selected_plugin(pluglist);
354 if(p == NULL)
355 return;
356 unload_plugin(p);
357 update_show_plugins();
358 }
359
360 static void plugin_reload_cb(GtkWidget *w, gpointer data)
361 {
362 struct gaim_plugin *p;
363 p = get_selected_plugin(pluglist);
364 if(p == NULL)
365 return;
366 p = reload_plugin(p);
367 update_show_plugins();
368
369 /* Try and reselect the plugin in list */
370 if (!pluglist)
371 return;
372 select_plugin(pluglist, p);
373 }
374
375
376 static void list_clicked(GtkWidget *w, gpointer data)
377 {
378 void (*gaim_plugin_config)();
379 struct gaim_plugin *p;
380 GtkTextBuffer *buffer;
381 GtkTextIter iter;
382
383 if (confighandle != 0) {
384 gtk_signal_disconnect(GTK_OBJECT(config), confighandle);
385 confighandle = 0;
386 }
387
388 p = get_selected_plugin(pluglist);
389 if(p == NULL) { /* No selected plugin */
390 clear_plugin_display();
391 return;
392 }
393
394 /* Set text and filepath widgets */
395 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(plugtext));
396 gtk_text_buffer_set_text(buffer, "", -1);
397 gtk_text_buffer_get_start_iter(buffer, &iter);
398
399 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, "Name:", -1,
400 "bold", NULL);
401 gtk_text_buffer_insert(buffer, &iter, " ", -1);
402 gtk_text_buffer_insert(buffer, &iter, (p->name != NULL) ? p->name : "", -1);
403 gtk_text_buffer_insert(buffer, &iter, "\n\n", -1);
404 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, "Description:", -1,
405 "bold", NULL);
406 gtk_text_buffer_insert(buffer, &iter, "\n", -1);
407 gtk_text_buffer_insert(buffer, &iter,
408 (p->description != NULL) ? p->description : "", -1);
409
410 gtk_entry_set_text(GTK_ENTRY(plugentry), g_module_name(p->handle));
411 /* Find out if this plug-in has a configuration function */
412 if (g_module_symbol(p->handle, "gaim_plugin_config", (gpointer *)&gaim_plugin_config)) {
413 confighandle = gtk_signal_connect(GTK_OBJECT(config), "clicked",
414 GTK_SIGNAL_FUNC(gaim_plugin_config), NULL);
415 gtk_widget_set_sensitive(config, TRUE);
416 } else {
417 confighandle = 0;
418 gtk_widget_set_sensitive(config, FALSE);
419 }
420
421 gtk_widget_set_sensitive(reload, TRUE);
422 gtk_widget_set_sensitive(unload, TRUE);
423 }
424
425 static void hide_plugins(GtkWidget *w, gpointer data)
426 {
427 if (plugwindow)
428 gtk_widget_destroy(plugwindow);
429 plugwindow = NULL;
430 config = NULL;
431 confighandle = 0;
432 }
433
434 static const gchar *plugin_makelistname(GModule *module)
435 {
436 static gchar filename[PATHSIZE];
437 const gchar *filepath = (char *)g_module_name(module);
438 const char *cp;
439
440 if (filepath == NULL || strlen(filepath) == 0)
441 return NULL;
442
443 if ((cp = strrchr(filepath, '/')) == NULL || *++cp == '\0')
444 cp = filepath;
445
446 strncpy(filename, cp, sizeof(filename));
447 filename[sizeof(filename) - 1] = '\0';
448
449 /* Try to pretty name by removing any trailing ".so" */
450 if (strlen(filename) > 3 &&
451 strncmp(filename + strlen(filename) - 3, ".so", 3) == 0)
452 filename[strlen(filename) - 3] = '\0';
453
454 return filename;
455 }
456
457 static struct gaim_plugin *get_selected_plugin(GtkWidget *w) {
458 /* Given the pluglist widget, this will return a pointer to the plugin
459 * currently selected in the list, and NULL if none is selected. */
460 gint index;
461 GList *plugs = plugins;
462 GtkTreeSelection *sel;
463 GtkTreeIter iter;
464 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(w));
465
466 /* Get list index of selected plugin */
467 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(w));
468 if(!gtk_tree_selection_get_selected(sel, &model, &iter))
469 return NULL;
470 gtk_tree_model_get(model, &iter, 1, &index, -1);
471
472 /* Get plugin entry from index */
473 plugs = g_list_nth(plugins, index);
474 if(plugs == NULL)
475 return NULL;
476 else
477 return (struct gaim_plugin *)plugs->data;
478 }
479
480 static void select_plugin(GtkWidget *w, struct gaim_plugin *p) {
481 /* Given the pluglist widget and a plugin, this will try to select
482 * entry in the list which corresponds with the plugin. */
483 GtkTreeSelection *sel;
484 GtkTreeIter iter;
485 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(w));
486 gchar temp[10];
487
488 if(g_list_index(plugins, p) == -1)
489 return;
490
491 snprintf(temp, 10, "%d", g_list_index(plugins, p));
492 gtk_tree_model_get_iter_from_string(model,
493 &iter, temp);
494 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(w));
495 gtk_tree_selection_select_iter(sel, &iter);
496 }
497
498 static void clear_plugin_display() {
499 GtkTreeSelection *selection;
500 GtkTextBuffer *buffer;
501
502 /* Clear the plugin display if nothing's selected */
503 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pluglist));
504 if(gtk_tree_selection_get_selected(selection, NULL, NULL) == FALSE) {
505 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(plugtext));
506 gtk_text_buffer_set_text(buffer, "", -1);
507 gtk_entry_set_text(GTK_ENTRY(plugentry), "");
508
509 gtk_widget_set_sensitive(config, FALSE);
510 gtk_widget_set_sensitive(reload, FALSE);
511 gtk_widget_set_sensitive(unload, FALSE);
512 }
513 }
514
515 #endif