[gnome-builder/wip/extensions] extensions: use external data in libpeas plugin info
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/extensions] extensions: use external data in libpeas plugin info
- Date: Sun, 28 Jun 2015 07:43:26 +0000 (UTC)
commit 15c09a33c6cd92a06b79b0db93bdd9a5e6c7687c
Author: Christian Hergert <christian hergert me>
Date: Sun Jun 28 00:41:04 2015 -0700
extensions: use external data in libpeas plugin info
This required a lot of churn in the IdeExtensionPoint API (which is a good
thing). It also required making services and a few other base classes use
GTypeInterface instead.
However, this allows for using dependency injection from .plugin files
for a concrete implementation. We can even swap out the old version at
runtime for a higher priority version when a plugin is loaded/unloaded.
libide/ide-extension-point.c | 282 +++++++++++++++++++-----------------------
libide/ide-extension-point.h | 15 ++-
2 files changed, 133 insertions(+), 164 deletions(-)
---
diff --git a/libide/ide-extension-point.c b/libide/ide-extension-point.c
index 7d502ff..0a145a2 100644
--- a/libide/ide-extension-point.c
+++ b/libide/ide-extension-point.c
@@ -20,27 +20,22 @@
#include <glib/gi18n.h>
#include <libpeas/peas.h>
+#include <stdlib.h>
#include "ide-extension-point.h"
struct _IdeExtensionPoint
{
GObject parent_instance;
- const gchar *name;
- GPtrArray *extensions;
-};
-typedef struct
-{
- const gchar *module_name;
- GType type;
- gint priority;
- guint loaded : 1;
-} IdeExtension;
+ GType interface_type;
+ const gchar *match_key;
+ const gchar *priority_key;
+};
enum {
PROP_0,
- PROP_NAME,
+ PROP_REQUIRED_TYPE,
LAST_PROP
};
@@ -56,38 +51,11 @@ static GRecMutex gExtensionsMutex;
static GHashTable *gExtensions;
static guint gSignals [LAST_SIGNAL];
-static IdeExtension *
-ide_extension_new (GType type,
- gint priority)
-{
- IdeExtension *exten;
- GTypePlugin *plugin;
-
- exten = g_slice_new0 (IdeExtension);
- exten->type = type;
- exten->priority = priority;
- exten->loaded = TRUE;
-
- plugin = g_type_get_plugin (type);
-
- if (PEAS_IS_OBJECT_MODULE (plugin))
- {
- gchar *module_name;
-
- g_object_get (plugin, "module-name", &module_name, NULL);
- exten->module_name = g_intern_string (module_name);
- g_free (module_name);
- }
-
- return exten;
-}
-
static void
load_plugin_cb (PeasEngine *engine,
PeasPluginInfo *plugin_info,
gpointer unused)
{
- const gchar *module_name;
GHashTableIter iter;
gpointer key;
gpointer value;
@@ -95,13 +63,6 @@ load_plugin_cb (PeasEngine *engine,
g_assert (PEAS_IS_ENGINE (engine));
g_assert (plugin_info != NULL);
- /*
- * FIXME: Since we don't have loader information, we could possibly have
- * two plugins from different loaders with the same module name.
- */
-
- module_name = peas_plugin_info_get_module_name (plugin_info);
-
g_rec_mutex_lock (&gExtensionsMutex);
g_hash_table_iter_init (&iter, gExtensions);
@@ -109,24 +70,8 @@ load_plugin_cb (PeasEngine *engine,
while (g_hash_table_iter_next (&iter, &key, &value))
{
IdeExtensionPoint *point = value;
- gboolean emit_changed = FALSE;
- gsize i;
- for (i = 0; i < point->extensions->len; i++)
- {
- IdeExtension *exten = g_ptr_array_index (point->extensions, i);
-
- if (g_strcmp0 (exten->module_name, module_name) == 0)
- {
- if (exten->loaded != TRUE)
- {
- exten->loaded = TRUE;
- emit_changed = TRUE;
- }
- }
- }
-
- if (emit_changed)
+ if (peas_engine_provides_extension (engine, plugin_info, point->interface_type))
g_signal_emit (point, gSignals [CHANGED], 0);
}
@@ -138,7 +83,6 @@ unload_plugin_cb (PeasEngine *engine,
PeasPluginInfo *plugin_info,
gpointer unused)
{
- const gchar *module_name;
GHashTableIter iter;
gpointer key;
gpointer value;
@@ -146,13 +90,6 @@ unload_plugin_cb (PeasEngine *engine,
g_assert (PEAS_IS_ENGINE (engine));
g_assert (plugin_info != NULL);
- /*
- * FIXME: Since we don't have loader information, we could possibly have
- * two plugins from different loaders with the same module name.
- */
-
- module_name = peas_plugin_info_get_module_name (plugin_info);
-
g_rec_mutex_lock (&gExtensionsMutex);
g_hash_table_iter_init (&iter, gExtensions);
@@ -160,24 +97,8 @@ unload_plugin_cb (PeasEngine *engine,
while (g_hash_table_iter_next (&iter, &key, &value))
{
IdeExtensionPoint *point = value;
- gboolean emit_changed = FALSE;
- gsize i;
- for (i = 0; i < point->extensions->len; i++)
- {
- IdeExtension *exten = g_ptr_array_index (point->extensions, i);
-
- if (g_strcmp0 (exten->module_name, module_name) == 0)
- {
- if (exten->loaded != FALSE)
- {
- exten->loaded = FALSE;
- emit_changed = TRUE;
- }
- }
- }
-
- if (emit_changed)
+ if (peas_engine_provides_extension (engine, plugin_info, point->interface_type))
g_signal_emit (point, gSignals [CHANGED], 0);
}
@@ -207,23 +128,17 @@ ensure_plugin_signals_locked (void)
}
static void
-ide_extension_point_finalize (GObject *object)
-{
- G_OBJECT_CLASS (ide_extension_point_parent_class)->finalize (object);
-}
-
-static void
ide_extension_point_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
- IdeExtensionPoint *self = IDE_EXTENSION_POINT (object);
+ IdeExtensionPoint *self = (IdeExtensionPoint *)object;
switch (prop_id)
{
- case PROP_NAME:
- g_value_set_static_string (value, self->name);
+ case PROP_REQUIRED_TYPE:
+ g_value_set_gtype (value, self->interface_type);
break;
default:
@@ -237,12 +152,12 @@ ide_extension_point_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
- IdeExtensionPoint *self = IDE_EXTENSION_POINT (object);
+ IdeExtensionPoint *self = (IdeExtensionPoint *)object;
switch (prop_id)
{
- case PROP_NAME:
- self->name = g_intern_string (g_value_get_string (value));
+ case PROP_REQUIRED_TYPE:
+ self->interface_type = g_value_get_gtype (value);
break;
default:
@@ -255,15 +170,14 @@ ide_extension_point_class_init (IdeExtensionPointClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = ide_extension_point_finalize;
object_class->get_property = ide_extension_point_get_property;
object_class->set_property = ide_extension_point_set_property;
- gParamSpecs [PROP_NAME] =
- g_param_spec_string("name",
- _("Name"),
- _("Name"),
- NULL,
+ gParamSpecs [PROP_REQUIRED_TYPE] =
+ g_param_spec_gtype ("required-type",
+ _("Required Type"),
+ _("Required Type"),
+ G_TYPE_INTERFACE,
(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, gParamSpecs);
@@ -278,7 +192,39 @@ ide_extension_point_class_init (IdeExtensionPointClass *klass)
static void
ide_extension_point_init (IdeExtensionPoint *self)
{
- self->extensions = g_ptr_array_new ();
+}
+
+void
+ide_extension_point_register (GType interface_type,
+ const gchar *match_key,
+ const gchar *priority_key)
+{
+ IdeExtensionPoint *point;
+
+ g_return_if_fail (G_TYPE_IS_INTERFACE (interface_type));
+
+ point = g_object_new (IDE_TYPE_EXTENSION_POINT,
+ "required-type", interface_type,
+ NULL);
+ point->match_key = g_intern_string (match_key);
+ point->priority_key = g_intern_string (priority_key);
+
+ g_rec_mutex_lock (&gExtensionsMutex);
+
+ if (gExtensions == NULL)
+ gExtensions = g_hash_table_new (NULL, NULL);
+
+ if (g_hash_table_contains (gExtensions, (gpointer)interface_type))
+ {
+ g_warning ("IdeExtensionPoint for interface \"%s\" is already registered.",
+ g_type_name (interface_type));
+ goto unlock;
+ }
+
+ g_hash_table_insert (gExtensions, (gpointer)interface_type, point);
+
+unlock:
+ g_rec_mutex_unlock (&gExtensionsMutex);
}
/**
@@ -289,67 +235,54 @@ ide_extension_point_init (IdeExtensionPoint *self)
* Returns: (transfer none): An #IdeExtensionPoint.
*/
IdeExtensionPoint *
-ide_extension_point_lookup (const gchar *name)
+ide_extension_point_lookup (GType type)
{
- IdeExtensionPoint *self;
+ IdeExtensionPoint *point = NULL;
+
+ g_return_val_if_fail (G_TYPE_IS_INTERFACE (type), NULL);
g_rec_mutex_lock (&gExtensionsMutex);
ensure_plugin_signals_locked ();
- name = g_intern_string (name);
-
- if (gExtensions == NULL)
- gExtensions = g_hash_table_new (NULL, NULL);
-
- self = g_hash_table_lookup (gExtensions, name);
-
- if (self == NULL)
- {
- self = g_object_new (IDE_TYPE_EXTENSION_POINT,
- "name", name,
- NULL);
- g_hash_table_insert (gExtensions, (gchar *)name, self);
- }
+ if (gExtensions != NULL)
+ point = g_hash_table_lookup (gExtensions, (gpointer)type);
g_rec_mutex_unlock (&gExtensionsMutex);
- return self;
+ return point;
}
-static gint
-compare_extension (gconstpointer a,
- gconstpointer b)
+static gboolean
+matches_value (IdeExtensionPoint *point,
+ PeasPluginInfo *plugin_info,
+ const gchar *match_value)
{
- const IdeExtension *exta = a;
- const IdeExtension *extb = b;
+ const gchar *line;
- if (exta->priority == extb->priority)
- return g_strcmp0 (g_type_name (exta->type), g_type_name (extb->type));
+ if ((point->match_key == NULL) || (match_value == NULL))
+ return TRUE;
- return extb->priority - exta->priority;
-}
+ line = peas_plugin_info_get_external_data (plugin_info, point->match_key);
-void
-ide_extension_point_implement (const gchar *name,
- GType implementation_type,
- gint priority)
-{
- IdeExtensionPoint *self;
- IdeExtension *exten;
+ if (line != NULL)
+ {
+ g_auto(GStrv) parts = NULL;
+ gint i;
- g_return_if_fail (name);
- g_return_if_fail (*name != '\0');
- g_return_if_fail (implementation_type != G_TYPE_INVALID);
- g_return_if_fail (G_TYPE_IS_OBJECT (implementation_type));
+ if (strstr (line, ",") == NULL)
+ return (g_strcmp0 (match_value, line) == 0);
- self = ide_extension_point_lookup (name);
- exten = ide_extension_new (implementation_type, priority);
+ parts = g_strsplit (line, ",", 0);
- g_ptr_array_add (self->extensions, exten);
- g_ptr_array_sort (self->extensions, compare_extension);
+ for (i = 0; parts [i]; i++)
+ {
+ if (g_strcmp0 (parts [i], match_value))
+ return TRUE;
+ }
+ }
- g_signal_emit (self, gSignals [CHANGED], 0);
+ return FALSE;
}
/**
@@ -360,30 +293,65 @@ ide_extension_point_implement (const gchar *name,
* Returns: (transfer full) (nullable) (type GObject.Object): A new #GObject or %NULL.
*/
gpointer
-ide_extension_point_create (const gchar *name,
+ide_extension_point_create (GType type,
+ const gchar *match_value,
const gchar *first_property,
...)
{
- IdeExtensionPoint *self;
+ IdeExtensionPoint *point;
+ const GList *list;
+ PeasEngine *engine;
+ PeasPluginInfo *best_match = NULL;
+ gint best_match_priority = G_MAXINT32;
gpointer ret = NULL;
va_list args;
- gint i;
- self = ide_extension_point_lookup (name);
+ g_return_val_if_fail (G_TYPE_IS_INTERFACE (type), NULL);
+
+ point = ide_extension_point_lookup (type);
+
+ if (point == NULL)
+ {
+ g_warning ("No IdeExtensionPoint has been registered for type \"%s\".",
+ g_type_name (type));
+ return NULL;
+ }
+
+ engine = peas_engine_get_default ();
+ list = peas_engine_get_plugin_list (engine);
- for (i = 0; (ret == NULL) && (i < self->extensions->len); i++)
+ for (; list; list = list->next)
{
- IdeExtension *exten;
+ PeasPluginInfo *plugin_info = list->data;
+ const gchar *priority_str;
+ gint priority = 0;
- exten = g_ptr_array_index (self->extensions, i);
+ if (!peas_plugin_info_is_loaded (plugin_info))
+ continue;
+
+ if (!peas_engine_provides_extension (engine, plugin_info, type))
+ continue;
- if (!exten->loaded)
+ if (!matches_value (point, plugin_info, match_value))
continue;
+ priority_str = peas_plugin_info_get_external_data (plugin_info, point->priority_key);
+
+ if (priority_str != NULL)
+ priority = atoi (priority_str);
+
+ if (priority < best_match_priority)
+ best_match = plugin_info;
+ }
+
+ if (best_match)
+ {
va_start (args, first_property);
- ret = g_object_new_valist (exten->type, first_property, args);
+ ret = peas_engine_create_extension_valist (engine, best_match, type, first_property, args);
va_end (args);
}
+ g_print ("Created Type: %s\n", ret ? G_OBJECT_TYPE_NAME (ret) : "<None>");
+
return ret;
}
diff --git a/libide/ide-extension-point.h b/libide/ide-extension-point.h
index e917a68..b757459 100644
--- a/libide/ide-extension-point.h
+++ b/libide/ide-extension-point.h
@@ -27,13 +27,14 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeExtensionPoint, ide_extension_point, IDE, EXTENSION_POINT, GObject)
-IdeExtensionPoint *ide_extension_point_lookup (const gchar *name);
-void ide_extension_point_implement (const gchar *name,
- GType implementation_type,
- gint priority);
-gpointer ide_extension_point_create (const gchar *name,
- const gchar *first_property,
- ...);
+void ide_extension_point_register (GType interface_type,
+ const gchar *match_key,
+ const gchar *priority_key);
+IdeExtensionPoint *ide_extension_point_lookup (GType interface_type);
+gpointer ide_extension_point_create (GType interface_type,
+ const gchar *match_key,
+ const gchar *first_property,
+ ...);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]