1 /**
2  * @file lv_event.c
3  *
4  */
5 
6 /*********************
7  *      INCLUDES
8  *********************/
9 #include "lv_event_private.h"
10 #include "../core/lv_global.h"
11 #include "../stdlib/lv_mem.h"
12 #include "lv_assert.h"
13 #include "lv_types.h"
14 
15 /*********************
16  *      DEFINES
17  *********************/
18 
19 #define event_head LV_GLOBAL_DEFAULT()->event_header
20 #define event_last_id LV_GLOBAL_DEFAULT()->event_last_register_id
21 
22 /**********************
23  *      TYPEDEFS
24  **********************/
25 
26 /**********************
27  *  STATIC PROTOTYPES
28  **********************/
29 
30 /* Traverse the list to delete the objects marked for deletion */
31 static void cleanup_event_list(lv_event_list_t * list);
32 static void cleanup_event_list_core(lv_array_t * array);
33 
34 static void event_mark_deleting(lv_event_list_t * list, lv_event_dsc_t * dsc);
35 static bool event_is_marked_deleting(lv_event_dsc_t * dsc);
36 static uint32_t event_array_size(lv_event_list_t * list);
37 static lv_event_dsc_t ** event_array_at(lv_event_list_t * list, uint32_t index);
38 
39 /**********************
40  *  STATIC VARIABLES
41  **********************/
42 
43 /**********************
44  *      MACROS
45  **********************/
46 
47 #if LV_USE_LOG && LV_LOG_TRACE_EVENT
48     #define LV_TRACE_EVENT(...) LV_LOG_TRACE(__VA_ARGS__)
49 #else
50     #define LV_TRACE_EVENT(...)
51 #endif
52 
53 /**********************
54  *   GLOBAL FUNCTIONS
55  **********************/
56 
lv_event_push(lv_event_t * e)57 void lv_event_push(lv_event_t * e)
58 {
59     /*Build a simple linked list from the objects used in the events
60      *It's important to know if this object was deleted by a nested event
61      *called from this `event_cb`.*/
62     e->prev = event_head;
63     event_head = e;
64 
65 }
66 
lv_event_pop(lv_event_t * e)67 void lv_event_pop(lv_event_t * e)
68 {
69     event_head = e->prev;
70 }
71 
lv_event_send(lv_event_list_t * list,lv_event_t * e,bool preprocess)72 lv_result_t lv_event_send(lv_event_list_t * list, lv_event_t * e, bool preprocess)
73 {
74     if(list == NULL) return LV_RESULT_OK;
75     if(e->deleted) return LV_RESULT_INVALID;
76 
77     /* When obj is deleted in its own event, it will cause the `list->array` header to be released,
78      * but the content still exists, which leads to memory leakage.
79      * Therefore, back up the header in advance,
80      * which can strive to release the memory and prevent used-after-free. */
81     lv_array_t back_array_head = list->array;
82 
83     /* Dealing with the problem of nested event deletion event */
84     const bool is_traversing = list->is_traversing;
85     list->is_traversing = true;
86 
87     lv_result_t res = LV_RESULT_OK;
88     const uint32_t size = event_array_size(list);
89     for(uint32_t i = 0; i < size && !e->deleted; i++) {
90         lv_event_dsc_t * dsc = *event_array_at(list, i);
91         if(dsc->cb == NULL) continue;
92         if(event_is_marked_deleting(dsc)) continue;
93         const bool is_preprocessed = (dsc->filter & LV_EVENT_PREPROCESS) != 0;
94         if(is_preprocessed != preprocess) continue;
95         lv_event_code_t filter = dsc->filter & ~LV_EVENT_PREPROCESS;
96         if(filter == LV_EVENT_ALL || filter == e->code) {
97             e->user_data = dsc->user_data;
98             dsc->cb(e);
99             if(e->stop_processing) break;
100 
101             /*Stop if the object is deleted*/
102             if(e->deleted) {
103                 res = LV_RESULT_INVALID;
104                 break;
105             }
106         }
107     }
108 
109     if(is_traversing) return res;
110 
111     if(e->deleted) cleanup_event_list_core(&back_array_head);
112     else {
113         list->is_traversing = false;
114         cleanup_event_list(list);
115     }
116 
117     return res;
118 }
119 
lv_event_add(lv_event_list_t * list,lv_event_cb_t cb,lv_event_code_t filter,void * user_data)120 lv_event_dsc_t * lv_event_add(lv_event_list_t * list, lv_event_cb_t cb, lv_event_code_t filter,
121                               void * user_data)
122 {
123     lv_event_dsc_t * dsc = lv_malloc(sizeof(lv_event_dsc_t));
124     LV_ASSERT_NULL(dsc);
125 
126     dsc->cb = cb;
127     dsc->filter = filter;
128     dsc->user_data = user_data;
129 
130     if(event_array_size(list) == 0) {
131         /*event list hasn't been initialized.*/
132         lv_array_init(&list->array, 1, sizeof(lv_event_dsc_t *));
133     }
134 
135     lv_array_push_back(&list->array, &dsc);
136     return dsc;
137 }
138 
lv_event_remove_dsc(lv_event_list_t * list,lv_event_dsc_t * dsc)139 bool lv_event_remove_dsc(lv_event_list_t * list, lv_event_dsc_t * dsc)
140 {
141     LV_ASSERT_NULL(list);
142     LV_ASSERT_NULL(dsc);
143 
144     const uint32_t size = event_array_size(list);
145     for(uint32_t i = 0; i < size; i++) {
146         lv_event_dsc_t * event = *event_array_at(list, i);
147         if(event == dsc) {
148             event_mark_deleting(list, event);
149             cleanup_event_list(list);
150             return true;
151         }
152     }
153 
154     return false;
155 }
156 
lv_event_get_count(lv_event_list_t * list)157 uint32_t lv_event_get_count(lv_event_list_t * list)
158 {
159     LV_ASSERT_NULL(list);
160     return event_array_size(list);
161 }
162 
lv_event_get_dsc(lv_event_list_t * list,uint32_t index)163 lv_event_dsc_t * lv_event_get_dsc(lv_event_list_t * list, uint32_t index)
164 {
165     LV_ASSERT_NULL(list);
166     lv_event_dsc_t ** dsc = event_array_at(list, index);
167     return dsc ? *dsc : NULL;
168 }
169 
lv_event_dsc_get_cb(lv_event_dsc_t * dsc)170 lv_event_cb_t lv_event_dsc_get_cb(lv_event_dsc_t * dsc)
171 {
172     LV_ASSERT_NULL(dsc);
173     return dsc->cb;
174 }
175 
lv_event_dsc_get_user_data(lv_event_dsc_t * dsc)176 void * lv_event_dsc_get_user_data(lv_event_dsc_t * dsc)
177 {
178     LV_ASSERT_NULL(dsc);
179     return dsc->user_data;
180 
181 }
182 
lv_event_remove(lv_event_list_t * list,uint32_t index)183 bool lv_event_remove(lv_event_list_t * list, uint32_t index)
184 {
185     LV_ASSERT_NULL(list);
186     lv_event_dsc_t * dsc = lv_event_get_dsc(list, index);
187     if(dsc == NULL) return false;
188     event_mark_deleting(list, dsc);
189     cleanup_event_list(list);
190     return true;
191 }
192 
lv_event_remove_all(lv_event_list_t * list)193 void lv_event_remove_all(lv_event_list_t * list)
194 {
195     LV_ASSERT_NULL(list);
196     const uint32_t size = event_array_size(list);
197     for(uint32_t i = 0; i < size; i++)
198         event_mark_deleting(list, *event_array_at(list, i));
199     cleanup_event_list(list);
200 }
201 
lv_event_get_current_target(lv_event_t * e)202 void * lv_event_get_current_target(lv_event_t * e)
203 {
204     return e->current_target;
205 }
206 
lv_event_get_target(lv_event_t * e)207 void * lv_event_get_target(lv_event_t * e)
208 {
209     return e->original_target;
210 }
211 
lv_event_get_code(lv_event_t * e)212 lv_event_code_t lv_event_get_code(lv_event_t * e)
213 {
214     return e->code & ~LV_EVENT_PREPROCESS;
215 }
216 
lv_event_get_param(lv_event_t * e)217 void * lv_event_get_param(lv_event_t * e)
218 {
219     return e->param;
220 }
221 
lv_event_get_user_data(lv_event_t * e)222 void * lv_event_get_user_data(lv_event_t * e)
223 {
224     return e->user_data;
225 }
226 
lv_event_stop_bubbling(lv_event_t * e)227 void lv_event_stop_bubbling(lv_event_t * e)
228 {
229     e->stop_bubbling = 1;
230 }
231 
lv_event_stop_processing(lv_event_t * e)232 void lv_event_stop_processing(lv_event_t * e)
233 {
234     e->stop_processing = 1;
235 }
236 
lv_event_register_id(void)237 uint32_t lv_event_register_id(void)
238 {
239     event_last_id ++;
240     return event_last_id;
241 }
242 
lv_event_mark_deleted(void * target)243 void lv_event_mark_deleted(void * target)
244 {
245     lv_event_t * e = event_head;
246 
247     while(e) {
248         if(e->original_target == target || e->current_target == target) e->deleted = 1;
249         e = e->prev;
250     }
251 }
252 
lv_event_code_get_name(lv_event_code_t code)253 const char * lv_event_code_get_name(lv_event_code_t code)
254 {
255     /*Remove the preprocess flag*/
256     code &= ~LV_EVENT_PREPROCESS;
257 
258 #define ENUM_CASE(x) case LV_##x: return #x
259 
260     switch(code) {
261             ENUM_CASE(EVENT_ALL);
262 
263             /** Input device events*/
264             ENUM_CASE(EVENT_PRESSED);
265             ENUM_CASE(EVENT_PRESSING);
266             ENUM_CASE(EVENT_PRESS_LOST);
267             ENUM_CASE(EVENT_SHORT_CLICKED);
268             ENUM_CASE(EVENT_SINGLE_CLICKED);
269             ENUM_CASE(EVENT_DOUBLE_CLICKED);
270             ENUM_CASE(EVENT_TRIPLE_CLICKED);
271             ENUM_CASE(EVENT_LONG_PRESSED);
272             ENUM_CASE(EVENT_LONG_PRESSED_REPEAT);
273             ENUM_CASE(EVENT_CLICKED);
274             ENUM_CASE(EVENT_RELEASED);
275             ENUM_CASE(EVENT_SCROLL_BEGIN);
276             ENUM_CASE(EVENT_SCROLL_THROW_BEGIN);
277             ENUM_CASE(EVENT_SCROLL_END);
278             ENUM_CASE(EVENT_SCROLL);
279             ENUM_CASE(EVENT_GESTURE);
280             ENUM_CASE(EVENT_KEY);
281             ENUM_CASE(EVENT_ROTARY);
282             ENUM_CASE(EVENT_FOCUSED);
283             ENUM_CASE(EVENT_DEFOCUSED);
284             ENUM_CASE(EVENT_LEAVE);
285             ENUM_CASE(EVENT_HIT_TEST);
286             ENUM_CASE(EVENT_INDEV_RESET);
287             ENUM_CASE(EVENT_HOVER_OVER);
288             ENUM_CASE(EVENT_HOVER_LEAVE);
289 
290             /** Drawing events*/
291             ENUM_CASE(EVENT_COVER_CHECK);
292             ENUM_CASE(EVENT_REFR_EXT_DRAW_SIZE);
293             ENUM_CASE(EVENT_DRAW_MAIN_BEGIN);
294             ENUM_CASE(EVENT_DRAW_MAIN);
295             ENUM_CASE(EVENT_DRAW_MAIN_END);
296             ENUM_CASE(EVENT_DRAW_POST_BEGIN);
297             ENUM_CASE(EVENT_DRAW_POST);
298             ENUM_CASE(EVENT_DRAW_POST_END);
299             ENUM_CASE(EVENT_DRAW_TASK_ADDED);
300 
301             /** Special events*/
302             ENUM_CASE(EVENT_VALUE_CHANGED);
303             ENUM_CASE(EVENT_INSERT);
304             ENUM_CASE(EVENT_REFRESH);
305             ENUM_CASE(EVENT_READY);
306             ENUM_CASE(EVENT_CANCEL);
307 
308             /** Other events*/
309             ENUM_CASE(EVENT_CREATE);
310             ENUM_CASE(EVENT_DELETE);
311             ENUM_CASE(EVENT_CHILD_CHANGED);
312             ENUM_CASE(EVENT_CHILD_CREATED);
313             ENUM_CASE(EVENT_CHILD_DELETED);
314             ENUM_CASE(EVENT_SCREEN_UNLOAD_START);
315             ENUM_CASE(EVENT_SCREEN_LOAD_START);
316             ENUM_CASE(EVENT_SCREEN_LOADED);
317             ENUM_CASE(EVENT_SCREEN_UNLOADED);
318             ENUM_CASE(EVENT_SIZE_CHANGED);
319             ENUM_CASE(EVENT_STYLE_CHANGED);
320             ENUM_CASE(EVENT_LAYOUT_CHANGED);
321             ENUM_CASE(EVENT_GET_SELF_SIZE);
322 
323             /** Events of optional LVGL components*/
324             ENUM_CASE(EVENT_INVALIDATE_AREA);
325             ENUM_CASE(EVENT_RESOLUTION_CHANGED);
326             ENUM_CASE(EVENT_COLOR_FORMAT_CHANGED);
327             ENUM_CASE(EVENT_REFR_REQUEST);
328             ENUM_CASE(EVENT_REFR_START);
329             ENUM_CASE(EVENT_REFR_READY);
330             ENUM_CASE(EVENT_RENDER_START);
331             ENUM_CASE(EVENT_RENDER_READY);
332             ENUM_CASE(EVENT_FLUSH_START);
333             ENUM_CASE(EVENT_FLUSH_FINISH);
334             ENUM_CASE(EVENT_FLUSH_WAIT_START);
335             ENUM_CASE(EVENT_FLUSH_WAIT_FINISH);
336 
337             ENUM_CASE(EVENT_VSYNC);
338 
339         /* Special event flags */
340         case LV_EVENT_LAST:
341         case LV_EVENT_PREPROCESS:
342         case LV_EVENT_MARKED_DELETING:
343             break;
344 
345             /* Note that default is not added here because when adding new event code,
346              * if forget to add case, the compiler will automatically report a warning.
347              */
348     }
349 
350 #undef ENUM_CASE
351 
352     return "EVENT_UNKNOWN";
353 }
354 
355 /**********************
356  *   STATIC FUNCTIONS
357  **********************/
358 
cleanup_event_list_core(lv_array_t * array)359 static void cleanup_event_list_core(lv_array_t * array)
360 {
361     const uint32_t size = lv_array_size(array);
362     uint32_t kept_count = 0;
363     for(uint32_t i = 0; i < size; i++) {
364         lv_event_dsc_t ** dsc_i = lv_array_at(array, i);
365         lv_event_dsc_t ** dsc_kept = lv_array_at(array, kept_count);
366         if(event_is_marked_deleting(*dsc_i)) lv_free(*dsc_i);
367         else {
368             *dsc_kept = *dsc_i;
369             kept_count++;
370         }
371     }
372 
373     if(kept_count == 0) lv_array_deinit(array);
374     else lv_array_resize(array, kept_count);
375 }
376 
cleanup_event_list(lv_event_list_t * list)377 static void cleanup_event_list(lv_event_list_t * list)
378 {
379     if(list->is_traversing) return;
380     if(list->has_marked_deleting == false) return;
381 
382     cleanup_event_list_core(&list->array);
383 
384     list->has_marked_deleting = false;
385 }
386 
event_mark_deleting(lv_event_list_t * list,lv_event_dsc_t * dsc)387 static void event_mark_deleting(lv_event_list_t * list, lv_event_dsc_t * dsc)
388 {
389     list->has_marked_deleting = true;
390     dsc->filter |= LV_EVENT_MARKED_DELETING;
391 }
event_is_marked_deleting(lv_event_dsc_t * dsc)392 static bool event_is_marked_deleting(lv_event_dsc_t * dsc)
393 {
394     return (dsc->filter & LV_EVENT_MARKED_DELETING) != 0;
395 }
event_array_size(lv_event_list_t * list)396 static uint32_t event_array_size(lv_event_list_t * list)
397 {
398     return lv_array_size(&list->array);
399 }
event_array_at(lv_event_list_t * list,uint32_t index)400 static lv_event_dsc_t ** event_array_at(lv_event_list_t * list, uint32_t index)
401 {
402     return lv_array_at(&list->array, index);
403 }
404