
Hooks need to have a priority relative to the event they are executed on, so it does not make much sense to have all kinds of different priorities based also on the event type and/or the module where they are defined. Also, it wouldn't be acceptable to have such an enumeration on the public API.
2217 lines
57 KiB
C
2217 lines
57 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 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);
|
|
|
|
/* 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 = NULL;
|
|
lua_pushliteral (L, "wireplumber_export_core");
|
|
lua_gettable (L, LUA_REGISTRYINDEX);
|
|
if (wplua_isobject (L, -1, WP_TYPE_CORE))
|
|
core = wplua_toobject (L, -1);
|
|
lua_pop (L, 1);
|
|
return core ? core : get_wp_core(L);
|
|
}
|
|
|
|
/* 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_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_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 const luaL_Reg core_funcs[] = {
|
|
{ "get_info", core_get_info },
|
|
{ "get_vm_type", core_get_vm_type },
|
|
{ "idle_add", core_idle_add },
|
|
{ "timeout_add", core_timeout_add },
|
|
{ "sync", core_sync },
|
|
{ "quit", core_quit },
|
|
{ "require_api", core_require_api },
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* WpLog */
|
|
|
|
static int
|
|
log_log (lua_State *L, GLogLevelFlags lvl)
|
|
{
|
|
lua_Debug ar = {0};
|
|
const gchar *message, *tmp;
|
|
gchar domain[25];
|
|
gchar line_str[11];
|
|
gconstpointer instance = NULL;
|
|
GType type = G_TYPE_INVALID;
|
|
int index = 1;
|
|
|
|
if (!wp_log_level_is_enabled (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, 1, G_TYPE_OBJECT)) {
|
|
instance = wplua_toobject (L, 1);
|
|
type = G_TYPE_FROM_INSTANCE (instance);
|
|
index++;
|
|
}
|
|
else if (wplua_isboxed (L, 1, G_TYPE_BOXED)) {
|
|
instance = wplua_toboxed (L, 1);
|
|
type = wplua_gvalue_userdata_type (L, 1);
|
|
index++;
|
|
}
|
|
|
|
message = luaL_checkstring (L, index);
|
|
tmp = ar.source ? g_strrstr (ar.source, ".lua") : NULL;
|
|
snprintf (domain, 25, "script/%.*s",
|
|
tmp ? MIN((gint)(tmp - ar.source), 17) : 17,
|
|
ar.source);
|
|
snprintf (line_str, 11, "%d", ar.currentline);
|
|
ar.name = ar.name ? ar.name : "chunk";
|
|
|
|
wp_log_structured_standard (domain, 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_message (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_funcs[] = {
|
|
{ "warning", log_warning },
|
|
{ "message", log_message },
|
|
{ "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_message_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;
|
|
}
|
|
|
|
/* 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)) {
|
|
guint32 s = 0;
|
|
const gchar *k = NULL, *t = NULL, *v = NULL;
|
|
wp_metadata_iterator_item_extract (&item, &s, &k, &t, &v);
|
|
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) {
|
|
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;
|
|
}
|
|
|
|
/* WpEndpoint */
|
|
|
|
static const luaL_Reg endpoint_methods[] = {
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
/* 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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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) {
|
|
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 '-': 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_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 },
|
|
{ "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_message_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_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 },
|
|
{ "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;
|
|
}
|
|
}
|
|
|
|
static int
|
|
settings_get (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const char *m = NULL;
|
|
|
|
if (lua_type (L, 2) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 2);
|
|
|
|
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L), m);
|
|
|
|
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_parse_boolean_safe (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const gboolean v = lua_toboolean (L, 2) ? TRUE : FALSE;
|
|
const char *m = NULL;
|
|
g_autoptr (WpSettings) s = NULL;
|
|
|
|
if (lua_type (L, 3) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 3);
|
|
|
|
s = wp_settings_get_instance (get_wp_core (L), m);
|
|
if (s)
|
|
lua_pushboolean (L, wp_settings_parse_boolean_safe (s, setting, v));
|
|
else
|
|
lua_pushboolean (L, v);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_parse_int_safe (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const gint v = luaL_checkinteger (L, 2);
|
|
const char *m = NULL;
|
|
g_autoptr (WpSettings) s = NULL;
|
|
|
|
if (lua_type (L, 3) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 3);
|
|
|
|
s = wp_settings_get_instance (get_wp_core (L), m);
|
|
if (s)
|
|
lua_pushinteger (L, wp_settings_parse_int_safe (s, setting, v));
|
|
else
|
|
lua_pushinteger (L, v);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_parse_float_safe (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const float v = lua_tonumber (L, 2);
|
|
const char *m = NULL;
|
|
g_autoptr (WpSettings) s = NULL;
|
|
|
|
if (lua_type (L, 3) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 3);
|
|
|
|
s = wp_settings_get_instance (get_wp_core (L), m);
|
|
if (s)
|
|
lua_pushnumber (L, wp_settings_parse_float_safe (s, setting, v));
|
|
else
|
|
lua_pushnumber (L, v);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_parse_string_safe (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const char *v = luaL_checkstring (L, 2);
|
|
const char *m = NULL;
|
|
g_autoptr (WpSettings) s = NULL;
|
|
g_autofree gchar *res = NULL;
|
|
|
|
if (lua_type (L, 3) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 3);
|
|
|
|
s = wp_settings_get_instance (get_wp_core (L), m);
|
|
res = s ? wp_settings_parse_string_safe (s, setting, v) : g_strdup (v);
|
|
lua_pushstring (L, res);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_parse_array_safe (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const char *m = NULL;
|
|
g_autoptr (WpSettings) s = NULL;
|
|
g_autoptr (WpSpaJson) json_default = NULL;
|
|
|
|
if (lua_isuserdata (L, 2)) {
|
|
WpSpaJson *v = wplua_checkboxed (L, 2, WP_TYPE_SPA_JSON);
|
|
if (v && wp_spa_json_is_array (v))
|
|
json_default = wp_spa_json_ref (v);
|
|
}
|
|
if (!json_default) {
|
|
wp_warning ("Using empty array for setting '%s' as fallback value isn't "
|
|
"a JSON array", setting);
|
|
json_default = wp_spa_json_new_array (NULL, NULL);
|
|
}
|
|
|
|
if (lua_type (L, 3) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 3);
|
|
|
|
s = wp_settings_get_instance (get_wp_core (L), m);
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j) {
|
|
if (wp_spa_json_is_array (j)) {
|
|
push_luajson (L, j);
|
|
return 1;
|
|
} else {
|
|
wp_warning ("Ignoring setting '%s' as it isn't a JSON array", setting);
|
|
}
|
|
}
|
|
}
|
|
|
|
push_luajson (L, json_default);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_parse_object_safe (lua_State *L)
|
|
{
|
|
const char *setting = luaL_checkstring (L, 1);
|
|
const char *m = NULL;
|
|
g_autoptr (WpSettings) s = NULL;
|
|
g_autoptr (WpSpaJson) json_default = NULL;
|
|
|
|
if (lua_isuserdata (L, 2)) {
|
|
WpSpaJson *v = wplua_checkboxed (L, 2, WP_TYPE_SPA_JSON);
|
|
if (v && wp_spa_json_is_object (v))
|
|
json_default = wp_spa_json_ref (v);
|
|
}
|
|
if (!json_default) {
|
|
wp_warning ("Using empty object for setting '%s' as fallback value isn't "
|
|
"a JSON object", setting);
|
|
json_default = wp_spa_json_new_array (NULL, NULL);
|
|
}
|
|
|
|
if (lua_type (L, 3) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 3);
|
|
|
|
s = wp_settings_get_instance (get_wp_core (L), m);
|
|
if (s) {
|
|
g_autoptr (WpSpaJson) j = wp_settings_get (s, setting);
|
|
if (j) {
|
|
if (wp_spa_json_is_object (j)) {
|
|
push_luajson (L, j);
|
|
return 1;
|
|
} else {
|
|
wp_warning ("Ignoring setting '%s' as it isn't a JSON object", setting);
|
|
}
|
|
}
|
|
}
|
|
|
|
push_luajson (L, json_default);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_apply_rule (lua_State *L)
|
|
{
|
|
const char *r = luaL_checkstring (L, 1);
|
|
const char *m = NULL;
|
|
g_autoptr (WpProperties) cp = wplua_table_to_properties (L, 2);
|
|
g_autoptr (WpProperties) ap = wp_properties_new_empty ();
|
|
|
|
if (lua_type (L, -1) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, -1);
|
|
|
|
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L), m);
|
|
|
|
if (s) {
|
|
gboolean value = wp_settings_apply_rule (s, r, cp, ap);
|
|
lua_pushboolean (L, value);
|
|
wplua_properties_to_table (L, ap);
|
|
return 2;
|
|
}
|
|
|
|
lua_pushnil (L);
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
settings_subscribe (lua_State *L)
|
|
{
|
|
const gchar *pattern = luaL_checkstring (L, 1);
|
|
const gchar *m = NULL;
|
|
guintptr sub_id = 0;
|
|
|
|
GClosure * closure = wplua_function_to_closure (L, -1);
|
|
|
|
if (lua_type (L, 2) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 2);
|
|
|
|
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L), m);
|
|
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);
|
|
const gchar *m = NULL;
|
|
gboolean ret = FALSE;
|
|
if (lua_type (L, 2) == LUA_TSTRING)
|
|
m = luaL_checkstring (L, 2);
|
|
|
|
g_autoptr (WpSettings) s = wp_settings_get_instance (get_wp_core (L), m);
|
|
if (s)
|
|
ret = wp_settings_unsubscribe (s, sub_id);
|
|
|
|
lua_pushboolean (L, ret);
|
|
return 1;
|
|
}
|
|
|
|
static const luaL_Reg settings_methods[] = {
|
|
{ "get", settings_get },
|
|
{ "parse_boolean_safe", settings_parse_boolean_safe },
|
|
{ "parse_int_safe", settings_parse_int_safe },
|
|
{ "parse_float_safe", settings_parse_float_safe },
|
|
{ "parse_string_safe", settings_parse_string_safe },
|
|
{ "parse_array_safe", settings_parse_array_safe },
|
|
{ "parse_object_safe", settings_parse_object_safe },
|
|
{ "apply_rule", settings_apply_rule },
|
|
{ "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 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 },
|
|
{ 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;
|
|
|
|
luaL_checktype (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);
|
|
|
|
g_autoptr (WpEventDispatcher) dispatcher =
|
|
wp_event_dispatcher_get_instance (get_wp_core (L));
|
|
WpEvent *event = wp_event_new (type, priority, properties, source, subject);
|
|
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;
|
|
gint priority = 0;
|
|
gint priority_type = 0;
|
|
const gchar *name;
|
|
WpEventHookExecType type = 0;
|
|
GClosure *closure = NULL;
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 1, LUA_TTABLE);
|
|
|
|
lua_pushliteral (L, "name");
|
|
if (lua_gettable (L, 1) != LUA_TSTRING)
|
|
luaL_error(L, "SimpleEventHook: expected 'name' as string");
|
|
name = lua_tostring (L, -1);
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "priority");
|
|
priority_type = lua_gettable (L, 1);
|
|
if (priority_type == LUA_TNUMBER)
|
|
priority = lua_tointeger (L, -1);
|
|
else
|
|
luaL_error (L, "SimpleEventHook: expected 'priority' as number");
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, 1) == LUA_TSTRING)
|
|
type = wplua_lua_to_enum (L, -1, WP_TYPE_EVENT_HOOK_EXEC_TYPE);
|
|
else
|
|
luaL_error (L, "SimpleEventHook: expected 'type' as string");
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "execute");
|
|
if (lua_gettable (L, 1) == LUA_TFUNCTION)
|
|
closure = wplua_function_to_closure (L, -1);
|
|
else
|
|
luaL_error (L, "SimpleEventHook: expected 'execute' as function");
|
|
lua_pop (L, 1);
|
|
|
|
hook = wp_simple_event_hook_new (name, priority, type, closure);
|
|
wplua_pushobject (L, hook);
|
|
|
|
lua_pushliteral (L, "interests");
|
|
if (lua_gettable (L, 1) == 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);
|
|
|
|
/* 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;
|
|
}
|
|
step_str = lua_tostring (L, -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 '%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;
|
|
const gchar *name;
|
|
gint priority = 0;
|
|
gint priority_type = 0;
|
|
WpEventHookExecType type = 0;
|
|
GClosure *get_next_step = NULL;
|
|
GClosure *execute_step = NULL;
|
|
|
|
/* validate arguments */
|
|
luaL_checktype (L, 1, LUA_TTABLE);
|
|
|
|
lua_pushliteral (L, "name");
|
|
if (lua_gettable (L, 1) != LUA_TSTRING)
|
|
luaL_error (L, "AsyncEventHook: expected 'name' as string");
|
|
name = lua_tostring (L, -1);
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "priority");
|
|
priority_type = lua_gettable(L, 1);
|
|
if (priority_type == LUA_TNUMBER)
|
|
priority = lua_tointeger (L, -1);
|
|
else
|
|
luaL_error(L, "AsyncEventHook: expected 'priority' as number");
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "type");
|
|
if (lua_gettable (L, 1) != LUA_TSTRING)
|
|
luaL_error (L, "AsyncEventHook: expected 'type' as string");
|
|
type = wplua_lua_to_enum (L, -1, WP_TYPE_EVENT_HOOK_EXEC_TYPE);
|
|
lua_pop (L, 1);
|
|
|
|
lua_pushliteral (L, "steps");
|
|
if (lua_gettable (L, 1) != LUA_TTABLE)
|
|
luaL_error (L, "AsyncEventHook: expected 'steps' as table");
|
|
|
|
async_event_hook_prepare_steps_table (L, -1);
|
|
|
|
lua_pushvalue (L, -1);
|
|
lua_pushcclosure (L, async_event_hook_get_next_step, 1);
|
|
get_next_step = wplua_function_to_closure (L, -1);
|
|
lua_pop (L, 1);
|
|
|
|
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, priority, type, get_next_step,
|
|
execute_step);
|
|
wplua_pushobject (L, hook);
|
|
|
|
lua_pushliteral (L, "interests");
|
|
if (lua_gettable (L, 1) == 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, 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_ENDPOINT,
|
|
NULL, endpoint_methods);
|
|
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);
|
|
}
|
|
}
|