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