Allow build without libmenu-cache.
[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"
a52c2257 33
239cb032 34#include <glib-object.h>
a52c2257
HJYP
35
36//#define DEBUG
37#include "dbg.h"
38
39static GList *pcl = NULL;
40
239cb032
HJYP
41#if 0
42/* dummy type plugin for dynamic plugins registering new types */
43static void
44lx_type_plugin_iface_init(gpointer g_iface, gpointer g_iface_data);
45
46G_DEFINE_TYPE_EXTENDED ( LXTypePlugin,
47 lx_type_plugin,
48 G_TYPE_OBJECT,
49 0,
50 G_IMPLEMENT_INTERFACE (G_TYPE_TYPE_PLUGIN,
51 lx_type_plugin_iface_init))
52
53void lx_type_plugin_init( LXTypePlugin* tp )
54{
55}
56
57void lx_type_plugin_class_init(LXTypePluginClass* klass)
58{
59}
60
61void lx_type_plugin_iface_init(gpointer g_iface, gpointer g_iface_data)
62{
63}
64
65GTypePlugin* lx_type_plugin_get(const char* plugin_name)
66{
67 LXTypePlugin* tp = g_object_new(LX_TYPE_TYPE_PLUGIN, NULL);
68 return tp;
69}
70#endif
a52c2257
HJYP
71
72/* counter for static (built-in) plugins must be greater then zero
73 * so lxpanel will not try to unload them */
74
75#define REGISTER_PLUGIN_CLASS(pc, dynamic) \
76do {\
22242ed4 77 extern PluginClass pc;\
a52c2257
HJYP
78 register_plugin_class(&pc, dynamic);\
79} while (0)
80
81
82static void
22242ed4 83register_plugin_class(PluginClass *pc, int dynamic)
a52c2257
HJYP
84{
85 pcl = g_list_append(pcl, pc);
86 pc->dynamic = dynamic;
87 if (!pc->dynamic)
88 pc->count++;
239cb032 89 /* reloading netstatus results in segfault due to registering static type in dll.
a52c2257 90 * so keep it always onboard until bug fix */
239cb032 91 if (!strcmp(pc->type, "netstatus"))
bee4c26e 92 pc->count++;
a52c2257
HJYP
93}
94
95static void
96init_plugin_class_list()
97{
a52c2257
HJYP
98#ifdef STATIC_SEPARATOR
99 REGISTER_PLUGIN_CLASS(separator_plugin_class, 0);
100#endif
bee4c26e 101
239cb032
HJYP
102/* Remove image plugin since it seems to be useless. */
103/*
a52c2257
HJYP
104#ifdef STATIC_IMAGE
105 REGISTER_PLUGIN_CLASS(image_plugin_class, 0);
106#endif
239cb032 107*/
bee4c26e 108
a52c2257
HJYP
109#ifdef STATIC_LAUNCHBAR
110 REGISTER_PLUGIN_CLASS(launchbar_plugin_class, 0);
111#endif
bee4c26e 112
a52c2257
HJYP
113#ifdef STATIC_DCLOCK
114 REGISTER_PLUGIN_CLASS(dclock_plugin_class, 0);
115#endif
bee4c26e 116
a52c2257
HJYP
117#ifdef STATIC_WINCMD
118 REGISTER_PLUGIN_CLASS(wincmd_plugin_class, 0);
119#endif
120
f9dfb60b 121#ifdef STATIC_DIRMENU
239cb032 122 REGISTER_PLUGIN_CLASS(dirmenu_plugin_class, 0);
a52c2257 123#endif
a52c2257
HJYP
124
125#ifdef STATIC_TASKBAR
126 REGISTER_PLUGIN_CLASS(taskbar_plugin_class, 0);
127#endif
128
129#ifdef STATIC_PAGER
130 REGISTER_PLUGIN_CLASS(pager_plugin_class, 0);
131#endif
132
133#ifdef STATIC_TRAY
134 REGISTER_PLUGIN_CLASS(tray_plugin_class, 0);
135#endif
136
ace2a572 137#ifndef DISABLE_MENU
a52c2257
HJYP
138#ifdef STATIC_MENU
139 REGISTER_PLUGIN_CLASS(menu_plugin_class, 0);
140#endif
ace2a572 141#endif
a52c2257
HJYP
142
143#ifdef STATIC_SPACE
144 REGISTER_PLUGIN_CLASS(space_plugin_class, 0);
145#endif
146
a52c2257
HJYP
147 RET();
148}
149
6a6ad54e
HJYP
150GList* plugin_find_class( const char* type )
151{
152 GList *tmp;
22242ed4 153 PluginClass *pc = NULL;
6a6ad54e 154 for (tmp = pcl; tmp; tmp = g_list_next(tmp)) {
22242ed4 155 pc = (PluginClass *) tmp->data;
6a6ad54e
HJYP
156 if (!g_ascii_strcasecmp(type, pc->type)) {
157 LOG(LOG_INFO, " already have it\n");
158 break;
159 }
160 }
161 return tmp;
162}
a52c2257 163
22242ed4 164static PluginClass*
2da66cf4 165plugin_load_dynamic( const char* type, const gchar* path )
6a6ad54e 166{
22242ed4 167 PluginClass *pc = NULL;
6a6ad54e
HJYP
168 GModule *m;
169 gpointer tmpsym;
170 char class_name[ 128 ];
171 m = g_module_open(path, G_MODULE_BIND_LAZY);
172 if (!m) {
173 /* ERR("error is %s\n", g_module_error()); */
174 RET(NULL);
175 }
176 g_snprintf( class_name, 128, "%s_plugin_class", type );
a52c2257 177
6a6ad54e
HJYP
178 if (!g_module_symbol(m, class_name, &tmpsym)
179 || (pc = tmpsym) == NULL
180 || strcmp(type, pc->type)) {
181 g_module_close(m);
182 ERR("%s.so is not a lxpanel plugin\n", type);
183 RET(NULL);
184 }
185 pc->gmodule = m;
186 register_plugin_class(pc, 1);
187 return pc;
188}
a52c2257 189
22242ed4 190Plugin *
a52c2257
HJYP
191plugin_load(char *type)
192{
193 GList *tmp;
22242ed4
HJYP
194 PluginClass *pc = NULL;
195 Plugin *plug = NULL;
bee4c26e 196
a52c2257
HJYP
197 ENTER;
198 if (!pcl)
199 init_plugin_class_list();
200
6a6ad54e
HJYP
201 tmp = plugin_find_class( type );
202
203 if( tmp ) {
22242ed4 204 pc = (PluginClass *) tmp->data;
a52c2257 205 }
2d29cc96 206#ifndef DISABLE_PLUGINS_LOADING
6a6ad54e 207 else if ( g_module_supported() ) {
2da66cf4 208 gchar path[ PATH_MAX ];
209
24053345 210#if 0 /* put plugins in config dir is too dirty... */
6a6ad54e
HJYP
211 g_snprintf(path, PATH_MAX, "%s/.lxpanel/plugins/%s.so", getenv("HOME"), type);
212 pc = plugin_load_dynamic( type, path );
24053345 213#endif
6a6ad54e
HJYP
214 if( !pc ) {
215 g_snprintf(path, PATH_MAX, PACKAGE_LIB_DIR "/lxpanel/plugins/%s.so", type);
216 pc = plugin_load_dynamic( type, path );
a52c2257 217 }
a52c2257 218 }
52cb5b58 219#endif /* DISABLE_PLUGINS_LOADING */
a52c2257
HJYP
220
221 /* nothing was found */
222 if (!pc)
223 RET(NULL);
bee4c26e 224
22242ed4 225 plug = g_new0(Plugin, 1);
a52c2257
HJYP
226 g_return_val_if_fail (plug != NULL, NULL);
227 plug->class = pc;
228 pc->count++;
229 RET(plug);
230}
231
232
22242ed4 233void plugin_put(Plugin *this)
a52c2257 234{
22242ed4 235 PluginClass *pc = this->class;
a52c2257 236 ENTER;
6a6ad54e 237 plugin_class_unref( pc );
a52c2257
HJYP
238 g_free(this);
239 RET();
240}
241
242int
22242ed4 243plugin_start(Plugin *this, char** fp)
a52c2257
HJYP
244{
245 ENTER;
246
247 DBG("%s\n", this->class->type);
4542c20d
HJYP
248
249 if (!this->class->constructor(this, fp)) {
250// if (!this->class->invisible)
251// gtk_widget_destroy(this->pwid);
252 RET(0);
253 }
254
255 if (!this->class->invisible && this->pwid ) {
256 /* this->pwid is created by the plugin */
257 //this->pwid = gtk_bgbox_new();
a52c2257
HJYP
258 gtk_widget_set_name(this->pwid, this->class->type);
259 gtk_box_pack_start(GTK_BOX(this->panel->box), this->pwid, this->expand, TRUE,
260 this->padding);
a52c2257 261 gtk_container_set_border_width(GTK_CONTAINER(this->pwid), this->border);
4542c20d 262
a52c2257 263 gtk_widget_show(this->pwid);
a52c2257 264 }
a52c2257
HJYP
265 RET(1);
266}
267
268
22242ed4 269void plugin_stop(Plugin *this)
a52c2257
HJYP
270{
271 ENTER;
87cbb654 272 /* g_debug("%s\n", this->class->type); */
a52c2257
HJYP
273 this->class->destructor(this);
274 this->panel->plug_num--;
4542c20d 275 if (!this->class->invisible && this->pwid )
a52c2257 276 gtk_widget_destroy(this->pwid);
4542c20d 277 /* this->pwid is destroyed in the dtor of plugins */
a52c2257
HJYP
278 RET();
279}
280
22242ed4 281void plugin_class_unref( PluginClass* pc )
6a6ad54e
HJYP
282{
283 --pc->count;
284 if (pc->count == 0 && pc->dynamic) {
285 pcl = g_list_remove(pcl, pc);
286 /* pc points now somewhere inside loaded lib, so if g_module_close
287 * will touch it after dlclose (and 2.6 does) it will result in segfault */
288 g_module_close(pc->gmodule);
289 }
290}
291
292/*
293 Get a list of all available plugin classes
16fb8c2e
HJYP
294 Return a newly allocated GList which should be freed with
295 plugin_class_list_free( list );
6a6ad54e
HJYP
296*/
297GList* plugin_get_available_classes()
298{
299 GList* classes = NULL;
2da66cf4 300 gchar *path;
301 char *dir_path;
6a6ad54e
HJYP
302 const char* file;
303 GDir* dir;
304 GList* l;
22242ed4 305 PluginClass *pc;
6a6ad54e 306
316347ab
HJYP
307 if (!pcl)
308 init_plugin_class_list();
309
6a6ad54e 310 for( l = pcl; l; l = l->next ) {
22242ed4 311 pc = (PluginClass*)l->data;
6a6ad54e
HJYP
312 classes = g_list_prepend( classes, pc );
313 ++pc->count;
314 }
315
316#ifndef DISABLE_PLUGINS_LOADING
24053345 317#if 0 /* Put plugins in config dir is too dirty... */
6a6ad54e
HJYP
318 dir_path = g_build_filename( g_get_home_dir(), ".lxpanel/plugins", NULL );
319 if( dir = g_dir_open( dir_path, 0, NULL ) ) {
320 while( file = g_dir_read_name( dir ) ) {
321 GModule *m;
322 char* type;
323 if( ! g_str_has_suffix( file, ".so" ) )
324 continue;
325 type = g_strndup( file, strlen(file) - 3 );
326 l = plugin_find_class( type );
327 if( l == NULL ) { /* If it has not been loaded */
328 path = g_build_filename( dir_path, file, NULL );
329 if( pc = plugin_load_dynamic( type, path ) ) {
330 ++pc->count;
331 classes = g_list_prepend( classes, pc );
332 }
333 g_free( path );
334 }
335 g_free( type );
336 }
337 g_dir_close( dir );
338 }
339 g_free( dir_path );
24053345 340#endif
6a6ad54e
HJYP
341 if( dir = g_dir_open( PACKAGE_LIB_DIR "/lxpanel/plugins", 0, NULL ) ) {
342 while( file = g_dir_read_name( dir ) ) {
343 GModule *m;
344 char* type;
345 if( ! g_str_has_suffix( file, ".so" ) )
346 continue;
347 type = g_strndup( file, strlen(file) - 3 );
348 l = plugin_find_class( type );
349 if( l == NULL ) { /* If it has not been loaded */
350 path = g_build_filename( PACKAGE_LIB_DIR "/lxpanel/plugins", file, NULL );
351 if( pc = plugin_load_dynamic( type, path ) ) {
352 ++pc->count;
353 classes = g_list_prepend( classes, pc );
354 }
355 g_free( path );
356 }
357 g_free( type );
358 }
359 g_dir_close( dir );
360 }
361#endif
362 /* classes = g_list_reverse( classes ); */
363 return classes;
364}
365
16fb8c2e
HJYP
366void plugin_class_list_free( GList* classes )
367{
2da66cf4 368 g_list_foreach( classes, (GFunc)plugin_class_unref, NULL );
16fb8c2e
HJYP
369 g_list_free( classes );
370}
4542c20d
HJYP
371
372void
22242ed4 373plugin_widget_set_background( GtkWidget* w, Panel* p )
4542c20d 374{
f37da9d7 375 static gboolean in_tray = FALSE;
a66c0500 376 gboolean is_tray;
f37da9d7 377
4542c20d
HJYP
378 if( ! w )
379 return;
380
a66c0500
HJYP
381 is_tray = ( GTK_IS_CONTAINER(w) && strcmp( gtk_widget_get_name( w ), "tray" ) == 0 );
382
4542c20d
HJYP
383 if( ! GTK_WIDGET_NO_WINDOW( w ) )
384 {
385 if( p->background || p->transparent )
386 {
387 gtk_widget_set_app_paintable( w, TRUE );
388 if( GTK_WIDGET_REALIZED(w) )
389 gdk_window_set_back_pixmap( w->window, NULL, TRUE );
390 }
391 else
392 {
393 gtk_widget_set_app_paintable( w, FALSE );
394 if( GTK_WIDGET_REALIZED(w) )
f37da9d7 395 {
4542c20d 396 gdk_window_set_back_pixmap( w->window, NULL, FALSE );
f37da9d7
HJYP
397
398 /* dirty hack to fix the background color of tray icons :-( */
399 if( in_tray )
400 gdk_window_set_background( w->window, &w->style->bg[ GTK_STATE_NORMAL ] );
401 }
4542c20d
HJYP
402 }
403 // g_debug("%s has window (%s)", gtk_widget_get_name(w), G_OBJECT_TYPE_NAME(w) );
404 }
7a90db30 405 /*
4542c20d 406 else
7a90db30
HJYP
407 g_debug("%s has NO window (%s)", gtk_widget_get_name(w), G_OBJECT_TYPE_NAME(w) );
408 */
4542c20d
HJYP
409 if( GTK_IS_CONTAINER( w ) )
410 {
f37da9d7
HJYP
411 if( is_tray )
412 in_tray = TRUE;
413
2da66cf4 414 gtk_container_foreach( (GtkContainer*)w,
415 (GtkCallback)plugin_widget_set_background, p );
f37da9d7
HJYP
416
417 if( is_tray )
418 in_tray = FALSE;
4542c20d
HJYP
419 }
420
421 /* Dirty hack: Force repaint of tray icons!!
422 * Normal gtk+ repaint cannot work across different processes.
423 * So, we need some dirty tricks here.
424 */
f37da9d7 425 if( is_tray )
4542c20d
HJYP
426 {
427 gtk_widget_set_size_request( w, w->allocation.width, w->allocation.height );
428 gtk_widget_hide (gtk_bin_get_child((GtkBin*)w));
429 if( gtk_events_pending() )
430 gtk_main_iteration();
431 gtk_widget_show (gtk_bin_get_child((GtkBin*)w));
432 if( gtk_events_pending() )
433 gtk_main_iteration();
434 gtk_widget_set_size_request( w, -1, -1 );
435 }
436}
437
22242ed4 438void plugin_set_background( Plugin* pl, Panel* p )
4542c20d
HJYP
439{
440 if( G_UNLIKELY( pl->class->invisible || ! pl->pwid ) )
441 return;
442 plugin_widget_set_background( pl->pwid, p );
443}