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