Add dialog used to add new plugins to the panel at runtime.
[lxde/lxpanel.git] / src / plugin.c
CommitLineData
16fb8c2e 1/**
a99ee9e1
JH
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
a52c2257
HJYP
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include "plugin.h"
24
25#include <gdk-pixbuf/gdk-pixbuf.h>
26#include <gdk-pixbuf-xlib/gdk-pixbuf-xlib.h>
27#include <gdk/gdk.h>
28#include <string.h>
29#include <stdlib.h>
30
a52c2257
HJYP
31#include "misc.h"
32#include "bg.h"
33#include "gtkbgbox.h"
34
35
36//#define DEBUG
37#include "dbg.h"
38
39static GList *pcl = NULL;
40
41
42/* counter for static (built-in) plugins must be greater then zero
43 * so lxpanel will not try to unload them */
44
45#define REGISTER_PLUGIN_CLASS(pc, dynamic) \
46do {\
47 extern plugin_class pc;\
48 register_plugin_class(&pc, dynamic);\
49} while (0)
50
51
52static void
53register_plugin_class(plugin_class *pc, int dynamic)
54{
55 pcl = g_list_append(pcl, pc);
56 pc->dynamic = dynamic;
57 if (!pc->dynamic)
58 pc->count++;
59 /* reloading tray results in segfault due to registering static type in dll.
60 * so keep it always onboard until bug fix */
61 if (!strcmp(pc->type, "tray"))
bee4c26e 62 pc->count++;
a52c2257
HJYP
63}
64
65static void
66init_plugin_class_list()
67{
68 ENTER;
69#ifdef STATIC_SEPARATOR
70 REGISTER_PLUGIN_CLASS(separator_plugin_class, 0);
71#endif
bee4c26e 72
a52c2257
HJYP
73#ifdef STATIC_IMAGE
74 REGISTER_PLUGIN_CLASS(image_plugin_class, 0);
75#endif
bee4c26e 76
a52c2257
HJYP
77#ifdef STATIC_LAUNCHBAR
78 REGISTER_PLUGIN_CLASS(launchbar_plugin_class, 0);
79#endif
bee4c26e 80
a52c2257
HJYP
81#ifdef STATIC_DCLOCK
82 REGISTER_PLUGIN_CLASS(dclock_plugin_class, 0);
83#endif
bee4c26e 84
a52c2257
HJYP
85#ifdef STATIC_WINCMD
86 REGISTER_PLUGIN_CLASS(wincmd_plugin_class, 0);
87#endif
88
f9dfb60b
HJYP
89#ifdef STATIC_DIRMENU
90 REGISTER_PLUGIN_CLASS(dirmenu_plugin_class, 0);
a52c2257 91#endif
a52c2257
HJYP
92
93#ifdef STATIC_TASKBAR
94 REGISTER_PLUGIN_CLASS(taskbar_plugin_class, 0);
95#endif
96
97#ifdef STATIC_PAGER
98 REGISTER_PLUGIN_CLASS(pager_plugin_class, 0);
99#endif
100
101#ifdef STATIC_TRAY
102 REGISTER_PLUGIN_CLASS(tray_plugin_class, 0);
103#endif
104
105#ifdef STATIC_MENU
106 REGISTER_PLUGIN_CLASS(menu_plugin_class, 0);
107#endif
108
109#ifdef STATIC_SPACE
110 REGISTER_PLUGIN_CLASS(space_plugin_class, 0);
111#endif
112
113#ifdef STATIC_ICONS
114 REGISTER_PLUGIN_CLASS(icons_plugin_class, 0);
115#endif
116
a52c2257
HJYP
117 RET();
118}
119
6a6ad54e
HJYP
120GList* plugin_find_class( const char* type )
121{
122 GList *tmp;
123 plugin_class *pc = NULL;
124 for (tmp = pcl; tmp; tmp = g_list_next(tmp)) {
125 pc = (plugin_class *) tmp->data;
126 if (!g_ascii_strcasecmp(type, pc->type)) {
127 LOG(LOG_INFO, " already have it\n");
128 break;
129 }
130 }
131 return tmp;
132}
a52c2257 133
6a6ad54e
HJYP
134static plugin_class*
135plugin_load_dynamic( const char* type, const char* path )
136{
137 plugin_class *pc = NULL;
138 GModule *m;
139 gpointer tmpsym;
140 char class_name[ 128 ];
141 m = g_module_open(path, G_MODULE_BIND_LAZY);
142 if (!m) {
143 /* ERR("error is %s\n", g_module_error()); */
144 RET(NULL);
145 }
146 g_snprintf( class_name, 128, "%s_plugin_class", type );
a52c2257 147
6a6ad54e
HJYP
148 if (!g_module_symbol(m, class_name, &tmpsym)
149 || (pc = tmpsym) == NULL
150 || strcmp(type, pc->type)) {
151 g_module_close(m);
152 ERR("%s.so is not a lxpanel plugin\n", type);
153 RET(NULL);
154 }
155 pc->gmodule = m;
156 register_plugin_class(pc, 1);
157 return pc;
158}
a52c2257
HJYP
159
160plugin *
161plugin_load(char *type)
162{
163 GList *tmp;
164 plugin_class *pc = NULL;
165 plugin *plug = NULL;
bee4c26e 166
a52c2257
HJYP
167 ENTER;
168 if (!pcl)
169 init_plugin_class_list();
170
6a6ad54e
HJYP
171 tmp = plugin_find_class( type );
172
173 if( tmp ) {
a52c2257 174 pc = (plugin_class *) tmp->data;
a52c2257 175 }
2d29cc96 176#ifndef DISABLE_PLUGINS_LOADING
6a6ad54e
HJYP
177 else if ( g_module_supported() ) {
178 char* path[ PATH_MAX ];
179 g_snprintf(path, PATH_MAX, "%s/.lxpanel/plugins/%s.so", getenv("HOME"), type);
180 pc = plugin_load_dynamic( type, path );
181 if( !pc ) {
182 g_snprintf(path, PATH_MAX, PACKAGE_LIB_DIR "/lxpanel/plugins/%s.so", type);
183 pc = plugin_load_dynamic( type, path );
a52c2257 184 }
a52c2257 185 }
f5e3de23 186#endif /* DISABLE_PLUGINS_LOADING */
a52c2257
HJYP
187
188 /* nothing was found */
189 if (!pc)
190 RET(NULL);
bee4c26e 191
a52c2257
HJYP
192 plug = g_new0(plugin, 1);
193 g_return_val_if_fail (plug != NULL, NULL);
194 plug->class = pc;
195 pc->count++;
196 RET(plug);
197}
198
199
200void plugin_put(plugin *this)
201{
202 plugin_class *pc = this->class;
a52c2257 203 ENTER;
6a6ad54e 204 plugin_class_unref( pc );
a52c2257
HJYP
205 g_free(this);
206 RET();
207}
208
209int
db449f6e 210plugin_start(plugin *this, char** fp)
a52c2257
HJYP
211{
212 ENTER;
213
214 DBG("%s\n", this->class->type);
215 if (!this->class->invisible) {
216 this->pwid = gtk_bgbox_new();
217 gtk_widget_set_name(this->pwid, this->class->type);
218 gtk_box_pack_start(GTK_BOX(this->panel->box), this->pwid, this->expand, TRUE,
219 this->padding);
a52c2257 220 gtk_container_set_border_width(GTK_CONTAINER(this->pwid), this->border);
a52c2257 221 if (this->panel->transparent) {
a52c2257
HJYP
222 gtk_bgbox_set_background(this->pwid, BG_ROOT, this->panel->tintcolor, this->panel->alpha);
223 }
a52c2257 224 gtk_widget_show(this->pwid);
a52c2257 225 }
db449f6e 226 if (!this->class->constructor(this, fp)) {
a52c2257
HJYP
227 if (!this->class->invisible)
228 gtk_widget_destroy(this->pwid);
229 RET(0);
230 }
231 RET(1);
232}
233
234
235void plugin_stop(plugin *this)
236{
237 ENTER;
238 DBG("%s\n", this->class->type);
239 this->class->destructor(this);
240 this->panel->plug_num--;
bee4c26e 241 if (!this->class->invisible)
a52c2257
HJYP
242 gtk_widget_destroy(this->pwid);
243 RET();
244}
245
6a6ad54e
HJYP
246void plugin_class_unref( plugin_class* pc )
247{
248 --pc->count;
249 if (pc->count == 0 && pc->dynamic) {
250 pcl = g_list_remove(pcl, pc);
251 /* pc points now somewhere inside loaded lib, so if g_module_close
252 * will touch it after dlclose (and 2.6 does) it will result in segfault */
253 g_module_close(pc->gmodule);
254 }
255}
256
257/*
258 Get a list of all available plugin classes
16fb8c2e
HJYP
259 Return a newly allocated GList which should be freed with
260 plugin_class_list_free( list );
6a6ad54e
HJYP
261*/
262GList* plugin_get_available_classes()
263{
264 GList* classes = NULL;
265 char *path, *dir_path;
266 const char* file;
267 GDir* dir;
268 GList* l;
269 plugin_class *pc;
270
271 for( l = pcl; l; l = l->next ) {
272 pc = (plugin_class*)l->data;
273 classes = g_list_prepend( classes, pc );
274 ++pc->count;
275 }
276
277#ifndef DISABLE_PLUGINS_LOADING
278 dir_path = g_build_filename( g_get_home_dir(), ".lxpanel/plugins", NULL );
279 if( dir = g_dir_open( dir_path, 0, NULL ) ) {
280 while( file = g_dir_read_name( dir ) ) {
281 GModule *m;
282 char* type;
283 if( ! g_str_has_suffix( file, ".so" ) )
284 continue;
285 type = g_strndup( file, strlen(file) - 3 );
286 l = plugin_find_class( type );
287 if( l == NULL ) { /* If it has not been loaded */
288 path = g_build_filename( dir_path, file, NULL );
289 if( pc = plugin_load_dynamic( type, path ) ) {
290 ++pc->count;
291 classes = g_list_prepend( classes, pc );
292 }
293 g_free( path );
294 }
295 g_free( type );
296 }
297 g_dir_close( dir );
298 }
299 g_free( dir_path );
300
301 if( dir = g_dir_open( PACKAGE_LIB_DIR "/lxpanel/plugins", 0, NULL ) ) {
302 while( file = g_dir_read_name( dir ) ) {
303 GModule *m;
304 char* type;
305 if( ! g_str_has_suffix( file, ".so" ) )
306 continue;
307 type = g_strndup( file, strlen(file) - 3 );
308 l = plugin_find_class( type );
309 if( l == NULL ) { /* If it has not been loaded */
310 path = g_build_filename( PACKAGE_LIB_DIR "/lxpanel/plugins", file, NULL );
311 if( pc = plugin_load_dynamic( type, path ) ) {
312 ++pc->count;
313 classes = g_list_prepend( classes, pc );
314 }
315 g_free( path );
316 }
317 g_free( type );
318 }
319 g_dir_close( dir );
320 }
321#endif
322 /* classes = g_list_reverse( classes ); */
323 return classes;
324}
325
16fb8c2e
HJYP
326void plugin_class_list_free( GList* classes )
327{
328 g_list_foreach( classes, plugin_class_unref, NULL );
329 g_list_free( classes );
330}