[libpeas] Add basic support for plugin dependencies.



commit d230359cd8fb58b6628f4b2faaac515202fd975f
Author: Steve Frécinaux <code istique net>
Date:   Sat Jul 24 01:09:07 2010 +0200

    Add basic support for plugin dependencies.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=625156

 configure.ac                                       |    1 +
 docs/reference/libpeas-sections.txt                |    2 +
 libpeas/peas-engine.c                              |   47 ++++++-
 libpeas/peas-plugin-info.c                         |   42 ++++++
 libpeas/peas-plugin-info.h                         |    3 +
 peas-demo/plugins/Makefile.am                      |    2 +-
 peas-demo/plugins/secondtime/Makefile.am           |   19 +++
 peas-demo/plugins/secondtime/second-time.c         |  145 ++++++++++++++++++++
 peas-demo/plugins/secondtime/second-time.h         |   35 +++++
 .../plugins/secondtime/secondtime.peasdemo-plugin  |    9 ++
 10 files changed, 299 insertions(+), 6 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 1d5086a..e89f9d0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -298,6 +298,7 @@ peas-demo/Makefile
 peas-demo/plugins/Makefile
 peas-demo/plugins/helloworld/Makefile
 peas-demo/plugins/pythonhello/Makefile
+peas-demo/plugins/secondtime/Makefile
 peas-demo/plugins/seedhello/Makefile
 po/Makefile.in
 ])
diff --git a/docs/reference/libpeas-sections.txt b/docs/reference/libpeas-sections.txt
index 62b937e..9196867 100644
--- a/docs/reference/libpeas-sections.txt
+++ b/docs/reference/libpeas-sections.txt
@@ -185,6 +185,8 @@ peas_plugin_info_is_builtin
 peas_plugin_info_get_module_name
 peas_plugin_info_get_module_dir
 peas_plugin_info_get_data_dir
+peas_plugin_info_get_dependencies
+peas_plugin_info_has_dependency
 peas_plugin_info_get_name
 peas_plugin_info_get_description
 peas_plugin_info_get_icon_name
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c
index 8cbab4e..336fad2 100644
--- a/libpeas/peas-engine.c
+++ b/libpeas/peas-engine.c
@@ -754,6 +754,9 @@ static gboolean
 load_plugin (PeasEngine     *engine,
              PeasPluginInfo *info)
 {
+  const gchar **dependencies;
+  PeasPluginInfo *dep_info;
+  guint i;
   PeasPluginLoader *loader;
 
   if (peas_plugin_info_is_loaded (info))
@@ -762,6 +765,24 @@ load_plugin (PeasEngine     *engine,
   if (!peas_plugin_info_is_available (info))
     return FALSE;
 
+  /* We set the plugin info as loaded before trying to load the dependencies,
+   * to make sure we won't have an infinite loop. */
+  info->loaded = TRUE;
+
+  dependencies = peas_plugin_info_get_dependencies (info);
+  for (i = 0; dependencies[i] != NULL; i++)
+    {
+      dep_info = peas_engine_get_plugin_info (engine, dependencies[i]);
+      if (!dep_info)
+        {
+          g_warning ("Plugin not found: %s", dependencies[i]);
+          return FALSE;
+        }
+
+      if (!peas_engine_load_plugin (engine, dep_info))
+        return FALSE;
+    }
+
   loader = get_plugin_loader (engine, info);
 
   if (loader == NULL)
@@ -772,11 +793,10 @@ load_plugin (PeasEngine     *engine,
       return FALSE;
     }
 
-  info->loaded = peas_plugin_loader_load (loader, info);
-
-  if (info->loaded == FALSE)
+  if (!peas_plugin_loader_load (loader, info))
     {
       g_warning ("Error loading plugin '%s'", info->name);
+      info->loaded = FALSE;
       info->available = FALSE;
       return FALSE;
     }
@@ -824,20 +844,37 @@ static void
 peas_engine_unload_plugin_real (PeasEngine     *engine,
                                 PeasPluginInfo *info)
 {
+  GList *item;
+  const gchar *module_name;
   PeasPluginLoader *loader;
 
   if (!peas_plugin_info_is_loaded (info) ||
       !peas_plugin_info_is_available (info))
     return;
 
+  /* We set the plugin info as unloaded before trying to unload the
+   * dependants, to make sure we won't have an infinite loop. */
+  info->loaded = FALSE;
+
+  /* First unload all the dependant plugins */
+  module_name = peas_plugin_info_get_module_name (info);
+  for (item = engine->priv->plugin_list; item; item = item->next)
+    {
+      PeasPluginInfo *other_info = PEAS_PLUGIN_INFO (item->data);
+
+      if (!peas_plugin_info_is_loaded (other_info))
+        continue;
+
+      if (peas_plugin_info_has_dependency (other_info, module_name))
+         peas_engine_unload_plugin (engine, other_info);
+    }
+
   /* find the loader and tell it to gc and unload the plugin */
   loader = get_plugin_loader (engine, info);
 
   peas_plugin_loader_garbage_collect (loader);
   peas_plugin_loader_unload (loader, info);
 
-  info->loaded = FALSE;
-
   g_object_notify (G_OBJECT (engine), "loaded-plugins");
 }
 
diff --git a/libpeas/peas-plugin-info.c b/libpeas/peas-plugin-info.c
index a3dd0da..68931c7 100644
--- a/libpeas/peas-plugin-info.c
+++ b/libpeas/peas-plugin-info.c
@@ -445,6 +445,48 @@ peas_plugin_info_get_data_dir (const PeasPluginInfo *info)
 }
 
 /**
+ * peas_plugin_info_get_dependencies:
+ * @info: A #PeasPluginInfo.
+ *
+ * Gets the dependencies of the plugin.
+ *
+ * Returns: the plugin's dependencies.
+ */
+const gchar **
+peas_plugin_info_get_dependencies (const PeasPluginInfo *info)
+{
+  g_return_val_if_fail (info != NULL, NULL);
+
+  return (const gchar **) info->dependencies;
+}
+
+/**
+ * peas_plugin_info_has_dependency:
+ * @info: A #PeasPluginInfo.
+ * @module_name: The name of the plugin to check.
+ *
+ * Check if the plugin depends on another plugin.
+ *
+ * Returns: whether the plugin depends on the plugin @module_name.
+ */
+gboolean
+peas_plugin_info_has_dependency (const PeasPluginInfo *info,
+                                 const gchar          *module_name)
+{
+  guint i;
+
+  g_return_val_if_fail (info != NULL, FALSE);
+  g_return_val_if_fail (module_name != NULL, FALSE);
+
+  for (i = 0; info->dependencies[i] != NULL; i++)
+    if (g_ascii_strcasecmp (module_name, info->dependencies[i]) == 0)
+      return TRUE;
+
+  return FALSE;
+}
+
+
+/**
  * peas_plugin_info_get_name:
  * @info: A #PeasPluginInfo.
  *
diff --git a/libpeas/peas-plugin-info.h b/libpeas/peas-plugin-info.h
index d60deab..10756d1 100644
--- a/libpeas/peas-plugin-info.h
+++ b/libpeas/peas-plugin-info.h
@@ -46,6 +46,9 @@ gboolean      peas_plugin_info_is_builtin       (const PeasPluginInfo *info);
 const gchar  *peas_plugin_info_get_module_name  (const PeasPluginInfo *info);
 const gchar  *peas_plugin_info_get_module_dir   (const PeasPluginInfo *info);
 const gchar  *peas_plugin_info_get_data_dir     (const PeasPluginInfo *info);
+const gchar **peas_plugin_info_get_dependencies (const PeasPluginInfo *info);
+gboolean      peas_plugin_info_has_dependency   (const PeasPluginInfo *info,
+                                                 const gchar          *name);
 
 const gchar  *peas_plugin_info_get_name         (const PeasPluginInfo *info);
 const gchar  *peas_plugin_info_get_description  (const PeasPluginInfo *info);
diff --git a/peas-demo/plugins/Makefile.am b/peas-demo/plugins/Makefile.am
index 3ce8c21..d2824e1 100644
--- a/peas-demo/plugins/Makefile.am
+++ b/peas-demo/plugins/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = helloworld
+SUBDIRS = helloworld secondtime
 
 if ENABLE_PYTHON
 SUBDIRS += pythonhello
diff --git a/peas-demo/plugins/secondtime/Makefile.am b/peas-demo/plugins/secondtime/Makefile.am
new file mode 100644
index 0000000..3a1c4c5
--- /dev/null
+++ b/peas-demo/plugins/secondtime/Makefile.am
@@ -0,0 +1,19 @@
+plugindir = $(libdir)/peas-demo/plugins/secondtime
+
+INCLUDES = \
+	-I$(top_srcdir) 	\
+	$(PEAS_CFLAGS)		\
+	$(PEASUI_CFLAGS)
+
+plugin_LTLIBRARIES = libsecondtime.la
+
+libsecondtime_la_SOURCES = \
+	second-time.h		\
+	second-time.c
+
+libsecondtime_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS)
+libsecondtime_la_LIBADD  = $(PEAS_LIBS) $(PEASUI_LIBS)
+
+plugin_DATA = secondtime.peasdemo-plugin
+
+EXTRA_DIST = $(plugin_DATA)
diff --git a/peas-demo/plugins/secondtime/second-time.c b/peas-demo/plugins/secondtime/second-time.c
new file mode 100644
index 0000000..fdb7f95
--- /dev/null
+++ b/peas-demo/plugins/secondtime/second-time.c
@@ -0,0 +1,145 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+#include <gtk/gtk.h>
+
+#include <libpeas/peas.h>
+
+#include "second-time.h"
+
+static void peas_activatable_iface_init     (PeasActivatableInterface    *iface);
+
+G_DEFINE_DYNAMIC_TYPE_EXTENDED (PeasDemoSecondTime,
+                                peasdemo_second_time,
+                                PEAS_TYPE_EXTENSION_BASE,
+                                0,
+                                G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_TYPE_ACTIVATABLE,
+                                                               peas_activatable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_OBJECT
+};
+
+static void
+peasdemo_second_time_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  PeasDemoSecondTime *plugin = PEASDEMO_SECOND_TIME (object);
+
+  switch (prop_id)
+    {
+    case PROP_OBJECT:
+      plugin->window = GTK_WIDGET (g_value_dup_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+peasdemo_second_time_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  PeasDemoSecondTime *plugin = PEASDEMO_SECOND_TIME (object);
+
+  switch (prop_id)
+    {
+    case PROP_OBJECT:
+      g_value_set_object (value, plugin->window);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+peasdemo_second_time_init (PeasDemoSecondTime *plugin)
+{
+  g_debug (G_STRFUNC);
+}
+
+static void
+peasdemo_second_time_finalize (GObject *object)
+{
+  PeasDemoSecondTime *plugin = PEASDEMO_SECOND_TIME (object);
+
+  g_debug (G_STRFUNC);
+
+  g_object_unref (plugin->label);
+
+  G_OBJECT_CLASS (peasdemo_second_time_parent_class)->finalize (object);
+}
+
+static GtkBox *
+get_box (GtkWidget *window)
+{
+  return GTK_BOX (gtk_bin_get_child (GTK_BIN (window)));
+}
+
+static void
+peasdemo_second_time_activate (PeasActivatable *activatable)
+{
+  PeasDemoSecondTime *plugin = PEASDEMO_SECOND_TIME (activatable);
+  GtkWidget *label;
+
+  g_debug (G_STRFUNC);
+
+  plugin->label = gtk_label_new ("A second time!");
+  gtk_box_pack_start (get_box (plugin->window), plugin->label, 1, 1, 0);
+  gtk_widget_show (plugin->label);
+  g_object_ref (plugin->label);
+}
+
+static void
+peasdemo_second_time_deactivate (PeasActivatable *activatable)
+{
+  PeasDemoSecondTime *plugin = PEASDEMO_SECOND_TIME (activatable);
+
+  g_debug (G_STRFUNC);
+
+  gtk_container_remove (GTK_CONTAINER (get_box (plugin->window)), plugin->label);
+}
+
+static void
+peasdemo_second_time_class_init (PeasDemoSecondTimeClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = peasdemo_second_time_set_property;
+  object_class->get_property = peasdemo_second_time_get_property;
+  object_class->finalize = peasdemo_second_time_finalize;
+
+  g_object_class_override_property (object_class, PROP_OBJECT, "object");
+}
+
+static void
+peas_activatable_iface_init (PeasActivatableInterface *iface)
+{
+  iface->activate = peasdemo_second_time_activate;
+  iface->deactivate = peasdemo_second_time_deactivate;
+}
+
+static void
+peasdemo_second_time_class_finalize (PeasDemoSecondTimeClass *klass)
+{
+}
+
+G_MODULE_EXPORT void
+peas_register_types (PeasObjectModule *module)
+{
+  peasdemo_second_time_register_type (G_TYPE_MODULE (module));
+
+  peas_object_module_register_extension_type (module,
+                                              PEAS_TYPE_ACTIVATABLE,
+                                              PEASDEMO_TYPE_SECOND_TIME);
+}
diff --git a/peas-demo/plugins/secondtime/second-time.h b/peas-demo/plugins/secondtime/second-time.h
new file mode 100644
index 0000000..c0345ae
--- /dev/null
+++ b/peas-demo/plugins/secondtime/second-time.h
@@ -0,0 +1,35 @@
+#ifndef __PEASDEMO_SECOND_TIME_H__
+#define __PEASDEMO_SECOND_TIME_H__
+
+#include <gtk/gtk.h>
+#include <libpeas/peas.h>
+
+G_BEGIN_DECLS
+
+#define PEASDEMO_TYPE_SECOND_TIME         (peasdemo_second_time_get_type ())
+#define PEASDEMO_SECOND_TIME(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), PEASDEMO_TYPE_SECOND_TIME, PeasDemoSecondTime))
+#define PEASDEMO_SECOND_TIME_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), PEASDEMO_TYPE_SECOND_TIME, PeasDemoSecondTime))
+#define PEASDEMO_IS_SECOND_TIME(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), PEASDEMO_TYPE_SECOND_TIME))
+#define PEASDEMO_IS_SECOND_TIME_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), PEASDEMO_TYPE_SECOND_TIME))
+#define PEASDEMO_SECOND_TIME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PEASDEMO_TYPE_SECOND_TIME, PeasDemoSecondTimeClass))
+
+typedef struct _PeasDemoSecondTime       PeasDemoSecondTime;
+typedef struct _PeasDemoSecondTimeClass  PeasDemoSecondTimeClass;
+
+struct _PeasDemoSecondTime {
+  PeasExtensionBase parent_instance;
+
+  GtkWidget *window;
+  GtkWidget *label;
+};
+
+struct _PeasDemoSecondTimeClass {
+  PeasExtensionBaseClass parent_class;
+};
+
+GType                 peasdemo_second_time_get_type               (void) G_GNUC_CONST;
+G_MODULE_EXPORT void  peas_register_types                         (PeasObjectModule *module);
+
+G_END_DECLS
+
+#endif /* __PeasDEMO_HELLO_WORLD_PLUGIN_H__ */
diff --git a/peas-demo/plugins/secondtime/secondtime.peasdemo-plugin b/peas-demo/plugins/secondtime/secondtime.peasdemo-plugin
new file mode 100644
index 0000000..22c798e
--- /dev/null
+++ b/peas-demo/plugins/secondtime/secondtime.peasdemo-plugin
@@ -0,0 +1,9 @@
+[PeasDemo Plugin]
+Module=secondtime
+Depends=helloworld
+IAge=2
+Name=A Second Time!
+Description=Inserts a box containing "A second time!" in every windows.
+Authors=Steve Frécinaux <code istique net>
+Copyright=Copyright © 2010 Steve Frécinaux
+Website=http://live.gnome.org/Libpeas



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]