
We do not use these APIs, so there's no point in keeping them. Realistically, every component that needs a section just does its own parsing on it, so the _get_value() functions are not needed. The fallback in _get_section() is also not needed, as we always pass NULL and then test for it. In Lua, however, it seems we are using the fallback to return an empty object, so that getting a section does not expand to multiple lines of code. For that reason, I have kept the syntax there and implemented it in the bindings layer.
2707 lines
69 KiB
C
2707 lines
69 KiB
C
/* WirePlumber
|
|
*
|
|
* Copyright © 2020 Collabora Ltd.
|
|
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <glib/gstdio.h>
|
|
#include <wp/wp.h>
|
|
#include <pipewire/pipewire.h>
|
|
#include <wplua/wplua.h>
|
|
#include <libintl.h>
|
|
|
|
#define WP_LOCAL_LOG_TOPIC log_topic_lua_scripting
|
|
WP_LOG_TOPIC_EXTERN (log_topic_lua_scripting)
|
|
|
|
#define URI_API "resource:///org/freedesktop/pipewire/wireplumber/m-lua-scripting/api.lua"
|
|
|
|
void wp_lua_scripting_pod_init (lua_State *L);
|
|
void wp_lua_scripting_json_init (lua_State *L);
|
|
void push_luajson (lua_State *L, WpSpaJson *json, gint n_recursions);
|
|
|
|
/* helpers */
|
|
|
|
static WpCore *
|
|
get_wp_core (lua_State *L)
|
|
{
|
|
WpCore *core = NULL;
|
|
lua_pushliteral (L, "wireplumber_core");
|
|
lua_gettable (L, LUA_REGISTRYINDEX);
|
|
core = lua_touserdata (L, -1);
|
|
lua_pop (L, 1);
|
|
return core;
|
|
}
|
|
|
|
static WpCore *
|
|
get_wp_export_core (lua_State *L)
|
|
{
|
|
WpCore *core = get_wp_core (L);
|
|
g_autoptr (WpCore) export_core = wp_core_get_export_core (core);
|
|
return export_core ? export_core : core;
|
|
}
|
|
|
|
/* GLib */
|
|
|
|
static int
|
|
glib_get_monotonic_time (lua_State *L)
|
|
{
|
|
lua_pushinteger (L, g_get_monotonic_time ());
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
glib_get_real_time (lua_State *L)
|
|
{
|
|
lua_pushinteger (L, g_get_real_time ());
|
|
return 1;
|
|
}
|
|
|
|
static gboolean
|
|
access_parse_mode (const gchar * mode_str, gint *mode)
|
|
{
|
|
*mode = 0;
|
|
|
|
if (!mode_str)
|
|
return FALSE;
|
|
else {
|
|
for (guint i = 0; i < strlen (mode_str); i++) {
|
|
switch (mode_str[i]) {
|
|
case 'r': *mode |= R_OK; break;
|
|
case 'w': *mode |= W_OK; break;
|
|
case 'x': *mode |= X_OK; break;
|
|
case 'f': *mode |= F_OK; break;
|
|
case '-': break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
glib_access (lua_State *L)
|
|
{
|
|
const gchar *filename = luaL_checkstring (L, 1);
|
|
int mode = 0;
|
|
if (!access_parse_mode (luaL_checkstring (L, 2), &mode))
|
|
luaL_error (L, "invalid mode string: '%s'", lua_tostring (L, 2));
|
|
lua_pushboolean (L, g_access (filename, mode) >= 0);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg glib_methods[] = {
|
|
{ "get_monotonic_time", glib_get_monotonic_time },
|
|
{ "get_real_time", glib_get_real_time },
|
|
{ "access", glib_access },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* GSource */
|
|
|
|
static int
|
|
source_destroy (lua_State *L)
|
|
{
|
|
GSource *source = wplua_checkboxed (L, 1, G_TYPE_SOURCE);
|
|
g_source_destroy (source);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg source_methods[] = {
|
|
{ "destroy", source_destroy },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* i18n */
|
|
|
|
static int
|
|
i18n_gettext (lua_State *L)
|
|
{
|
|
const gchar * msgid = luaL_checkstring (L, 1);
|
|
lua_pushstring (L, dgettext (GETTEXT_PACKAGE, msgid));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
i18n_ngettext (lua_State *L)
|
|
{
|
|
const gchar * msgid = luaL_checkstring (L, 1);
|
|
const gchar *msgid_plural = luaL_checkstring (L, 2);
|
|
gulong n = luaL_checkinteger (L, 3);
|
|
lua_pushstring (L, dngettext (GETTEXT_PACKAGE, msgid, msgid_plural, n));
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg i18n_funcs[] = {
|
|
{ "gettext", i18n_gettext },
|
|
{ "ngettext", i18n_ngettext },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpCore */
|
|
|
|
static int
|
|
core_get_properties (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autoptr (WpProperties) p = wp_core_get_properties (core);
|
|
wplua_properties_to_table (L, p);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_get_info (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autoptr (WpProperties) p = wp_core_get_remote_properties (core);
|
|
|
|
lua_newtable (L);
|
|
lua_pushinteger (L, wp_core_get_remote_cookie (core));
|
|
lua_setfield (L, -2, "cookie");
|
|
lua_pushstring (L, wp_core_get_remote_name (core));
|
|
lua_setfield (L, -2, "name");
|
|
lua_pushstring (L, wp_core_get_remote_user_name (core));
|
|
lua_setfield (L, -2, "user_name");
|
|
lua_pushstring (L, wp_core_get_remote_host_name (core));
|
|
lua_setfield (L, -2, "host_name");
|
|
lua_pushstring (L, wp_core_get_remote_version (core));
|
|
lua_setfield (L, -2, "version");
|
|
wplua_properties_to_table (L, p);
|
|
lua_setfield (L, -2, "properties");
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_get_vm_type (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autofree gchar *vm = wp_core_get_vm_type (core);
|
|
lua_pushstring (L, vm);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_get_own_bound_id (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
guint32 id = wp_core_get_own_bound_id (core);
|
|
lua_pushinteger (L, id);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_idle_add (lua_State *L)
|
|
{
|
|
GSource *source = NULL;
|
|
luaL_checktype (L, 1, LUA_TFUNCTION);
|
|
wp_core_idle_add_closure (get_wp_core (L), &source,
|
|
wplua_function_to_closure (L, 1));
|
|
wplua_pushboxed (L, G_TYPE_SOURCE, source);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
core_timeout_add (lua_State *L)
|
|
{
|
|
GSource *source = NULL;
|
|
lua_Integer timeout_ms = luaL_checkinteger (L, 1);
|
|
luaL_checktype (L, 2, LUA_TFUNCTION);
|
|
wp_core_timeout_add_closure (get_wp_core (L), &source, timeout_ms,
|
|
wplua_function_to_closure (L, 2));
|
|
wplua_pushboxed (L, G_TYPE_SOURCE, source);
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
on_core_done (WpCore * core, GAsyncResult * res, GClosure * closure)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
GValue val = G_VALUE_INIT;
|
|
int n_vals = 0;
|
|
|
|
if (!wp_core_sync_finish (core, res, &error)) {
|
|
g_value_init (&val, G_TYPE_STRING);
|
|
g_value_set_string (&val, error->message);
|
|
n_vals = 1;
|
|
}
|
|
g_closure_invoke (closure, NULL, n_vals, &val, NULL);
|
|
g_value_unset (&val);
|
|
g_closure_invalidate (closure);
|
|
g_closure_unref (closure);
|
|
}
|
|
|
|
static int
|
|
core_sync (lua_State *L)
|
|
{
|
|
luaL_checktype (L, 1, LUA_TFUNCTION);
|
|
GClosure * closure = wplua_function_to_closure (L, 1);
|
|
g_closure_sink (g_closure_ref (closure));
|
|
wp_core_sync (get_wp_core (L), NULL, (GAsyncReadyCallback) on_core_done,
|
|
closure);
|
|
return 0;
|
|
}
|
|
|
|
static gboolean
|
|
core_disconnect (WpCore * core)
|
|
{
|
|
wp_core_disconnect (core);
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static int
|
|
core_quit (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autoptr (WpProperties) p = wp_core_get_properties (core);
|
|
const gchar *daemon = wp_properties_get (p, "wireplumber.daemon");
|
|
if (!g_strcmp0 (daemon, "true")) {
|
|
wp_warning ("script attempted to quit, but the engine is "
|
|
"running in the wireplumber daemon; ignoring");
|
|
return 0;
|
|
}
|
|
|
|
/* wp_core_disconnect() will immediately destroy the lua plugin
|
|
and the lua engine, so we cannot call it directly */
|
|
wp_core_idle_add (core, NULL, G_SOURCE_FUNC (core_disconnect), core, NULL);
|
|
return 0;
|
|
}
|
|
|
|
#include "require.c"
|
|
|
|
static int
|
|
core_require_api (lua_State *L)
|
|
{
|
|
WpCore * core = get_wp_core (L);
|
|
g_autoptr (WpProperties) p = wp_core_get_properties (core);
|
|
const gchar *daemon = wp_properties_get (p, "wireplumber.daemon");
|
|
if (!g_strcmp0 (daemon, "true")) {
|
|
wp_warning ("script attempted to load an API module, but the engine is "
|
|
"running in the wireplumber daemon; ignoring");
|
|
return 0;
|
|
}
|
|
return wp_require_api_transition_new_from_lua (L, core);
|
|
}
|
|
|
|
static int
|
|
core_test_feature (lua_State *L)
|
|
{
|
|
WpCore *core = get_wp_core(L);
|
|
const char *f = luaL_checkstring (L, 1);
|
|
lua_pushboolean (L, wp_core_test_feature (core, f));
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg core_funcs[] = {
|
|
{ "get_properties", core_get_properties },
|
|
{ "get_info", core_get_info },
|
|
{ "get_vm_type", core_get_vm_type },
|
|
{ "get_own_bound_id", core_get_own_bound_id },
|
|
{ "idle_add", core_idle_add },
|
|
{ "timeout_add", core_timeout_add },
|
|
{ "sync", core_sync },
|
|
{ "quit", core_quit },
|
|
{ "require_api", core_require_api },
|
|
{ "test_feature", core_test_feature },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpLog */
|
|
|
|
typedef struct _WpLogTopic WpLuaLogTopic;
|
|
|
|
static WpLuaLogTopic *
|
|
wp_lua_log_topic_new (const char *name)
|
|
{
|
|
WpLuaLogTopic *topic = g_new0 (WpLuaLogTopic, 1);
|
|
topic->topic_name = g_ref_string_new (name);
|
|
wp_log_topic_register (topic);
|
|
return topic;
|
|
}
|
|
|
|
static WpLuaLogTopic *
|
|
wp_lua_log_topic_copy (WpLuaLogTopic *topic)
|
|
{
|
|
WpLuaLogTopic *copy = g_new0 (WpLuaLogTopic, 1);
|
|
copy->topic_name = g_ref_string_acquire ((char *) copy->topic_name);
|
|
wp_log_topic_register (copy);
|
|
return copy;
|
|
}
|
|
|
|
static void
|
|
wp_lua_log_topic_free (WpLuaLogTopic *topic)
|
|
{
|
|
wp_log_topic_unregister (topic);
|
|
g_ref_string_release ((char *) topic->topic_name);
|
|
g_free (topic);
|
|
}
|
|
|
|
G_DEFINE_BOXED_TYPE (WpLuaLogTopic, wp_lua_log_topic, wp_lua_log_topic_copy,
|
|
wp_lua_log_topic_free)
|
|
|
|
static int
|
|
log_log (lua_State *L, GLogLevelFlags lvl)
|
|
{
|
|
lua_Debug ar = {0};
|
|
const gchar *message;
|
|
gchar line_str[11];
|
|
gconstpointer instance = NULL;
|
|
GType type = G_TYPE_INVALID;
|
|
int index = 1;
|
|
WpLogTopic *topic = log_topic_lua_scripting;
|
|
|
|
/* if called with log topic object */
|
|
if (lua_istable (L, index)) {
|
|
if (lua_getmetatable (L, index)) {
|
|
lua_getfield (L, -1, "__topic");
|
|
if (wplua_isboxed (L, -1, wp_lua_log_topic_get_type ())) {
|
|
topic = wplua_toboxed (L, -1);
|
|
}
|
|
lua_pop (L, 2);
|
|
}
|
|
index++;
|
|
}
|
|
|
|
if (!wp_log_topic_is_enabled (topic, lvl))
|
|
return 0;
|
|
|
|
g_warn_if_fail (lua_getstack (L, 1, &ar) == 1);
|
|
g_warn_if_fail (lua_getinfo (L, "nSl", &ar) == 1);
|
|
|
|
if (wplua_isobject (L, index, G_TYPE_OBJECT)) {
|
|
instance = wplua_toobject (L, index);
|
|
type = G_TYPE_FROM_INSTANCE (instance);
|
|
index++;
|
|
}
|
|
else if (wplua_isboxed (L, index, G_TYPE_BOXED)) {
|
|
instance = wplua_toboxed (L, index);
|
|
type = wplua_gvalue_userdata_type (L, index);
|
|
index++;
|
|
}
|
|
|
|
message = luaL_checkstring (L, index);
|
|
snprintf (line_str, 11, "%d", ar.currentline);
|
|
ar.name = ar.name ? ar.name : "chunk";
|
|
|
|
wp_log_checked (topic->topic_name, lvl,
|
|
ar.source, line_str, ar.name, type, instance, "%s", message);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
log_warning (lua_State *L) { return log_log (L, G_LOG_LEVEL_WARNING); }
|
|
|
|
static int
|
|
log_notice (lua_State *L) { return log_log (L, G_LOG_LEVEL_MESSAGE); }
|
|
|
|
static int
|
|
log_info (lua_State *L) { return log_log (L, G_LOG_LEVEL_INFO); }
|
|
|
|
static int
|
|
log_debug (lua_State *L) { return log_log (L, G_LOG_LEVEL_DEBUG); }
|
|
|
|
static int
|
|
log_trace (lua_State *L) { return log_log (L, WP_LOG_LEVEL_TRACE); }
|
|
|
|
static const luaL_Reg log_obj_funcs[] = {
|
|
{ "warning", log_warning },
|
|
{ "notice", log_notice },
|
|
{ "info", log_info },
|
|
{ "debug", log_debug },
|
|
{ "trace", log_trace },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
static int
|
|
log_open_topic (lua_State *L)
|
|
{
|
|
const char *name = luaL_checkstring (L, 1);
|
|
WpLuaLogTopic *topic = wp_lua_log_topic_new (name);
|
|
|
|
lua_newtable (L); // empty table
|
|
lua_newtable (L); // metatable
|
|
luaL_newlib (L, log_obj_funcs);
|
|
lua_setfield (L, -2, "__index");
|
|
wplua_pushboxed (L, wp_lua_log_topic_get_type (), topic);
|
|
lua_setfield (L, -2, "__topic");
|
|
lua_setmetatable (L, -2);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg log_funcs[] = {
|
|
{ "open_topic", log_open_topic },
|
|
{ "warning", log_warning },
|
|
{ "notice", log_notice },
|
|
{ "info", log_info },
|
|
{ "debug", log_debug },
|
|
{ "trace", log_trace },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpPlugin */
|
|
|
|
static int
|
|
plugin_find (lua_State *L)
|
|
{
|
|
const char *name = luaL_checkstring (L, 1);
|
|
WpPlugin *plugin = wp_plugin_find (get_wp_core (L), name);
|
|
if (plugin)
|
|
wplua_pushobject (L, plugin);
|
|
else
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg plugin_funcs[] = {
|
|
{ "find", plugin_find },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpObject */
|
|
|
|
static void
|
|
object_activate_done (WpObject *o, GAsyncResult * res, GClosure * closure)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
GValue val[2] = { G_VALUE_INIT, G_VALUE_INIT };
|
|
int n_vals = 1;
|
|
|
|
if (!wp_object_activate_finish (o, res, &error)) {
|
|
wp_notice_object (o, "%s", error->message);
|
|
if (closure) {
|
|
g_value_init (&val[1], G_TYPE_STRING);
|
|
g_value_set_string (&val[1], error->message);
|
|
n_vals = 2;
|
|
}
|
|
}
|
|
if (closure) {
|
|
g_value_init_from_instance (&val[0], o);
|
|
g_closure_invoke (closure, NULL, n_vals, val, NULL);
|
|
g_value_unset (&val[0]);
|
|
g_value_unset (&val[1]);
|
|
g_closure_invalidate (closure);
|
|
g_closure_unref (closure);
|
|
}
|
|
}
|
|
|
|
static int
|
|
object_activate (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = luaL_checkinteger (L, 2);
|
|
GClosure * closure = luaL_opt (L, wplua_checkclosure, 3, NULL);
|
|
if (closure)
|
|
g_closure_sink (g_closure_ref (closure));
|
|
wp_object_activate (o, features, NULL,
|
|
(GAsyncReadyCallback) object_activate_done, closure);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
object_deactivate (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = luaL_checkinteger (L, 2);
|
|
wp_object_deactivate (o, features);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
object_get_active_features (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = wp_object_get_active_features (o);
|
|
lua_pushinteger (L, features);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_get_supported_features (lua_State *L)
|
|
{
|
|
WpObject *o = wplua_checkobject (L, 1, WP_TYPE_OBJECT);
|
|
WpObjectFeatures features = wp_object_get_supported_features (o);
|
|
lua_pushinteger (L, features);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg object_methods[] = {
|
|
{ "activate", object_activate },
|
|
{ "deactivate", object_deactivate },
|
|
{ "get_active_features", object_get_active_features },
|
|
{ "get_supported_features", object_get_supported_features },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpProxy */
|
|
|
|
static int
|
|
proxy_get_interface_type (lua_State *L)
|
|
{
|
|
WpProxy * p = wplua_checkobject (L, 1, WP_TYPE_PROXY);
|
|
guint32 version = 0;
|
|
const gchar *type = wp_proxy_get_interface_type (p, &version);
|
|
lua_pushstring (L, type);
|
|
lua_pushinteger (L, version);
|
|
return 2;
|
|
}
|
|
|
|
static const luaL_Reg proxy_methods[] = {
|
|
{ "get_interface_type", proxy_get_interface_type },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpGlobalProxy */
|
|
|
|
static int
|
|
global_proxy_request_destroy (lua_State *L)
|
|
{
|
|
WpGlobalProxy * p = wplua_checkobject (L, 1, WP_TYPE_GLOBAL_PROXY);
|
|
wp_global_proxy_request_destroy (p);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg global_proxy_methods[] = {
|
|
{ "request_destroy", global_proxy_request_destroy },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpIterator */
|
|
|
|
static int
|
|
iterator_next (lua_State *L)
|
|
{
|
|
WpIterator *it = wplua_checkboxed (L, 1, WP_TYPE_ITERATOR);
|
|
g_auto (GValue) v = G_VALUE_INIT;
|
|
if (it && wp_iterator_next (it, &v)) {
|
|
return wplua_gvalue_to_lua (L, &v);
|
|
} else {
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int
|
|
push_wpiterator (lua_State *L, WpIterator *it)
|
|
{
|
|
lua_pushcfunction (L, iterator_next);
|
|
wplua_pushboxed (L, WP_TYPE_ITERATOR, it);
|
|
return 2;
|
|
}
|
|
|
|
/* Settings WpIterator */
|
|
|
|
static int
|
|
settings_iterator_next (lua_State *L)
|
|
{
|
|
WpIterator *it = wplua_checkboxed (L, 1, WP_TYPE_ITERATOR);
|
|
g_auto (GValue) item = G_VALUE_INIT;
|
|
if (wp_iterator_next (it, &item)) {
|
|
WpSettingsItem *si = g_value_get_boxed (&item);
|
|
const gchar *k = wp_settings_item_get_key (si);
|
|
WpSpaJson *v = wp_settings_item_get_value (si);
|
|
lua_pushstring (L, k);
|
|
wplua_pushboxed (L, WP_TYPE_SPA_JSON, v);
|
|
return 2;
|
|
} else {
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int
|
|
push_settings_wpiterator (lua_State *L, WpIterator *it)
|
|
{
|
|
lua_pushcfunction (L, settings_iterator_next);
|
|
wplua_pushboxed (L, WP_TYPE_ITERATOR, it);
|
|
return 2;
|
|
}
|
|
|
|
/* Metadata WpIterator */
|
|
|
|
static int
|
|
metadata_iterator_next (lua_State *L)
|
|
{
|
|
WpIterator *it = wplua_checkboxed (L, 1, WP_TYPE_ITERATOR);
|
|
g_auto (GValue) item = G_VALUE_INIT;
|
|
if (wp_iterator_next (it, &item)) {
|
|
WpMetadataItem *mi = g_value_get_boxed (&item);
|
|
guint32 s = wp_metadata_item_get_subject (mi);
|
|
const gchar *k = wp_metadata_item_get_key (mi);
|
|
const gchar *t = wp_metadata_item_get_value_type (mi);
|
|
const gchar *v = wp_metadata_item_get_value (mi);
|
|
lua_pushinteger (L, s);
|
|
lua_pushstring (L, k);
|
|
lua_pushstring (L, t);
|
|
lua_pushstring (L, v);
|
|
return 4;
|
|
} else {
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
static int
|
|
push_metadata_wpiterator (lua_State *L, WpIterator *it)
|
|
{
|
|
lua_pushcfunction (L, metadata_iterator_next);
|
|
wplua_pushboxed (L, WP_TYPE_ITERATOR, it);
|
|
return 2;
|
|
}
|
|
|
|
/* WpObjectInterest */
|
|
|
|
static GVariant *
|
|
constraint_value_to_variant (lua_State *L, int idx)
|
|
{
|
|
switch (lua_type (L, idx)) {
|
|
case LUA_TBOOLEAN:
|
|
return g_variant_new_boolean (lua_toboolean (L, idx));
|
|
case LUA_TSTRING:
|
|
return g_variant_new_string (lua_tostring (L, idx));
|
|
case LUA_TNUMBER:
|
|
if (lua_isinteger (L, idx))
|
|
return g_variant_new_int64 (lua_tointeger (L, idx));
|
|
else
|
|
return g_variant_new_double (lua_tonumber (L, idx));
|
|
default:
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
object_interest_new_add_constraint (lua_State *L, GType type,
|
|
WpObjectInterest *interest)
|
|
{
|
|
int constraint_idx;
|
|
WpConstraintType ctype;
|
|
const gchar *subject;
|
|
WpConstraintVerb verb;
|
|
GVariant *value = NULL;
|
|
|
|
constraint_idx = lua_absindex (L, -1);
|
|
|
|
/* verify this is a Constraint{} */
|
|
if (lua_type (L, constraint_idx) != LUA_TTABLE) {
|
|
luaL_error (L, "Interest: expected Constraint at index %d",
|
|
lua_tointeger (L, -2));
|
|
}
|
|
|
|
if (luaL_getmetafield (L, constraint_idx, "__name") == LUA_TNIL ||
|
|
g_strcmp0 (lua_tostring (L, -1), "Constraint") != 0) {
|
|
luaL_error (L, "Interest: expected Constraint at index %d",
|
|
lua_tointeger (L, -2));
|
|
}
|
|
lua_pop (L, 1);
|
|
|
|
/* get the constraint type */
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, constraint_idx) == LUA_TNUMBER)
|
|
ctype = lua_tointeger (L, -1);
|
|
else
|
|
ctype = WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY;
|
|
lua_pop (L, 1);
|
|
|
|
/* get t[1] (the subject) and t[2] (the verb) */
|
|
lua_geti (L, constraint_idx, 1);
|
|
subject = lua_tostring (L, -1);
|
|
|
|
lua_geti (L, constraint_idx, 2);
|
|
verb = lua_tostring (L, -1)[0];
|
|
|
|
switch (verb) {
|
|
case WP_CONSTRAINT_VERB_EQUALS:
|
|
case WP_CONSTRAINT_VERB_NOT_EQUALS:
|
|
case WP_CONSTRAINT_VERB_MATCHES: {
|
|
lua_geti (L, constraint_idx, 3);
|
|
value = constraint_value_to_variant (L, -1);
|
|
if (G_UNLIKELY (!value))
|
|
luaL_error (L, "Constraint: bad value type");
|
|
break;
|
|
}
|
|
case WP_CONSTRAINT_VERB_IN_RANGE: {
|
|
GVariant *values[2];
|
|
lua_geti (L, constraint_idx, 3);
|
|
lua_geti (L, constraint_idx, 4);
|
|
values[0] = constraint_value_to_variant (L, -2);
|
|
values[1] = constraint_value_to_variant (L, -1);
|
|
if (G_UNLIKELY (!values[0] || !values[1])) {
|
|
g_clear_pointer (&values[0], g_variant_unref);
|
|
g_clear_pointer (&values[1], g_variant_unref);
|
|
luaL_error (L, "Constraint: bad value type");
|
|
}
|
|
value = g_variant_new_tuple (values, 2);
|
|
break;
|
|
}
|
|
case WP_CONSTRAINT_VERB_IN_LIST: {
|
|
GPtrArray *values =
|
|
g_ptr_array_new_with_free_func ((GDestroyNotify) g_variant_unref);
|
|
int i = 3;
|
|
while (lua_geti (L, constraint_idx, i++) != LUA_TNIL) {
|
|
GVariant *tmp = constraint_value_to_variant (L, -1);
|
|
if (G_UNLIKELY (!tmp)) {
|
|
g_ptr_array_unref (values);
|
|
luaL_error (L, "Constraint: bad value type");
|
|
}
|
|
g_ptr_array_add (values, g_variant_ref_sink (tmp));
|
|
lua_pop (L, 1);
|
|
}
|
|
value = g_variant_new_tuple ((GVariant **) values->pdata, values->len);
|
|
g_ptr_array_unref (values);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
wp_object_interest_add_constraint (interest, ctype, subject, verb, value);
|
|
lua_settop (L, constraint_idx);
|
|
}
|
|
|
|
static GType
|
|
parse_gtype (const gchar *str)
|
|
{
|
|
g_autofree gchar *typestr = NULL;
|
|
GType res = G_TYPE_INVALID;
|
|
|
|
g_return_val_if_fail (str, res);
|
|
|
|
/* "device" -> "WpDevice" */
|
|
typestr = g_strdup_printf ("Wp%s", str);
|
|
if (typestr[2] != 0) {
|
|
typestr[2] = g_ascii_toupper (typestr[2]);
|
|
res = g_type_from_name (typestr);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
object_interest_new_index (lua_State *L, int idx, GType def_type)
|
|
{
|
|
WpObjectInterest *interest = NULL;
|
|
GType type = def_type;
|
|
|
|
luaL_checktype (L, idx, LUA_TTABLE);
|
|
|
|
/* type = "string" */
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, idx) == LUA_TSTRING) {
|
|
type = parse_gtype (lua_tostring (L, -1));
|
|
if (type == G_TYPE_INVALID)
|
|
luaL_error (L, "Interest: unknown type '%s'", lua_tostring (L, -1));
|
|
}
|
|
else if (def_type == G_TYPE_INVALID)
|
|
luaL_error (L, "Interest: expected 'type' as string");
|
|
lua_pop (L, 1);
|
|
|
|
interest = wp_object_interest_new_type (type);
|
|
wplua_pushboxed (L, WP_TYPE_OBJECT_INTEREST, interest);
|
|
|
|
/* add constraints */
|
|
lua_pushnil (L);
|
|
while (lua_next (L, idx)) {
|
|
/* if the key isn't "type" */
|
|
if (!(lua_type (L, -2) == LUA_TSTRING &&
|
|
!g_strcmp0 ("type", lua_tostring (L, -2))))
|
|
object_interest_new_add_constraint (L, type, interest);
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_interest_new (lua_State *L)
|
|
{
|
|
return object_interest_new_index (L, 1, G_TYPE_INVALID);
|
|
}
|
|
|
|
static int
|
|
object_interest_matches (lua_State *L)
|
|
{
|
|
WpObjectInterest *interest = wplua_checkboxed (L, 1, WP_TYPE_OBJECT_INTEREST);
|
|
gboolean matches = FALSE;
|
|
|
|
if (wplua_isobject (L, 2, G_TYPE_OBJECT)) {
|
|
matches = wp_object_interest_matches (interest, wplua_toobject (L, 2));
|
|
}
|
|
else if (lua_istable (L, 2)) {
|
|
g_autoptr (WpProperties) props = wplua_table_to_properties (L, 2);
|
|
matches = wp_object_interest_matches (interest, props);
|
|
} else
|
|
luaL_argerror (L, 2, "expected GObject or table");
|
|
|
|
lua_pushboolean (L, matches);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg object_interest_methods[] = {
|
|
{ "matches", object_interest_matches },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
static WpObjectInterest *
|
|
get_optional_object_interest (lua_State *L, int idx, GType def_type)
|
|
{
|
|
if (lua_isnoneornil (L, idx))
|
|
return NULL;
|
|
else if (lua_isuserdata (L, idx))
|
|
return wplua_checkboxed (L, idx, WP_TYPE_OBJECT_INTEREST);
|
|
else if (lua_istable (L, idx)) {
|
|
object_interest_new_index (L, idx, def_type);
|
|
return wplua_toboxed (L, -1);
|
|
} else {
|
|
luaL_error (L, "expected Interest or none/nil");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* WpObjectManager */
|
|
|
|
static int
|
|
object_manager_new (lua_State *L)
|
|
{
|
|
WpObjectManager *om;
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 1, LUA_TTABLE);
|
|
|
|
/* push to Lua asap to have a way to unref in case of error */
|
|
om = wp_object_manager_new ();
|
|
wplua_pushobject (L, om);
|
|
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 1)) {
|
|
WpObjectInterest *interest =
|
|
wplua_checkboxed (L, -1, WP_TYPE_OBJECT_INTEREST);
|
|
wp_object_manager_add_interest_full (om, wp_object_interest_ref (interest));
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
/* request all the features for Lua scripts to make their job easier */
|
|
wp_object_manager_request_object_features (om,
|
|
WP_TYPE_OBJECT, WP_OBJECT_FEATURES_ALL);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_manager_activate (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
wp_core_install_object_manager (get_wp_core (L), om);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
object_manager_get_n_objects (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
lua_pushinteger (L, wp_object_manager_get_n_objects (om));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
object_manager_iterate (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, G_TYPE_OBJECT);
|
|
WpIterator *it = oi ?
|
|
wp_object_manager_new_filtered_iterator_full (om,
|
|
wp_object_interest_ref (oi)) :
|
|
wp_object_manager_new_iterator (om);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
object_manager_lookup (lua_State *L)
|
|
{
|
|
WpObjectManager *om = wplua_checkobject (L, 1, WP_TYPE_OBJECT_MANAGER);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, G_TYPE_OBJECT);
|
|
WpObject *o = oi ?
|
|
wp_object_manager_lookup_full (om, wp_object_interest_ref (oi)) :
|
|
wp_object_manager_lookup (om, G_TYPE_OBJECT, NULL);
|
|
if (o) {
|
|
wplua_pushobject (L, o);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg object_manager_methods[] = {
|
|
{ "activate", object_manager_activate },
|
|
{ "get_n_objects", object_manager_get_n_objects },
|
|
{ "iterate", object_manager_iterate },
|
|
{ "lookup", object_manager_lookup },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpMetadata */
|
|
|
|
static int
|
|
metadata_iterate (lua_State *L)
|
|
{
|
|
WpMetadata *metadata = wplua_checkobject (L, 1, WP_TYPE_METADATA);
|
|
lua_Integer subject = luaL_checkinteger (L, 2);
|
|
WpIterator *it = wp_metadata_new_iterator (metadata, subject);
|
|
return push_metadata_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
metadata_find (lua_State *L)
|
|
{
|
|
WpMetadata *metadata = wplua_checkobject (L, 1, WP_TYPE_METADATA);
|
|
lua_Integer subject = luaL_checkinteger (L, 2);
|
|
const char *key = luaL_checkstring (L, 3), *v = NULL, *t = NULL;
|
|
v = wp_metadata_find (metadata, subject, key, &t);
|
|
lua_pushstring (L, v);
|
|
lua_pushstring (L, t);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
metadata_set (lua_State *L)
|
|
{
|
|
WpMetadata *metadata = wplua_checkobject (L, 1, WP_TYPE_METADATA);
|
|
lua_Integer subject = luaL_checkinteger (L, 2);
|
|
const char *key = luaL_opt (L, luaL_checkstring, 3, NULL);
|
|
const char *type = luaL_opt (L, luaL_checkstring, 4, NULL);
|
|
const char *value = luaL_opt (L, luaL_checkstring, 5, NULL);
|
|
wp_metadata_set (metadata, subject, key, type, value);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg metadata_methods[] = {
|
|
{ "iterate", metadata_iterate },
|
|
{ "find", metadata_find },
|
|
{ "set", metadata_set },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpImplMetadata */
|
|
|
|
static int
|
|
impl_metadata_new (lua_State *L)
|
|
{
|
|
const char *name = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpImplMetadata *m = wp_impl_metadata_new_full (get_wp_core (L),
|
|
name, properties);
|
|
if (m)
|
|
wplua_pushobject (L, m);
|
|
return m ? 1 : 0;
|
|
}
|
|
|
|
/* Device */
|
|
|
|
static int
|
|
device_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpDevice *d = wp_device_new_from_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
/* WpSpaDevice */
|
|
|
|
static int
|
|
spa_device_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpSpaDevice *d = wp_spa_device_new_from_spa_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
spa_device_iterate_managed_objects (lua_State *L)
|
|
{
|
|
WpSpaDevice *device = wplua_checkobject (L, 1, WP_TYPE_SPA_DEVICE);
|
|
WpIterator *it = wp_spa_device_new_managed_object_iterator (device);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
spa_device_get_managed_object (lua_State *L)
|
|
{
|
|
WpSpaDevice *device = wplua_checkobject (L, 1, WP_TYPE_SPA_DEVICE);
|
|
guint id = luaL_checkinteger (L, 2);
|
|
GObject *obj = wp_spa_device_get_managed_object (device, id);
|
|
if (obj)
|
|
wplua_pushobject (L, obj);
|
|
return obj ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
spa_device_store_managed_object (lua_State *L)
|
|
{
|
|
WpSpaDevice *device = wplua_checkobject (L, 1, WP_TYPE_SPA_DEVICE);
|
|
guint id = luaL_checkinteger (L, 2);
|
|
GObject *obj = (lua_type (L, 3) != LUA_TNIL) ?
|
|
g_object_ref (wplua_checkobject (L, 3, G_TYPE_OBJECT)) : NULL;
|
|
|
|
wp_spa_device_store_managed_object (device, id, obj);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg spa_device_methods[] = {
|
|
{ "iterate_managed_objects", spa_device_iterate_managed_objects },
|
|
{ "get_managed_object", spa_device_get_managed_object },
|
|
{ "store_managed_object", spa_device_store_managed_object },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* Node */
|
|
|
|
static int
|
|
node_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpNode *d = wp_node_new_from_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
node_get_state (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
const gchar *error = NULL;
|
|
WpNodeState state = wp_node_get_state (node, &error);
|
|
wplua_enum_to_lua (L, state, WP_TYPE_NODE_STATE);
|
|
lua_pushstring (L, error ? error : "");
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
node_get_n_input_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
guint max = 0;
|
|
guint ports = wp_node_get_n_input_ports (node, &max);
|
|
lua_pushinteger (L, ports);
|
|
lua_pushinteger (L, max);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
node_get_n_output_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
guint max = 0;
|
|
guint ports = wp_node_get_n_output_ports (node, &max);
|
|
lua_pushinteger (L, ports);
|
|
lua_pushinteger (L, max);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
node_get_n_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
guint ports = wp_node_get_n_ports (node);
|
|
lua_pushinteger (L, ports);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
node_iterate_ports (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, WP_TYPE_PORT);
|
|
WpIterator *it = oi ?
|
|
wp_node_new_ports_filtered_iterator_full (node,
|
|
wp_object_interest_ref (oi)) :
|
|
wp_node_new_ports_iterator (node);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
node_lookup_port (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
WpObjectInterest *oi = get_optional_object_interest (L, 2, WP_TYPE_PORT);
|
|
WpPort *port = oi ?
|
|
wp_node_lookup_port_full (node, wp_object_interest_ref (oi)) :
|
|
wp_node_lookup_port (node, G_TYPE_OBJECT, NULL);
|
|
if (port) {
|
|
wplua_pushobject (L, port);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
node_send_command (lua_State *L)
|
|
{
|
|
WpNode *node = wplua_checkobject (L, 1, WP_TYPE_NODE);
|
|
const char *command = luaL_checkstring (L, 2);
|
|
wp_node_send_command (node, command);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg node_methods[] = {
|
|
{ "get_state", node_get_state },
|
|
{ "get_n_input_ports", node_get_n_input_ports },
|
|
{ "get_n_output_ports", node_get_n_output_ports },
|
|
{ "get_n_ports", node_get_n_ports },
|
|
{ "iterate_ports", node_iterate_ports },
|
|
{ "lookup_port", node_lookup_port },
|
|
{ "send_command", node_send_command },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* ImplNode */
|
|
|
|
static int
|
|
impl_node_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpImplNode *d = wp_impl_node_new_from_pw_factory (get_wp_export_core (L),
|
|
factory, properties);
|
|
if (d)
|
|
wplua_pushobject (L, d);
|
|
return d ? 1 : 0;
|
|
}
|
|
|
|
/* Port */
|
|
|
|
static int
|
|
port_get_direction (lua_State *L)
|
|
{
|
|
WpPort *port = wplua_checkobject (L, 1, WP_TYPE_PORT);
|
|
WpDirection direction = wp_port_get_direction (port);
|
|
wplua_enum_to_lua (L, direction, WP_TYPE_DIRECTION);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg port_methods[] = {
|
|
{ "get_direction", port_get_direction },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* Link */
|
|
|
|
static int
|
|
link_new (lua_State *L)
|
|
{
|
|
const char *factory = luaL_checkstring (L, 1);
|
|
WpProperties *properties = NULL;
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL) {
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
}
|
|
|
|
WpLink *l = wp_link_new_from_factory (get_wp_core (L), factory, properties);
|
|
if (l)
|
|
wplua_pushobject (L, l);
|
|
return l ? 1 : 0;
|
|
}
|
|
|
|
/* Client */
|
|
|
|
static gboolean
|
|
client_parse_permissions (const gchar * perms_str, guint32 *perms)
|
|
{
|
|
*perms = 0;
|
|
|
|
if (!perms_str)
|
|
return FALSE;
|
|
else if (g_strcmp0 (perms_str, "all") == 0)
|
|
*perms = PW_PERM_ALL;
|
|
else {
|
|
for (guint i = 0; i < strlen (perms_str); i++) {
|
|
switch (perms_str[i]) {
|
|
case 'r': *perms |= PW_PERM_R; break;
|
|
case 'w': *perms |= PW_PERM_W; break;
|
|
case 'x': *perms |= PW_PERM_X; break;
|
|
case 'm': *perms |= PW_PERM_M; break;
|
|
case 'l': *perms |= PW_PERM_L; break;
|
|
case '-': break;
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
client_update_permissions (lua_State *L)
|
|
{
|
|
WpClient *client = wplua_checkobject (L, 1, WP_TYPE_CLIENT);
|
|
g_autoptr (GArray) arr = NULL;
|
|
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
|
|
lua_pushnil(L);
|
|
while (lua_next (L, -2)) {
|
|
struct pw_permission perm = {0};
|
|
|
|
if (lua_type (L, -2) == LUA_TSTRING &&
|
|
(!g_ascii_strcasecmp (lua_tostring(L, -2), "any") ||
|
|
!g_ascii_strcasecmp (lua_tostring(L, -2), "all")))
|
|
perm.id = PW_ID_ANY;
|
|
else if (lua_isinteger (L, -2))
|
|
perm.id = lua_tointeger (L, -2);
|
|
else
|
|
luaL_error (L, "invalid key for permissions array");
|
|
|
|
if (!client_parse_permissions (lua_tostring (L, -1), &perm.permissions))
|
|
luaL_error (L, "invalid permission string: '%s'", lua_tostring (L, -1));
|
|
|
|
if (!arr)
|
|
arr = g_array_new (FALSE, FALSE, sizeof (struct pw_permission));
|
|
|
|
g_array_append_val (arr, perm);
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
wp_client_update_permissions_array (client, arr->len,
|
|
(const struct pw_permission *) arr->data);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
client_update_properties (lua_State *L)
|
|
{
|
|
WpClient *client = wplua_checkobject (L, 1, WP_TYPE_CLIENT);
|
|
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
WpProperties *properties = wplua_table_to_properties (L, 2);
|
|
|
|
wp_client_update_properties (client, properties);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
client_send_error (lua_State *L)
|
|
{
|
|
WpClient *client = wplua_checkobject (L, 1, WP_TYPE_CLIENT);
|
|
guint id = luaL_checkinteger (L, 2);
|
|
int res = luaL_checkinteger (L, 3);
|
|
const char *message = luaL_checkstring (L, 4);
|
|
wp_client_send_error (client, id, res, message);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg client_methods[] = {
|
|
{ "update_permissions", client_update_permissions },
|
|
{ "update_properties", client_update_properties },
|
|
{ "send_error", client_send_error },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpSessionItem */
|
|
|
|
static int
|
|
session_item_new (lua_State *L)
|
|
{
|
|
const char *type = luaL_checkstring (L, 1);
|
|
WpSessionItem *si = wp_session_item_make (get_wp_core (L), type);
|
|
if (si)
|
|
wplua_pushobject (L, si);
|
|
return si ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
session_item_get_associated_proxy (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
const char *typestr = luaL_checkstring (L, 2);
|
|
WpProxy *proxy = wp_session_item_get_associated_proxy (si,
|
|
parse_gtype (typestr));
|
|
if (proxy)
|
|
wplua_pushobject (L, proxy);
|
|
return proxy ? 1 : 0;
|
|
}
|
|
|
|
static int
|
|
session_item_reset (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
wp_session_item_reset (si);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
session_item_configure (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
WpProperties *props = wp_properties_new_empty ();
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
|
|
/* build the configuration properties */
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 2)) {
|
|
const gchar *key = NULL;
|
|
g_autofree gchar *var = NULL;
|
|
|
|
switch (lua_type (L, -1)) {
|
|
case LUA_TBOOLEAN:
|
|
var = g_strdup_printf ("%u", lua_toboolean (L, -1));
|
|
break;
|
|
case LUA_TNUMBER:
|
|
if (lua_isinteger (L, -1))
|
|
var = g_strdup_printf ("%lld", lua_tointeger (L, -1));
|
|
else
|
|
var = g_strdup_printf ("%f", lua_tonumber (L, -1));
|
|
break;
|
|
case LUA_TSTRING:
|
|
var = g_strdup (lua_tostring (L, -1));
|
|
break;
|
|
case LUA_TUSERDATA: {
|
|
GValue *v = lua_touserdata (L, -1);
|
|
gpointer p = g_value_peek_pointer (v);
|
|
var = g_strdup_printf ("%p", p);
|
|
break;
|
|
}
|
|
default:
|
|
luaL_error (L, "configure does not support lua type ",
|
|
lua_typename(L, lua_type(L, -1)));
|
|
break;
|
|
}
|
|
|
|
key = luaL_tolstring (L, -2, NULL);
|
|
wp_properties_set (props, key, var);
|
|
lua_pop (L, 2);
|
|
}
|
|
|
|
lua_pushboolean (L, wp_session_item_configure (si, props));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
session_item_register (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
wp_session_item_register (g_object_ref (si));
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
session_item_remove (lua_State *L)
|
|
{
|
|
WpSessionItem *si = wplua_checkobject (L, 1, WP_TYPE_SESSION_ITEM);
|
|
wp_session_item_remove (si);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg session_item_methods[] = {
|
|
{ "get_associated_proxy", session_item_get_associated_proxy },
|
|
{ "reset", session_item_reset },
|
|
{ "configure", session_item_configure },
|
|
{ "register", session_item_register },
|
|
{ "remove", session_item_remove },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpSiAdapter */
|
|
|
|
static int
|
|
si_adapter_get_ports_format (lua_State *L)
|
|
{
|
|
WpSiAdapter *adapter = wplua_checkobject (L, 1, WP_TYPE_SI_ADAPTER);
|
|
const gchar *mode = NULL;
|
|
WpSpaPod *format = wp_si_adapter_get_ports_format (adapter, &mode);
|
|
wplua_pushboxed (L, WP_TYPE_SPA_POD, format);
|
|
lua_pushstring (L, mode);
|
|
return 2;
|
|
}
|
|
|
|
static void
|
|
si_adapter_set_ports_format_done (WpObject *o, GAsyncResult * res,
|
|
GClosure * closure)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
GValue val[2] = { G_VALUE_INIT, G_VALUE_INIT };
|
|
int n_vals = 1;
|
|
|
|
if (!wp_si_adapter_set_ports_format_finish (WP_SI_ADAPTER (o), res, &error)) {
|
|
wp_notice_object (o, "%s", error->message);
|
|
if (closure) {
|
|
g_value_init (&val[1], G_TYPE_STRING);
|
|
g_value_set_string (&val[1], error->message);
|
|
n_vals = 2;
|
|
}
|
|
}
|
|
if (closure) {
|
|
g_value_init_from_instance (&val[0], o);
|
|
g_closure_invoke (closure, NULL, n_vals, val, NULL);
|
|
g_value_unset (&val[0]);
|
|
g_value_unset (&val[1]);
|
|
g_closure_invalidate (closure);
|
|
g_closure_unref (closure);
|
|
}
|
|
}
|
|
|
|
static int
|
|
si_adapter_set_ports_format (lua_State *L)
|
|
{
|
|
WpSiAdapter *adapter = wplua_checkobject (L, 1, WP_TYPE_SI_ADAPTER);
|
|
WpSpaPod *format = wplua_checkboxed (L, 2, WP_TYPE_SPA_POD);
|
|
const gchar *mode = luaL_checkstring (L, 3);
|
|
GClosure * closure = luaL_opt (L, wplua_checkclosure, 4, NULL);
|
|
if (closure)
|
|
g_closure_sink (g_closure_ref (closure));
|
|
wp_si_adapter_set_ports_format (adapter, wp_spa_pod_ref (format), mode,
|
|
(GAsyncReadyCallback) si_adapter_set_ports_format_done, closure);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg si_adapter_methods[] = {
|
|
{ "get_ports_format", si_adapter_get_ports_format },
|
|
{ "set_ports_format", si_adapter_set_ports_format },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpPipewireObject */
|
|
|
|
static int
|
|
pipewire_object_iterate_params (lua_State *L)
|
|
{
|
|
WpPipewireObject *pwobj = wplua_checkobject (L, 1, WP_TYPE_PIPEWIRE_OBJECT);
|
|
const gchar *id = luaL_checkstring (L, 2);
|
|
WpIterator *it = wp_pipewire_object_enum_params_sync (pwobj, id, NULL);
|
|
return push_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
pipewire_object_set_param (lua_State *L)
|
|
{
|
|
WpPipewireObject *pwobj = wplua_checkobject (L, 1, WP_TYPE_PIPEWIRE_OBJECT);
|
|
const gchar *id = luaL_checkstring (L, 2);
|
|
WpSpaPod *pod = wplua_checkboxed (L, 3, WP_TYPE_SPA_POD);
|
|
wp_pipewire_object_set_param (pwobj, id, 0, wp_spa_pod_ref (pod));
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg pipewire_object_methods[] = {
|
|
{ "iterate_params", pipewire_object_iterate_params },
|
|
{ "set_param" , pipewire_object_set_param },
|
|
{ "set_params" , pipewire_object_set_param }, /* deprecated, compat only */
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpState */
|
|
|
|
static int
|
|
state_new (lua_State *L)
|
|
{
|
|
const gchar *name = luaL_checkstring (L, 1);
|
|
WpState *state = wp_state_new (name);
|
|
wplua_pushobject (L, state);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
state_clear (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
wp_state_clear (state);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
state_save (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
g_autoptr (WpProperties) props = wplua_table_to_properties (L, 2);
|
|
g_autoptr (GError) error = NULL;
|
|
gboolean saved = wp_state_save (state, props, &error);
|
|
lua_pushboolean (L, saved);
|
|
lua_pushstring (L, error ? error->message : "");
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
state_save_after_timeout (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
g_autoptr (WpProperties) props = wplua_table_to_properties (L, 2);
|
|
wp_state_save_after_timeout (state, get_wp_core (L), props);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
state_load (lua_State *L)
|
|
{
|
|
WpState *state = wplua_checkobject (L, 1, WP_TYPE_STATE);
|
|
g_autoptr (WpProperties) props = wp_state_load (state);
|
|
wplua_properties_to_table (L, props);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg state_methods[] = {
|
|
{ "clear", state_clear },
|
|
{ "save" , state_save },
|
|
{ "save_after_timeout", state_save_after_timeout },
|
|
{ "load" , state_load },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* ImplModule */
|
|
|
|
static int
|
|
impl_module_new (lua_State *L)
|
|
{
|
|
const char *name, *args = NULL;
|
|
WpProperties *properties = NULL;
|
|
|
|
name = luaL_checkstring (L, 1);
|
|
|
|
if (lua_type (L, 2) != LUA_TNONE && lua_type (L, 2) != LUA_TNIL)
|
|
args = luaL_checkstring (L, 2);
|
|
|
|
if (lua_type (L, 3) != LUA_TNONE && lua_type (L, 3) != LUA_TNIL) {
|
|
luaL_checktype (L, 3, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 3);
|
|
}
|
|
|
|
WpImplModule *m = wp_impl_module_load (get_wp_export_core (L),
|
|
name, args, properties);
|
|
|
|
if (m) {
|
|
wplua_pushobject (L, m);
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* WpConf */
|
|
|
|
static int
|
|
conf_get_section (lua_State *L)
|
|
{
|
|
g_autoptr (WpConf) conf = wp_core_get_conf (get_wp_core (L));
|
|
const char *section;
|
|
g_autoptr (WpSpaJson) fb = NULL;
|
|
g_autoptr (WpSpaJson) s = NULL;
|
|
|
|
if (!conf) {
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
section = luaL_checkstring (L, 1);
|
|
if (lua_isuserdata (L, 2)) {
|
|
WpSpaJson *v = wplua_checkboxed (L, 2, WP_TYPE_SPA_JSON);
|
|
if (v)
|
|
fb = wp_spa_json_ref (v);
|
|
}
|
|
|
|
s = wp_conf_get_section (conf, section);
|
|
if (s)
|
|
wplua_pushboxed (L, WP_TYPE_SPA_JSON, g_steal_pointer (&s));
|
|
else if (fb)
|
|
wplua_pushboxed (L, WP_TYPE_SPA_JSON, g_steal_pointer (&fb));
|
|
else
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg conf_methods[] = {
|
|
{ "get_section", conf_get_section },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* JsonUtils */
|
|
|
|
static gboolean
|
|
json_utils_match_rules_cb (gpointer data, const gchar * action,
|
|
WpSpaJson * value, GError ** error)
|
|
{
|
|
lua_State *L = data;
|
|
g_autoptr (GError) pcall_err = NULL;
|
|
gboolean ret = TRUE;
|
|
int top = lua_gettop (L);
|
|
|
|
/* this callback is called within the context of json_utils_match_rules()
|
|
* and the Lua callback function is at the top of the stack at this point */
|
|
|
|
/* re-push the function because lua_call pops it; then, push arguments */
|
|
lua_pushvalue (L, -1);
|
|
lua_pushstring (L, action);
|
|
wplua_pushboxed (L, WP_TYPE_SPA_JSON, wp_spa_json_ref (value));
|
|
|
|
lua_call (L, 2, 2);
|
|
|
|
ret = lua_toboolean (L, -2);
|
|
if (!ret) {
|
|
g_set_error (error, WP_DOMAIN_LIBRARY, WP_LIBRARY_ERROR_OPERATION_FAILED,
|
|
"%s", lua_tostring (L, -1));
|
|
}
|
|
|
|
lua_settop (L, top);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
json_utils_match_rules (lua_State *L)
|
|
{
|
|
g_autoptr (WpProperties) properties = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
WpSpaJson *json;
|
|
gboolean res;
|
|
|
|
json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
luaL_checktype (L, 3, LUA_TFUNCTION);
|
|
|
|
properties = wplua_table_to_properties (L, 2);
|
|
|
|
res = wp_json_utils_match_rules (json, properties, json_utils_match_rules_cb,
|
|
L, &error);
|
|
|
|
lua_pushboolean (L, res);
|
|
if (error)
|
|
lua_pushstring (L, error->message);
|
|
else
|
|
lua_pushnil (L);
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
json_utils_match_rules_update_properties (lua_State *L)
|
|
{
|
|
g_autoptr (WpProperties) properties = NULL;
|
|
WpSpaJson *json;
|
|
int count;
|
|
|
|
json = wplua_checkboxed (L, 1, WP_TYPE_SPA_JSON);
|
|
luaL_checktype (L, 2, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, 2);
|
|
|
|
count = wp_json_utils_match_rules_update_properties (json, properties);
|
|
|
|
lua_pushinteger (L, count);
|
|
wplua_properties_to_table (L, properties);
|
|
return 2;
|
|
}
|
|
|
|
static const luaL_Reg json_utils_funcs[] = {
|
|
{ "match_rules", json_utils_match_rules },
|
|
{ "match_rules_update_properties", json_utils_match_rules_update_properties },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpSettings */
|
|
|
|
static int
|
|
settings_get (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s) {
|
|
WpSpaJson *j = wp_settings_get (s, setting);
|
|
if (j)
|
|
wplua_pushboxed (L, WP_TYPE_SPA_JSON, j);
|
|
else
|
|
lua_pushnil (L);
|
|
} else
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_boolean (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
gboolean val = FALSE;
|
|
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j)
|
|
wp_spa_json_parse_boolean (j, &val);
|
|
}
|
|
|
|
lua_pushboolean (L, val);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_int (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
gint val = 0;
|
|
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j)
|
|
wp_spa_json_parse_int (j, &val);
|
|
}
|
|
|
|
lua_pushinteger (L, val);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_float (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
float val = 0.0;
|
|
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j)
|
|
wp_spa_json_parse_float (j, &val);
|
|
}
|
|
|
|
lua_pushnumber (L, val);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_string (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j) {
|
|
g_autofree gchar *val = wp_spa_json_parse_string (j);
|
|
if (val) {
|
|
lua_pushstring (L, val);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
lua_pushstring (L, "");
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_array (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
g_autoptr (WpSpaJson) val = NULL;
|
|
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j && wp_spa_json_is_array (j)) {
|
|
push_luajson (L, j, INT_MAX);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
val = wp_spa_json_new_array (NULL, NULL);
|
|
push_luajson (L, val, INT_MAX);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_object (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
g_autoptr (WpSpaJson) val = NULL;
|
|
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j && wp_spa_json_is_object (j)) {
|
|
push_luajson (L, j, INT_MAX);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
val = wp_spa_json_new_object (NULL, NULL, NULL);
|
|
push_luajson (L, val, INT_MAX);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_get_saved (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s) {
|
|
WpSpaJson *j = wp_settings_get_saved (s, setting);
|
|
if (j)
|
|
wplua_pushboxed (L, WP_TYPE_SPA_JSON, j);
|
|
else
|
|
lua_pushnil (L);
|
|
} else
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_set (lua_State *L)
|
|
{
|
|
const char *key = luaL_checkstring (L, 1);
|
|
WpSpaJson *val = wplua_checkboxed (L, 2, WP_TYPE_SPA_JSON);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s) {
|
|
lua_pushboolean (L, wp_settings_set (s, key, val));
|
|
} else {
|
|
lua_pushboolean (L, FALSE);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_reset (lua_State *L)
|
|
{
|
|
const char *key = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s) {
|
|
lua_pushboolean (L, wp_settings_reset (s, key));
|
|
} else {
|
|
lua_pushboolean (L, FALSE);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_save (lua_State *L)
|
|
{
|
|
const char *key = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s) {
|
|
lua_pushboolean (L, wp_settings_save (s, key));
|
|
} else {
|
|
lua_pushboolean (L, FALSE);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_delete (lua_State *L)
|
|
{
|
|
const char *key = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s) {
|
|
lua_pushboolean (L, wp_settings_delete (s, key));
|
|
} else {
|
|
lua_pushboolean (L, FALSE);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_reset_all (lua_State *L)
|
|
{
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s)
|
|
wp_settings_reset_all (s);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
settings_save_all (lua_State *L)
|
|
{
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s)
|
|
wp_settings_save_all (s);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
settings_delete_all (lua_State *L)
|
|
{
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
if (s)
|
|
wp_settings_delete_all (s);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
settings_iterate (lua_State *L)
|
|
{
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
WpIterator *it = wp_settings_new_iterator (s);
|
|
return push_settings_wpiterator (L, it);
|
|
}
|
|
|
|
static int
|
|
settings_subscribe (lua_State *L)
|
|
{
|
|
const gchar *pattern = luaL_checkstring (L, 1);
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
|
|
guintptr sub_id = 0;
|
|
|
|
GClosure * closure = wplua_function_to_closure (L, -1);
|
|
|
|
if (s)
|
|
sub_id = wp_settings_subscribe_closure (s, pattern, closure);
|
|
|
|
lua_pushinteger (L, sub_id);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_unsubscribe (lua_State *L)
|
|
{
|
|
guintptr sub_id = luaL_checkinteger (L, 1);
|
|
gboolean ret = FALSE;
|
|
g_autoptr (WpSettings) s = wp_settings_find (get_wp_core (L), NULL);
|
|
|
|
if (s)
|
|
ret = wp_settings_unsubscribe (s, sub_id);
|
|
|
|
lua_pushboolean (L, ret);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg settings_methods[] = {
|
|
{ "get", settings_get },
|
|
{ "get_boolean", settings_get_boolean },
|
|
{ "get_int", settings_get_int },
|
|
{ "get_float", settings_get_float },
|
|
{ "get_string", settings_get_string },
|
|
{ "get_array", settings_get_array },
|
|
{ "get_object", settings_get_object },
|
|
{ "get_saved", settings_get_saved },
|
|
{ "set", settings_set },
|
|
{ "reset", settings_reset },
|
|
{ "save", settings_save },
|
|
{ "delete", settings_delete },
|
|
{ "reset_all", settings_reset_all },
|
|
{ "save_all", settings_save_all },
|
|
{ "delete_all", settings_delete_all },
|
|
{ "iterate", settings_iterate },
|
|
{ "subscribe", settings_subscribe },
|
|
{ "unsubscribe", settings_unsubscribe },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpEvent */
|
|
|
|
static int
|
|
event_get_properties (lua_State *L)
|
|
{
|
|
WpEvent *event = wplua_checkboxed (L, 1, WP_TYPE_EVENT);
|
|
g_autoptr (WpProperties) props = wp_event_get_properties (event);
|
|
wplua_properties_to_table (L, props);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
event_get_source (lua_State *L)
|
|
{
|
|
WpEvent *event = wplua_checkboxed (L, 1, WP_TYPE_EVENT);
|
|
wplua_pushobject (L, wp_event_get_source (event));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
event_get_subject (lua_State *L)
|
|
{
|
|
WpEvent *event = wplua_checkboxed (L, 1, WP_TYPE_EVENT);
|
|
wplua_pushobject (L, wp_event_get_subject (event));
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
event_stop_processing (lua_State *L)
|
|
{
|
|
WpEvent *event = wplua_checkboxed (L, 1, WP_TYPE_EVENT);
|
|
wp_event_stop_processing (event);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
event_set_data (lua_State *L)
|
|
{
|
|
WpEvent *event = wplua_checkboxed (L, 1, WP_TYPE_EVENT);
|
|
const gchar *key = luaL_checkstring (L, 2);
|
|
GType type = G_TYPE_INVALID;
|
|
g_auto (GValue) value = G_VALUE_INIT;
|
|
const GValue *data = NULL;
|
|
|
|
switch (lua_type (L, 3)) {
|
|
case LUA_TNONE:
|
|
case LUA_TNIL:
|
|
break;
|
|
case LUA_TUSERDATA:
|
|
type = wplua_gvalue_userdata_type (L, 3);
|
|
if (G_UNLIKELY (type == G_TYPE_INVALID))
|
|
wp_warning ("cannot set userdata on event data (not GValue userdata)");
|
|
break;
|
|
case LUA_TBOOLEAN:
|
|
type = G_TYPE_BOOLEAN;
|
|
break;
|
|
case LUA_TNUMBER:
|
|
type = lua_isinteger (L, 3) ? G_TYPE_INT64 : G_TYPE_DOUBLE;
|
|
break;
|
|
case LUA_TSTRING:
|
|
type = G_TYPE_STRING;
|
|
break;
|
|
case LUA_TTABLE:
|
|
type = WP_TYPE_PROPERTIES;
|
|
break;
|
|
default:
|
|
wp_warning ("cannot set value on event data (value type not supported)");
|
|
break;
|
|
}
|
|
|
|
if (type != G_TYPE_INVALID) {
|
|
g_value_init (&value, type);
|
|
wplua_lua_to_gvalue (L, 3, &value);
|
|
data = &value;
|
|
}
|
|
|
|
wp_event_set_data (event, key, data);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
event_get_data (lua_State *L)
|
|
{
|
|
WpEvent *event = wplua_checkboxed (L, 1, WP_TYPE_EVENT);
|
|
const gchar *key = luaL_checkstring (L, 2);
|
|
const GValue *data = wp_event_get_data (event, key);
|
|
if (data)
|
|
wplua_gvalue_to_lua (L, data);
|
|
else
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg event_methods[] = {
|
|
{ "get_properties", event_get_properties },
|
|
{ "get_source", event_get_source },
|
|
{ "get_subject", event_get_subject },
|
|
{ "stop_processing", event_stop_processing },
|
|
{ "set_data", event_set_data },
|
|
{ "get_data", event_get_data },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpEventDispatcher */
|
|
|
|
static int
|
|
event_dispatcher_push_event (lua_State *L)
|
|
{
|
|
const gchar *type = NULL;
|
|
gint priority = 0;
|
|
WpProperties *properties = NULL;
|
|
GObject *source = NULL;
|
|
GObject *subject = NULL;
|
|
WpEvent *event = NULL;
|
|
|
|
if (lua_type (L, 1) == LUA_TTABLE) {
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, 1) != LUA_TSTRING)
|
|
luaL_error (L, "EventDispatcher.push_event: expected 'type' as string");
|
|
type = lua_tostring (L, -1);
|
|
// not popping to keep the string allocated
|
|
|
|
lua_pushliteral (L, "priority");
|
|
if (lua_gettable (L, 1) != LUA_TNUMBER)
|
|
luaL_error (L, "EventDispatcher.push_event: expected 'priority' as number");
|
|
priority = lua_tointeger (L, -1);
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "properties");
|
|
if (lua_gettable (L, 1) != LUA_TNIL) {
|
|
luaL_checktype (L, -1, LUA_TTABLE);
|
|
properties = wplua_table_to_properties (L, -1);
|
|
}
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "source");
|
|
if (lua_gettable (L, 1) != LUA_TNIL)
|
|
source = wplua_checkobject (L, -1, G_TYPE_OBJECT);
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "subject");
|
|
if (lua_gettable (L, 1) != LUA_TNIL)
|
|
subject = wplua_checkobject (L, -1, G_TYPE_OBJECT);
|
|
lua_pop (L, 1);
|
|
|
|
event = wp_event_new (type, priority, properties, source, subject);
|
|
} else {
|
|
event = wp_event_ref (wplua_checkboxed (L, 1, WP_TYPE_EVENT));
|
|
}
|
|
|
|
g_autoptr (WpEventDispatcher) dispatcher =
|
|
wp_event_dispatcher_get_instance (get_wp_core (L));
|
|
wp_event_dispatcher_push_event (dispatcher, wp_event_ref (event));
|
|
wplua_pushboxed (L, WP_TYPE_EVENT, event);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg event_dispatcher_funcs[] = {
|
|
{ "push_event", event_dispatcher_push_event },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpEventHook */
|
|
|
|
static int
|
|
event_hook_register (lua_State *L)
|
|
{
|
|
WpEventHook *hook = wplua_checkobject (L, 1, WP_TYPE_EVENT_HOOK);
|
|
g_autoptr (WpEventDispatcher) dispatcher =
|
|
wp_event_dispatcher_get_instance (get_wp_core (L));
|
|
wp_event_dispatcher_register_hook (dispatcher, hook);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
event_hook_remove (lua_State *L)
|
|
{
|
|
WpEventHook *hook = wplua_checkobject (L, 1, WP_TYPE_EVENT_HOOK);
|
|
g_autoptr (WpEventDispatcher) dispatcher =
|
|
wp_event_dispatcher_get_instance (get_wp_core (L));
|
|
wp_event_dispatcher_unregister_hook (dispatcher, hook);
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg event_hook_methods[] = {
|
|
{ "register", event_hook_register },
|
|
{ "remove", event_hook_remove },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpSimpleEventHook */
|
|
|
|
static int
|
|
simple_event_hook_new (lua_State *L)
|
|
{
|
|
WpEventHook *hook = NULL;
|
|
int before_size = 0, after_size = 0, i = 0;
|
|
const gchar **before, **after;
|
|
const gchar *name;
|
|
GClosure *closure = NULL;
|
|
|
|
/* discard any possible arguments after the first one to avoid
|
|
any surprises when working with absolute stack indices below */
|
|
lua_settop (L, 1);
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 1, LUA_TTABLE);
|
|
|
|
if (lua_getfield (L, 1, "name") != LUA_TSTRING)
|
|
luaL_error(L, "SimpleEventHook: expected 'name' as string");
|
|
|
|
if (lua_getfield (L, 1, "execute") != LUA_TFUNCTION)
|
|
luaL_error (L, "SimpleEventHook: expected 'execute' as function");
|
|
|
|
switch (lua_getfield (L, 1, "before")) {
|
|
case LUA_TTABLE:
|
|
lua_len (L, -1);
|
|
before_size = lua_tointeger (L, -1);
|
|
lua_pop (L, 1);
|
|
break;
|
|
case LUA_TSTRING:
|
|
before_size = 1;
|
|
break;
|
|
case LUA_TNIL:
|
|
before_size = 0;
|
|
break;
|
|
default:
|
|
luaL_error(L, "SimpleEventHook: unexpected value type for 'before'; "
|
|
"should be table or string");
|
|
}
|
|
|
|
switch (lua_getfield (L, 1, "after")) {
|
|
case LUA_TTABLE:
|
|
lua_len (L, -1);
|
|
after_size = lua_tointeger (L, -1);
|
|
lua_pop (L, 1);
|
|
break;
|
|
case LUA_TSTRING:
|
|
after_size = 1;
|
|
break;
|
|
case LUA_TNIL:
|
|
after_size = 0;
|
|
break;
|
|
default:
|
|
luaL_error(L, "SimpleEventHook: unexpected value type for 'after'; "
|
|
"should be table or string");
|
|
}
|
|
|
|
/* allocate C stack space for before & after arrays */
|
|
before = before_size > 0 ?
|
|
(const gchar **) g_newa (gpointer, before_size + 1) : NULL;
|
|
after = after_size > 0 ?
|
|
(const gchar **) g_newa (gpointer, after_size + 1) : NULL;
|
|
|
|
/* parse before */
|
|
if (lua_type (L, 4) == LUA_TTABLE && before_size > 0) {
|
|
i = 0;
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 4) && i < before_size) {
|
|
before[i++] = luaL_checkstring (L, -1);
|
|
/* bring the key on top without popping the string value */
|
|
lua_rotate (L, lua_gettop (L) - 1, 1);
|
|
}
|
|
before[i] = NULL;
|
|
} else if (lua_type (L, 4) == LUA_TSTRING) {
|
|
before[0] = lua_tostring (L, 4);
|
|
before[1] = NULL;
|
|
}
|
|
|
|
/* parse after */
|
|
if (lua_type (L, 5) == LUA_TTABLE && after_size > 0) {
|
|
i = 0;
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 5) && i < after_size) {
|
|
after[i++] = luaL_checkstring (L, -1);
|
|
/* bring the key on top without popping the string value */
|
|
lua_rotate (L, lua_gettop (L) - 1, 1);
|
|
}
|
|
after[i] = NULL;
|
|
} else if (lua_type (L, 5) == LUA_TSTRING) {
|
|
after[0] = lua_tostring (L, 5);
|
|
after[1] = NULL;
|
|
}
|
|
|
|
name = lua_tostring (L, 2);
|
|
closure = wplua_function_to_closure (L, 3);
|
|
|
|
hook = wp_simple_event_hook_new (name, before, after, closure);
|
|
|
|
/* clear the lua stack now to make some space */
|
|
lua_settop (L, 1);
|
|
|
|
wplua_pushobject (L, hook);
|
|
|
|
if (lua_getfield (L, 1, "interests") == LUA_TTABLE) {
|
|
lua_pushnil (L);
|
|
while (lua_next (L, -2)) {
|
|
WpObjectInterest *interest =
|
|
wplua_checkboxed (L, -1, WP_TYPE_OBJECT_INTEREST);
|
|
wp_interest_event_hook_add_interest_full (WP_INTEREST_EVENT_HOOK (hook),
|
|
wp_object_interest_ref (interest));
|
|
lua_pop (L, 1);
|
|
}
|
|
}
|
|
lua_pop (L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* WpAsyncEventHook */
|
|
|
|
static int
|
|
async_event_hook_get_next_step (lua_State *L)
|
|
{
|
|
WpTransition *transition = wplua_checkobject (L, 1, WP_TYPE_TRANSITION);
|
|
guint step = luaL_checkinteger (L, 2);
|
|
|
|
wp_trace_object (transition, "prev step: %u", step);
|
|
|
|
if (step == WP_TRANSITION_STEP_NONE) {
|
|
lua_pushinteger (L, WP_TRANSITION_STEP_CUSTOM_START);
|
|
return 1;
|
|
}
|
|
|
|
/* step number is the value on the stack at this point */
|
|
if (G_UNLIKELY (lua_gettable (L, lua_upvalueindex (1)) != LUA_TSTRING)) {
|
|
wp_critical_object (transition, "unknown step number");
|
|
lua_pushinteger (L, WP_TRANSITION_STEP_ERROR);
|
|
return 1;
|
|
}
|
|
/* step string is now on the stack */
|
|
if (G_UNLIKELY (lua_gettable (L, lua_upvalueindex (1)) != LUA_TTABLE)) {
|
|
wp_critical_object (transition, "unknown step string");
|
|
lua_pushinteger (L, WP_TRANSITION_STEP_ERROR);
|
|
return 1;
|
|
}
|
|
lua_pushliteral (L, "next_idx");
|
|
if (G_UNLIKELY (lua_gettable (L, -2) != LUA_TNUMBER)) {
|
|
wp_critical_object (transition, "next_idx not found");
|
|
lua_pushinteger (L, WP_TRANSITION_STEP_ERROR);
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
async_event_hook_execute_step (lua_State *L)
|
|
{
|
|
WpTransition *transition = wplua_checkobject (L, 1, WP_TYPE_TRANSITION);
|
|
WpEvent *event = wp_transition_get_data (transition);
|
|
guint step = luaL_checkinteger (L, 2);
|
|
const char *step_str = NULL;
|
|
|
|
wp_trace_object (transition, "execute step: %u", step);
|
|
|
|
if (G_LIKELY (step != WP_TRANSITION_STEP_ERROR)) {
|
|
/* step_str = steps_table[step_number] */
|
|
/* step number is the value on the stack at this point */
|
|
if (G_UNLIKELY (lua_gettable (L, lua_upvalueindex (1)) != LUA_TSTRING)) {
|
|
wp_critical_object (transition, "unknown step number %u", step);
|
|
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
|
WP_LIBRARY_ERROR_INVARIANT, "unknown step number %u", step));
|
|
return 0;
|
|
}
|
|
} else {
|
|
/* try to execute a step called "error", if it exists */
|
|
lua_pushliteral (L, "error");
|
|
}
|
|
step_str = lua_tostring (L, -1);
|
|
|
|
/* step string is now on the stack */
|
|
if (G_UNLIKELY (lua_gettable (L, lua_upvalueindex (1)) != LUA_TTABLE)) {
|
|
/* it's ok if the "error" step is missing */
|
|
if (step != WP_TRANSITION_STEP_ERROR) {
|
|
wp_critical_object (transition, "unknown step string '%s'", step_str);
|
|
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
|
WP_LIBRARY_ERROR_INVARIANT, "unknown step string '%s", step_str));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
lua_pushliteral (L, "execute");
|
|
if (G_UNLIKELY (lua_gettable (L, -2) != LUA_TFUNCTION)) {
|
|
wp_critical_object (transition, "no execute function defined for '%s'",
|
|
step_str);
|
|
wp_transition_return_error (transition, g_error_new (WP_DOMAIN_LIBRARY,
|
|
WP_LIBRARY_ERROR_INVARIANT, "no execute function defined for '%s'",
|
|
step_str));
|
|
return 0;
|
|
}
|
|
|
|
wplua_pushboxed (L, WP_TYPE_EVENT, wp_event_ref (event));
|
|
wplua_pushobject (L, g_object_ref (transition));
|
|
lua_call (L, 2, 0);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
async_event_hook_prepare_steps_table (lua_State *L, int steps_tbl)
|
|
{
|
|
const char *step_str = NULL;
|
|
int step_str_index = 0;
|
|
int step = WP_TRANSITION_STEP_CUSTOM_START;
|
|
|
|
steps_tbl = lua_absindex (L, steps_tbl);
|
|
|
|
lua_pushliteral (L, "start");
|
|
step_str_index = lua_absindex (L, -1);
|
|
step_str = lua_tostring (L, -1);
|
|
|
|
while (step != WP_TRANSITION_STEP_NONE) {
|
|
/* steps[step number] = step string */
|
|
lua_pushvalue (L, -1);
|
|
lua_seti (L, steps_tbl, step);
|
|
|
|
lua_pushvalue (L, -1);
|
|
if (lua_gettable (L, steps_tbl) != LUA_TTABLE)
|
|
luaL_error (L, "AsyncEventHook: expected '%s' in 'steps'", step_str);
|
|
|
|
lua_pushinteger (L, step++);
|
|
lua_setfield (L, -2, "idx");
|
|
|
|
lua_pushliteral (L, "next");
|
|
if (lua_gettable (L, -2) != LUA_TSTRING)
|
|
luaL_error (L, "AsyncEventHook: expected 'next' in step '%s'", step_str);
|
|
lua_replace (L, step_str_index);
|
|
step_str = lua_tostring (L, step_str_index);
|
|
|
|
if (!g_strcmp0 (step_str, "none"))
|
|
step = WP_TRANSITION_STEP_NONE;
|
|
|
|
lua_pushinteger (L, step);
|
|
lua_setfield (L, -2, "next_idx");
|
|
|
|
lua_settop (L, step_str_index);
|
|
}
|
|
|
|
lua_pop (L, 1);
|
|
}
|
|
|
|
static int
|
|
async_event_hook_new (lua_State *L)
|
|
{
|
|
WpEventHook *hook = NULL;
|
|
int before_size = 0, after_size = 0, i = 0;
|
|
const gchar **before, **after;
|
|
const gchar *name;
|
|
GClosure *get_next_step = NULL;
|
|
GClosure *execute_step = NULL;
|
|
|
|
/* discard any possible arguments after the first one to avoid
|
|
any surprises when working with absolute stack indices below */
|
|
lua_settop (L, 1);
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 1, LUA_TTABLE);
|
|
|
|
if (lua_getfield (L, 1, "name") != LUA_TSTRING)
|
|
luaL_error(L, "AsyncEventHook: expected 'name' as string");
|
|
|
|
if (lua_getfield (L, 1, "steps") != LUA_TTABLE)
|
|
luaL_error (L, "AsyncEventHook: expected 'steps' as table");
|
|
|
|
switch (lua_getfield (L, 1, "before")) {
|
|
case LUA_TTABLE:
|
|
lua_len (L, -1);
|
|
before_size = lua_tointeger (L, -1);
|
|
lua_pop (L, 1);
|
|
break;
|
|
case LUA_TSTRING:
|
|
before_size = 1;
|
|
break;
|
|
case LUA_TNIL:
|
|
before_size = 0;
|
|
break;
|
|
default:
|
|
luaL_error(L, "AsyncEventHook: unexpected value type for 'before'; "
|
|
"should be table or string");
|
|
}
|
|
|
|
switch (lua_getfield (L, 1, "after")) {
|
|
case LUA_TTABLE:
|
|
lua_len (L, -1);
|
|
after_size = lua_tointeger (L, -1);
|
|
lua_pop (L, 1);
|
|
break;
|
|
case LUA_TSTRING:
|
|
after_size = 1;
|
|
break;
|
|
case LUA_TNIL:
|
|
after_size = 0;
|
|
break;
|
|
default:
|
|
luaL_error(L, "AsyncEventHook: unexpected value type for 'after'; "
|
|
"should be table or string");
|
|
}
|
|
|
|
/* allocate C stack space for before & after arrays */
|
|
before = before_size > 0 ?
|
|
(const gchar **) g_newa (gpointer, before_size + 1) : NULL;
|
|
after = after_size > 0 ?
|
|
(const gchar **) g_newa (gpointer, after_size + 1) : NULL;
|
|
|
|
/* parse before */
|
|
if (lua_type (L, 4) == LUA_TTABLE && before_size > 0) {
|
|
i = 0;
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 4) && i < before_size) {
|
|
before[i++] = luaL_checkstring (L, -1);
|
|
/* bring the key on top without popping the string value */
|
|
lua_rotate (L, lua_gettop (L) - 1, 1);
|
|
}
|
|
before[i] = NULL;
|
|
} else if (lua_type (L, 4) == LUA_TSTRING) {
|
|
before[0] = lua_tostring (L, 4);
|
|
before[1] = NULL;
|
|
}
|
|
|
|
/* parse after */
|
|
if (lua_type (L, 5) == LUA_TTABLE && after_size > 0) {
|
|
i = 0;
|
|
lua_pushnil (L);
|
|
while (lua_next (L, 5) && i < after_size) {
|
|
after[i++] = luaL_checkstring (L, -1);
|
|
/* bring the key on top without popping the string value */
|
|
lua_rotate (L, lua_gettop (L) - 1, 1);
|
|
}
|
|
after[i] = NULL;
|
|
} else if (lua_type (L, 5) == LUA_TSTRING) {
|
|
after[0] = lua_tostring (L, 5);
|
|
after[1] = NULL;
|
|
}
|
|
|
|
name = lua_tostring (L, 2);
|
|
async_event_hook_prepare_steps_table (L, 3);
|
|
|
|
lua_pushvalue (L, 3); /* pass 'steps' table as upvalue */
|
|
lua_pushcclosure (L, async_event_hook_get_next_step, 1);
|
|
get_next_step = wplua_function_to_closure (L, -1);
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushvalue (L, 3); /* pass 'steps' table as upvalue */
|
|
lua_pushcclosure (L, async_event_hook_execute_step, 1);
|
|
execute_step = wplua_function_to_closure (L, -1);
|
|
lua_pop (L, 1);
|
|
|
|
hook = wp_async_event_hook_new (name, before, after, get_next_step,
|
|
execute_step);
|
|
|
|
/* clear the lua stack now to make some space */
|
|
lua_settop (L, 1);
|
|
|
|
wplua_pushobject (L, hook);
|
|
|
|
if (lua_getfield (L, 1, "interests") == LUA_TTABLE) {
|
|
lua_pushnil (L);
|
|
while (lua_next (L, -2)) {
|
|
WpObjectInterest *interest =
|
|
wplua_checkboxed (L, -1, WP_TYPE_OBJECT_INTEREST);
|
|
wp_interest_event_hook_add_interest_full (WP_INTEREST_EVENT_HOOK (hook),
|
|
wp_object_interest_ref (interest));
|
|
lua_pop (L, 1);
|
|
}
|
|
}
|
|
lua_pop (L, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
transition_advance (lua_State *L)
|
|
{
|
|
WpTransition *t = wplua_checkobject (L, 1, WP_TYPE_TRANSITION);
|
|
wp_transition_advance (t);
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
transition_return_error (lua_State *L)
|
|
{
|
|
WpTransition *t = wplua_checkobject (L, 1, WP_TYPE_TRANSITION);
|
|
const char *err = luaL_checkstring (L, 2);
|
|
wp_transition_return_error (t, g_error_new (WP_DOMAIN_LIBRARY,
|
|
WP_LIBRARY_ERROR_OPERATION_FAILED, "%s", err));
|
|
return 0;
|
|
}
|
|
|
|
static const luaL_Reg transition_methods[] = {
|
|
{ "advance", transition_advance },
|
|
{ "return_error", transition_return_error },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
void
|
|
wp_lua_scripting_api_init (lua_State *L)
|
|
{
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
luaL_newlib (L, glib_methods);
|
|
lua_setglobal (L, "GLib");
|
|
|
|
luaL_newlib (L, i18n_funcs);
|
|
lua_setglobal (L, "I18n");
|
|
|
|
luaL_newlib (L, log_funcs);
|
|
lua_setglobal (L, "WpLog");
|
|
|
|
luaL_newlib (L, core_funcs);
|
|
lua_setglobal (L, "WpCore");
|
|
|
|
luaL_newlib (L, plugin_funcs);
|
|
lua_setglobal (L, "WpPlugin");
|
|
|
|
luaL_newlib (L, conf_methods);
|
|
lua_setglobal (L, "WpConf");
|
|
|
|
luaL_newlib (L, json_utils_funcs);
|
|
lua_setglobal (L, "JsonUtils");
|
|
|
|
luaL_newlib (L, settings_methods);
|
|
lua_setglobal (L, "WpSettings");
|
|
|
|
luaL_newlib (L, event_dispatcher_funcs);
|
|
lua_setglobal (L, "WpEventDispatcher");
|
|
|
|
wp_lua_scripting_pod_init (L);
|
|
wp_lua_scripting_json_init (L);
|
|
|
|
wplua_register_type_methods (L, G_TYPE_SOURCE,
|
|
NULL, source_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_OBJECT,
|
|
NULL, object_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_PROXY,
|
|
NULL, proxy_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_GLOBAL_PROXY,
|
|
NULL, global_proxy_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_OBJECT_INTEREST,
|
|
object_interest_new, object_interest_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_OBJECT_MANAGER,
|
|
object_manager_new, object_manager_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_METADATA,
|
|
NULL, metadata_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_IMPL_METADATA,
|
|
impl_metadata_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_DEVICE,
|
|
device_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_SPA_DEVICE,
|
|
spa_device_new, spa_device_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_NODE,
|
|
node_new, node_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_IMPL_NODE,
|
|
impl_node_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_PORT,
|
|
NULL, port_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_LINK,
|
|
link_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_CLIENT,
|
|
NULL, client_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_SESSION_ITEM,
|
|
session_item_new, session_item_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_SI_ADAPTER,
|
|
NULL, si_adapter_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_PIPEWIRE_OBJECT,
|
|
NULL, pipewire_object_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_STATE,
|
|
state_new, state_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_IMPL_MODULE,
|
|
impl_module_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_EVENT,
|
|
NULL, event_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_EVENT_HOOK,
|
|
NULL, event_hook_methods);
|
|
wplua_register_type_methods (L, WP_TYPE_SIMPLE_EVENT_HOOK,
|
|
simple_event_hook_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_ASYNC_EVENT_HOOK,
|
|
async_event_hook_new, NULL);
|
|
wplua_register_type_methods (L, WP_TYPE_TRANSITION,
|
|
NULL, transition_methods);
|
|
|
|
if (!wplua_load_uri (L, URI_API, &error) ||
|
|
!wplua_pcall (L, 0, 0, &error)) {
|
|
wp_critical ("Failed to load api: %s", error->message);
|
|
}
|
|
}
|