[gnome-builder: 53/139] libide-plugins: add libide-plugins static library



commit 4817db6543ff3747dab418050b16468583e12f5f
Author: Christian Hergert <chergert redhat com>
Date:   Wed Jan 9 16:46:23 2019 -0800

    libide-plugins: add libide-plugins static library
    
    This moves the extension components into a static library and can bridge
    the child extensions into the IdeObject tree.

 src/libide/plugins/ide-extension-adapter.c         | 105 ++++++-----
 src/libide/plugins/ide-extension-adapter.h         |  10 +-
 src/libide/plugins/ide-extension-set-adapter.c     | 204 ++++++++++++++-------
 src/libide/plugins/ide-extension-set-adapter.h     |  10 +-
 ...tension-util.h => ide-extension-util-private.h} |   0
 src/libide/plugins/ide-extension-util.c            |  26 ++-
 src/libide/plugins/libide-plugins.h                |  34 ++++
 src/libide/plugins/meson.build                     |  57 +++++-
 8 files changed, 314 insertions(+), 132 deletions(-)
---
diff --git a/src/libide/plugins/ide-extension-adapter.c b/src/libide/plugins/ide-extension-adapter.c
index 2480a0ce8..d6043385f 100644
--- a/src/libide/plugins/ide-extension-adapter.c
+++ b/src/libide/plugins/ide-extension-adapter.c
@@ -25,11 +25,8 @@
 #include <dazzle.h>
 #include <glib/gi18n.h>
 
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "plugins/ide-extension-adapter.h"
-#include "plugins/ide-extension-util.h"
+#include "ide-extension-adapter.h"
+#include "ide-extension-util-private.h"
 
 struct _IdeExtensionAdapter
 {
@@ -62,6 +59,20 @@ enum {
 
 static GParamSpec *properties [LAST_PROP];
 
+static gchar *
+ide_extension_adapter_repr (IdeObject *object)
+{
+  IdeExtensionAdapter *self = (IdeExtensionAdapter *)object;
+
+  g_assert (IDE_IS_EXTENSION_ADAPTER (self));
+
+  return g_strdup_printf ("%s interface=“%s” key=“%s” value=“%s”",
+                          G_OBJECT_TYPE_NAME (self),
+                          g_type_name (self->interface_type),
+                          self->key ?: "",
+                          self->value ?: "");
+}
+
 static GSettings *
 ide_extension_adapter_get_settings (IdeExtensionAdapter *self,
                                     PeasPluginInfo      *plugin_info)
@@ -107,9 +118,18 @@ ide_extension_adapter_set_extension (IdeExtensionAdapter *self,
 
   self->plugin_info = plugin_info;
 
-  if (g_set_object (&self->extension, extension))
+  if (extension != self->extension)
     {
+      if (IDE_IS_OBJECT (self->extension))
+        ide_object_destroy (IDE_OBJECT (self->extension));
+
+      g_set_object (&self->extension, extension);
+
+      if (IDE_IS_OBJECT (extension))
+        ide_object_append (IDE_OBJECT (self), IDE_OBJECT (extension));
+
       ide_extension_adapter_monitor (self, plugin_info);
+
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_EXTENSION]);
     }
 }
@@ -168,30 +188,10 @@ ide_extension_adapter_reload (IdeExtensionAdapter *self)
     return;
 
   if (best_match != NULL)
-    {
-      IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
-
-      if (g_type_is_a (self->interface_type, IDE_TYPE_OBJECT))
-        extension = ide_extension_new (self->engine,
-                                       best_match,
-                                       self->interface_type,
-                                       "context", context,
-                                       NULL);
-      else
-        {
-          extension = ide_extension_new (self->engine,
-                                         best_match,
-                                         self->interface_type,
-                                         NULL);
-          /*
-           * If the plugin object turned out to have IdeObject
-           * as a base, try to set it now (even though we couldn't
-           * do it at construction time).
-           */
-          if (IDE_IS_OBJECT (extension))
-            ide_object_set_context (IDE_OBJECT (extension), context);
-        }
-    }
+    extension = ide_extension_new (self->engine,
+                                   best_match,
+                                   self->interface_type,
+                                   NULL);
 
   ide_extension_adapter_set_extension (self, best_match, extension);
 
@@ -220,7 +220,7 @@ ide_extension_adapter_queue_reload (IdeExtensionAdapter *self)
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_EXTENSION_ADAPTER (self));
 
-  dzl_clear_source (&self->queue_handler);
+  g_clear_handle_id (&self->queue_handler, g_source_remove);
   self->queue_handler = g_timeout_add (0, ide_extension_adapter_do_reload, self);
 }
 
@@ -311,7 +311,7 @@ ide_extension_adapter__changed_disabled (IdeExtensionAdapter *self,
   g_assert (IDE_IS_EXTENSION_ADAPTER (self));
   g_assert (G_IS_SETTINGS (settings));
 
-  if (dzl_str_equal0 (changed_key, "disabled"))
+  if (ide_str_equal0 (changed_key, "disabled"))
     ide_extension_adapter_queue_reload (self);
 }
 
@@ -322,7 +322,7 @@ ide_extension_adapter_dispose (GObject *object)
 
   self->interface_type = G_TYPE_INVALID;
 
-  dzl_clear_source (&self->queue_handler);
+  g_clear_handle_id (&self->queue_handler, g_source_remove);
 
   ide_extension_adapter_monitor (self, NULL);
 
@@ -418,12 +418,15 @@ static void
 ide_extension_adapter_class_init (IdeExtensionAdapterClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
 
   object_class->dispose = ide_extension_adapter_dispose;
   object_class->finalize = ide_extension_adapter_finalize;
   object_class->get_property = ide_extension_adapter_get_property;
   object_class->set_property = ide_extension_adapter_set_property;
 
+  i_object_class->repr = ide_extension_adapter_repr;
+
   properties [PROP_ENGINE] =
     g_param_spec_object ("engine",
                          "Engine",
@@ -491,7 +494,7 @@ ide_extension_adapter_set_key (IdeExtensionAdapter *self,
   g_return_if_fail (IDE_IS_MAIN_THREAD ());
   g_return_if_fail (IDE_IS_EXTENSION_ADAPTER (self));
 
-  if (!dzl_str_equal0 (self->key, key))
+  if (!ide_str_equal0 (self->key, key))
     {
       g_free (self->key);
       self->key = g_strdup (key);
@@ -516,7 +519,7 @@ ide_extension_adapter_set_value (IdeExtensionAdapter *self,
   g_return_if_fail (IDE_IS_MAIN_THREAD ());
   g_return_if_fail (IDE_IS_EXTENSION_ADAPTER (self));
 
-  if (!dzl_str_equal0 (self->value, value))
+  if (!ide_str_equal0 (self->value, value))
     {
       g_free (self->value);
       self->value = g_strdup (value);
@@ -573,46 +576,54 @@ ide_extension_adapter_get_extension (IdeExtensionAdapter *self)
 
 /**
  * ide_extension_adapter_new:
- * @context: An #IdeContext.
- * @engine: (allow-none): a #PeasEngine or %NULL.
+ * @parent: (nullable): An #IdeObject or %NULL
+ * @engine: (allow-none): a #PeasEngine or %NULL
  * @interface_type: The #GType of the interface to be implemented.
  * @key: The key for matching extensions from plugin info external data.
  * @value: (allow-none): The value to use when matching keys.
  *
  * Creates a new #IdeExtensionAdapter.
  *
- * The #IdeExtensionAdapter object can be used to wrap an extension that might need to change
- * at runtime based on various changing parameters. For example, it can watch the loading and
- * unloading of plugins and reload the #IdeExtensionAdapter:extension property.
+ * The #IdeExtensionAdapter object can be used to wrap an extension that might
+ * need to change at runtime based on various changing parameters. For example,
+ * it can watch the loading and unloading of plugins and reload the
+ * #IdeExtensionAdapter:extension property.
  *
  * Additionally, it can match a specific plugin based on the @value provided.
  *
- * This uses #IdeExtensionPoint to create the extension implementation, which means that
- * extension points that are disabled (such as from the plugins GSettings) will be ignored.
- * As such, if one plugin that is higher priority than another, but is disabled, will be
- * ignored and the secondary plugin will be used.
+ * This uses #IdeExtensionPoint to create the extension implementation, which
+ * means that extension points that are disabled (such as from the plugins
+ * GSettings) will be ignored.  As such, if one plugin that is higher priority
+ * than another, but is disabled, will be ignored and the secondary plugin will
+ * be used.
  *
  * Returns: (transfer full): A newly created #IdeExtensionAdapter.
  *
  * Since: 3.32
  */
 IdeExtensionAdapter *
-ide_extension_adapter_new (IdeContext  *context,
+ide_extension_adapter_new (IdeObject   *parent,
                            PeasEngine  *engine,
                            GType        interface_type,
                            const gchar *key,
                            const gchar *value)
 {
+  IdeExtensionAdapter *self;
+
   g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
   g_return_val_if_fail (!engine || PEAS_IS_ENGINE (engine), NULL);
   g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
   g_return_val_if_fail (key != NULL, NULL);
 
-  return g_object_new (IDE_TYPE_EXTENSION_ADAPTER,
-                       "context", context,
+  self = g_object_new (IDE_TYPE_EXTENSION_ADAPTER,
                        "engine", engine,
                        "interface-type", interface_type,
                        "key", key,
                        "value", value,
                        NULL);
+
+  if (parent != NULL)
+    ide_object_append (parent, IDE_OBJECT (self));
+
+  return g_steal_pointer (&self);
 }
diff --git a/src/libide/plugins/ide-extension-adapter.h b/src/libide/plugins/ide-extension-adapter.h
index 0a0aaea94..e8499ec69 100644
--- a/src/libide/plugins/ide-extension-adapter.h
+++ b/src/libide/plugins/ide-extension-adapter.h
@@ -20,10 +20,12 @@
 
 #pragma once
 
-#include <libpeas/peas.h>
+#if !defined (IDE_PLUGINS_INSIDE) && !defined (IDE_PLUGINS_COMPILATION)
+# error "Only <libide-plugins.h> can be included directly."
+#endif
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#include <libpeas/peas.h>
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
@@ -33,7 +35,7 @@ IDE_AVAILABLE_IN_3_32
 G_DECLARE_FINAL_TYPE (IdeExtensionAdapter, ide_extension_adapter, IDE, EXTENSION_ADAPTER, IdeObject)
 
 IDE_AVAILABLE_IN_3_32
-IdeExtensionAdapter *ide_extension_adapter_new                (IdeContext          *context,
+IdeExtensionAdapter *ide_extension_adapter_new                (IdeObject           *parent,
                                                                PeasEngine          *engine,
                                                                GType                interface_type,
                                                                const gchar         *key,
diff --git a/src/libide/plugins/ide-extension-set-adapter.c b/src/libide/plugins/ide-extension-set-adapter.c
index 966c26f4a..d4586b1f6 100644
--- a/src/libide/plugins/ide-extension-set-adapter.c
+++ b/src/libide/plugins/ide-extension-set-adapter.c
@@ -26,12 +26,8 @@
 #include <glib/gi18n.h>
 #include <stdlib.h>
 
-#include "ide-context.h"
-#include "ide-debug.h"
-
-#include "application/ide-application.h"
-#include "plugins/ide-extension-set-adapter.h"
-#include "plugins/ide-extension-util.h"
+#include "ide-extension-set-adapter.h"
+#include "ide-extension-util-private.h"
 
 struct _IdeExtensionSetAdapter
 {
@@ -71,6 +67,20 @@ static guint signals [LAST_SIGNAL];
 
 static void ide_extension_set_adapter_queue_reload (IdeExtensionSetAdapter *);
 
+static gchar *
+ide_extension_set_adapter_repr (IdeObject *object)
+{
+  IdeExtensionSetAdapter *self = (IdeExtensionSetAdapter *)object;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
+
+  return g_strdup_printf ("%s interface=\"%s\" key=\"%s\" value=\"%s\"",
+                          G_OBJECT_TYPE_NAME (self),
+                          g_type_name (self->interface_type),
+                          self->key ?: "",
+                          self->value ?: "");
+}
+
 static void
 add_extension (IdeExtensionSetAdapter *self,
                PeasPluginInfo         *plugin_info,
@@ -83,6 +93,19 @@ add_extension (IdeExtensionSetAdapter *self,
   g_assert (g_type_is_a (G_OBJECT_TYPE (exten), self->interface_type));
 
   g_hash_table_insert (self->extensions, plugin_info, exten);
+
+  /* Ensure that we take the reference in case it's a floating ref */
+  if (G_IS_INITIALLY_UNOWNED (exten) && g_object_is_floating (exten))
+    g_object_ref_sink (exten);
+
+  /*
+   * If the plugin object turned out to have IdeObject as a
+   * base, make it a child of ourselves, because we're an
+   * IdeObject too and that gives it access to the context.
+   */
+  if (IDE_IS_OBJECT (exten))
+    ide_object_append (IDE_OBJECT (self), IDE_OBJECT (exten));
+
   g_signal_emit (self, signals [EXTENSION_ADDED], 0, plugin_info, exten);
 }
 
@@ -104,6 +127,9 @@ remove_extension (IdeExtensionSetAdapter *self,
 
   g_hash_table_remove (self->extensions, plugin_info);
   g_signal_emit (self, signals [EXTENSION_REMOVED], 0, plugin_info, hold);
+
+  if (IDE_IS_OBJECT (hold))
+    ide_object_destroy (IDE_OBJECT (hold));
 }
 
 static void
@@ -130,7 +156,7 @@ watch_extension (IdeExtensionSetAdapter *self,
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
   g_assert (plugin_info != NULL);
-  g_assert (G_TYPE_IS_INTERFACE (interface_type));
+  g_assert (G_TYPE_IS_INTERFACE (interface_type) || G_TYPE_IS_OBJECT (interface_type));
 
   path = g_strdup_printf ("/org/gnome/builder/extension-types/%s/%s/",
                           peas_plugin_info_get_module_name (plugin_info),
@@ -152,7 +178,6 @@ watch_extension (IdeExtensionSetAdapter *self,
 static void
 ide_extension_set_adapter_reload (IdeExtensionSetAdapter *self)
 {
-  IdeContext *context;
   const GList *plugins;
 
   g_assert (IDE_IS_MAIN_THREAD ());
@@ -170,11 +195,8 @@ ide_extension_set_adapter_reload (IdeExtensionSetAdapter *self)
       g_ptr_array_remove_index (self->settings, self->settings->len - 1);
     }
 
-  context = ide_object_get_context (IDE_OBJECT (self));
   plugins = peas_engine_get_plugin_list (self->engine);
 
-  g_assert (IDE_IS_CONTEXT (context));
-
   for (; plugins; plugins = plugins->next)
     {
       PeasPluginInfo *plugin_info = plugins->data;
@@ -183,8 +205,10 @@ ide_extension_set_adapter_reload (IdeExtensionSetAdapter *self)
       if (!peas_plugin_info_is_loaded (plugin_info))
         continue;
 
-      if (peas_engine_provides_extension (self->engine, plugin_info, self->interface_type))
-        watch_extension (self, plugin_info, self->interface_type);
+      if (!peas_engine_provides_extension (self->engine, plugin_info, self->interface_type))
+        continue;
+
+      watch_extension (self, plugin_info, self->interface_type);
 
       if (ide_extension_util_can_use_plugin (self->engine,
                                              plugin_info,
@@ -197,26 +221,10 @@ ide_extension_set_adapter_reload (IdeExtensionSetAdapter *self)
             {
               PeasExtension *exten;
 
-              if (g_type_is_a (self->interface_type, IDE_TYPE_OBJECT))
-                exten = ide_extension_new (self->engine,
-                                           plugin_info,
-                                           self->interface_type,
-                                           "context", context,
-                                           NULL);
-              else
-                {
-                  exten = ide_extension_new (self->engine,
-                                             plugin_info,
-                                             self->interface_type,
-                                             NULL);
-                  /*
-                   * If the plugin object turned out to have IdeObject
-                   * as a base, try to set it now (even though we couldn't
-                   * do it at construction time).
-                   */
-                  if (IDE_IS_OBJECT (exten))
-                    ide_object_set_context (IDE_OBJECT (exten), context);
-                }
+              exten = ide_extension_new (self->engine,
+                                         plugin_info,
+                                         self->interface_type,
+                                         NULL);
 
               add_extension (self, plugin_info, exten);
             }
@@ -255,7 +263,7 @@ ide_extension_set_adapter_queue_reload (IdeExtensionSetAdapter *self)
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
 
-  dzl_clear_source (&self->reload_handler);
+  g_clear_handle_id (&self->reload_handler, g_source_remove);
 
   self->reload_handler = g_idle_add_full (G_PRIORITY_HIGH,
                                           ide_extension_set_adapter_do_reload,
@@ -263,16 +271,57 @@ ide_extension_set_adapter_queue_reload (IdeExtensionSetAdapter *self)
                                           NULL);
 }
 
+static void
+ide_extension_set_adapter_load_plugin (IdeExtensionSetAdapter *self,
+                                       PeasPluginInfo         *plugin_info,
+                                       PeasEngine             *engine)
+{
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
+  g_assert (plugin_info != NULL);
+  g_assert (PEAS_IS_ENGINE (engine));
+
+  ide_extension_set_adapter_queue_reload (self);
+}
+
+static void
+ide_extension_set_adapter_unload_plugin (IdeExtensionSetAdapter *self,
+                                         PeasPluginInfo         *plugin_info,
+                                         PeasEngine             *engine)
+{
+  PeasExtension *exten;
+
+  g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
+  g_assert (plugin_info != NULL);
+  g_assert (PEAS_IS_ENGINE (engine));
+
+  if ((exten = g_hash_table_lookup (self->extensions, plugin_info)))
+    {
+      remove_extension (self, plugin_info, exten);
+      g_hash_table_remove (self->extensions, plugin_info);
+    }
+}
+
 static void
 ide_extension_set_adapter_set_engine (IdeExtensionSetAdapter *self,
                                       PeasEngine             *engine)
 {
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
-  g_assert (PEAS_IS_ENGINE (engine));
+  g_assert (!engine || PEAS_IS_ENGINE (engine));
+
+  if (engine == NULL)
+    engine = peas_engine_get_default ();
 
   if (g_set_object (&self->engine, engine))
     {
+      g_signal_connect_object (self->engine, "load-plugin",
+                               G_CALLBACK (ide_extension_set_adapter_load_plugin),
+                               self,
+                               G_CONNECT_AFTER | G_CONNECT_SWAPPED);
+      g_signal_connect_object (self->engine, "unload-plugin",
+                               G_CALLBACK (ide_extension_set_adapter_unload_plugin),
+                               self,
+                               G_CONNECT_SWAPPED);
       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENGINE]);
       ide_extension_set_adapter_queue_reload (self);
     }
@@ -284,7 +333,7 @@ ide_extension_set_adapter_set_interface_type (IdeExtensionSetAdapter *self,
 {
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
-  g_assert (G_TYPE_IS_INTERFACE (interface_type));
+  g_assert (G_TYPE_IS_INTERFACE (interface_type) || G_TYPE_IS_OBJECT (interface_type));
 
   if (interface_type != self->interface_type)
     {
@@ -295,7 +344,7 @@ ide_extension_set_adapter_set_interface_type (IdeExtensionSetAdapter *self,
 }
 
 static void
-ide_extension_set_adapter_dispose (GObject *object)
+ide_extension_set_adapter_destroy (IdeObject *object)
 {
   IdeExtensionSetAdapter *self = (IdeExtensionSetAdapter *)object;
   g_autoptr(GHashTable) extensions = NULL;
@@ -307,7 +356,7 @@ ide_extension_set_adapter_dispose (GObject *object)
   g_assert (IDE_IS_EXTENSION_SET_ADAPTER (self));
 
   self->interface_type = G_TYPE_INVALID;
-  dzl_clear_source (&self->reload_handler);
+  g_clear_handle_id (&self->reload_handler, g_source_remove);
 
   /*
    * Steal the extensions so we can be re-entrant safe and not break
@@ -327,7 +376,7 @@ ide_extension_set_adapter_dispose (GObject *object)
       g_hash_table_iter_remove (&iter);
     }
 
-  G_OBJECT_CLASS (ide_extension_set_adapter_parent_class)->dispose (object);
+  IDE_OBJECT_CLASS (ide_extension_set_adapter_parent_class)->destroy (object);
 }
 
 static void
@@ -421,12 +470,15 @@ static void
 ide_extension_set_adapter_class_init (IdeExtensionSetAdapterClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
 
-  object_class->dispose = ide_extension_set_adapter_dispose;
   object_class->finalize = ide_extension_set_adapter_finalize;
   object_class->get_property = ide_extension_set_adapter_get_property;
   object_class->set_property = ide_extension_set_adapter_set_property;
 
+  i_object_class->destroy = ide_extension_set_adapter_destroy;
+  i_object_class->repr = ide_extension_set_adapter_repr;
+
   properties [PROP_ENGINE] =
     g_param_spec_object ("engine",
                          "Engine",
@@ -438,7 +490,7 @@ ide_extension_set_adapter_class_init (IdeExtensionSetAdapterClass *klass)
     g_param_spec_gtype ("interface-type",
                         "Interface Type",
                         "Interface Type",
-                        G_TYPE_INTERFACE,
+                        G_TYPE_OBJECT,
                         (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
 
   properties [PROP_KEY] =
@@ -535,7 +587,7 @@ ide_extension_set_adapter_set_key (IdeExtensionSetAdapter *self,
   g_return_if_fail (IDE_IS_MAIN_THREAD ());
   g_return_if_fail (IDE_IS_EXTENSION_SET_ADAPTER (self));
 
-  if (!dzl_str_equal0 (self->key, key))
+  if (!ide_str_equal0 (self->key, key))
     {
       g_free (self->key);
       self->key = g_strdup (key);
@@ -564,7 +616,7 @@ ide_extension_set_adapter_set_value (IdeExtensionSetAdapter *self,
                  g_type_name (self->interface_type),
                  value ?: "");
 
-  if (!dzl_str_equal0 (self->value, value))
+  if (!ide_str_equal0 (self->value, value))
     {
       g_free (self->value);
       self->value = g_strdup (value);
@@ -588,22 +640,25 @@ ide_extension_set_adapter_foreach (IdeExtensionSetAdapter            *self,
                                    IdeExtensionSetAdapterForeachFunc  foreach_func,
                                    gpointer                           user_data)
 {
-  GHashTableIter iter;
-  gpointer key;
-  gpointer value;
+  const GList *list;
 
-  g_return_if_fail (IDE_IS_MAIN_THREAD ());
   g_return_if_fail (IDE_IS_EXTENSION_SET_ADAPTER (self));
   g_return_if_fail (foreach_func != NULL);
 
-  g_hash_table_iter_init (&iter, self->extensions);
+  /*
+   * Use the ordered list of plugins as it is sorted including any
+   * dependencies of plugins.
+   */
 
-  while (g_hash_table_iter_next (&iter, &key, &value))
+  list = peas_engine_get_plugin_list (self->engine);
+
+  for (const GList *iter = list; iter; iter = iter->next)
     {
-      PeasPluginInfo *plugin_info = key;
-      PeasExtension *exten = value;
+      PeasPluginInfo *plugin_info = iter->data;
+      PeasExtension *exten = g_hash_table_lookup (self->extensions, plugin_info);
 
-      foreach_func (self, plugin_info, exten, user_data);
+      if (exten != NULL)
+        foreach_func (self, plugin_info, exten, user_data);
     }
 }
 
@@ -651,6 +706,12 @@ ide_extension_set_adapter_foreach_by_priority (IdeExtensionSetAdapter
   g_return_if_fail (IDE_IS_EXTENSION_SET_ADAPTER (self));
   g_return_if_fail (foreach_func != NULL);
 
+  if (self->key == NULL)
+    {
+      ide_extension_set_adapter_foreach (self, foreach_func, user_data);
+      return;
+    }
+
   prio_key = g_strdup_printf ("%s-Priority", self->key);
   sorted = g_array_new (FALSE, FALSE, sizeof (SortedInfo));
 
@@ -689,25 +750,40 @@ ide_extension_set_adapter_get_n_extensions (IdeExtensionSetAdapter *self)
 }
 
 IdeExtensionSetAdapter *
-ide_extension_set_adapter_new (IdeContext  *context,
+ide_extension_set_adapter_new (IdeObject   *parent,
                                PeasEngine  *engine,
                                GType        interface_type,
                                const gchar *key,
                                const gchar *value)
 {
+  IdeExtensionSetAdapter *ret;
+
   g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
-  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (!parent || IDE_IS_OBJECT (parent), NULL);
   g_return_val_if_fail (!engine || PEAS_IS_ENGINE (engine), NULL);
-  g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type), NULL);
-  g_return_val_if_fail (key != NULL, NULL);
-
-  return g_object_new (IDE_TYPE_EXTENSION_SET_ADAPTER,
-                       "context", context,
-                       "engine", engine,
-                       "interface-type", interface_type,
-                       "key", key,
-                       "value", value,
-                       NULL);
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (interface_type) ||
+                        G_TYPE_IS_OBJECT (interface_type), NULL);
+
+  ret = g_object_new (IDE_TYPE_EXTENSION_SET_ADAPTER,
+                      "engine", engine,
+                      "interface-type", interface_type,
+                      "key", key,
+                      "value", value,
+                      NULL);
+
+  if (parent != NULL)
+    ide_object_append (parent, IDE_OBJECT (ret));
+
+  /* If we have a reload queued, just process it immediately so that
+   * there is some determinism in plugin loading.
+   */
+  if (ret->reload_handler != 0)
+    {
+      g_clear_handle_id (&ret->reload_handler, g_source_remove);
+      ide_extension_set_adapter_do_reload (ret);
+    }
+
+  return ret;
 }
 
 /**
diff --git a/src/libide/plugins/ide-extension-set-adapter.h b/src/libide/plugins/ide-extension-set-adapter.h
index e61228450..24708e56f 100644
--- a/src/libide/plugins/ide-extension-set-adapter.h
+++ b/src/libide/plugins/ide-extension-set-adapter.h
@@ -20,10 +20,12 @@
 
 #pragma once
 
-#include <libpeas/peas.h>
+#if !defined (IDE_PLUGINS_INSIDE) && !defined (IDE_PLUGINS_COMPILATION)
+# error "Only <libide-plugins.h> can be included directly."
+#endif
 
-#include "ide-object.h"
-#include "ide-version-macros.h"
+#include <libpeas/peas.h>
+#include <libide-core.h>
 
 G_BEGIN_DECLS
 
@@ -38,7 +40,7 @@ typedef void (*IdeExtensionSetAdapterForeachFunc) (IdeExtensionSetAdapter *set,
                                                    gpointer                user_data);
 
 IDE_AVAILABLE_IN_3_32
-IdeExtensionSetAdapter *ide_extension_set_adapter_new                (IdeContext                        
*context,
+IdeExtensionSetAdapter *ide_extension_set_adapter_new                (IdeObject                         
*parent,
                                                                       PeasEngine                        
*engine,
                                                                       GType                              
interface_type,
                                                                       const gchar                       *key,
diff --git a/src/libide/plugins/ide-extension-util.h b/src/libide/plugins/ide-extension-util-private.h
similarity index 100%
rename from src/libide/plugins/ide-extension-util.h
rename to src/libide/plugins/ide-extension-util-private.h
diff --git a/src/libide/plugins/ide-extension-util.c b/src/libide/plugins/ide-extension-util.c
index ffc12848d..bcd32b1cc 100644
--- a/src/libide/plugins/ide-extension-util.c
+++ b/src/libide/plugins/ide-extension-util.c
@@ -22,10 +22,11 @@
 
 #include "config.h"
 
+#include <libide-core.h>
 #include <gobject/gvaluecollector.h>
 #include <stdlib.h>
 
-#include "plugins/ide-extension-util.h"
+#include "ide-extension-util-private.h"
 
 gboolean
 ide_extension_util_can_use_plugin (PeasEngine     *engine,
@@ -39,7 +40,8 @@ ide_extension_util_can_use_plugin (PeasEngine     *engine,
   g_autoptr(GSettings) settings = NULL;
 
   g_return_val_if_fail (plugin_info != NULL, FALSE);
-  g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_INTERFACE), FALSE);
+  g_return_val_if_fail (g_type_is_a (interface_type, G_TYPE_INTERFACE) ||
+                        g_type_is_a (interface_type, G_TYPE_OBJECT), FALSE);
   g_return_val_if_fail (priority != NULL, FALSE);
 
   *priority = 0;
@@ -49,7 +51,18 @@ ide_extension_util_can_use_plugin (PeasEngine     *engine,
    * information to do so.
    */
   if ((key != NULL) && (value == NULL))
-    return FALSE;
+    {
+      const gchar *found;
+
+      /* If the plugin has the key and its empty, or doesn't have the key,
+       * then we can assume it wants the equivalent of "*".
+       */
+      found = peas_plugin_info_get_external_data (plugin_info, key);
+      if (ide_str_empty0 (found))
+        return TRUE;
+
+      return FALSE;
+    }
 
   /*
    * If the plugin isn't loaded, then we shouldn't use it.
@@ -70,12 +83,15 @@ ide_extension_util_can_use_plugin (PeasEngine     *engine,
   if (key != NULL)
     {
       g_autofree gchar *priority_name = NULL;
+      g_autofree gchar *delimit = NULL;
       g_auto(GStrv) values_array = NULL;
       const gchar *values;
       const gchar *priority_value;
 
       values = peas_plugin_info_get_external_data (plugin_info, key);
-      values_array = g_strsplit (values ? values : "", ",", 0);
+      /* Canonicalize input (for both , and ;) */
+      delimit = g_strdelimit (g_strdup (values ? values : ""), ";,", ';');
+      values_array = g_strsplit (delimit, ";", 0);
 
       /* An empty value implies "*" to match anything */
       if (!values || g_strv_contains ((const gchar * const *)values_array, "*"))
@@ -256,7 +272,7 @@ ide_extension_new (PeasEngine     *engine,
   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);
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (type) || G_TYPE_IS_OBJECT (type), NULL);
 
   if (engine == NULL)
     engine = peas_engine_get_default ();
diff --git a/src/libide/plugins/libide-plugins.h b/src/libide/plugins/libide-plugins.h
new file mode 100644
index 000000000..1260890cd
--- /dev/null
+++ b/src/libide/plugins/libide-plugins.h
@@ -0,0 +1,34 @@
+/* libide-plugins.h
+ *
+ * Copyright 2018-2019 Christian Hergert <chergert redhat com>
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define IDE_PLUGINS_INSIDE
+
+#include "ide-extension-adapter.h"
+#include "ide-extension-set-adapter.h"
+
+#undef IDE_PLUGINS_INSIDE
+
+G_END_DECLS
diff --git a/src/libide/plugins/meson.build b/src/libide/plugins/meson.build
index 07466addd..a33c528c9 100644
--- a/src/libide/plugins/meson.build
+++ b/src/libide/plugins/meson.build
@@ -1,20 +1,61 @@
-plugins_headers = [
+libide_plugins_header_subdir = join_paths(libide_header_subdir, 'plugins')
+libide_include_directories += include_directories('.')
+
+#
+# Public API Headers
+#
+
+libide_plugins_public_headers = [
   'ide-extension-adapter.h',
   'ide-extension-set-adapter.h',
+  'libide-plugins.h',
+]
+
+libide_plugins_private_headers = [
+  'ide-extension-util-private.h',
 ]
 
-plugins_sources = [
+install_headers(libide_plugins_public_headers, subdir: libide_plugins_header_subdir)
+
+#
+# Sources
+#
+
+libide_plugins_public_sources = [
   'ide-extension-adapter.c',
   'ide-extension-set-adapter.c',
 ]
 
-plugins_private_sources = [
+libide_plugins_private_sources = [
   'ide-extension-util.c',
-  'ide-extension-util.h',
 ]
 
-libide_public_headers += files(plugins_headers)
-libide_public_sources += files(plugins_sources)
-libide_private_sources += files(plugins_private_sources)
+#
+# Library Definitions
+#
+
+libide_plugins_deps = [
+  libgio_dep,
+  libpeas_dep,
+  libdazzle_dep,
+
+  libide_core_dep,
+]
+
+libide_plugins = static_library('ide-plugins-' + libide_api_version,
+  libide_plugins_public_sources, libide_plugins_private_sources,
+   dependencies: libide_plugins_deps,
+         c_args: libide_args + release_args + ['-DIDE_PLUGINS_COMPILATION'],
+)
+
+libide_plugins_dep = declare_dependency(
+              sources: libide_plugins_private_headers,
+         dependencies: libide_plugins_deps,
+           link_whole: libide_plugins,
+  include_directories: include_directories('.'),
+)
 
-install_headers(plugins_headers, subdir: join_paths(libide_header_subdir, 'plugins'))
+gnome_builder_public_sources += files(libide_plugins_public_sources)
+gnome_builder_public_headers += files(libide_plugins_public_headers)
+gnome_builder_include_subdirs += libide_plugins_header_subdir
+gnome_builder_gir_extra_args += ['--c-include=libide-plugins.h', '-DIDE_PLUGINS_COMPILATION']


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