Commit 08310b69 authored by Christian Hergert's avatar Christian Hergert
Browse files

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
parent 7480f87a
......@@ -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);
}
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment