Make it possible for Lua to emulate arbitrary properties
This makes it possible to add something similar to a __index / __newindex metamethod to all our C objects. Based on this, Lua can then easily implement arbitrary properties on our capi objects.
This commit is contained in:
parent
bf630de74e
commit
a5a106f97f
|
@ -251,6 +251,8 @@ luaA_class_setup(lua_State *L, lua_class_t *class,
|
|||
class->parent = parent;
|
||||
class->tostring = NULL;
|
||||
class->instances = 0;
|
||||
class->index_miss_handler = LUA_REFNIL;
|
||||
class->newindex_miss_handler = LUA_REFNIL;
|
||||
|
||||
signal_add(&class->signals, "new");
|
||||
|
||||
|
@ -361,6 +363,40 @@ luaA_class_property_get(lua_State *L, lua_class_t *lua_class, int fieldidx)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/** Call a registered function.
|
||||
* \param L The Lua VM state.
|
||||
* \param handler The function to call.
|
||||
* \return The number of elements pushed on stack.
|
||||
*/
|
||||
static
|
||||
int luaA_class_call_handler(lua_State *L, int handler)
|
||||
{
|
||||
/* This is based on luaA_dofunction, but allows multiple return values */
|
||||
assert(handler != LUA_REFNIL);
|
||||
|
||||
int nargs = lua_gettop(L);
|
||||
|
||||
/* Push error handling function and move it before args */
|
||||
lua_pushcfunction(L, luaA_dofunction_error);
|
||||
lua_insert(L, - nargs - 1);
|
||||
int error_func_pos = 1;
|
||||
|
||||
/* push function and move it before args */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, handler);
|
||||
lua_insert(L, - nargs - 1);
|
||||
|
||||
if(lua_pcall(L, nargs, LUA_MULTRET, error_func_pos))
|
||||
{
|
||||
warn("%s", lua_tostring(L, -1));
|
||||
/* Remove error function and error string */
|
||||
lua_pop(L, 2);
|
||||
return 0;
|
||||
}
|
||||
/* Remove error function */
|
||||
lua_remove(L, error_func_pos);
|
||||
return lua_gettop(L);
|
||||
}
|
||||
|
||||
/** Generic index meta function for objects.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
|
@ -397,6 +433,8 @@ luaA_class_index(lua_State *L)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(class->index_miss_handler != LUA_REFNIL)
|
||||
return luaA_class_call_handler(L, class->index_miss_handler);
|
||||
if(class->index_miss_property)
|
||||
return class->index_miss_property(L, luaA_checkudata(L, 1, class));
|
||||
}
|
||||
|
@ -427,6 +465,8 @@ luaA_class_newindex(lua_State *L)
|
|||
}
|
||||
else
|
||||
{
|
||||
if(class->newindex_miss_handler != LUA_REFNIL)
|
||||
return luaA_class_call_handler(L, class->newindex_miss_handler);
|
||||
if(class->newindex_miss_property)
|
||||
return class->newindex_miss_property(L, luaA_checkudata(L, 1, class));
|
||||
}
|
||||
|
|
|
@ -74,6 +74,10 @@ struct lua_class_t
|
|||
unsigned int instances;
|
||||
/** Class tostring method */
|
||||
lua_class_propfunc_t tostring;
|
||||
/** Function to call on index misses */
|
||||
int index_miss_handler;
|
||||
/** Function to call on newindex misses */
|
||||
int newindex_miss_handler;
|
||||
};
|
||||
|
||||
const char * luaA_typename(lua_State *, int);
|
||||
|
@ -152,6 +156,18 @@ luaA_checkudataornil(lua_State *L, int udx, lua_class_t *class)
|
|||
{ \
|
||||
lua_pushnumber(L, (lua_class).instances); \
|
||||
return 1; \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
luaA_##prefix##_set_index_miss_handler(lua_State *L) \
|
||||
{ \
|
||||
return luaA_registerfct(L, 1, &(lua_class).index_miss_handler); \
|
||||
} \
|
||||
\
|
||||
static inline int \
|
||||
luaA_##prefix##_set_newindex_miss_handler(lua_State *L) \
|
||||
{ \
|
||||
return luaA_registerfct(L, 1, &(lua_class).newindex_miss_handler); \
|
||||
}
|
||||
|
||||
#define LUA_CLASS_METHODS(class) \
|
||||
|
@ -160,6 +176,8 @@ luaA_checkudataornil(lua_State *L, int udx, lua_class_t *class)
|
|||
{ "disconnect_signal", luaA_##class##_class_disconnect_signal }, \
|
||||
{ "emit_signal", luaA_##class##_class_emit_signal }, \
|
||||
{ "instances", luaA_##class##_class_instances }, \
|
||||
{ "set_index_miss_handler", luaA_##class##_set_index_miss_handler }, \
|
||||
{ "set_newindex_miss_handler", luaA_##class##_set_newindex_miss_handler }, \
|
||||
|
||||
#define LUA_CLASS_META \
|
||||
{ "__index", luaA_class_index }, \
|
||||
|
|
|
@ -49,6 +49,16 @@
|
|||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all button instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all button instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
/** Create a new mouse button bindings.
|
||||
* \param L The Lua VM state.
|
||||
* \return The number of elements pushed on stack.
|
||||
|
|
|
@ -126,6 +126,16 @@
|
|||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all client instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all client instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
static area_t titlebar_get_area(client_t *c, client_titlebar_t bar);
|
||||
static drawable_t *titlebar_get_drawable(lua_State *L, client_t *c, int cl_idx, client_titlebar_t bar);
|
||||
|
||||
|
|
|
@ -49,6 +49,16 @@
|
|||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all drawable instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all drawable instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
static lua_class_t drawable_class;
|
||||
|
||||
LUA_OBJECT_FUNCS(drawable_class, drawable_t, drawable)
|
||||
|
|
|
@ -83,6 +83,16 @@
|
|||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all drawin instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all drawin instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
LUA_OBJECT_FUNCS(drawin_class, drawin_t, drawin)
|
||||
|
||||
/** Kick out systray windows.
|
||||
|
|
|
@ -61,6 +61,16 @@
|
|||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all key instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all key instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
static void
|
||||
luaA_keystore(lua_State *L, int ud, const char *str, ssize_t len)
|
||||
{
|
||||
|
|
|
@ -54,6 +54,22 @@
|
|||
* @table screen
|
||||
*/
|
||||
|
||||
/** Get the number of instances.
|
||||
*
|
||||
* @return The number of screen objects alive.
|
||||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all screen instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all screen instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
struct screen_output_t
|
||||
{
|
||||
/** The XRandR names of the output */
|
||||
|
|
|
@ -54,6 +54,16 @@
|
|||
* @function instances
|
||||
*/
|
||||
|
||||
/** Set a __index metamethod for all tag instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_index_miss_handler
|
||||
*/
|
||||
|
||||
/** Set a __newindex metamethod for all tag instances.
|
||||
* @tparam function cb The meta-method
|
||||
* @function set_newindex_miss_handler
|
||||
*/
|
||||
|
||||
/** Tag type */
|
||||
struct tag
|
||||
{
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
-- Test set_{,new}index_miss_handler
|
||||
|
||||
local class = tag
|
||||
local obj = class({})
|
||||
|
||||
awesome.connect_signal("debug::index::miss", error)
|
||||
awesome.connect_signal("debug::newindex::miss", error)
|
||||
|
||||
class.set_index_miss_handler(function(o, k)
|
||||
assert(o == obj)
|
||||
assert(k == "key")
|
||||
return 42
|
||||
end)
|
||||
assert(obj.key == 42)
|
||||
|
||||
local called = false
|
||||
class.set_newindex_miss_handler(function(o, k, v)
|
||||
assert(o == obj)
|
||||
assert(k == "key")
|
||||
assert(v == 42)
|
||||
called = true
|
||||
end)
|
||||
obj.key = 42
|
||||
assert(called)
|
||||
|
||||
require("_runner").run_steps({ function() return true end })
|
Loading…
Reference in New Issue