diff --git a/efl/eo/efl.eo.pyx b/efl/eo/efl.eo.pyx index 6a2cd03..20dc136 100644 --- a/efl/eo/efl.eo.pyx +++ b/efl/eo/efl.eo.pyx @@ -20,14 +20,16 @@ from cpython cimport PyObject, Py_INCREF, Py_DECREF, PyUnicode_AsUTF8String from libc.stdint cimport uintptr_t from efl.eina cimport Eina_Bool, \ Eina_Hash, eina_hash_string_superfast_new, eina_hash_add, eina_hash_del, \ - eina_hash_find, EINA_LOG_DOM_DBG, EINA_LOG_DOM_INFO + eina_hash_find, EINA_LOG_DOM_DBG, EINA_LOG_DOM_INFO, \ + eina_hash_pointer_new from efl.c_eo cimport Eo as cEo, eo_init, eo_shutdown, eo_del, eo_do, \ eo_class_name_get, eo_class_get, eo_base_class_get,\ eo_key_data_set, eo_key_data_get, eo_key_data_del, \ eo_event_callback_add, eo_event_callback_del, EO_EV_DEL, \ eo_parent_get, eo_parent_set, Eo_Event_Description, \ eo_event_freeze, eo_event_thaw, eo_event_freeze_count_get, \ - eo_event_global_freeze, eo_event_global_thaw, eo_event_global_freeze_count_get + eo_event_global_freeze, eo_event_global_thaw, \ + eo_event_global_freeze_count_get cimport efl.eo.enums as enums @@ -193,6 +195,30 @@ cdef Eina_Bool _eo_event_del_cb(void *data, cEo *obj, return enums.EO_CALLBACK_STOP +cdef Eina_Bool _py_efl_eo_event_cb( + void *data, cEo *obj, const Eo_Event_Description *desc, void *event_info): + + cdef: + void* tmp + bint ret + Eo o + + func = data + o = object_from_instance(obj) + + # create event description python object + + tmp = eina_hash_find(o.event_conv_mapping, desc) + if tmp == NULL: + py_ev_info_obj = None + else: + py_ev_info_cls = tmp + # use a generic class and set some conv func?? + #py_ev_info_obj = py_ev_info_cls.__new__(py_ev_info_cls) + + #ret = func(py_ev_desc, py_ev_info_obj) # o as first param? + #return ret + cdef class Eo(object): """ @@ -204,6 +230,8 @@ cdef class Eo(object): # c globals declared in eo.pxd (to make the class available to others) def __cinit__(self): + self.event_desc_mapping = eina_hash_string_superfast_new(NULL) + self.event_conv_mapping = eina_hash_pointer_new(NULL) self.data = dict() def __init__(self, *args, **kwargs): @@ -296,7 +324,49 @@ cdef class Eo(object): :return: the freeze count :rtype: int - + """ cdef int fcount = eo_do(self.obj, eo_event_freeze_count_get()) return fcount + + def event_callback_add(self, event_name, func): + cdef: + void *desc + const char *ev_name + + if isinstance(event_name, unicode): + event_name = PyUnicode_AsUTF8String(event_name) + + ev_name = event_name + + desc = eina_hash_find(self.event_desc_mapping, ev_name) + if desc is NULL: + raise RuntimeError("Unknown Eo event name: %s" % (event_name)) + + eo_event_callback_add( + desc, + _py_efl_eo_event_cb, + func + ) + Py_INCREF(func) + + def event_callback_del(self, event_name, func): + cdef: + void *desc + const char *ev_name + + if isinstance(event_name, unicode): + event_name = PyUnicode_AsUTF8String(event_name) + + ev_name = event_name + + desc = eina_hash_find(self.event_desc_mapping, ev_name) + if desc is NULL: + raise RuntimeError("Unknown Eo event name: %s" % (event_name)) + + eo_event_callback_del( + desc, + _py_efl_eo_event_cb, + func + ) + Py_DECREF(func) diff --git a/include/efl.c_eo.pxd b/include/efl.c_eo.pxd index 1dec22a..f62a029 100644 --- a/include/efl.c_eo.pxd +++ b/include/efl.c_eo.pxd @@ -17,7 +17,7 @@ from efl.eina cimport Eina_Bool -cdef extern from "*": +cdef extern from *: struct CFILE "__FILE__" struct CLINE "__LINE__" struct CFUNC "__FUNCTION__" diff --git a/include/efl.eina.pxd b/include/efl.eina.pxd index 6c16eba..8aceb65 100644 --- a/include/efl.eina.pxd +++ b/include/efl.eina.pxd @@ -161,6 +161,7 @@ cdef extern from "Eina.h": unsigned int eina_list_count(Eina_List *list) Eina_Hash *eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb) + Eina_Hash *eina_hash_pointer_new(Eina_Free_Cb data_free_cb) Eina_Bool eina_hash_add(Eina_Hash *hash, const void *key, const void *data) Eina_Bool eina_hash_del(Eina_Hash *hash, const void *key, const void *data) void *eina_hash_find(Eina_Hash *hash, const void *key) diff --git a/include/efl.eo.pxd b/include/efl.eo.pxd index 3e8e2b1..f0de416 100644 --- a/include/efl.eo.pxd +++ b/include/efl.eo.pxd @@ -16,11 +16,14 @@ # along with this Python-EFL. If not, see . from efl.c_eo cimport Eo as cEo +from efl.eina cimport Eina_Hash cdef: class Eo(object): cdef: cEo *obj + Eina_Hash *event_desc_mapping + Eina_Hash *event_conv_mapping readonly dict data int _set_obj(self, cEo *obj) except 0 diff --git a/scripts/converters.py b/scripts/converters.py index 461f0ad..6fc786c 100644 --- a/scripts/converters.py +++ b/scripts/converters.py @@ -6,6 +6,9 @@ import keyword from efl import eolian +class EolianTypeError(Exception): + pass + docstring_replacements = ( ("@brief ", ""), (re.compile(r"@ingroup .+", re.S), r""), @@ -95,16 +98,20 @@ conversions_out = { } -class EolianTypeError(TypeError): - pass - - -def conv_cls_name(name): - s = name.split("_") +def conv_cls_name(cls): + if cls.namespaces: + lib_name = ".".join(map(unicode.lower, cls.namespaces)) + name = cls.name + else: + s = cls.name.split("_") if len(s) > 1: - return s[0], "_".join(s[1:]) + lib_name = s[0] + name = "_".join(s[1:]) else: - return name, name + lib_name = s + name = s + + return lib_name, name def remove_type_prefixes(ctype): @@ -188,3 +195,7 @@ def conv_type_ret(tp): py_ret_type = py_t[0] return py_ret_type, c_type + +def event_conversion_get(tp): + if tp.type != eolian.TypeType.UNKNOWN: + return "Eo_Event_%s" % tp.name diff --git a/scripts/eolian_generate.py b/scripts/eolian_generate.py index 6ad0b0f..2541419 100755 --- a/scripts/eolian_generate.py +++ b/scripts/eolian_generate.py @@ -37,9 +37,12 @@ eolian.init() from converters import convert_in_param, convert_out_param, conv_type_ret, \ - conv_cls_name, EolianTypeError + conv_cls_name, EolianTypeError, event_conversion_get +class EolianSkip(Exception): + pass + class Generator(object): @@ -97,10 +100,11 @@ class Generator(object): #self.write(docs, wrapped=True) #self.write('"""') - def printout(self, filepath=None): + def printout(self, filepath=None, append=False): result = "\n".join(self.result) if filepath: - with open(filepath, "w") as f: + mode = "a" if append else "w" + with open(filepath, mode) as f: f.write(result.encode("utf-8")) f.write("\n") log.info(filepath + " written") @@ -336,7 +340,7 @@ class Function(object): ret = self.RET_PARAM try: ret_type = convert_out_param(ret_type, ret) - except Exception: + except EolianTypeError: gen.write("# FIXME: Unknown return type") gen.dedent() raise @@ -482,11 +486,7 @@ class Class(object): class_counter[cls.name] += 1 self.c_name = cls.name - if cls.namespaces: - self.lib_name = ".".join(map(unicode.lower, cls.namespaces)) - self.name = cls.name - else: - self.lib_name, self.name = conv_cls_name(cls.name) + self.lib_name, self.name = conv_cls_name(cls) header_path = cls.filename if not header_path: @@ -505,8 +505,8 @@ class Class(object): self.prefix = prefix - #if cls.type == eolian.ClassType.REGULAR: # or cls.type == eolian.ClassType.MIXIN: - self.ctor.append(Constructor(cls.constructors, prefix)) + if cls.type == eolian.ClassType.REGULAR: # or cls.type == eolian.ClassType.MIXIN: + self.ctor.append(Constructor(cls.constructors, prefix)) props = cls.functions_get(eolian.FunctionType.PROPERTY) for prop in props: @@ -568,10 +568,16 @@ class Class(object): if i_cls.type == eolian.ClassType.INTERFACE or \ i_cls.type == eolian.ClassType.MIXIN: continue + if i_cls.full_name == "Eo.Base": + inherits.append("Eo") + continue + lib_name, name = conv_cls_name(i_cls) + #i = i.rpartition(".")[2] + inherits.append("_" + name) else: - log.warn("Class %s is unknown" % (i)) - i = i.rpartition(".")[2] - inherits.append("_" + i) + log.warn("Inherited class %s is unknown" % (i)) + i = i.rpartition(".")[2] + inherits.append("_" + i) if len(inherits) > 1: log.error( "Multiple inheritance is not supported in extension classes.\n" @@ -586,12 +592,24 @@ class Class(object): gen.write("cdef class _%s(%s):" % (self.name, inherits)) gen.indent() + gen.write("def __cinit__(self):") + gen.indent() + for o in self.events: + try: + o.generate(gen) + except EolianTypeError: + log.info("Skipping %r because of unknown type", o) + except Exception: + log.exception("Error while generating %r", o) + gen.dedent() + gen.write() + if not self.ctor and not self.props and not self.methods: gen.write("pass") else: for o in ( - self.ctor + - list(self.events) + self.ctor #+ + #list(self.events) ): try: o.generate(gen) @@ -625,11 +643,15 @@ class Class(object): if i_cls.type == eolian.ClassType.REGULAR or \ i_cls.type == eolian.ClassType.ABSTRACT: continue + lib_name, name = conv_cls_name(i_cls) + #i = i.rpartition(".")[2] else: log.warn("Class %s is unknown" % (i)) - l, n = conv_cls_name(i) - inherits.append("_" + n) - imports.append((l, "_" + n)) + i = i.rpartition(".") + lib_name, name = i[0], i[2] + + inherits.append("_" + name) + imports.append((lib_name, "_" + name)) for l, n in imports: l = l.lower() @@ -652,6 +674,8 @@ class Class(object): gen.dedent() gen.dedent() gen.write() + gen.write('_object_mapping_register("%s", %s)' % (self.c_name, self.name)) + gen.write() class File(object): @@ -662,33 +686,13 @@ class File(object): self.cls = eolian.Class.get_by_file(filepath) if not self.cls: raise RuntimeError("Could not get class from %s" % (filepath)) + if self.cls.full_name.startswith("Eo."): + raise EolianSkip("Skipping Eo class") self.gencls = Class.parse(self.cls) def cdefs_generate(self): gen = self.pyxgen - # gen.write('cdef extern from "*":') - # gen.indent() - # gen.write('struct CFILE "__FILE__"') - # gen.write('struct CLINE "__LINE__"') - # gen.write('struct CFUNC "__FUNCTION__"') - # gen.dedent() - # gen.write() - - # gen.write('cdef extern from "Eina.h":') - # gen.indent() - # gen.write('Eina_Bool eina_main_loop_is(void)') - # gen.dedent() - # gen.write() - - # gen.write('cdef extern from "Eo.h":') - # gen.indent() - #gen.write('Eina_Bool _eo_do_start(const Eo *obj, const Eo_Class *cur_klass, Eina_Bool is_super, Eina_Bool is_main_loop, const char *file, const char *func, int line)') - # gen.write('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)') - #gen.write('void _eo_do_end(const Eo **ojb)') - # gen.dedent() - # gen.write() - gen.write('cdef extern from "%s":' % (self.gencls.header_path)) gen.indent() @@ -750,24 +754,32 @@ class File(object): def py_generate(self): py_path = os.path.join(args.output, "__init__" + ".py") - if os.path.exists(py_path): - os.remove(py_path) self.gencls.py_generate(self.pygen) - self.pygen.printout(filepath=py_path) + self.pygen.printout(filepath=py_path, append=True) class Event(object): def __init__(self, event): self.event = event - #print(event) def cdef_generate(self, gen): gen.write("enum: %s" % (self.event.c_name)) def generate(self, gen): - pass + gen.write( + 'eina_hash_set(self.event_desc_mapping, "%s", %s)' % ( + self.event.name, self.event.c_name + ) + ) + conv = event_conversion_get(self.event.type) + if conv: + gen.write( + 'eina_hash_set(self.event_conv_mapping, %s, %s)' % ( + self.event.c_name, conv + ) + ) class_counter = Counter() @@ -775,6 +787,9 @@ generated_class_counter = Counter() function_counter = Counter() generated_function_counter = Counter() +py_path = os.path.join(args.output, "__init__" + ".py") +if os.path.exists(py_path): + os.remove(py_path) for path in args.paths: for dirpath, dirnames, filenames in os.walk(path): @@ -788,6 +803,8 @@ for path in args.paths: try: eolf = File(filename) + except EolianSkip: + continue except Exception: log.exception("Exception while creating %s" % (filename)) continue @@ -804,6 +821,12 @@ for path in args.paths: log.exception("Exception while generating pyx for %s" % (filename)) continue + try: + eolf.py_generate() + except Exception: + log.exception("Exception while generating py for %s" % (filename)) + continue + def report(): print("===============================================")