fix crash after click on empty part of panel
[lxde/lxpanel.git] / src / plugin.c
CommitLineData
16fb8c2e 1/**
8c9c4b55 2 * Copyright (c) 2006-2014 LxDE Developers, see the file AUTHORS for details.
a99ee9e1
JH
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
b31cb1d2 23#include "private.h"
a52c2257
HJYP
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>
3b847d8b
AG
35#include <glib/gi18n.h>
36#include <libfm/fm-gtk.h>
a52c2257
HJYP
37
38//#define DEBUG
39#include "dbg.h"
40
2918994e 41static void init_plugin_class_list(void);
2918994e 42static void plugin_class_unref(PluginClass * pc);
239cb032 43
752ee4e2
AG
44GQuark lxpanel_plugin_qinit;
45GQuark lxpanel_plugin_qconf;
17fab6e5
AG
46GQuark lxpanel_plugin_qdata;
47static GHashTable *_all_types = NULL;
48
2918994e 49/* Dynamic parameter for static (built-in) plugins must be FALSE so we will not try to unload them */
9dd114c4 50#define REGISTER_STATIC_PLUGIN_CLASS(pc) \
a52c2257 51do {\
22242ed4 52 extern PluginClass pc;\
9dd114c4 53 register_plugin_class(&pc, FALSE);\
a52c2257
HJYP
54} while (0)
55
10b7f93c
AG
56/* The same for new plugins type - they will be not unloaded by FmModule */
57#define REGISTER_STATIC_MODULE(pc) do { \
58 extern LXPanelPluginInit lxpanel_static_plugin_##pc; \
59 lxpanel_register_plugin_type(#pc, &lxpanel_static_plugin_##pc); } while (0)
60
191694fb 61static inline const LXPanelPluginInit *_find_plugin(const char *name)
17fab6e5
AG
62{
63 return g_hash_table_lookup(_all_types, name);
64}
65
752ee4e2 66static GtkWidget *_old_plugin_config(LXPanel *panel, GtkWidget *instance)
17fab6e5 67{
191694fb 68 const LXPanelPluginInit *init = PLUGIN_CLASS(instance);
17fab6e5
AG
69 Plugin * plugin;
70
131514c9 71 g_return_val_if_fail(init != NULL && init->new_instance == NULL, NULL);
17fab6e5
AG
72 plugin = lxpanel_plugin_get_data(instance);
73 if (plugin->class->config)
752ee4e2 74 plugin->class->config(plugin, GTK_WINDOW(panel));
131514c9 75 return NULL;
17fab6e5
AG
76}
77
a7bd16a4 78static void _old_plugin_reconfigure(LXPanel *panel, GtkWidget *instance)
17fab6e5 79{
191694fb 80 const LXPanelPluginInit *init = PLUGIN_CLASS(instance);
17fab6e5
AG
81 Plugin * plugin;
82
83 g_return_if_fail(init != NULL && init->new_instance == NULL);
84 plugin = lxpanel_plugin_get_data(instance);
85 if (plugin->class->panel_configuration_changed)
86 plugin->class->panel_configuration_changed(plugin);
87}
88
2918994e 89/* Register a PluginClass. */
90static void register_plugin_class(PluginClass * pc, gboolean dynamic)
a52c2257 91{
17fab6e5
AG
92 LXPanelPluginInit *init = g_new0(LXPanelPluginInit, 1);
93 init->_reserved1 = pc;
94 init->name = pc->name;
95 init->description = pc->description;
96 if (pc->config)
97 init->config = _old_plugin_config;
98 if (pc->panel_configuration_changed)
99 init->reconfigure = _old_plugin_reconfigure;
100 init->one_per_system = pc->one_per_system;
101 init->expand_available = pc->expand_available;
102 init->expand_default = pc->expand_default;
a52c2257 103 pc->dynamic = dynamic;
17fab6e5 104 g_hash_table_insert(_all_types, g_strdup(pc->type), init);
a52c2257
HJYP
105}
106
2918994e 107/* Initialize the static plugins. */
108static void init_plugin_class_list(void)
a52c2257 109{
a52c2257 110#ifdef STATIC_SEPARATOR
10b7f93c 111 REGISTER_STATIC_MODULE(separator);
a52c2257 112#endif
bee4c26e 113
56f19a82 114#ifdef STATIC_LAUNCHTASKBAR
6951c204 115 REGISTER_STATIC_MODULE(launchtaskbar);
56f19a82
GP
116#endif
117
a52c2257 118#ifdef STATIC_DCLOCK
8c9c4b55 119 REGISTER_STATIC_MODULE(dclock);
a52c2257 120#endif
bee4c26e 121
a52c2257 122#ifdef STATIC_WINCMD
b8c2e0be 123 REGISTER_STATIC_MODULE(wincmd);
a52c2257
HJYP
124#endif
125
f9dfb60b 126#ifdef STATIC_DIRMENU
de5a8e6c 127 REGISTER_STATIC_MODULE(dirmenu);
a52c2257 128#endif
a52c2257 129
a52c2257 130#ifdef STATIC_PAGER
0c86059b 131 REGISTER_STATIC_MODULE(pager);
a52c2257
HJYP
132#endif
133
134#ifdef STATIC_TRAY
d8eb63e4 135 REGISTER_STATIC_MODULE(tray);
a52c2257
HJYP
136#endif
137
ace2a572 138#ifndef DISABLE_MENU
a52c2257 139#ifdef STATIC_MENU
dd731fde 140 REGISTER_STATIC_MODULE(menu);
a52c2257 141#endif
ace2a572 142#endif
a52c2257
HJYP
143
144#ifdef STATIC_SPACE
c69f8a97 145 REGISTER_STATIC_MODULE(space);
a52c2257 146#endif
a52c2257
HJYP
147}
148
2918994e 149/* Load a dynamic plugin. */
17fab6e5 150static void plugin_load_dynamic(const char * type, const gchar * path)
6a6ad54e 151{
2918994e 152 PluginClass * pc = NULL;
153
154 /* Load the external module. */
155 GModule * m = g_module_open(path, G_MODULE_BIND_LAZY);
156 if (m != NULL)
157 {
158 /* Formulate the name of the expected external variable of type PluginClass. */
159 char class_name[128];
160 g_snprintf(class_name, sizeof(class_name), "%s_plugin_class", type);
161
162 /* Validate that the external variable is of type PluginClass. */
163 gpointer tmpsym;
164 if (( ! g_module_symbol(m, class_name, &tmpsym)) /* Ensure symbol is present */
165 || ((pc = tmpsym) == NULL)
166 || (pc->structure_size != sizeof(PluginClass)) /* Then check versioning information */
167 || (pc->structure_version != PLUGINCLASS_VERSION)
168 || (strcmp(type, pc->type) != 0)) /* Then and only then access other fields; check name */
169 {
170 g_module_close(m);
06e29ce1 171 g_warning("%s.so is not a lxpanel plugin", type);
17fab6e5 172 return;
2918994e 173 }
174
175 /* Register the newly loaded and valid plugin. */
176 pc->gmodule = m;
177 register_plugin_class(pc, TRUE);
17fab6e5 178 pc->count = 1;
6a6ad54e 179 }
a52c2257
HJYP
180}
181
2918994e 182/* Unreference a dynamic plugin. */
183static void plugin_class_unref(PluginClass * pc)
6a6ad54e 184{
2918994e 185 pc->count -= 1;
186
187 /* If the reference count drops to zero, unload the plugin if it is dynamic and has declared itself unloadable. */
188 if ((pc->count == 0)
189 && (pc->dynamic)
190 && ( ! pc->not_unloadable))
191 {
6a6ad54e
HJYP
192 g_module_close(pc->gmodule);
193 }
194}
195
17fab6e5
AG
196/* Loads all available old type plugins. Should be removed in future releases. */
197static void plugin_get_available_classes(void)
6a6ad54e 198{
2918994e 199 /* Initialize static plugins on first call. */
17fab6e5 200 init_plugin_class_list();
6a6ad54e
HJYP
201
202#ifndef DISABLE_PLUGINS_LOADING
2918994e 203 GDir * dir = g_dir_open(PACKAGE_LIB_DIR "/lxpanel/plugins", 0, NULL);
204 if (dir != NULL)
205 {
206 const char * file;
207 while ((file = g_dir_read_name(dir)) != NULL)
208 {
209 if (g_str_has_suffix(file, ".so"))
210 {
211 char * type = g_strndup(file, strlen(file) - 3);
17fab6e5 212 if (_find_plugin(type) == NULL)
2918994e 213 {
214 /* If it has not been loaded, do it. If successful, add it to the result. */
215 char * path = g_build_filename(PACKAGE_LIB_DIR "/lxpanel/plugins", file, NULL );
17fab6e5 216 plugin_load_dynamic(type, path);
2918994e 217 g_free(path);
6a6ad54e 218 }
2918994e 219 g_free(type);
6a6ad54e 220 }
6a6ad54e 221 }
2918994e 222 g_dir_close(dir);
6a6ad54e
HJYP
223 }
224#endif
16fb8c2e 225}
4542c20d 226
2918994e 227/* Recursively set the background of all widgets on a panel background configuration change. */
a7bd16a4 228void plugin_widget_set_background(GtkWidget * w, LXPanel * panel)
4542c20d 229{
2918994e 230 if (w != NULL)
4542c20d 231 {
a7bd16a4 232 Panel *p = panel->priv;
09fa171b 233 if (gtk_widget_get_has_window(w))
4542c20d 234 {
2918994e 235 if ((p->background) || (p->transparent))
236 {
09fa171b
AG
237#if GTK_CHECK_VERSION(2, 20, 0)
238 if (gtk_widget_get_realized(w))
239#else
2918994e 240 if (GTK_WIDGET_REALIZED(w))
09fa171b 241#endif
964b8b7e 242 {
a7bd16a4 243 _panel_determine_background_pixmap(panel, w);
175f73d1 244 gdk_window_invalidate_rect(gtk_widget_get_window(w), NULL, TRUE);
964b8b7e 245 }
2918994e 246 }
247 else
248 {
249 /* Set background according to the current GTK style. */
250 gtk_widget_set_app_paintable(w, FALSE);
09fa171b
AG
251#if GTK_CHECK_VERSION(2, 20, 0)
252 if (gtk_widget_get_realized(w))
253#else
2918994e 254 if (GTK_WIDGET_REALIZED(w))
09fa171b 255#endif
1a571d96 256 {
175f73d1
AG
257 gdk_window_set_back_pixmap(gtk_widget_get_window(w), NULL, TRUE);
258 gtk_style_set_background(gtk_widget_get_style(w),
259 gtk_widget_get_window(w),
260 GTK_STATE_NORMAL);
1a571d96 261 }
2918994e 262 }
4542c20d 263 }
2918994e 264
964b8b7e 265 /* Special handling to get tray icons redrawn. */
2918994e 266 if (GTK_IS_SOCKET(w))
267 {
268 gtk_widget_hide(w);
964b8b7e 269 gdk_window_process_all_updates();
2918994e 270 gtk_widget_show(w);
964b8b7e 271 gdk_window_process_all_updates();
2918994e 272 }
4542c20d 273
2918994e 274 /* Recursively process all children of a container. */
275 if (GTK_IS_CONTAINER(w))
a7bd16a4 276 gtk_container_foreach(GTK_CONTAINER(w), (GtkCallback) plugin_widget_set_background, panel);
4542c20d
HJYP
277 }
278}
279
9dd114c4 280/* Handler for "button_press_event" signal with Plugin as parameter.
281 * External so can be used from a plugin. */
ffdd4b7b 282static gboolean lxpanel_plugin_button_press_event(GtkWidget *plugin, GdkEventButton *event, LXPanel *panel)
9dd114c4 283{
1639d6b3
AG
284 if (event->button == 3 && /* right button */
285 (event->state & gtk_accelerator_get_default_mod_mask()) == 0) /* no key */
9dd114c4 286 {
e56f2fdd 287 GtkMenu* popup = (GtkMenu*)lxpanel_get_plugin_menu(panel, plugin, FALSE);
9dd114c4 288 gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
289 return TRUE;
17fab6e5 290 }
9dd114c4 291 return FALSE;
4542c20d 292}
2918994e 293
17fab6e5
AG
294/* for old plugins compatibility */
295gboolean plugin_button_press_event(GtkWidget *widget, GdkEventButton *event, Plugin *plugin)
296{
e56f2fdd 297 return lxpanel_plugin_button_press_event(plugin->pwid, event, PLUGIN_PANEL(plugin->pwid));
17fab6e5
AG
298}
299
2918994e 300/* Helper for position-calculation callback for popup menus. */
a7bd16a4 301void lxpanel_plugin_popup_set_position_helper(LXPanel * p, GtkWidget * near, GtkWidget * popup, gint * px, gint * py)
2918994e 302{
2918994e 303 gint x, y;
175f73d1 304 GtkAllocation allocation;
d9523b89 305 GtkAllocation popup_req;
d6101d43
AG
306
307 /* Get the allocation of the popup menu. */
d9523b89
AG
308 gtk_widget_realize(popup);
309 gtk_widget_get_allocation(popup, &popup_req);
50aa486e
AG
310 if (gtk_widget_is_toplevel(popup))
311 {
312 GdkRectangle extents;
313 /* FIXME: can we wait somehow for WM drawing decorations? */
d9523b89 314 gdk_window_process_all_updates();
50aa486e
AG
315 gdk_window_get_frame_extents(gtk_widget_get_window(popup), &extents);
316 popup_req.width = extents.width;
317 popup_req.height = extents.height;
318 }
175f73d1 319
d6101d43 320 /* Get the origin of the requested-near widget in screen coordinates. */
175f73d1
AG
321 gtk_widget_get_allocation(near, &allocation);
322 gdk_window_get_origin(gtk_widget_get_window(near), &x, &y);
d9523b89
AG
323 if (!gtk_widget_get_has_window(near))
324 {
325 /* For non-window widgets allocation is given within the screen */
326 x += allocation.x;
327 y += allocation.y;
328 }
2918994e 329
330 /* Dispatch on edge to lay out the popup menu with respect to the button.
331 * Also set "push-in" to avoid any case where it might flow off screen. */
a7bd16a4 332 switch (p->priv->edge)
2918994e 333 {
175f73d1 334 case EDGE_TOP: y += allocation.height; break;
d6101d43 335 case EDGE_BOTTOM: y -= popup_req.height; break;
175f73d1 336 case EDGE_LEFT: x += allocation.width; break;
d6101d43 337 case EDGE_RIGHT: x -= popup_req.width; break;
2918994e 338 }
d6101d43
AG
339
340 /* Push onscreen. */
341 int screen_width = gdk_screen_width();
342 int screen_height = gdk_screen_height();
d9523b89
AG
343 x = CLAMP(x, 0, screen_width - popup_req.width);
344 y = CLAMP(y, 0, screen_height - popup_req.height);
345 /* FIXME: take monitor area into account not just screen */
d6101d43 346
2918994e 347 *px = x;
348 *py = y;
349}
4ec924bc 350
d6101d43 351/* for old plugins compatibility -- popup_req is ignored here */
17fab6e5
AG
352void plugin_popup_set_position_helper(Plugin * p, GtkWidget * near, GtkWidget * popup, GtkRequisition * popup_req, gint * px, gint * py)
353{
a7bd16a4 354 lxpanel_plugin_popup_set_position_helper(p->panel->topgwin, near, popup, px, py);
17fab6e5
AG
355}
356
4ec924bc
MJ
357/* Adjust the position of a popup window to ensure that it is not hidden by the panel.
358 * It is observed that some window managers do not honor the strut that is set on the panel. */
17fab6e5 359void lxpanel_plugin_adjust_popup_position(GtkWidget * popup, GtkWidget * parent)
4ec924bc 360{
d9523b89 361 gint x, y;
4ec924bc 362
d9523b89
AG
363 /* Calculate desired position for the popup. */
364 lxpanel_plugin_popup_set_position_helper(PLUGIN_PANEL(parent), parent,
365 popup, &x, &y);
4ec924bc 366 /* Move the popup to position. */
175f73d1 367 gdk_window_move(gtk_widget_get_window(popup), x, y);
4ec924bc 368}
17fab6e5
AG
369
370/* for old plugins compatibility */
371void plugin_adjust_popup_position(GtkWidget * popup, Plugin * plugin)
372{
373 lxpanel_plugin_adjust_popup_position(popup, plugin->pwid);
374}
375
3b847d8b
AG
376/* Open a specified path in a file manager. */
377static gboolean _open_dir_in_file_manager(GAppLaunchContext* ctx, GList* folder_infos,
378 gpointer user_data, GError** err)
379{
380 FmFileInfo *fi = folder_infos->data; /* only first is used */
381 GAppInfo *app = g_app_info_get_default_for_type("inode/directory", TRUE);
382 GFile *gf;
383 gboolean ret;
384
385 if (app == NULL)
386 {
387 g_set_error_literal(err, G_SHELL_ERROR, G_SHELL_ERROR_EMPTY_STRING,
388 _("No file manager is configured."));
389 return FALSE;
390 }
391 gf = fm_path_to_gfile(fm_file_info_get_path(fi));
392 folder_infos = g_list_prepend(NULL, gf);
393 ret = fm_app_info_launch(app, folder_infos, ctx, err);
394 g_list_free(folder_infos);
395 g_object_unref(gf);
396 g_object_unref(app);
397 return ret;
398}
399
a7bd16a4 400gboolean lxpanel_launch_path(LXPanel *panel, FmPath *path)
3b847d8b
AG
401{
402 return fm_launch_path_simple(NULL, NULL, path, _open_dir_in_file_manager, NULL);
403}
404
2f1173de 405void lxpanel_plugin_show_config_dialog(GtkWidget* plugin)
131514c9 406{
191694fb 407 const LXPanelPluginInit *init = PLUGIN_CLASS(plugin);
a7bd16a4
AG
408 LXPanel *panel = PLUGIN_PANEL(plugin);
409 GtkWidget *dlg = panel->priv->plugin_pref_dialog;
131514c9
AG
410
411 if (dlg && g_object_get_data(G_OBJECT(dlg), "generic-config-plugin") == plugin)
412 return; /* configuration dialog is already shown for this widget */
2f1173de 413 g_return_if_fail(panel != NULL);
752ee4e2 414 dlg = init->config(panel, plugin);
131514c9
AG
415 if (dlg)
416 _panel_show_config_dialog(panel, plugin, dlg);
417}
418
17fab6e5
AG
419#if GLIB_CHECK_VERSION(2, 32, 0)
420static GRecMutex _mutex;
421#else
422static GStaticRecMutex _mutex = G_STATIC_REC_MUTEX_INIT;
423#endif
424
8dfa5918 425#ifndef DISABLE_PLUGINS_LOADING
17fab6e5
AG
426FM_MODULE_DEFINE_TYPE(lxpanel_gtk, LXPanelPluginInit, 1)
427
428static gboolean fm_module_callback_lxpanel_gtk(const char *name, gpointer init, int ver)
429{
430 /* ignore ver for now, only 1 exists */
431 return lxpanel_register_plugin_type(name, init);
432}
8dfa5918 433#endif
17fab6e5
AG
434
435static gboolean old_plugins_loaded = FALSE;
436
437void _prepare_modules(void)
438{
439 _all_types = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
440 lxpanel_plugin_qdata = g_quark_from_static_string("LXPanel::plugin-data");
441 lxpanel_plugin_qinit = g_quark_from_static_string("LXPanel::plugin-init");
442 lxpanel_plugin_qconf = g_quark_from_static_string("LXPanel::plugin-conf");
8dfa5918 443#ifndef DISABLE_PLUGINS_LOADING
17fab6e5
AG
444 fm_modules_add_directory(PACKAGE_LIB_DIR "/lxpanel/plugins");
445 fm_module_register_lxpanel_gtk();
8dfa5918 446#endif
17fab6e5
AG
447}
448
449void _unload_modules(void)
450{
451 GHashTableIter iter;
452 gpointer key, val;
453
17fab6e5
AG
454 g_hash_table_iter_init(&iter, _all_types);
455 while(g_hash_table_iter_next(&iter, &key, &val))
456 {
191694fb 457 register const LXPanelPluginInit *init = val;
17fab6e5
AG
458 if (init->new_instance == NULL) /* old type of plugin */
459 {
460 plugin_class_unref(init->_reserved1);
461 g_free(val);
462 }
463 }
464 g_hash_table_destroy(_all_types);
d6ca4fc5
AG
465#ifndef DISABLE_PLUGINS_LOADING
466 fm_module_unregister_type("lxpanel_gtk");
467#endif
17fab6e5
AG
468 old_plugins_loaded = FALSE;
469}
470
191694fb 471gboolean lxpanel_register_plugin_type(const char *name, const LXPanelPluginInit *init)
17fab6e5 472{
191694fb 473 const LXPanelPluginInit *data;
17fab6e5
AG
474
475 /* validate it */
476 if (init->new_instance == NULL || name == NULL || name[0] == '\0')
477 return FALSE;
478#if GLIB_CHECK_VERSION(2, 32, 0)
479 g_rec_mutex_lock(&_mutex);
480#else
481 g_static_rec_mutex_lock(&_mutex);
482#endif
483 /* test if it's registered already */
484 data = _find_plugin(name);
485 if (data == NULL)
486 {
487 if (init->init)
488 init->init();
191694fb 489 g_hash_table_insert(_all_types, g_strdup(name), (gpointer)init);
17fab6e5
AG
490 }
491#if GLIB_CHECK_VERSION(2, 32, 0)
492 g_rec_mutex_unlock(&_mutex);
493#else
494 g_static_rec_mutex_unlock(&_mutex);
495#endif
496 return (data == NULL);
497}
498
499static void _old_plugin_save_hook(const config_setting_t * setting, FILE * f, gpointer user_data)
500{
501 Plugin *pl = user_data;
502 PluginClass *pc = pl->class;
503 if (pc->save)
504 pc->save(pl, f);
505}
506
507/* This is called right before Plugin instance is destroyed */
508static void _old_plugin_destroy(gpointer data)
509{
510 Plugin *pl = data;
511
17fab6e5
AG
512 plugin_class_unref(pl->class);
513
514 /* Free the Plugin structure. */
515 g_free(pl);
516}
517
fcbe8a69
AG
518static void _on_old_widget_destroy(GtkWidget *widget, Plugin *pl)
519{
520 /* Never let run it again. */
521 g_signal_handlers_disconnect_by_func(widget, _on_old_widget_destroy, pl);
522 /* Run the destructor before destroying the top level widget.
523 * This prevents problems with the plugin destroying child widgets. */
524 pl->class->destructor(pl);
525}
526
a7bd16a4 527//static void on_size_allocate(GtkWidget *widget, GdkRectangle *allocation, LXPanel *p)
de5a8e6c
AG
528//{
529// _queue_panel_calculate_size(p);
530//}
531
a7bd16a4 532GtkWidget *lxpanel_add_plugin(LXPanel *p, const char *name, config_setting_t *cfg, gint at)
17fab6e5 533{
191694fb 534 const LXPanelPluginInit *init;
17fab6e5 535 GtkWidget *widget;
761af06c 536 config_setting_t *s, *pconf;
17fab6e5
AG
537 gint expand, padding = 0, border = 0, i;
538
539 CHECK_MODULES();
540 if (!old_plugins_loaded)
541 plugin_get_available_classes();
542 old_plugins_loaded = TRUE;
543 init = _find_plugin(name);
544 if (init == NULL)
545 return NULL;
546 /* prepare widget settings */
547 if (!init->expand_available)
548 expand = 0;
549 else if ((s = config_setting_get_member(cfg, "expand")))
550 expand = config_setting_get_int(s);
551 else
552 expand = init->expand_default;
553 s = config_setting_get_member(cfg, "padding");
554 if (s)
555 padding = config_setting_get_int(s);
556 s = config_setting_get_member(cfg, "border");
557 if (s)
558 border = config_setting_get_int(s);
559 /* prepare config and create it if need */
560 s = config_setting_add(cfg, "", PANEL_CONF_TYPE_LIST);
761af06c
AG
561 for (i = 0; (pconf = config_setting_get_elem(s, i)); i++)
562 if (strcmp(config_setting_get_name(pconf), "Config") == 0)
17fab6e5 563 break;
761af06c
AG
564 if (!pconf)
565 pconf = config_setting_add(s, "Config", PANEL_CONF_TYPE_GROUP);
17fab6e5
AG
566 /* If this plugin can only be instantiated once, count the instantiation.
567 * This causes the configuration system to avoid displaying the plugin as one that can be added. */
568 if (init->new_instance) /* new style of plugin */
569 {
761af06c 570 widget = init->new_instance(p, pconf);
17fab6e5
AG
571 if (widget == NULL)
572 return widget;
1639d6b3
AG
573 /* always connect lxpanel_plugin_button_press_event() */
574 g_signal_connect(widget, "button-press-event",
575 G_CALLBACK(lxpanel_plugin_button_press_event), p);
e56f2fdd
AG
576 if (init->button_press_event)
577 g_signal_connect(widget, "button-press-event",
578 G_CALLBACK(init->button_press_event), p);
17fab6e5
AG
579 }
580 else
581 {
582 Plugin *pl = g_new0(Plugin, 1);
583 PluginClass *pc = init->_reserved1;
761af06c 584 char *conf = config_setting_to_string(pconf), *fp;
17fab6e5
AG
585
586 pl->class = pc;
a7bd16a4 587 pl->panel = p->priv;
17fab6e5
AG
588 widget = NULL;
589 fp = &conf[9]; /* skip "Config {\n" */
590 /* g_debug("created conf: %s",conf); */
591 /* Call the constructor.
592 * It is responsible for parsing the parameters, and setting "pwid" to the top level widget. */
593 if (pc->constructor(pl, &fp))
594 widget = pl->pwid;
595 g_free(conf);
596
597 if (widget == NULL) /* failed */
598 {
599 g_free(pl);
600 return widget;
601 }
602
603 pc->count += 1;
fcbe8a69 604 g_signal_connect(widget, "destroy", G_CALLBACK(_on_old_widget_destroy), pl);
761af06c 605 config_setting_set_save_hook(pconf, _old_plugin_save_hook, pl);
17fab6e5
AG
606 lxpanel_plugin_set_data(widget, pl, _old_plugin_destroy);
607 }
1e6368db 608 gtk_widget_set_name(widget, name);
a7bd16a4 609 gtk_box_pack_start(GTK_BOX(p->priv->box), widget, expand, TRUE, padding);
17fab6e5 610 gtk_container_set_border_width(GTK_CONTAINER(widget), border);
de5a8e6c 611// g_signal_connect(widget, "size-allocate", G_CALLBACK(on_size_allocate), p);
17fab6e5
AG
612 gtk_widget_show(widget);
613 g_object_set_qdata(G_OBJECT(widget), lxpanel_plugin_qconf, cfg);
191694fb 614 g_object_set_qdata(G_OBJECT(widget), lxpanel_plugin_qinit, (gpointer)init);
17fab6e5
AG
615 return widget;
616}
617
618/* transfer none - note that not all fields are valid there */
619GHashTable *lxpanel_get_all_types(void)
620{
621 return _all_types;
622}