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->parent = parent;
|
||||||
class->tostring = NULL;
|
class->tostring = NULL;
|
||||||
class->instances = 0;
|
class->instances = 0;
|
||||||
|
class->index_miss_handler = LUA_REFNIL;
|
||||||
|
class->newindex_miss_handler = LUA_REFNIL;
|
||||||
|
|
||||||
signal_add(&class->signals, "new");
|
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;
|
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.
|
/** Generic index meta function for objects.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \return The number of elements pushed on stack.
|
* \return The number of elements pushed on stack.
|
||||||
|
@ -397,6 +433,8 @@ luaA_class_index(lua_State *L)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if(class->index_miss_handler != LUA_REFNIL)
|
||||||
|
return luaA_class_call_handler(L, class->index_miss_handler);
|
||||||
if(class->index_miss_property)
|
if(class->index_miss_property)
|
||||||
return class->index_miss_property(L, luaA_checkudata(L, 1, class));
|
return class->index_miss_property(L, luaA_checkudata(L, 1, class));
|
||||||
}
|
}
|
||||||
|
@ -427,6 +465,8 @@ luaA_class_newindex(lua_State *L)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if(class->newindex_miss_handler != LUA_REFNIL)
|
||||||
|
return luaA_class_call_handler(L, class->newindex_miss_handler);
|
||||||
if(class->newindex_miss_property)
|
if(class->newindex_miss_property)
|
||||||
return class->newindex_miss_property(L, luaA_checkudata(L, 1, class));
|
return class->newindex_miss_property(L, luaA_checkudata(L, 1, class));
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,10 @@ struct lua_class_t
|
||||||
unsigned int instances;
|
unsigned int instances;
|
||||||
/** Class tostring method */
|
/** Class tostring method */
|
||||||
lua_class_propfunc_t tostring;
|
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);
|
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); \
|
lua_pushnumber(L, (lua_class).instances); \
|
||||||
return 1; \
|
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) \
|
#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 }, \
|
{ "disconnect_signal", luaA_##class##_class_disconnect_signal }, \
|
||||||
{ "emit_signal", luaA_##class##_class_emit_signal }, \
|
{ "emit_signal", luaA_##class##_class_emit_signal }, \
|
||||||
{ "instances", luaA_##class##_class_instances }, \
|
{ "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 \
|
#define LUA_CLASS_META \
|
||||||
{ "__index", luaA_class_index }, \
|
{ "__index", luaA_class_index }, \
|
||||||
|
|
|
@ -49,6 +49,16 @@
|
||||||
* @function instances
|
* @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.
|
/** Create a new mouse button bindings.
|
||||||
* \param L The Lua VM state.
|
* \param L The Lua VM state.
|
||||||
* \return The number of elements pushed on stack.
|
* \return The number of elements pushed on stack.
|
||||||
|
|
|
@ -126,6 +126,16 @@
|
||||||
* @function instances
|
* @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 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);
|
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
|
* @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;
|
static lua_class_t drawable_class;
|
||||||
|
|
||||||
LUA_OBJECT_FUNCS(drawable_class, drawable_t, drawable)
|
LUA_OBJECT_FUNCS(drawable_class, drawable_t, drawable)
|
||||||
|
|
|
@ -83,6 +83,16 @@
|
||||||
* @function instances
|
* @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)
|
LUA_OBJECT_FUNCS(drawin_class, drawin_t, drawin)
|
||||||
|
|
||||||
/** Kick out systray windows.
|
/** Kick out systray windows.
|
||||||
|
|
|
@ -61,6 +61,16 @@
|
||||||
* @function instances
|
* @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
|
static void
|
||||||
luaA_keystore(lua_State *L, int ud, const char *str, ssize_t len)
|
luaA_keystore(lua_State *L, int ud, const char *str, ssize_t len)
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,6 +54,22 @@
|
||||||
* @table screen
|
* @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
|
struct screen_output_t
|
||||||
{
|
{
|
||||||
/** The XRandR names of the output */
|
/** The XRandR names of the output */
|
||||||
|
|
|
@ -54,6 +54,16 @@
|
||||||
* @function instances
|
* @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 */
|
/** Tag type */
|
||||||
struct tag
|
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