[grilo-plugins] lua-factory: Add GOA support



commit bb4b13e4d886242dbf290f0cbc3c8321499694f2
Author: Bastien Nocera <hadess hadess net>
Date:   Thu Jul 16 12:28:51 2015 +0200

    lua-factory: Add GOA support
    
    Make it possible for sources to be spawned for each account of a
    specific provider (Google, VK, etc.) and specific feature (Music, Read
    Later, Videos).
    
    Based on original patch by RadistMorse <radist morse gmail com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=751981

 configure.ac                      |    6 +
 src/lua-factory/grl-lua-common.h  |   10 +
 src/lua-factory/grl-lua-factory.c |  466 ++++++++++++++++++++++++++++++++++++-
 src/lua-factory/grl-lua-library.c |   46 ++++
 4 files changed, 521 insertions(+), 7 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index db16b5a..b0b3d2b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -821,8 +821,14 @@ AC_SUBST(LUA_FACTORY_PLUGIN_ID)
 AC_DEFINE_UNQUOTED([LUA_FACTORY_PLUGIN_ID], ["$LUA_FACTORY_PLUGIN_ID"], [Lua Factory plugin ID])
 
 DEPS_LUA_FACTORY_CFLAGS="$DEPS_CFLAGS $LUA_CFLAGS $ARCHIVE_CFLAGS $GRLNET_CFLAGS $JSON_CFLAGS"
+if test "x$enable_goa" = "xyes"; then
+       DEPS_LUA_FACTORY_CFLAGS="$DEPS_LUA_FACTORY_CFLAGS $GOA_CFLAGS"
+fi
 AC_SUBST(DEPS_LUA_FACTORY_CFLAGS)
 DEPS_LUA_FACTORY_LIBS="$DEPS_LIBS $LUA_LIBS $ARCHIVE_LIBS $GRLNET_LIBS $JSON_LIBS"
+if test "x$enable_goa" = "xyes"; then
+       DEPS_LUA_FACTORY_LIBS="$DEPS_LUA_FACTORY_LIBS $GOA_LIBS"
+fi
 AC_SUBST(DEPS_LUA_FACTORY_LIBS)
 
 LUA_FACTORY_SOURCE_LOCATION="grilo-plugins/${LUA_FACTORY_PLUGIN_ID}"
diff --git a/src/lua-factory/grl-lua-common.h b/src/lua-factory/grl-lua-common.h
index 6042991..9c6f901 100644
--- a/src/lua-factory/grl-lua-common.h
+++ b/src/lua-factory/grl-lua-common.h
@@ -29,6 +29,13 @@
 #include "grl-lua-library.h"
 #include <glib/gi18n-lib.h>
 
+#ifdef GOA_ENABLED
+#define GOA_API_IS_SUBJECT_TO_CHANGE
+#include <goa/goa.h>
+#endif
+
+#define GOA_LUA_NAME "goa_object"
+
 typedef enum {
   LUA_SEARCH,
   LUA_BROWSE,
@@ -83,4 +90,7 @@ OperationSpec *grl_lua_library_load_operation_data (lua_State *L, guint operatio
 void grl_lua_library_set_current_operation (lua_State *L, guint operation_id);
 OperationSpec * grl_lua_library_get_current_operation (lua_State *L);
 
+void grl_lua_library_save_goa_data (lua_State *L, gpointer goa_object);
+gpointer grl_lua_library_load_goa_data (lua_State *L);
+
 #endif /* _GRL_LUA_LIBRARY_COMMON_H_ */
diff --git a/src/lua-factory/grl-lua-factory.c b/src/lua-factory/grl-lua-factory.c
index 41ab77c..5ddd3b8 100644
--- a/src/lua-factory/grl-lua-factory.c
+++ b/src/lua-factory/grl-lua-factory.c
@@ -55,6 +55,8 @@ GRL_LOG_DOMAIN_STATIC (lua_factory_log_domain);
 #define LUA_SOURCE_SUPPORTED_KEYS   "supported_keys"
 #define LUA_SOURCE_SLOW_KEYS        "slow_keys"
 #define LUA_SOURCE_RESOLVE_KEYS     "resolve_keys"
+#define LUA_GOA_ACCOUNT_PROVIDER    "goa_account_provider"
+#define LUA_GOA_ACCOUNT_FEATURE     "goa_account_feature"
 #define LUA_REQUIRED_TABLE          "required"
 #define LUA_OPTIONAL_TABLE          "optional"
 
@@ -77,10 +79,32 @@ struct _GrlLuaFactorySourcePrivate {
   GrlConfig *configs;
 };
 
+#ifdef GOA_ENABLED
+typedef struct {
+  GrlPlugin *plugin;
+  GrlRegistry *registry;
+  GList *configs;
+  GoaClient *client;
+  gchar *lua_source_path;
+  gchar *account_provider;
+  gchar *account_feature;
+  GHashTable *sources;
+} GrlLuaGoaData;
+
+typedef struct {
+  gchar *lua_source_path;
+  gchar *lua_account_provider;
+  gchar *lua_account_feature;
+} GrlLuaGoaInitData;
+#endif
+
 static GList *get_lua_sources (void);
 
-static GrlLuaFactorySource *grl_lua_factory_source_new (gchar *lua_plugin_path,
-                                                        GList *configs);
+static GrlLuaFactorySource *grl_lua_factory_source_new (gchar       *lua_plugin_path,
+                                                        GList       *configs,
+                                                        const gchar *source_id_suffix,
+                                                        const gchar *account_name,
+                                                        gpointer     goa_object);
 
 static gint lua_plugin_source_info (lua_State *L,
                                     gchar **source_id,
@@ -91,6 +115,8 @@ static gint lua_plugin_source_info (lua_State *L,
                                     guint *auto_split_threshold,
                                     gchar ***source_tags);
 
+static void lua_load_safe_libs (lua_State *L);
+
 static gint lua_plugin_source_operations (lua_State *L,
                                           gboolean fn[LUA_NUM_OPERATIONS]);
 
@@ -138,6 +164,16 @@ static gboolean all_mandatory_options_has_value (const gchar *source_id,
 
 static gboolean lua_plugin_source_init (GrlLuaFactorySource *lua_source);
 
+static GList *handle_goa_sources (GList  *lua_sources,
+                                  GList **goa_sources);
+
+#ifdef GOA_ENABLED
+static void grl_lua_factory_goa_init (GObject *source_object,
+                                      GAsyncResult *res,
+                                      gpointer user_data);
+static void grl_lua_goa_data_free (GrlLuaGoaData *data);
+#endif
+
 /* ================== Lua-Factory Plugin  ================================== */
 
 static gboolean
@@ -146,9 +182,13 @@ grl_lua_factory_plugin_init (GrlRegistry *registry,
                              GList *configs)
 {
   GList *it = NULL;
-  GList *lua_sources = NULL;
+  GList *lua_sources, *goa_sources;
   GError *err = NULL;
   gboolean source_loaded = FALSE;
+  GCancellable *cancellable;
+#ifdef GOA_ENABLED
+  GList *lua_init_sources = NULL;
+#endif
 
   GRL_LOG_DOMAIN_INIT (lua_factory_log_domain, "lua-factory");
 
@@ -158,10 +198,42 @@ grl_lua_factory_plugin_init (GrlRegistry *registry,
   if (!lua_sources)
     return TRUE;
 
+  cancellable = g_cancellable_new ();
+  g_object_set_data (G_OBJECT (plugin), "cancellable", cancellable);
+
+  lua_sources = handle_goa_sources (lua_sources, &goa_sources);
+
+#ifdef GOA_ENABLED
+  for (it = goa_sources; it; it = g_list_next (it)) {
+    GrlLuaGoaInitData *data = it->data;
+    GrlLuaGoaData *goa_data;
+
+    goa_data = g_new0 (GrlLuaGoaData, 1);
+    goa_data->plugin = plugin;
+    goa_data->registry = registry;
+    goa_data->configs = configs;
+    goa_data->account_provider = data->lua_account_provider;
+    goa_data->account_feature = data->lua_account_feature;
+    goa_data->lua_source_path = data->lua_source_path;
+
+    /* All struct members in GrlLuaGoaInitData have been taken */
+    g_free (data);
+
+    goa_client_new (cancellable, grl_lua_factory_goa_init, goa_data);
+
+    lua_init_sources = g_list_prepend (lua_init_sources, goa_data);
+  }
+
+  g_list_free (goa_sources);
+  g_object_set_data (G_OBJECT (plugin), "lua-init-sources", lua_init_sources);
+#else
+  g_assert (goa_sources == NULL);
+#endif
+
   for (it = lua_sources; it; it = g_list_next (it)) {
     GrlLuaFactorySource *source;
 
-    source = grl_lua_factory_source_new (it->data, configs);
+    source = grl_lua_factory_source_new (it->data, configs, NULL, NULL, NULL);
     if (source == NULL) {
       GRL_DEBUG ("Fail to initialize.");
       continue;
@@ -190,7 +262,27 @@ grl_lua_factory_plugin_init (GrlRegistry *registry,
   return source_loaded;
 }
 
-GRL_PLUGIN_REGISTER (grl_lua_factory_plugin_init, NULL, LUA_FACTORY_PLUGIN_ID);
+static void
+grl_lua_factory_plugin_deinit (GrlPlugin *plugin)
+{
+  GCancellable *cancellable;
+  GList *lua_init_sources, *it;
+
+  cancellable = g_object_get_data (G_OBJECT (plugin), "cancellable");
+  if (cancellable) {
+    g_cancellable_cancel (cancellable);
+    g_object_unref (cancellable);
+    g_object_set_data (G_OBJECT (plugin), "cancellable", NULL);
+  }
+
+  lua_init_sources = g_object_get_data (G_OBJECT (plugin), "lua-init-sources");
+  for (it = lua_init_sources; it != NULL; it = it->next)
+    grl_lua_goa_data_free (it->data);
+  g_list_free (lua_init_sources);
+  g_object_set_data (G_OBJECT (plugin), "lua-init-sources", NULL);
+}
+
+GRL_PLUGIN_REGISTER (grl_lua_factory_plugin_init, grl_lua_factory_plugin_deinit, LUA_FACTORY_PLUGIN_ID);
 
 /* ================== Lua-Factory GObject ================================== */
 
@@ -239,8 +331,11 @@ load_gresource (const char *script_path)
 }
 
 static GrlLuaFactorySource *
-grl_lua_factory_source_new (gchar *lua_plugin_path,
-                            GList *configs)
+grl_lua_factory_source_new (gchar       *lua_plugin_path,
+                            GList       *configs,
+                            const gchar *source_id_suffix,
+                            const gchar *account_name,
+                            gpointer     goa_object)
 {
   GrlLuaFactorySource *source = NULL;
   lua_State *L = NULL;
@@ -296,6 +391,26 @@ grl_lua_factory_source_new (gchar *lua_plugin_path,
   if (ret != LUA_OK)
     goto bail;
 
+  /* Override source id, name and description for GOA sources */
+  if (source_id_suffix) {
+    gchar *new_source_id = g_strdup_printf ("%s-%s", source_id, source_id_suffix);
+    g_free (source_id);
+    source_id = new_source_id;
+  }
+
+  if (account_name) {
+    gchar *new_source_name;
+    gchar *new_source_desc;
+
+    new_source_name = g_strdup_printf ("%s (%s)", source_name, account_name);
+    g_free (source_name);
+    source_name = new_source_name;
+
+    new_source_desc = g_strdup_printf ("%s (%s)", source_desc, account_name);
+    g_free (source_desc);
+    source_desc = new_source_desc;
+  }
+
   GRL_DEBUG ("source_info ok! source_id: '%s'", source_id);
 
   source = g_object_new (GRL_LUA_FACTORY_SOURCE_TYPE,
@@ -337,6 +452,9 @@ grl_lua_factory_source_new (gchar *lua_plugin_path,
   source->priv->config_keys = config_keys;
   source->priv->l_st = L;
 
+  if (goa_object != NULL)
+    grl_lua_library_save_goa_data (source->priv->l_st, goa_object);
+
   if (lua_plugin_source_init (source) == FALSE) {
     g_clear_object (&source);
   }
@@ -475,6 +593,230 @@ lua_plugin_source_init (GrlLuaFactorySource *lua_source)
   return ret;
 }
 
+#ifdef GOA_ENABLED
+/* ===================== GOA functions ==================================== */
+
+static void
+grl_lua_factory_add_goa_source (GrlLuaGoaData *lua_data,
+                                GoaObject     *object,
+                                const gchar   *source_id_suffix,
+                                const gchar   *account_name)
+{
+  GError *error = NULL;
+  GrlLuaFactorySource *source;
+
+  source = grl_lua_factory_source_new (lua_data->lua_source_path, lua_data->configs,
+                                       source_id_suffix, account_name, object);
+
+  if (source == NULL) {
+    GRL_DEBUG ("[%s] Fail to initialize.", lua_data->lua_source_path);
+    return;
+  }
+
+  /* In case the plugin gets unref'ed during registration */
+  g_object_add_weak_pointer (G_OBJECT (source), (gpointer *) &source);
+
+  if (!grl_registry_register_source (lua_data->registry, lua_data->plugin,
+                                     GRL_SOURCE (source), &error)) {
+    GRL_DEBUG ("[%s] Fail to register source: %s.", lua_data->lua_source_path, error->message);
+    g_clear_object (&source);
+    g_error_free (error);
+    return;
+  }
+
+  if (!source)
+    return;
+
+  g_object_remove_weak_pointer (G_OBJECT (source), (gpointer *) &source);
+  g_hash_table_insert (lua_data->sources, g_strdup (source_id_suffix), source);
+}
+
+typedef enum {
+  GOA_ADD,
+  GOA_REMOVE,
+  GOA_NOTHING
+} GoaTristate;
+
+static GoaTristate
+enable_goa_source (GrlLuaGoaData *lua_data,
+                  GoaObject     *object,
+                  GoaAccount    *acc,
+                  const gchar   *feature,
+                  gchar        **source_id_suffix)
+{
+  const gchar *account_id;
+
+  account_id = goa_account_get_id (acc);
+  *source_id_suffix = g_strdup_printf ("%s-%s", account_id, feature);
+
+  if (g_strcmp0 (feature, "photos") == 0) {
+    if (!goa_object_peek_photos (object))
+      return GOA_NOTHING;
+    if (!goa_account_get_photos_disabled (acc) &&
+        !g_hash_table_contains (lua_data->sources, *source_id_suffix))
+      return GOA_ADD;
+    if (goa_account_get_photos_disabled (acc) &&
+        g_hash_table_contains (lua_data->sources, *source_id_suffix))
+      return GOA_REMOVE;
+  } else if (g_strcmp0 (feature, "music") == 0) {
+    if (!goa_object_peek_music (object))
+      return GOA_NOTHING;
+    if (!goa_account_get_music_disabled (acc) &&
+        !g_hash_table_contains (lua_data->sources, *source_id_suffix))
+      return GOA_ADD;
+    if (goa_account_get_music_disabled (acc) &&
+        g_hash_table_contains (lua_data->sources, *source_id_suffix))
+      return GOA_REMOVE;
+  } else if (g_strcmp0 (feature, "read-later") == 0) {
+    if (!goa_object_peek_read_later (object))
+      return GOA_NOTHING;
+    if (!goa_account_get_read_later_disabled (acc) &&
+        !g_hash_table_contains (lua_data->sources, *source_id_suffix))
+      return GOA_ADD;
+    if (goa_account_get_read_later_disabled (acc) &&
+        g_hash_table_contains (lua_data->sources, *source_id_suffix))
+      return GOA_REMOVE;
+  }
+
+  return GOA_NOTHING;
+}
+
+static void
+grl_lua_factory_goa_update (GoaClient *client,
+                            GoaObject *object,
+                            gpointer   user_data)
+{
+  GrlLuaGoaData *lua_data = user_data;
+  GoaAccount *acc;
+  gchar *source_id_suffix;
+
+  acc = goa_object_peek_account (object);
+
+  if (g_strcmp0 (goa_account_get_provider_type (acc), lua_data->account_provider) != 0)
+    return;
+
+  switch (enable_goa_source (lua_data, object, acc, lua_data->account_feature, &source_id_suffix)) {
+  case GOA_ADD: {
+    const gchar *account_name;
+    account_name = goa_account_get_presentation_identity (acc);
+    GRL_DEBUG("[%s] GOA update: creating new source for %s support",
+              lua_data->lua_source_path,
+              lua_data->account_feature);
+    grl_lua_factory_add_goa_source (lua_data, object, source_id_suffix, account_name);
+    }
+    break;
+  case GOA_REMOVE: {
+    GrlLuaFactorySource *source = g_hash_table_lookup (lua_data->sources, source_id_suffix);
+    grl_registry_unregister_source (lua_data->registry, GRL_SOURCE (source), NULL);
+    g_hash_table_remove (lua_data->sources, source_id_suffix);
+    GRL_DEBUG ("[%s] GOA update: removed source for %s support",
+               source_id_suffix, lua_data->account_feature);
+    }
+    break;
+  case GOA_NOTHING:
+    /* Nothing changed */
+    break;
+  default:
+    g_assert_not_reached ();
+  }
+
+  g_free (source_id_suffix);
+}
+
+static void
+grl_lua_factory_goa_remove (GoaClient *client,
+                            GoaObject *object,
+                            gpointer   user_data)
+{
+  GrlLuaGoaData *lua_data = user_data;
+  GoaAccount *acc;
+  const gchar *account_id;
+  gchar *source_id;
+
+  acc = goa_object_peek_account (object);
+
+  if (g_strcmp0 (goa_account_get_provider_type (acc), lua_data->account_provider) != 0)
+    return;
+
+  account_id = goa_account_get_id (acc);
+
+  source_id = g_strdup_printf ("%s-%s", account_id, lua_data->account_feature);
+  if (g_hash_table_contains (lua_data->sources, source_id)) {
+    GrlLuaFactorySource *source = g_hash_table_lookup (lua_data->sources, source_id);
+    grl_registry_unregister_source (lua_data->registry, GRL_SOURCE (source), NULL);
+    g_hash_table_remove (lua_data->sources, account_id);
+    g_object_unref (source);
+    GRL_DEBUG ("[%s] GOA update: removed source for %s support", account_id, lua_data->account_feature);
+  }
+  g_free (source_id);
+}
+
+static void
+grl_lua_goa_data_free (GrlLuaGoaData *data)
+{
+  if (data == NULL)
+    return;
+
+  g_clear_object (&data->client);
+  g_free (data->lua_source_path);
+  g_free (data->account_provider);
+  g_free (data->account_feature);
+  g_clear_pointer (&data->sources, g_hash_table_destroy);
+}
+
+static void
+grl_lua_factory_goa_init (GObject *source_object,
+                          GAsyncResult *res,
+                          gpointer user_data)
+{
+  GError *error = NULL;
+  GList *tmp;
+  GList *acc_list;
+  GList *lua_acc_list = NULL;
+  GrlLuaGoaData *lua_data = user_data;
+  GoaClient *client;
+
+  client = goa_client_new_finish (res, &error);
+
+  if (error) {
+    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+      GRL_MESSAGE ("Can't connect to GOA: %s\n", error->message);
+    g_error_free (error);
+    grl_lua_goa_data_free (lua_data);
+    return;
+  }
+
+  lua_data->client = client;
+
+  acc_list = goa_client_get_accounts (client);
+  for (tmp = acc_list; tmp != NULL; tmp = tmp->next) {
+    GoaAccount *acc = goa_object_peek_account (tmp->data);
+
+    if (g_strcmp0 (goa_account_get_provider_type (acc), lua_data->account_provider) == 0)
+      lua_acc_list = g_list_append (lua_acc_list, tmp->data);
+    else
+      g_object_unref(tmp->data);
+  }
+
+  g_list_free (acc_list);
+
+  lua_data->sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+  g_signal_connect (client, "account-added", G_CALLBACK (grl_lua_factory_goa_update), user_data);
+  g_signal_connect (client, "account-removed", G_CALLBACK (grl_lua_factory_goa_remove), user_data);
+  g_signal_connect (client, "account-changed", G_CALLBACK (grl_lua_factory_goa_update), user_data);
+
+  for (tmp = lua_acc_list; tmp != NULL; tmp = tmp->next) {
+    /* the initial adding of the accounts should be done manually, */
+    /* but we can re-use the update function */
+    grl_lua_factory_goa_update (client, (GoaObject *)tmp->data, user_data);
+    g_object_unref (tmp->data);
+  }
+  g_list_free (lua_acc_list);
+}
+
+#endif /* GOA_ENABLED */
+
 /* ======================= Utilities ======================================= */
 
 static GList *
@@ -537,6 +879,116 @@ keys_table_array_to_list (lua_State *L,
   return g_list_reverse (filtered_list);
 }
 
+static gboolean
+validate_account_feature (const char *lua_account_feature)
+{
+  const char const *features[] = {
+    "photos",
+    "read-later",
+    "music",
+    NULL
+  };
+
+  return g_strv_contains (features, lua_account_feature);
+}
+
+static GList *
+handle_goa_sources (GList  *lua_sources,
+                   GList **goa_sources)
+{
+  GList *new_lua_sources = NULL;
+  GList *new_goa_sources = NULL;
+  GList *it;
+
+  for (it = lua_sources; it; it = g_list_next (it)) {
+    lua_State *L;
+    GrlLuaGoaInitData *data;
+    const char *lua_account_provider;
+    const char *lua_account_feature;
+    int ret;
+
+    L = luaL_newstate ();
+    if (L == NULL) {
+      GRL_WARNING ("Unable to create new lua state for '%s'.", (gchar *)it->data);
+      continue;
+    }
+
+    /* Standard Lua libraries */
+    lua_load_safe_libs (L);
+
+    /* Load the plugin */
+    ret = luaL_loadfile (L, it->data);
+    if (ret != LUA_OK) {
+      GRL_WARNING ("[%s] failed to load: %s", (gchar *)it->data, lua_tostring (L, -1));
+      lua_close (L);
+      continue;
+    }
+
+    ret = lua_pcall (L, 0, 0, 0);
+    if (ret != LUA_OK) {
+      GRL_WARNING ("[%s] failed to run: %s", (gchar *)it->data, lua_tostring (L, -1));
+      lua_close (L);
+      continue;
+    }
+
+    lua_getglobal (L, LUA_SOURCE_TABLE);
+    if (!lua_istable (L, -1)) {
+      GRL_DEBUG ("'%s' %s", LUA_SOURCE_TABLE, "table is not defined");
+      lua_close (L);
+      continue;
+    }
+
+    lua_getfield (L, -1, LUA_GOA_ACCOUNT_PROVIDER);
+    lua_account_provider = lua_tolstring (L, -1, NULL);
+    lua_getfield (L, -2, LUA_GOA_ACCOUNT_FEATURE);
+    lua_account_feature = lua_tolstring (L, -1, NULL);
+
+    lua_pop (L, 3);
+
+    if ((lua_account_provider == NULL && lua_account_feature != NULL)
+        || (lua_account_provider != NULL && lua_account_feature == NULL)) {
+      GRL_WARNING ("GOA requirements not well defined for %s", (char *) it->data);
+      lua_close (L);
+      continue;
+    }
+
+#ifndef GOA_ENABLED
+    if (lua_account_provider != NULL && lua_account_feature != NULL) {
+      GRL_DEBUG ("GOA required for source %s but Lua factory compiled without support",
+                 (char *) it->data);
+      lua_close (L);
+      continue;
+    }
+#endif
+
+    if (lua_account_provider == NULL && lua_account_feature == NULL) {
+      new_lua_sources = g_list_prepend (new_lua_sources, g_strdup (it->data));
+      lua_close (L);
+      continue;
+    }
+
+    if (!validate_account_feature (lua_account_feature)) {
+      GRL_WARNING ("Invalid or unsupported account feature '%s' for %s",
+                   lua_account_feature, (char *) it->data);
+      lua_close (L);
+      continue;
+    }
+
+    data = g_new0 (GrlLuaGoaInitData, 1);
+    data->lua_source_path = g_strdup (it->data);
+    data->lua_account_provider = g_strdup (lua_account_provider);
+    data->lua_account_feature = g_strdup (lua_account_feature);
+
+    new_goa_sources = g_list_prepend (new_goa_sources, data);
+
+    lua_close (L);
+  }
+
+  g_list_free_full (lua_sources, g_free);
+  *goa_sources = g_list_reverse (new_goa_sources);
+  return g_list_reverse (new_lua_sources);
+}
+
 static GList *
 get_lua_sources (void)
 {
diff --git a/src/lua-factory/grl-lua-library.c b/src/lua-factory/grl-lua-library.c
index 5dbfaf1..55e08a2 100644
--- a/src/lua-factory/grl-lua-library.c
+++ b/src/lua-factory/grl-lua-library.c
@@ -1479,3 +1479,49 @@ grl_lua_library_get_current_operation (lua_State *L)
 
   return os;
 }
+
+/**
+ * grl_lua_library_save_goa_data
+ *
+ * @L: LuaState where the data will be stored.
+ * @goa_object: #GoaObject to store.
+ * @return: Nothing.
+ *
+ * Stores the GoaObject from Lua-Factory in the global environment of
+ * lua_State.
+ **/
+void
+grl_lua_library_save_goa_data (lua_State *L, gpointer goa_object)
+{
+  g_return_if_fail (goa_object != NULL);
+
+#ifdef GOA_ENABLED
+  lua_pushlightuserdata (L, goa_object);
+  lua_setglobal (L, GOA_LUA_NAME);
+#else
+  GRL_WARNING ("grl_lua_library_save_goa_data() called but GOA support disabled.");
+#endif /* GOA_ENABLED */
+}
+
+/**
+ * grl_lua_library_load_goa_data
+ *
+ * @L: LuaState where the data is stored.
+ * @return: The #GoaObject.
+ **/
+gpointer
+grl_lua_library_load_goa_data (lua_State *L)
+{
+#ifdef GOA_ENABLED
+  GoaObject *goa_object;
+
+  lua_getglobal (L, GOA_LUA_NAME);
+  goa_object = (lua_islightuserdata(L, -1)) ? lua_touserdata(L, -1) : NULL;
+  lua_pop(L, 1);
+
+  return goa_object;
+#else
+  GRL_WARNING ("grl_lua_library_load_goa_data() called but GOA support disabled.");
+  return NULL;
+#endif /* GOA_ENABLED */
+}


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