~ubuntu-branches/ubuntu/hardy/gnome-commander/hardy

« back to all changes in this revision

Viewing changes to src/plugin_manager.cc

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2007-06-11 09:37:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070611093703-zfmi3bh086344wuq
Tags: 1.2.4-1
New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    GNOME Commander - A GNOME based file manager
 
3
    Copyright (C) 2001-2006 Marcus Bjurman
 
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 2 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, write to the Free Software
 
17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 
18
*/
 
19
 
 
20
#include <config.h>
 
21
#include <dirent.h>
 
22
#include <gmodule.h>
 
23
#include "gnome-cmd-includes.h"
 
24
#include "gnome-cmd-data.h"
 
25
#include "plugin_manager.h"
 
26
#include "utils.h"
 
27
#include "imageloader.h"
 
28
#include "gnome-cmd-main-win.h"
 
29
#include "gnome-cmd-about-plugin.h"
 
30
 
 
31
using namespace std;
 
32
 
 
33
 
 
34
// The names of these functions shall never change
 
35
#define MODULE_INIT_FUNC "create_plugin"
 
36
#define MODULE_INFO_FUNC "get_plugin_info"
 
37
 
 
38
 
 
39
static GList *plugins = NULL;
 
40
static GdkPixmap *exec_pixmap = NULL;
 
41
static GdkBitmap *exec_mask = NULL;
 
42
static GdkPixmap *blank_pixmap = NULL;
 
43
static GdkBitmap *blank_mask = NULL;
 
44
 
 
45
 
 
46
static void
 
47
load_plugin (PluginData *data)
 
48
{
 
49
    GModule *module = g_module_open (data->fpath, G_MODULE_BIND_LAZY);
 
50
    PluginInfoFunc info_func;
 
51
    PluginConstructorFunc init_func;
 
52
    GnomeCmdPlugin *plugin;
 
53
 
 
54
    if (!module)
 
55
    {
 
56
        g_printerr ("ERROR: Failed to load the plugin '%s': %s\n", data->fname, g_module_error ());
 
57
        return;
 
58
    }
 
59
 
 
60
    // Try to get a reference to the "get_plugin_info" function
 
61
    if (!g_module_symbol (module, MODULE_INFO_FUNC, (gpointer *) &info_func))
 
62
    {
 
63
        g_printerr ("ERROR: The plugin-file '%s' has no function named '%s'.\n", data->fname, MODULE_INFO_FUNC);
 
64
        g_module_close (module);
 
65
        return;
 
66
    }
 
67
 
 
68
    // Try to get the plugin info
 
69
    data->info = info_func ();
 
70
    if (!data->info)
 
71
    {
 
72
        g_printerr ("ERROR: The plugin-file '%s' did not return valid plugin info:\n", data->fname);
 
73
        g_printerr ("  The function '%s' returned NULL\n", MODULE_INFO_FUNC);
 
74
        g_module_close (module);
 
75
        return;
 
76
    }
 
77
 
 
78
    // Check that the plugin is compatible
 
79
    if (data->info->plugin_system_version != GNOME_CMD_PLUGIN_SYSTEM_CURRENT_VERSION)
 
80
    {
 
81
        g_printerr ("ERROR: The plugin '%s' is not compatible with this version of %s:\n", data->info->name, PACKAGE);
 
82
        g_printerr ("  Plugin system supported by the plugin is %d, it should be %d\n", data->info->plugin_system_version,
 
83
                    GNOME_CMD_PLUGIN_SYSTEM_CURRENT_VERSION);
 
84
        return;
 
85
    }
 
86
 
 
87
    // Try to get a reference to the "create_plugin" function
 
88
    if (!g_module_symbol (module, MODULE_INIT_FUNC, (gpointer *) &init_func))
 
89
    {
 
90
        g_printerr ("ERROR: The plugin '%s' has no '%s' function\n", data->info->name, MODULE_INIT_FUNC);
 
91
        g_module_close (module);
 
92
        return;
 
93
    }
 
94
 
 
95
    // Try to initialize the plugin
 
96
    plugin = init_func ();
 
97
    if (!plugin)
 
98
    {
 
99
        g_printerr ("ERROR: The plugin '%s' could not be initialized:\n", data->info->name);
 
100
        g_printerr ("  The '%s' function returned NULL\n", MODULE_INIT_FUNC);
 
101
        g_module_close (module);
 
102
        return;
 
103
    }
 
104
 
 
105
    // All is OK, everyone is happy
 
106
    data->plugin = plugin;
 
107
    data->module = module;
 
108
    data->loaded = TRUE;
 
109
}
 
110
 
 
111
 
 
112
static void
 
113
activate_plugin (PluginData *data)
 
114
{
 
115
    if (data->active)
 
116
        return;
 
117
 
 
118
    if (!data->loaded)
 
119
        load_plugin (data);
 
120
 
 
121
    if (!data->loaded)
 
122
        return;
 
123
 
 
124
    data->active = TRUE;
 
125
 
 
126
    GnomeCmdState *state = gnome_cmd_main_win_get_state (main_win);
 
127
    data->menu = gnome_cmd_plugin_create_main_menu (data->plugin, state);
 
128
    if (data->menu)
 
129
        gnome_cmd_main_win_add_plugin_menu (main_win, data);
 
130
}
 
131
 
 
132
 
 
133
static void
 
134
inactivate_plugin (PluginData *data)
 
135
{
 
136
    if (!data->active)
 
137
        return;
 
138
 
 
139
    data->active = FALSE;
 
140
    if (data->menu)
 
141
        gtk_object_destroy (GTK_OBJECT (data->menu));
 
142
}
 
143
 
 
144
 
 
145
static void
 
146
scan_plugins_in_dir (const gchar *dpath)
 
147
{
 
148
    DIR *dir = opendir (dpath);
 
149
    char prev_dir[256];
 
150
    struct dirent *ent;
 
151
 
 
152
    if (dir == NULL)
 
153
    {
 
154
        gchar *msg = g_strdup_printf ("Could not list files in %s: %s\n", dpath, strerror (errno));
 
155
        warn_print (msg);
 
156
        g_free (msg);
 
157
        return;
 
158
    }
 
159
 
 
160
    getcwd (prev_dir, sizeof(prev_dir));
 
161
    chdir (dpath);
 
162
 
 
163
    while ((ent = readdir (dir)) != NULL)
 
164
    {
 
165
        struct stat buf;
 
166
 
 
167
        if (strcmp (ent->d_name+strlen(ent->d_name)-3, ".so") != 0)
 
168
            continue;
 
169
 
 
170
        if (stat (ent->d_name, &buf) == 0)
 
171
        {
 
172
            if (buf.st_mode & S_IFREG)
 
173
            {
 
174
                // the direntry has the .so extension and is a regular file, lets accept it
 
175
                PluginData *data = g_new (PluginData, 1);
 
176
                data->fname = g_strdup (ent->d_name);
 
177
                data->fpath = g_build_path (G_DIR_SEPARATOR_S, dpath, ent->d_name, NULL);
 
178
                data->loaded = FALSE;
 
179
                data->active = FALSE;
 
180
                data->menu = NULL;
 
181
                data->autoload = FALSE;
 
182
                activate_plugin (data);
 
183
                if (!data->loaded)
 
184
                {
 
185
                    g_free (data->fname);
 
186
                    g_free (data->fpath);
 
187
                    g_free (data);
 
188
                }
 
189
                else
 
190
                    plugins = g_list_append (plugins, data);
 
191
            }
 
192
            else
 
193
                printf ("%s is not a regular file\n", ent->d_name);
 
194
        }
 
195
        else
 
196
            printf ("Failed to stat %s\n", ent->d_name);
 
197
    }
 
198
 
 
199
    closedir (dir);
 
200
 
 
201
    if (prev_dir)
 
202
        chdir (prev_dir);
 
203
}
 
204
 
 
205
 
 
206
void plugin_manager_init (void)
 
207
{
 
208
    if (plugins)
 
209
    {
 
210
        warn_print ("plugin_manager already initiated\n");
 
211
        return;
 
212
    }
 
213
 
 
214
    // find user plugins
 
215
    gchar *user_dir = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir(), ".gnome-commander/plugins", NULL);
 
216
    create_dir_if_needed (user_dir);
 
217
    scan_plugins_in_dir (user_dir);
 
218
    g_free (user_dir);
 
219
 
 
220
    // find system plugins
 
221
    scan_plugins_in_dir (PLUGIN_DIR);
 
222
 
 
223
    // activate plugins
 
224
    for (GList *l=gnome_cmd_data_get_auto_load_plugins (); l; l=l->next)
 
225
    {
 
226
        char *name = (gchar *) l->data;
 
227
 
 
228
        for (GList *l2 = plugins; l2; l2 = l2->next)
 
229
        {
 
230
            PluginData *data = (PluginData *) l2->data;
 
231
            if (strcmp (name, data->fname) == 0)
 
232
                data->autoload = TRUE;
 
233
        }
 
234
    }
 
235
 
 
236
    // inactivate plugins that shouldn't be autoloaded
 
237
    for (GList *l=plugins; l; l=l->next)
 
238
    {
 
239
        PluginData *data = (PluginData *) l->data;
 
240
        if (!data->autoload)
 
241
            inactivate_plugin (data);
 
242
    }
 
243
}
 
244
 
 
245
 
 
246
void plugin_manager_shutdown (void)
 
247
{
 
248
    GList *out = NULL;
 
249
 
 
250
    for (GList *l=plugins; l; l=l->next)
 
251
    {
 
252
        PluginData *data = (PluginData *) l->data;
 
253
        if (data->active)
 
254
            out = g_list_append (out, data->fname);
 
255
    }
 
256
 
 
257
    gnome_cmd_data_set_auto_load_plugins (out);
 
258
}
 
259
 
 
260
 
 
261
GList *plugin_manager_get_all (void)
 
262
{
 
263
    return plugins;
 
264
}
 
265
 
 
266
 
 
267
PluginData *
 
268
get_selected_plugin (GtkCList *list)
 
269
{
 
270
    return (PluginData *) gtk_clist_get_row_data (list, list->focus_row);
 
271
}
 
272
 
 
273
 
 
274
static void
 
275
update_plugin_list (GtkCList *list, GtkWidget *dialog)
 
276
{
 
277
    gint old_focus = list->focus_row;
 
278
    gint row = 0;
 
279
    gboolean only_update = (list->rows > 0);
 
280
 
 
281
    for (GList *tmp=plugins; tmp; tmp=tmp->next)
 
282
    {
 
283
        PluginData *data = (PluginData *) tmp->data;
 
284
        gchar *text[5];
 
285
 
 
286
        text[0] = NULL;
 
287
        text[1] = data->info->name;
 
288
        text[2] = data->info->version;
 
289
        text[3] = data->fname;
 
290
        text[4] = NULL;
 
291
 
 
292
        if (only_update)
 
293
            gtk_clist_set_text (list, row, 1, text[1]);
 
294
        else
 
295
            gtk_clist_append (list, text);
 
296
 
 
297
        if (data->active)
 
298
            gtk_clist_set_pixmap (list, row, 0, exec_pixmap, exec_mask);
 
299
        else
 
300
            gtk_clist_set_pixmap (list, row, 0, blank_pixmap, blank_mask);
 
301
 
 
302
 
 
303
        gtk_clist_set_row_data (list, row, data);
 
304
 
 
305
        row++;
 
306
    }
 
307
 
 
308
    gtk_clist_select_row (list, old_focus, 0);
 
309
}
 
310
 
 
311
 
 
312
static void
 
313
do_toggle (GtkWidget *dialog)
 
314
{
 
315
    GtkCList *list = GTK_CLIST (lookup_widget (dialog, "avail_list"));
 
316
    PluginData *data = get_selected_plugin (list);
 
317
 
 
318
    if (!data) return;
 
319
 
 
320
    if (data->active)
 
321
        inactivate_plugin (data);
 
322
    else
 
323
        activate_plugin (data);
 
324
 
 
325
    update_plugin_list (list, dialog);
 
326
}
 
327
 
 
328
 
 
329
static void
 
330
on_plugin_selected (GtkCList *list, gint row, gint column,
 
331
                    GdkEventButton *event, GtkWidget *dialog)
 
332
{
 
333
    GtkWidget *toggle_button = lookup_widget (dialog, "toggle_button");
 
334
    GtkWidget *conf_button = lookup_widget (dialog, "conf_button");
 
335
    GtkWidget *about_button = lookup_widget (dialog, "about_button");
 
336
 
 
337
    PluginData *data = get_selected_plugin (list);
 
338
    g_return_if_fail (data != NULL);
 
339
 
 
340
    if (event && event->type == GDK_2BUTTON_PRESS && event->button == 1)
 
341
    {
 
342
        do_toggle (dialog);
 
343
        return;
 
344
    }
 
345
 
 
346
    gtk_widget_set_sensitive (about_button, TRUE);
 
347
    gtk_button_set_label (GTK_BUTTON (toggle_button), data->active ? _("Disable") : _("Enable"));
 
348
    gtk_widget_set_sensitive (toggle_button, TRUE);
 
349
    gtk_widget_set_sensitive (conf_button, data->active);
 
350
}
 
351
 
 
352
 
 
353
static void
 
354
on_plugin_unselected (GtkCList *list, gint row, gint column,
 
355
                      GdkEventButton *event, GtkWidget *dialog)
 
356
{
 
357
    GtkWidget *toggle_button = lookup_widget (dialog, "toggle_button");
 
358
    GtkWidget *conf_button = lookup_widget (dialog, "conf_button");
 
359
    GtkWidget *about_button = lookup_widget (dialog, "about_button");
 
360
 
 
361
    gtk_widget_set_sensitive (toggle_button, FALSE);
 
362
    gtk_widget_set_sensitive (about_button, FALSE);
 
363
    gtk_widget_set_sensitive (conf_button, FALSE);
 
364
}
 
365
 
 
366
 
 
367
static void
 
368
on_toggle (GtkButton *button, GtkWidget *dialog)
 
369
{
 
370
    do_toggle (dialog);
 
371
}
 
372
 
 
373
 
 
374
static void
 
375
on_configure (GtkButton *button, GtkWidget *dialog)
 
376
{
 
377
    GtkCList *list = GTK_CLIST (lookup_widget (dialog, "avail_list"));
 
378
    PluginData *data = get_selected_plugin (list);
 
379
 
 
380
    g_return_if_fail (data != NULL);
 
381
    g_return_if_fail (data->active);
 
382
 
 
383
    gnome_cmd_plugin_configure (data->plugin);
 
384
}
 
385
 
 
386
 
 
387
static void
 
388
on_about (GtkButton *button, GtkWidget *dialog)
 
389
{
 
390
    GtkCList *list = GTK_CLIST (lookup_widget (dialog, "avail_list"));
 
391
    PluginData *data = get_selected_plugin (list);
 
392
    GtkWidget *about = gnome_cmd_about_plugin_new (data->info);
 
393
 
 
394
    g_return_if_fail (data != NULL);
 
395
 
 
396
    gtk_window_set_transient_for (GTK_WINDOW (about), GTK_WINDOW (main_win));
 
397
    gtk_widget_ref (about);
 
398
    gtk_widget_show (about);
 
399
}
 
400
 
 
401
 
 
402
static void
 
403
on_close (GtkButton *button, GtkWidget *dialog)
 
404
{
 
405
    gtk_widget_destroy (dialog);
 
406
}
 
407
 
 
408
 
 
409
void plugin_manager_show (void)
 
410
{
 
411
    GtkWidget *dialog, *hbox, *bbox, *button;
 
412
    GtkWidget *avail_list;
 
413
 
 
414
    dialog = gnome_cmd_dialog_new (_("Available plugins"));
 
415
    gtk_widget_ref (dialog);
 
416
 
 
417
    hbox = create_vbox (dialog, FALSE, 6);
 
418
    avail_list = create_clist (dialog, "avail_list", 4, 20, GTK_SIGNAL_FUNC (on_plugin_selected), NULL);
 
419
    create_clist_column (avail_list, 0, 20, "");
 
420
    create_clist_column (avail_list, 1, 200, _("Name"));
 
421
    create_clist_column (avail_list, 2, 50, _("Version"));
 
422
    create_clist_column (avail_list, 3, 50, _("File"));
 
423
 
 
424
    bbox = create_hbuttonbox (dialog);
 
425
    gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_START);
 
426
 
 
427
    button = create_button (GTK_WIDGET (dialog), _("_Enable"), GTK_SIGNAL_FUNC (on_toggle));
 
428
    gtk_object_set_data (GTK_OBJECT (dialog), "toggle_button", button);
 
429
    gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, FALSE, 0);
 
430
 
 
431
    button = create_button (GTK_WIDGET (dialog), _("_Configure"), GTK_SIGNAL_FUNC (on_configure));
 
432
    gtk_object_set_data (GTK_OBJECT (dialog), "conf_button", button);
 
433
    gtk_widget_set_sensitive (button, FALSE);
 
434
    gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, FALSE, 0);
 
435
 
 
436
    button = create_button (GTK_WIDGET (dialog), _("_About"), GTK_SIGNAL_FUNC (on_about));
 
437
    gtk_object_set_data (GTK_OBJECT (dialog), "about_button", button);
 
438
    gtk_widget_set_sensitive (button, FALSE);
 
439
    gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, FALSE, 0);
 
440
 
 
441
    gtk_box_pack_start (GTK_BOX (hbox), avail_list, TRUE, TRUE, 0);
 
442
    gtk_box_pack_start (GTK_BOX (hbox), bbox, FALSE, TRUE, 0);
 
443
 
 
444
    gnome_cmd_dialog_add_expanding_category (GNOME_CMD_DIALOG (dialog), hbox);
 
445
 
 
446
    avail_list = lookup_widget (avail_list, "avail_list");
 
447
    gtk_signal_connect (GTK_OBJECT (avail_list), "unselect-row", GTK_SIGNAL_FUNC (on_plugin_unselected), dialog);
 
448
 
 
449
    if (!exec_pixmap)
 
450
    {
 
451
        exec_pixmap = IMAGE_get_pixmap (PIXMAP_EXEC_WHEEL);
 
452
        exec_mask = IMAGE_get_mask (PIXMAP_EXEC_WHEEL);
 
453
    }
 
454
 
 
455
    if (!blank_pixmap)
 
456
    {
 
457
        blank_pixmap = IMAGE_get_pixmap (PIXMAP_FLIST_ARROW_BLANK);
 
458
        blank_mask = IMAGE_get_mask (PIXMAP_FLIST_ARROW_BLANK);
 
459
    }
 
460
 
 
461
    update_plugin_list (GTK_CLIST (avail_list), dialog);
 
462
 
 
463
    gnome_cmd_dialog_add_button (GNOME_CMD_DIALOG (dialog), GNOME_STOCK_BUTTON_CLOSE, GTK_SIGNAL_FUNC(on_close), dialog);
 
464
    gnome_cmd_dialog_set_transient_for (GNOME_CMD_DIALOG (dialog), GTK_WINDOW (main_win));
 
465
 
 
466
    gtk_widget_set_size_request (GTK_WIDGET (dialog), 500, 300);
 
467
    gtk_window_set_resizable((GtkWindow *) GTK_WIDGET (dialog), TRUE);
 
468
    gtk_widget_show_all (GTK_WIDGET (dialog));
 
469
}