Add new API for creating evas_object for elm_win.
[apps/native/widget/widget.git] / src / virtual_window.c
1 #include <Elementary.h>
2 #include <string.h>
3 #include <Ecore_Evas.h>
4 #include <Evas.h>
5
6 #include <dlog.h>
7 #include <livebox-errno.h>
8 #include <livebox-service.h>
9
10 #include "livebox.h"
11 #include "debug.h"
12
13 #define IS_PD 1
14
15 #define PUBLIC __attribute__((visibility("default")))
16 /*!
17  * \brief
18  * Abstracted Data Type of Virtual Window
19  */
20 struct info {
21         char *id; /*!< Identification */
22         int width; /*!< Width */
23         int height; /*!< Height */
24         struct livebox_buffer *handle; /*!< Livebox buffer handle */
25         Evas_Object *window; /*!< Parent evas object - WARN: Incompatible with the elm_win object */
26         int is_hw; /*!< 1 if a buffer is created on the H/W accelerated place or 0 */
27 };
28
29 static inline Evas_Object *get_highlighted_object(Evas_Object *obj)
30 {
31         Evas_Object *o, *ho;
32
33         o = evas_object_name_find(evas_object_evas_get(obj), "_elm_access_disp");
34         if (!o) return NULL;
35
36         ho = evas_object_data_get(o, "_elm_access_target");
37         return ho;
38 }
39
40 /*!
41  * \note
42  * Every user event (mouse) on the buffer will be passed via this event callback
43  */
44 static int event_handler_cb(struct livebox_buffer *handler, struct buffer_event_data *event_info, void *data)
45 {
46         struct info *info = data;
47         Elm_Access_Action_Info action_info;
48         Elm_Access_Action_Type action_type;
49         Evas *e;
50         Ecore_Evas *ee;
51         Evas_Object *parent_elm;
52         int ret = 0;
53
54         if (!info->handle) {
55                 /* Just ignore this event */
56                 return 0;
57         }
58
59         e = evas_object_evas_get(info->window);
60
61         memset(&action_info, 0, sizeof(action_info));
62
63         /*!
64          * \note
65          * Feed up events
66          */
67         switch (event_info->type) {
68         case BUFFER_EVENT_ENTER:
69                 evas_event_feed_mouse_in(e, event_info->timestamp * 1000, NULL);
70                 break;
71         case BUFFER_EVENT_LEAVE:
72                 evas_event_feed_mouse_out(e, event_info->timestamp * 1000, NULL);
73                 break;
74         case BUFFER_EVENT_DOWN:
75                 /*!
76                  * \note
77                  * Calculate the event occurred X & Y on the buffer
78                  */
79                 evas_event_feed_mouse_in(e, (event_info->timestamp - 0.002f) * 1000, NULL);
80                 evas_event_feed_mouse_move(e, info->width * event_info->info.pointer.x, info->height * event_info->info.pointer.y, (event_info->timestamp - 0.001f) * 1000, NULL); /* + 0.1f just for fake event */
81                 evas_event_feed_mouse_down(e, 1, EVAS_BUTTON_NONE, event_info->timestamp * 1000, NULL); /* + 0.2f just for fake event */
82                 break;
83         case BUFFER_EVENT_MOVE:
84                 /*!
85                  * \note
86                  * Calculate the event occurred X & Y on the buffer
87                  */
88                 evas_event_feed_mouse_move(e, info->width * event_info->info.pointer.x, info->height * event_info->info.pointer.y, event_info->timestamp * 1000, NULL);
89                 break;
90         case BUFFER_EVENT_UP:
91                 evas_event_feed_mouse_up(e, 1, EVAS_BUTTON_NONE, event_info->timestamp * 1000, NULL);
92                 evas_event_feed_mouse_out(e, (event_info->timestamp + 0.001f) * 1000, NULL); /* + 0.1f just for fake event */
93                 break;
94         case BUFFER_EVENT_HIGHLIGHT:
95                 ee = ecore_evas_ecore_evas_get(e);
96                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
97                 if (!parent_elm) {
98                         ret = LB_ACCESS_STATUS_ERROR;
99                         break;
100                 }
101                 action_type = ELM_ACCESS_ACTION_HIGHLIGHT;
102                 /*!
103                  * \note
104                  * Calculate the event occurred X & Y on the buffer
105                  */
106                 action_info.x = info->width * event_info->info.pointer.x;
107                 action_info.y = info->height * event_info->info.pointer.y;
108                 ret = elm_access_action(parent_elm, action_type, &action_info);
109                 if (ret == EINA_TRUE) {
110                         if (!get_highlighted_object(parent_elm)) {
111                                 LOGE("Highlighted object is not found\n");
112                                 ret = LB_ACCESS_STATUS_ERROR;
113                         } else {
114                                 LOGD("Highlighted object is found\n");
115                                 ret = LB_ACCESS_STATUS_DONE;
116                         }
117                 } else {
118                         LOGE("Action error\n");
119                         ret = LB_ACCESS_STATUS_ERROR;
120                 }
121                 break;
122         case BUFFER_EVENT_HIGHLIGHT_NEXT:
123                 ee = ecore_evas_ecore_evas_get(e);
124                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
125                 if (!parent_elm) {
126                         ret = LB_ACCESS_STATUS_ERROR;
127                         break;
128                 }
129                 action_type = ELM_ACCESS_ACTION_HIGHLIGHT_NEXT;
130                 action_info.highlight_cycle = EINA_FALSE;
131                 ret = elm_access_action(parent_elm, action_type, &action_info);
132                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_LAST : LB_ACCESS_STATUS_DONE;
133                 break;
134         case BUFFER_EVENT_HIGHLIGHT_PREV:
135                 ee = ecore_evas_ecore_evas_get(e);
136                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
137                 if (!parent_elm) {
138                         ret = LB_ACCESS_STATUS_ERROR;
139                         break;
140                 }
141                 action_type = ELM_ACCESS_ACTION_HIGHLIGHT_PREV;
142                 action_info.highlight_cycle = EINA_FALSE;
143                 ret = elm_access_action(parent_elm, action_type, &action_info);
144                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_FIRST : LB_ACCESS_STATUS_DONE;
145                 break;
146         case BUFFER_EVENT_ACTIVATE:
147                 ee = ecore_evas_ecore_evas_get(e);
148                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
149                 if (!parent_elm) {
150                         ret = LB_ACCESS_STATUS_ERROR;
151                         break;
152                 }
153                 action_type = ELM_ACCESS_ACTION_ACTIVATE;
154                 ret = elm_access_action(parent_elm, action_type, &action_info);
155                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
156                 break;
157         case BUFFER_EVENT_ACTION_UP:
158                 ee = ecore_evas_ecore_evas_get(e);
159                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
160                 if (!parent_elm) {
161                         ret = LB_ACCESS_STATUS_ERROR;
162                         break;
163                 }
164                 action_type = ELM_ACCESS_ACTION_UP;
165                 ret = elm_access_action(parent_elm, action_type, &action_info);
166                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
167                 break;
168         case BUFFER_EVENT_ACTION_DOWN:
169                 ee = ecore_evas_ecore_evas_get(e);
170                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
171                 if (!parent_elm) {
172                         ret = LB_ACCESS_STATUS_ERROR;
173                         break;
174                 }
175                 action_type = ELM_ACCESS_ACTION_DOWN;
176                 ret = elm_access_action(parent_elm, action_type, &action_info);
177                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
178                 break;
179         case BUFFER_EVENT_SCROLL_UP:
180                 ee = ecore_evas_ecore_evas_get(e);
181                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
182                 if (!parent_elm) {
183                         ret = LB_ACCESS_STATUS_ERROR;
184                         break;
185                 }
186                 action_type = ELM_ACCESS_ACTION_SCROLL;
187                 action_info.x = info->width * event_info->info.pointer.x;
188                 action_info.y = info->height * event_info->info.pointer.y;
189                 action_info.mouse_type = 2;
190                 ret = elm_access_action(parent_elm, action_type, &action_info);
191                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
192                 break;
193         case BUFFER_EVENT_SCROLL_MOVE:
194                 ee = ecore_evas_ecore_evas_get(e);
195                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
196                 if (!parent_elm) {
197                         ret = LB_ACCESS_STATUS_ERROR;
198                         break;
199                 }
200                 action_type = ELM_ACCESS_ACTION_SCROLL;
201                 action_info.x = info->width * event_info->info.pointer.x;
202                 action_info.y = info->height * event_info->info.pointer.y;
203                 action_info.mouse_type = 1;
204                 ret = elm_access_action(parent_elm, action_type, &action_info);
205                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
206                 break;
207         case BUFFER_EVENT_SCROLL_DOWN:
208                 ee = ecore_evas_ecore_evas_get(e);
209                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
210                 if (!parent_elm) {
211                         ret = LB_ACCESS_STATUS_ERROR;
212                         break;
213                 }
214                 action_type = ELM_ACCESS_ACTION_SCROLL;
215                 action_info.x = info->width * event_info->info.pointer.x;
216                 action_info.y = info->height * event_info->info.pointer.y;
217                 action_info.mouse_type = 0;
218                 ret = elm_access_action(parent_elm, action_type, &action_info);
219                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
220                 break;
221         case BUFFER_EVENT_UNHIGHLIGHT:
222                 ee = ecore_evas_ecore_evas_get(e);
223                 parent_elm = ecore_evas_data_get(ee, "parent,elm");
224                 if (!parent_elm) {
225                         ret = LB_ACCESS_STATUS_ERROR;
226                         break;
227                 }
228                 action_type = ELM_ACCESS_ACTION_UNHIGHLIGHT;
229                 ret = elm_access_action(parent_elm, action_type, &action_info);
230                 ret = (ret == EINA_FALSE) ? LB_ACCESS_STATUS_ERROR : LB_ACCESS_STATUS_DONE;
231                 break;
232         case BUFFER_EVENT_KEY_DOWN:
233                 ret = LB_KEY_STATUS_ERROR;
234                 break;
235         case BUFFER_EVENT_KEY_UP:
236                 ret = LB_KEY_STATUS_ERROR;
237                 break;
238         case BUFFER_EVENT_KEY_FOCUS_IN:
239                 ret = LB_KEY_STATUS_ERROR;
240                 break;
241         case BUFFER_EVENT_KEY_FOCUS_OUT:
242                 ret = LB_KEY_STATUS_ERROR;
243                 break;
244         default:
245                 LOGD("Unhandled buffer event (%d)\n", event_info->type);
246                 break;
247         }
248
249         return ret;
250 }
251
252 static void *alloc_fb(void *data, int size)
253 {
254         struct info *info = data;
255         void *buffer;
256
257         /*!
258          * Acquire a buffer for canvas.
259          */
260         info->handle = livebox_acquire_buffer(info->id, IS_PD,
261                                         info->width, info->height,
262                                         event_handler_cb, info);
263
264         /*!
265          * If it supports the H/W accelerated buffer,
266          * Use it.
267          */
268         if (livebox_support_hw_buffer(info->handle)) {
269                 if (livebox_create_hw_buffer(info->handle) == 0) {
270                         buffer = livebox_buffer_hw_buffer(info->handle);
271                         if (buffer) {
272                                 LOGD("HW Accelerated buffer is created\n");
273                                 info->is_hw = 1;
274                                 return buffer;
275                         }
276                 }
277
278                 LOGE("Failed to allocate HW Accelerated buffer\n");
279         }
280
281         /*!
282          * Or use the buffer of a S/W backend.
283          */
284         buffer = livebox_ref_buffer(info->handle);
285         LOGD("SW buffer is created\n");
286         info->is_hw = 0;
287         return buffer;
288 }
289
290 static void free_fb(void *data, void *ptr)
291 {
292         struct info *info = data;
293
294         if (!info->handle) {
295                 return;
296         }
297
298         if (info->is_hw) {
299                 if (livebox_destroy_hw_buffer(info->handle) == 0) {
300                         LOGD("HW Accelerated buffer is destroyed\n");
301                         goto out;
302                 }
303         }
304
305         livebox_unref_buffer(ptr);
306         LOGD("SW buffer is destroyed\n");
307 out:
308         livebox_release_buffer(info->handle);
309         info->handle = NULL;
310 }
311
312 static void resize_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
313 {
314         struct info *info = data;
315         Ecore_Evas *ee;
316
317         ee = ecore_evas_ecore_evas_get(e);
318         if (!ee) {
319                 return;
320         }
321
322         evas_object_geometry_get(obj, NULL, NULL, &info->width, &info->height);
323         SECURE_LOGD("Resize to %dx%d\n", info->width, info->height);
324         /*!
325          * Box(parent object) is resized.
326          * Try to resize the canvas too.
327          */
328         ecore_evas_resize(ee, info->width, info->height);
329 }
330
331 /*!
332  * If a canvas is destroyed,
333  * Free all buffer of canvas.
334  */
335 static void del_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
336 {
337         Ecore_Evas *ee;
338         struct info *info = data;
339
340         ee = ecore_evas_ecore_evas_get(e);
341         if (!ee) {
342                 return;
343         }
344
345         ecore_evas_free(ee);
346         free(info->id);
347         free(info);
348 }
349
350 static void pre_render_cb(void *data, Evas *e, void *event_info)
351 {
352         struct info *info = data;
353
354         if (!info->handle) {
355                 return;
356         }
357
358         if (info->is_hw) {
359                 livebox_buffer_pre_render(info->handle);
360         }
361 }
362
363 static void post_render_cb(void *data, Evas *e, void *event_info)
364 {
365         struct info *info = data;
366
367         if (!info->handle) {
368                 return;
369         }
370
371         if (info->is_hw) {
372                 livebox_buffer_post_render(info->handle);
373         } else {
374                 livebox_sync_buffer(info->handle);
375         }
376 }
377
378 PUBLIC Evas_Object *livebox_get_evas_object(const char *id, int width, int height)
379 {
380         Ecore_Evas *ee;
381         Evas *e;
382         struct info *info;
383
384         info = calloc(1, sizeof(*info));
385         if (!info) {
386                 ErrPrint("Heap: %s\n", strerror(errno));
387                 return NULL;
388         }
389
390         info->id = strdup(id);
391         if (!info->id) {
392                 ErrPrint("Heap: %s\n", strerror(errno));
393                 free(info);
394                 return NULL;
395         }
396
397         info->width = width;
398         info->height = height;
399
400         ee = ecore_evas_buffer_allocfunc_new(width, height, alloc_fb, free_fb, info);
401         if (!ee) {
402                 ErrPrint("Failed to create ecore_evas (%dx%d)\n", width, height);
403                 free(info->id);
404                 free(info);
405                 return NULL;
406         }
407
408         pre_render_cb(info, NULL, NULL);
409         ecore_evas_alpha_set(ee, EINA_TRUE);
410         post_render_cb(info, NULL, NULL);
411         
412         ecore_evas_manual_render_set(ee, EINA_FALSE);
413         ecore_evas_resize(ee, width, height);
414
415         e = ecore_evas_get(ee);
416         if (!e) {
417                 ErrPrint("Failed to get evas\n");
418                 ecore_evas_free(ee);
419                 return NULL;
420         }
421
422         evas_event_callback_add(e, EVAS_CALLBACK_RENDER_POST, post_render_cb, info);
423         evas_event_callback_add(e, EVAS_CALLBACK_RENDER_PRE, pre_render_cb, info);
424
425         info->window = evas_object_rectangle_add(e);
426         if (!info->window) {
427                 ErrPrint("Failed to create evas_object\n");
428                 ecore_evas_free(ee);
429                 return NULL;
430         }
431
432         evas_object_resize(info->window, width, height);
433         evas_object_color_set(info->window, 0, 0, 0, 0);
434         evas_object_event_callback_add(info->window, EVAS_CALLBACK_DEL, del_cb, info);
435         evas_object_event_callback_add(info->window, EVAS_CALLBACK_RESIZE, resize_cb, info);
436
437         return info->window;
438 }
439
440 PUBLIC int livebox_set_elm_window(Evas_Object *lb_evas_object, Evas_Object *window)
441 {
442         Evas *e;
443         Ecore_Evas *ee;
444
445         if (!lb_evas_object) {
446                 return LB_STATUS_ERROR_INVALID;
447         }
448
449         e = evas_object_evas_get(lb_evas_object);
450         if (!e) {
451                 return LB_STATUS_ERROR_FAULT;
452         }
453
454         ee = ecore_evas_ecore_evas_get(e);
455         if (!ee) {
456                 return LB_STATUS_ERROR_FAULT;
457         }
458
459         ecore_evas_data_set(ee, "parent,elm", window);
460         return 0;
461 }
462
463 /* End of a file */