wplua: move under modules/module-lua-scripting
It's unlikely that wplua will ever be useful outside the context of module-lua-scripting, so let's move it to keep all the code in one place
This commit is contained in:
246
modules/module-lua-scripting/wplua/object.c
Normal file
246
modules/module-lua-scripting/wplua/object.c
Normal file
@@ -0,0 +1,246 @@
|
||||
/* WirePlumber
|
||||
*
|
||||
* Copyright © 2020 Collabora Ltd.
|
||||
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "wplua.h"
|
||||
#include "private.h"
|
||||
#include <wp/wp.h>
|
||||
|
||||
static int
|
||||
_wplua_gobject_call (lua_State *L)
|
||||
{
|
||||
GObject *obj = wplua_checkobject (L, 1, G_TYPE_OBJECT);
|
||||
const char *sig_name = lua_tostring (L, 2);
|
||||
guint n_params = lua_gettop (L) - 2;
|
||||
GSignalQuery query;
|
||||
guint sig_id = 0;
|
||||
GQuark detail = 0;
|
||||
|
||||
if (G_UNLIKELY (!g_signal_parse_name (sig_name, G_TYPE_FROM_INSTANCE (obj),
|
||||
&sig_id, &detail, FALSE)))
|
||||
luaL_error (L, "unknown signal '%s::%s'", G_OBJECT_TYPE_NAME (obj),
|
||||
sig_name);
|
||||
|
||||
g_signal_query (sig_id, &query);
|
||||
|
||||
if (G_UNLIKELY (!(query.signal_flags & G_SIGNAL_ACTION)))
|
||||
luaL_error (L, "lua code is not allowed to emit non-action signal '%s::%s'",
|
||||
G_OBJECT_TYPE_NAME (obj), sig_name);
|
||||
|
||||
if (G_UNLIKELY (query.n_params > n_params))
|
||||
luaL_error (L, "not enough arguments for '%s::%s': expected %d, got %d",
|
||||
G_OBJECT_TYPE_NAME (obj), sig_name, query.n_params, n_params);
|
||||
|
||||
GValue ret = G_VALUE_INIT;
|
||||
GValue *vals = g_newa (GValue, n_params + 1);
|
||||
memset (vals, 0, sizeof (GValue) * (n_params + 1));
|
||||
|
||||
if (query.return_type != G_TYPE_NONE)
|
||||
g_value_init (&ret, query.return_type);
|
||||
|
||||
g_value_init_from_instance (&vals[0], obj);
|
||||
for (guint i = 0; i < n_params; i++) {
|
||||
g_value_init (&vals[i+1], query.param_types[i]);
|
||||
wplua_lua_to_gvalue (L, i+3, &vals[i+1]);
|
||||
}
|
||||
|
||||
g_signal_emitv (vals, sig_id, detail, &ret);
|
||||
|
||||
for (guint i = 0; i < n_params + 1; i++) {
|
||||
g_value_unset (&vals[i]);
|
||||
}
|
||||
|
||||
int n_ret = 0;
|
||||
if (query.return_type != G_TYPE_NONE)
|
||||
n_ret = wplua_gvalue_to_lua (L, &ret);
|
||||
|
||||
g_value_unset (&ret);
|
||||
return n_ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_wplua_gobject_connect (lua_State *L)
|
||||
{
|
||||
GObject *obj = wplua_checkobject (L, 1, G_TYPE_OBJECT);
|
||||
const char *sig_name = luaL_checkstring (L, 2);
|
||||
luaL_checktype (L, 3, LUA_TFUNCTION);
|
||||
|
||||
guint sig_id = 0;
|
||||
GQuark detail = 0;
|
||||
|
||||
if (G_UNLIKELY (!g_signal_parse_name (sig_name, G_TYPE_FROM_INSTANCE (obj),
|
||||
&sig_id, &detail, FALSE)))
|
||||
luaL_error (L, "unknown signal '%s::%s'", G_OBJECT_TYPE_NAME (obj),
|
||||
sig_name);
|
||||
|
||||
GClosure *closure = wplua_function_to_closure (L, 3);
|
||||
gulong handler =
|
||||
g_signal_connect_closure_by_id (obj, sig_id, detail, closure, FALSE);
|
||||
|
||||
lua_pushinteger (L, handler);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static lua_CFunction
|
||||
find_method_in_luaL_Reg (luaL_Reg *reg, const gchar *method)
|
||||
{
|
||||
if (reg) {
|
||||
while (reg->name) {
|
||||
if (!g_strcmp0 (method, reg->name))
|
||||
return reg->func;
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
_wplua_gobject___index (lua_State *L)
|
||||
{
|
||||
GObject *obj = wplua_checkobject (L, 1, G_TYPE_OBJECT);
|
||||
const gchar *key = luaL_checkstring (L, 2);
|
||||
lua_CFunction func = NULL;
|
||||
GHashTable *vtables;
|
||||
|
||||
lua_pushliteral (L, "wplua_vtables");
|
||||
lua_gettable (L, LUA_REGISTRYINDEX);
|
||||
vtables = wplua_toboxed (L, -1);
|
||||
lua_pop (L, 1);
|
||||
|
||||
if (!g_strcmp0 (key, "call"))
|
||||
func = _wplua_gobject_call;
|
||||
else if (!g_strcmp0 (key, "connect"))
|
||||
func = _wplua_gobject_connect;
|
||||
|
||||
/* search in registered vtables */
|
||||
if (!func) {
|
||||
GType type = G_TYPE_FROM_INSTANCE (obj);
|
||||
while (!func && type) {
|
||||
luaL_Reg *reg = g_hash_table_lookup (vtables, GUINT_TO_POINTER (type));
|
||||
func = find_method_in_luaL_Reg (reg, key);
|
||||
type = g_type_parent (type);
|
||||
}
|
||||
}
|
||||
|
||||
/* search in registered vtables of interfaces */
|
||||
if (!func) {
|
||||
g_autofree GType *interfaces =
|
||||
g_type_interfaces (G_TYPE_FROM_INSTANCE (obj), NULL);
|
||||
GType *type = interfaces;
|
||||
while (!func && *type) {
|
||||
luaL_Reg *reg = g_hash_table_lookup (vtables, GUINT_TO_POINTER (*type));
|
||||
func = find_method_in_luaL_Reg (reg, key);
|
||||
type++;
|
||||
}
|
||||
}
|
||||
|
||||
if (func) {
|
||||
lua_pushcfunction (L, func);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
/* search in properties */
|
||||
GObjectClass *klass = G_OBJECT_GET_CLASS (obj);
|
||||
GParamSpec *pspec = g_object_class_find_property (klass, key);
|
||||
if (pspec && (pspec->flags & G_PARAM_READABLE)) {
|
||||
g_auto (GValue) v = G_VALUE_INIT;
|
||||
g_value_init (&v, pspec->value_type);
|
||||
g_object_get_property (obj, key, &v);
|
||||
return wplua_gvalue_to_lua (L, &v);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_wplua_gobject___newindex (lua_State *L)
|
||||
{
|
||||
GObject *obj = wplua_checkobject (L, 1, G_TYPE_OBJECT);
|
||||
const gchar *key = luaL_checkstring (L, 2);
|
||||
|
||||
/* search in properties */
|
||||
GObjectClass *klass = G_OBJECT_GET_CLASS (obj);
|
||||
GParamSpec *pspec = g_object_class_find_property (klass, key);
|
||||
if (pspec && (pspec->flags & G_PARAM_WRITABLE)) {
|
||||
g_auto (GValue) v = G_VALUE_INIT;
|
||||
g_value_init (&v, pspec->value_type);
|
||||
wplua_lua_to_gvalue (L, 3, &v);
|
||||
g_object_set_property (obj, key, &v);
|
||||
} else {
|
||||
luaL_error (L, "attempted to assign unknown or non-writable property '%s'",
|
||||
key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_wplua_gobject__tostring (lua_State *L)
|
||||
{
|
||||
GObject *obj;
|
||||
gchar *str;
|
||||
|
||||
obj = wplua_checkobject (L, 1, G_TYPE_OBJECT);
|
||||
str = g_strdup_printf (WP_OBJECT_FORMAT, WP_OBJECT_ARGS (obj));
|
||||
lua_pushstring (L, str);
|
||||
g_free (str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
_wplua_init_gobject (lua_State *L)
|
||||
{
|
||||
static const luaL_Reg gobject_meta[] = {
|
||||
{ "__gc", _wplua_gvalue_userdata___gc },
|
||||
{ "__eq", _wplua_gvalue_userdata___eq },
|
||||
{ "__index", _wplua_gobject___index },
|
||||
{ "__newindex", _wplua_gobject___newindex },
|
||||
{ "__tostring", _wplua_gobject__tostring },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
luaL_newmetatable (L, "GObject");
|
||||
luaL_setfuncs (L, gobject_meta, 0);
|
||||
lua_pop (L, 1);
|
||||
}
|
||||
|
||||
void
|
||||
wplua_pushobject (lua_State * L, gpointer object)
|
||||
{
|
||||
g_return_if_fail (G_IS_OBJECT (object));
|
||||
|
||||
GValue *v = _wplua_pushgvalue_userdata (L, G_TYPE_FROM_INSTANCE (object));
|
||||
wp_trace_object (object, "pushing to Lua, v=%p", v);
|
||||
g_value_take_object (v, object);
|
||||
|
||||
luaL_getmetatable (L, "GObject");
|
||||
lua_setmetatable (L, -2);
|
||||
}
|
||||
|
||||
gpointer
|
||||
wplua_toobject (lua_State *L, int idx)
|
||||
{
|
||||
g_return_val_if_fail (_wplua_isgvalue_userdata (L, idx, G_TYPE_OBJECT), NULL);
|
||||
return g_value_get_object ((GValue *) lua_touserdata (L, idx));
|
||||
}
|
||||
|
||||
gpointer
|
||||
wplua_checkobject (lua_State *L, int idx, GType type)
|
||||
{
|
||||
if (G_UNLIKELY (!_wplua_isgvalue_userdata (L, idx, type))) {
|
||||
wp_critical ("expected userdata storing GValue<%s>", g_type_name (type));
|
||||
luaL_argerror (L, idx, "expected userdata storing GValue<GObject>");
|
||||
}
|
||||
return g_value_get_object ((GValue *) lua_touserdata (L, idx));
|
||||
}
|
||||
|
||||
gboolean
|
||||
wplua_isobject (lua_State *L, int idx, GType type)
|
||||
{
|
||||
if (!g_type_is_a (type, G_TYPE_OBJECT)) return FALSE;
|
||||
return _wplua_isgvalue_userdata (L, idx, type);
|
||||
}
|
Reference in New Issue
Block a user