summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Huuhko <kai.huuhko@gmail.com>2015-03-13 19:21:36 +0200
committerKai Huuhko <kai.huuhko@gmail.com>2015-03-13 19:22:01 +0200
commit4ccea0f35d1a920aeb1b30451c58dab53909664b (patch)
treef528b7dbb31b6b8c0694e0f3fe31637a118b3175
parentea2d5bd689226dc2a8c5cb2d0ca28ec0913bffa7 (diff)
Evas.SmartObject: Add smart callback introspection
-rw-r--r--efl/evas/efl.evas_object_smart.pxi234
-rw-r--r--examples/elementary/test_core_evas_smart.py26
-rw-r--r--include/efl.evas.pxd22
3 files changed, 262 insertions, 20 deletions
diff --git a/efl/evas/efl.evas_object_smart.pxi b/efl/evas/efl.evas_object_smart.pxi
index 460f3b7..b8bc667 100644
--- a/efl/evas/efl.evas_object_smart.pxi
+++ b/efl/evas/efl.evas_object_smart.pxi
@@ -21,10 +21,78 @@ from efl.eo cimport Eo, EoIterator
21 21
22from cpython cimport Py_INCREF, Py_DECREF, PyObject_Call, \ 22from cpython cimport Py_INCREF, Py_DECREF, PyObject_Call, \
23 PyMem_Malloc, PyMem_Free 23 PyMem_Malloc, PyMem_Free
24from libc.stdlib cimport malloc
25from libc.string cimport strdup
24 26
25#cdef object _smart_classes 27#cdef object _smart_classes
26#_smart_classes = list() 28#_smart_classes = list()
27 29
30cdef list _descriptions_to_list(const Evas_Smart_Cb_Description **arr, unsigned int arr_len):
31 cdef:
32 unsigned int i
33 list ret = list()
34
35 if arr == NULL:
36 return ret
37
38 for i in range(arr_len):
39 ret.append(SmartCbDescription.create(arr[i]))
40
41 if arr[i+1] != NULL:
42 EINA_LOG_DOM_WARN(PY_EFL_EVAS_LOG_DOMAIN, "array was not NULL terminated!", NULL)
43
44 return ret
45
46cdef Evas_Smart_Cb_Description *_descriptions_to_array(descs):
47 cdef:
48 unsigned int arr_len = len(descs)
49 Evas_Smart_Cb_Description *arr
50 SmartCbDescription desc
51
52 if arr_len == 0:
53 return NULL
54
55 # allocate arr_len + 1 so it's NULL terminated
56 arr = <Evas_Smart_Cb_Description *>malloc(arr_len + 1 * sizeof(Evas_Smart_Cb_Description))
57
58 for i, desc in enumerate(descs):
59 arr[i] = desc.desc[0]
60
61 return arr
62
63
64cdef class SmartCbDescription:
65 """Introspection description for a smart callback"""
66 cdef const Evas_Smart_Cb_Description *desc
67
68 def __init__(self, name, types):
69 cdef Evas_Smart_Cb_Description *tmp
70 tmp = <Evas_Smart_Cb_Description *>malloc(sizeof(Evas_Smart_Cb_Description*))
71 if isinstance(name, unicode): name = PyUnicode_AsUTF8String(name)
72 tmp.name = strdup(name)
73 if isinstance(types, unicode): types = PyUnicode_AsUTF8String(types)
74 tmp.type = strdup(types)
75 self.desc = <const Evas_Smart_Cb_Description *>tmp
76
77 @staticmethod
78 cdef create(const Evas_Smart_Cb_Description *desc):
79 cdef SmartCbDescription ret = SmartCbDescription.__new__(SmartCbDescription)
80 ret.desc = desc
81 return ret
82
83 def __repr__(self):
84 return "%s(%r, %r)" % (self.__class__.__name__, self.name, self.type)
85
86 property name:
87 """:type: string"""
88 def __get__(self):
89 return _ctouni(self.desc.name)
90
91 property type:
92 """:type: string"""
93 def __get__(self):
94 return _ctouni(self.desc.type)
95
28 96
29cdef void _smart_object_delete(Evas_Object *o) with gil: 97cdef void _smart_object_delete(Evas_Object *o) with gil:
30 cdef: 98 cdef:
@@ -416,8 +484,9 @@ cdef class Smart(object):
416 .. versionadded:: 1.14 484 .. versionadded:: 1.14
417 """ 485 """
418 486
419 def __cinit__(self, bint clipped=False): 487 def __cinit__(self, Smart parent=None, bint clipped=False, callback_descriptions=[], *args, **kwargs):
420 cdef Evas_Smart_Class *cls_def 488 cdef:
489 Evas_Smart_Class *cls_def
421 490
422 cls_def = <Evas_Smart_Class*>PyMem_Malloc(sizeof(Evas_Smart_Class)) 491 cls_def = <Evas_Smart_Class*>PyMem_Malloc(sizeof(Evas_Smart_Class))
423 if cls_def == NULL: 492 if cls_def == NULL:
@@ -445,20 +514,55 @@ cdef class Smart(object):
445 cls_def.member_add = _smart_object_member_add 514 cls_def.member_add = _smart_object_member_add
446 cls_def.member_del = _smart_object_member_del 515 cls_def.member_del = _smart_object_member_del
447 516
448 cls_def.parent = NULL 517 cls_def.parent = parent.cls_def if parent is not None else NULL
449 cls_def.callbacks = NULL 518
519 cls_def.callbacks = _descriptions_to_array(callback_descriptions)
520
521 # TODO: interfaces?
450 cls_def.interfaces = NULL 522 cls_def.interfaces = NULL
523
451 cls_def.data = <void *>self 524 cls_def.data = <void *>self
452 525
453 self.cls = evas_smart_class_new(cls_def) 526 self.cls_def = <const Evas_Smart_Class *>cls_def
527 self.cls = evas_smart_class_new(self.cls_def)
454 528
455 def __dealloc__(self): 529 def __dealloc__(self):
456 cdef const Evas_Smart_Class *cls_def 530 cdef const Evas_Smart_Class *cls_def
457 cls_def = evas_smart_class_get(self.cls) 531 cls_def = evas_smart_class_get(self.cls)
458 PyMem_Free(<void*>cls_def) 532 PyMem_Free(<void*>cls_def)
459 evas_smart_free(self.cls) 533 evas_smart_free(self.cls) # FIXME: Check that all resources (cb descriptions etc.) are truly freed
460 self.cls = NULL 534 self.cls = NULL
461 535
536 property callback_descriptions:
537 def __get__(self):
538 cdef:
539 const Evas_Smart_Cb_Description **descriptions
540 unsigned int count
541
542 descriptions = evas_smart_callbacks_descriptions_get(self.cls, &count)
543
544 return _descriptions_to_list(descriptions, count)
545
546 def callback_descriptions_get(self):
547 cdef:
548 const Evas_Smart_Cb_Description **descriptions
549 unsigned int count
550
551 descriptions = evas_smart_callbacks_descriptions_get(self.cls, &count)
552
553 return _descriptions_to_list(descriptions, count)
554
555 def callback_description_find(self, name):
556 cdef:
557 const Evas_Smart_Cb_Description *desc
558
559 if isinstance(name, unicode): name = PyUnicode_AsUTF8String(name)
560 desc = evas_smart_callback_description_find(self.cls, name)
561 if desc == NULL:
562 return None
563
564 return SmartCbDescription.create(desc)
565
462 @staticmethod 566 @staticmethod
463 def delete(obj): 567 def delete(obj):
464 """ 568 """
@@ -638,7 +742,7 @@ cdef class SmartObject(Object):
638 #_smart_classes.append(<uintptr_t>cls_def) 742 #_smart_classes.append(<uintptr_t>cls_def)
639 self._set_obj(evas_object_smart_add(canvas.obj, smart.cls)) 743 self._set_obj(evas_object_smart_add(canvas.obj, smart.cls))
640 self._set_properties_from_keyword_args(kwargs) 744 self._set_properties_from_keyword_args(kwargs)
641 self.smart = smart 745 self._smart = smart
642 746
643 cdef int _set_obj(self, cEo *obj) except 0: 747 cdef int _set_obj(self, cEo *obj) except 0:
644 assert self.obj == NULL, "Object must be clean" 748 assert self.obj == NULL, "Object must be clean"
@@ -699,6 +803,13 @@ cdef class SmartObject(Object):
699 eina_list_free(lst) 803 eina_list_free(lst)
700 return tuple(ret) 804 return tuple(ret)
701 805
806 property smart:
807 def __get__(self):
808 if self._smart is not None:
809 return self._smart
810 else:
811 return Smart.create(evas_object_smart_smart_get(self.obj))
812
702 def smart_get(self): 813 def smart_get(self):
703 return self.smart 814 return self.smart
704 815
@@ -947,5 +1058,114 @@ cdef class SmartObject(Object):
947 <void*>event_info if event_info is not None else NULL 1058 <void*>event_info if event_info is not None else NULL
948 ) 1059 )
949 1060
1061 def callback_descriptions_set(self, descriptions):
1062 """Set an smart object **instance's** smart callbacks descriptions.
1063
1064 :return: ``True`` on success, ``False`` on failure.
1065
1066 These descriptions are hints to be used by introspection and are
1067 not enforced in any way.
1068
1069 It will not be checked if instance callbacks descriptions have the same
1070 name as respective possibly registered in the smart object **class**.
1071 Both are kept in different arrays and users of
1072 :meth:`callbacks_descriptions_get` should handle this case as they
1073 wish.
1074
1075 .. note::
1076
1077 While instance callbacks descriptions are possible, they are
1078 **not** recommended. Use **class** callbacks descriptions
1079 instead as they make you smart object user's life simpler and
1080 will use less memory, as descriptions and arrays will be
1081 shared among all instances.
1082
1083
1084 :param descriptions: A list with :class:`SmartCbDescription`
1085 descriptions. List elements won't be modified at run time, but
1086 references to them and their contents will be made, so this array
1087 should be kept alive during the whole object's lifetime.
1088
1089 """
1090
1091 if not evas_object_smart_callbacks_descriptions_set(
1092 self.obj,
1093 <const Evas_Smart_Cb_Description *>_descriptions_to_array(descriptions)
1094 ):
1095 raise ValueError("Could not set callback descriptions")
1096
1097 def callback_descriptions_get(self, get_class=True, get_instance=True):
1098 """Retrieve a smart object's known smart callback descriptions
1099
1100 This call searches for registered callback descriptions for both
1101 instance and class of the given smart object. These lists will be
1102 sorted by name.
1103
1104 .. note::
1105
1106 If just class descriptions are of interest, try
1107 :meth:`Smart.callbacks_descriptions_get` instead.
1108
1109 :param bool get_class: Get class descriptions
1110 :param bool get_instance: Get instance descriptions
1111 :return: A tuple with two lists, for both class and instance
1112 descriptions.
1113 :rtype: tuple
1114 """
1115 cdef:
1116 const Evas_Smart_Cb_Description **class_descriptions
1117 const Evas_Smart_Cb_Description **instance_descriptions
1118 unsigned int class_count, instance_count
1119
1120 evas_object_smart_callbacks_descriptions_get(
1121 self.obj,
1122 &class_descriptions if get_class is True else NULL,
1123 &class_count,
1124 &instance_descriptions if get_instance is True else NULL,
1125 &instance_count
1126 )
1127 return (
1128 _descriptions_to_list(class_descriptions, class_count),
1129 _descriptions_to_list(instance_descriptions, instance_count)
1130 )
1131
1132 def callback_description_find(self, name, search_class=True, search_instance=True):
1133 """Find callback description for callback given in ``name``.
1134
1135 or ``None`` if not found.
1136
1137 :param string name: name of desired callback, must **not** be ``None``.
1138 :param bool search_class: whether to search in class descriptions
1139 :param bool search_instance: whether to search in instance descriptions
1140 :return: reference to description if found, ``None`` if not found.
1141
1142 ..
1143 The
1144 search have a special case for ``name`` being the same
1145 pointer as registered with Evas_Smart_Cb_Description, one
1146 can use it to avoid excessive use of strcmp().
1147 """
1148 cdef:
1149 const Evas_Smart_Cb_Description *class_description
1150 const Evas_Smart_Cb_Description *instance_description
1151 list ret = list()
1152
1153 if isinstance(name, unicode): name = PyUnicode_AsUTF8String(name)
1154
1155 evas_object_smart_callback_description_find(
1156 self.obj, name,
1157 &class_description if search_class is True else NULL,
1158 &instance_description if search_instance is True else NULL
1159 )
1160
1161 if class_description != NULL:
1162 ret.append(SmartCbDescription.create(class_description))
1163 else:
1164 ret.append(None)
1165 if instance_description != NULL:
1166 ret.append(SmartCbDescription.create(instance_description))
1167 else:
1168 ret.append(None)
1169 return ret
950 1170
951_object_mapping_register("Evas_Smart", SmartObject) 1171_object_mapping_register("Evas_Smart", SmartObject)
diff --git a/examples/elementary/test_core_evas_smart.py b/examples/elementary/test_core_evas_smart.py
index e1bb7cf..adb73fc 100644
--- a/examples/elementary/test_core_evas_smart.py
+++ b/examples/elementary/test_core_evas_smart.py
@@ -4,9 +4,8 @@
4import os 4import os
5from random import randint 5from random import randint
6 6
7from efl.eo import Eo
8from efl.evas import SmartObject, Smart, EXPAND_BOTH, FILL_BOTH, Rectangle, \ 7from efl.evas import SmartObject, Smart, EXPAND_BOTH, FILL_BOTH, Rectangle, \
9 Line, FilledImage, Polygon, Text 8 Line, FilledImage, Polygon, Text, SmartCbDescription
10from efl import elementary 9from efl import elementary
11from efl.elementary.window import StandardWindow 10from efl.elementary.window import StandardWindow
12from efl.elementary.box import Box 11from efl.elementary.box import Box
@@ -23,6 +22,7 @@ def random_color():
23 22
24 23
25class MySmart(Smart): 24class MySmart(Smart):
25
26 @staticmethod 26 @staticmethod
27 def resize(smart_object, w, h): 27 def resize(smart_object, w, h):
28 print("RESIZE", w, h) 28 print("RESIZE", w, h)
@@ -72,10 +72,15 @@ class MySmart(Smart):
72 def clip_unset(smart_object): 72 def clip_unset(smart_object):
73 pass 73 pass
74 74
75descriptions = (
76 SmartCbDescription("mycb", "i"),
77 )
78
79
75class MySmartObj(SmartObject): 80class MySmartObj(SmartObject):
76 81
77 def __init__(self, canvas): 82 def __init__(self, canvas, smart):
78 SmartObject.__init__(self, canvas, MySmart()) 83 SmartObject.__init__(self, canvas, smart)
79 84
80 # gray background 85 # gray background
81 self.bg = Rectangle(canvas, color=(128, 128, 128, 128)) 86 self.bg = Rectangle(canvas, color=(128, 128, 128, 128))
@@ -131,11 +136,13 @@ class MySmartObj(SmartObject):
131 136
132 137
133def btn_add_cb(b): 138def btn_add_cb(b):
134 sm = MySmartObj(b.evas) 139 sm = MySmart(callback_descriptions=descriptions)
135 sm.size = 100, 100 140 print(sm.callback_descriptions)
136 sm.pos = 100, 100 141 so = MySmartObj(b.evas, sm)
137 sm.show() 142 so.size = 100, 100
138 objects.append(sm) 143 so.pos = 100, 100
144 so.show()
145 objects.append(so)
139 146
140 147
141def btn_del_cb(b): 148def btn_del_cb(b):
@@ -154,6 +161,7 @@ def btn_show_cb(b):
154 161
155def core_evas_smart_clicked(obj, item=None): 162def core_evas_smart_clicked(obj, item=None):
156 win = StandardWindow("evassmart", "Evas Smart Object Test", autodel=True) 163 win = StandardWindow("evassmart", "Evas Smart Object Test", autodel=True)
164 print(win.callback_descriptions_get())
157 if obj is None: 165 if obj is None:
158 win.callback_delete_request_add(lambda o: elementary.exit()) 166 win.callback_delete_request_add(lambda o: elementary.exit())
159 167
diff --git a/include/efl.evas.pxd b/include/efl.evas.pxd
index 1ca573f..15ccc57 100644
--- a/include/efl.evas.pxd
+++ b/include/efl.evas.pxd
@@ -387,7 +387,7 @@ cdef extern from "Evas.h":
387 void (*member_add)(Evas_Object *o, Evas_Object *child) 387 void (*member_add)(Evas_Object *o, Evas_Object *child)
388 void (*member_del)(Evas_Object *o, Evas_Object *child) 388 void (*member_del)(Evas_Object *o, Evas_Object *child)
389 const Evas_Smart_Class *parent 389 const Evas_Smart_Class *parent
390 Evas_Smart_Cb_Description *callbacks 390 const Evas_Smart_Cb_Description *callbacks
391 const Evas_Smart_Interface **interfaces 391 const Evas_Smart_Interface **interfaces
392 const void *data 392 const void *data
393 393
@@ -781,12 +781,14 @@ cdef extern from "Evas.h":
781 781
782 782
783 #################################################################### 783 ####################################################################
784 # Smart Object (py3:TODO) 784 # Smart Object
785 # 785 #
786 void evas_smart_free(Evas_Smart *s) 786 void evas_smart_free(Evas_Smart *s)
787 Evas_Smart *evas_smart_class_new(Evas_Smart_Class *sc) 787 Evas_Smart *evas_smart_class_new(Evas_Smart_Class *sc)
788 Evas_Smart_Class *evas_smart_class_get(Evas_Smart *s) 788 Evas_Smart_Class *evas_smart_class_get(Evas_Smart *s)
789 const Eo_Class *evas_object_smart_class_get() 789 const Eo_Class *evas_object_smart_class_get()
790 const Evas_Smart_Cb_Description **evas_smart_callbacks_descriptions_get(const Evas_Smart *s, unsigned int *count)
791 const Evas_Smart_Cb_Description *evas_smart_callback_description_find(const Evas_Smart *s, const char *name)
790 792
791 void *evas_smart_data_get(Evas_Smart *s) 793 void *evas_smart_data_get(Evas_Smart *s)
792 794
@@ -809,6 +811,9 @@ cdef extern from "Evas.h":
809 void evas_object_smart_move_children_relative(Evas_Object *obj, int dx, int dy) 811 void evas_object_smart_move_children_relative(Evas_Object *obj, int dx, int dy)
810 Eina_Iterator *evas_object_smart_iterator_new(const Evas_Object_Smart *obj) 812 Eina_Iterator *evas_object_smart_iterator_new(const Evas_Object_Smart *obj)
811 void evas_object_smart_clipped_smart_set(Evas_Smart_Class *sc) 813 void evas_object_smart_clipped_smart_set(Evas_Smart_Class *sc)
814 Eina_Bool evas_object_smart_callbacks_descriptions_set(Evas_Object_Smart *obj, const Evas_Smart_Cb_Description *descriptions)
815 void evas_object_smart_callbacks_descriptions_get(const Evas_Object_Smart *obj, const Evas_Smart_Cb_Description ***class_descriptions, unsigned int *class_count, const Evas_Smart_Cb_Description ***instance_descriptions, unsigned int *instance_count)
816 void evas_object_smart_callback_description_find(const Evas_Object_Smart *obj, const char *name, const Evas_Smart_Cb_Description **class_description, const Evas_Smart_Cb_Description **instance_description)
812 817
813 818
814 #################################################################### 819 ####################################################################
@@ -1210,11 +1215,20 @@ cdef class Textblock(Object):
1210# ctypedef object(*Smart_Conv_Func)(void *) 1215# ctypedef object(*Smart_Conv_Func)(void *)
1211 1216
1212cdef class Smart: 1217cdef class Smart:
1213 cdef Evas_Smart *cls 1218 cdef:
1219 Evas_Smart *cls
1220 const Evas_Smart_Class *cls_def
1221
1222 @staticmethod
1223 cdef inline create(Evas_Smart *cls):
1224 cdef Smart ret = Smart.__new__(Smart)
1225 ret.cls = cls
1226 ret.cls_def = evas_smart_class_get(cls)
1227 return ret
1214 1228
1215cdef class SmartObject(Object): 1229cdef class SmartObject(Object):
1216 cdef: 1230 cdef:
1217 public Smart smart 1231 Smart _smart
1218 dict _smart_callback_specs 1232 dict _smart_callback_specs
1219 int _set_obj(self, cEo *obj) except 0 1233 int _set_obj(self, cEo *obj) except 0
1220 int _callback_add_full(self, event, object(*)(void*), func, tuple args, dict kargs) except 0 1234 int _callback_add_full(self, event, object(*)(void*), func, tuple args, dict kargs) except 0