[Xfce4-commits] [apps/xfdashboard] 01/01: Implemented a basic and simple plugin system

noreply at xfce.org noreply at xfce.org
Thu Nov 12 21:26:01 CET 2015


This is an automated email from the git hooks/post-receive script.

nomad pushed a commit to branch master
in repository apps/xfdashboard.

commit cefed5340b9a0cd0bd16a6855048de39a1e9b6d1
Author: Stephan Haller <nomad at froevel.de>
Date:   Thu Nov 12 21:11:15 2015 +0100

    Implemented a basic and simple plugin system
    
    This commit is huge as it implements a basic and simple plugin system as well a sample plugin adding a new view showing a clock when this plugin is enabled. By default the plugin manager does not load anything as it looks at the property "/enabled-plugin" in channel "xfdashboard" of xfconf which is empty by default. The plugin manager expects an array of string at this property whereby each string in this array contains the name of the plugin to load, e.g. "clock-view" for the sample  [...]
    
    The plugin are searched in the following search paths in this order: the path at the environment variable XFDASHBOARD_PLUGINS_PATH (if set), $HOME/.local/share/xfdashboard/plugins, (install prefix)/lib/xfdashboard/plugins.
    
    The sample plugin can be tested by enabling it with the command (you should add parameter "-n" to xfconf-query at the beginning at the first time):
    xfconf-query -c xfdashboard -p /enabled-plugins -a -s clock-view -t string
    
    To disable all plugins use:
    xfconf-query -c xfdashboard -r -p /enabled-plugins
    
    Currently the plugin manager does not listen to changes at this property in xfconf so it does not load or unload any plugin automatically at changes. The application has to be restarted.
---
 Makefile.am                     |    1 +
 configure.ac.in                 |    2 +
 plugins/Makefile.am             |    2 +
 plugins/clock-view/Makefile.am  |   43 ++
 plugins/clock-view/clock-view.c |  312 ++++++++++++++
 plugins/clock-view/clock-view.h |   67 +++
 plugins/clock-view/plugin.c     |   85 ++++
 xfdashboard/Makefile.am         |    5 +
 xfdashboard/application.c       |   48 ++-
 xfdashboard/plugin-manager.c    |  343 +++++++++++++++
 xfdashboard/plugin-manager.h    |   67 +++
 xfdashboard/plugin.c            |  888 +++++++++++++++++++++++++++++++++++++++
 xfdashboard/plugin.h            |  109 +++++
 13 files changed, 1971 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 43a9b82..8e3689c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,7 @@ DISTCLEANFILES = \
 
 SUBDIRS = \
 	data \
+	plugins \
 	po \
 	settings \
 	xfdashboard
diff --git a/configure.ac.in b/configure.ac.in
index 40491c2..838e5fe 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -257,6 +257,8 @@ data/themes/xfdashboard-dark/Makefile
 data/themes/xfdashboard-mint/Makefile
 data/themes/xfdashboard-moranga/Makefile
 data/themes/xfdashboard-wine/Makefile
+plugins/Makefile
+plugins/clock-view/Makefile
 po/Makefile.in
 settings/Makefile
 xfdashboard/Makefile
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
new file mode 100644
index 0000000..4927e70
--- /dev/null
+++ b/plugins/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = \
+	clock-view
diff --git a/plugins/clock-view/Makefile.am b/plugins/clock-view/Makefile.am
new file mode 100644
index 0000000..35793d2
--- /dev/null
+++ b/plugins/clock-view/Makefile.am
@@ -0,0 +1,43 @@
+plugindir = $(libdir)/xfdashboard/plugins
+
+AM_CPPFLAGS = \
+	-I$(top_builddir) \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/xfdashboard \
+	-DG_LOG_DOMAIN=\"xfdashboard-plugin-clock_view\" \
+	-DLIBEXECDIR=\"$(libexecdir)\" \
+	-DPACKAGE_LOCALE_DIR=\"$(localedir)\"
+
+plugin_LTLIBRARIES = \
+	clock-view.la
+
+clock_view_la_SOURCES = \
+	clock-view.c \
+	clock-view.h \
+	plugin.c
+
+clock_view_la_CFLAGS = \
+	$(PLATFORM_CFLAGS) \
+	$(LIBXFCE4UTIL_CFLAGS) \
+	$(GTK_CFLAGS) \
+	$(CLUTTER_CFLAGS)
+
+clock_view_la_LDFLAGS = \
+	-avoid-version \
+	-export-dynamic \
+	-module \
+	$(PLATFORM_LDFLAGS)
+
+clock_view_la_LIBADD = \
+	$(LIBXFCE4UTIL_LIBS) \
+	$(GTK_LIBS) \
+	$(CLUTTER_LIBS)
+
+CLEANFILES = \
+	$(plugin_DATA)
+
+EXTRA_DIST = \
+	$(plugin_DATA)
+
+DISTCLEANFILES = \
+	$(plugin_DATA)
diff --git a/plugins/clock-view/clock-view.c b/plugins/clock-view/clock-view.c
new file mode 100644
index 0000000..4f1a5fc
--- /dev/null
+++ b/plugins/clock-view/clock-view.c
@@ -0,0 +1,312 @@
+/*
+ * clock-view: A view showing a clock
+ * 
+ * Copyright 2012-2014 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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.
+ * 
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <math.h>
+
+#include "clock-view.h"
+#include "utils.h"
+#include "view.h"
+#include "fill-box-layout.h"
+
+/* Define this class in GObject system */
+G_DEFINE_DYNAMIC_TYPE(XfdashboardClockView,
+						xfdashboard_clock_view,
+						XFDASHBOARD_TYPE_VIEW)
+
+/* Define this class in this plugin */
+XFDASHBOARD_DEFINE_PLUGIN_TYPE(xfdashboard_clock_view);
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_CLOCK_VIEW_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_CLOCK_VIEW, XfdashboardClockViewPrivate))
+
+struct _XfdashboardClockViewPrivate
+{
+	/* Instance related */
+	ClutterActor			*clockActor;
+	ClutterContent			*clockCanvas;
+	guint					timeoutID;
+};
+
+/* IMPLEMENTATION: Private variables and methods */
+
+/* Rectangle canvas should be redrawn */
+static gboolean _xfdashboard_clock_view_on_draw_canvas(XfdashboardClockView *self,
+														cairo_t *inContext,
+														int inWidth,
+														int inHeight,
+														gpointer inUserData)
+{
+	GDateTime		*now;
+	gfloat			hours, minutes, seconds;
+	ClutterColor	*color;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_CLOCK_VIEW(self), TRUE);
+	g_return_val_if_fail(CLUTTER_IS_CANVAS(inUserData), TRUE);
+
+	/* Get the current time and compute the angles */
+	now=g_date_time_new_now_local();
+	seconds=g_date_time_get_second(now)*G_PI/30;
+	minutes=g_date_time_get_minute(now)*G_PI/30;
+	hours=g_date_time_get_hour(now)*G_PI/6;
+	g_date_time_unref(now);
+
+	/* Clear the contents of the canvas, to avoid painting
+	 * over the previous frame
+	 */
+	cairo_save(inContext);
+
+	cairo_set_operator(inContext, CAIRO_OPERATOR_CLEAR);
+	cairo_paint(inContext);
+
+	cairo_restore(inContext);
+
+	cairo_set_operator(inContext, CAIRO_OPERATOR_OVER);
+
+	/* Scale the modelview to the size of the surface and
+	 * center clock in view.
+	 */
+	if(inHeight<inWidth)
+	{
+		cairo_scale(inContext, inHeight, inHeight);
+		cairo_translate(inContext, (inWidth/2.0f)/(gfloat)inHeight, 0.5f);
+	}
+		else
+		{
+			cairo_scale(inContext, inWidth, inWidth);
+			cairo_translate(inContext, 0.5f, (inHeight/2.0f)/(gfloat)inWidth);
+		}
+
+	cairo_set_line_cap(inContext, CAIRO_LINE_CAP_ROUND);
+	cairo_set_line_width(inContext, 0.1f);
+
+	/* The blue circle that holds the seconds indicator */
+	clutter_cairo_set_source_color(inContext, CLUTTER_COLOR_Blue);
+	cairo_arc(inContext, 0.0f, 0.0f, 0.4f, 0.0f, G_PI*2.0f);
+	cairo_stroke(inContext);
+
+	/* The seconds indicator */
+	color=clutter_color_copy(CLUTTER_COLOR_White);
+	color->alpha=128;
+
+	clutter_cairo_set_source_color(inContext, color);
+	cairo_move_to(inContext, 0.0f, 0.0f);
+	cairo_arc(inContext, sinf(seconds)*0.4f, -cosf(seconds)*0.4f, 0.05f, 0.0f, G_PI*2);
+	cairo_fill(inContext);
+
+	clutter_color_free(color);
+
+	/* The minutes indicator */
+	color=clutter_color_copy(CLUTTER_COLOR_LightChameleon);
+	color->alpha=196;
+
+	clutter_cairo_set_source_color(inContext, color);
+	cairo_move_to(inContext, 0.0f, 0.0f);
+	cairo_line_to(inContext, sinf(minutes)*0.4f, -cosf(minutes)*0.4f);
+	cairo_stroke(inContext);
+
+	clutter_color_free(color);
+
+	/* The hours indicator */
+	color=clutter_color_copy(CLUTTER_COLOR_LightChameleon);
+	color->alpha=196;
+
+	clutter_cairo_set_source_color(inContext, color);
+	cairo_move_to(inContext, 0.0f, 0.0f);
+	cairo_line_to(inContext, sinf(hours)*0.2f, -cosf(hours)*0.2f);
+	cairo_stroke(inContext);
+
+	clutter_color_free(color);
+
+	/* Done drawing */
+	return(CLUTTER_EVENT_STOP);
+}
+
+/* Timeout source callback which invalidate clock canvas */
+static gboolean _xfdashboard_clock_view_on_timeout(gpointer inUserData)
+{
+	XfdashboardClockView			*self;
+	XfdashboardClockViewPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_CLOCK_VIEW(inUserData));
+
+	self=XFDASHBOARD_CLOCK_VIEW(inUserData);
+	priv=self->priv;
+
+	/* Invalidate clock canvas which force a redraw with current time */
+	clutter_content_invalidate(CLUTTER_CONTENT(priv->clockCanvas));
+
+	return(TRUE);
+}
+
+/* IMPLEMENTATION: XfdashboardView */
+
+/* View was activated */
+static void _xfdashboard_clock_view_activated(XfdashboardView *inView)
+{
+	XfdashboardClockView			*self;
+	XfdashboardClockViewPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_CLOCK_VIEW(inView));
+
+	self=XFDASHBOARD_CLOCK_VIEW(inView);
+	priv=self->priv;
+
+	/* Create timeout source will invalidate canvas each second */
+	priv->timeoutID=clutter_threads_add_timeout(1000, _xfdashboard_clock_view_on_timeout, self);
+}
+
+/* View will be deactivated */
+static void _xfdashboard_clock_view_deactivating(XfdashboardView *inView)
+{
+	XfdashboardClockView			*self;
+	XfdashboardClockViewPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_CLOCK_VIEW(inView));
+
+	self=XFDASHBOARD_CLOCK_VIEW(inView);
+	priv=self->priv;
+
+	/* Remove timeout source if available */
+	if(priv->timeoutID)
+	{
+		g_source_remove(priv->timeoutID);
+		priv->timeoutID=0;
+	}
+}
+
+/* IMPLEMENTATION: ClutterActor */
+
+/* Allocate position and size of actor and its children*/
+static void _xfdashboard_clock_view_allocate(ClutterActor *inActor,
+												const ClutterActorBox *inBox,
+												ClutterAllocationFlags inFlags)
+{
+	XfdashboardClockView			*self=XFDASHBOARD_CLOCK_VIEW(inActor);
+	XfdashboardClockViewPrivate		*priv=self->priv;
+
+	/* Chain up to store the allocation of the actor */
+	CLUTTER_ACTOR_CLASS(xfdashboard_clock_view_parent_class)->allocate(inActor, inBox, inFlags);
+
+	/* Set size of actor and canvas */
+	clutter_actor_allocate(priv->clockActor, inBox, inFlags);
+
+	clutter_canvas_set_size(CLUTTER_CANVAS(priv->clockCanvas),
+								clutter_actor_box_get_width(inBox),
+								clutter_actor_box_get_height(inBox));
+}
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_clock_view_dispose(GObject *inObject)
+{
+	XfdashboardClockView			*self=XFDASHBOARD_CLOCK_VIEW(inObject);
+	XfdashboardClockViewPrivate		*priv=self->priv;
+
+	/* Release allocated resources */
+	if(priv->timeoutID)
+	{
+		g_source_remove(priv->timeoutID);
+		priv->timeoutID=0;
+	}
+
+	if(priv->clockActor)
+	{
+		clutter_actor_destroy(priv->clockActor);
+		priv->clockActor=NULL;
+	}
+
+	if(priv->clockCanvas)
+	{
+		g_object_unref(priv->clockCanvas);
+		priv->clockCanvas=NULL;
+	}
+
+	/* Call parent's class dispose method */
+	G_OBJECT_CLASS(xfdashboard_clock_view_parent_class)->dispose(inObject);
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+void xfdashboard_clock_view_class_init(XfdashboardClockViewClass *klass)
+{
+	XfdashboardViewClass	*viewClass=XFDASHBOARD_VIEW_CLASS(klass);
+	ClutterActorClass		*actorClass=CLUTTER_ACTOR_CLASS(klass);
+	GObjectClass			*gobjectClass=G_OBJECT_CLASS(klass);
+
+	/* Override functions */
+	gobjectClass->dispose=_xfdashboard_clock_view_dispose;
+
+	actorClass->allocate=_xfdashboard_clock_view_allocate;
+
+	viewClass->activated=_xfdashboard_clock_view_activated;
+	viewClass->deactivating=_xfdashboard_clock_view_deactivating;
+
+	/* Set up private structure */
+	g_type_class_add_private(klass, sizeof(XfdashboardClockViewPrivate));
+}
+
+/* Class finalization */
+void xfdashboard_clock_view_class_finalize(XfdashboardClockViewClass *klass)
+{
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+void xfdashboard_clock_view_init(XfdashboardClockView *self)
+{
+	XfdashboardClockViewPrivate		*priv;
+	// TODO: ClutterLayoutManager			*layout;
+
+	self->priv=priv=XFDASHBOARD_CLOCK_VIEW_GET_PRIVATE(self);
+
+	/* Set up default values */
+	priv->timeoutID=0;
+
+	/* Set up this actor */
+	xfdashboard_view_set_view_fit_mode(XFDASHBOARD_VIEW(self), XFDASHBOARD_VIEW_FIT_MODE_BOTH);
+
+	priv->clockCanvas=clutter_canvas_new();
+	clutter_canvas_set_size(CLUTTER_CANVAS(priv->clockCanvas), 100.0f, 100.0f);
+	g_signal_connect_swapped(priv->clockCanvas, "draw", G_CALLBACK(_xfdashboard_clock_view_on_draw_canvas), self);
+
+	priv->clockActor=clutter_actor_new();
+	clutter_actor_show(priv->clockActor);
+	clutter_actor_set_content(priv->clockActor, priv->clockCanvas);
+	clutter_actor_set_size(priv->clockActor, 100.0f, 100.0f);
+	clutter_actor_add_child(CLUTTER_ACTOR(self), priv->clockActor);
+
+	/* Set up view */
+	xfdashboard_view_set_name(XFDASHBOARD_VIEW(self), _("Clock"));
+	xfdashboard_view_set_icon(XFDASHBOARD_VIEW(self), "appointment-soon");
+}
diff --git a/plugins/clock-view/clock-view.h b/plugins/clock-view/clock-view.h
new file mode 100644
index 0000000..0a3f1f2
--- /dev/null
+++ b/plugins/clock-view/clock-view.h
@@ -0,0 +1,67 @@
+/*
+ * clock-view: A view showing a clock
+ * 
+ * Copyright 2012-2014 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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 __XFDASHBOARD_CLOCK_VIEW__
+#define __XFDASHBOARD_CLOCK_VIEW__
+
+#include "plugin.h"
+#include "view.h"
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_CLOCK_VIEW				(xfdashboard_clock_view_get_type())
+#define XFDASHBOARD_CLOCK_VIEW(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_CLOCK_VIEW, XfdashboardClockView))
+#define XFDASHBOARD_IS_CLOCK_VIEW(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_CLOCK_VIEW))
+#define XFDASHBOARD_CLOCK_VIEW_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_CLOCK_VIEW, XfdashboardClockViewClass))
+#define XFDASHBOARD_IS_CLOCK_VIEW_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_CLOCK_VIEW))
+#define XFDASHBOARD_CLOCK_VIEW_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_CLOCK_VIEW, XfdashboardClockViewClass))
+
+typedef struct _XfdashboardClockView			XfdashboardClockView; 
+typedef struct _XfdashboardClockViewPrivate		XfdashboardClockViewPrivate;
+typedef struct _XfdashboardClockViewClass		XfdashboardClockViewClass;
+
+struct _XfdashboardClockView
+{
+	/* Parent instance */
+	XfdashboardView						parent_instance;
+
+	/* Private structure */
+	XfdashboardClockViewPrivate	*priv;
+};
+
+struct _XfdashboardClockViewClass
+{
+	/*< private >*/
+	/* Parent class */
+	XfdashboardViewClass				parent_class;
+};
+
+/* Public API */
+GType xfdashboard_clock_view_get_type(void) G_GNUC_CONST;
+void xfdashboard_clock_view_type_register(GTypeModule *inModule);
+
+XFDASHBOARD_DECLARE_PLUGIN_TYPE(xfdashboard_clock_view);
+
+G_END_DECLS
+
+#endif
diff --git a/plugins/clock-view/plugin.c b/plugins/clock-view/plugin.c
new file mode 100644
index 0000000..e2a4720
--- /dev/null
+++ b/plugins/clock-view/plugin.c
@@ -0,0 +1,85 @@
+/*
+ * plugin: Plugin functions for 'clock-view'
+ * 
+ * Copyright 2012-2014 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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.
+ * 
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "plugin.h"
+
+#include <libxfce4util/libxfce4util.h>
+
+#include "view-manager.h"
+#include "clock-view.h"
+
+
+/* IMPLEMENTATION: XfdashboardPlugin */
+
+/* Forward declarations */
+G_MODULE_EXPORT void plugin_init(XfdashboardPlugin *self);
+G_MODULE_EXPORT void plugin_enable(XfdashboardPlugin *self);
+G_MODULE_EXPORT void plugin_disable(XfdashboardPlugin *self);
+
+/* Plugin initialization function */
+G_MODULE_EXPORT void plugin_init(XfdashboardPlugin *self)
+{
+	/* Set up localization */
+	xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
+
+	/* Set plugin info */
+	xfdashboard_plugin_set_info(self,
+								"id", "clock-view",
+								"name", _("Clock"),
+								"description", _("Adds new a view showing a clock"),
+								"author", "Stephan Haller <nomad at froevel.de>",
+								NULL);
+
+	/* Register GObject types of this plugin */
+	XFDASHBOARD_REGISTER_PLUGIN_TYPE(self, xfdashboard_clock_view);
+}
+
+/* Plugin enable function */
+G_MODULE_EXPORT void plugin_enable(XfdashboardPlugin *self)
+{
+	XfdashboardViewManager	*viewManager;
+
+	/* Register view */
+	viewManager=xfdashboard_view_manager_get_default();
+
+	xfdashboard_view_manager_register(viewManager, "clock", XFDASHBOARD_TYPE_CLOCK_VIEW);
+
+	g_object_unref(viewManager);
+}
+
+/* Plugin disable function */
+G_MODULE_EXPORT void plugin_disable(XfdashboardPlugin *self)
+{
+	XfdashboardViewManager	*viewManager;
+
+	/* Unregister view */
+	viewManager=xfdashboard_view_manager_get_default();
+
+	xfdashboard_view_manager_unregister(viewManager, "clock");
+
+	g_object_unref(viewManager);
+}
diff --git a/xfdashboard/Makefile.am b/xfdashboard/Makefile.am
index 6be4798..e2054a6 100644
--- a/xfdashboard/Makefile.am
+++ b/xfdashboard/Makefile.am
@@ -3,6 +3,7 @@ AM_CPPFLAGS = \
 	-DG_LOG_DOMAIN=\"xfdashboard\" \
 	-DPACKAGE_DATADIR=\"$(datadir)\" \
 	-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
+	-DPACKAGE_LIBDIR=\"$(libdir)\" \
 	$(PLATFORM_CPPFLAGS)
 
 noinst_LTLIBRARIES = \
@@ -48,6 +49,8 @@ xfdashboard_headers = \
 	live-window.h \
 	live-workspace.h \
 	outline-effect.h \
+	plugin.h \
+	plugin-manager.h \
 	quicklaunch.h \
 	scaled-table-layout.h \
 	scrollbar.h \
@@ -111,6 +114,8 @@ libxfdashboard_la_SOURCES = \
 	live-window.c \
 	live-workspace.c \
 	outline-effect.c \
+	plugin.c \
+	plugin-manager.c \
 	quicklaunch.c \
 	scaled-table-layout.c \
 	scrollbar.c \
diff --git a/xfdashboard/application.c b/xfdashboard/application.c
index 98c769f..1fc3c8a 100644
--- a/xfdashboard/application.c
+++ b/xfdashboard/application.c
@@ -48,6 +48,7 @@
 #include "bindings-pool.h"
 #include "application-database.h"
 #include "application-tracker.h"
+#include "plugin-manager.h"
 
 /* Define this class in GObject system */
 G_DEFINE_TYPE(XfdashboardApplication,
@@ -83,6 +84,8 @@ struct _XfdashboardApplicationPrivate
 	XfdashboardApplicationTracker	*appTracker;
 
 	XfceSMClient					*sessionManagementClient;
+
+	XfdashboardPluginManager		*pluginManager;
 };
 
 /* Properties */
@@ -419,6 +422,22 @@ static gboolean _xfdashboard_application_initialize_full(XfdashboardApplication
 
 	xfdashboard_search_manager_register(priv->searchManager, "applications", XFDASHBOARD_TYPE_APPLICATIONS_SEARCH_PROVIDER);
 
+	/* Create single-instance of plugin manager to keep it alive while
+	 * application is running.
+	 */
+	priv->pluginManager=xfdashboard_plugin_manager_get_default();
+	if(!priv->pluginManager)
+	{
+		g_critical(_("Could not initialize plugin manager"));
+		return(FALSE);
+	}
+
+	if(!xfdashboard_plugin_manager_setup(priv->pluginManager))
+	{
+		g_critical(_("Could not setup plugin manager"));
+		return(FALSE);
+	}
+
 	/* Create single-instance of focus manager to keep it alive while
 	 * application is running.
 	 */
@@ -716,6 +735,12 @@ static void _xfdashboard_application_dispose(GObject *inObject)
 	g_signal_emit(self, XfdashboardApplicationSignals[SIGNAL_SHUTDOWN_FINAL], 0);
 
 	/* Release allocated resources */
+	if(priv->pluginManager)
+	{
+		g_object_unref(priv->pluginManager);
+		priv->pluginManager=NULL;
+	}
+
 	if(priv->xfconfThemeChangedSignalID)
 	{
 		xfconf_g_property_unbind(priv->xfconfThemeChangedSignalID);
@@ -970,6 +995,7 @@ static void xfdashboard_application_init(XfdashboardApplication *self)
 	priv->xfconfThemeChangedSignalID=0L;
 	priv->isQuitting=FALSE;
 	priv->sessionManagementClient=NULL;
+	priv->pluginManager=NULL;
 
 	/* Add callable DBUS actions for this application */
 	action=g_simple_action_new("Quit", NULL);
@@ -985,10 +1011,30 @@ XfdashboardApplication* xfdashboard_application_get_default(void)
 {
 	if(G_UNLIKELY(application==NULL))
 	{
+		gchar			*appID;
+		const gchar		*forceNewInstance=NULL;
+
+#ifdef DEBUG
+		/* If a new instance of xfdashboard is forced, e.g. for debugging purposes,
+		 * then create a unique application ID.
+		 */
+		forceNewInstance=g_getenv("XFDASHBOARD_FORCE_NEW_INSTANCE");
+#endif
+
+		if(forceNewInstance)
+		{
+			appID=g_strdup_printf("%s-%u", XFDASHBOARD_APP_ID, getpid());
+			g_message("Forcing new application instance with ID '%s'", appID);
+		}
+			else appID=g_strdup(XFDASHBOARD_APP_ID);
+
 		application=g_object_new(XFDASHBOARD_TYPE_APPLICATION,
-									"application-id", XFDASHBOARD_APP_ID,
+									"application-id", appID,
 									"flags", G_APPLICATION_HANDLES_COMMAND_LINE,
 									NULL);
+
+		/* Release allocated resources */
+		if(appID) g_free(appID);
 	}
 
 	return(application);
diff --git a/xfdashboard/plugin-manager.c b/xfdashboard/plugin-manager.c
new file mode 100644
index 0000000..8148205
--- /dev/null
+++ b/xfdashboard/plugin-manager.c
@@ -0,0 +1,343 @@
+/*
+ * plugin-manager: Single-instance managing plugins
+ * 
+ * Copyright 2012-2015 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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.
+ * 
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin-manager.h"
+
+#include <glib/gi18n-lib.h>
+
+#include "plugin.h"
+#include "application.h"
+
+
+/* Define this class in GObject system */
+G_DEFINE_TYPE(XfdashboardPluginManager,
+				xfdashboard_plugin_manager,
+				G_TYPE_OBJECT)
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_PLUGIN_MANAGER_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_PLUGIN_MANAGER, XfdashboardPluginManagerPrivate))
+
+struct _XfdashboardPluginManagerPrivate
+{
+	/* Instance related */
+	gboolean		isInited;
+	GList			*searchPaths;
+	GList			*plugins;
+};
+
+
+/* IMPLEMENTATION: Private variables and methods */
+#define ENABLED_PLUGINS_XFCONF_PROP			"/enabled-plugins"
+
+/* Single instance of plugin manager */
+static XfdashboardPluginManager*			_xfdashboard_plugin_manager=NULL;
+
+/* Add path to search path but avoid duplicates */
+static gboolean _xfdashboard_plugin_manager_add_search_path(XfdashboardPluginManager *self,
+																const gchar *inPath)
+{
+	XfdashboardPluginManagerPrivate		*priv;
+	gchar								*normalizedPath;
+	GList								*iter;
+	gchar								*iterPath;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_PLUGIN_MANAGER(self), FALSE);
+	g_return_val_if_fail(inPath && *inPath, FALSE);
+
+	priv=self->priv;
+
+	/* Normalize requested path to add to list of search paths that means
+	 * that it should end with a directory seperator.
+	 */
+	if(!g_str_has_suffix(inPath, G_DIR_SEPARATOR_S))
+	{
+		normalizedPath=g_strjoin(NULL, inPath, G_DIR_SEPARATOR_S, NULL);
+	}
+		else normalizedPath=g_strdup(inPath);
+
+	/* Check if path is already in list of search paths */
+	for(iter=priv->searchPaths; iter; iter=g_list_next(iter))
+	{
+		/* Get search path at iterator */
+		iterPath=(gchar*)iter->data;
+
+		/* If the path at iterator matches the requested one that it is
+		 * already in list of search path, so return here with fail result.
+		 */
+		if(g_strcmp0(iterPath, normalizedPath)==0)
+		{
+			g_debug("Path '%s' was already added to search paths of plugin manager", normalizedPath);
+
+			/* Release allocated resources */
+			if(normalizedPath) g_free(normalizedPath);
+
+			/* Return fail result */
+			return(FALSE);
+		}
+	}
+
+	/* If we get here the requested path is not in list of search path and
+	 * we can add it now.
+	 */
+	priv->searchPaths=g_list_append(priv->searchPaths, g_strdup(normalizedPath));
+	g_debug("Added path '%s' to search paths of plugin manager", normalizedPath);
+
+	/* Release allocated resources */
+	if(normalizedPath) g_free(normalizedPath);
+
+	/* Return success result */
+	return(TRUE);
+}
+
+/* Find path to plugin */
+static gchar* _xfdashboard_plugin_manager_find_plugin_path(XfdashboardPluginManager *self,
+															const gchar *inPluginName)
+{
+	XfdashboardPluginManagerPrivate		*priv;
+	gchar								*path;
+	GList								*iter;
+	gchar								*iterPath;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_PLUGIN_MANAGER(self), NULL);
+	g_return_val_if_fail(inPluginName && *inPluginName, NULL);
+
+	priv=self->priv;
+
+	/* Iterate through list of search paths, lookup file name containing plugin name
+	 * followed by suffix ".so" and return first path found.
+	 */
+	for(iter=priv->searchPaths; iter; iter=g_list_next(iter))
+	{
+		/* Get search path at iterator */
+		iterPath=(gchar*)iter->data;
+
+		/* Create full path of search path and plugin name */
+		path=g_strdup_printf("%s%s%s.%s", iterPath, G_DIR_SEPARATOR_S, inPluginName, G_MODULE_SUFFIX);
+		if(!path) continue;
+
+		/* Check if file exists and return it if we does */
+		if(g_file_test(path, G_FILE_TEST_IS_REGULAR))
+		{
+			g_debug("Found path %s for plugin '%s'", path, inPluginName);
+			return(path);
+		}
+
+		/* Release allocated resources */
+		if(path) g_free(path);
+	}
+
+	/* If we get here we did not found any suitable file, so return NULL */
+	g_debug("Plugin '%s' not found in search paths", inPluginName);
+	return(NULL);
+}
+
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_plugin_manager_dispose_remove_plugin(gpointer inData)
+{
+	XfdashboardPlugin					*plugin;
+
+	g_return_if_fail(inData && XFDASHBOARD_IS_PLUGIN(inData));
+
+	plugin=XFDASHBOARD_PLUGIN(inData);
+
+	/* Disable plugin */
+	xfdashboard_plugin_disable(plugin);
+
+	/* Unload plugin */
+	g_type_module_unuse(G_TYPE_MODULE(plugin));
+}
+
+static void _xfdashboard_plugin_manager_dispose(GObject *inObject)
+{
+	XfdashboardPluginManager			*self=XFDASHBOARD_PLUGIN_MANAGER(inObject);
+	XfdashboardPluginManagerPrivate		*priv=self->priv;
+
+	/* Release allocated resources */
+	if(priv->plugins)
+	{
+		g_list_free_full(priv->plugins, (GDestroyNotify)_xfdashboard_plugin_manager_dispose_remove_plugin);
+		priv->plugins=NULL;
+	}
+
+	if(priv->searchPaths)
+	{
+		g_list_free_full(priv->searchPaths, g_free);
+		priv->searchPaths=NULL;
+	}
+
+	/* Unset singleton */
+	if(G_LIKELY(G_OBJECT(_xfdashboard_plugin_manager)==inObject)) _xfdashboard_plugin_manager=NULL;
+
+	/* Call parent's class dispose method */
+	G_OBJECT_CLASS(xfdashboard_plugin_manager_parent_class)->dispose(inObject);
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+static void xfdashboard_plugin_manager_class_init(XfdashboardPluginManagerClass *klass)
+{
+	GObjectClass		*gobjectClass=G_OBJECT_CLASS(klass);
+
+	/* Override functions */
+	gobjectClass->dispose=_xfdashboard_plugin_manager_dispose;
+
+	/* Set up private structure */
+	g_type_class_add_private(klass, sizeof(XfdashboardPluginManagerPrivate));
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+static void xfdashboard_plugin_manager_init(XfdashboardPluginManager *self)
+{
+	XfdashboardPluginManagerPrivate		*priv;
+
+	priv=self->priv=XFDASHBOARD_PLUGIN_MANAGER_GET_PRIVATE(self);
+
+	/* Set default values */
+	priv->isInited=FALSE;
+	priv->searchPaths=NULL;
+	priv->plugins=NULL;
+}
+
+/* IMPLEMENTATION: Public API */
+
+/* Get single instance of manager */
+XfdashboardPluginManager* xfdashboard_plugin_manager_get_default(void)
+{
+	if(G_UNLIKELY(_xfdashboard_plugin_manager==NULL))
+	{
+		_xfdashboard_plugin_manager=g_object_new(XFDASHBOARD_TYPE_PLUGIN_MANAGER, NULL);
+	}
+		else g_object_ref(_xfdashboard_plugin_manager);
+
+	return(_xfdashboard_plugin_manager);
+}
+
+/* Initialize plugin manager */
+gboolean xfdashboard_plugin_manager_setup(XfdashboardPluginManager *self)
+{
+	XfdashboardPluginManagerPrivate		*priv;
+	gchar								*path;
+	const gchar							*envPath;
+	gchar								**enabledPlugins;
+	gchar								**iter;
+	GError								*error;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_PLUGIN_MANAGER(self), FALSE);
+
+	priv=self->priv;
+	error=NULL;
+
+	/* If plugin manager is already initialized then return immediately */
+	if(priv->isInited) return(TRUE);
+
+	/* Add search paths. Some paths may fail because they already exist
+	 * in list of search paths. So this should not fail this function.
+	 */
+	envPath=g_getenv("XFDASHBOARD_PLUGINS_PATH");
+	if(envPath)
+	{
+		_xfdashboard_plugin_manager_add_search_path(self, envPath);
+	}
+
+	path=g_build_filename(g_get_user_data_dir(), "xfdashboard", "plugins", NULL);
+	_xfdashboard_plugin_manager_add_search_path(self, path);
+	g_free(path);
+
+	path=g_build_filename(PACKAGE_LIBDIR, "xfdashboard", "plugins", NULL);
+	_xfdashboard_plugin_manager_add_search_path(self, path);
+	g_free(path);
+
+	/* Get list of enabled plugins and try to load them */
+	enabledPlugins=xfconf_channel_get_string_list(xfdashboard_application_get_xfconf_channel(),
+													ENABLED_PLUGINS_XFCONF_PROP);
+
+	/* Try to load all enabled plugin and collect each error occurred. */
+	for(iter=enabledPlugins; iter && *iter; iter++)
+	{
+		gchar							*pluginName;
+		XfdashboardPlugin				*plugin;
+
+		/* Get plugin name */
+		pluginName=*iter;
+		g_debug("Try to load plugin '%s'", pluginName);
+
+		/* Find path to plugin */
+		path=_xfdashboard_plugin_manager_find_plugin_path(self, pluginName);
+		if(!path)
+		{
+			/* Show error message */
+			g_warning(_("Could not load plugin '%s': Path not found"), pluginName);
+
+			/* Continue with next enabled plugin in list */
+			continue;
+		}
+
+		/* Create plugin */
+		plugin=xfdashboard_plugin_new(path, &error);
+		if(!plugin)
+		{
+			/* Show error message */
+			g_warning(_("Could not load plugin '%s': %s"),
+						pluginName,
+						error ? error->message : _("Unknown error"));
+
+			/* Release allocated resources */
+			if(error)
+			{
+				g_error_free(error);
+				error=NULL;
+			}
+
+			/* Continue with next enabled plugin in list */
+			continue;
+		}
+
+		/* Enable plugin */
+		xfdashboard_plugin_enable(plugin);
+
+		/* Store enabled plugin in list of enabled plugins */
+		priv->plugins=g_list_prepend(priv->plugins, plugin);
+	}
+
+	/* If we get here then initialization was successful so set flag that
+	 * this plugin manager is initialized and return with TRUE result.
+	 */
+	priv->isInited=TRUE;
+
+	/* Release allocated resources */
+	if(enabledPlugins) g_strfreev(enabledPlugins);
+
+	return(TRUE);
+}
diff --git a/xfdashboard/plugin-manager.h b/xfdashboard/plugin-manager.h
new file mode 100644
index 0000000..9894f1b
--- /dev/null
+++ b/xfdashboard/plugin-manager.h
@@ -0,0 +1,67 @@
+/*
+ * plugin-manager: Single-instance managing plugins
+ * 
+ * Copyright 2012-2015 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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 __XFDASHBOARD_PLUGIN_MANAGER__
+#define __XFDASHBOARD_PLUGIN_MANAGER__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define XFDASHBOARD_TYPE_PLUGIN_MANAGER				(xfdashboard_plugin_manager_get_type())
+#define XFDASHBOARD_PLUGIN_MANAGER(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_PLUGIN_MANAGER, XfdashboardPluginManager))
+#define XFDASHBOARD_IS_PLUGIN_MANAGER(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_PLUGIN_MANAGER))
+#define XFDASHBOARD_PLUGIN_MANAGER_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_PLUGIN_MANAGER, XfdashboardPluginManagerClass))
+#define XFDASHBOARD_IS_PLUGIN_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_PLUGIN_MANAGER))
+#define XFDASHBOARD_PLUGIN_MANAGER_GET_CLASS(obj)		(G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_PLUGIN_MANAGER, XfdashboardPluginManagerClass))
+
+typedef struct _XfdashboardPluginManager			XfdashboardPluginManager;
+typedef struct _XfdashboardPluginManagerClass		XfdashboardPluginManagerClass;
+typedef struct _XfdashboardPluginManagerPrivate		XfdashboardPluginManagerPrivate;
+
+struct _XfdashboardPluginManager
+{
+	/* Parent instance */
+	GObject							parent_instance;
+
+	/* Private structure */
+	XfdashboardPluginManagerPrivate	*priv;
+};
+
+struct _XfdashboardPluginManagerClass
+{
+	/*< private >*/
+	/* Parent class */
+	GObjectClass					parent_class;
+};
+
+/* Public API */
+GType xfdashboard_plugin_manager_get_type(void) G_GNUC_CONST;
+
+XfdashboardPluginManager* xfdashboard_plugin_manager_get_default(void);
+
+gboolean xfdashboard_plugin_manager_setup(XfdashboardPluginManager *self);
+
+G_END_DECLS
+
+#endif	/* __XFDASHBOARD_PLUGIN_MANAGER__ */
diff --git a/xfdashboard/plugin.c b/xfdashboard/plugin.c
new file mode 100644
index 0000000..85a01b9
--- /dev/null
+++ b/xfdashboard/plugin.c
@@ -0,0 +1,888 @@
+/*
+ * plugin: A plugin class managing loading the shared object as well as
+ *         initializing and setting up extensions to this application
+ * 
+ * Copyright 2012-2015 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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.
+ * 
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "plugin.h"
+
+#include <glib/gi18n-lib.h>
+
+
+/* Forward declaration */
+typedef enum /*< skip,prefix=XFDASHBOARD_PLUGIN_STATE >*/
+{
+	XFDASHBOARD_PLUGIN_STATE_NONE=0,
+	XFDASHBOARD_PLUGIN_STATE_INITIALIZED,
+	XFDASHBOARD_PLUGIN_STATE_ENABLED,
+} XfdashboardPluginState;
+
+
+/* Define this class in GObject system */
+G_DEFINE_TYPE(XfdashboardPlugin,
+				xfdashboard_plugin,
+				G_TYPE_TYPE_MODULE)
+
+/* Private structure - access only by public API if needed */
+#define XFDASHBOARD_PLUGIN_GET_PRIVATE(obj) \
+	(G_TYPE_INSTANCE_GET_PRIVATE((obj), XFDASHBOARD_TYPE_PLUGIN, XfdashboardPluginPrivate))
+
+struct _XfdashboardPluginPrivate
+{
+	/* Instance related */
+	gchar						*filename;
+	GModule						*module;
+	XfdashboardPluginState		state;
+	gchar						*lastLoadingError;
+
+	/* Properties related */
+	gchar						*id;
+	gchar						*name;
+	gchar						*description;
+	gchar						*author;
+	gchar						*copyright;
+	gchar						*license;
+};
+
+/* Properties */
+enum
+{
+	PROP_0,
+
+	PROP_FILENAME,
+
+	PROP_ID,
+	PROP_NAME,
+	PROP_DESCRIPTION,
+	PROP_AUTHOR,
+	PROP_COPYRIGHT,
+	PROP_LICENSE,
+
+	PROP_LAST
+};
+
+static GParamSpec* XfdashboardPluginProperties[PROP_LAST]={ 0, };
+
+
+/* IMPLEMENTATION: Private variables and methods */
+#define XFDASHBOARD_PLUGIN_CRITICAL_NOT_IMPLEMENTED(self, vfunc) \
+	g_critical(_("Plugin at path '%s' does not implement required virtual function XfdashboardPlugin::%s"), \
+				self->priv->filename ? self->priv->filename : _("unknown filename"), \
+				vfunc);
+
+#define XFDASHBOARD_PLUGIN_FUNCTION_NAME_INITIALIZE		"plugin_init"
+#define XFDASHBOARD_PLUGIN_FUNCTION_NAME_ENABLE			"plugin_enable"
+#define XFDASHBOARD_PLUGIN_FUNCTION_NAME_DISABLE		"plugin_disable"
+
+/* Get display name for XFDASHBOARD_PLUGIN_STATE_* enum values */
+static const gchar* _xfdashboard_plugin_get_plugin_state_value_name(XfdashboardPluginState inState)
+{
+	g_return_val_if_fail(inState>XFDASHBOARD_PLUGIN_STATE_ENABLED, NULL);
+
+	/* Lookup name for value and return it */
+	switch(inState)
+	{
+		case XFDASHBOARD_PLUGIN_STATE_NONE:
+			return("none");
+
+		case XFDASHBOARD_PLUGIN_STATE_INITIALIZED:
+			return("initialized");
+
+		case XFDASHBOARD_PLUGIN_STATE_ENABLED:
+			return("enabled");
+
+		default:
+			break;
+	}
+
+	/* We should normally never get here. But if we do return NULL. */
+	return(NULL);
+}
+
+/* Return error message of last load attempt */
+static const gchar* _xfdashboard_plugin_get_loading_error(XfdashboardPlugin *self)
+{
+	XfdashboardPluginPrivate	*priv;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_PLUGIN(self), NULL);
+
+	priv=self->priv;
+
+	/* Return error message of last loading attempt */
+	return(priv->lastLoadingError);
+}
+
+/* Set file name for plugin */
+static void _xfdashboard_plugin_set_filename(XfdashboardPlugin *self, const gchar *inFilename)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(inFilename && *inFilename);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+	g_return_if_fail(self->priv->filename==NULL);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->filename, inFilename)!=0)
+	{
+		/* Set value */
+		if(priv->filename) g_free(priv->filename);
+		priv->filename=g_strdup(inFilename);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_FILENAME]);
+	}
+}
+
+/* Set ID for plugin */
+static void _xfdashboard_plugin_set_id(XfdashboardPlugin *self, const gchar *inID)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(inID && *inID);
+	g_return_if_fail(self->priv->id==NULL);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->id, inID)!=0)
+	{
+		/* Set value */
+		if(priv->id) g_free(priv->id);
+		priv->id=g_strdup(inID);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_ID]);
+	}
+}
+
+/* Set name for plugin */
+static void _xfdashboard_plugin_set_name(XfdashboardPlugin *self, const gchar *inName)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(self->priv->name==NULL);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->name, inName)!=0)
+	{
+		/* Set value */
+		if(priv->name)
+		{
+			g_free(priv->name);
+			priv->name=NULL;
+		}
+
+		if(inName) priv->name=g_strdup(inName);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_NAME]);
+	}
+}
+
+/* Set description for plugin */
+static void _xfdashboard_plugin_set_description(XfdashboardPlugin *self, const gchar *inDescription)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(self->priv->description==NULL);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->description, inDescription)!=0)
+	{
+		/* Set value */
+		if(priv->description)
+		{
+			g_free(priv->description);
+			priv->description=NULL;
+		}
+
+		if(inDescription) priv->description=g_strdup(inDescription);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_DESCRIPTION]);
+	}
+}
+
+/* Set author for plugin */
+static void _xfdashboard_plugin_set_author(XfdashboardPlugin *self, const gchar *inAuthor)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(self->priv->author==NULL);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->author, inAuthor)!=0)
+	{
+		/* Set value */
+		if(priv->author)
+		{
+			g_free(priv->author);
+			priv->author=NULL;
+		}
+
+		if(inAuthor) priv->author=g_strdup(inAuthor);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_AUTHOR]);
+	}
+}
+
+/* Set copyright for plugin */
+static void _xfdashboard_plugin_set_copyright(XfdashboardPlugin *self, const gchar *inCopyright)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(self->priv->copyright==NULL);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->copyright, inCopyright)!=0)
+	{
+		/* Set value */
+		if(priv->copyright)
+		{
+			g_free(priv->copyright);
+			priv->copyright=NULL;
+		}
+
+		if(inCopyright) priv->copyright=g_strdup(inCopyright);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_COPYRIGHT]);
+	}
+}
+
+/* Set license for plugin */
+static void _xfdashboard_plugin_set_license(XfdashboardPlugin *self, const gchar *inLicense)
+{
+	XfdashboardPluginPrivate		*priv;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+	g_return_if_fail(self->priv->license==NULL);
+	g_return_if_fail(self->priv->state==XFDASHBOARD_PLUGIN_STATE_NONE);
+
+	priv=self->priv;
+
+	/* Set value if changed */
+	if(g_strcmp0(priv->license, inLicense)!=0)
+	{
+		/* Set value */
+		if(priv->license)
+		{
+			g_free(priv->license);
+			priv->license=NULL;
+		}
+
+		if(inLicense) priv->license=g_strdup(inLicense);
+
+		/* Notify about property change */
+		g_object_notify_by_pspec(G_OBJECT(self), XfdashboardPluginProperties[PROP_LICENSE]);
+	}
+}
+
+
+/* IMPLEMENTATION: GTypeModule */
+
+/* Load and initialize plugin */
+static gboolean _xfdashboard_plugin_load(GTypeModule *inModule)
+{
+	XfdashboardPlugin			*self;
+	XfdashboardPluginPrivate	*priv;
+	XfdashboardPluginClass		*klass;
+
+	g_return_val_if_fail(XFDASHBOARD_IS_PLUGIN(inModule), FALSE);
+	g_return_val_if_fail(G_IS_TYPE_MODULE(inModule), FALSE);
+
+	self=XFDASHBOARD_PLUGIN(inModule);
+	priv=self->priv;
+	klass=XFDASHBOARD_PLUGIN_GET_CLASS(self);
+
+	/* Reset last loading error if set */
+	if(priv->lastLoadingError)
+	{
+		g_free(priv->lastLoadingError);
+		priv->lastLoadingError=NULL;
+	}
+
+	/* Check if path to plugin was set and exists */
+	if(!priv->filename)
+	{
+		priv->lastLoadingError=g_strdup(_("Missing path to plugin"));
+		return(FALSE);
+	}
+
+	if(!g_file_test(priv->filename, G_FILE_TEST_IS_REGULAR))
+	{
+		priv->lastLoadingError=g_strdup_printf(_("Path '%s' does not exist"), priv->filename);
+		return(FALSE);
+	}
+
+	/* Check that plugin is not in any state */
+	if(priv->state!=XFDASHBOARD_PLUGIN_STATE_NONE)
+	{
+		priv->lastLoadingError=
+			g_strdup_printf(_("Bad state '%s' - expected '%s"),
+							_xfdashboard_plugin_get_plugin_state_value_name(priv->state),
+							_xfdashboard_plugin_get_plugin_state_value_name(XFDASHBOARD_PLUGIN_STATE_NONE));
+		return(FALSE);
+	}
+
+	/* Open plugin module */
+	if(priv->module)
+	{
+		priv->lastLoadingError=g_strdup(_("Plugin was already initialized"));
+		return(FALSE);
+	}
+
+	priv->module=g_module_open(priv->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+	if(!priv->module)
+	{
+		priv->lastLoadingError=g_strdup(g_module_error());
+		return(FALSE);
+	}
+
+	/* Check that plugin provides all necessary functions and get the address
+	 * to these functions.
+	 */
+	if(!g_module_symbol(priv->module, XFDASHBOARD_PLUGIN_FUNCTION_NAME_INITIALIZE, (gpointer*)&klass->initialize) ||
+		!g_module_symbol(priv->module, XFDASHBOARD_PLUGIN_FUNCTION_NAME_ENABLE, (gpointer*)&klass->enable) ||
+		!g_module_symbol(priv->module, XFDASHBOARD_PLUGIN_FUNCTION_NAME_DISABLE, (gpointer*)&klass->disable))
+	{
+		priv->lastLoadingError=g_strdup(g_module_error());
+		return(FALSE);
+	}
+
+	/* Initialize plugin */
+	if(klass->initialize)
+	{
+		klass->initialize(self);
+	}
+		else
+		{
+			/* If we get here the virtual function was not overridden */
+			priv->lastLoadingError=g_strdup(_("Plugin does not implement required virtual function XfdashboardPlugin::initialize"));
+
+			XFDASHBOARD_PLUGIN_CRITICAL_NOT_IMPLEMENTED(self, "initialize");
+			return(FALSE);
+		}
+
+	/* Check that plugin has required properties set */
+	if(!priv->id)
+	{
+		priv->lastLoadingError=g_strdup(_("Plugin did not set required ID"));
+		return(FALSE);
+	}
+
+	/* Set state of plugin */
+	priv->state=XFDASHBOARD_PLUGIN_STATE_INITIALIZED;
+
+	/* If we get here then loading and initializing plugin was successful */
+	g_debug("Loaded plugin '%s' successfully:\n  File: %s\n  Name: %s\n  Description: %s\n  Author: %s\n  Copyright: %s\n  License: %s",
+				priv->id,
+				priv->filename,
+				priv->name ? priv->name : "",
+				priv->description ? priv->description : "",
+				priv->author ? priv->author : "",
+				priv->copyright ? priv->copyright : "",
+				priv->license ? priv->license : "");
+
+	return(TRUE);
+}
+
+/* Disable and unload plugin */
+static void _xfdashboard_plugin_unload(GTypeModule *inModule)
+{
+	XfdashboardPlugin			*self;
+	XfdashboardPluginPrivate	*priv;
+	XfdashboardPluginClass		*klass;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(inModule));
+	g_return_if_fail(G_IS_TYPE_MODULE(inModule));
+
+	self=XFDASHBOARD_PLUGIN(inModule);
+	priv=self->priv;
+	klass=XFDASHBOARD_PLUGIN_GET_CLASS(self);
+
+	/* Disable plugin if it is still enabled */
+	if(priv->state==XFDASHBOARD_PLUGIN_STATE_ENABLED)
+	{
+		g_debug("Disabing plugin '%s' before unloading module", priv->id);
+		xfdashboard_plugin_disable(self);
+	}
+
+	/* Close plugin module */
+	if(priv->module)
+	{
+		/* Close module */
+		if(g_module_close(priv->module))
+		{
+			g_warning(_("Plugin '%s' could not be unloaded successfully: %s"),
+						priv->id ? priv->id : _("Unknown"),
+						g_module_error());
+			return;
+		}
+
+		/* Unset module and function pointers from plugin module */
+		klass->initialize=NULL;
+		klass->enable=NULL;
+		klass->disable=NULL;
+
+		priv->module=NULL;
+	}
+
+	/* Set state of plugin */
+	priv->state=XFDASHBOARD_PLUGIN_STATE_NONE;
+}
+
+/* IMPLEMENTATION: GObject */
+
+/* Dispose this object */
+static void _xfdashboard_plugin_dispose(GObject *inObject)
+{
+	XfdashboardPlugin			*self=XFDASHBOARD_PLUGIN(inObject);
+	XfdashboardPluginPrivate	*priv=self->priv;
+
+	/* Release allocated resources */
+	if(priv->module)
+	{
+		_xfdashboard_plugin_unload(G_TYPE_MODULE(self));
+	}
+
+	if(priv->lastLoadingError)
+	{
+		g_free(priv->lastLoadingError);
+		priv->lastLoadingError=NULL;
+	}
+
+	if(priv->id)
+	{
+		g_free(priv->id);
+		priv->id=NULL;
+	}
+
+	if(priv->name)
+	{
+		g_free(priv->name);
+		priv->name=NULL;
+	}
+
+	if(priv->description)
+	{
+		g_free(priv->description);
+		priv->description=NULL;
+	}
+
+	if(priv->author)
+	{
+		g_free(priv->author);
+		priv->author=NULL;
+	}
+
+	if(priv->copyright)
+	{
+		g_free(priv->copyright);
+		priv->copyright=NULL;
+	}
+
+	if(priv->license)
+	{
+		g_free(priv->license);
+		priv->license=NULL;
+	}
+
+	/* Call parent's class dispose method */
+	G_OBJECT_CLASS(xfdashboard_plugin_parent_class)->dispose(inObject);
+}
+
+/* Set/get properties */
+static void _xfdashboard_plugin_set_property(GObject *inObject,
+											guint inPropID,
+											const GValue *inValue,
+											GParamSpec *inSpec)
+{
+	XfdashboardPlugin			*self=XFDASHBOARD_PLUGIN(inObject);
+	
+	switch(inPropID)
+	{
+		case PROP_FILENAME:
+			_xfdashboard_plugin_set_filename(self, g_value_get_string(inValue));
+			break;
+
+		case PROP_ID:
+			_xfdashboard_plugin_set_id(self, g_value_get_string(inValue));
+			break;
+
+		case PROP_NAME:
+			_xfdashboard_plugin_set_name(self, g_value_get_string(inValue));
+			break;
+
+		case PROP_DESCRIPTION:
+			_xfdashboard_plugin_set_description(self, g_value_get_string(inValue));
+			break;
+
+		case PROP_AUTHOR:
+			_xfdashboard_plugin_set_author(self, g_value_get_string(inValue));
+			break;
+
+		case PROP_COPYRIGHT:
+			_xfdashboard_plugin_set_copyright(self, g_value_get_string(inValue));
+			break;
+
+		case PROP_LICENSE:
+			_xfdashboard_plugin_set_license(self, g_value_get_string(inValue));
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+			break;
+	}
+}
+
+static void _xfdashboard_plugin_get_property(GObject *inObject,
+												guint inPropID,
+												GValue *outValue,
+												GParamSpec *inSpec)
+{
+	XfdashboardPlugin			*self=XFDASHBOARD_PLUGIN(inObject);
+	XfdashboardPluginPrivate	*priv=self->priv;
+
+	switch(inPropID)
+	{
+		case PROP_FILENAME:
+			g_value_set_string(outValue, priv->filename);
+			break;
+
+		case PROP_ID:
+			g_value_set_string(outValue, priv->id);
+			break;
+
+		case PROP_NAME:
+			g_value_set_string(outValue, priv->name);
+			break;
+
+		case PROP_DESCRIPTION:
+			g_value_set_string(outValue, priv->description);
+			break;
+
+		case PROP_AUTHOR:
+			g_value_set_string(outValue, priv->author);
+			break;
+
+		case PROP_COPYRIGHT:
+			g_value_set_string(outValue, priv->copyright);
+			break;
+
+		case PROP_LICENSE:
+			g_value_set_string(outValue, priv->license);
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
+			break;
+	}
+}
+
+/* Class initialization
+ * Override functions in parent classes and define properties
+ * and signals
+ */
+static void xfdashboard_plugin_class_init(XfdashboardPluginClass *klass)
+{
+	GTypeModuleClass		*moduleClass=G_TYPE_MODULE_CLASS(klass);
+	GObjectClass			*gobjectClass=G_OBJECT_CLASS(klass);
+
+	/* Override functions */
+	moduleClass->load=_xfdashboard_plugin_load;
+	moduleClass->unload=_xfdashboard_plugin_unload;
+
+	gobjectClass->set_property=_xfdashboard_plugin_set_property;
+	gobjectClass->get_property=_xfdashboard_plugin_get_property;
+	gobjectClass->dispose=_xfdashboard_plugin_dispose;
+
+	/* Set up private structure */
+	g_type_class_add_private(klass, sizeof(XfdashboardPluginPrivate));
+
+	/* Define properties */
+	XfdashboardPluginProperties[PROP_FILENAME]=
+		g_param_spec_string("filename",
+							_("File name"),
+							_("Path and file name of this plugin"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
+
+	XfdashboardPluginProperties[PROP_ID]=
+		g_param_spec_string("id",
+							_("ID"),
+							_("The unique ID used to register this plugin"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	XfdashboardPluginProperties[PROP_NAME]=
+		g_param_spec_string("name",
+							_("name"),
+							_("Name of plugin"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	XfdashboardPluginProperties[PROP_DESCRIPTION]=
+		g_param_spec_string("description",
+							_("Description"),
+							_("A short description about this plugin"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	XfdashboardPluginProperties[PROP_AUTHOR]=
+		g_param_spec_string("author",
+							_("Author"),
+							_("The author of this plugin"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	XfdashboardPluginProperties[PROP_COPYRIGHT]=
+		g_param_spec_string("copyright",
+							_("Copyright"),
+							_("The copyright of this plugin which usually contains year of development"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	XfdashboardPluginProperties[PROP_LICENSE]=
+		g_param_spec_string("license",
+							_("License"),
+							_("The license of this plugin"),
+							NULL,
+							G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+	g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardPluginProperties);
+}
+
+/* Object initialization
+ * Create private structure and set up default values
+ */
+static void xfdashboard_plugin_init(XfdashboardPlugin *self)
+{
+	XfdashboardPluginPrivate	*priv;
+
+	priv=self->priv=XFDASHBOARD_PLUGIN_GET_PRIVATE(self);
+
+	/* Set up default values */
+	priv->filename=NULL;
+	priv->module=NULL;
+	priv->state=XFDASHBOARD_PLUGIN_STATE_NONE;
+	priv->lastLoadingError=NULL;
+
+	priv->id=NULL;
+	priv->name=NULL;
+	priv->description=NULL;
+	priv->author=NULL;
+	priv->copyright=NULL;
+	priv->license=NULL;
+}
+
+
+/* IMPLEMENTATION: Errors */
+
+GQuark xfdashboard_plugin_error_quark(void)
+{
+	return(g_quark_from_static_string("xfdashboard-plugin-error-quark"));
+}
+
+
+/* IMPLEMENTATION: Public API */
+
+/* Create an uninitialized plugin */
+XfdashboardPlugin* xfdashboard_plugin_new(const gchar *inPluginFilename, GError **outError)
+{
+	GObject			*plugin;
+
+	g_return_val_if_fail(inPluginFilename && *inPluginFilename, NULL);
+	g_return_val_if_fail(outError==NULL || *outError==NULL, FALSE);
+
+	/* Create object instance */
+	plugin=g_object_new(XFDASHBOARD_TYPE_PLUGIN,
+						"filename", inPluginFilename,
+						NULL);
+	if(!plugin)
+	{
+		/* Set error */
+		g_set_error(outError,
+					XFDASHBOARD_PLUGIN_ERROR,
+					XFDASHBOARD_PLUGIN_ERROR_ERROR,
+					_("Could not create plugin instance"));
+
+		/* Return NULL to indicate failure */
+		return(NULL);
+	}
+
+	/* Load plugin */
+	if(!g_type_module_use(G_TYPE_MODULE(plugin)))
+	{
+		/* Set error */
+		g_set_error(outError,
+					XFDASHBOARD_PLUGIN_ERROR,
+					XFDASHBOARD_PLUGIN_ERROR_ERROR,
+					"%s",
+					_xfdashboard_plugin_get_loading_error(XFDASHBOARD_PLUGIN(plugin)));
+
+		/* At this point we return NULL to indicate failure although the object
+		 * instance (subclassing GTypeModule) now exists and it was tried to
+		 * use it (via g_type_module_use). As describe in GObject documentation
+		 * the object must not be unreffed via g_object_unref() but we also should
+		 * not call g_type_module_unuse() because loading failed and the reference
+		 * counter was not increased.
+		 */
+		return(NULL);
+	}
+
+	/* Plugin loaded so return it */
+	return(XFDASHBOARD_PLUGIN(plugin));
+}
+
+/* Set plugin information */
+void xfdashboard_plugin_set_info(XfdashboardPlugin *self,
+									const gchar *inFirstPropertyName, ...)
+{
+	XfdashboardPluginPrivate		*priv;
+	va_list							args;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+
+	priv=self->priv;
+
+	/* Check that plugin is not initialized already */
+	if(priv->state!=XFDASHBOARD_PLUGIN_STATE_NONE)
+	{
+		g_critical(_("Setting plugin information for plugin '%s' at path '%s' failed: Plugin is already initialized"),
+					priv->id ? priv->id : _("Unknown"),
+					priv->filename);
+		return;
+	}
+
+	/* Set up properties */
+	va_start(args, inFirstPropertyName);
+	g_object_set_valist(G_OBJECT(self), inFirstPropertyName, args);
+	va_end(args);
+}
+
+/* Enable plugin */
+void xfdashboard_plugin_enable(XfdashboardPlugin *self)
+{
+	XfdashboardPluginPrivate		*priv;
+	XfdashboardPluginClass			*klass;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+
+	priv=self->priv;
+	klass=XFDASHBOARD_PLUGIN_GET_CLASS(self);
+
+	/* Do nothing and return immediately if plugin is enabled already */
+	if(priv->state==XFDASHBOARD_PLUGIN_STATE_ENABLED)
+	{
+		g_debug("Plugin '%s' is already enabled", priv->id);
+		return;
+	}
+
+	/* Check that plugin is initialized */
+	if(priv->state!=XFDASHBOARD_PLUGIN_STATE_INITIALIZED)
+	{
+		g_critical(_("Enabling plugin '%s' failed: Bad state '%s' - expected '%s'"),
+					priv->id ? priv->id : _("Unknown"),
+					_xfdashboard_plugin_get_plugin_state_value_name(priv->state),
+					_xfdashboard_plugin_get_plugin_state_value_name(XFDASHBOARD_PLUGIN_STATE_INITIALIZED));
+		return;
+	}
+
+	/* Call overriden enable function of plugin */
+	if(klass->enable)
+	{
+		/* Enable plugin */
+		klass->enable(self);
+		g_debug("Plugin '%s' enabled", priv->id);
+
+		/* Set disabled state, i.e. revert to initialized state */
+		priv->state=XFDASHBOARD_PLUGIN_STATE_ENABLED;
+
+		return;
+	}
+
+	/* If we get here the virtual function was not overridden */
+	XFDASHBOARD_PLUGIN_CRITICAL_NOT_IMPLEMENTED(self, "enable");
+	return;
+}
+
+/* Disable plugin */
+void xfdashboard_plugin_disable(XfdashboardPlugin *self)
+{
+	XfdashboardPluginPrivate		*priv;
+	XfdashboardPluginClass			*klass;
+
+	g_return_if_fail(XFDASHBOARD_IS_PLUGIN(self));
+
+	priv=self->priv;
+	klass=XFDASHBOARD_PLUGIN_GET_CLASS(self);
+
+	/* Do nothing and return immediately if plugin is not enabled */
+	if(priv->state!=XFDASHBOARD_PLUGIN_STATE_ENABLED)
+	{
+		g_debug("Plugin '%s' is already disabled", priv->id);
+		return;
+	}
+
+	/* Call overriden disable function of plugin */
+	if(klass->disable)
+	{
+		/* Disable plugin */
+		klass->disable(self);
+		g_debug("Plugin '%s' disabled", priv->id);
+
+		/* Set disabled state, i.e. revert to initialized state */
+		priv->state=XFDASHBOARD_PLUGIN_STATE_INITIALIZED;
+
+		return;
+	}
+
+	/* If we get here the virtual function was not overridden */
+	XFDASHBOARD_PLUGIN_CRITICAL_NOT_IMPLEMENTED(self, "disable");
+	return;
+}
diff --git a/xfdashboard/plugin.h b/xfdashboard/plugin.h
new file mode 100644
index 0000000..9f2d1ec
--- /dev/null
+++ b/xfdashboard/plugin.h
@@ -0,0 +1,109 @@
+/*
+ * plugin: A plugin class managing loading the shared object as well as
+ *         initializing and setting up extensions to this application
+ * 
+ * Copyright 2012-2015 Stephan Haller <nomad at froevel.de>
+ * 
+ * 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 __XFDASHBOARD_PLUGIN__
+#define __XFDASHBOARD_PLUGIN__
+
+#include <glib-object.h>
+#include <gmodule.h>
+
+G_BEGIN_DECLS
+
+/* Helper macros to declare, define and register GObject types in plugins */
+#define XFDASHBOARD_DECLARE_PLUGIN_TYPE(inFunctionNamePrefix) \
+	void inFunctionNamePrefix##_register_plugin_type(XfdashboardPlugin *inPlugin);
+
+#define XFDASHBOARD_DEFINE_PLUGIN_TYPE(inFunctionNamePrefix) \
+	void inFunctionNamePrefix##_register_plugin_type(XfdashboardPlugin *inPlugin) \
+	{ \
+		inFunctionNamePrefix##_register_type(G_TYPE_MODULE(inPlugin)); \
+	}
+
+#define XFDASHBOARD_REGISTER_PLUGIN_TYPE(self, inFunctionNamePrefix) \
+	inFunctionNamePrefix##_register_plugin_type(XFDASHBOARD_PLUGIN(self));
+
+
+/* Object declaration */
+#define XFDASHBOARD_TYPE_PLUGIN				(xfdashboard_plugin_get_type())
+#define XFDASHBOARD_PLUGIN(obj)				(G_TYPE_CHECK_INSTANCE_CAST((obj), XFDASHBOARD_TYPE_PLUGIN, XfdashboardPlugin))
+#define XFDASHBOARD_IS_PLUGIN(obj)			(G_TYPE_CHECK_INSTANCE_TYPE((obj), XFDASHBOARD_TYPE_PLUGIN))
+#define XFDASHBOARD_PLUGIN_CLASS(klass)		(G_TYPE_CHECK_CLASS_CAST((klass), XFDASHBOARD_TYPE_PLUGIN, XfdashboardPluginClass))
+#define XFDASHBOARD_IS_PLUGIN_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE((klass), XFDASHBOARD_TYPE_PLUGIN))
+#define XFDASHBOARD_PLUGIN_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), XFDASHBOARD_TYPE_PLUGIN, XfdashboardPluginClass))
+
+typedef struct _XfdashboardPlugin			XfdashboardPlugin;
+typedef struct _XfdashboardPluginClass		XfdashboardPluginClass;
+typedef struct _XfdashboardPluginPrivate	XfdashboardPluginPrivate;
+
+struct _XfdashboardPlugin
+{
+	/* Parent instance */
+	GTypeModule						parent_instance;
+
+	/* Private structure */
+	XfdashboardPluginPrivate		*priv;
+};
+
+struct _XfdashboardPluginClass
+{
+	/*< private >*/
+	/* Parent class */
+	GTypeModuleClass				parent_class;
+
+	/*< public >*/
+	/* Virtual functions */
+	void (*initialize)(XfdashboardPlugin *self);
+
+	void (*enable)(XfdashboardPlugin *self);
+	void (*disable)(XfdashboardPlugin *self);
+
+	void (*configure)(XfdashboardPlugin *self);
+};
+
+/* Error */
+#define XFDASHBOARD_PLUGIN_ERROR					(xfdashboard_plugin_error_quark())
+
+GQuark xfdashboard_plugin_error_quark(void);
+
+typedef enum /*< prefix=XFDASHBOARD_PLUGIN_ERROR >*/
+{
+	XFDASHBOARD_PLUGIN_ERROR_NONE,
+	XFDASHBOARD_PLUGIN_ERROR_ERROR,
+} XfdashboardPluginErrorEnum;
+
+/* Public API */
+GType xfdashboard_plugin_get_type(void) G_GNUC_CONST;
+
+XfdashboardPlugin* xfdashboard_plugin_new(const gchar *inPluginFilename, GError **outError);
+
+void xfdashboard_plugin_set_info(XfdashboardPlugin *self,
+									const gchar *inFirstPropertyName, ...)
+									G_GNUC_NULL_TERMINATED;
+
+void xfdashboard_plugin_enable(XfdashboardPlugin *self);
+void xfdashboard_plugin_disable(XfdashboardPlugin *self);
+
+G_END_DECLS
+
+#endif	/* __XFDASHBOARD_PLUGIN__ */

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list