2014-04-16 03:42:18 -07:00
|
|
|
-- EFL LuaJIT bindings: Eo
|
|
|
|
-- For use with Elua
|
|
|
|
|
|
|
|
local ffi = require("ffi")
|
|
|
|
|
|
|
|
ffi.cdef [[
|
|
|
|
typedef unsigned char Eina_Bool;
|
2014-09-24 03:09:46 -07:00
|
|
|
typedef struct _Eina_Iterator Eina_Iterator;
|
2014-04-16 03:42:18 -07:00
|
|
|
|
|
|
|
typedef struct _Eo_Opaque Eo;
|
|
|
|
typedef Eo Eo_Class;
|
|
|
|
|
2014-09-24 03:09:46 -07:00
|
|
|
typedef short Eo_Callback_Priority;
|
|
|
|
|
|
|
|
typedef void (*eo_key_data_free_func)(void *);
|
|
|
|
|
|
|
|
struct _Eo_Event_Description {
|
|
|
|
const char *name;
|
|
|
|
const char *doc;
|
|
|
|
Eina_Bool unfreezable;
|
|
|
|
};
|
|
|
|
typedef struct _Eo_Event_Description Eo_Event_Description;
|
|
|
|
|
|
|
|
typedef Eina_Bool (*Eo_Event_Cb)(void *data, Eo *obj,
|
|
|
|
const Eo_Event_Description *desc, void *event_info);
|
|
|
|
|
|
|
|
struct _Eo_Callback_Array_Item {
|
|
|
|
const Eo_Event_Description *desc;
|
|
|
|
Eo_Event_Cb func;
|
|
|
|
};
|
|
|
|
typedef struct _Eo_Callback_Array_Item Eo_Callback_Array_Item;
|
|
|
|
|
2014-04-16 03:42:18 -07:00
|
|
|
Eina_Bool eo_init(void);
|
|
|
|
Eina_Bool eo_shutdown(void);
|
|
|
|
|
2014-06-05 03:15:29 -07:00
|
|
|
Eina_Bool eo_isa(const Eo *obj, const Eo_Class *klass);
|
|
|
|
|
2014-09-24 02:39:47 -07:00
|
|
|
const char *eo_class_name_get(const Eo_Class *klass);
|
|
|
|
|
2014-04-16 03:42:18 -07:00
|
|
|
void eo_constructor(void);
|
|
|
|
void eo_destructor(void);
|
|
|
|
|
|
|
|
Eo *_eo_add_internal_start(const char *file, int line,
|
2014-10-02 07:04:02 -07:00
|
|
|
const Eo_Class *klass_id, Eo *parent, Eina_Bool ref);
|
2014-04-16 03:42:18 -07:00
|
|
|
|
|
|
|
Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass,
|
|
|
|
Eina_Bool is_super, const char *file, const char *func, int line);
|
|
|
|
void _eo_do_end (const Eo **ojb);
|
|
|
|
|
2014-09-24 02:39:47 -07:00
|
|
|
const Eo_Class *eo_class_get(const Eo *obj);
|
|
|
|
|
|
|
|
void *eo_data_xref_internal(const char *file, int line, const Eo *obj,
|
|
|
|
const Eo_Class *klass, const Eo *ref_obj);
|
|
|
|
void eo_data_xunref_internal(const Eo *obj, void *data, const Eo *ref_obj);
|
|
|
|
Eo *eo_xref_internal(const char *file, int line, Eo *obj, const Eo *ref_obj);
|
|
|
|
void eo_xunref(Eo *obj, const Eo *ref_obj);
|
|
|
|
Eo *eo_ref(const Eo *obj);
|
|
|
|
void eo_unref(const Eo *obj);
|
|
|
|
int eo_ref_get(const Eo *obj);
|
2014-09-24 03:09:46 -07:00
|
|
|
void eo_wref_add(Eo **wref);
|
|
|
|
void eo_wref_del(Eo **wref);
|
|
|
|
|
2014-09-24 02:39:47 -07:00
|
|
|
void eo_del(const Eo *obj);
|
|
|
|
|
|
|
|
void eo_manual_free_set(Eo *obj, Eina_Bool manual_free);
|
|
|
|
Eina_Bool eo_manual_free(Eo *obj);
|
|
|
|
Eina_Bool eo_destructed_is(const Eo *obj);
|
|
|
|
|
|
|
|
Eina_Bool eo_composite_attach(Eo *comp_obj, Eo *parent);
|
|
|
|
Eina_Bool eo_composite_detach(Eo *comp_obj, Eo *parent);
|
|
|
|
Eina_Bool eo_composite_is(const Eo *comp_obj);
|
|
|
|
|
2014-04-16 03:42:18 -07:00
|
|
|
void eo_parent_set(Eo *parent);
|
|
|
|
Eo *eo_parent_get(void);
|
|
|
|
|
|
|
|
void eo_event_freeze(void);
|
|
|
|
void eo_event_thaw(void);
|
2014-06-05 08:28:10 -07:00
|
|
|
int eo_event_freeze_count_get(void);
|
2014-04-16 03:42:18 -07:00
|
|
|
void eo_event_global_freeze(void);
|
|
|
|
void eo_event_global_thaw(void);
|
2014-06-05 08:28:10 -07:00
|
|
|
int eo_event_global_freeze_count_get(void);
|
2014-09-24 03:09:46 -07:00
|
|
|
|
|
|
|
Eina_Bool eo_finalized_get(void);
|
|
|
|
Eo *eo_finalize(void);
|
|
|
|
|
|
|
|
void eo_event_callback_forwarder_add(const Eo_Event_Description *desc,
|
|
|
|
Eo *new_obj);
|
|
|
|
void eo_event_callback_forwarder_del(const Eo_Event_Description *desc,
|
|
|
|
Eo *new_obj);
|
|
|
|
void eo_event_callback_priority_add(const Eo_Event_Description *desc,
|
|
|
|
Eo_Callback_Priority priority, Eo_Event_Cb cb, const void *data);
|
|
|
|
void eo_event_callback_del(const Eo_Event_Description *desc,
|
|
|
|
Eo_Event_Cb func, const void *user_data);
|
|
|
|
void eo_event_callback_array_priority_add(const Eo_Callback_Array_Item *array,
|
|
|
|
Eo_Callback_Priority priority, const void *data);
|
|
|
|
void eo_event_callback_array_del(const Eo_Callback_Array_Item *array,
|
|
|
|
const void *user_data);
|
|
|
|
Eina_Bool eo_event_callback_call(const Eo_Event_Description *desc,
|
|
|
|
void *event_info);
|
|
|
|
|
|
|
|
void eo_key_data_set(const char *key, const void *data,
|
|
|
|
eo_key_data_free_func free_func);
|
|
|
|
void *eo_key_data_get(const char *key);
|
|
|
|
void eo_key_data_del(const char *key);
|
|
|
|
|
|
|
|
Eina_Iterator *eo_children_iterator_new(void);
|
2014-09-24 05:49:39 -07:00
|
|
|
|
|
|
|
const Eo_Class *eo_base_class_get(void);
|
2014-04-16 03:42:18 -07:00
|
|
|
]]
|
|
|
|
|
2014-10-17 06:56:28 -07:00
|
|
|
local addr_d = ffi.typeof("union { double d; const Eo_Class *p; }")
|
|
|
|
local eo_class_addr_get = function(x)
|
|
|
|
local v = addr_d()
|
|
|
|
v.p = x
|
|
|
|
return tonumber(v.d)
|
|
|
|
end
|
|
|
|
|
2014-04-16 03:42:18 -07:00
|
|
|
local cutil = require("cutil")
|
|
|
|
local util = require("util")
|
|
|
|
|
|
|
|
local M = {}
|
|
|
|
|
|
|
|
local eo
|
|
|
|
|
2014-10-10 05:48:25 -07:00
|
|
|
local classes = {}
|
|
|
|
local eo_classes = {}
|
|
|
|
|
2014-04-16 03:42:18 -07:00
|
|
|
local init = function()
|
|
|
|
eo = util.lib_load("eo")
|
|
|
|
eo.eo_init()
|
2014-10-17 06:56:28 -07:00
|
|
|
local eocl = eo.eo_base_class_get()
|
|
|
|
local addr = eo_class_addr_get(eocl)
|
2014-10-10 05:48:25 -07:00
|
|
|
classes["Eo_Base"] = util.Object:clone {
|
2014-10-10 05:58:04 -07:00
|
|
|
connect = function(self, ename, func)
|
|
|
|
local ev = self.__events[ename]
|
|
|
|
if not ev then
|
|
|
|
error("invalid event '" .. ename .. "'", 2)
|
|
|
|
end
|
|
|
|
local cl = eo_classes["Eo_Base"]
|
|
|
|
M.__do_start(self, cl)
|
|
|
|
eo.eo_event_callback_priority_add(ev, 0,
|
|
|
|
function(data, obj, desc, einfo)
|
2014-10-10 06:46:50 -07:00
|
|
|
return func(obj, einfo) ~= false
|
2014-10-10 05:58:04 -07:00
|
|
|
end,
|
|
|
|
nil)
|
|
|
|
M.__do_end()
|
|
|
|
end,
|
|
|
|
|
2014-10-10 05:48:25 -07:00
|
|
|
__events = util.Object:clone {},
|
|
|
|
__properties = util.Object:clone {}
|
|
|
|
}
|
2014-10-17 06:56:28 -07:00
|
|
|
classes[addr] = classes["Eo_Base"]
|
|
|
|
eo_classes["Eo_Base"] = eocl
|
|
|
|
eo_classes[addr] = eocl
|
2014-04-16 03:42:18 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
local shutdown = function()
|
2014-10-17 06:56:28 -07:00
|
|
|
M.class_unregister("Eo_Base")
|
2014-04-16 03:42:18 -07:00
|
|
|
eo.eo_shutdown()
|
|
|
|
util.lib_unload("eo")
|
|
|
|
end
|
|
|
|
|
|
|
|
local getinfo = debug.getinfo
|
|
|
|
|
|
|
|
local getfuncname = function(info)
|
|
|
|
return info.name or "<" .. tostring(info.func) .. ">"
|
|
|
|
end
|
|
|
|
|
2014-04-23 01:25:39 -07:00
|
|
|
M.class_get = function(name)
|
|
|
|
return classes[name]
|
|
|
|
end
|
|
|
|
|
2014-09-24 05:49:39 -07:00
|
|
|
M.eo_class_get = function(name)
|
|
|
|
return eo_classes[name]
|
|
|
|
end
|
|
|
|
|
2014-10-02 02:41:06 -07:00
|
|
|
M.class_register = function(name, parent, body, eocl)
|
2014-10-10 05:48:25 -07:00
|
|
|
parent = classes[parent]
|
|
|
|
if body.__events then
|
|
|
|
body.__events = parent.__events:clone(body.__events)
|
|
|
|
end
|
|
|
|
if body.__properties then
|
|
|
|
body.__properties = parent.__properties:clone(body.__properties)
|
|
|
|
end
|
2014-10-17 06:56:28 -07:00
|
|
|
local addr = eo_class_addr_get(eocl)
|
2014-10-10 05:48:25 -07:00
|
|
|
classes[name] = parent:clone(body)
|
2014-10-17 06:56:28 -07:00
|
|
|
classes[addr] = classes[name]
|
2014-10-02 02:41:06 -07:00
|
|
|
eo_classes[name] = eocl
|
2014-10-17 06:56:28 -07:00
|
|
|
eo_classes[addr] = eocl
|
2014-04-23 01:25:39 -07:00
|
|
|
end
|
|
|
|
|
2014-09-24 05:49:39 -07:00
|
|
|
M.class_unregister = function(name)
|
2014-10-17 06:56:28 -07:00
|
|
|
local addr = eo_class_addr_get(eo_classes[name])
|
2014-09-24 05:49:39 -07:00
|
|
|
classes[name] = nil
|
2014-10-17 06:56:28 -07:00
|
|
|
classes[addr] = nil
|
2014-09-24 05:49:39 -07:00
|
|
|
eo_classes[name] = nil
|
2014-10-17 06:56:28 -07:00
|
|
|
eo_classes[addr] = nil
|
2014-09-24 05:49:39 -07:00
|
|
|
end
|
|
|
|
|
2014-10-17 08:14:49 -07:00
|
|
|
local mixin_tbl = function(cl, mixin, field)
|
|
|
|
local mxt = mixin[field]
|
|
|
|
if mxt then
|
2015-02-25 04:09:16 -08:00
|
|
|
local clt = rawget(cl, field)
|
2014-10-17 08:14:49 -07:00
|
|
|
if not clt then
|
2015-02-25 04:09:16 -08:00
|
|
|
-- will always succeed, even if it means deep lookups
|
2015-02-25 07:11:52 -08:00
|
|
|
clt = cl.__protos[1][field]:clone()
|
2015-02-25 04:09:16 -08:00
|
|
|
rawset(cl, field, clt)
|
2014-10-17 08:14:49 -07:00
|
|
|
end
|
2015-02-25 04:09:16 -08:00
|
|
|
for k, v in pairs(mxt) do clt[k] = v end
|
2014-10-17 08:14:49 -07:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-10-02 02:41:06 -07:00
|
|
|
M.class_mixin = function(name, mixin)
|
2014-10-17 08:14:49 -07:00
|
|
|
local cl = classes[name]
|
2015-02-25 06:01:45 -08:00
|
|
|
local mi = classes[mixin]
|
|
|
|
local ck = "__mixin_" .. mixin
|
|
|
|
-- do not mixin if it already has been mixed in previously
|
|
|
|
-- but only do it for mixins, not for ifaces, for proper lookup order
|
|
|
|
if mi[ck] and cl[ck] then
|
|
|
|
return
|
|
|
|
end
|
2014-10-17 08:14:49 -07:00
|
|
|
-- mixin properties/events
|
2015-02-25 06:01:45 -08:00
|
|
|
mixin_tbl(cl, mi, "__properties")
|
|
|
|
mixin_tbl(cl, mi, "__events")
|
2014-10-17 08:14:49 -07:00
|
|
|
-- mixin the rest
|
|
|
|
cl:mixin(classes[mixin])
|
2014-10-02 02:41:06 -07:00
|
|
|
end
|
|
|
|
|
2014-10-10 07:44:49 -07:00
|
|
|
local obj_gccb = function(obj)
|
|
|
|
eo.eo_unref(obj)
|
|
|
|
end
|
|
|
|
|
2014-10-02 06:55:30 -07:00
|
|
|
M.__ctor_common = function(klass, parent, ctor, loff, ...)
|
|
|
|
local info = getinfo(2 + (loff or 0), "nlSf")
|
|
|
|
local source = info.source
|
|
|
|
local func = getfuncname(info)
|
|
|
|
local line = info.currentline
|
2014-10-02 07:04:02 -07:00
|
|
|
local ret = eo._eo_add_internal_start(source, line, klass, parent, true)
|
2014-06-06 06:40:04 -07:00
|
|
|
local retval
|
2014-10-02 06:55:30 -07:00
|
|
|
if eo._eo_do_start(ret, nil, false, source, func, line) ~= 0 then
|
|
|
|
eo.eo_constructor()
|
2014-10-10 05:48:25 -07:00
|
|
|
if ctor then ctor(ret, ...) end
|
2014-10-02 06:55:30 -07:00
|
|
|
ret = eo.eo_finalize()
|
2014-06-06 06:40:04 -07:00
|
|
|
eo._eo_do_end(nil)
|
|
|
|
end
|
2014-10-10 07:44:49 -07:00
|
|
|
ffi.gc(ret, obj_gccb)
|
2014-10-02 06:55:30 -07:00
|
|
|
return ret
|
2014-06-06 06:40:04 -07:00
|
|
|
end
|
|
|
|
|
|
|
|
M.__do_start = function(self, klass)
|
2014-10-10 05:48:25 -07:00
|
|
|
if eo.eo_isa(self, klass) == 0 then
|
2014-06-06 06:40:04 -07:00
|
|
|
error("method call on an invalid object", 3)
|
2014-04-16 03:42:18 -07:00
|
|
|
end
|
2014-06-06 06:40:04 -07:00
|
|
|
local info = getinfo(3, "nlSf")
|
2014-10-10 05:48:25 -07:00
|
|
|
return eo._eo_do_start(self, nil, false, info.source,
|
2014-06-06 06:40:04 -07:00
|
|
|
getfuncname(info), info.currentline) ~= 0
|
|
|
|
end
|
|
|
|
|
|
|
|
M.__do_end = function()
|
|
|
|
eo._eo_do_end(nil) -- the parameter is unused and originally there
|
|
|
|
-- only for cleanup (dtor)
|
|
|
|
end
|
|
|
|
|
2014-10-17 06:56:28 -07:00
|
|
|
local get_obj_mt = function(obj)
|
|
|
|
local cl = eo.eo_class_get(obj)
|
|
|
|
if cl == nil then return nil end
|
|
|
|
return classes[eo_class_addr_get(cl)]
|
|
|
|
end
|
|
|
|
|
2014-10-17 07:54:07 -07:00
|
|
|
local prop_proxy_meta = {
|
|
|
|
__index = function(self, key)
|
|
|
|
if self.nkeys > 1 and type(key) == "table" then
|
|
|
|
if self.nvals > 1 then
|
|
|
|
return { self(unpack(key)) }
|
|
|
|
else
|
|
|
|
return self(unpack(key))
|
|
|
|
end
|
|
|
|
else
|
|
|
|
if self.nvals > 1 then
|
|
|
|
return { self(key) }
|
|
|
|
else
|
|
|
|
return self(key)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
__newindex = function(self, key, val)
|
|
|
|
local nkeys = self.nkeys
|
|
|
|
if nkeys > 1 then
|
|
|
|
-- ultra slow path, q66 failed optimizing this
|
|
|
|
local atbl
|
|
|
|
if type(key) == "table" then
|
|
|
|
atbl = { unpack(key) }
|
|
|
|
else
|
|
|
|
atbl = { key }
|
|
|
|
end
|
|
|
|
if self.nvals > 1 and type(val) == "table" then
|
|
|
|
for i, v in ipairs(val) do atbl[nkeys + i] = v end
|
|
|
|
else
|
|
|
|
atbl[nkeys + 1] = val
|
|
|
|
end
|
|
|
|
self.mt[self.key .. "_set"](self.obj, unpack(atbl))
|
|
|
|
else
|
|
|
|
if self.nvals > 1 and type(val) == "table" then
|
|
|
|
-- somewhat less slow but still slow path
|
|
|
|
self.mt[self.key .. "_set"](self.obj, key, unpack(val))
|
|
|
|
else
|
|
|
|
-- least slow, no unpacks, no temporaries, just proxy
|
|
|
|
self.mt[self.key .. "_set"](self.obj, key, val)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
|
|
|
|
-- provides alt syntax for getters with keys
|
|
|
|
__call = function(self, ...)
|
|
|
|
return self.mt[self.key .. "_get"](self.obj, ...)
|
|
|
|
end
|
|
|
|
}
|
|
|
|
|
2014-09-24 03:51:11 -07:00
|
|
|
ffi.metatype("Eo", {
|
|
|
|
__index = function(self, key)
|
2014-10-17 06:56:28 -07:00
|
|
|
local mt = get_obj_mt(self)
|
2014-09-24 03:51:11 -07:00
|
|
|
if mt == nil then return nil end
|
2014-10-17 07:54:07 -07:00
|
|
|
local pt = mt.__properties
|
|
|
|
local pp = pt[key]
|
|
|
|
if not pp then
|
|
|
|
return mt[key]
|
|
|
|
end
|
|
|
|
if not pp[3] then
|
|
|
|
error("property '" .. key .. "' is not gettable", 2)
|
|
|
|
end
|
|
|
|
local nkeys, nvals = pp[1], pp[2]
|
|
|
|
if nkeys ~= 0 then
|
|
|
|
-- proxy - slow path... TODO: find a better way
|
|
|
|
return setmetatable({ nkeys = nkeys, nvals = nvals,
|
|
|
|
obj = self, key = key, mt = mt }, prop_proxy_meta)
|
|
|
|
end
|
|
|
|
if nvals > 1 then
|
|
|
|
return { mt[key .. "_get"](self) }
|
|
|
|
else
|
|
|
|
return mt[key .. "_get"](self)
|
|
|
|
end
|
2014-10-10 05:48:25 -07:00
|
|
|
end,
|
|
|
|
|
|
|
|
__newindex = function(self, key, val)
|
2014-10-17 06:56:28 -07:00
|
|
|
local mt = get_obj_mt(self)
|
|
|
|
if mt == nil then return nil end
|
2014-10-10 05:48:25 -07:00
|
|
|
local pt = mt.__properties
|
|
|
|
local pp = pt[key]
|
|
|
|
if not pp then
|
|
|
|
error("no such property '" .. key .. "'", 2)
|
|
|
|
end
|
|
|
|
if not pp[4] then
|
2014-10-17 07:54:07 -07:00
|
|
|
error("property '" .. key .. "' is not settable", 2)
|
2014-10-10 05:48:25 -07:00
|
|
|
end
|
|
|
|
if pp[1] ~= 0 then
|
|
|
|
error("property '" .. key .. "' requires " .. pp[1] .. " keys", 2)
|
|
|
|
end
|
|
|
|
local nvals = pp[2]
|
|
|
|
if nvals > 1 and type(val) == "table" then
|
|
|
|
mt[key .. "_set"](self, unpack(val))
|
|
|
|
else
|
|
|
|
mt[key .. "_set"](self, val)
|
|
|
|
end
|
2014-09-24 03:51:11 -07:00
|
|
|
end
|
|
|
|
})
|
|
|
|
|
2014-10-10 05:48:25 -07:00
|
|
|
cutil.init_module(init, shutdown)
|
2014-04-16 03:42:18 -07:00
|
|
|
|
2014-06-10 04:35:54 -07:00
|
|
|
return M
|