[gnome-builder] plugins: add GParameter helper



commit 08310b69ad2a1c34fa3dc1a25246309e944b648f
Author: Christian Hergert <chergert redhat com>
Date:   Sat Mar 11 01:47:16 2017 -0800

    plugins: add GParameter helper
    
    Libpeas is not sufficient to extract GParameters that we need because we
    also care about the base objects in the prerequisites, not just interfaces.
    
    This is a sort of barebones implementation of that. Scan the interfaces
    chain, and then the objects that are pre-reqs. If we find the property,
    all good.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=779891

 libide/plugins/ide-extension-util.c |  178 +++++++++++++++++++++++++++++++++++
 libide/plugins/ide-extension-util.h |   21 +++-
 2 files changed, 193 insertions(+), 6 deletions(-)
---
diff --git a/libide/plugins/ide-extension-util.c b/libide/plugins/ide-extension-util.c
index 77b1b90..5d81c53 100644
--- a/libide/plugins/ide-extension-util.c
+++ b/libide/plugins/ide-extension-util.c
@@ -18,6 +18,8 @@
 
 #define G_LOG_DOMAIN "ide-extension-util"
 
+#include <glib-object.h>
+#include <gobject/gvaluecollector.h>
 #include <stdlib.h>
 
 #include "ide-extension-util.h"
@@ -92,3 +94,179 @@ ide_extension_util_can_use_plugin (PeasEngine     *engine,
   settings = g_settings_new_with_path ("org.gnome.builder.extension-type", path);
   return g_settings_get_boolean (settings, "enabled");
 }
+
+static void
+clear_param (gpointer data)
+{
+  GParameter *p = data;
+  g_value_unset (&p->value);
+}
+
+static GType
+find_property_type (GType        type,
+                    const gchar *name)
+{
+  g_autoptr(GArray) types = NULL;
+  g_autofree GType *prereqs = NULL;
+  guint n_prereqs = 0;
+  GType ancestor = type;
+
+  g_assert (name != NULL);
+  g_assert (G_TYPE_IS_INTERFACE (type));
+
+  /* Collect all the types to locate properties from */
+  types = g_array_new (FALSE, FALSE, sizeof (GType));
+  for (ancestor = type; ancestor != 0; ancestor = g_type_parent (ancestor))
+    g_array_append_val (types, ancestor);
+  prereqs = g_type_interface_prerequisites (type, &n_prereqs);
+  for (guint i = 0; i < n_prereqs; i++)
+    g_array_append_val (types, prereqs[i]);
+
+  /* Try to locate the property within the types */
+  for (guint i = 0; i < types->len; i++)
+    {
+      GType prereq_type = g_array_index (types, GType, i);
+      GObjectClass *klass = NULL;
+      GTypeInterface *iface = NULL;
+      GParamSpec *pspec = NULL;
+      GType ret = G_TYPE_INVALID;
+
+      if (G_TYPE_IS_FUNDAMENTAL (prereq_type))
+        continue;
+
+      if (!G_TYPE_IS_OBJECT (prereq_type) && !G_TYPE_IS_INTERFACE (prereq_type))
+        continue;
+
+      if (G_TYPE_IS_OBJECT (prereq_type))
+        {
+          klass = g_type_class_ref (prereq_type);
+          pspec = g_object_class_find_property (klass, name);
+        }
+      else if (G_TYPE_IS_INTERFACE (prereq_type))
+        {
+          iface = g_type_default_interface_ref (prereq_type);
+          pspec = g_object_interface_find_property (iface, name);
+        }
+      else
+        g_assert_not_reached ();
+
+      if (pspec != NULL)
+        ret = pspec->value_type;
+
+      g_clear_pointer (&klass, g_type_class_unref);
+      g_clear_pointer (&iface, g_type_default_interface_unref);
+
+      if (ret != G_TYPE_INVALID)
+        return ret;
+    }
+
+  return G_TYPE_INVALID;
+}
+
+static GArray *
+collect_parameters (GType        type,
+                    const gchar *first_property,
+                    va_list      args)
+{
+  const gchar *property = first_property;
+  g_autoptr(GArray) params = NULL;
+
+  params = g_array_new (FALSE, FALSE, sizeof (GParameter));
+  g_array_set_clear_func (params, clear_param);
+
+  while (property != NULL)
+    {
+      GType property_type = find_property_type (type, property);
+      GParameter param = { property };
+      g_autofree gchar *errmsg = NULL;
+
+      if (property_type == G_TYPE_INVALID)
+        {
+          g_warning ("Unknown property \"%s\" from interface %s", property, g_type_name (type));
+          break;
+        }
+
+      G_VALUE_COLLECT_INIT (&param.value, property_type, args, 0, &errmsg);
+
+      if (errmsg)
+        {
+          g_warning ("Error collecting property: %s", errmsg);
+          break;
+        }
+
+      g_array_append_val (params, param);
+
+      property = va_arg (args, const gchar *);
+    }
+
+  if (property != NULL)
+    return NULL;
+
+  return g_steal_pointer (&params);
+}
+
+/**
+ * ide_extension_set_new:
+ *
+ * This function acts like peas_extension_set_new() except that it allows for
+ * us to pass properties that are in the parent class.
+ *
+ * It does this by duplicating some of the GParameter stuff that libpeas does
+ * but looking at base-classes in addition to interface properties.
+ *
+ * Returns: (transfer full): A #PeasExtensionSet.
+ */
+PeasExtensionSet *
+ide_extension_set_new (PeasEngine     *engine,
+                       GType           type,
+                       const gchar    *first_property,
+                       ...)
+{
+  g_autoptr(GArray) params = NULL;
+  va_list args;
+
+  g_return_val_if_fail (!engine || PEAS_IS_ENGINE (engine), NULL);
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (type), NULL);
+
+  if (engine == NULL)
+    engine = peas_engine_get_default ();
+
+  va_start (args, first_property);
+  params = collect_parameters (type, first_property, args);
+  va_end (args);
+
+  if (params == NULL)
+    return NULL;
+
+  return peas_extension_set_newv (engine, type, params->len, (GParameter *)params->data);
+}
+
+PeasExtension *
+ide_extension_new (PeasEngine     *engine,
+                   PeasPluginInfo *plugin_info,
+                   GType           type,
+                   const gchar    *first_property,
+                   ...)
+{
+  g_autoptr(GArray) params = NULL;
+  va_list args;
+
+  g_return_val_if_fail (!engine || PEAS_IS_ENGINE (engine), NULL);
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (type), NULL);
+
+  if (engine == NULL)
+    engine = peas_engine_get_default ();
+
+  va_start (args, first_property);
+  params = collect_parameters (type, first_property, args);
+  va_end (args);
+
+  if (params == NULL)
+    return NULL;
+
+  return peas_engine_create_extensionv (engine,
+                                        plugin_info,
+                                        type,
+                                        params->len,
+                                        (GParameter *)params->data);
+}
diff --git a/libide/plugins/ide-extension-util.h b/libide/plugins/ide-extension-util.h
index b7ec516..637c003 100644
--- a/libide/plugins/ide-extension-util.h
+++ b/libide/plugins/ide-extension-util.h
@@ -23,12 +23,21 @@
 
 G_BEGIN_DECLS
 
-gboolean ide_extension_util_can_use_plugin (PeasEngine     *engine,
-                                            PeasPluginInfo *plugin_info,
-                                            GType           interface_type,
-                                            const gchar    *key,
-                                            const gchar    *value,
-                                            gint           *priority);
+gboolean         ide_extension_util_can_use_plugin (PeasEngine     *engine,
+                                                    PeasPluginInfo *plugin_info,
+                                                    GType           interface_type,
+                                                    const gchar    *key,
+                                                    const gchar    *value,
+                                                    gint           *priority);
+PeasExtensionSet *ide_extension_set_new            (PeasEngine     *engine,
+                                                    GType           type,
+                                                    const gchar    *first_property,
+                                                    ...);
+PeasExtension    *ide_extension_new                (PeasEngine     *engine,
+                                                    PeasPluginInfo *plugin_info,
+                                                    GType           interface_type,
+                                                    const gchar    *first_property,
+                                                    ...);
 
 G_END_DECLS
 


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