New plugins API implementation. Works. Need thorough testing yet.
authorAndriy Grytsenko <andrej@rep.kiev.ua>
Sun, 2 Feb 2014 22:55:29 +0000 (00:55 +0200)
committerAndriy Grytsenko <andrej@rep.kiev.ua>
Tue, 4 Feb 2014 00:57:57 +0000 (02:57 +0200)
src/conf.c
src/conf.h
src/configurator.c
src/misc.c
src/panel.c
src/plugin.c
src/plugin.h [new file with mode: 0644]
src/private.h

index bee9285..27261b4 100644 (file)
 
 #include "conf.h"
 
+#include <string.h>
+#include <stdlib.h>
+
 struct _config_setting_t
 {
     config_setting_t *next;
     config_setting_t *parent;
     PanelConfType type;
     PanelConfSaveHook hook;
+    gpointer hook_data;
     char *name;
     union {
         gint num; /* for integer or boolean */
@@ -115,6 +119,7 @@ PanelConf *config_new(void)
 {
     PanelConf *c = g_slice_new(PanelConf);
     c->root = _config_setting_t_new(NULL, -1, NULL, PANEL_CONF_TYPE_GROUP);
+    return c;
 }
 
 void config_destroy(PanelConf * config)
@@ -167,23 +172,26 @@ _skip_all:
                 *c++ = '\0';
             else
             {
-                g_warning("invalid scalar definition");
+                g_warning("config: invalid scalar definition");
                 goto _skip_all;
             }
-            while (*c && *c != ' ' && *c != '\t' && *c != '\n')
+            while (*c == ' ' || *c == '\t')
                 c++; /* skip spaces after '=' */
-            if (name == NULL || *c == '\0' || *c != '\n') /* invalid statement */
+            if (name == NULL || *c == '\0' || *c == '\n') /* invalid statement */
                 break;
             size = strtol(c, &end, 10);
-            while (*end && *end != ' ' && *end != '\t' && *end != '\n')
+            while (*end == ' ' || *end == '\t')
                 c++; /* skip trailing spaces */
             if (*end == '\0' || *end == '\n')
             {
                 s = config_setting_add(parent, name, PANEL_CONF_TYPE_INT);
                 if (s)
+                {
                     s->num = (int)size;
+                    /* g_debug("config loader: got new int %s: %d", name, s->num); */
+                }
                 else
-                    g_warning("duplicate setting '%s' conflicts, ignored", name);
+                    g_warning("config: duplicate setting '%s' conflicts, ignored", name);
             }
             else
             {
@@ -194,9 +202,10 @@ _skip_all:
                 {
                     g_free(s->str);
                     s->str = g_strndup(c, end - c);
+                    /* g_debug("config loader: got new string %s: %s", name, s->str); */
                 }
                 else
-                    g_warning("duplicate setting '%s' conflicts, ignored", name);
+                    g_warning("config: duplicate setting '%s' conflicts, ignored", name);
             }
             c = end;
             break;
@@ -213,10 +222,10 @@ _skip_all:
             if (s)
             {
                 parent = s;
-                g_debug("group '%s' added", name);
+                /* g_debug("config loader: group '%s' added", name); */
             }
             else
-                g_warning("invalid group '%s' in config file ignored", name);
+                g_warning("config: invalid group '%s' in config file ignored", name);
             name = NULL;
             break;
         case '}':
@@ -258,12 +267,12 @@ static void _config_write_setting(const config_setting_t *setting, GString *buf,
         {
             g_string_append(out, buf->str);
             g_string_append(out, setting->name);
-            g_string_append(out, "{\n");
+            g_string_append(out, " {\n");
         }
         else
             fprintf(f, "%s%s {\n", buf->str, setting->name);
         if (!out && setting->hook) /* plugin does not support settings */
-            setting->hook(setting, f);
+            setting->hook(setting, f, setting->hook_data);
         else
         {
             g_string_append(buf, SETTING_INDENT);
@@ -305,7 +314,8 @@ gboolean config_write_file(PanelConf * config, const char * filename)
     GString *str;
     if (f == NULL)
         return FALSE;
-    str = g_string_sized_new(128);
+    str = g_string_new("# lxpanel <profile> config file. Manually editing is not recommended.\n"
+                       "# Use preference dialog in lxpanel to adjust config when you can.\n\n");
     _config_write_setting(config->root, str, NULL, f);
     /* FIXME: handle errors */
     fclose(f);
@@ -330,27 +340,42 @@ config_setting_t * config_root_setting(const PanelConf * config)
     return config->root;
 }
 
-config_setting_t * config_setting_get_member(const config_setting_t * setting, const char * name)
+static inline config_setting_t * _config_setting_get_member(const config_setting_t * setting, const char * name)
 {
     config_setting_t *s;
-    g_return_val_if_fail(name && setting, FALSE);
-    g_return_val_if_fail(setting->type == PANEL_CONF_TYPE_GROUP, FALSE);
     for (s = setting->first; s; s = s->next)
-        if (strcmp(s->name, s) == 0)
+        if (g_strcmp0(s->name, name) == 0)
             break;
     return s;
 }
 
+config_setting_t * config_setting_get_member(const config_setting_t * setting, const char * name)
+{
+    g_return_val_if_fail(name && setting, NULL);
+    g_return_val_if_fail(setting->type == PANEL_CONF_TYPE_GROUP, NULL);
+    return _config_setting_get_member(setting, name);
+}
+
 config_setting_t * config_setting_get_elem(const config_setting_t * setting, unsigned int index)
 {
     config_setting_t *s;
-    g_return_val_if_fail(setting, FALSE);
-    g_return_val_if_fail(setting->type == PANEL_CONF_TYPE_LIST || setting->type == PANEL_CONF_TYPE_GROUP, FALSE);
+    g_return_val_if_fail(setting, NULL);
+    g_return_val_if_fail(setting->type == PANEL_CONF_TYPE_LIST || setting->type == PANEL_CONF_TYPE_GROUP, NULL);
     for (s = setting->first; s && index > 0; s = s->next)
         index--;
     return s;
 }
 
+const char * config_setting_get_name(const config_setting_t * setting)
+{
+    return setting->name;
+}
+
+config_setting_t * config_setting_get_parent(const config_setting_t * setting)
+{
+    return setting->parent;
+}
+
 int config_setting_get_int(const config_setting_t * setting)
 {
     if (!setting || setting->type != PANEL_CONF_TYPE_INT)
@@ -361,7 +386,7 @@ int config_setting_get_int(const config_setting_t * setting)
 const char * config_setting_get_string(const config_setting_t * setting)
 {
     if (!setting || setting->type != PANEL_CONF_TYPE_STRING)
-        return 0;
+        return NULL;
     return setting->str;
 }
 
@@ -380,20 +405,12 @@ config_setting_t * config_setting_add(config_setting_t * parent, const char * na
     else if (name == NULL || name[0] == '\0')
         /* other types should be not anonymous */
         return NULL;
-    else if ((s = config_setting_get_member(parent, name)))
+    if (parent->type == PANEL_CONF_TYPE_GROUP &&
+        (s = _config_setting_get_member(parent, name)))
         return (s->type == type) ? s : NULL;
     return _config_setting_t_new(parent, -1, name, type);
 }
 
-config_setting_t * config_setting_insert_elem(config_setting_t * parent, int index, PanelConfType type)
-{
-    if (parent == NULL || parent->type != PANEL_CONF_TYPE_LIST)
-        return NULL;
-    if (type != PANEL_CONF_TYPE_GROUP) /* we support only list of groups now */
-        return NULL;
-    return _config_setting_t_new(parent, index, NULL, type);
-}
-
 gboolean config_setting_move_member(config_setting_t * setting, config_setting_t * parent, const char * name)
 {
     config_setting_t *s;
@@ -401,7 +418,7 @@ gboolean config_setting_move_member(config_setting_t * setting, config_setting_t
     g_return_val_if_fail(setting && setting->parent, FALSE);
     if (parent == NULL || name == NULL || parent->type != PANEL_CONF_TYPE_GROUP)
         return FALSE;
-    s = config_setting_get_member(parent, name);
+    s = _config_setting_get_member(parent, name);
     if (s) /* we cannot rename/move to this name, it exists already */
         return (s == setting);
     if (setting->parent == parent) /* it's just renaming thing */
@@ -526,12 +543,22 @@ gboolean config_setting_remove_elem(config_setting_t * parent, unsigned int inde
     return TRUE;
 }
 
+gboolean config_setting_destroy(config_setting_t * setting)
+{
+    if (setting == NULL || setting->parent == NULL)
+        return FALSE;
+    _config_setting_t_remove(setting);
+    return TRUE;
+}
+
 PanelConfType config_setting_type(const config_setting_t * setting)
 {
     return setting->type;
 }
 
-void config_setting_set_save_hook(config_setting_t * setting, PanelConfSaveHook hook)
+void config_setting_set_save_hook(config_setting_t * setting, PanelConfSaveHook hook,
+                                  gpointer user_data)
 {
     setting->hook = hook;
+    setting->hook_data = user_data;
 }
index 9b10b16..41272dc 100644 (file)
@@ -43,7 +43,7 @@ typedef enum
     PANEL_CONF_TYPE_LIST
 } PanelConfType;
 
-typedef void (*PanelConfSaveHook)(const config_setting_t * setting, FILE * f);
+typedef void (*PanelConfSaveHook)(const config_setting_t * setting, FILE * f, gpointer user_data);
 
 PanelConf *config_new(void);
 void config_destroy(PanelConf * config);
@@ -54,12 +54,13 @@ char * config_setting_to_string(const config_setting_t * setting);
 config_setting_t * config_root_setting(const PanelConf * config);
 config_setting_t * config_setting_get_member(const config_setting_t * setting, const char * name);
 config_setting_t * config_setting_get_elem(const config_setting_t * setting, unsigned int index);
+const char * config_setting_get_name(const config_setting_t * setting);
+config_setting_t * config_setting_get_parent(const config_setting_t * setting);
 
 int config_setting_get_int(const config_setting_t * setting);
 const char * config_setting_get_string(const config_setting_t * setting);
 
 config_setting_t * config_setting_add(config_setting_t * parent, const char * name, PanelConfType type);
-config_setting_t * config_setting_insert_elem(config_setting_t * parent, int index, PanelConfType type);
 
 gboolean config_setting_move_member(config_setting_t * setting, config_setting_t * parent, const char * name);
 gboolean config_setting_move_elem(config_setting_t * setting, config_setting_t * parent, int index);
@@ -68,6 +69,7 @@ gboolean config_setting_set_int(config_setting_t * setting, int value);
 gboolean config_setting_set_string(config_setting_t * setting, const char * value);
 gboolean config_setting_remove(config_setting_t * parent, const char * name);
 gboolean config_setting_remove_elem(config_setting_t * parent, unsigned int index);
+gboolean config_setting_destroy(config_setting_t * setting);
 
 PanelConfType config_setting_type(const config_setting_t * setting);
 #define config_setting_is_group(_s) config_setting_type(_s) == PANEL_CONF_TYPE_GROUP
@@ -76,7 +78,7 @@ PanelConfType config_setting_type(const config_setting_t * setting);
         (config_setting_type(_s) == PANEL_CONF_TYPE_INT || \
          config_setting_type(_s) == PANEL_CONF_TYPE_STRING)
 
-void config_setting_set_save_hook(config_setting_t * setting, PanelConfSaveHook hook);
+void config_setting_set_save_hook(config_setting_t * setting, PanelConfSaveHook hook, gpointer user_data);
 
 G_END_DECLS
 
index ab298c7..9f5e8a2 100644 (file)
@@ -65,6 +65,28 @@ extern GSList* all_panels;
 extern gchar *cprofile;
 extern int config;
 
+/* macros to update config */
+#define UPDATE_GLOBAL_INT(panel,name,val) do { \
+    config_setting_t *_s = config_setting_add(config_setting_get_elem(config_setting_get_member(config_root_setting(panel->config),""),\
+                                                                      0),\
+                                              name,PANEL_CONF_TYPE_INT);\
+    if (_s) config_setting_set_int(_s,val); } while(0)
+
+#define UPDATE_GLOBAL_STRING(panel,name,val) do { \
+    config_setting_t *_s = config_setting_add(config_setting_get_elem(config_setting_get_member(config_root_setting(panel->config),""),\
+                                                                      0),\
+                                              name,PANEL_CONF_TYPE_STRING);\
+    if (_s) config_setting_set_string(_s,val); } while(0)
+
+#define UPDATE_GLOBAL_COLOR(panel,name,val) do { \
+    config_setting_t *_s = config_setting_add(config_setting_get_elem(config_setting_get_member(config_root_setting(panel->config),""),\
+                                                                      0),\
+                                              name,PANEL_CONF_TYPE_INT);\
+    if (_s) { \
+        char _c[8];\
+        snprintf(_c, sizeof(_c), "#%06x",val);\
+        config_setting_set_string(_s,_c); } } while(0)
+
 /* GtkColotButton expects a number between 0 and 65535, but p->alpha has range
  * 0 to 255, and (2^(2n) - 1) / (2^n - 1) = 2^n + 1 = 257, with n = 8. */
 static guint16 const alpha_scale_factor = 257;
@@ -133,7 +155,7 @@ static void set_edge(Panel* p, int edge)
 {
     p->edge = edge;
     update_panel_geometry(p);
-    panel_set_panel_configuration_changed(p);
+    UPDATE_GLOBAL_STRING(p, "edge", num2str(edge_pair, edge, "none"));
 }
 
 static void edge_bottom_toggle(GtkToggleButton *widget, Panel *p)
@@ -165,6 +187,7 @@ static void set_monitor(GtkAdjustment *widget, Panel *p)
     p->monitor = gtk_adjustment_get_value(widget);
     update_panel_geometry(p);
     panel_set_panel_configuration_changed(p);
+    UPDATE_GLOBAL_INT(p, "monitor", p->monitor);
 }
 
 static void set_alignment(Panel* p, int align)
@@ -173,6 +196,7 @@ static void set_alignment(Panel* p, int align)
         gtk_widget_set_sensitive(p->margin_control, (align != ALLIGN_CENTER));
     p->allign = align;
     update_panel_geometry(p);
+    UPDATE_GLOBAL_STRING(p, "allign", num2str(allign_pair, align, "none"));
 }
 
 static void align_left_toggle(GtkToggleButton *widget, Panel *p)
@@ -198,6 +222,7 @@ set_margin( GtkSpinButton* spin,  Panel* p  )
 {
     p->margin = (int)gtk_spin_button_get_value(spin);
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "margin", p->margin);
 }
 
 static void
@@ -205,6 +230,7 @@ set_width(  GtkSpinButton* spin, Panel* p )
 {
     p->width = (int)gtk_spin_button_get_value(spin);
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "width", p->width);
 }
 
 static void
@@ -212,6 +238,7 @@ set_height( GtkSpinButton* spin, Panel* p )
 {
     p->height = (int)gtk_spin_button_get_value(spin);
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "height", p->height);
 }
 
 static void set_width_type( GtkWidget *item, Panel* p )
@@ -246,8 +273,11 @@ static void set_width_type( GtkWidget *item, Panel* p )
         return;
 
     update_panel_geometry(p);
+    UPDATE_GLOBAL_STRING(p, "widthtype", num2str(width_pair, widthtype, "none"));
 }
 
+/* FIXME: heighttype and spacing and RoundCorners */
+
 static void set_log_level( GtkWidget *cbox, Panel* p)
 {
     configured_log_level = gtk_combo_box_get_active(GTK_COMBO_BOX(cbox));
@@ -255,6 +285,7 @@ static void set_log_level( GtkWidget *cbox, Panel* p)
         log_level = configured_log_level;
     ERR("panel-pref: log level configured to %d, log_level is now %d\n",
             configured_log_level, log_level);
+    UPDATE_GLOBAL_INT(p, "loglevel", configured_log_level);
 }
 
 static void transparency_toggle( GtkWidget *b, Panel* p)
@@ -275,6 +306,8 @@ static void transparency_toggle( GtkWidget *b, Panel* p)
         p->transparent = 1;
         p->background = 0;
         panel_update_background( p );
+        UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
+        UPDATE_GLOBAL_INT(p, "background", p->background);
     }
     RET();
 }
@@ -286,6 +319,7 @@ static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser
     {
         g_free(p->background_file);
         p->background_file = file;
+        UPDATE_GLOBAL_STRING(p, "backgroundfile", p->background_file);
     }
 
     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
@@ -295,6 +329,8 @@ static void background_file_helper(Panel * p, GtkWidget * toggle, GtkFileChooser
             p->transparent = FALSE;
             p->background = TRUE;
             panel_update_background(p);
+            UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
+            UPDATE_GLOBAL_INT(p, "background", p->background);
         }
     }
 }
@@ -322,6 +358,8 @@ background_disable_toggle( GtkWidget *b, Panel* p )
             p->transparent = 0;
             /* Update background immediately. */
             panel_update_background( p );
+            UPDATE_GLOBAL_INT(p, "transparent", p->transparent);
+            UPDATE_GLOBAL_INT(p, "background", p->background);
         }
     }
 
@@ -333,6 +371,8 @@ on_font_color_set( GtkColorButton* clr,  Panel* p )
 {
     gtk_color_button_get_color( clr, &p->gfontcolor );
     panel_set_panel_configuration_changed(p);
+    p->fontcolor = gcolor2rgb24(&p->gfontcolor);
+    UPDATE_GLOBAL_COLOR(p, "fontcolor", p->fontcolor);
 }
 
 static void
@@ -342,6 +382,8 @@ on_tint_color_set( GtkColorButton* clr,  Panel* p )
     p->tintcolor = gcolor2rgb24(&p->gtintcolor);
     p->alpha = gtk_color_button_get_alpha( clr ) / alpha_scale_factor;
     panel_update_background( p );
+    UPDATE_GLOBAL_COLOR(p, "tintcolor", p->tintcolor);
+    UPDATE_GLOBAL_INT(p, "alpha", p->alpha);
 }
 
 static void
@@ -354,6 +396,7 @@ on_use_font_color_toggled( GtkToggleButton* btn,   Panel* p )
         gtk_widget_set_sensitive( clr, FALSE );
     p->usefontcolor = gtk_toggle_button_get_active( btn );
     panel_set_panel_configuration_changed(p);
+    UPDATE_GLOBAL_INT(p, "usefontcolor", p->usefontcolor);
 }
 
 static void
@@ -361,6 +404,7 @@ on_font_size_set( GtkSpinButton* spin, Panel* p )
 {
     p->fontsize = (int)gtk_spin_button_get_value(spin);
     panel_set_panel_configuration_changed(p);
+    UPDATE_GLOBAL_INT(p, "fontsize", p->fontsize);
 }
 
 static void
@@ -373,6 +417,7 @@ on_use_font_size_toggled( GtkToggleButton* btn,   Panel* p )
         gtk_widget_set_sensitive( clr, FALSE );
     p->usefontsize = gtk_toggle_button_get_active( btn );
     panel_set_panel_configuration_changed(p);
+    UPDATE_GLOBAL_INT(p, "usefontsize", p->usefontsize);
 }
 
 
@@ -382,6 +427,7 @@ set_dock_type(GtkToggleButton* toggle,  Panel* p )
     p->setdocktype = gtk_toggle_button_get_active(toggle) ? 1 : 0;
     panel_set_dock_type( p );
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "setdocktype", p->setdocktype);
 }
 
 static void
@@ -389,6 +435,7 @@ set_strut(GtkToggleButton* toggle,  Panel* p )
 {
     p->setstrut = gtk_toggle_button_get_active(toggle) ? 1 : 0;
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "setpartialstrut", p->setstrut);
 }
 
 static void
@@ -396,6 +443,7 @@ set_autohide(GtkToggleButton* toggle,  Panel* p )
 {
     p->autohide = gtk_toggle_button_get_active(toggle) ? 1 : 0;
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "autohide", p->autohide);
 }
 
 static void
@@ -403,6 +451,7 @@ set_height_when_minimized( GtkSpinButton* spin,  Panel* p  )
 {
     p->height_when_hidden = (int)gtk_spin_button_get_value(spin);
     update_panel_geometry(p);
+    UPDATE_GLOBAL_INT(p, "heightwhenhidden", p->height_when_hidden);
 }
 
 static void
@@ -410,6 +459,7 @@ set_icon_size( GtkSpinButton* spin,  Panel* p  )
 {
     p->icon_size = (int)gtk_spin_button_get_value(spin);
     panel_set_panel_configuration_changed(p);
+    UPDATE_GLOBAL_INT(p, "iconsize", p->icon_size);
 }
 
 static void
@@ -417,15 +467,17 @@ on_sel_plugin_changed( GtkTreeSelection* tree_sel, GtkWidget* label )
 {
     GtkTreeIter it;
     GtkTreeModel* model;
-    Plugin* pl;
+    GtkWidget* pl;
 
     if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
     {
         GtkTreeView* view = gtk_tree_selection_get_tree_view( tree_sel );
         GtkWidget *edit_btn = GTK_WIDGET(g_object_get_data( G_OBJECT(view), "edit_btn" ));
+        LXPanelPluginInit *init;
         gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
-        gtk_label_set_text( GTK_LABEL(label), _(pl->class->description) );
-        gtk_widget_set_sensitive( edit_btn, pl->class->config != NULL );
+        init = PLUGIN_CLASS(pl);
+        gtk_label_set_text( GTK_LABEL(label), _(init->description) );
+        gtk_widget_set_sensitive( edit_btn, init->config != NULL );
     }
 }
 
@@ -438,24 +490,27 @@ on_plugin_expand_toggled(GtkCellRendererToggle* render, char* path, GtkTreeView*
     model = gtk_tree_view_get_model( view );
     if( gtk_tree_model_get_iter( model, &it, tp ) )
     {
-        Plugin* pl;
+        GtkWidget* pl;
         gboolean old_expand, expand, fill;
         guint padding;
         GtkPackType pack_type;
+        LXPanelPluginInit *init;
+        Panel *panel;
 
         gtk_tree_model_get( model, &it, COL_DATA, &pl, COL_EXPAND, &expand, -1 );
+        init = PLUGIN_CLASS(pl);
+        panel = PLUGIN_PANEL(pl);
 
-        if (pl->class->expand_available)
+        if (init->expand_available)
         {
             /* Only honor "stretch" if allowed by the plugin. */
             expand = ! expand;
-            pl->expand = expand;
             gtk_list_store_set( GTK_LIST_STORE(model), &it, COL_EXPAND, expand, -1 );
 
             /* Query the old packing of the plugin widget.
              * Apply the new packing with only "expand" modified. */
-            gtk_box_query_child_packing( GTK_BOX(pl->panel->box), pl->pwid, &old_expand, &fill, &padding, &pack_type );
-            gtk_box_set_child_packing( GTK_BOX(pl->panel->box), pl->pwid, expand, fill, padding, pack_type );
+            gtk_box_query_child_packing( GTK_BOX(panel->box), pl, &old_expand, &fill, &padding, &pack_type );
+            gtk_box_set_child_packing( GTK_BOX(panel->box), pl, expand, fill, padding, pack_type );
         }
     }
     gtk_tree_path_free( tp );
@@ -465,10 +520,10 @@ static void on_stretch_render(GtkTreeViewColumn * column, GtkCellRenderer * rend
 {
     /* Set the control visible depending on whether stretch is available for the plugin.
      * The g_object_set method is touchy about its parameter, so we can't pass the boolean directly. */
-    Plugin * pl;
+    GtkWidget * pl;
     gtk_tree_model_get(model, iter, COL_DATA, &pl, -1);
     g_object_set(renderer,
-        "visible", ((pl->class->expand_available) ? TRUE : FALSE),
+        "visible", ((PLUGIN_CLASS(pl)->expand_available) ? TRUE : FALSE),
         NULL);
 }
 
@@ -478,7 +533,7 @@ static void init_plugin_list( Panel* p, GtkTreeView* view, GtkWidget* label )
     GtkTreeViewColumn* col;
     GtkCellRenderer* render;
     GtkTreeSelection* tree_sel;
-    GListl;
+    GList *plugins, *l;
     GtkTreeIter it;
 
     g_object_set_data( G_OBJECT(view), "panel", p );
@@ -501,17 +556,21 @@ static void init_plugin_list( Panel* p, GtkTreeView* view, GtkWidget* label )
     gtk_tree_view_append_column( view, col );
 
     list = gtk_list_store_new( N_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER );
-    for( l = p->plugins; l; l = l->next )
+    plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
+    for( l = plugins; l; l = l->next )
     {
         GtkTreeIter it;
-        Plugin* pl = (Plugin*)l->data;
+        gboolean expand;
+        GtkWidget *w = (GtkWidget*)l->data;
+        gtk_container_child_get(GTK_CONTAINER(p->box), w, "expand", &expand, NULL);
         gtk_list_store_append( list, &it );
         gtk_list_store_set( list, &it,
-                            COL_NAME, _(pl->class->name),
-                            COL_EXPAND, pl->expand,
-                            COL_DATA, pl,
+                            COL_NAME, _(PLUGIN_CLASS(w)->name),
+                            COL_EXPAND, expand,
+                            COL_DATA, w,
                             -1);
     }
+    g_list_free(plugins);
     gtk_tree_view_set_model( view, GTK_TREE_MODEL( list ) );
     g_signal_connect( view, "row-activated",
                       G_CALLBACK(modify_plugin), NULL );
@@ -557,31 +616,27 @@ static void on_add_plugin_response( GtkDialog* dlg,
         if( gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
         {
             char* type = NULL;
-            Plugin* pl;
+            GtkWidget *pl;
+            config_setting_t *cfg;
+            config_setting_t *s = config_setting_get_member(config_root_setting(p->config), "");
+            cfg = config_setting_add(s, "Plugin", PANEL_CONF_TYPE_GROUP);
             gtk_tree_model_get( model, &it, 1, &type, -1 );
-            if ((pl = plugin_load(type)) != NULL)
+            s = config_setting_add(cfg, "type", PANEL_CONF_TYPE_STRING);
+            config_setting_set_string(s, type);
+            if ((pl = lxpanel_add_plugin(p, type, cfg, -1)))
             {
                 GtkTreePath* tree_path;
+                gboolean expand;
 
-                pl->panel = p;
-                if (pl->class->expand_default) pl->expand = TRUE;
-                plugin_start( pl, NULL );
-                p->plugins = g_list_append(p->plugins, pl);
                 panel_config_save(p);
 
-                if (pl->pwid)
-                {
-                    gtk_widget_show(pl->pwid);
-
-                    /* update background of the newly added plugin */
-                    plugin_widget_set_background( pl->pwid, pl->panel );
-                }
-
+                plugin_widget_set_background(pl, p);
+                gtk_container_child_get(GTK_CONTAINER(p->box), pl, "expand", &expand, NULL);
                 model = gtk_tree_view_get_model( _view );
                 gtk_list_store_append( GTK_LIST_STORE(model), &it );
                 gtk_list_store_set( GTK_LIST_STORE(model), &it,
-                                    COL_NAME, _(pl->class->name),
-                                    COL_EXPAND, pl->expand,
+                                    COL_NAME, _(PLUGIN_CLASS(pl)->name),
+                                    COL_EXPAND, expand,
                                     COL_DATA, pl, -1 );
                 tree_sel = gtk_tree_view_get_selection( _view );
                 gtk_tree_selection_select_iter( tree_sel, &it );
@@ -591,26 +646,39 @@ static void on_add_plugin_response( GtkDialog* dlg,
                     gtk_tree_path_free( tree_path );
                 }
             }
+            else /* free unused setting */
+                config_setting_destroy(cfg);
             g_free( type );
         }
     }
     gtk_widget_destroy( GTK_WIDGET(dlg) );
 }
 
+static gboolean _class_is_present(LXPanelPluginInit *init, GList *p)
+{
+    for ( ; p; p = p->next)
+        if (PLUGIN_CLASS(p->data) == init)
+            return TRUE;
+    return FALSE;
+}
+
 static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
 {
     GtkWidget* dlg, *parent_win, *scroll;
-    GList* classes;
-    GList* tmp;
+    GHashTable *classes;
+    GList *plugins;
     GtkTreeViewColumn* col;
     GtkCellRenderer* render;
     GtkTreeView* view;
     GtkListStore* list;
     GtkTreeSelection* tree_sel;
+    GHashTableIter iter;
+    gpointer key, val;
 
     Panel* p = (Panel*) g_object_get_data( G_OBJECT(_view), "panel" );
 
-    classes = plugin_get_available_classes();
+    classes = lxpanel_get_all_types();
+    plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
 
     parent_win = gtk_widget_get_toplevel( GTK_WIDGET(_view) );
     dlg = gtk_dialog_new_with_buttons( _("Add plugin to panel"),
@@ -651,15 +719,18 @@ static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
 
     /* Populate list of available plugins.
      * Omit plugins that can only exist once per system if it is already configured. */
-    for( tmp = classes; tmp; tmp = tmp->next ) {
-        PluginClass* pc = (PluginClass*)tmp->data;
-        if (( ! pc->one_per_system ) || ( ! pc->one_per_system_instantiated))
+    g_hash_table_iter_init(&iter, classes);
+    while(g_hash_table_iter_next(&iter, &key, &val))
+    {
+        register LXPanelPluginInit *init = val;
+        if (!init->one_per_system || !_class_is_present(init, plugins))
         {
             GtkTreeIter it;
             gtk_list_store_append( list, &it );
+            /* it is safe to put classes data here - they will be valid until restart */
             gtk_list_store_set( list, &it,
-                                0, _(pc->name),
-                                1, pc->type,
+                                0, _(init->name),
+                                1, key,
                                 -1 );
             /* g_debug( "%s (%s)", pc->type, _(pc->name) ); */
         }
@@ -678,7 +749,7 @@ static void on_add_plugin( GtkButton* btn, GtkTreeView* _view )
                       G_CALLBACK(on_add_plugin_row_activated), (gpointer) dlg);
 
     g_object_set_data( G_OBJECT(dlg), "avail-plugins", view );
-    g_object_weak_ref( G_OBJECT(dlg), (GWeakNotify) plugin_class_list_free, classes );
+    g_list_free(plugins);
 
     gtk_window_set_default_size( GTK_WINDOW(dlg), 320, 400 );
     gtk_widget_show_all( dlg );
@@ -690,7 +761,7 @@ static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
     GtkTreePath* tree_path;
     GtkTreeModel* model;
     GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
-    Plugin* pl;
+    GtkWidget* pl;
 
     Panel* p = (Panel*) g_object_get_data( G_OBJECT(view), "panel" );
 
@@ -704,8 +775,10 @@ static void on_remove_plugin( GtkButton* btn, GtkTreeView* view )
         gtk_tree_selection_select_path( tree_sel, tree_path );
         gtk_tree_path_free( tree_path );
 
-        p->plugins = g_list_remove( p->plugins, pl );
-        plugin_delete(pl);
+        config_setting_destroy(g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf));
+        /* reset conf pointer because the widget still may be referenced by configurator */
+        g_object_set_qdata(G_OBJECT(pl), lxpanel_plugin_qconf, NULL);
+        gtk_widget_destroy(pl);
         panel_config_save(p);
     }
 }
@@ -715,34 +788,28 @@ void modify_plugin( GtkTreeView* view )
     GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
     GtkTreeModel* model;
     GtkTreeIter it;
-    Plugin* pl;
+    GtkWidget* pl;
+    LXPanelPluginInit *init;
 
     if( ! gtk_tree_selection_get_selected( tree_sel, &model, &it ) )
         return;
 
     gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
-    if( pl->class->config )
-        pl->class->config( pl, GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))) );
+    init = PLUGIN_CLASS(pl);
+    if (init->config)
+        init->config(PLUGIN_PANEL(pl), pl, GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(view))));
 }
 
-static int get_widget_index(    Panel* p, Plugin* pl )
+static int get_widget_index(Panel* p, GtkWidget* pl)
 {
-    GList* l;
-    int i;
-    for( i = 0, l = p->plugins; l; l = l->next )
-    {
-        Plugin* _pl = (Plugin*)l->data;
-        if( _pl == pl )
-            return i;
-        if( _pl->pwid )
-            ++i;
-    }
-    return -1;
+    GList *plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
+    int i = g_list_index(plugins, pl);
+    g_list_free(plugins);
+    return i;
 }
 
 static void on_moveup_plugin(  GtkButton* btn, GtkTreeView* view )
 {
-    GList *l;
     GtkTreeIter it, prev;
     GtkTreeModel* model = gtk_tree_view_get_model( view );
     GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
@@ -757,24 +824,18 @@ static void on_moveup_plugin(  GtkButton* btn, GtkTreeView* view )
     do{
         if( gtk_tree_selection_iter_is_selected(tree_sel, &it) )
         {
-            Plugin* pl;
+            GtkWidget* pl;
+            config_setting_t *s;
             gtk_tree_model_get( model, &it, COL_DATA, &pl, -1 );
             gtk_list_store_move_before( GTK_LIST_STORE( model ),
                                         &it, &prev );
 
-            i = 0;
-            for( l = panel->plugins; l; l = l->next, ++i )
-            {
-                if( l->data == pl  )
-                {
-                    panel->plugins = g_list_insert( panel->plugins, pl, i - 1);
-                    panel->plugins = g_list_delete_link( panel->plugins, l);
-                }
-            }
-            if( pl->pwid )
-            {
-                gtk_box_reorder_child( GTK_BOX(panel->box), pl->pwid, get_widget_index( panel, pl ) );
-            }
+            i = get_widget_index(panel, pl);
+            s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
+            /* reorder in config, 0 is Global */
+            config_setting_move_elem(s, config_setting_get_parent(s), i);
+            /* reorder in panel */
+            gtk_box_reorder_child(GTK_BOX(panel->box), pl, i - 1);
             panel_config_save(panel);
             return;
         }
@@ -784,11 +845,11 @@ static void on_moveup_plugin(  GtkButton* btn, GtkTreeView* view )
 
 static void on_movedown_plugin(  GtkButton* btn, GtkTreeView* view )
 {
-    GList *l;
     GtkTreeIter it, next;
     GtkTreeModel* model;
     GtkTreeSelection* tree_sel = gtk_tree_view_get_selection( view );
-    Plugin* pl;
+    GtkWidget* pl;
+    config_setting_t *s;
     int i;
 
     Panel* panel = (Panel*) g_object_get_data( G_OBJECT(view), "panel" );
@@ -804,19 +865,12 @@ static void on_movedown_plugin(  GtkButton* btn, GtkTreeView* view )
 
     gtk_list_store_move_after( GTK_LIST_STORE( model ), &it, &next );
 
-    i = 0;
-    for( l = panel->plugins; l; l = l->next, ++i )
-    {
-        if( l->data == pl  )
-        {
-            panel->plugins = g_list_insert( panel->plugins, pl, i + 2);
-            panel->plugins = g_list_delete_link( panel->plugins, l);
-        }
-    }
-    if( pl->pwid )
-    {
-        gtk_box_reorder_child( GTK_BOX(panel->box), pl->pwid, get_widget_index( panel, pl ) );
-    }
+    i = get_widget_index(panel, pl) + 1;
+    s = g_object_get_qdata(G_OBJECT(pl), lxpanel_plugin_qconf);
+    /* reorder in config, 0 is Global */
+    config_setting_move_elem(s, config_setting_get_parent(s), i + 1);
+    /* reorder in panel */
+    gtk_box_reorder_child(GTK_BOX(panel->box), pl, i);
     panel_config_save(panel);
 }
 
@@ -1123,67 +1177,9 @@ void panel_configure( Panel* p, int sel_page )
     g_object_unref(builder);
 }
 
-void
-panel_global_config_save( Panel* p, FILE *fp)
-{
-    fprintf(fp, "# lxpanel <profile> config file. Manually editing is not recommended.\n"
-                "# Use preference dialog in lxpanel to adjust config when you can.\n\n");
-    lxpanel_put_line(fp, "Global {");
-    lxpanel_put_str(fp, "edge", num2str(edge_pair, p->edge, "none"));
-    lxpanel_put_int(fp, "monitor", p->monitor);
-    lxpanel_put_str(fp, "allign", num2str(allign_pair, p->allign, "none"));
-    lxpanel_put_int(fp, "margin", p->margin);
-    lxpanel_put_str(fp, "widthtype", num2str(width_pair, p->widthtype, "none"));
-    lxpanel_put_int(fp, "width", p->width);
-    lxpanel_put_int(fp, "height", p->height);
-    lxpanel_put_bool(fp, "transparent", p->transparent );
-    lxpanel_put_line(fp, "tintcolor=#%06x", gcolor2rgb24(&p->gtintcolor));
-    lxpanel_put_int(fp, "alpha", p->alpha);
-    lxpanel_put_bool(fp, "autohide", p->autohide);
-    lxpanel_put_int(fp, "heightwhenhidden", p->height_when_hidden);
-    lxpanel_put_bool(fp, "setdocktype", p->setdocktype);
-    lxpanel_put_bool(fp, "setpartialstrut", p->setstrut);
-    lxpanel_put_bool(fp, "usefontcolor", p->usefontcolor);
-    lxpanel_put_int(fp, "fontsize", p->fontsize);
-    lxpanel_put_line(fp, "fontcolor=#%06x", gcolor2rgb24(&p->gfontcolor));
-    lxpanel_put_bool(fp, "usefontsize", p->usefontsize);
-    lxpanel_put_bool(fp, "background", p->background );
-    lxpanel_put_str(fp, "backgroundfile", p->background_file);
-    lxpanel_put_int(fp, "iconsize", p->icon_size);
-    lxpanel_put_int(fp, "loglevel", configured_log_level);
-    lxpanel_put_line(fp, "}\n");
-}
-
-void
-panel_plugin_config_save( Panel* p, FILE *fp)
-{
-    GList* l;
-    for( l = p->plugins; l; l = l->next )
-    {
-        Plugin* pl = (Plugin*)l->data;
-        lxpanel_put_line( fp, "Plugin {" );
-        lxpanel_put_line( fp, "type = %s", pl->class->type );
-        if( pl->expand )
-            lxpanel_put_bool( fp, "expand", TRUE );
-        if( pl->padding > 0 )
-            lxpanel_put_int( fp, "padding", pl->padding );
-        if( pl->border > 0 )
-            lxpanel_put_int( fp, "border", pl->border );
-
-        if( pl->class->save )
-        {
-            lxpanel_put_line( fp, "Config {" );
-            pl->class->save( pl, fp );
-            lxpanel_put_line( fp, "}" );
-        }
-        lxpanel_put_line( fp, "}\n" );
-    }
-}
-
 void panel_config_save( Panel* p )
 {
     gchar *fname, *dir;
-    FILE *fp;
 
     dir = get_config_file( cprofile, "panels", FALSE );
     fname = g_build_filename( dir, p->name, NULL );
@@ -1193,15 +1189,11 @@ void panel_config_save( Panel* p )
         g_mkdir_with_parents( dir, 0755 );
     g_free( dir );
 
-    if (!(fp = fopen(fname, "w"))) {
+    if (!config_write_file(p->config, fname)) {
         ERR("can't open for write %s:", fname);
         g_free( fname );
-        perror(NULL);
         RET();
     }
-    panel_global_config_save(p, fp);
-    panel_plugin_config_save(p, fp);
-    fclose(fp);
     g_free( fname );
 
     /* save the global config file */
index 266ab22..0f09810 100644 (file)
@@ -205,7 +205,7 @@ pair pos_pair[] = {
 
 
 int
-str2num(pair *p, gchar *str, int defval)
+str2num(pair *p, const gchar *str, int defval)
 {
     ENTER;
     for (;p && p->str; p++) {
@@ -215,8 +215,8 @@ str2num(pair *p, gchar *str, int defval)
     RET(defval);
 }
 
-gchar *
-num2str(pair *p, int num, gchar *defval)
+const gchar *
+num2str(pair *p, int num, const gchar *defval)
 {
     ENTER;
     for (;p && p->str; p++) {
@@ -534,8 +534,8 @@ char **
 get_utf8_property_list(Window win, Atom atom, int *count)
 {
     Atom type;
-    int format, i;
-    gulong nitems;
+    int format;
+    gulong nitems, i;
     gulong bytes_after;
     gchar *s, **retval = NULL;
     int result;
@@ -556,7 +556,7 @@ get_utf8_property_list(Window win, Atom atom, int *count)
                 (*count)++;
         }
         retval = g_new0 (char*, *count + 2);
-        for (i = 0, s = val; i < *count; i++, s = s +  strlen (s) + 1) {
+        for (i = 0, s = val; (int)i < *count; i++, s = s +  strlen (s) + 1) {
             retval[i] = g_strdup(s);
         }
         if (val[nitems-1]) {
index 0bc9fb2..68f6340 100644 (file)
@@ -52,7 +52,7 @@ GSList* all_panels = NULL;  /* a single-linked list storing all panels */
 
 gboolean is_restarting = FALSE;
 
-static int panel_start( Panel *p, char **fp );
+static int panel_start(Panel *p);
 static void panel_start_gui(Panel *p);
 void panel_config_save(Panel* panel);   /* defined in configurator.c */
 
@@ -112,6 +112,7 @@ static Panel* panel_allocate(void)
     p->spacing = 0;
     p->icon_size = PANEL_ICON_SIZE;
     p->icon_theme = gtk_icon_theme_get_default();
+    p->config = config_new();
     return p;
 }
 
@@ -442,20 +443,18 @@ void panel_determine_background_pixmap(Panel * p, GtkWidget * widget, GdkWindow
  * This function should only be called after the panel has been realized. */
 void panel_update_background(Panel * p)
 {
+    GList *plugins, *l;
+
     /* Redraw the top level widget. */
     panel_determine_background_pixmap(p, p->topgwin, p->topgwin->window);
     gdk_window_clear(p->topgwin->window);
     gtk_widget_queue_draw(p->topgwin);
 
     /* Loop over all plugins redrawing each plugin. */
-    GList * l;
-    for (l = p->plugins; l != NULL; l = l->next)
-    {
-        Plugin * pl = (Plugin *) l->data;
-        if (pl->pwid != NULL)
-            plugin_widget_set_background(pl->pwid, p);
-    }
-
+    plugins = gtk_container_get_children(GTK_CONTAINER(p->box));
+    for (l = plugins; l != NULL; l = l->next)
+        plugin_widget_set_background(l->data, p);
+    g_list_free(plugins);
 }
 
 static gboolean delay_update_background( Panel* p )
@@ -555,19 +554,22 @@ static gboolean panel_button_press_event_with_panel(GtkWidget *widget, GdkEventB
 {
     if (event->button == 3)     /* right button */
     {
-        GtkMenu* popup = (GtkMenu*) lxpanel_get_panel_menu(panel, NULL, FALSE);
+        GtkMenu* popup = (GtkMenu*) lxpanel_get_plugin_menu(panel, NULL, FALSE);
         gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
         return TRUE;
     }    
     return FALSE;
 }
 
-static void panel_popupmenu_config_plugin( GtkMenuItem* item, Plugin* plugin )
+static void panel_popupmenu_config_plugin( GtkMenuItem* item, GtkWidget* plugin )
 {
-    plugin->class->config( plugin, GTK_WINDOW(plugin->panel->topgwin) );
+    LXPanelPluginInit *init = PLUGIN_CLASS(plugin);
+    Panel *panel = PLUGIN_PANEL(plugin);
+
+    init->config(panel, plugin, GTK_WINDOW(panel->topgwin));
 
     /* FIXME: this should be more elegant */
-    plugin->panel->config_changed = TRUE;
+    panel->config_changed = TRUE;
 }
 
 static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
@@ -576,9 +578,9 @@ static void panel_popupmenu_add_item( GtkMenuItem* item, Panel* panel )
     panel_configure( panel, 2 );
 }
 
-static void panel_popupmenu_remove_item( GtkMenuItem* item, Plugin* plugin )
+static void panel_popupmenu_remove_item( GtkMenuItem* item, GtkWidget* plugin )
 {
-    Panel* panel = plugin->panel;
+    Panel* panel = PLUGIN_PANEL(plugin);
 
     /* If the configuration dialog is open, there will certainly be a crash if the
      * user manipulates the Configured Plugins list, after we remove this entry.
@@ -588,10 +590,12 @@ static void panel_popupmenu_remove_item( GtkMenuItem* item, Plugin* plugin )
         gtk_widget_destroy(panel->pref_dialog);
         panel->pref_dialog = NULL;
     }
+    config_setting_destroy(g_object_get_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf));
+    /* reset conf pointer because the widget still may be referenced by configurator */
+    g_object_set_qdata(G_OBJECT(plugin), lxpanel_plugin_qconf, NULL);
 
-    panel->plugins = g_list_remove( panel->plugins, plugin );
-    panel_config_save( plugin->panel );
-    plugin_delete(plugin);
+    panel_config_save(panel);
+    gtk_widget_destroy(plugin);
 }
 
 /* FIXME: Potentially we can support multiple panels at the same edge,
@@ -651,6 +655,7 @@ static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
         }
     }
 
+    panel_destroy(new_panel);
     ERR("Error adding panel: There is no room for another panel. All the edges are taken.\n");
     err = gtk_message_dialog_new(NULL,0,GTK_MESSAGE_ERROR,GTK_BUTTONS_OK,_("There is no room for another panel. All the edges are taken."));
     gtk_dialog_run(GTK_DIALOG(err));
@@ -660,6 +665,10 @@ static void panel_popupmenu_create_panel( GtkMenuItem* item, Panel* panel )
 found_edge:
     new_panel->name = gen_panel_name(new_panel->edge,new_panel->monitor);
 
+    /* create new config with first group "Global" */
+    config_setting_add(config_setting_add(config_root_setting(new_panel->config),
+                                          "", PANEL_CONF_TYPE_LIST),
+                       "Global", PANEL_CONF_TYPE_GROUP);
     panel_configure(new_panel, 0);
     panel_normalize_configuration(new_panel);
     panel_start_gui(new_panel);
@@ -764,11 +773,11 @@ void panel_apply_icon( GtkWindow *w )
     gtk_window_set_icon(w, window_icon);
 }
 
-GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
+GtkMenu* lxpanel_get_plugin_menu( Panel* panel, GtkWidget* plugin, gboolean use_sub_menu )
 {
     GtkWidget  *menu_item, *img;
     GtkMenu *ret,*menu;
-    
+    LXPanelPluginInit *init = PLUGIN_CLASS(plugin);
     char* tmp;
     ret = menu = GTK_MENU(gtk_menu_new());
 
@@ -781,7 +790,7 @@ GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_
     if( plugin )
     {
         img = gtk_image_new_from_stock( GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU );
-        tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(plugin->class->name) );
+        tmp = g_strdup_printf( _("Remove \"%s\" From Panel"), _(init->name) );
         menu_item = gtk_image_menu_item_new_with_label( tmp );
         g_free( tmp );
         gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
@@ -837,12 +846,12 @@ GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_
         gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
 
         img = gtk_image_new_from_stock( GTK_STOCK_PREFERENCES, GTK_ICON_SIZE_MENU );
-        tmp = g_strdup_printf( _("\"%s\" Settings"), _(plugin->class->name) );
+        tmp = g_strdup_printf( _("\"%s\" Settings"), _(init->name) );
         menu_item = gtk_image_menu_item_new_with_label( tmp );
         g_free( tmp );
         gtk_image_menu_item_set_image( (GtkImageMenuItem*)menu_item, img );
         gtk_menu_shell_prepend(GTK_MENU_SHELL(ret), menu_item);
-        if( plugin->class->config )
+        if( init->config )
             g_signal_connect( menu_item, "activate", G_CALLBACK(panel_popupmenu_config_plugin), plugin );
         else
             gtk_widget_set_sensitive( menu_item, FALSE );
@@ -854,6 +863,12 @@ GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_
     return ret;
 }
 
+/* for old plugins compatibility */
+GtkMenu* lxpanel_get_panel_menu( Panel* panel, Plugin* plugin, gboolean use_sub_menu )
+{
+    return lxpanel_get_plugin_menu(panel, plugin->pwid, use_sub_menu);
+}
+
 /****************************************************
  *         panel creation                           *
  ****************************************************/
@@ -1177,7 +1192,7 @@ void panel_draw_label_text(Panel * p, GtkWidget * label, char * text, gboolean b
 
 void panel_set_panel_configuration_changed(Panel *p)
 {
-    GListl;
+    GList *plugins, *l;
 
     int previous_orientation = p->orientation;
     p->orientation = (p->edge == EDGE_TOP || p->edge == EDGE_BOTTOM)
@@ -1228,94 +1243,94 @@ void panel_set_panel_configuration_changed(Panel *p)
        This is used when the orientation of the panel is changed
        from the config dialog, and plugins should be re-layout.
     */
-    for( l = p->plugins; l; l = l->next ) {
-        Plugin* pl = (Plugin*)l->data;
-        if( pl->class->panel_configuration_changed ) {
-            pl->class->panel_configuration_changed( pl );
-        }
+    plugins = p->box ? gtk_container_get_children(GTK_CONTAINER(p->box)) : NULL;
+    for( l = plugins; l; l = l->next ) {
+        GtkWidget *w = (GtkWidget*)l->data;
+        LXPanelPluginInit *init = PLUGIN_CLASS(w);
+        if (init->reconfigure)
+            init->reconfigure(p, w);
     }
+    g_list_free(plugins);
 }
 
 static int
-panel_parse_global(Panel *p, char **fp)
+panel_parse_global(Panel *p, config_setting_t *cfg)
 {
-    line s;
-    s.len = 256;
+    config_setting_t *s;
 
-    if( G_LIKELY( fp ) )
+    /* check Global config */
+    if (!cfg || strcmp(config_setting_get_name(cfg), "Global") != 0)
     {
-        while (lxpanel_get_line(fp, &s) != LINE_NONE) {
-            if (s.type == LINE_VAR) {
-                if (!g_ascii_strcasecmp(s.t[0], "edge")) {
-                    p->edge = str2num(edge_pair, s.t[1], EDGE_NONE);
-                } else if (!g_ascii_strcasecmp(s.t[0], "allign")) {
-                    p->allign = str2num(allign_pair, s.t[1], ALLIGN_NONE);
-                } else if (!g_ascii_strcasecmp(s.t[0], "monitor")) {
-                    p->monitor = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "margin")) {
-                    p->margin = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "widthtype")) {
-                    p->widthtype = str2num(width_pair, s.t[1], WIDTH_NONE);
-                } else if (!g_ascii_strcasecmp(s.t[0], "width")) {
-                    p->width = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "heighttype")) {
-                    p->heighttype = str2num(height_pair, s.t[1], HEIGHT_NONE);
-                } else if (!g_ascii_strcasecmp(s.t[0], "height")) {
-                    p->height = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "spacing")) {
-                    p->spacing = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "SetDockType")) {
-                    p->setdocktype = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "SetPartialStrut")) {
-                    p->setstrut = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "RoundCorners")) {
-                    p->round_corners = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "Transparent")) {
-                    p->transparent = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "Alpha")) {
-                    p->alpha = atoi(s.t[1]);
-                    if (p->alpha > 255)
-                        p->alpha = 255;
-                } else if (!g_ascii_strcasecmp(s.t[0], "AutoHide")) {
-                    p->autohide = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "HeightWhenHidden")) {
-                    p->height_when_hidden = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "TintColor")) {
-                    if (!gdk_color_parse (s.t[1], &p->gtintcolor))
-                        gdk_color_parse ("white", &p->gtintcolor);
-                    p->tintcolor = gcolor2rgb24(&p->gtintcolor);
-                    DBG("tintcolor=%x\n", p->tintcolor);
-                } else if (!g_ascii_strcasecmp(s.t[0], "useFontColor")) {
-                    p->usefontcolor = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "FontColor")) {
-                    if (!gdk_color_parse (s.t[1], &p->gfontcolor))
-                        gdk_color_parse ("black", &p->gfontcolor);
-                    p->fontcolor = gcolor2rgb24(&p->gfontcolor);
-                    DBG("fontcolor=%x\n", p->fontcolor);
-                } else if (!g_ascii_strcasecmp(s.t[0], "useFontSize")) {
-                    p->usefontsize = str2num(bool_pair, s.t[1], 0);
-                } else if (!g_ascii_strcasecmp(s.t[0], "FontSize")) {
-                    p->fontsize = atoi(s.t[1]);                    
-                } else if (!g_ascii_strcasecmp(s.t[0], "Background")) {
-                    p->background = str2num(bool_pair, s.t[1], 0);
-                } else if( !g_ascii_strcasecmp(s.t[0], "BackgroundFile") ) {
-                    p->background_file = g_strdup( s.t[1] );
-                } else if (!g_ascii_strcasecmp(s.t[0], "IconSize")) {
-                    p->icon_size = atoi(s.t[1]);
-                } else if (!g_ascii_strcasecmp(s.t[0], "LogLevel")) {
-                    configured_log_level = atoi(s.t[1]);
-                    if (!log_level_set_on_commandline)
-                        log_level = configured_log_level;
-                } else {
-                    ERR( "lxpanel: %s - unknown var in Global section\n", s.t[0]);
-                }
-            } else if (s.type == LINE_BLOCK_END) {
-                break;
-            } else {
-                ERR( "lxpanel: illegal in this context %s\n", s.str);
-                RET(0);
-            }
-        }
+        ERR( "lxpanel: Global section not found\n");
+        RET(0);
+    }
+    if ((s = config_setting_get_member(cfg, "edge")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+        p->edge = str2num(edge_pair, config_setting_get_string(s), EDGE_NONE);
+    if ((s = config_setting_get_member(cfg, "allign")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+        p->allign = str2num(allign_pair, config_setting_get_string(s), ALLIGN_NONE);
+    if ((s = config_setting_get_member(cfg, "monitor")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->monitor = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "margin")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->margin = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "widthtype")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+        p->widthtype = str2num(width_pair, config_setting_get_string(s), WIDTH_NONE);
+    if ((s = config_setting_get_member(cfg, "width")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->width = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "heighttype")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+        p->heighttype = str2num(height_pair, config_setting_get_string(s), HEIGHT_NONE);
+    if ((s = config_setting_get_member(cfg, "height")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->height = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "spacing")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->spacing = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "setdocktype")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->setdocktype = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "setpartialstrut")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->setstrut = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "RoundCorners")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->round_corners = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "transparent")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->transparent = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "alpha")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+    {
+        p->alpha = config_setting_get_int(s);
+        if (p->alpha > 255)
+            p->alpha = 255;
+    }
+    if ((s = config_setting_get_member(cfg, "autohide")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->autohide = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "heightwhenhidden")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->height_when_hidden = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "tintcolor")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+    {
+        if (!gdk_color_parse (config_setting_get_string(s), &p->gtintcolor))
+            gdk_color_parse ("white", &p->gtintcolor);
+        p->tintcolor = gcolor2rgb24(&p->gtintcolor);
+            DBG("tintcolor=%x\n", p->tintcolor);
+    }
+    if ((s = config_setting_get_member(cfg, "usefontcolor")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->usefontcolor = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "fontcolor")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+    {
+        if (!gdk_color_parse (config_setting_get_string(s), &p->gfontcolor))
+            gdk_color_parse ("black", &p->gfontcolor);
+        p->fontcolor = gcolor2rgb24(&p->gfontcolor);
+            DBG("fontcolor=%x\n", p->fontcolor);
+    }
+    if ((s = config_setting_get_member(cfg, "usefontsize")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->usefontsize = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "fontsize")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->fontsize = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "background")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->background = config_setting_get_int(s) != 0;
+    if ((s = config_setting_get_member(cfg, "backgroundfile")) && config_setting_type(s) == PANEL_CONF_TYPE_STRING)
+        p->background_file = g_strdup(config_setting_get_string(s));
+    if ((s = config_setting_get_member(cfg, "iconsize")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+        p->icon_size = config_setting_get_int(s);
+    if ((s = config_setting_get_member(cfg, "loglevel")) && config_setting_type(s) == PANEL_CONF_TYPE_INT)
+    {
+        configured_log_level = config_setting_get_int(s);
+        if (!log_level_set_on_commandline)
+            log_level = configured_log_level;
     }
 
     panel_normalize_configuration(p);
@@ -1324,123 +1339,52 @@ panel_parse_global(Panel *p, char **fp)
 }
 
 static int
-panel_parse_plugin(Panel *p, char **fp)
+panel_parse_plugin(Panel *p, config_setting_t *cfg)
 {
-    line s;
-    Plugin *plug = NULL;
-    gchar *type = NULL;
-    int expand , padding, border;
-    char* pconfig = NULL;
+    config_setting_t *s;
+    const char *type;
 
     ENTER;
-    s.len = 256;
-    border = expand = padding = 0;
-    while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
-        if (s.type == LINE_NONE) {
-            ERR( "lxpanel: bad line %s\n", s.str);
-            goto error;
-        }
-        if (s.type == LINE_VAR) {
-            if (!g_ascii_strcasecmp(s.t[0], "type")) {
-                type = g_strdup(s.t[1]);
-                DBG("plug %s\n", type);
-            } else if (!g_ascii_strcasecmp(s.t[0], "expand"))
-                expand = str2num(bool_pair,  s.t[1], 0);
-            else if (!g_ascii_strcasecmp(s.t[0], "padding"))
-                padding = atoi(s.t[1]);
-            else if (!g_ascii_strcasecmp(s.t[0], "border"))
-                border = atoi(s.t[1]);
-            else {
-                ERR( "lxpanel: unknown var %s\n", s.t[0]);
-            }
-        } else if (s.type == LINE_BLOCK_START) {
-            if (!g_ascii_strcasecmp(s.t[0], "Config")) {
-                pconfig = *fp;
-                int pno = 1;
-                while (pno) {
-                    get_line_as_is(fp, &s);
-                    if (s.type == LINE_NONE) {
-                        ERR( "lxpanel: unexpected eof\n");
-                        goto error;
-                    } else if (s.type == LINE_BLOCK_START) {
-                        pno++;
-                    } else if (s.type == LINE_BLOCK_END) {
-                        pno--;
-                    }
-                }
-            } else {
-                ERR( "lxpanel: unknown block %s\n", s.t[0]);
-                goto error;
-            }
-        } else {
-            ERR( "lxpanel: illegal in this context %s\n", s.str);
-            goto error;
-        }
-    }
+    s = config_setting_get_member(cfg, "type");
+    type = s ? config_setting_get_string(s) : NULL;
+    DBG("plug %s\n", type);
 
-    if (!type || !(plug = plugin_load(type))) {
+    if (!type || lxpanel_add_plugin(p, type, cfg, -1) == NULL) {
         ERR( "lxpanel: can't load %s plugin\n", type);
         goto error;
     }
-
-    plug->panel = p;
-    if (plug->class->expand_available) plug->expand = expand;
-    plug->padding = padding;
-    plug->border = border;
-    DBG("starting\n");
-    if (!plugin_start(plug, pconfig ? &pconfig : NULL)) {
-        ERR( "lxpanel: can't start plugin %s\n", type);
-        goto error;
-    }
-    DBG("plug %s\n", type);
-    p->plugins = g_list_append(p->plugins, plug);
-
-    g_free( type );
     RET(1);
 
- error:
-    if (plug != NULL)
-        plugin_unload(plug);
-    g_free(type);
+error:
     RET(0);
 }
 
-int panel_start( Panel *p, char **fp )
+int panel_start( Panel *p )
 {
-    line s;
+    config_setting_t *list, *s;
+    int i;
 
     /* parse global section */
     ENTER;
-    s.len = 256;
 
-    if ((lxpanel_get_line(fp, &s) != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Global")) {
-        ERR( "lxpanel: config file must start from Global section\n");
-        RET(0);
-    }
-    if (!panel_parse_global(p, fp))
+    list = config_setting_get_member(config_root_setting(p->config), "");
+    if (!list || !panel_parse_global(p, config_setting_get_elem(list, 0)))
         RET(0);
 
     panel_start_gui(p);
 
-    while (lxpanel_get_line(fp, &s) != LINE_NONE) {
-        if ((s.type  != LINE_BLOCK_START) || g_ascii_strcasecmp(s.t[0], "Plugin")) {
-            ERR( "lxpanel: expecting Plugin section\n");
-            RET(0);
-        }
-        panel_parse_plugin(p, fp);
-    }
+    for (i = 1; (s = config_setting_get_elem(list, i)) != NULL; )
+        if (strcmp(config_setting_get_name(s), "Plugin") == 0 &&
+            panel_parse_plugin(p, s)) /* success on plugin start */
+            i++;
+        else /* remove invalid data from config */
+            config_setting_remove_elem(list, i);
 
     /* update backgrond of panel and all plugins */
     panel_update_background( p );
     return 1;
 }
 
-static void
-delete_plugin(gpointer data, gpointer udata)
-{
-    plugin_delete((Plugin *)data);
-}
-
 void panel_destroy(Panel *p)
 {
     ENTER;
@@ -1461,20 +1405,18 @@ void panel_destroy(Panel *p)
 
     if( p->config_changed )
         panel_config_save( p );
-
-    g_list_foreach(p->plugins, delete_plugin, NULL);
-    g_list_free(p->plugins);
-    p->plugins = NULL;
+    config_destroy(p->config);
 
     if( p->system_menus ){
         do{
         } while ( g_source_remove_by_user_data( p->system_menus ) );
     }
 
-    gtk_window_group_remove_window( win_grp, GTK_WINDOW(  p->topgwin ) );
-
     if( p->topgwin )
+    {
+        gtk_window_group_remove_window( win_grp, GTK_WINDOW(  p->topgwin ) );
         gtk_widget_destroy(p->topgwin);
+    }
     g_free(p->workarea);
     g_free( p->background_file );
     g_slist_free( p->system_menus );
@@ -1489,26 +1431,18 @@ void panel_destroy(Panel *p)
 
 Panel* panel_new( const char* config_file, const char* config_name )
 {
-    char *fp, *pfp; /* point to current position of profile data in memory */
     Panel* panel = NULL;
 
-    if( G_LIKELY(config_file) )
+    if (G_LIKELY(config_file))
     {
-        g_file_get_contents( config_file, &fp, NULL, NULL );
-        if( fp )
+        panel = panel_allocate();
+        g_debug("starting panel from file %s",config_file);
+        if (!config_read_file(panel->config, config_file) ||
+            !panel_start(panel))
         {
-            panel = panel_allocate();
-            panel->orientation = ORIENT_NONE;
-            panel->name = g_strdup( config_name );
-            pfp = fp;
-
-            if (! panel_start( panel, &pfp )) {
-                ERR( "lxpanel: can't start panel\n");
-                panel_destroy( panel );
-                panel = NULL;
-            }
-
-            g_free( fp );
+            ERR( "lxpanel: can't start panel\n");
+            panel_destroy( panel );
+            panel = NULL;
         }
     }
     return panel;
@@ -1658,7 +1592,6 @@ int main(int argc, char *argv[], char *env[])
        gdk_threads_enter();
 
     gtk_init(&argc, &argv);
-    fm_gtk_init(NULL);
 
 #ifdef ENABLE_NLS
     bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
@@ -1724,6 +1657,12 @@ int main(int argc, char *argv[], char *env[])
 restart:
     is_restarting = FALSE;
 
+    /* init LibFM */
+    fm_gtk_init(NULL);
+
+    /* prepare modules data */
+    _prepare_modules();
+
     load_global_config();
 
        /* NOTE: StructureNotifyMask is required by XRandR
@@ -1753,11 +1692,13 @@ restart:
 
     free_global_config();
 
+    _unload_modules();
+    fm_gtk_finalize();
+
     if( is_restarting )
         goto restart;
 
     gdk_threads_leave();
-    fm_gtk_finalize();
 
     g_object_unref(win_grp);
     g_object_unref(fbev);
index 128a778..80e3ef5 100644 (file)
 //#define DEBUG
 #include "dbg.h"
 
-static GList * pcl = NULL;                     /* List of PluginClass structures */
-
 static void register_plugin_class(PluginClass * pc, gboolean dynamic);
 static void init_plugin_class_list(void);
-static PluginClass * plugin_find_class(const char * type);
-static PluginClass * plugin_load_dynamic(const char * type, const gchar * path);
 static void plugin_class_unref(PluginClass * pc);
 
+GQuark lxpanel_plugin_qdata;
+static GHashTable *_all_types = NULL;
+
 /* Dynamic parameter for static (built-in) plugins must be FALSE so we will not try to unload them */
 #define REGISTER_STATIC_PLUGIN_CLASS(pc) \
 do {\
@@ -51,11 +50,49 @@ do {\
     register_plugin_class(&pc, FALSE);\
 } while (0)
 
+static inline LXPanelPluginInit *_find_plugin(const char *name)
+{
+    return g_hash_table_lookup(_all_types, name);
+}
+
+static void _old_plugin_config(Panel *panel, GtkWidget *instance, GtkWindow *parent)
+{
+    LXPanelPluginInit *init = PLUGIN_CLASS(instance);
+    Plugin * plugin;
+
+    g_return_if_fail(init != NULL && init->new_instance == NULL);
+    plugin = lxpanel_plugin_get_data(instance);
+    if (plugin->class->config)
+        plugin->class->config(plugin, parent);
+}
+
+static void _old_plugin_reconfigure(Panel *panel, GtkWidget *instance)
+{
+    LXPanelPluginInit *init = PLUGIN_CLASS(instance);
+    Plugin * plugin;
+
+    g_return_if_fail(init != NULL && init->new_instance == NULL);
+    plugin = lxpanel_plugin_get_data(instance);
+    if (plugin->class->panel_configuration_changed)
+        plugin->class->panel_configuration_changed(plugin);
+}
+
 /* Register a PluginClass. */
 static void register_plugin_class(PluginClass * pc, gboolean dynamic)
 {
-    pcl = g_list_append(pcl, pc);
+    LXPanelPluginInit *init = g_new0(LXPanelPluginInit, 1);
+    init->_reserved1 = pc;
+    init->name = pc->name;
+    init->description = pc->description;
+    if (pc->config)
+        init->config = _old_plugin_config;
+    if (pc->panel_configuration_changed)
+        init->reconfigure = _old_plugin_reconfigure;
+    init->one_per_system = pc->one_per_system;
+    init->expand_available = pc->expand_available;
+    init->expand_default = pc->expand_default;
     pc->dynamic = dynamic;
+    g_hash_table_insert(_all_types, g_strdup(pc->type), init);
 }
 
 /* Initialize the static plugins. */
@@ -104,21 +141,8 @@ static void init_plugin_class_list(void)
 #endif
 }
 
-/* Look up a plugin class by name. */
-static PluginClass * plugin_find_class(const char * type)
-{
-    GList * tmp;
-    for (tmp = pcl; tmp != NULL; tmp = g_list_next(tmp))
-    {
-        PluginClass * pc = (PluginClass *) tmp->data;
-        if (g_ascii_strcasecmp(type, pc->type) == 0)
-            return pc;
-    }
-    return NULL;
-}
-
 /* Load a dynamic plugin. */
-static PluginClass * plugin_load_dynamic(const char * type, const gchar * path)
+static void plugin_load_dynamic(const char * type, const gchar * path)
 {
     PluginClass * pc = NULL;
 
@@ -140,103 +164,14 @@ static PluginClass * plugin_load_dynamic(const char * type, const gchar * path)
         {
             g_module_close(m);
             ERR("%s.so is not a lxpanel plugin\n", type);
-            return NULL;
+            return;
         }
 
         /* Register the newly loaded and valid plugin. */
         pc->gmodule = m;
         register_plugin_class(pc, TRUE);
+        pc->count = 1;
     }
-    return pc;
-}
-
-/* Create an instance of a plugin with a specified name, loading it if external. */
-Plugin * plugin_load(char * type)
-{
-    /* Initialize static plugins on first call. */
-    if (pcl == NULL)
-        init_plugin_class_list();
-
-    /* Look up the PluginClass. */
-    PluginClass * pc = plugin_find_class(type);
-
-#ifndef DISABLE_PLUGINS_LOADING
-    /* If not found and dynamic loading is available, try to locate an external plugin. */
-    if ((pc == NULL) && (g_module_supported()))
-    {
-        gchar path[PATH_MAX];
-        g_snprintf(path, sizeof(path), PACKAGE_LIB_DIR "/lxpanel/plugins/%s.so", type);
-        pc = plugin_load_dynamic(type, path);
-    }
-#endif  /* DISABLE_PLUGINS_LOADING */
-
-    /* If not found, return failure. */
-    if (pc == NULL)
-        return NULL;
-
-    /* Instantiate the plugin */
-    Plugin * plug = g_new0(Plugin, 1);
-    plug->class = pc;
-    pc->count += 1;
-    return plug;
-}
-
-/* Configure and start a plugin by calling its constructor. */
-int plugin_start(Plugin * pl, char ** fp)
-{
-    /* Call the constructor.
-     * It is responsible for parsing the parameters, and setting "pwid" to the top level widget. */
-    if ( ! pl->class->constructor(pl, fp))
-        return 0;
-
-    /* If this plugin can only be instantiated once, count the instantiation.
-     * This causes the configuration system to avoid displaying the plugin as one that can be added. */
-    if (pl->class->one_per_system)
-        pl->class->one_per_system_instantiated = TRUE;
-
-    /* If the plugin has a top level widget, add it to the panel's container. */
-    if (pl->pwid != NULL)
-    {
-        gtk_widget_set_name(pl->pwid, pl->class->type);
-        gtk_box_pack_start(GTK_BOX(pl->panel->box), pl->pwid, pl->expand, TRUE, pl->padding);
-        gtk_container_set_border_width(GTK_CONTAINER(pl->pwid), pl->border);
-        gtk_widget_show(pl->pwid);
-    }
-    return 1;
-}
-
-/* Unload a plugin if initialization fails. */
-void plugin_unload(Plugin * pl)
-{
-    plugin_class_unref(pl->class);
-    g_free(pl);
-}
-
-/* Delete a plugin. */
-void plugin_delete(Plugin * pl)
-{
-    Panel * p = pl->panel;
-    PluginClass * pc = pl->class;
-
-    /* If a plugin configuration dialog is open, close it. */
-    if (p->plugin_pref_dialog != NULL)
-    {
-        gtk_widget_destroy(p->plugin_pref_dialog);
-        p->plugin_pref_dialog = NULL;
-    }
-
-    /* Run the destructor and then destroy the top level widget.
-     * This prevents problems with the plugin destroying child widgets. */
-    pc->destructor(pl);
-    if (pl->pwid != NULL)
-        gtk_widget_destroy(pl->pwid);
-
-    /* Data structure bookkeeping. */
-    pc->one_per_system_instantiated = FALSE;
-    plugin_class_unref(pc);
-
-    /* Free the Plugin structure. */
-    g_free(pl);
 }
 
 /* Unreference a dynamic plugin. */
@@ -249,29 +184,15 @@ static void plugin_class_unref(PluginClass * pc)
     && (pc->dynamic)
     && ( ! pc->not_unloadable))
     {
-        pcl = g_list_remove(pcl, pc);
         g_module_close(pc->gmodule);
     }
 }
 
-/* Get a list of all available plugin classes.
- * Returns a newly allocated GList which should be freed with plugin_class_list_free(list). */
-GList * plugin_get_available_classes(void)
+/* Loads all available old type plugins. Should be removed in future releases. */
+static void plugin_get_available_classes(void)
 {
     /* Initialize static plugins on first call. */
-    if (pcl == NULL)
-        init_plugin_class_list();
-
-    /* Loop over all classes to formulate the result.
-     * Increase the reference count; it will be decreased in plugin_class_list_free. */
-    GList * classes = NULL;
-    GList * l;
-    for (l = pcl; l != NULL; l = l->next)
-    {
-        PluginClass * pc = (PluginClass *) l->data;
-        classes = g_list_prepend(classes, pc);
-        pc->count += 1;
-    }
+    init_plugin_class_list();
 
 #ifndef DISABLE_PLUGINS_LOADING
     GDir * dir = g_dir_open(PACKAGE_LIB_DIR "/lxpanel/plugins", 0, NULL);
@@ -283,16 +204,11 @@ GList * plugin_get_available_classes(void)
             if (g_str_has_suffix(file, ".so"))
             {
                 char * type = g_strndup(file, strlen(file) - 3);
-                if (plugin_find_class(type) == NULL)
+                if (_find_plugin(type) == NULL)
                 {
                     /* If it has not been loaded, do it.  If successful, add it to the result. */
                     char * path = g_build_filename(PACKAGE_LIB_DIR "/lxpanel/plugins", file, NULL );
-                    PluginClass * pc = plugin_load_dynamic(type, path);
-                    if (pc != NULL)
-                    {
-                        pc->count += 1;
-                        classes = g_list_prepend(classes, pc);
-                    }
+                    plugin_load_dynamic(type, path);
                     g_free(path);
                 }
                 g_free(type);
@@ -301,14 +217,6 @@ GList * plugin_get_available_classes(void)
         g_dir_close(dir);
     }
 #endif
-    return classes;
-}
-
-/* Free the list allocated by plugin_get_available_classes. */
-void plugin_class_list_free(GList * list)
-{
-   g_list_foreach(list, (GFunc) plugin_class_unref, NULL);
-   g_list_free(list);
 }
 
 /* Recursively set the background of all widgets on a panel background configuration change. */
@@ -355,19 +263,25 @@ void plugin_widget_set_background(GtkWidget * w, Panel * p)
 
 /* Handler for "button_press_event" signal with Plugin as parameter.
  * External so can be used from a plugin. */
-gboolean plugin_button_press_event(GtkWidget *widget, GdkEventButton *event, Plugin *plugin)
+gboolean lxpanel_plugin_button_press_event(GtkWidget *widget, GdkEventButton *event, GtkWidget *plugin)
 {
-    if (event->button == 3)     /* right button */
+    if (event->button == 3) /* right button */
     {
-        GtkMenu* popup = (GtkMenu*) lxpanel_get_panel_menu(plugin->panel, plugin, FALSE);
+        GtkMenu* popup = (GtkMenu*)lxpanel_get_plugin_menu(PLUGIN_PANEL(plugin), plugin, FALSE);
         gtk_menu_popup(popup, NULL, NULL, NULL, NULL, event->button, event->time);
         return TRUE;
-    }    
+    }
     return FALSE;
 }
 
+/* for old plugins compatibility */
+gboolean plugin_button_press_event(GtkWidget *widget, GdkEventButton *event, Plugin *plugin)
+{
+    return lxpanel_plugin_button_press_event(widget, event, plugin->pwid);
+}
+
 /* Helper for position-calculation callback for popup menus. */
-void plugin_popup_set_position_helper(Plugin * p, GtkWidget * near, GtkWidget * popup, GtkRequisition * popup_req, gint * px, gint * py)
+void lxpanel_plugin_popup_set_position_helper(Panel * p, GtkWidget * near, GtkWidget * popup, GtkRequisition * popup_req, gint * px, gint * py)
 {
     /* Get the origin of the requested-near widget in screen coordinates. */
     gint x, y;
@@ -377,7 +291,7 @@ void plugin_popup_set_position_helper(Plugin * p, GtkWidget * near, GtkWidget *
 
     /* Dispatch on edge to lay out the popup menu with respect to the button.
      * Also set "push-in" to avoid any case where it might flow off screen. */
-    switch (p->panel->edge)
+    switch (p->edge)
     {
         case EDGE_TOP:          y += near->allocation.height;         break;
         case EDGE_BOTTOM:       y -= popup_req->height;                break;
@@ -388,13 +302,18 @@ void plugin_popup_set_position_helper(Plugin * p, GtkWidget * near, GtkWidget *
     *py = y;
 }
 
+/* for old plugins compatibility */
+void plugin_popup_set_position_helper(Plugin * p, GtkWidget * near, GtkWidget * popup, GtkRequisition * popup_req, gint * px, gint * py)
+{
+    lxpanel_plugin_popup_set_position_helper(p->panel, near, popup, popup_req, px, py);
+}
+
 /* Adjust the position of a popup window to ensure that it is not hidden by the panel.
  * It is observed that some window managers do not honor the strut that is set on the panel. */
-void plugin_adjust_popup_position(GtkWidget * popup, Plugin * plugin)
+void lxpanel_plugin_adjust_popup_position(GtkWidget * popup, GtkWidget * parent)
 {
     /* Initialize. */
-    Panel * p = plugin->panel;
-    GtkWidget * parent = plugin->pwid;
+    Panel * p = PLUGIN_PANEL(parent);
 
     /* Get the coordinates of the plugin top level widget. */
     int x = p->cx + parent->allocation.x;
@@ -426,3 +345,190 @@ void plugin_adjust_popup_position(GtkWidget * popup, Plugin * plugin)
     /* Move the popup to position. */
     gdk_window_move(popup->window, x, y);
 }
+
+/* for old plugins compatibility */
+void plugin_adjust_popup_position(GtkWidget * popup, Plugin * plugin)
+{
+    lxpanel_plugin_adjust_popup_position(popup, plugin->pwid);
+}
+
+#if GLIB_CHECK_VERSION(2, 32, 0)
+static GRecMutex _mutex;
+#else
+static GStaticRecMutex _mutex = G_STATIC_REC_MUTEX_INIT;
+#endif
+
+FM_MODULE_DEFINE_TYPE(lxpanel_gtk, LXPanelPluginInit, 1)
+
+static gboolean fm_module_callback_lxpanel_gtk(const char *name, gpointer init, int ver)
+{
+    /* ignore ver for now, only 1 exists */
+    return lxpanel_register_plugin_type(name, init);
+}
+
+static gboolean old_plugins_loaded = FALSE;
+
+void _prepare_modules(void)
+{
+    _all_types = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+    lxpanel_plugin_qdata = g_quark_from_static_string("LXPanel::plugin-data");
+    lxpanel_plugin_qinit = g_quark_from_static_string("LXPanel::plugin-init");
+    lxpanel_plugin_qconf = g_quark_from_static_string("LXPanel::plugin-conf");
+    lxpanel_plugin_qpanel = g_quark_from_static_string("LXPanel::plugin-panel");
+    fm_modules_add_directory(PACKAGE_LIB_DIR "/lxpanel/plugins");
+    fm_module_register_lxpanel_gtk();
+}
+
+void _unload_modules(void)
+{
+    GHashTableIter iter;
+    gpointer key, val;
+
+    fm_module_unregister_type("lxpanel_gtk");
+    g_hash_table_iter_init(&iter, _all_types);
+    while(g_hash_table_iter_next(&iter, &key, &val))
+    {
+        register LXPanelPluginInit *init = val;
+        if (init->new_instance == NULL) /* old type of plugin */
+        {
+            plugin_class_unref(init->_reserved1);
+            g_free(val);
+        }
+    }
+    g_hash_table_destroy(_all_types);
+    old_plugins_loaded = FALSE;
+}
+
+gboolean lxpanel_register_plugin_type(const char *name, LXPanelPluginInit *init)
+{
+    LXPanelPluginInit *data;
+
+    /* validate it */
+    if (init->new_instance == NULL || name == NULL || name[0] == '\0')
+        return FALSE;
+#if GLIB_CHECK_VERSION(2, 32, 0)
+    g_rec_mutex_lock(&_mutex);
+#else
+    g_static_rec_mutex_lock(&_mutex);
+#endif
+    /* test if it's registered already */
+    data = _find_plugin(name);
+    if (data == NULL)
+    {
+        if (init->init)
+            init->init();
+        g_hash_table_insert(_all_types, g_strdup(name), init);
+    }
+#if GLIB_CHECK_VERSION(2, 32, 0)
+    g_rec_mutex_unlock(&_mutex);
+#else
+    g_static_rec_mutex_unlock(&_mutex);
+#endif
+    return (data == NULL);
+}
+
+static void _old_plugin_save_hook(const config_setting_t * setting, FILE * f, gpointer user_data)
+{
+    Plugin *pl = user_data;
+    PluginClass *pc = pl->class;
+    if (pc->save)
+        pc->save(pl, f);
+}
+
+/* This is called right before Plugin instance is destroyed */
+static void _old_plugin_destroy(gpointer data)
+{
+    Plugin *pl = data;
+
+    /* Run the destructor. */
+    pl->class->destructor(pl);
+    plugin_class_unref(pl->class);
+
+    /* Free the Plugin structure. */
+    g_free(pl);
+}
+
+GtkWidget *lxpanel_add_plugin(Panel *p, const char *name, config_setting_t *cfg, gint at)
+{
+    LXPanelPluginInit *init;
+    GtkWidget *widget;
+    config_setting_t *s;
+    gint expand, padding = 0, border = 0, i;
+
+    CHECK_MODULES();
+    if (!old_plugins_loaded)
+        plugin_get_available_classes();
+    old_plugins_loaded = TRUE;
+    init = _find_plugin(name);
+    if (init == NULL)
+        return NULL;
+    /* prepare widget settings */
+    if (!init->expand_available)
+        expand = 0;
+    else if ((s = config_setting_get_member(cfg, "expand")))
+        expand = config_setting_get_int(s);
+    else
+        expand = init->expand_default;
+    s = config_setting_get_member(cfg, "padding");
+    if (s)
+        padding = config_setting_get_int(s);
+    s = config_setting_get_member(cfg, "border");
+    if (s)
+        border = config_setting_get_int(s);
+    /* prepare config and create it if need */
+    s = config_setting_add(cfg, "", PANEL_CONF_TYPE_LIST);
+    for (i = 0; (cfg = config_setting_get_elem(s, i)); i++)
+        if (strcmp(config_setting_get_name(cfg), "Config") == 0)
+            break;
+    if (!cfg)
+        cfg = config_setting_add(s, "Config", PANEL_CONF_TYPE_GROUP);
+    /* If this plugin can only be instantiated once, count the instantiation.
+     * This causes the configuration system to avoid displaying the plugin as one that can be added. */
+    if (init->new_instance) /* new style of plugin */
+    {
+        widget = init->new_instance(p, cfg);
+        if (widget == NULL)
+            return widget;
+    }
+    else
+    {
+        Plugin *pl = g_new0(Plugin, 1);
+        PluginClass *pc = init->_reserved1;
+        char *conf = config_setting_to_string(cfg), *fp;
+
+        pl->class = pc;
+        pl->panel = p;
+        widget = NULL;
+        fp = &conf[9]; /* skip "Config {\n" */
+        /* g_debug("created conf: %s",conf); */
+    /* Call the constructor.
+     * It is responsible for parsing the parameters, and setting "pwid" to the top level widget. */
+        if (pc->constructor(pl, &fp))
+            widget = pl->pwid;
+        g_free(conf);
+
+        if (widget == NULL) /* failed */
+        {
+            g_free(pl);
+            return widget;
+        }
+
+        pc->count += 1;
+        config_setting_set_save_hook(cfg, _old_plugin_save_hook, pl);
+        lxpanel_plugin_set_data(widget, pl, _old_plugin_destroy);
+    }
+    gtk_widget_set_name(widget, init->name);
+    gtk_box_pack_start(GTK_BOX(p->box), widget, expand, TRUE, padding);
+    gtk_container_set_border_width(GTK_CONTAINER(widget), border);
+    gtk_widget_show(widget);
+    g_object_set_qdata(G_OBJECT(widget), lxpanel_plugin_qconf, cfg);
+    g_object_set_qdata(G_OBJECT(widget), lxpanel_plugin_qinit, init);
+    g_object_set_qdata(G_OBJECT(widget), lxpanel_plugin_qpanel, p);
+    return widget;
+}
+
+/* transfer none - note that not all fields are valid there */
+GHashTable *lxpanel_get_all_types(void)
+{
+    return _all_types;
+}
diff --git a/src/plugin.h b/src/plugin.h
new file mode 100644 (file)
index 0000000..136a559
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2014 LxDE Developers, see the file AUTHORS for details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __PLUGIN_H__
+#define __PLUGIN_H__ 1
+
+#include <libfm/fm.h>
+
+#include "panel.h"
+#include "conf.h"
+
+G_BEGIN_DECLS
+
+/* New plugins style which uses FmModule loader, our module type is "lxpanel_gtk" */
+
+#define FM_MODULE_lxpanel_gtk_VERSION 1 /* version of this API */
+
+typedef struct {
+    /*< public >*/
+    void (*init)(void);         /* optional startup */
+    void (*finalize)(void);     /* optional finalize */
+    char *name;                 /* name to represent in lists */
+    char *description;          /* tooltip text */
+    GtkWidget *(*new_instance)(Panel *panel, config_setting_t *settings);
+    void (*config)(Panel *panel, GtkWidget *instance, GtkWindow *parent);
+    void (*reconfigure)(Panel *panel, GtkWidget *instance);
+    int one_per_system : 1;     /* True to disable more than one instance */
+    int expand_available : 1;   /* True if "stretch" option is available */
+    int expand_default : 1;     /* True if "stretch" option is default */
+    /*< private >*/
+    gpointer _reserved1;
+    gpointer _reserved2;
+} LXPanelPluginInit; /* constant data */
+
+extern LXPanelPluginInit fm_module_init_lxpanel_gtk;
+
+extern GQuark lxpanel_plugin_qdata; /* access to plugin private data */
+#define lxpanel_plugin_get_data(_i) g_object_get_qdata(G_OBJECT(_i),lxpanel_plugin_qdata)
+#define lxpanel_plugin_set_data(_i,_data,_destructor) g_object_set_qdata_full(G_OBJECT(_i),lxpanel_plugin_qdata,_data,_destructor)
+
+/* register new plugin type - can be called from plugins init() too */
+extern gboolean lxpanel_register_plugin_type(const char *name, LXPanelPluginInit *init);
+
+/* few helper functions */
+extern GtkMenu* lxpanel_get_plugin_menu(Panel* panel, GtkWidget* plugin, gboolean use_sub_menu);
+extern gboolean lxpanel_plugin_button_press_event(GtkWidget *widget, GdkEventButton *event, GtkWidget *plugin);
+                       /* Handler for "button_press_event" signal with Plugin as parameter */
+extern void lxpanel_plugin_adjust_popup_position(GtkWidget * popup, GtkWidget * plugin);
+                       /* Helper to move popup windows away from the panel */
+extern void lxpanel_plugin_popup_set_position_helper(Panel * p, GtkWidget * near, GtkWidget * popup, GtkRequisition * popup_req, gint * px, gint * py);
+                       /* Helper for position-calculation callback for popup menus */
+extern void plugin_widget_set_background(GtkWidget * plugin, Panel * p);
+                       /* Recursively set the background of all widgets on a panel background configuration change */
+
+G_END_DECLS
+
+#endif /* __PLUGIN_H__ */
index e050cb7..70de285 100644 (file)
@@ -19,7 +19,8 @@
 #ifndef PRIVATE_H
 #define PRIVATE_H
 
-//#include "plugin.h"
+#include "plugin.h"
+#include "conf.h"
 
 #include <gmodule.h>
 
@@ -114,8 +115,8 @@ struct _Panel {
 
     char* background_file;
 
-    GList * plugins;                   /* List of all plugins */
     GSList * system_menus;             /* List of plugins having menus */
+    PanelConf * config;                 /* Panel configuration data */
 
     GtkWidget* plugin_pref_dialog;     /* Plugin preference dialog */
     GtkWidget* pref_dialog;            /* preference dialog */
@@ -175,8 +176,8 @@ extern pair height_pair[];
 extern pair bool_pair[];
 extern pair pos_pair[];
 
-int str2num(pair *p, gchar *str, int defval);
-gchar *num2str(pair *p, int num, gchar *defval);
+int str2num(pair *p, const gchar *str, int defval);
+const gchar *num2str(pair *p, int num, const gchar *defval);
 
 extern int lxpanel_get_line(char **fp, line *s);
 extern int lxpanel_put_line(FILE* fp, const char* format, ...);
@@ -260,12 +261,6 @@ struct _Plugin {
 };
 
 /* Plugins management - deprecated style, for backward compatibility */
-extern Plugin * plugin_load(char * type);              /* Create an instance of a plugin, loading it if necessary */
-extern int plugin_start(Plugin * this, char ** fp);    /* Configure and start a plugin by calling its constructor */
-extern void plugin_unload(Plugin * pl);                        /* Delete an instance of a plugin if initialization fails */
-extern void plugin_delete(Plugin * pl);                        /* Delete an instance of a plugin */
-extern GList * plugin_get_available_classes(void);     /* Get a list of all plugin classes; free with plugin_class_list_free */
-extern void plugin_class_list_free(GList * list);      /* Free the list allocated by plugin_get_available_classes */
 extern gboolean plugin_button_press_event(GtkWidget *widget, GdkEventButton *event, Plugin *plugin);
                                                         /* Handler for "button_press_event" signal with Plugin as parameter */
 extern void plugin_adjust_popup_position(GtkWidget * popup, Plugin * plugin);
@@ -273,9 +268,6 @@ extern void plugin_adjust_popup_position(GtkWidget * popup, Plugin * plugin);
 extern void plugin_popup_set_position_helper(Plugin * p, GtkWidget * near, GtkWidget * popup, GtkRequisition * popup_req, gint * px, gint * py);
                                                        /* Helper for position-calculation callback for popup menus */
 
-extern void plugin_widget_set_background(GtkWidget * w, Panel * p);
-                                                       /* Recursively set the background of all widgets on a panel background configuration change */
-
 /* FIXME: optional definitions */
 #define STATIC_SEPARATOR
 #define STATIC_LAUNCHBAR
@@ -290,12 +282,18 @@ extern void plugin_widget_set_background(GtkWidget * w, Panel * p);
 #define STATIC_ICONS
 
 /* Plugins management - new style */
-gboolean lxpanel_add_plugin(Panel *p, const char *name, gint at);
-GList *lxpanel_get_all_types(void); /* transfer none */
+void _prepare_modules(void);
+void _unload_modules(void);
+
+GtkWidget *lxpanel_add_plugin(Panel *p, const char *name, config_setting_t *cfg, gint at);
+GHashTable *lxpanel_get_all_types(void); /* transfer none */
 
 GQuark lxpanel_plugin_qinit; /* access to LXPanelPluginInit data */
-#define PLUGIN_CLASS(_i) (g_object_get_qdata(G_OBJECT(_i),lxpanel_plugin_qinit))
+#define PLUGIN_CLASS(_i) ((LXPanelPluginInit*)g_object_get_qdata(G_OBJECT(_i),lxpanel_plugin_qinit))
 
 GQuark lxpanel_plugin_qconf; /* access to congig_setting_t data */
 
+GQuark lxpanel_plugin_qpanel; /* access to Panel */
+#define PLUGIN_PANEL(_i) ((Panel*)g_object_get_qdata(G_OBJECT(_i),lxpanel_plugin_qpanel))
+
 #endif